4646 from .run import RunConfig
4747 from .stream_events import StreamEvent
4848
49+ # Per-process, ephemeral map linking a tool call ID to its nested
50+ # Agent run result within the same run; entry is removed after consumption.
51+ _agent_tool_run_results : dict [str , RunResult | RunResultStreaming ] = {}
52+
53+
54+ def save_agent_tool_run_result (
55+ tool_call : ResponseFunctionToolCall | None ,
56+ run_result : RunResult | RunResultStreaming ,
57+ ) -> None :
58+ """Save the nested agent run result for later consumption.
59+
60+ This is used when an agent is used as a tool. The run result is stored
61+ so that interruptions from the nested agent run can be collected.
62+ """
63+ if tool_call :
64+ _agent_tool_run_results [tool_call .call_id ] = run_result
65+
66+
67+ def consume_agent_tool_run_result (
68+ tool_call : ResponseFunctionToolCall ,
69+ ) -> RunResult | RunResultStreaming | None :
70+ """Consume and return the nested agent run result for a tool call.
71+
72+ This retrieves and removes the stored run result. Returns None if
73+ no result was stored for this tool call.
74+ """
75+ run_result = _agent_tool_run_results .pop (tool_call .call_id , None )
76+ return run_result
77+
4978
5079@dataclass
5180class ToolsToFinalOutputResult :
@@ -412,6 +441,8 @@ def as_tool(
412441 is_enabled : bool
413442 | Callable [[RunContextWrapper [Any ], AgentBase [Any ]], MaybeAwaitable [bool ]] = True ,
414443 on_stream : Callable [[AgentToolStreamEvent ], MaybeAwaitable [None ]] | None = None ,
444+ needs_approval : bool
445+ | Callable [[RunContextWrapper [Any ], dict [str , Any ], str ], Awaitable [bool ]] = False ,
415446 run_config : RunConfig | None = None ,
416447 max_turns : int | None = None ,
417448 hooks : RunHooks [TContext ] | None = None ,
@@ -441,6 +472,13 @@ def as_tool(
441472 agent run. The callback receives an `AgentToolStreamEvent` containing the nested
442473 agent, the originating tool call (when available), and each stream event. When
443474 provided, the nested agent is executed in streaming mode.
475+ needs_approval: Whether the tool needs approval before execution.
476+ If True, the run will be interrupted and the tool call will need
477+ to be approved using RunState.approve() or rejected using
478+ RunState.reject() before continuing. Can be a bool
479+ (always/never needs approval) or a function that takes
480+ (run_context, tool_parameters, call_id) and returns whether this
481+ specific call needs approval.
444482 failure_error_function: If provided, generate an error message when the tool (agent) run
445483 fails. The message is sent to the LLM. If None, the exception is raised instead.
446484 """
@@ -449,10 +487,12 @@ def as_tool(
449487 name_override = tool_name or _transforms .transform_string_function_style (self .name ),
450488 description_override = tool_description or "" ,
451489 is_enabled = is_enabled ,
490+ needs_approval = needs_approval ,
452491 failure_error_function = failure_error_function ,
453492 )
454493 async def run_agent (context : ToolContext , input : str ) -> Any :
455494 from .run import DEFAULT_MAX_TURNS , Runner
495+ from .tool_context import ToolContext
456496
457497 resolved_max_turns = max_turns if max_turns is not None else DEFAULT_MAX_TURNS
458498 run_result : RunResult | RunResultStreaming
@@ -530,12 +570,24 @@ async def dispatch_stream_events() -> None:
530570 conversation_id = conversation_id ,
531571 session = session ,
532572 )
573+
574+ # Store the run result keyed by tool_call_id so it can be retrieved later
575+ # when the tool_call is available during result processing
576+ # At runtime, context is actually a ToolContext which has tool_call_id
577+ if isinstance (context , ToolContext ):
578+ _agent_tool_run_results [context .tool_call_id ] = run_result
579+
533580 if custom_output_extractor :
534581 return await custom_output_extractor (run_result )
535582
536583 return run_result .final_output
537584
538- return run_agent
585+ # Mark the function tool as an agent tool
586+ run_agent_tool = run_agent
587+ run_agent_tool ._is_agent_tool = True
588+ run_agent_tool ._agent_instance = self
589+
590+ return run_agent_tool
539591
540592 async def get_system_prompt (self , run_context : RunContextWrapper [TContext ]) -> str | None :
541593 if isinstance (self .instructions , str ):
0 commit comments