1- from typing import Any , List , Optional
1+ """OpenAI agents adapter for CrewAI integration.
22
3- from pydantic import Field , PrivateAttr
3+ This module contains the OpenAIAgentAdapter class that integrates OpenAI Assistants
4+ with CrewAI's agent system, providing tool integration and structured output support.
5+ """
6+
7+ from typing import Any , cast
8+
9+ from pydantic import ConfigDict , Field , PrivateAttr
10+ from typing_extensions import Unpack
411
512from crewai .agents .agent_adapters .base_agent_adapter import BaseAgentAdapter
13+ from crewai .agents .agent_adapters .openai_agents .openai_agent_tool_adapter import (
14+ OpenAIAgentToolAdapter ,
15+ )
16+ from crewai .agents .agent_adapters .openai_agents .protocols import (
17+ AgentKwargs ,
18+ OpenAIAgentsModule ,
19+ )
20+ from crewai .agents .agent_adapters .openai_agents .protocols import (
21+ OpenAIAgent as OpenAIAgentProtocol ,
22+ )
623from crewai .agents .agent_adapters .openai_agents .structured_output_converter import (
724 OpenAIConverterAdapter ,
825)
926from crewai .agents .agent_builder .base_agent import BaseAgent
10- from crewai .tools import BaseTool
11- from crewai .tools .agent_tools .agent_tools import AgentTools
12- from crewai .utilities import Logger
1327from crewai .events .event_bus import crewai_event_bus
1428from crewai .events .types .agent_events import (
1529 AgentExecutionCompletedEvent ,
1630 AgentExecutionErrorEvent ,
1731 AgentExecutionStartedEvent ,
1832)
19-
20- try :
21- from agents import Agent as OpenAIAgent # type: ignore
22- from agents import Runner , enable_verbose_stdout_logging # type: ignore
23-
24- from .openai_agent_tool_adapter import OpenAIAgentToolAdapter
25-
26- OPENAI_AVAILABLE = True
27- except ImportError :
28- OPENAI_AVAILABLE = False
33+ from crewai .tools import BaseTool
34+ from crewai .tools .agent_tools .agent_tools import AgentTools
35+ from crewai .utilities import Logger
36+ from crewai .utilities .import_utils import require
37+
38+ openai_agents_module = cast (
39+ OpenAIAgentsModule ,
40+ require (
41+ "agents" ,
42+ purpose = "OpenAI agents functionality" ,
43+ ),
44+ )
45+ OpenAIAgent = openai_agents_module .Agent
46+ Runner = openai_agents_module .Runner
47+ enable_verbose_stdout_logging = openai_agents_module .enable_verbose_stdout_logging
2948
3049
3150class OpenAIAgentAdapter (BaseAgentAdapter ):
32- """Adapter for OpenAI Assistants"""
51+ """Adapter for OpenAI Assistants.
52+
53+ Integrates OpenAI Assistants API with CrewAI's agent system, providing
54+ tool configuration, structured output handling, and task execution.
55+ """
3356
34- model_config = { " arbitrary_types_allowed" : True }
57+ model_config = ConfigDict ( arbitrary_types_allowed = True )
3558
36- _openai_agent : "OpenAIAgent" = PrivateAttr ()
37- _logger : Logger = PrivateAttr (default_factory = lambda : Logger () )
38- _active_thread : Optional [ str ] = PrivateAttr (default = None )
59+ _openai_agent : OpenAIAgentProtocol = PrivateAttr ()
60+ _logger : Logger = PrivateAttr (default_factory = Logger )
61+ _active_thread : str | None = PrivateAttr (default = None )
3962 function_calling_llm : Any = Field (default = None )
4063 step_callback : Any = Field (default = None )
41- _tool_adapter : " OpenAIAgentToolAdapter" = PrivateAttr ()
64+ _tool_adapter : OpenAIAgentToolAdapter = PrivateAttr ()
4265 _converter_adapter : OpenAIConverterAdapter = PrivateAttr ()
4366
4467 def __init__ (
4568 self ,
46- model : str = "gpt-4o-mini" ,
47- tools : Optional [List [BaseTool ]] = None ,
48- agent_config : Optional [dict ] = None ,
49- ** kwargs ,
50- ):
51- if not OPENAI_AVAILABLE :
52- raise ImportError (
53- "OpenAI Agent Dependencies are not installed. Please install it using `uv add openai-agents`"
54- )
55- else :
56- role = kwargs .pop ("role" , None )
57- goal = kwargs .pop ("goal" , None )
58- backstory = kwargs .pop ("backstory" , None )
59- super ().__init__ (
60- role = role ,
61- goal = goal ,
62- backstory = backstory ,
63- tools = tools ,
64- agent_config = agent_config ,
65- ** kwargs ,
66- )
67- self ._tool_adapter = OpenAIAgentToolAdapter (tools = tools )
68- self .llm = model
69- self ._converter_adapter = OpenAIConverterAdapter (self )
69+ ** kwargs : Unpack [AgentKwargs ],
70+ ) -> None :
71+ """Initialize the OpenAI agent adapter.
72+
73+ Args:
74+ **kwargs: All initialization arguments including role, goal, backstory,
75+ model, tools, and agent_config.
76+
77+ Raises:
78+ ImportError: If OpenAI agent dependencies are not installed.
79+ """
80+ super ().__init__ (** kwargs )
81+ self ._tool_adapter = OpenAIAgentToolAdapter (tools = kwargs .get ("tools" ))
82+ self .llm = kwargs .get ("model" , "gpt-4o-mini" )
83+ self ._converter_adapter = OpenAIConverterAdapter (agent_adapter = self )
7084
7185 def _build_system_prompt (self ) -> str :
72- """Build a system prompt for the OpenAI agent."""
86+ """Build a system prompt for the OpenAI agent.
87+
88+ Creates a prompt containing the agent's role, goal, and backstory,
89+ then enhances it with structured output instructions if needed.
90+
91+ Returns:
92+ The complete system prompt string.
93+ """
7394 base_prompt = f"""
7495 You are { self .role } .
75-
96+
7697 Your goal is: { self .goal }
7798
7899 Your backstory: { self .backstory }
@@ -84,18 +105,33 @@ def _build_system_prompt(self) -> str:
84105 def execute_task (
85106 self ,
86107 task : Any ,
87- context : Optional [ str ] = None ,
88- tools : Optional [ List [ BaseTool ]] = None ,
108+ context : str | None = None ,
109+ tools : list [ BaseTool ] | None = None ,
89110 ) -> str :
90- """Execute a task using the OpenAI Assistant"""
111+ """Execute a task using the OpenAI Assistant.
112+
113+ Configures the assistant, processes the task, and handles event emission
114+ for execution tracking.
115+
116+ Args:
117+ task: The task object to execute.
118+ context: Optional context information for the task.
119+ tools: Optional additional tools for this execution.
120+
121+ Returns:
122+ The final answer from the task execution.
123+
124+ Raises:
125+ Exception: If task execution fails.
126+ """
91127 self ._converter_adapter .configure_structured_output (task )
92128 self .create_agent_executor (tools )
93129
94130 if self .verbose :
95131 enable_verbose_stdout_logging ()
96132
97133 try :
98- task_prompt = task .prompt ()
134+ task_prompt : str = task .prompt ()
99135 if context :
100136 task_prompt = self .i18n .slice ("task_with_context" ).format (
101137 task = task_prompt , context = context
@@ -109,8 +145,8 @@ def execute_task(
109145 task = task ,
110146 ),
111147 )
112- result = self .agent_executor .run_sync (self ._openai_agent , task_prompt )
113- final_answer = self .handle_execution_result (result )
148+ result : Any = self .agent_executor .run_sync (self ._openai_agent , task_prompt )
149+ final_answer : str = self .handle_execution_result (result )
114150 crewai_event_bus .emit (
115151 self ,
116152 event = AgentExecutionCompletedEvent (
@@ -120,7 +156,7 @@ def execute_task(
120156 return final_answer
121157
122158 except Exception as e :
123- self ._logger .log ("error" , f"Error executing OpenAI task: { str ( e ) } " )
159+ self ._logger .log ("error" , f"Error executing OpenAI task: { e !s } " )
124160 crewai_event_bus .emit (
125161 self ,
126162 event = AgentExecutionErrorEvent (
@@ -131,15 +167,22 @@ def execute_task(
131167 )
132168 raise
133169
134- def create_agent_executor (self , tools : Optional [ List [ BaseTool ]] = None ) -> None :
135- """
136- Configure the OpenAI agent for execution.
170+ def create_agent_executor (self , tools : list [ BaseTool ] | None = None ) -> None :
171+ """Configure the OpenAI agent for execution.
172+
137173 While OpenAI handles execution differently through Runner,
138- we can use this method to set up tools and configurations.
174+ this method sets up tools and agent configuration.
175+
176+ Args:
177+ tools: Optional tools to configure for the agent.
178+
179+ Notes:
180+ TODO: Properly type agent_executor in BaseAgent to avoid type issues
181+ when assigning Runner class to this attribute.
139182 """
140- all_tools = list (self .tools or []) + list (tools or [])
183+ all_tools : list [ BaseTool ] = list (self .tools or []) + list (tools or [])
141184
142- instructions = self ._build_system_prompt ()
185+ instructions : str = self ._build_system_prompt ()
143186 self ._openai_agent = OpenAIAgent (
144187 name = self .role ,
145188 instructions = instructions ,
@@ -152,27 +195,48 @@ def create_agent_executor(self, tools: Optional[List[BaseTool]] = None) -> None:
152195
153196 self .agent_executor = Runner
154197
155- def configure_tools (self , tools : Optional [List [BaseTool ]] = None ) -> None :
156- """Configure tools for the OpenAI Assistant"""
198+ def configure_tools (self , tools : list [BaseTool ] | None = None ) -> None :
199+ """Configure tools for the OpenAI Assistant.
200+
201+ Args:
202+ tools: Optional tools to configure for the assistant.
203+ """
157204 if tools :
158205 self ._tool_adapter .configure_tools (tools )
159206 if self ._tool_adapter .converted_tools :
160207 self ._openai_agent .tools = self ._tool_adapter .converted_tools
161208
162209 def handle_execution_result (self , result : Any ) -> str :
163- """Process OpenAI Assistant execution result converting any structured output to a string"""
210+ """Process OpenAI Assistant execution result.
211+
212+ Converts any structured output to a string through the converter adapter.
213+
214+ Args:
215+ result: The execution result from the OpenAI assistant.
216+
217+ Returns:
218+ Processed result as a string.
219+ """
164220 return self ._converter_adapter .post_process_result (result .final_output )
165221
166- def get_delegation_tools (self , agents : List [BaseAgent ]) -> List [BaseTool ]:
167- """Implement delegation tools support"""
168- agent_tools = AgentTools (agents = agents )
169- tools = agent_tools .tools ()
170- return tools
222+ def get_delegation_tools (self , agents : list [BaseAgent ]) -> list [BaseTool ]:
223+ """Implement delegation tools support.
224+
225+ Creates delegation tools that allow this agent to delegate tasks to other agents.
226+
227+ Args:
228+ agents: List of agents available for delegation.
229+
230+ Returns:
231+ List of delegation tools.
232+ """
233+ agent_tools : AgentTools = AgentTools (agents = agents )
234+ return agent_tools .tools ()
171235
172- def configure_structured_output (self , task ) -> None :
236+ def configure_structured_output (self , task : Any ) -> None :
173237 """Configure the structured output for the specific agent implementation.
174238
175239 Args:
176- structured_output : The structured output to be configured
240+ task : The task object containing output format specifications.
177241 """
178242 self ._converter_adapter .configure_structured_output (task )
0 commit comments