From 65b1e57084d77f3428e283c1a59df850dbb7f747 Mon Sep 17 00:00:00 2001 From: Jeff Haynie Date: Tue, 19 Aug 2025 08:29:39 -0700 Subject: [PATCH 1/2] Swap OpenAI Swarm -> OpenAI Agents framework (modern) --- common/py/openai_agents.py | 87 ++++++++++++++++++++++++++++++++++++++ common/py/swarm.py | 55 ------------------------ python-uv/templates.yaml | 30 +++++++------ 3 files changed, 103 insertions(+), 69 deletions(-) create mode 100644 common/py/openai_agents.py delete mode 100644 common/py/swarm.py diff --git a/common/py/openai_agents.py b/common/py/openai_agents.py new file mode 100644 index 0000000..050194b --- /dev/null +++ b/common/py/openai_agents.py @@ -0,0 +1,87 @@ +from agentuity import AgentRequest, AgentResponse, AgentContext +from agents import Agent, InputGuardrail, GuardrailFunctionOutput, Runner +from pydantic import BaseModel + +class QueryClassification(BaseModel): + is_valid: bool + category: str + reasoning: str + +# Define the classification agent for input validation +classification_agent = Agent( + name="Query Classifier", + instructions="Classify user queries and determine if they are valid and what category they belong to.", + output_type=QueryClassification, +) + +# Define specialist agents +general_assistant_agent = Agent( + name="General Assistant", + handoff_description="General purpose assistant for various queries", + instructions="You are a helpful general assistant that can answer a wide variety of questions with accuracy and clarity.", +) + +technical_agent = Agent( + name="Technical Specialist", + handoff_description="Technical specialist for programming and technical questions", + instructions="You are a technical specialist who helps with programming, software development, and technical problem-solving. Provide detailed explanations and code examples when appropriate.", +) + +# Create guardrail function for input validation +async def query_validation_guardrail(ctx, agent, input_data): + result = await Runner.run(classification_agent, input_data, context=ctx) + classification = result.final_output_as(QueryClassification) + return GuardrailFunctionOutput( + output_info=classification, + tripwire_triggered=not classification.is_valid, + ) + +# Main triage agent that routes queries to specialist agents +triage_agent = Agent( + name="Triage Agent", + instructions="You determine which specialist agent to use based on the user's query. Route technical questions to the Technical Specialist and general questions to the General Assistant.", + handoffs=[general_assistant_agent, technical_agent], + input_guardrails=[ + InputGuardrail(guardrail_function=query_validation_guardrail), + ], +) + +def welcome(): + return { + "welcome": "Welcome to the OpenAI Agents framework! I use multiple specialized agents to handle different types of queries with handoffs and guardrails for better responses.", + "prompts": [ + { + "data": "How do I build a REST API with Python?", + "contentType": "text/plain" + }, + { + "data": "What's the weather like today?", + "contentType": "text/plain" + }, + { + "data": "Explain how machine learning works", + "contentType": "text/plain" + } + ] + } + +async def run(request: AgentRequest, response: AgentResponse, context: AgentContext): + try: + # Extract the user's question from the request + user_question = await request.data.text() + + # Log the incoming request + context.logger.info("Processing question with OpenAI Agents: %s", user_question) + + # Run the OpenAI Agents workflow + result = await Runner.run(triage_agent, user_question, context=context) + + # Log the result + context.logger.info("OpenAI Agents workflow completed successfully") + + # Return the response from the OpenAI Agents workflow + return response.text(str(result.final_output)) + + except Exception as e: + context.logger.error("Error in OpenAI Agents workflow: %s", str(e)) + return response.text(f"Sorry, I encountered an error processing your request: {str(e)}") diff --git a/common/py/swarm.py b/common/py/swarm.py deleted file mode 100644 index aace0d5..0000000 --- a/common/py/swarm.py +++ /dev/null @@ -1,55 +0,0 @@ -from agentuity import AgentRequest, AgentResponse, AgentContext -from swarm import Swarm, Agent - -# Initialize the Swarm client -client = Swarm() - -def welcome(): - return { - "welcome": "Welcome to the OpenAI Swarm Agent! I can help you build multi-agent orchestration systems with lightweight agent handoffs.", - "prompts": [ - { - "data": "Show me how agents can hand off conversations to each other", - "contentType": "text/plain" - }, - { - "data": "What are the best practices for designing multi-agent workflows?", - "contentType": "text/plain" - } - ] - } - -# Helper agent that can handle specialized tasks -def transfer_to_specialist(): - return specialist_agent - -# Main conversational agent -main_agent = Agent( - name="Main Agent", - instructions="You are a helpful assistant. If the user asks for specialized help or complex analysis, transfer them to the specialist agent using the transfer_to_specialist function.", - functions=[transfer_to_specialist], -) - -# Specialist agent for complex queries -specialist_agent = Agent( - name="Specialist Agent", - instructions="You are a specialist agent with deep expertise. Provide detailed, technical responses and thorough analysis.", -) - -async def run(request: AgentRequest, response: AgentResponse, context: AgentContext): - try: - user_message = await request.data.text() or "Hello! I'd like to learn about OpenAI Swarm." - - # Run the swarm with the main agent - swarm_response = client.run( - agent=main_agent, - messages=[{"role": "user", "content": user_message}], - ) - - # Get the final message from the conversation - final_message = swarm_response.messages[-1]["content"] - - return response.text(final_message) - except Exception as e: - context.logger.error(f"Error running Swarm agent: {e}") - return response.text("Sorry, there was an error processing your request with the Swarm agents.") diff --git a/python-uv/templates.yaml b/python-uv/templates.yaml index eaca640..52444c3 100644 --- a/python-uv/templates.yaml +++ b/python-uv/templates.yaml @@ -120,20 +120,6 @@ - action: create_file filename: "agentuity_agents/{{ .AgentName | safe_filename }}/__init__.py" template: "common/py/init.py" -- name: "OpenAI Swarm" - description: "OpenAI Swarm is an educational framework for building lightweight multi-agent orchestration systems." - steps: - - command: uv - args: - - add - - --quiet - - git+https://github.com/openai/swarm.git - - action: create_file - filename: "agentuity_agents/{{ .AgentName | safe_filename }}/agent.py" - from: "common/py/swarm.py" - - action: create_file - filename: "agentuity_agents/{{ .AgentName | safe_filename }}/__init__.py" - template: "common/py/init.py" - name: "AutoGen" description: "Microsoft AutoGen is a framework for building multi-agent conversational AI applications." steps: @@ -209,3 +195,19 @@ - action: create_file filename: "agentuity_agents/{{ .AgentName | safe_filename }}/__init__.py" template: "common/py/init.py" +- name: "OpenAI Agents" + description: "OpenAI Agents framework for building multi-agent systems with handoffs, guardrails, and specialization." + steps: + - command: uv + args: + - add + - --quiet + - openai>=1.82.0 + - git+https://github.com/openai/openai-agents-python.git + - pydantic + - action: create_file + filename: "agentuity_agents/{{ .AgentName | safe_filename }}/agent.py" + from: "common/py/openai_agents.py" + - action: create_file + filename: "agentuity_agents/{{ .AgentName | safe_filename }}/__init__.py" + template: "common/py/init.py" From 212cdf196508b0602d8ec209417bccb406c8038c Mon Sep 17 00:00:00 2001 From: Jeff Haynie Date: Tue, 19 Aug 2025 08:42:15 -0700 Subject: [PATCH 2/2] fix and test code rabbit feedback --- common/py/openai_agents.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/py/openai_agents.py b/common/py/openai_agents.py index 050194b..1e559c4 100644 --- a/common/py/openai_agents.py +++ b/common/py/openai_agents.py @@ -1,5 +1,5 @@ from agentuity import AgentRequest, AgentResponse, AgentContext -from agents import Agent, InputGuardrail, GuardrailFunctionOutput, Runner +from agents import Agent, Runner, InputGuardrail, GuardrailFunctionOutput from pydantic import BaseModel class QueryClassification(BaseModel):