Skip to content

Commit ca60099

Browse files
committed
run tool only once.
1 parent 3755ea8 commit ca60099

File tree

1 file changed

+104
-102
lines changed

1 file changed

+104
-102
lines changed

src/agents/_run_impl.py

Lines changed: 104 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ def generated_items(self) -> list[RunItem]:
173173

174174

175175
def get_model_tracing_impl(
176-
tracing_disabled: bool, trace_include_sensitive_data: bool
176+
tracing_disabled: bool, trace_include_sensitive_data: bool
177177
) -> ModelTracing:
178178
if tracing_disabled:
179179
return ModelTracing.DISABLED
@@ -186,19 +186,19 @@ def get_model_tracing_impl(
186186
class RunImpl:
187187
@classmethod
188188
async def execute_tools_and_side_effects(
189-
cls,
190-
*,
191-
agent: Agent[TContext],
192-
# The original input to the Runner
193-
original_input: str | list[TResponseInputItem],
194-
# Everything generated by Runner since the original input, but before the current step
195-
pre_step_items: list[RunItem],
196-
new_response: ModelResponse,
197-
processed_response: ProcessedResponse,
198-
output_schema: AgentOutputSchemaBase | None,
199-
hooks: RunHooks[TContext],
200-
context_wrapper: RunContextWrapper[TContext],
201-
run_config: RunConfig,
189+
cls,
190+
*,
191+
agent: Agent[TContext],
192+
# The original input to the Runner
193+
original_input: str | list[TResponseInputItem],
194+
# Everything generated by Runner since the original input, but before the current step
195+
pre_step_items: list[RunItem],
196+
new_response: ModelResponse,
197+
processed_response: ProcessedResponse,
198+
output_schema: AgentOutputSchemaBase | None,
199+
hooks: RunHooks[TContext],
200+
context_wrapper: RunContextWrapper[TContext],
201+
run_config: RunConfig,
202202
) -> SingleStepResult:
203203
# Make a copy of the generated items
204204
pre_step_items = list(pre_step_items)
@@ -294,7 +294,7 @@ async def execute_tools_and_side_effects(
294294
context_wrapper=context_wrapper,
295295
)
296296
elif (
297-
not output_schema or output_schema.is_plain_text()
297+
not output_schema or output_schema.is_plain_text()
298298
) and not processed_response.has_tools_to_run():
299299
return await cls.execute_final_output(
300300
agent=agent,
@@ -318,7 +318,7 @@ async def execute_tools_and_side_effects(
318318

319319
@classmethod
320320
def maybe_reset_tool_choice(
321-
cls, agent: Agent[Any], tool_use_tracker: AgentToolUseTracker, model_settings: ModelSettings
321+
cls, agent: Agent[Any], tool_use_tracker: AgentToolUseTracker, model_settings: ModelSettings
322322
) -> ModelSettings:
323323
"""Resets tool choice to None if the agent has used tools and the agent's reset_tool_choice
324324
flag is True."""
@@ -330,13 +330,13 @@ def maybe_reset_tool_choice(
330330

331331
@classmethod
332332
def process_model_response(
333-
cls,
334-
*,
335-
agent: Agent[Any],
336-
all_tools: list[Tool],
337-
response: ModelResponse,
338-
output_schema: AgentOutputSchemaBase | None,
339-
handoffs: list[Handoff],
333+
cls,
334+
*,
335+
agent: Agent[Any],
336+
all_tools: list[Tool],
337+
response: ModelResponse,
338+
output_schema: AgentOutputSchemaBase | None,
339+
handoffs: list[Handoff],
340340
) -> ProcessedResponse:
341341
items: list[RunItem] = []
342342

@@ -421,16 +421,16 @@ def process_model_response(
421421

422422
@classmethod
423423
async def execute_function_tool_calls(
424-
cls,
425-
*,
426-
agent: Agent[TContext],
427-
tool_runs: list[ToolRunFunction],
428-
hooks: RunHooks[TContext],
429-
context_wrapper: RunContextWrapper[TContext],
430-
config: RunConfig,
424+
cls,
425+
*,
426+
agent: Agent[TContext],
427+
tool_runs: list[ToolRunFunction],
428+
hooks: RunHooks[TContext],
429+
context_wrapper: RunContextWrapper[TContext],
430+
config: RunConfig,
431431
) -> list[FunctionToolResult]:
432432
async def run_single_tool(
433-
func_tool: FunctionTool, tool_call: ResponseFunctionToolCall
433+
func_tool: FunctionTool, tool_call: ResponseFunctionToolCall
434434
) -> Any:
435435
with function_span(func_tool.name) as span_fn:
436436
if config.trace_include_sensitive_data:
@@ -473,6 +473,8 @@ async def run_single_tool(
473473
for tool_run in tool_runs:
474474
function_tool = tool_run.function_tool
475475
tasks.append(run_single_tool(function_tool, tool_run.tool_call))
476+
# run tool only once.
477+
break
476478

477479
results = await asyncio.gather(*tasks)
478480

@@ -491,13 +493,13 @@ async def run_single_tool(
491493

492494
@classmethod
493495
async def execute_computer_actions(
494-
cls,
495-
*,
496-
agent: Agent[TContext],
497-
actions: list[ToolRunComputerAction],
498-
hooks: RunHooks[TContext],
499-
context_wrapper: RunContextWrapper[TContext],
500-
config: RunConfig,
496+
cls,
497+
*,
498+
agent: Agent[TContext],
499+
actions: list[ToolRunComputerAction],
500+
hooks: RunHooks[TContext],
501+
context_wrapper: RunContextWrapper[TContext],
502+
config: RunConfig,
501503
) -> list[RunItem]:
502504
results: list[RunItem] = []
503505
# Need to run these serially, because each action can affect the computer state
@@ -516,17 +518,17 @@ async def execute_computer_actions(
516518

517519
@classmethod
518520
async def execute_handoffs(
519-
cls,
520-
*,
521-
agent: Agent[TContext],
522-
original_input: str | list[TResponseInputItem],
523-
pre_step_items: list[RunItem],
524-
new_step_items: list[RunItem],
525-
new_response: ModelResponse,
526-
run_handoffs: list[ToolRunHandoff],
527-
hooks: RunHooks[TContext],
528-
context_wrapper: RunContextWrapper[TContext],
529-
run_config: RunConfig,
521+
cls,
522+
*,
523+
agent: Agent[TContext],
524+
original_input: str | list[TResponseInputItem],
525+
pre_step_items: list[RunItem],
526+
new_step_items: list[RunItem],
527+
new_response: ModelResponse,
528+
run_handoffs: list[ToolRunHandoff],
529+
hooks: RunHooks[TContext],
530+
context_wrapper: RunContextWrapper[TContext],
531+
run_config: RunConfig,
530532
) -> SingleStepResult:
531533
# If there is more than one handoff, add tool responses that reject those handoffs
532534
multiple_handoffs = len(run_handoffs) > 1
@@ -645,16 +647,16 @@ async def execute_handoffs(
645647

646648
@classmethod
647649
async def execute_final_output(
648-
cls,
649-
*,
650-
agent: Agent[TContext],
651-
original_input: str | list[TResponseInputItem],
652-
new_response: ModelResponse,
653-
pre_step_items: list[RunItem],
654-
new_step_items: list[RunItem],
655-
final_output: Any,
656-
hooks: RunHooks[TContext],
657-
context_wrapper: RunContextWrapper[TContext],
650+
cls,
651+
*,
652+
agent: Agent[TContext],
653+
original_input: str | list[TResponseInputItem],
654+
new_response: ModelResponse,
655+
pre_step_items: list[RunItem],
656+
new_step_items: list[RunItem],
657+
final_output: Any,
658+
hooks: RunHooks[TContext],
659+
context_wrapper: RunContextWrapper[TContext],
658660
) -> SingleStepResult:
659661
# Run the on_end hooks
660662
await cls.run_final_output_hooks(agent, hooks, context_wrapper, final_output)
@@ -669,11 +671,11 @@ async def execute_final_output(
669671

670672
@classmethod
671673
async def run_final_output_hooks(
672-
cls,
673-
agent: Agent[TContext],
674-
hooks: RunHooks[TContext],
675-
context_wrapper: RunContextWrapper[TContext],
676-
final_output: Any,
674+
cls,
675+
agent: Agent[TContext],
676+
hooks: RunHooks[TContext],
677+
context_wrapper: RunContextWrapper[TContext],
678+
final_output: Any,
677679
):
678680
await asyncio.gather(
679681
hooks.on_agent_end(context_wrapper, agent, final_output),
@@ -684,11 +686,11 @@ async def run_final_output_hooks(
684686

685687
@classmethod
686688
async def run_single_input_guardrail(
687-
cls,
688-
agent: Agent[Any],
689-
guardrail: InputGuardrail[TContext],
690-
input: str | list[TResponseInputItem],
691-
context: RunContextWrapper[TContext],
689+
cls,
690+
agent: Agent[Any],
691+
guardrail: InputGuardrail[TContext],
692+
input: str | list[TResponseInputItem],
693+
context: RunContextWrapper[TContext],
692694
) -> InputGuardrailResult:
693695
with guardrail_span(guardrail.get_name()) as span_guardrail:
694696
result = await guardrail.run(agent, input, context)
@@ -697,11 +699,11 @@ async def run_single_input_guardrail(
697699

698700
@classmethod
699701
async def run_single_output_guardrail(
700-
cls,
701-
guardrail: OutputGuardrail[TContext],
702-
agent: Agent[Any],
703-
agent_output: Any,
704-
context: RunContextWrapper[TContext],
702+
cls,
703+
guardrail: OutputGuardrail[TContext],
704+
agent: Agent[Any],
705+
agent_output: Any,
706+
context: RunContextWrapper[TContext],
705707
) -> OutputGuardrailResult:
706708
with guardrail_span(guardrail.get_name()) as span_guardrail:
707709
result = await guardrail.run(agent=agent, agent_output=agent_output, context=context)
@@ -710,9 +712,9 @@ async def run_single_output_guardrail(
710712

711713
@classmethod
712714
def stream_step_result_to_queue(
713-
cls,
714-
step_result: SingleStepResult,
715-
queue: asyncio.Queue[StreamEvent | QueueCompleteSentinel],
715+
cls,
716+
step_result: SingleStepResult,
717+
queue: asyncio.Queue[StreamEvent | QueueCompleteSentinel],
716718
):
717719
for item in step_result.new_step_items:
718720
if isinstance(item, MessageOutputItem):
@@ -736,12 +738,12 @@ def stream_step_result_to_queue(
736738

737739
@classmethod
738740
async def _check_for_final_output_from_tools(
739-
cls,
740-
*,
741-
agent: Agent[TContext],
742-
tool_results: list[FunctionToolResult],
743-
context_wrapper: RunContextWrapper[TContext],
744-
config: RunConfig,
741+
cls,
742+
*,
743+
agent: Agent[TContext],
744+
tool_results: list[FunctionToolResult],
745+
context_wrapper: RunContextWrapper[TContext],
746+
config: RunConfig,
745747
) -> ToolsToFinalOutputResult:
746748
"""Returns (i, final_output)."""
747749
if not tool_results:
@@ -780,12 +782,12 @@ class TraceCtxManager:
780782
"""Creates a trace only if there is no current trace, and manages the trace lifecycle."""
781783

782784
def __init__(
783-
self,
784-
workflow_name: str,
785-
trace_id: str | None,
786-
group_id: str | None,
787-
metadata: dict[str, Any] | None,
788-
disabled: bool,
785+
self,
786+
workflow_name: str,
787+
trace_id: str | None,
788+
group_id: str | None,
789+
metadata: dict[str, Any] | None,
790+
disabled: bool,
789791
):
790792
self.trace: Trace | None = None
791793
self.workflow_name = workflow_name
@@ -816,13 +818,13 @@ def __exit__(self, exc_type, exc_val, exc_tb):
816818
class ComputerAction:
817819
@classmethod
818820
async def execute(
819-
cls,
820-
*,
821-
agent: Agent[TContext],
822-
action: ToolRunComputerAction,
823-
hooks: RunHooks[TContext],
824-
context_wrapper: RunContextWrapper[TContext],
825-
config: RunConfig,
821+
cls,
822+
*,
823+
agent: Agent[TContext],
824+
action: ToolRunComputerAction,
825+
hooks: RunHooks[TContext],
826+
context_wrapper: RunContextWrapper[TContext],
827+
config: RunConfig,
826828
) -> RunItem:
827829
output_func = (
828830
cls._get_screenshot_async(action.computer_tool.computer, action.tool_call)
@@ -866,9 +868,9 @@ async def execute(
866868

867869
@classmethod
868870
async def _get_screenshot_sync(
869-
cls,
870-
computer: Computer,
871-
tool_call: ResponseComputerToolCall,
871+
cls,
872+
computer: Computer,
873+
tool_call: ResponseComputerToolCall,
872874
) -> str:
873875
action = tool_call.action
874876
if isinstance(action, ActionClick):
@@ -894,9 +896,9 @@ async def _get_screenshot_sync(
894896

895897
@classmethod
896898
async def _get_screenshot_async(
897-
cls,
898-
computer: AsyncComputer,
899-
tool_call: ResponseComputerToolCall,
899+
cls,
900+
computer: AsyncComputer,
901+
tool_call: ResponseComputerToolCall,
900902
) -> str:
901903
action = tool_call.action
902904
if isinstance(action, ActionClick):

0 commit comments

Comments
 (0)