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.
Files changed (96) hide show
  1. agents/__init__.py +105 -4
  2. agents/_debug.py +15 -4
  3. agents/_run_impl.py +1203 -96
  4. agents/agent.py +164 -19
  5. agents/apply_diff.py +329 -0
  6. agents/editor.py +47 -0
  7. agents/exceptions.py +35 -0
  8. agents/extensions/experimental/__init__.py +6 -0
  9. agents/extensions/experimental/codex/__init__.py +92 -0
  10. agents/extensions/experimental/codex/codex.py +89 -0
  11. agents/extensions/experimental/codex/codex_options.py +35 -0
  12. agents/extensions/experimental/codex/codex_tool.py +1142 -0
  13. agents/extensions/experimental/codex/events.py +162 -0
  14. agents/extensions/experimental/codex/exec.py +263 -0
  15. agents/extensions/experimental/codex/items.py +245 -0
  16. agents/extensions/experimental/codex/output_schema_file.py +50 -0
  17. agents/extensions/experimental/codex/payloads.py +31 -0
  18. agents/extensions/experimental/codex/thread.py +214 -0
  19. agents/extensions/experimental/codex/thread_options.py +54 -0
  20. agents/extensions/experimental/codex/turn_options.py +36 -0
  21. agents/extensions/handoff_filters.py +13 -1
  22. agents/extensions/memory/__init__.py +120 -0
  23. agents/extensions/memory/advanced_sqlite_session.py +1285 -0
  24. agents/extensions/memory/async_sqlite_session.py +239 -0
  25. agents/extensions/memory/dapr_session.py +423 -0
  26. agents/extensions/memory/encrypt_session.py +185 -0
  27. agents/extensions/memory/redis_session.py +261 -0
  28. agents/extensions/memory/sqlalchemy_session.py +334 -0
  29. agents/extensions/models/litellm_model.py +449 -36
  30. agents/extensions/models/litellm_provider.py +3 -1
  31. agents/function_schema.py +47 -5
  32. agents/guardrail.py +16 -2
  33. agents/{handoffs.py → handoffs/__init__.py} +89 -47
  34. agents/handoffs/history.py +268 -0
  35. agents/items.py +237 -11
  36. agents/lifecycle.py +75 -14
  37. agents/mcp/server.py +280 -37
  38. agents/mcp/util.py +24 -3
  39. agents/memory/__init__.py +22 -2
  40. agents/memory/openai_conversations_session.py +91 -0
  41. agents/memory/openai_responses_compaction_session.py +249 -0
  42. agents/memory/session.py +19 -261
  43. agents/memory/sqlite_session.py +275 -0
  44. agents/memory/util.py +20 -0
  45. agents/model_settings.py +14 -3
  46. agents/models/__init__.py +13 -0
  47. agents/models/chatcmpl_converter.py +303 -50
  48. agents/models/chatcmpl_helpers.py +63 -0
  49. agents/models/chatcmpl_stream_handler.py +290 -68
  50. agents/models/default_models.py +58 -0
  51. agents/models/interface.py +4 -0
  52. agents/models/openai_chatcompletions.py +103 -49
  53. agents/models/openai_provider.py +10 -4
  54. agents/models/openai_responses.py +162 -46
  55. agents/realtime/__init__.py +4 -0
  56. agents/realtime/_util.py +14 -3
  57. agents/realtime/agent.py +7 -0
  58. agents/realtime/audio_formats.py +53 -0
  59. agents/realtime/config.py +78 -10
  60. agents/realtime/events.py +18 -0
  61. agents/realtime/handoffs.py +2 -2
  62. agents/realtime/items.py +17 -1
  63. agents/realtime/model.py +13 -0
  64. agents/realtime/model_events.py +12 -0
  65. agents/realtime/model_inputs.py +18 -1
  66. agents/realtime/openai_realtime.py +696 -150
  67. agents/realtime/session.py +243 -23
  68. agents/repl.py +7 -3
  69. agents/result.py +197 -38
  70. agents/run.py +949 -168
  71. agents/run_context.py +13 -2
  72. agents/stream_events.py +1 -0
  73. agents/strict_schema.py +14 -0
  74. agents/tool.py +413 -15
  75. agents/tool_context.py +22 -1
  76. agents/tool_guardrails.py +279 -0
  77. agents/tracing/__init__.py +2 -0
  78. agents/tracing/config.py +9 -0
  79. agents/tracing/create.py +4 -0
  80. agents/tracing/processor_interface.py +84 -11
  81. agents/tracing/processors.py +65 -54
  82. agents/tracing/provider.py +64 -7
  83. agents/tracing/spans.py +105 -0
  84. agents/tracing/traces.py +116 -16
  85. agents/usage.py +134 -12
  86. agents/util/_json.py +19 -1
  87. agents/util/_transforms.py +12 -2
  88. agents/voice/input.py +5 -4
  89. agents/voice/models/openai_stt.py +17 -9
  90. agents/voice/pipeline.py +2 -0
  91. agents/voice/pipeline_config.py +4 -0
  92. {openai_agents-0.2.8.dist-info → openai_agents-0.6.8.dist-info}/METADATA +44 -19
  93. openai_agents-0.6.8.dist-info/RECORD +134 -0
  94. {openai_agents-0.2.8.dist-info → openai_agents-0.6.8.dist-info}/WHEEL +1 -1
  95. openai_agents-0.2.8.dist-info/RECORD +0 -103
  96. {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 DEFAULT_MODEL)
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), # type: ignore
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), # type: ignore
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 to the agent's execution.
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 .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
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 .agent import Agent, AgentBase
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
- Note that, since this property was added later on, it's optional for backwards compatibility.
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
- areas like billing, account management, etc.
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. The parameters passed are:
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
- Must return an agent.
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. By default, the new
104
- agent sees the entire conversation history. In some cases, you may want to filter inputs e.g.
105
- to remove older inputs, or remove tools from existing inputs.
106
-
107
- The function will receive the entire conversation history so far, including the input item
108
- that triggered the handoff and a tool call output item representing the handoff tool's output.
109
-
110
- You are free to modify the input history or new items as you see fit. The next agent that
111
- runs will receive `handoff_input_data.all_items`.
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 **strongly** recommend setting this to
119
- True, as it increases the likelihood of correct JSON input.
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
- [RunContextWrapper[Any], AgentBase[Any]], MaybeAwaitable[bool]
124
- ] = True
125
- """Whether the handoff is enabled. Either a bool or a Callable that takes the run context and
126
- agent and returns whether the handoff is enabled. You can use this to dynamically enable/disable
127
- a handoff based on your context/state."""
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, or a function that returns an agent.
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: the type of the input to the handoff. If provided, the input will be validated
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: a function that filters the inputs that are passed to the next agent.
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
- # If there is a need, we can make this configurable in the future
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 .agent import Agent
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
+ ]