2828 from ..agent import Agent , AgentBase
2929
3030
31+ # The handoff input type is the type of data passed when the agent is called via a handoff.
3132THandoffInput = TypeVar ("THandoffInput" , default = Any )
33+
34+ # The agent type that the handoff returns.
3235TAgent = TypeVar ("TAgent" , bound = "AgentBase[Any]" , default = "Agent[Any]" )
3336
3437OnHandoffWithInput = Callable [[RunContextWrapper [Any ], THandoffInput ], Any ]
3841@dataclass (frozen = True )
3942class HandoffInputData :
4043 input_history : str | tuple [TResponseInputItem , ...]
44+ """
45+ The input history before `Runner.run()` was called.
46+ """
47+
4148 pre_handoff_items : tuple [RunItem , ...]
49+ """
50+ The items generated before the agent turn where the handoff was invoked.
51+ """
52+
4253 new_items : tuple [RunItem , ...]
54+ """
55+ The new items generated during the current agent turn, including the item that triggered the
56+ handoff and the tool output message representing the response from the handoff output.
57+ """
58+
4359 run_context : RunContextWrapper [Any ] | None = None
60+ """
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+ """
4464
4565 def clone (self , ** kwargs : Any ) -> HandoffInputData :
66+ """
67+ Make a copy of the handoff input data, with the given arguments changed. For example, you
68+ could do:
69+
70+ ```
71+ new_handoff_input_data = handoff_input_data.clone(new_items=())
72+ ```
73+ """
74+
4675 return dataclasses_replace (self , ** kwargs )
4776
4877
4978HandoffInputFilter : TypeAlias = Callable [[HandoffInputData ], MaybeAwaitable [HandoffInputData ]]
79+ """A function that filters the input data passed to the next agent."""
80+
5081HandoffHistoryMapper : TypeAlias = Callable [[list [TResponseInputItem ]], list [TResponseInputItem ]]
82+ """A function that maps the previous transcript to the nested summary payload."""
5183
5284
5385@dataclass
5486class Handoff (Generic [TContext , TAgent ]):
87+ """A handoff is when an agent delegates a task to another agent.
88+
89+ For example, in a customer support scenario you might have a "triage agent" that determines
90+ which agent should handle the user's request, and sub-agents that specialize in different areas
91+ like billing, account management, etc.
92+ """
93+
5594 tool_name : str
95+ """The name of the tool that represents the handoff."""
96+
5697 tool_description : str
98+ """The description of the tool that represents the handoff."""
99+
57100 input_json_schema : dict [str , Any ]
101+ """The JSON schema for the handoff input. Can be empty if the handoff does not take an input."""
102+
58103 on_invoke_handoff : Callable [[RunContextWrapper [Any ], str ], Awaitable [TAgent ]]
104+ """The function that invokes the handoff.
105+
106+ The parameters passed are: (1) the handoff run context, (2) the arguments from the LLM as a
107+ JSON string (or an empty string if ``input_json_schema`` is empty). Must return an agent.
108+ """
109+
59110 agent_name : str
111+ """The name of the agent that is being handed off to."""
112+
60113 input_filter : HandoffInputFilter | None = None
114+ """A function that filters the inputs that are passed to the next agent.
115+
116+ By default, the new agent sees the entire conversation history. In some cases, you may want to
117+ filter inputs (for example, to remove older inputs or remove tools from existing inputs). The
118+ function receives the entire conversation history so far, including the input item that
119+ triggered the handoff and a tool call output item representing the handoff tool's output. You
120+ are free to modify the input history or new items as you see fit. The next agent that runs will
121+ receive ``handoff_input_data.all_items``. IMPORTANT: in streaming mode, we will not stream
122+ anything as a result of this function. The items generated before will already have been
123+ streamed.
124+ """
125+
61126 nest_handoff_history : bool | None = None
127+ """Override the run-level ``nest_handoff_history`` behavior for this handoff only."""
128+
62129 strict_json_schema : bool = True
130+ """Whether the input JSON schema is in strict mode. We strongly recommend setting this to True
131+ because it increases the likelihood of correct JSON input."""
132+
63133 is_enabled : bool | Callable [[RunContextWrapper [Any ], AgentBase [Any ]], MaybeAwaitable [bool ]] = (
64134 True
65135 )
136+ """Whether the handoff is enabled.
137+
138+ Either a bool or a callable that takes the run context and agent and returns whether the
139+ handoff is enabled. You can use this to dynamically enable or disable a handoff based on your
140+ context or state.
141+ """
66142
67143 def get_transfer_message (self , agent : AgentBase [Any ]) -> str :
68144 return json .dumps ({"assistant" : agent .name })
@@ -129,6 +205,24 @@ def handoff(
129205 is_enabled : bool
130206 | Callable [[RunContextWrapper [Any ], Agent [TContext ]], MaybeAwaitable [bool ]] = True ,
131207) -> Handoff [TContext , Agent [TContext ]]:
208+ """Create a handoff from an agent.
209+
210+ Args:
211+ agent: The agent to handoff to, or a function that returns an agent.
212+ tool_name_override: Optional override for the name of the tool that represents the handoff.
213+ tool_description_override: Optional override for the description of the tool that
214+ represents the handoff.
215+ on_handoff: A function that runs when the handoff is invoked.
216+ input_type: The type of the input to the handoff. If provided, the input will be validated
217+ against this type. Only relevant if you pass a function that takes an input.
218+ input_filter: A function that filters the inputs that are passed to the next agent.
219+ nest_handoff_history: Optional override for the RunConfig-level ``nest_handoff_history``
220+ flag. If ``None`` we fall back to the run's configuration.
221+ is_enabled: Whether the handoff is enabled. Can be a bool or a callable that takes the run
222+ context and agent and returns whether the handoff is enabled. Disabled handoffs are
223+ hidden from the LLM at runtime.
224+ """
225+
132226 assert (on_handoff and input_type ) or not (on_handoff and input_type ), (
133227 "You must provide either both on_handoff and input_type, or neither"
134228 )
@@ -183,6 +277,9 @@ async def _invoke_handoff(
183277
184278 tool_name = tool_name_override or Handoff .default_tool_name (agent )
185279 tool_description = tool_description_override or Handoff .default_tool_description (agent )
280+
281+ # Always ensure the input JSON schema is in strict mode. If needed, we can make this
282+ # configurable in the future.
186283 input_json_schema = ensure_strict_json_schema (input_json_schema )
187284
188285 async def _is_enabled (ctx : RunContextWrapper [Any ], agent_base : AgentBase [Any ]) -> bool :
@@ -193,7 +290,7 @@ async def _is_enabled(ctx: RunContextWrapper[Any], agent_base: AgentBase[Any]) -
193290 result = is_enabled (ctx , agent_base )
194291 if inspect .isawaitable (result ):
195292 return await result
196- return result
293+ return bool ( result )
197294
198295 return Handoff (
199296 tool_name = tool_name ,
0 commit comments