openai-agents 0.2.8__py3-none-any.whl → 0.6.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agents/__init__.py +105 -4
- agents/_debug.py +15 -4
- agents/_run_impl.py +1203 -96
- agents/agent.py +164 -19
- agents/apply_diff.py +329 -0
- agents/editor.py +47 -0
- agents/exceptions.py +35 -0
- agents/extensions/experimental/__init__.py +6 -0
- agents/extensions/experimental/codex/__init__.py +92 -0
- agents/extensions/experimental/codex/codex.py +89 -0
- agents/extensions/experimental/codex/codex_options.py +35 -0
- agents/extensions/experimental/codex/codex_tool.py +1142 -0
- agents/extensions/experimental/codex/events.py +162 -0
- agents/extensions/experimental/codex/exec.py +263 -0
- agents/extensions/experimental/codex/items.py +245 -0
- agents/extensions/experimental/codex/output_schema_file.py +50 -0
- agents/extensions/experimental/codex/payloads.py +31 -0
- agents/extensions/experimental/codex/thread.py +214 -0
- agents/extensions/experimental/codex/thread_options.py +54 -0
- agents/extensions/experimental/codex/turn_options.py +36 -0
- agents/extensions/handoff_filters.py +13 -1
- agents/extensions/memory/__init__.py +120 -0
- agents/extensions/memory/advanced_sqlite_session.py +1285 -0
- agents/extensions/memory/async_sqlite_session.py +239 -0
- agents/extensions/memory/dapr_session.py +423 -0
- agents/extensions/memory/encrypt_session.py +185 -0
- agents/extensions/memory/redis_session.py +261 -0
- agents/extensions/memory/sqlalchemy_session.py +334 -0
- agents/extensions/models/litellm_model.py +449 -36
- agents/extensions/models/litellm_provider.py +3 -1
- agents/function_schema.py +47 -5
- agents/guardrail.py +16 -2
- agents/{handoffs.py → handoffs/__init__.py} +89 -47
- agents/handoffs/history.py +268 -0
- agents/items.py +237 -11
- agents/lifecycle.py +75 -14
- agents/mcp/server.py +280 -37
- agents/mcp/util.py +24 -3
- agents/memory/__init__.py +22 -2
- agents/memory/openai_conversations_session.py +91 -0
- agents/memory/openai_responses_compaction_session.py +249 -0
- agents/memory/session.py +19 -261
- agents/memory/sqlite_session.py +275 -0
- agents/memory/util.py +20 -0
- agents/model_settings.py +14 -3
- agents/models/__init__.py +13 -0
- agents/models/chatcmpl_converter.py +303 -50
- agents/models/chatcmpl_helpers.py +63 -0
- agents/models/chatcmpl_stream_handler.py +290 -68
- agents/models/default_models.py +58 -0
- agents/models/interface.py +4 -0
- agents/models/openai_chatcompletions.py +103 -49
- agents/models/openai_provider.py +10 -4
- agents/models/openai_responses.py +162 -46
- agents/realtime/__init__.py +4 -0
- agents/realtime/_util.py +14 -3
- agents/realtime/agent.py +7 -0
- agents/realtime/audio_formats.py +53 -0
- agents/realtime/config.py +78 -10
- agents/realtime/events.py +18 -0
- agents/realtime/handoffs.py +2 -2
- agents/realtime/items.py +17 -1
- agents/realtime/model.py +13 -0
- agents/realtime/model_events.py +12 -0
- agents/realtime/model_inputs.py +18 -1
- agents/realtime/openai_realtime.py +696 -150
- agents/realtime/session.py +243 -23
- agents/repl.py +7 -3
- agents/result.py +197 -38
- agents/run.py +949 -168
- agents/run_context.py +13 -2
- agents/stream_events.py +1 -0
- agents/strict_schema.py +14 -0
- agents/tool.py +413 -15
- agents/tool_context.py +22 -1
- agents/tool_guardrails.py +279 -0
- agents/tracing/__init__.py +2 -0
- agents/tracing/config.py +9 -0
- agents/tracing/create.py +4 -0
- agents/tracing/processor_interface.py +84 -11
- agents/tracing/processors.py +65 -54
- agents/tracing/provider.py +64 -7
- agents/tracing/spans.py +105 -0
- agents/tracing/traces.py +116 -16
- agents/usage.py +134 -12
- agents/util/_json.py +19 -1
- agents/util/_transforms.py +12 -2
- agents/voice/input.py +5 -4
- agents/voice/models/openai_stt.py +17 -9
- agents/voice/pipeline.py +2 -0
- agents/voice/pipeline_config.py +4 -0
- {openai_agents-0.2.8.dist-info → openai_agents-0.6.8.dist-info}/METADATA +44 -19
- openai_agents-0.6.8.dist-info/RECORD +134 -0
- {openai_agents-0.2.8.dist-info → openai_agents-0.6.8.dist-info}/WHEEL +1 -1
- openai_agents-0.2.8.dist-info/RECORD +0 -103
- {openai_agents-0.2.8.dist-info → openai_agents-0.6.8.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
from ...models.default_models import get_default_model
|
|
1
2
|
from ...models.interface import Model, ModelProvider
|
|
2
3
|
from .litellm_model import LitellmModel
|
|
3
4
|
|
|
5
|
+
# This is kept for backward compatiblity but using get_default_model() method is recommended.
|
|
4
6
|
DEFAULT_MODEL: str = "gpt-4.1"
|
|
5
7
|
|
|
6
8
|
|
|
@@ -18,4 +20,4 @@ class LitellmProvider(ModelProvider):
|
|
|
18
20
|
"""
|
|
19
21
|
|
|
20
22
|
def get_model(self, model_name: str | None) -> Model:
|
|
21
|
-
return LitellmModel(model_name or
|
|
23
|
+
return LitellmModel(model_name or get_default_model())
|
agents/function_schema.py
CHANGED
|
@@ -5,7 +5,7 @@ import inspect
|
|
|
5
5
|
import logging
|
|
6
6
|
import re
|
|
7
7
|
from dataclasses import dataclass
|
|
8
|
-
from typing import Any, Callable, Literal, get_args, get_origin, get_type_hints
|
|
8
|
+
from typing import Annotated, Any, Callable, Literal, get_args, get_origin, get_type_hints
|
|
9
9
|
|
|
10
10
|
from griffe import Docstring, DocstringSectionKind
|
|
11
11
|
from pydantic import BaseModel, Field, create_model
|
|
@@ -185,6 +185,31 @@ def generate_func_documentation(
|
|
|
185
185
|
)
|
|
186
186
|
|
|
187
187
|
|
|
188
|
+
def _strip_annotated(annotation: Any) -> tuple[Any, tuple[Any, ...]]:
|
|
189
|
+
"""Returns the underlying annotation and any metadata from typing.Annotated."""
|
|
190
|
+
|
|
191
|
+
metadata: tuple[Any, ...] = ()
|
|
192
|
+
ann = annotation
|
|
193
|
+
|
|
194
|
+
while get_origin(ann) is Annotated:
|
|
195
|
+
args = get_args(ann)
|
|
196
|
+
if not args:
|
|
197
|
+
break
|
|
198
|
+
ann = args[0]
|
|
199
|
+
metadata = (*metadata, *args[1:])
|
|
200
|
+
|
|
201
|
+
return ann, metadata
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _extract_description_from_metadata(metadata: tuple[Any, ...]) -> str | None:
|
|
205
|
+
"""Extracts a human readable description from Annotated metadata if present."""
|
|
206
|
+
|
|
207
|
+
for item in metadata:
|
|
208
|
+
if isinstance(item, str):
|
|
209
|
+
return item
|
|
210
|
+
return None
|
|
211
|
+
|
|
212
|
+
|
|
188
213
|
def function_schema(
|
|
189
214
|
func: Callable[..., Any],
|
|
190
215
|
docstring_style: DocstringStyle | None = None,
|
|
@@ -219,17 +244,34 @@ def function_schema(
|
|
|
219
244
|
# 1. Grab docstring info
|
|
220
245
|
if use_docstring_info:
|
|
221
246
|
doc_info = generate_func_documentation(func, docstring_style)
|
|
222
|
-
param_descs = doc_info.param_descriptions or {}
|
|
247
|
+
param_descs = dict(doc_info.param_descriptions or {})
|
|
223
248
|
else:
|
|
224
249
|
doc_info = None
|
|
225
250
|
param_descs = {}
|
|
226
251
|
|
|
252
|
+
type_hints_with_extras = get_type_hints(func, include_extras=True)
|
|
253
|
+
type_hints: dict[str, Any] = {}
|
|
254
|
+
annotated_param_descs: dict[str, str] = {}
|
|
255
|
+
|
|
256
|
+
for name, annotation in type_hints_with_extras.items():
|
|
257
|
+
if name == "return":
|
|
258
|
+
continue
|
|
259
|
+
|
|
260
|
+
stripped_ann, metadata = _strip_annotated(annotation)
|
|
261
|
+
type_hints[name] = stripped_ann
|
|
262
|
+
|
|
263
|
+
description = _extract_description_from_metadata(metadata)
|
|
264
|
+
if description is not None:
|
|
265
|
+
annotated_param_descs[name] = description
|
|
266
|
+
|
|
267
|
+
for name, description in annotated_param_descs.items():
|
|
268
|
+
param_descs.setdefault(name, description)
|
|
269
|
+
|
|
227
270
|
# Ensure name_override takes precedence even if docstring info is disabled.
|
|
228
271
|
func_name = name_override or (doc_info.name if doc_info else func.__name__)
|
|
229
272
|
|
|
230
273
|
# 2. Inspect function signature and get type hints
|
|
231
274
|
sig = inspect.signature(func)
|
|
232
|
-
type_hints = get_type_hints(func)
|
|
233
275
|
params = list(sig.parameters.items())
|
|
234
276
|
takes_context = False
|
|
235
277
|
filtered_params = []
|
|
@@ -291,7 +333,7 @@ def function_schema(
|
|
|
291
333
|
# Default factory to empty list
|
|
292
334
|
fields[name] = (
|
|
293
335
|
ann,
|
|
294
|
-
Field(default_factory=list, description=field_description),
|
|
336
|
+
Field(default_factory=list, description=field_description),
|
|
295
337
|
)
|
|
296
338
|
|
|
297
339
|
elif param.kind == param.VAR_KEYWORD:
|
|
@@ -309,7 +351,7 @@ def function_schema(
|
|
|
309
351
|
|
|
310
352
|
fields[name] = (
|
|
311
353
|
ann,
|
|
312
|
-
Field(default_factory=dict, description=field_description),
|
|
354
|
+
Field(default_factory=dict, description=field_description),
|
|
313
355
|
)
|
|
314
356
|
|
|
315
357
|
else:
|
agents/guardrail.py
CHANGED
|
@@ -70,7 +70,7 @@ class OutputGuardrailResult:
|
|
|
70
70
|
|
|
71
71
|
@dataclass
|
|
72
72
|
class InputGuardrail(Generic[TContext]):
|
|
73
|
-
"""Input guardrails are checks that run in parallel
|
|
73
|
+
"""Input guardrails are checks that run either in parallel with the agent or before it starts.
|
|
74
74
|
They can be used to do things like:
|
|
75
75
|
- Check if input messages are off-topic
|
|
76
76
|
- Take over control of the agent's execution if an unexpected input is detected
|
|
@@ -97,6 +97,11 @@ class InputGuardrail(Generic[TContext]):
|
|
|
97
97
|
function's name.
|
|
98
98
|
"""
|
|
99
99
|
|
|
100
|
+
run_in_parallel: bool = True
|
|
101
|
+
"""Whether the guardrail runs concurrently with the agent (True, default) or before
|
|
102
|
+
the agent starts (False).
|
|
103
|
+
"""
|
|
104
|
+
|
|
100
105
|
def get_name(self) -> str:
|
|
101
106
|
if self.name:
|
|
102
107
|
return self.name
|
|
@@ -209,6 +214,7 @@ def input_guardrail(
|
|
|
209
214
|
def input_guardrail(
|
|
210
215
|
*,
|
|
211
216
|
name: str | None = None,
|
|
217
|
+
run_in_parallel: bool = True,
|
|
212
218
|
) -> Callable[
|
|
213
219
|
[_InputGuardrailFuncSync[TContext_co] | _InputGuardrailFuncAsync[TContext_co]],
|
|
214
220
|
InputGuardrail[TContext_co],
|
|
@@ -221,6 +227,7 @@ def input_guardrail(
|
|
|
221
227
|
| None = None,
|
|
222
228
|
*,
|
|
223
229
|
name: str | None = None,
|
|
230
|
+
run_in_parallel: bool = True,
|
|
224
231
|
) -> (
|
|
225
232
|
InputGuardrail[TContext_co]
|
|
226
233
|
| Callable[
|
|
@@ -235,8 +242,14 @@ def input_guardrail(
|
|
|
235
242
|
@input_guardrail
|
|
236
243
|
def my_sync_guardrail(...): ...
|
|
237
244
|
|
|
238
|
-
@input_guardrail(name="guardrail_name")
|
|
245
|
+
@input_guardrail(name="guardrail_name", run_in_parallel=False)
|
|
239
246
|
async def my_async_guardrail(...): ...
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
func: The guardrail function to wrap.
|
|
250
|
+
name: Optional name for the guardrail. If not provided, uses the function's name.
|
|
251
|
+
run_in_parallel: Whether to run the guardrail concurrently with the agent (True, default)
|
|
252
|
+
or before the agent starts (False).
|
|
240
253
|
"""
|
|
241
254
|
|
|
242
255
|
def decorator(
|
|
@@ -246,6 +259,7 @@ def input_guardrail(
|
|
|
246
259
|
guardrail_function=f,
|
|
247
260
|
# If not set, guardrail name uses the function’s name by default.
|
|
248
261
|
name=name if name else f.__name__,
|
|
262
|
+
run_in_parallel=run_in_parallel,
|
|
249
263
|
)
|
|
250
264
|
|
|
251
265
|
if func is not None:
|
|
@@ -9,22 +9,29 @@ from typing import TYPE_CHECKING, Any, Callable, Generic, cast, overload
|
|
|
9
9
|
from pydantic import TypeAdapter
|
|
10
10
|
from typing_extensions import TypeAlias, TypeVar
|
|
11
11
|
|
|
12
|
-
from
|
|
13
|
-
from
|
|
14
|
-
from
|
|
15
|
-
from
|
|
16
|
-
from
|
|
17
|
-
from
|
|
18
|
-
from
|
|
12
|
+
from ..exceptions import ModelBehaviorError, UserError
|
|
13
|
+
from ..items import RunItem, TResponseInputItem
|
|
14
|
+
from ..run_context import RunContextWrapper, TContext
|
|
15
|
+
from ..strict_schema import ensure_strict_json_schema
|
|
16
|
+
from ..tracing.spans import SpanError
|
|
17
|
+
from ..util import _error_tracing, _json, _transforms
|
|
18
|
+
from ..util._types import MaybeAwaitable
|
|
19
|
+
from .history import (
|
|
20
|
+
default_handoff_history_mapper,
|
|
21
|
+
get_conversation_history_wrappers,
|
|
22
|
+
nest_handoff_history,
|
|
23
|
+
reset_conversation_history_wrappers,
|
|
24
|
+
set_conversation_history_wrappers,
|
|
25
|
+
)
|
|
19
26
|
|
|
20
27
|
if TYPE_CHECKING:
|
|
21
|
-
from
|
|
28
|
+
from ..agent import Agent, AgentBase
|
|
22
29
|
|
|
23
30
|
|
|
24
31
|
# The handoff input type is the type of data passed when the agent is called via a handoff.
|
|
25
32
|
THandoffInput = TypeVar("THandoffInput", default=Any)
|
|
26
33
|
|
|
27
|
-
# The agent type that the handoff returns
|
|
34
|
+
# The agent type that the handoff returns.
|
|
28
35
|
TAgent = TypeVar("TAgent", bound="AgentBase[Any]", default="Agent[Any]")
|
|
29
36
|
|
|
30
37
|
OnHandoffWithInput = Callable[[RunContextWrapper[Any], THandoffInput], Any]
|
|
@@ -51,31 +58,44 @@ class HandoffInputData:
|
|
|
51
58
|
|
|
52
59
|
run_context: RunContextWrapper[Any] | None = None
|
|
53
60
|
"""
|
|
54
|
-
The run context at the time the handoff was invoked.
|
|
55
|
-
|
|
61
|
+
The run context at the time the handoff was invoked. Note that, since this property was added
|
|
62
|
+
later on, it is optional for backwards compatibility.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
input_items: tuple[RunItem, ...] | None = None
|
|
66
|
+
"""
|
|
67
|
+
Items to include in the next agent's input. When set, these items are used instead of
|
|
68
|
+
new_items for building the input to the next agent. This allows filtering duplicates
|
|
69
|
+
from agent input while preserving all items in new_items for session history.
|
|
56
70
|
"""
|
|
57
71
|
|
|
58
72
|
def clone(self, **kwargs: Any) -> HandoffInputData:
|
|
59
73
|
"""
|
|
60
74
|
Make a copy of the handoff input data, with the given arguments changed. For example, you
|
|
61
75
|
could do:
|
|
76
|
+
|
|
62
77
|
```
|
|
63
78
|
new_handoff_input_data = handoff_input_data.clone(new_items=())
|
|
64
79
|
```
|
|
65
80
|
"""
|
|
81
|
+
|
|
66
82
|
return dataclasses_replace(self, **kwargs)
|
|
67
83
|
|
|
68
84
|
|
|
69
85
|
HandoffInputFilter: TypeAlias = Callable[[HandoffInputData], MaybeAwaitable[HandoffInputData]]
|
|
70
86
|
"""A function that filters the input data passed to the next agent."""
|
|
71
87
|
|
|
88
|
+
HandoffHistoryMapper: TypeAlias = Callable[[list[TResponseInputItem]], list[TResponseInputItem]]
|
|
89
|
+
"""A function that maps the previous transcript to the nested summary payload."""
|
|
90
|
+
|
|
72
91
|
|
|
73
92
|
@dataclass
|
|
74
93
|
class Handoff(Generic[TContext, TAgent]):
|
|
75
94
|
"""A handoff is when an agent delegates a task to another agent.
|
|
95
|
+
|
|
76
96
|
For example, in a customer support scenario you might have a "triage agent" that determines
|
|
77
|
-
which agent should handle the user's request, and sub-agents that specialize in different
|
|
78
|
-
|
|
97
|
+
which agent should handle the user's request, and sub-agents that specialize in different areas
|
|
98
|
+
like billing, account management, etc.
|
|
79
99
|
"""
|
|
80
100
|
|
|
81
101
|
tool_name: str
|
|
@@ -85,46 +105,48 @@ class Handoff(Generic[TContext, TAgent]):
|
|
|
85
105
|
"""The description of the tool that represents the handoff."""
|
|
86
106
|
|
|
87
107
|
input_json_schema: dict[str, Any]
|
|
88
|
-
"""The JSON schema for the handoff input. Can be empty if the handoff does not take an input.
|
|
89
|
-
"""
|
|
108
|
+
"""The JSON schema for the handoff input. Can be empty if the handoff does not take an input."""
|
|
90
109
|
|
|
91
110
|
on_invoke_handoff: Callable[[RunContextWrapper[Any], str], Awaitable[TAgent]]
|
|
92
|
-
"""The function that invokes the handoff.
|
|
93
|
-
1. The handoff run context
|
|
94
|
-
2. The arguments from the LLM, as a JSON string. Empty string if input_json_schema is empty.
|
|
111
|
+
"""The function that invokes the handoff.
|
|
95
112
|
|
|
96
|
-
|
|
113
|
+
The parameters passed are: (1) the handoff run context, (2) the arguments from the LLM as a
|
|
114
|
+
JSON string (or an empty string if ``input_json_schema`` is empty). Must return an agent.
|
|
97
115
|
"""
|
|
98
116
|
|
|
99
117
|
agent_name: str
|
|
100
118
|
"""The name of the agent that is being handed off to."""
|
|
101
119
|
|
|
102
120
|
input_filter: HandoffInputFilter | None = None
|
|
103
|
-
"""A function that filters the inputs that are passed to the next agent.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
121
|
+
"""A function that filters the inputs that are passed to the next agent.
|
|
122
|
+
|
|
123
|
+
By default, the new agent sees the entire conversation history. In some cases, you may want to
|
|
124
|
+
filter inputs (for example, to remove older inputs or remove tools from existing inputs). The
|
|
125
|
+
function receives the entire conversation history so far, including the input item that
|
|
126
|
+
triggered the handoff and a tool call output item representing the handoff tool's output. You
|
|
127
|
+
are free to modify the input history or new items as you see fit. The next agent receives the
|
|
128
|
+
input history plus ``input_items`` when provided, otherwise it receives ``new_items``. Use
|
|
129
|
+
``input_items`` to filter model input while keeping ``new_items`` intact for session history.
|
|
113
130
|
IMPORTANT: in streaming mode, we will not stream anything as a result of this function. The
|
|
114
131
|
items generated before will already have been streamed.
|
|
115
132
|
"""
|
|
116
133
|
|
|
134
|
+
nest_handoff_history: bool | None = None
|
|
135
|
+
"""Override the run-level ``nest_handoff_history`` behavior for this handoff only."""
|
|
136
|
+
|
|
117
137
|
strict_json_schema: bool = True
|
|
118
|
-
"""Whether the input JSON schema is in strict mode. We
|
|
119
|
-
|
|
120
|
-
"""
|
|
138
|
+
"""Whether the input JSON schema is in strict mode. We strongly recommend setting this to True
|
|
139
|
+
because it increases the likelihood of correct JSON input."""
|
|
121
140
|
|
|
122
|
-
is_enabled: bool | Callable[
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
"""Whether the handoff is enabled.
|
|
126
|
-
|
|
127
|
-
a
|
|
141
|
+
is_enabled: bool | Callable[[RunContextWrapper[Any], AgentBase[Any]], MaybeAwaitable[bool]] = (
|
|
142
|
+
True
|
|
143
|
+
)
|
|
144
|
+
"""Whether the handoff is enabled.
|
|
145
|
+
|
|
146
|
+
Either a bool or a callable that takes the run context and agent and returns whether the
|
|
147
|
+
handoff is enabled. You can use this to dynamically enable or disable a handoff based on your
|
|
148
|
+
context or state.
|
|
149
|
+
"""
|
|
128
150
|
|
|
129
151
|
def get_transfer_message(self, agent: AgentBase[Any]) -> str:
|
|
130
152
|
return json.dumps({"assistant": agent.name})
|
|
@@ -148,6 +170,7 @@ def handoff(
|
|
|
148
170
|
tool_name_override: str | None = None,
|
|
149
171
|
tool_description_override: str | None = None,
|
|
150
172
|
input_filter: Callable[[HandoffInputData], HandoffInputData] | None = None,
|
|
173
|
+
nest_handoff_history: bool | None = None,
|
|
151
174
|
is_enabled: bool | Callable[[RunContextWrapper[Any], Agent[Any]], MaybeAwaitable[bool]] = True,
|
|
152
175
|
) -> Handoff[TContext, Agent[TContext]]: ...
|
|
153
176
|
|
|
@@ -161,6 +184,7 @@ def handoff(
|
|
|
161
184
|
tool_description_override: str | None = None,
|
|
162
185
|
tool_name_override: str | None = None,
|
|
163
186
|
input_filter: Callable[[HandoffInputData], HandoffInputData] | None = None,
|
|
187
|
+
nest_handoff_history: bool | None = None,
|
|
164
188
|
is_enabled: bool | Callable[[RunContextWrapper[Any], Agent[Any]], MaybeAwaitable[bool]] = True,
|
|
165
189
|
) -> Handoff[TContext, Agent[TContext]]: ...
|
|
166
190
|
|
|
@@ -173,6 +197,7 @@ def handoff(
|
|
|
173
197
|
tool_description_override: str | None = None,
|
|
174
198
|
tool_name_override: str | None = None,
|
|
175
199
|
input_filter: Callable[[HandoffInputData], HandoffInputData] | None = None,
|
|
200
|
+
nest_handoff_history: bool | None = None,
|
|
176
201
|
is_enabled: bool | Callable[[RunContextWrapper[Any], Agent[Any]], MaybeAwaitable[bool]] = True,
|
|
177
202
|
) -> Handoff[TContext, Agent[TContext]]: ...
|
|
178
203
|
|
|
@@ -184,24 +209,28 @@ def handoff(
|
|
|
184
209
|
on_handoff: OnHandoffWithInput[THandoffInput] | OnHandoffWithoutInput | None = None,
|
|
185
210
|
input_type: type[THandoffInput] | None = None,
|
|
186
211
|
input_filter: Callable[[HandoffInputData], HandoffInputData] | None = None,
|
|
212
|
+
nest_handoff_history: bool | None = None,
|
|
187
213
|
is_enabled: bool
|
|
188
214
|
| Callable[[RunContextWrapper[Any], Agent[TContext]], MaybeAwaitable[bool]] = True,
|
|
189
215
|
) -> Handoff[TContext, Agent[TContext]]:
|
|
190
216
|
"""Create a handoff from an agent.
|
|
191
217
|
|
|
192
218
|
Args:
|
|
193
|
-
agent: The agent to handoff to
|
|
219
|
+
agent: The agent to handoff to.
|
|
194
220
|
tool_name_override: Optional override for the name of the tool that represents the handoff.
|
|
195
221
|
tool_description_override: Optional override for the description of the tool that
|
|
196
222
|
represents the handoff.
|
|
197
223
|
on_handoff: A function that runs when the handoff is invoked.
|
|
198
|
-
input_type:
|
|
224
|
+
input_type: The type of the input to the handoff. If provided, the input will be validated
|
|
199
225
|
against this type. Only relevant if you pass a function that takes an input.
|
|
200
|
-
input_filter:
|
|
226
|
+
input_filter: A function that filters the inputs that are passed to the next agent.
|
|
227
|
+
nest_handoff_history: Optional override for the RunConfig-level ``nest_handoff_history``
|
|
228
|
+
flag. If ``None`` we fall back to the run's configuration.
|
|
201
229
|
is_enabled: Whether the handoff is enabled. Can be a bool or a callable that takes the run
|
|
202
230
|
context and agent and returns whether the handoff is enabled. Disabled handoffs are
|
|
203
231
|
hidden from the LLM at runtime.
|
|
204
232
|
"""
|
|
233
|
+
|
|
205
234
|
assert (on_handoff and input_type) or not (on_handoff and input_type), (
|
|
206
235
|
"You must provide either both on_handoff and input_type, or neither"
|
|
207
236
|
)
|
|
@@ -257,21 +286,19 @@ def handoff(
|
|
|
257
286
|
tool_name = tool_name_override or Handoff.default_tool_name(agent)
|
|
258
287
|
tool_description = tool_description_override or Handoff.default_tool_description(agent)
|
|
259
288
|
|
|
260
|
-
# Always ensure the input JSON schema is in strict mode
|
|
261
|
-
#
|
|
289
|
+
# Always ensure the input JSON schema is in strict mode. If needed, we can make this
|
|
290
|
+
# configurable in the future.
|
|
262
291
|
input_json_schema = ensure_strict_json_schema(input_json_schema)
|
|
263
292
|
|
|
264
293
|
async def _is_enabled(ctx: RunContextWrapper[Any], agent_base: AgentBase[Any]) -> bool:
|
|
265
|
-
from
|
|
294
|
+
from ..agent import Agent
|
|
266
295
|
|
|
267
296
|
assert callable(is_enabled), "is_enabled must be callable here"
|
|
268
297
|
assert isinstance(agent_base, Agent), "Can't handoff to a non-Agent"
|
|
269
298
|
result = is_enabled(ctx, agent_base)
|
|
270
|
-
|
|
271
299
|
if inspect.isawaitable(result):
|
|
272
300
|
return await result
|
|
273
|
-
|
|
274
|
-
return result
|
|
301
|
+
return bool(result)
|
|
275
302
|
|
|
276
303
|
return Handoff(
|
|
277
304
|
tool_name=tool_name,
|
|
@@ -279,6 +306,21 @@ def handoff(
|
|
|
279
306
|
input_json_schema=input_json_schema,
|
|
280
307
|
on_invoke_handoff=_invoke_handoff,
|
|
281
308
|
input_filter=input_filter,
|
|
309
|
+
nest_handoff_history=nest_handoff_history,
|
|
282
310
|
agent_name=agent.name,
|
|
283
311
|
is_enabled=_is_enabled if callable(is_enabled) else is_enabled,
|
|
284
312
|
)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
__all__ = [
|
|
316
|
+
"Handoff",
|
|
317
|
+
"HandoffHistoryMapper",
|
|
318
|
+
"HandoffInputData",
|
|
319
|
+
"HandoffInputFilter",
|
|
320
|
+
"default_handoff_history_mapper",
|
|
321
|
+
"get_conversation_history_wrappers",
|
|
322
|
+
"handoff",
|
|
323
|
+
"nest_handoff_history",
|
|
324
|
+
"reset_conversation_history_wrappers",
|
|
325
|
+
"set_conversation_history_wrappers",
|
|
326
|
+
]
|