10
10
import asyncio
11
11
import inspect
12
12
from collections .abc import Awaitable
13
- from typing import TYPE_CHECKING , Any , Callable , Generic , Literal , Union , cast
13
+ from typing import TYPE_CHECKING , Any , Callable , Generic , Literal , cast
14
14
15
15
from openai .types .responses .response_prompt_param import ResponsePromptParam
16
16
from pydantic import BaseModel , ConfigDict , Field , field_validator , model_validator
36
36
class ToolsToFinalOutputResult (BaseModel ):
37
37
"""
38
38
Result object for tool-to-final output processing.
39
-
39
+
40
40
Attributes:
41
41
is_final_output: Whether this is the final output. If False, the LLM will run again.
42
42
final_output: The final output value, if is_final_output is True.
43
43
"""
44
-
44
+
45
45
model_config = ConfigDict (
46
- arbitrary_types_allowed = True ,
47
- validate_assignment = True ,
48
- extra = 'forbid' ,
49
- frozen = True
46
+ arbitrary_types_allowed = True , validate_assignment = True , extra = "forbid" , frozen = True
50
47
)
51
-
48
+
52
49
is_final_output : bool = Field (
53
50
..., # Required field
54
- description = "Whether this is the final output. If False, the LLM will run again."
51
+ description = "Whether this is the final output. If False, the LLM will run again." ,
55
52
)
56
53
final_output : Any | None = Field (
57
- default = None ,
58
- description = "The final output value, if is_final_output is True."
54
+ default = None , description = "The final output value, if is_final_output is True."
59
55
)
60
-
61
- @field_validator (' is_final_output' )
56
+
57
+ @field_validator (" is_final_output" )
62
58
@classmethod
63
59
def validate_is_final_output (cls , v : Any ) -> bool :
64
60
"""Validate is_final_output is a boolean value."""
@@ -79,27 +75,29 @@ def validate_is_final_output(cls, v: Any) -> bool:
79
75
80
76
class StopAtTools (TypedDict ):
81
77
"""Configuration for stopping agent execution at specific tools."""
78
+
82
79
stop_at_tool_names : list [str ]
83
80
84
81
85
82
class MCPConfig (TypedDict ):
86
83
"""Configuration for Model Context Protocol servers."""
84
+
87
85
convert_schemas_to_strict : NotRequired [bool ]
88
86
89
87
90
88
def is_stop_at_tools_dict (v : dict ) -> bool :
91
89
"""
92
90
Validate if a dictionary matches the StopAtTools structure.
93
-
91
+
94
92
Args:
95
93
v: Dictionary to validate
96
-
94
+
97
95
Returns:
98
96
bool: True if dictionary is valid StopAtTools structure
99
97
"""
100
98
return (
101
- isinstance (v , dict )
102
- and "stop_at_tool_names" in v
99
+ isinstance (v , dict )
100
+ and "stop_at_tool_names" in v
103
101
and isinstance (v ["stop_at_tool_names" ], list )
104
102
and all (isinstance (x , str ) for x in v ["stop_at_tool_names" ])
105
103
)
@@ -108,77 +106,71 @@ def is_stop_at_tools_dict(v: dict) -> bool:
108
106
class AgentBase (BaseModel , Generic [TContext ]):
109
107
"""
110
108
Base class for Agent implementations providing core functionality.
111
-
109
+
112
110
This class implements the base agent functionality including tool management,
113
111
MCP server configuration, and validation.
114
-
112
+
115
113
Attributes:
116
114
name: The name of the agent
117
115
handoff_description: Optional description for handoff functionality
118
116
tools: List of available tools
119
117
mcp_servers: List of MCP servers
120
118
mcp_config: Configuration for MCP servers
121
119
"""
122
-
120
+
123
121
model_config = ConfigDict (
124
122
arbitrary_types_allowed = True ,
125
123
validate_assignment = True ,
126
- extra = ' forbid' ,
124
+ extra = " forbid" ,
127
125
frozen = True ,
128
- defer_build = True
126
+ defer_build = True ,
129
127
)
130
128
131
129
name : str = Field (
132
130
..., # Required field
133
- description = "The name of the agent."
131
+ description = "The name of the agent." ,
134
132
)
135
133
handoff_description : str | None = Field (
136
- default = None ,
137
- description = "Description used when the agent is used as a handoff."
134
+ default = None , description = "Description used when the agent is used as a handoff."
138
135
)
139
136
tools : list [Tool ] = Field (
140
- default_factory = list ,
141
- description = "List of tools available to the agent."
137
+ default_factory = list , description = "List of tools available to the agent."
142
138
)
143
139
mcp_servers : list [Any ] = Field (
144
- default_factory = list ,
145
- description = "List of MCP servers available to the agent."
140
+ default_factory = list , description = "List of MCP servers available to the agent."
146
141
)
147
142
mcp_config : dict [str , Any ] = Field (
148
143
default_factory = lambda : {"convert_schemas_to_strict" : False },
149
- description = "MCP configuration settings."
144
+ description = "MCP configuration settings." ,
150
145
)
151
146
152
147
# ... (validators remain the same but with improved docstrings) ...
153
148
154
149
async def get_mcp_tools (self , run_context : RunContextWrapper [TContext ]) -> list [Tool ]:
155
150
"""
156
151
Fetch available tools from MCP servers.
157
-
152
+
158
153
Args:
159
154
run_context: Current run context wrapper
160
-
155
+
161
156
Returns:
162
157
list[Tool]: List of available MCP tools
163
158
"""
164
159
convert_schemas_to_strict = self .mcp_config .get ("convert_schemas_to_strict" , False )
165
160
if not self .mcp_servers :
166
161
return []
167
-
162
+
168
163
return await MCPUtil .get_all_function_tools (
169
- self .mcp_servers ,
170
- convert_schemas_to_strict ,
171
- run_context ,
172
- self
164
+ self .mcp_servers , convert_schemas_to_strict , run_context , self
173
165
)
174
166
175
167
async def get_all_tools (self , run_context : RunContextWrapper [Any ]) -> list [Tool ]:
176
168
"""
177
169
Get all available tools, including MCP tools and function tools.
178
-
170
+
179
171
Args:
180
172
run_context: Current run context wrapper
181
-
173
+
182
174
Returns:
183
175
list[Tool]: Combined list of available tools
184
176
"""
@@ -205,10 +197,10 @@ async def _check_tool_enabled(tool: Tool) -> bool:
205
197
class Agent (AgentBase , Generic [TContext ]):
206
198
"""
207
199
Primary agent implementation with full configuration and behavior support.
208
-
200
+
209
201
This class extends AgentBase with additional functionality for instructions,
210
202
prompts, guardrails, and tool behavior configuration.
211
-
203
+
212
204
Attributes:
213
205
instructions: Agent instructions/system prompt
214
206
prompt: Prompt configuration
@@ -222,94 +214,73 @@ class Agent(AgentBase, Generic[TContext]):
222
214
tool_use_behavior: Tool usage configuration
223
215
reset_tool_choice: Tool choice reset behavior
224
216
"""
225
-
217
+
226
218
model_config = ConfigDict (
227
219
arbitrary_types_allowed = True ,
228
220
validate_assignment = True ,
229
- extra = ' forbid' ,
221
+ extra = " forbid" ,
230
222
frozen = True ,
231
- defer_build = True
223
+ defer_build = True ,
232
224
)
233
225
234
226
instructions : (
235
227
str
236
228
| Callable [
237
- [RunContextWrapper [TContext ], ' Agent[TContext]' ],
229
+ [RunContextWrapper [TContext ], Agent [TContext ]],
238
230
MaybeAwaitable [str ],
239
231
]
240
232
| None
241
- ) = Field (
242
- default = None ,
243
- description = "The instructions/system prompt for the agent."
244
- )
233
+ ) = Field (default = None , description = "The instructions/system prompt for the agent." )
245
234
246
235
prompt : Prompt | DynamicPromptFunction | None = Field (
247
- default = None ,
248
- description = "Prompt configuration for the agent."
236
+ default = None , description = "Prompt configuration for the agent."
249
237
)
250
238
251
239
handoffs : list [Any ] = Field (
252
- default_factory = list ,
253
- description = "List of sub-agents for delegation."
240
+ default_factory = list , description = "List of sub-agents for delegation."
254
241
)
255
242
256
- model : str | Model | None = Field (
257
- default = None ,
258
- description = "Model implementation to use."
259
- )
243
+ model : str | Model | None = Field (default = None , description = "Model implementation to use." )
260
244
261
245
model_settings : ModelSettings = Field (
262
- default_factory = ModelSettings ,
263
- description = "Model-specific configuration."
246
+ default_factory = ModelSettings , description = "Model-specific configuration."
264
247
)
265
248
266
249
input_guardrails : list [InputGuardrail [TContext ]] = Field (
267
- default_factory = list ,
268
- description = "Pre-execution validation checks."
250
+ default_factory = list , description = "Pre-execution validation checks."
269
251
)
270
252
271
253
output_guardrails : list [OutputGuardrail [TContext ]] = Field (
272
- default_factory = list ,
273
- description = "Post-execution validation checks."
254
+ default_factory = list , description = "Post-execution validation checks."
274
255
)
275
256
276
257
output_type : type [Any ] | AgentOutputSchemaBase | None = Field (
277
- default = None ,
278
- description = "Output type specification."
258
+ default = None , description = "Output type specification."
279
259
)
280
260
281
- hooks : Any | None = Field (
282
- default = None ,
283
- description = "Lifecycle event callbacks."
284
- )
261
+ hooks : Any | None = Field (default = None , description = "Lifecycle event callbacks." )
285
262
286
- tool_use_behavior : Union [
287
- Literal ["run_llm_again" , "stop_on_first_tool" ],
288
- StopAtTools ,
289
- ToolsToFinalOutputFunction
290
- ] = Field (
291
- default = "run_llm_again" ,
292
- description = "Tool usage behavior configuration."
293
- )
263
+ tool_use_behavior : (
264
+ Literal ["run_llm_again" , "stop_on_first_tool" ] | StopAtTools | ToolsToFinalOutputFunction
265
+ ) = Field (default = "run_llm_again" , description = "Tool usage behavior configuration." )
294
266
295
267
reset_tool_choice : bool = Field (
296
- default = True ,
297
- description = "Whether to reset tool choice after use."
268
+ default = True , description = "Whether to reset tool choice after use."
298
269
)
299
270
300
271
# ... (validators remain the same but with improved docstrings) ...
301
272
302
- @model_validator (mode = ' after' )
303
- def validate_model_configuration (self ) -> ' Agent' :
273
+ @model_validator (mode = " after" )
274
+ def validate_model_configuration (self ) -> Agent :
304
275
"""
305
276
Validate complete model configuration.
306
-
277
+
307
278
This validator ensures that the model configuration is consistent,
308
279
particularly the relationship between model and prompt settings.
309
-
280
+
310
281
Returns:
311
282
Agent: The validated agent instance
312
-
283
+
313
284
Raises:
314
285
ValueError: If validation fails
315
286
"""
@@ -320,13 +291,13 @@ def validate_model_configuration(self) -> 'Agent':
320
291
def clone (self , ** kwargs : Any ) -> Agent [TContext ]:
321
292
"""
322
293
Create a copy of the agent with specified modifications.
323
-
294
+
324
295
Args:
325
296
**kwargs: Fields to override in the new instance
326
-
297
+
327
298
Returns:
328
299
Agent[TContext]: New agent instance with specified changes
329
-
300
+
330
301
Note:
331
302
This performs a shallow copy. Mutable attributes like tools and
332
303
handoffs are shallow-copied.
@@ -341,15 +312,16 @@ def as_tool(
341
312
) -> Tool :
342
313
"""
343
314
Convert this agent into a tool callable by other agents.
344
-
315
+
345
316
Args:
346
317
tool_name: Name for the tool (defaults to agent name)
347
318
tool_description: Description of the tool's functionality
348
319
custom_output_extractor: Custom function to extract output
349
-
320
+
350
321
Returns:
351
322
Tool: Tool instance wrapping this agent
352
323
"""
324
+
353
325
@function_tool (
354
326
name_override = tool_name or _transforms .transform_string_function_style (self .name ),
355
327
description_override = tool_description or "" ,
@@ -372,13 +344,13 @@ async def run_agent(context: RunContextWrapper, input: str) -> str:
372
344
async def get_system_prompt (self , run_context : RunContextWrapper [TContext ]) -> str | None :
373
345
"""
374
346
Get the system prompt for the agent.
375
-
347
+
376
348
Args:
377
349
run_context: Current run context
378
-
350
+
379
351
Returns:
380
352
str | None: System prompt if available
381
-
353
+
382
354
Note:
383
355
Handles both static strings and dynamic prompt generation.
384
356
"""
@@ -397,10 +369,10 @@ async def get_prompt(
397
369
) -> ResponsePromptParam | None :
398
370
"""
399
371
Get the prompt configuration for the agent.
400
-
372
+
401
373
Args:
402
374
run_context: Current run context
403
-
375
+
404
376
Returns:
405
377
ResponsePromptParam | None: Prompt configuration if available
406
378
"""
0 commit comments