From 800d6fdf976f7205e1bf7fae90b3eba571c05bd5 Mon Sep 17 00:00:00 2001 From: Daniel Hashmi <151331476+DanielHashmi@users.noreply.github.com> Date: Fri, 4 Jul 2025 10:56:48 +0500 Subject: [PATCH 01/19] Maintain existing functionality for storing run_config in trace context --- src/agents/run.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/agents/run.py b/src/agents/run.py index e5f9378ec..c48da9ff0 100644 --- a/src/agents/run.py +++ b/src/agents/run.py @@ -338,7 +338,18 @@ async def run( group_id=run_config.group_id, metadata=run_config.trace_metadata, disabled=run_config.tracing_disabled, - ): + ) as trace_ctx: + if trace_ctx.trace: + # Store run_config in trace context for access by sub-agents + # Prefer storing in metadata if available + if ( + hasattr(trace_ctx.trace, "metadata") + and isinstance(trace_ctx.trace.metadata, dict) + ): + trace_ctx.trace.metadata["run_config"] = run_config + else: + trace_ctx.trace._run_config = run_config # type: ignore[attr-defined] + current_turn = 0 original_input: str | list[TResponseInputItem] = copy.deepcopy(input) generated_items: list[RunItem] = [] From 9ed72e792a71945f80a608239f2ad4d49da01715 Mon Sep 17 00:00:00 2001 From: Daniel Hashmi <151331476+DanielHashmi@users.noreply.github.com> Date: Fri, 4 Jul 2025 10:58:25 +0500 Subject: [PATCH 02/19] Add run_config inheritance for agent-as-tool functionality --- src/agents/agent.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/agents/agent.py b/src/agents/agent.py index 6c87297f1..dbabfd255 100644 --- a/src/agents/agent.py +++ b/src/agents/agent.py @@ -205,9 +205,9 @@ def as_tool( This is different from handoffs in two ways: 1. In handoffs, the new agent receives the conversation history. In this tool, the new agent - receives generated input. + receives generated input. 2. In handoffs, the new agent takes over the conversation. In this tool, the new agent is - called as a tool, and the conversation is continued by the original agent. + called as a tool, and the conversation is continued by the original agent. Args: tool_name: The name of the tool. If not provided, the agent's name will be used. @@ -223,11 +223,19 @@ def as_tool( ) async def run_agent(context: RunContextWrapper, input: str) -> str: from .run import Runner + from .tracing import get_current_trace + + # Get the current run_config from the trace context if available + run_config = None + current_trace = get_current_trace() + if current_trace and hasattr(current_trace, '_run_config'): + run_config = current_trace._run_config output = await Runner.run( starting_agent=self, input=input, context=context.context, + run_config=run_config, ) if custom_output_extractor: return await custom_output_extractor(output) From 78c94dcfe2c78d5b5b344fd4266b0df35d4f1dbe Mon Sep 17 00:00:00 2001 From: Daniel Hashmi <151331476+DanielHashmi@users.noreply.github.com> Date: Fri, 4 Jul 2025 10:59:41 +0500 Subject: [PATCH 03/19] Add _run_config attribute to trace classes --- src/agents/tracing/traces.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/agents/tracing/traces.py b/src/agents/tracing/traces.py index 53d062846..4d979d577 100644 --- a/src/agents/tracing/traces.py +++ b/src/agents/tracing/traces.py @@ -2,13 +2,15 @@ import abc import contextvars -from typing import Any +from typing import TYPE_CHECKING, Any from ..logger import logger from . import util from .processor_interface import TracingProcessor from .scope import Scope +if TYPE_CHECKING: + from ..run import RunConfig class Trace: """ @@ -66,7 +68,6 @@ def export(self) -> dict[str, Any] | None: """ pass - class NoOpTrace(Trace): """ A no-op trace that will not be recorded. @@ -75,16 +76,15 @@ class NoOpTrace(Trace): def __init__(self): self._started = False self._prev_context_token: contextvars.Token[Trace | None] | None = None + self._run_config: RunConfig | None = None def __enter__(self) -> Trace: if self._started: if not self._prev_context_token: logger.error("Trace already started but no context token set") return self - self._started = True self.start(mark_as_current=True) - return self def __exit__(self, exc_type, exc_val, exc_tb): @@ -110,10 +110,8 @@ def name(self) -> str: def export(self) -> dict[str, Any] | None: return None - NO_OP_TRACE = NoOpTrace() - class TraceImpl(Trace): """ A trace that will be recorded by the tracing library. @@ -127,6 +125,7 @@ class TraceImpl(Trace): "_prev_context_token", "_processor", "_started", + "_run_config", ) def __init__( @@ -144,6 +143,7 @@ def __init__( self._prev_context_token: contextvars.Token[Trace | None] | None = None self._processor = processor self._started = False + self._run_config: RunConfig | None = None @property def trace_id(self) -> str: @@ -156,19 +156,15 @@ def name(self) -> str: def start(self, mark_as_current: bool = False): if self._started: return - self._started = True self._processor.on_trace_start(self) - if mark_as_current: self._prev_context_token = Scope.set_current_trace(self) def finish(self, reset_current: bool = False): if not self._started: return - self._processor.on_trace_end(self) - if reset_current and self._prev_context_token is not None: Scope.reset_current_trace(self._prev_context_token) self._prev_context_token = None @@ -178,7 +174,6 @@ def __enter__(self) -> Trace: if not self._prev_context_token: logger.error("Trace already started but no context token set") return self - self.start(mark_as_current=True) return self From e90e48dc1306394ae17055af0e5fd2338547794e Mon Sep 17 00:00:00 2001 From: Daniel Hashmi <151331476+DanielHashmi@users.noreply.github.com> Date: Wed, 9 Jul 2025 16:37:12 +0500 Subject: [PATCH 04/19] Consolidate to one logger --- src/agents/tracing/traces.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/agents/tracing/traces.py b/src/agents/tracing/traces.py index 4d979d577..53d062846 100644 --- a/src/agents/tracing/traces.py +++ b/src/agents/tracing/traces.py @@ -2,15 +2,13 @@ import abc import contextvars -from typing import TYPE_CHECKING, Any +from typing import Any from ..logger import logger from . import util from .processor_interface import TracingProcessor from .scope import Scope -if TYPE_CHECKING: - from ..run import RunConfig class Trace: """ @@ -68,6 +66,7 @@ def export(self) -> dict[str, Any] | None: """ pass + class NoOpTrace(Trace): """ A no-op trace that will not be recorded. @@ -76,15 +75,16 @@ class NoOpTrace(Trace): def __init__(self): self._started = False self._prev_context_token: contextvars.Token[Trace | None] | None = None - self._run_config: RunConfig | None = None def __enter__(self) -> Trace: if self._started: if not self._prev_context_token: logger.error("Trace already started but no context token set") return self + self._started = True self.start(mark_as_current=True) + return self def __exit__(self, exc_type, exc_val, exc_tb): @@ -110,8 +110,10 @@ def name(self) -> str: def export(self) -> dict[str, Any] | None: return None + NO_OP_TRACE = NoOpTrace() + class TraceImpl(Trace): """ A trace that will be recorded by the tracing library. @@ -125,7 +127,6 @@ class TraceImpl(Trace): "_prev_context_token", "_processor", "_started", - "_run_config", ) def __init__( @@ -143,7 +144,6 @@ def __init__( self._prev_context_token: contextvars.Token[Trace | None] | None = None self._processor = processor self._started = False - self._run_config: RunConfig | None = None @property def trace_id(self) -> str: @@ -156,15 +156,19 @@ def name(self) -> str: def start(self, mark_as_current: bool = False): if self._started: return + self._started = True self._processor.on_trace_start(self) + if mark_as_current: self._prev_context_token = Scope.set_current_trace(self) def finish(self, reset_current: bool = False): if not self._started: return + self._processor.on_trace_end(self) + if reset_current and self._prev_context_token is not None: Scope.reset_current_trace(self._prev_context_token) self._prev_context_token = None @@ -174,6 +178,7 @@ def __enter__(self) -> Trace: if not self._prev_context_token: logger.error("Trace already started but no context token set") return self + self.start(mark_as_current=True) return self From 20bbe10b0adda356a51c16cab91535c6acbd4f15 Mon Sep 17 00:00:00 2001 From: Daniel Hashmi <151331476+DanielHashmi@users.noreply.github.com> Date: Wed, 9 Jul 2025 16:40:37 +0500 Subject: [PATCH 05/19] Enable RunConfig inheritance in as_tool() method --- src/agents/agent.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/agents/agent.py b/src/agents/agent.py index dbabfd255..80078006a 100644 --- a/src/agents/agent.py +++ b/src/agents/agent.py @@ -205,9 +205,9 @@ def as_tool( This is different from handoffs in two ways: 1. In handoffs, the new agent receives the conversation history. In this tool, the new agent - receives generated input. + receives generated input. 2. In handoffs, the new agent takes over the conversation. In this tool, the new agent is - called as a tool, and the conversation is continued by the original agent. + called as a tool, and the conversation is continued by the original agent. Args: tool_name: The name of the tool. If not provided, the agent's name will be used. @@ -223,13 +223,13 @@ def as_tool( ) async def run_agent(context: RunContextWrapper, input: str) -> str: from .run import Runner - from .tracing import get_current_trace + from .tracing.scope import Scope - # Get the current run_config from the trace context if available + # Get the current run_config from context if available run_config = None - current_trace = get_current_trace() - if current_trace and hasattr(current_trace, '_run_config'): - run_config = current_trace._run_config + current_run_config = Scope.get_current_run_config() + if current_run_config and current_run_config.pass_run_config_to_sub_agents: + run_config = current_run_config output = await Runner.run( starting_agent=self, @@ -239,7 +239,6 @@ async def run_agent(context: RunContextWrapper, input: str) -> str: ) if custom_output_extractor: return await custom_output_extractor(output) - return ItemHelpers.text_message_outputs(output.new_items) return run_agent From 878c7a61c45c56f498bc405f9d5acae4fa2852c8 Mon Sep 17 00:00:00 2001 From: Daniel Hashmi <151331476+DanielHashmi@users.noreply.github.com> Date: Wed, 9 Jul 2025 16:41:20 +0500 Subject: [PATCH 06/19] Add RunConfig inheritance with pass_run_config_to_sub_agents flag --- src/agents/run.py | 380 ++++++++++++++++++++++++---------------------- 1 file changed, 200 insertions(+), 180 deletions(-) diff --git a/src/agents/run.py b/src/agents/run.py index c48da9ff0..561c7d324 100644 --- a/src/agents/run.py +++ b/src/agents/run.py @@ -51,6 +51,7 @@ from .stream_events import AgentUpdatedStreamEvent, RawResponsesStreamEvent from .tool import Tool from .tracing import Span, SpanError, agent_span, get_current_trace, trace +from .tracing.scope import Scope from .tracing.span_data import AgentSpanData from .usage import Usage from .util import _coro, _error_tracing @@ -137,6 +138,11 @@ class RunConfig: An optional dictionary of additional metadata to include with the trace. """ + pass_run_config_to_sub_agents: bool = False + """ + Whether to pass this run configuration to sub-agents when using as_tool(). + If True, sub-agents will inherit the parent's run configuration. + """ class RunOptions(TypedDict, Generic[TContext]): """Arguments for ``AgentRunner`` methods.""" @@ -332,88 +338,99 @@ async def run( tool_use_tracker = AgentToolUseTracker() - with TraceCtxManager( - workflow_name=run_config.workflow_name, - trace_id=run_config.trace_id, - group_id=run_config.group_id, - metadata=run_config.trace_metadata, - disabled=run_config.tracing_disabled, - ) as trace_ctx: - if trace_ctx.trace: - # Store run_config in trace context for access by sub-agents - # Prefer storing in metadata if available - if ( - hasattr(trace_ctx.trace, "metadata") - and isinstance(trace_ctx.trace.metadata, dict) - ): - trace_ctx.trace.metadata["run_config"] = run_config - else: - trace_ctx.trace._run_config = run_config # type: ignore[attr-defined] - - current_turn = 0 - original_input: str | list[TResponseInputItem] = copy.deepcopy(input) - generated_items: list[RunItem] = [] - model_responses: list[ModelResponse] = [] + # Set the run_config context variable if enabled + run_config_token = None + if run_config.pass_run_config_to_sub_agents: + run_config_token = Scope.set_current_run_config(run_config) - context_wrapper: RunContextWrapper[TContext] = RunContextWrapper( - context=context, # type: ignore - ) + try: + with TraceCtxManager( + workflow_name=run_config.workflow_name, + trace_id=run_config.trace_id, + group_id=run_config.group_id, + metadata=run_config.trace_metadata, + disabled=run_config.tracing_disabled, + ): + current_turn = 0 + original_input: str | list[TResponseInputItem] = copy.deepcopy(input) + generated_items: list[RunItem] = [] + model_responses: list[ModelResponse] = [] + + context_wrapper: RunContextWrapper[TContext] = RunContextWrapper( + context=context, # type: ignore + ) - input_guardrail_results: list[InputGuardrailResult] = [] - - current_span: Span[AgentSpanData] | None = None - current_agent = starting_agent - should_run_agent_start_hooks = True - - try: - while True: - all_tools = await AgentRunner._get_all_tools(current_agent, context_wrapper) - - # Start an agent span if we don't have one. This span is ended if the current - # agent changes, or if the agent loop ends. - if current_span is None: - handoff_names = [ - h.agent_name - for h in await AgentRunner._get_handoffs(current_agent, context_wrapper) - ] - if output_schema := AgentRunner._get_output_schema(current_agent): - output_type_name = output_schema.name() - else: - output_type_name = "str" + input_guardrail_results: list[InputGuardrailResult] = [] - current_span = agent_span( - name=current_agent.name, - handoffs=handoff_names, - output_type=output_type_name, - ) - current_span.start(mark_as_current=True) - current_span.span_data.tools = [t.name for t in all_tools] + current_span: Span[AgentSpanData] | None = None + current_agent = starting_agent + should_run_agent_start_hooks = True - current_turn += 1 - if current_turn > max_turns: - _error_tracing.attach_error_to_span( - current_span, - SpanError( - message="Max turns exceeded", - data={"max_turns": max_turns}, - ), - ) - raise MaxTurnsExceeded(f"Max turns ({max_turns}) exceeded") + try: + while True: + all_tools = await AgentRunner._get_all_tools(current_agent, context_wrapper) + + # Start an agent span if we don't have one. This span is ended if the + # current agent changes, or if the agent loop ends. + if current_span is None: + handoff_names = [ + h.agent_name + for h in await AgentRunner._get_handoffs( + current_agent, context_wrapper + ) + ] + if output_schema := AgentRunner._get_output_schema(current_agent): + output_type_name = output_schema.name() + else: + output_type_name = "str" + + current_span = agent_span( + name=current_agent.name, + handoffs=handoff_names, + output_type=output_type_name, + ) + current_span.start(mark_as_current=True) + current_span.span_data.tools = [t.name for t in all_tools] + + current_turn += 1 + if current_turn > max_turns: + _error_tracing.attach_error_to_span( + current_span, + SpanError( + message="Max turns exceeded", + data={"max_turns": max_turns}, + ), + ) + raise MaxTurnsExceeded(f"Max turns ({max_turns}) exceeded") - logger.debug( - f"Running agent {current_agent.name} (turn {current_turn})", - ) + logger.debug( + f"Running agent {current_agent.name} (turn {current_turn})", + ) - if current_turn == 1: - input_guardrail_results, turn_result = await asyncio.gather( - self._run_input_guardrails( - starting_agent, - starting_agent.input_guardrails - + (run_config.input_guardrails or []), - copy.deepcopy(input), - context_wrapper, - ), - self._run_single_turn( + if current_turn == 1: + input_guardrail_results, turn_result = await asyncio.gather( + self._run_input_guardrails( + starting_agent, + starting_agent.input_guardrails + + (run_config.input_guardrails or []), + copy.deepcopy(input), + context_wrapper, + ), + self._run_single_turn( + agent=current_agent, + all_tools=all_tools, + original_input=original_input, + generated_items=generated_items, + hooks=hooks, + context_wrapper=context_wrapper, + run_config=run_config, + should_run_agent_start_hooks=should_run_agent_start_hooks, + tool_use_tracker=tool_use_tracker, + previous_response_id=previous_response_id, + ), + ) + else: + turn_result = await self._run_single_turn( agent=current_agent, all_tools=all_tools, original_input=original_input, @@ -424,69 +441,61 @@ async def run( should_run_agent_start_hooks=should_run_agent_start_hooks, tool_use_tracker=tool_use_tracker, previous_response_id=previous_response_id, - ), - ) - else: - turn_result = await self._run_single_turn( - agent=current_agent, - all_tools=all_tools, - original_input=original_input, - generated_items=generated_items, - hooks=hooks, - context_wrapper=context_wrapper, - run_config=run_config, - should_run_agent_start_hooks=should_run_agent_start_hooks, - tool_use_tracker=tool_use_tracker, - previous_response_id=previous_response_id, - ) - should_run_agent_start_hooks = False + ) + should_run_agent_start_hooks = False - model_responses.append(turn_result.model_response) - original_input = turn_result.original_input - generated_items = turn_result.generated_items + model_responses.append(turn_result.model_response) + original_input = turn_result.original_input + generated_items = turn_result.generated_items - if isinstance(turn_result.next_step, NextStepFinalOutput): - output_guardrail_results = await self._run_output_guardrails( - current_agent.output_guardrails + (run_config.output_guardrails or []), - current_agent, - turn_result.next_step.output, - context_wrapper, - ) - return RunResult( - input=original_input, - new_items=generated_items, - raw_responses=model_responses, - final_output=turn_result.next_step.output, - _last_agent=current_agent, - input_guardrail_results=input_guardrail_results, - output_guardrail_results=output_guardrail_results, - context_wrapper=context_wrapper, - ) - elif isinstance(turn_result.next_step, NextStepHandoff): - current_agent = cast(Agent[TContext], turn_result.next_step.new_agent) + if isinstance(turn_result.next_step, NextStepFinalOutput): + output_guardrail_results = await self._run_output_guardrails( + current_agent.output_guardrails + ( + run_config.output_guardrails or [] + ), + current_agent, + turn_result.next_step.output, + context_wrapper, + ) + return RunResult( + input=original_input, + new_items=generated_items, + raw_responses=model_responses, + final_output=turn_result.next_step.output, + _last_agent=current_agent, + input_guardrail_results=input_guardrail_results, + output_guardrail_results=output_guardrail_results, + context_wrapper=context_wrapper, + ) + elif isinstance(turn_result.next_step, NextStepHandoff): + current_agent = cast(Agent[TContext], turn_result.next_step.new_agent) + current_span.finish(reset_current=True) + current_span = None + should_run_agent_start_hooks = True + elif isinstance(turn_result.next_step, NextStepRunAgain): + pass + else: + raise AgentsException( + f"Unknown next step type: {type(turn_result.next_step)}" + ) + except AgentsException as exc: + exc.run_data = RunErrorDetails( + input=original_input, + new_items=generated_items, + raw_responses=model_responses, + last_agent=current_agent, + context_wrapper=context_wrapper, + input_guardrail_results=input_guardrail_results, + output_guardrail_results=[], + ) + raise + finally: + if current_span: current_span.finish(reset_current=True) - current_span = None - should_run_agent_start_hooks = True - elif isinstance(turn_result.next_step, NextStepRunAgain): - pass - else: - raise AgentsException( - f"Unknown next step type: {type(turn_result.next_step)}" - ) - except AgentsException as exc: - exc.run_data = RunErrorDetails( - input=original_input, - new_items=generated_items, - raw_responses=model_responses, - last_agent=current_agent, - context_wrapper=context_wrapper, - input_guardrail_results=input_guardrail_results, - output_guardrail_results=[], - ) - raise - finally: - if current_span: - current_span.finish(reset_current=True) + finally: + # Always clean up the context variable + if run_config_token is not None: + Scope.reset_current_run_config(run_config_token) def run_sync( self, @@ -527,56 +536,67 @@ def run_streamed( if run_config is None: run_config = RunConfig() - # If there's already a trace, we don't create a new one. In addition, we can't end the - # trace here, because the actual work is done in `stream_events` and this method ends - # before that. - new_trace = ( - None - if get_current_trace() - else trace( - workflow_name=run_config.workflow_name, - trace_id=run_config.trace_id, - group_id=run_config.group_id, - metadata=run_config.trace_metadata, - disabled=run_config.tracing_disabled, - ) - ) + # Set the run_config context variable if enabled + run_config_token = None + if run_config.pass_run_config_to_sub_agents: + run_config_token = Scope.set_current_run_config(run_config) - output_schema = AgentRunner._get_output_schema(starting_agent) - context_wrapper: RunContextWrapper[TContext] = RunContextWrapper( - context=context # type: ignore - ) + try: + # If there's already a trace, we don't create a new one. In addition, we can't end the + # trace here, because the actual work is done in `stream_events` and this method ends + # before that. + new_trace = ( + None + if get_current_trace() + else trace( + workflow_name=run_config.workflow_name, + trace_id=run_config.trace_id, + group_id=run_config.group_id, + metadata=run_config.trace_metadata, + disabled=run_config.tracing_disabled, + ) + ) - streamed_result = RunResultStreaming( - input=copy.deepcopy(input), - new_items=[], - current_agent=starting_agent, - raw_responses=[], - final_output=None, - is_complete=False, - current_turn=0, - max_turns=max_turns, - input_guardrail_results=[], - output_guardrail_results=[], - _current_agent_output_schema=output_schema, - trace=new_trace, - context_wrapper=context_wrapper, - ) + output_schema = AgentRunner._get_output_schema(starting_agent) + context_wrapper: RunContextWrapper[TContext] = RunContextWrapper( + context=context # type: ignore + ) - # Kick off the actual agent loop in the background and return the streamed result object. - streamed_result._run_impl_task = asyncio.create_task( - self._start_streaming( - starting_input=input, - streamed_result=streamed_result, - starting_agent=starting_agent, + streamed_result = RunResultStreaming( + input=copy.deepcopy(input), + new_items=[], + current_agent=starting_agent, + raw_responses=[], + final_output=None, + is_complete=False, + current_turn=0, max_turns=max_turns, - hooks=hooks, + input_guardrail_results=[], + output_guardrail_results=[], + _current_agent_output_schema=output_schema, + trace=new_trace, context_wrapper=context_wrapper, - run_config=run_config, - previous_response_id=previous_response_id, ) - ) - return streamed_result + + # Kick off the actual agent loop in the background and return the + # streamed result object. + streamed_result._run_impl_task = asyncio.create_task( + self._start_streaming( + starting_input=input, + streamed_result=streamed_result, + starting_agent=starting_agent, + max_turns=max_turns, + hooks=hooks, + context_wrapper=context_wrapper, + run_config=run_config, + previous_response_id=previous_response_id, + ) + ) + return streamed_result + finally: + # Always reset the context variable + if run_config_token is not None: + Scope.reset_current_run_config(run_config_token) @classmethod async def _run_input_guardrails_with_queue( From e04462fcda5f503fcaecd36c3aa3ac2c850e55d4 Mon Sep 17 00:00:00 2001 From: Daniel Hashmi <151331476+DanielHashmi@users.noreply.github.com> Date: Wed, 9 Jul 2025 16:43:51 +0500 Subject: [PATCH 07/19] Add RunConfig inheritance with pass_run_config_to_sub_agents flag From 24c2b1e34655555486758c84b732fd1109eec8ae Mon Sep 17 00:00:00 2001 From: Daniel Hashmi <151331476+DanielHashmi@users.noreply.github.com> Date: Wed, 9 Jul 2025 16:44:38 +0500 Subject: [PATCH 08/19] Enable RunConfig inheritance in as_tool() method From f83f5f1645b61ca4864341fb7b52662df2a691c3 Mon Sep 17 00:00:00 2001 From: Daniel Hashmi <151331476+DanielHashmi@users.noreply.github.com> Date: Wed, 9 Jul 2025 16:45:43 +0500 Subject: [PATCH 09/19] Add RunConfig context variable management to Scope class --- src/agents/tracing/scope.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/agents/tracing/scope.py b/src/agents/tracing/scope.py index 1d31c1bd1..0f0948f59 100644 --- a/src/agents/tracing/scope.py +++ b/src/agents/tracing/scope.py @@ -5,6 +5,7 @@ from ..logger import logger if TYPE_CHECKING: + from ..run import RunConfig from .spans import Span from .traces import Trace @@ -16,6 +17,9 @@ "current_trace", default=None ) +_current_run_config: contextvars.ContextVar["RunConfig | None"] = contextvars.ContextVar( + "current_run_config", default=None +) class Scope: """ @@ -47,3 +51,17 @@ def set_current_trace(cls, trace: "Trace | None") -> "contextvars.Token[Trace | def reset_current_trace(cls, token: "contextvars.Token[Trace | None]") -> None: logger.debug("Resetting current trace") _current_trace.reset(token) + + @classmethod + def get_current_run_config(cls) -> "RunConfig | None": + return _current_run_config.get() + + @classmethod + def set_current_run_config( + cls, run_config: "RunConfig | None" + ) -> "contextvars.Token[RunConfig | None]": + return _current_run_config.set(run_config) + + @classmethod + def reset_current_run_config(cls, token: "contextvars.Token[RunConfig | None]") -> None: + _current_run_config.reset(token) From f3a6fe0bda5cf116626a1540a3892ffd9e65ebe6 Mon Sep 17 00:00:00 2001 From: Daniel Hashmi <151331476+DanielHashmi@users.noreply.github.com> Date: Wed, 9 Jul 2025 16:48:02 +0500 Subject: [PATCH 10/19] Add RunConfig inheritance tests with error handling coverage --- tests/test_run_config_inheritance.py | 173 +++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 tests/test_run_config_inheritance.py diff --git a/tests/test_run_config_inheritance.py b/tests/test_run_config_inheritance.py new file mode 100644 index 000000000..4e72c75e8 --- /dev/null +++ b/tests/test_run_config_inheritance.py @@ -0,0 +1,173 @@ +from __future__ import annotations + +from typing import cast + +import pytest + +from agents import Agent, RunConfig, Runner +from agents.tool import function_tool +from agents.tracing.scope import Scope + +from .fake_model import FakeModel +from .test_responses import get_function_tool_call, get_text_message + + +@pytest.mark.asyncio +async def test_run_config_inheritance_enabled(): + """Test that run_config is inherited when pass_run_config_to_sub_agents=True""" + inherited_configs = [] + + @function_tool + async def config_capture_tool() -> str: + """Tool that captures the current run config""" + current_config = Scope.get_current_run_config() + inherited_configs.append(current_config) + return "config_captured" + + sub_agent = Agent( + name="SubAgent", + instructions="You are a sub agent", + model=FakeModel(), + tools=[config_capture_tool], + ) + + sub_fake_model = cast(FakeModel, sub_agent.model) + sub_fake_model.add_multiple_turn_outputs( + [ + [get_function_tool_call("config_capture_tool", "{}")], + [get_text_message("sub_agent_response")], + ] + ) + + parent_agent = Agent( + name="ParentAgent", + instructions="You are a parent agent", + model=FakeModel(), + tools=[ + sub_agent.as_tool(tool_name="sub_agent_tool", tool_description="Call the sub agent") + ], + ) + + parent_fake_model = cast(FakeModel, parent_agent.model) + parent_fake_model.add_multiple_turn_outputs( + [ + [get_function_tool_call("sub_agent_tool", '{"input": "test"}')], + [get_text_message("parent_response")], + ] + ) + + run_config = RunConfig(pass_run_config_to_sub_agents=True) + + assert Scope.get_current_run_config() is None + + await Runner.run( + starting_agent=parent_agent, + input="Use the sub agent tool", + run_config=run_config, + ) + + assert Scope.get_current_run_config() is None + assert len(inherited_configs) == 1 + assert inherited_configs[0] is run_config + assert inherited_configs[0].pass_run_config_to_sub_agents is True + + +@pytest.mark.asyncio +async def test_run_config_inheritance_disabled(): + """Test that run_config is not inherited when pass_run_config_to_sub_agents=False""" + inherited_configs = [] + + @function_tool + async def config_capture_tool() -> str: + """Tool that captures the current run config""" + current_config = Scope.get_current_run_config() + inherited_configs.append(current_config) + return "config_captured" + + sub_agent = Agent( + name="SubAgent", + instructions="You are a sub agent", + model=FakeModel(), + tools=[config_capture_tool], + ) + + sub_fake_model = cast(FakeModel, sub_agent.model) + sub_fake_model.add_multiple_turn_outputs( + [ + [get_function_tool_call("config_capture_tool", "{}")], + [get_text_message("sub_agent_response")], + ] + ) + + parent_agent = Agent( + name="ParentAgent", + instructions="You are a parent agent", + model=FakeModel(), + tools=[ + sub_agent.as_tool(tool_name="sub_agent_tool", tool_description="Call the sub agent") + ], + ) + + parent_fake_model = cast(FakeModel, parent_agent.model) + parent_fake_model.add_multiple_turn_outputs( + [ + [get_function_tool_call("sub_agent_tool", '{"input": "test"}')], + [get_text_message("parent_response")], + ] + ) + + run_config = RunConfig() + + await Runner.run( + starting_agent=parent_agent, + input="Use the sub agent tool", + run_config=run_config, + ) + + assert Scope.get_current_run_config() is None + assert len(inherited_configs) == 1 + assert inherited_configs[0] is None + + +@pytest.mark.asyncio +async def test_context_variable_cleanup_on_error(): + """Test that context variable is cleaned up even when errors occur""" + failing_model = FakeModel() + failing_model.set_next_output(RuntimeError("Intentional test failure")) + + failing_agent = Agent( + name="FailingAgent", + instructions="Fail", + model=failing_model, + ) + + run_config = RunConfig(pass_run_config_to_sub_agents=True) + + assert Scope.get_current_run_config() is None + + with pytest.raises(RuntimeError, match="Intentional test failure"): + await Runner.run( + starting_agent=failing_agent, + input="This should fail", + run_config=run_config, + ) + + assert Scope.get_current_run_config() is None + + +@pytest.mark.asyncio +async def test_scope_methods_directly(): + """Test the Scope class methods directly for RunConfig management""" + run_config = RunConfig(pass_run_config_to_sub_agents=True) + + assert Scope.get_current_run_config() is None + + token = Scope.set_current_run_config(run_config) + assert Scope.get_current_run_config() is run_config + + Scope.reset_current_run_config(token) + assert Scope.get_current_run_config() is None + + token = Scope.set_current_run_config(None) + assert Scope.get_current_run_config() is None + Scope.reset_current_run_config(token) From 87f88e303a983a2172bd9b47ca2d8108bbf29904 Mon Sep 17 00:00:00 2001 From: Daniel Hashmi <151331476+DanielHashmi@users.noreply.github.com> Date: Thu, 10 Jul 2025 14:01:48 +0500 Subject: [PATCH 11/19] Update test_run_config_inheritance.py --- tests/test_run_config_inheritance.py | 40 +++++++++++++++------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/tests/test_run_config_inheritance.py b/tests/test_run_config_inheritance.py index 4e72c75e8..8886a37e4 100644 --- a/tests/test_run_config_inheritance.py +++ b/tests/test_run_config_inheritance.py @@ -5,8 +5,8 @@ import pytest from agents import Agent, RunConfig, Runner +from agents.run import get_current_run_config, reset_current_run_config, set_current_run_config from agents.tool import function_tool -from agents.tracing.scope import Scope from .fake_model import FakeModel from .test_responses import get_function_tool_call, get_text_message @@ -20,7 +20,7 @@ async def test_run_config_inheritance_enabled(): @function_tool async def config_capture_tool() -> str: """Tool that captures the current run config""" - current_config = Scope.get_current_run_config() + current_config = get_current_run_config() inherited_configs.append(current_config) return "config_captured" @@ -44,7 +44,9 @@ async def config_capture_tool() -> str: instructions="You are a parent agent", model=FakeModel(), tools=[ - sub_agent.as_tool(tool_name="sub_agent_tool", tool_description="Call the sub agent") + sub_agent.as_tool( + tool_name="sub_agent_tool", tool_description="Call the sub agent" + ) ], ) @@ -58,7 +60,7 @@ async def config_capture_tool() -> str: run_config = RunConfig(pass_run_config_to_sub_agents=True) - assert Scope.get_current_run_config() is None + assert get_current_run_config() is None await Runner.run( starting_agent=parent_agent, @@ -66,7 +68,7 @@ async def config_capture_tool() -> str: run_config=run_config, ) - assert Scope.get_current_run_config() is None + assert get_current_run_config() is None assert len(inherited_configs) == 1 assert inherited_configs[0] is run_config assert inherited_configs[0].pass_run_config_to_sub_agents is True @@ -80,7 +82,7 @@ async def test_run_config_inheritance_disabled(): @function_tool async def config_capture_tool() -> str: """Tool that captures the current run config""" - current_config = Scope.get_current_run_config() + current_config = get_current_run_config() inherited_configs.append(current_config) return "config_captured" @@ -104,7 +106,9 @@ async def config_capture_tool() -> str: instructions="You are a parent agent", model=FakeModel(), tools=[ - sub_agent.as_tool(tool_name="sub_agent_tool", tool_description="Call the sub agent") + sub_agent.as_tool( + tool_name="sub_agent_tool", tool_description="Call the sub agent" + ) ], ) @@ -124,7 +128,7 @@ async def config_capture_tool() -> str: run_config=run_config, ) - assert Scope.get_current_run_config() is None + assert get_current_run_config() is None assert len(inherited_configs) == 1 assert inherited_configs[0] is None @@ -143,7 +147,7 @@ async def test_context_variable_cleanup_on_error(): run_config = RunConfig(pass_run_config_to_sub_agents=True) - assert Scope.get_current_run_config() is None + assert get_current_run_config() is None with pytest.raises(RuntimeError, match="Intentional test failure"): await Runner.run( @@ -152,7 +156,7 @@ async def test_context_variable_cleanup_on_error(): run_config=run_config, ) - assert Scope.get_current_run_config() is None + assert get_current_run_config() is None @pytest.mark.asyncio @@ -160,14 +164,14 @@ async def test_scope_methods_directly(): """Test the Scope class methods directly for RunConfig management""" run_config = RunConfig(pass_run_config_to_sub_agents=True) - assert Scope.get_current_run_config() is None + assert get_current_run_config() is None - token = Scope.set_current_run_config(run_config) - assert Scope.get_current_run_config() is run_config + token = set_current_run_config(run_config) + assert get_current_run_config() is run_config - Scope.reset_current_run_config(token) - assert Scope.get_current_run_config() is None + reset_current_run_config(token) + assert get_current_run_config() is None - token = Scope.set_current_run_config(None) - assert Scope.get_current_run_config() is None - Scope.reset_current_run_config(token) + token = set_current_run_config(None) + assert get_current_run_config() is None + reset_current_run_config(token) From 7bf52029d633a76b8cd4c6687d2976c001b8c4ba Mon Sep 17 00:00:00 2001 From: Daniel Hashmi <151331476+DanielHashmi@users.noreply.github.com> Date: Thu, 10 Jul 2025 14:02:25 +0500 Subject: [PATCH 12/19] Update agent.py --- src/agents/agent.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/agents/agent.py b/src/agents/agent.py index 80078006a..dff7815e1 100644 --- a/src/agents/agent.py +++ b/src/agents/agent.py @@ -222,12 +222,11 @@ def as_tool( description_override=tool_description or "", ) async def run_agent(context: RunContextWrapper, input: str) -> str: - from .run import Runner - from .tracing.scope import Scope + from .run import Runner, get_current_run_config # Get the current run_config from context if available run_config = None - current_run_config = Scope.get_current_run_config() + current_run_config = get_current_run_config() if current_run_config and current_run_config.pass_run_config_to_sub_agents: run_config = current_run_config From 97b4f9a4022da7d983a44a7bd5e86e5a68bbb664 Mon Sep 17 00:00:00 2001 From: Daniel Hashmi <151331476+DanielHashmi@users.noreply.github.com> Date: Thu, 10 Jul 2025 14:03:22 +0500 Subject: [PATCH 13/19] Update run.py --- src/agents/run.py | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/agents/run.py b/src/agents/run.py index 561c7d324..7d3800593 100644 --- a/src/agents/run.py +++ b/src/agents/run.py @@ -1,6 +1,7 @@ from __future__ import annotations import asyncio +import contextvars import copy import inspect from dataclasses import dataclass, field @@ -51,11 +52,14 @@ from .stream_events import AgentUpdatedStreamEvent, RawResponsesStreamEvent from .tool import Tool from .tracing import Span, SpanError, agent_span, get_current_trace, trace -from .tracing.scope import Scope from .tracing.span_data import AgentSpanData from .usage import Usage from .util import _coro, _error_tracing +_current_run_config: contextvars.ContextVar[RunConfig | None] = contextvars.ContextVar( + "current_run_config", default=None +) + DEFAULT_MAX_TURNS = 10 DEFAULT_AGENT_RUNNER: AgentRunner = None # type: ignore @@ -80,6 +84,21 @@ def get_default_agent_runner() -> AgentRunner: return DEFAULT_AGENT_RUNNER +def get_current_run_config() -> RunConfig | None: + """Get the current run config from context.""" + return _current_run_config.get() + + +def set_current_run_config(run_config: RunConfig | None) -> contextvars.Token[RunConfig | None]: + """Set the current run config in context.""" + return _current_run_config.set(run_config) + + +def reset_current_run_config(token: contextvars.Token[RunConfig | None]) -> None: + """Reset the current run config in context.""" + _current_run_config.reset(token) + + @dataclass class RunConfig: """Configures settings for the entire agent run.""" @@ -341,7 +360,7 @@ async def run( # Set the run_config context variable if enabled run_config_token = None if run_config.pass_run_config_to_sub_agents: - run_config_token = Scope.set_current_run_config(run_config) + run_config_token = set_current_run_config(run_config) try: with TraceCtxManager( @@ -495,7 +514,7 @@ async def run( finally: # Always clean up the context variable if run_config_token is not None: - Scope.reset_current_run_config(run_config_token) + reset_current_run_config(run_config_token) def run_sync( self, @@ -539,7 +558,7 @@ def run_streamed( # Set the run_config context variable if enabled run_config_token = None if run_config.pass_run_config_to_sub_agents: - run_config_token = Scope.set_current_run_config(run_config) + run_config_token = set_current_run_config(run_config) try: # If there's already a trace, we don't create a new one. In addition, we can't end the @@ -596,7 +615,7 @@ def run_streamed( finally: # Always reset the context variable if run_config_token is not None: - Scope.reset_current_run_config(run_config_token) + reset_current_run_config(run_config_token) @classmethod async def _run_input_guardrails_with_queue( From 8ac4b4460056f2842afa092d81cb2114adb29f5c Mon Sep 17 00:00:00 2001 From: Daniel Hashmi <151331476+DanielHashmi@users.noreply.github.com> Date: Thu, 10 Jul 2025 14:08:17 +0500 Subject: [PATCH 14/19] Adding scope and span_data doc strings (#463) --- src/agents/tracing/scope.py | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/agents/tracing/scope.py b/src/agents/tracing/scope.py index 0f0948f59..1d31c1bd1 100644 --- a/src/agents/tracing/scope.py +++ b/src/agents/tracing/scope.py @@ -5,7 +5,6 @@ from ..logger import logger if TYPE_CHECKING: - from ..run import RunConfig from .spans import Span from .traces import Trace @@ -17,9 +16,6 @@ "current_trace", default=None ) -_current_run_config: contextvars.ContextVar["RunConfig | None"] = contextvars.ContextVar( - "current_run_config", default=None -) class Scope: """ @@ -51,17 +47,3 @@ def set_current_trace(cls, trace: "Trace | None") -> "contextvars.Token[Trace | def reset_current_trace(cls, token: "contextvars.Token[Trace | None]") -> None: logger.debug("Resetting current trace") _current_trace.reset(token) - - @classmethod - def get_current_run_config(cls) -> "RunConfig | None": - return _current_run_config.get() - - @classmethod - def set_current_run_config( - cls, run_config: "RunConfig | None" - ) -> "contextvars.Token[RunConfig | None]": - return _current_run_config.set(run_config) - - @classmethod - def reset_current_run_config(cls, token: "contextvars.Token[RunConfig | None]") -> None: - _current_run_config.reset(token) From 840d00ebc98d1d0b40089fe5bb1c64aecc71e0e3 Mon Sep 17 00:00:00 2001 From: Daniel Hashmi <151331476+DanielHashmi@users.noreply.github.com> Date: Wed, 16 Jul 2025 22:58:42 +0500 Subject: [PATCH 15/19] Update test_run_config_inheritance.py --- tests/test_run_config_inheritance.py | 89 ++++++++++++++++++++++++---- 1 file changed, 78 insertions(+), 11 deletions(-) diff --git a/tests/test_run_config_inheritance.py b/tests/test_run_config_inheritance.py index 8886a37e4..1d2debf8f 100644 --- a/tests/test_run_config_inheritance.py +++ b/tests/test_run_config_inheritance.py @@ -5,7 +5,7 @@ import pytest from agents import Agent, RunConfig, Runner -from agents.run import get_current_run_config, reset_current_run_config, set_current_run_config +from agents.run import get_current_run_config, set_current_run_config from agents.tool import function_tool from .fake_model import FakeModel @@ -44,9 +44,7 @@ async def config_capture_tool() -> str: instructions="You are a parent agent", model=FakeModel(), tools=[ - sub_agent.as_tool( - tool_name="sub_agent_tool", tool_description="Call the sub agent" - ) + sub_agent.as_tool(tool_name="sub_agent_tool", tool_description="Call the sub agent") ], ) @@ -60,6 +58,7 @@ async def config_capture_tool() -> str: run_config = RunConfig(pass_run_config_to_sub_agents=True) + # Ensure clean state before test assert get_current_run_config() is None await Runner.run( @@ -68,7 +67,10 @@ async def config_capture_tool() -> str: run_config=run_config, ) + # Verify context is cleaned up after execution assert get_current_run_config() is None + + # Verify the sub-agent received the inherited config assert len(inherited_configs) == 1 assert inherited_configs[0] is run_config assert inherited_configs[0].pass_run_config_to_sub_agents is True @@ -106,9 +108,7 @@ async def config_capture_tool() -> str: instructions="You are a parent agent", model=FakeModel(), tools=[ - sub_agent.as_tool( - tool_name="sub_agent_tool", tool_description="Call the sub agent" - ) + sub_agent.as_tool(tool_name="sub_agent_tool", tool_description="Call the sub agent") ], ) @@ -120,6 +120,7 @@ async def config_capture_tool() -> str: ] ) + # Default RunConfig has pass_run_config_to_sub_agents=False run_config = RunConfig() await Runner.run( @@ -156,22 +157,88 @@ async def test_context_variable_cleanup_on_error(): run_config=run_config, ) + # Verify context is cleaned up even after error assert get_current_run_config() is None @pytest.mark.asyncio -async def test_scope_methods_directly(): - """Test the Scope class methods directly for RunConfig management""" +async def test_context_var_methods_directly(): + """Test the ContextVar methods directly for RunConfig management""" run_config = RunConfig(pass_run_config_to_sub_agents=True) assert get_current_run_config() is None + # Test setting and getting token = set_current_run_config(run_config) assert get_current_run_config() is run_config - reset_current_run_config(token) + # Test resetting using token - use the proper API + set_current_run_config(token.old_value) assert get_current_run_config() is None + # Test setting None token = set_current_run_config(None) assert get_current_run_config() is None - reset_current_run_config(token) + set_current_run_config(token.old_value) + + +@pytest.mark.asyncio +async def test_streaming_run_config_inheritance(): + """Test that run_config inheritance works with streaming execution""" + inherited_configs = [] + + @function_tool + async def config_capture_tool() -> str: + """Tool that captures the current run config""" + current_config = get_current_run_config() + inherited_configs.append(current_config) + return "config_captured" + + sub_agent = Agent( + name="SubAgent", + instructions="You are a sub agent", + model=FakeModel(), + tools=[config_capture_tool], + ) + + sub_fake_model = cast(FakeModel, sub_agent.model) + sub_fake_model.add_multiple_turn_outputs( + [ + [get_function_tool_call("config_capture_tool", "{}")], + [get_text_message("sub_agent_response")], + ] + ) + + parent_agent = Agent( + name="ParentAgent", + instructions="You are a parent agent", + model=FakeModel(), + tools=[ + sub_agent.as_tool(tool_name="sub_agent_tool", tool_description="Call the sub agent") + ], + ) + + parent_fake_model = cast(FakeModel, parent_agent.model) + parent_fake_model.add_multiple_turn_outputs( + [ + [get_function_tool_call("sub_agent_tool", '{"input": "test"}')], + [get_text_message("parent_response")], + ] + ) + + run_config = RunConfig(pass_run_config_to_sub_agents=True) + + # Test with streaming execution + result = Runner.run_streamed( + starting_agent=parent_agent, + input="Use the sub agent tool", + run_config=run_config, + ) + + async for _ in result.stream_events(): + pass + + # Verify inheritance worked in streaming mode + assert get_current_run_config() is None + assert len(inherited_configs) == 1 + assert inherited_configs[0] is run_config From 3f186f09d0655caaf56f31be3f8377531401bb5b Mon Sep 17 00:00:00 2001 From: Daniel Hashmi <151331476+DanielHashmi@users.noreply.github.com> Date: Wed, 16 Jul 2025 22:59:23 +0500 Subject: [PATCH 16/19] Update agent.py --- src/agents/agent.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/agents/agent.py b/src/agents/agent.py index 693897fd1..f025bdef5 100644 --- a/src/agents/agent.py +++ b/src/agents/agent.py @@ -221,6 +221,10 @@ class Agent(AgentBase, Generic[TContext]): """Whether to reset the tool choice to the default value after a tool has been called. Defaults to True. This ensures that the agent doesn't enter an infinite loop of tool usage.""" + def __post_init__(self): + if not isinstance(self.name, str): + raise TypeError(f"Agent name must be a string, got {type(self.name).__name__}") + def clone(self, **kwargs: Any) -> Agent[TContext]: """Make a copy of the agent, with the given arguments changed. For example, you could do: ``` @@ -259,19 +263,17 @@ async def run_agent(context: RunContextWrapper, input: str) -> str: from .run import Runner, get_current_run_config # Get the current run_config from context if available - run_config = None current_run_config = get_current_run_config() - if current_run_config and current_run_config.pass_run_config_to_sub_agents: - run_config = current_run_config output = await Runner.run( starting_agent=self, input=input, context=context.context, - run_config=run_config, + run_config=current_run_config, # Pass inherited config ) if custom_output_extractor: return await custom_output_extractor(output) + return ItemHelpers.text_message_outputs(output.new_items) return run_agent From b722b701f2e7a398fb74b1e9784b66deb145c8d8 Mon Sep 17 00:00:00 2001 From: Daniel Hashmi <151331476+DanielHashmi@users.noreply.github.com> Date: Wed, 16 Jul 2025 23:03:34 +0500 Subject: [PATCH 17/19] Update run.py --- src/agents/run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/agents/run.py b/src/agents/run.py index 6ef5de3bc..a12fb1e74 100644 --- a/src/agents/run.py +++ b/src/agents/run.py @@ -1283,4 +1283,4 @@ async def _save_result_to_session( await session.add_items(items_to_save) -DEFAULT_AGENT_RUNNER = AgentRunner() \ No newline at end of file +DEFAULT_AGENT_RUNNER = AgentRunner() From 191a34e9e7fa40a24ae9096131071559a2e08165 Mon Sep 17 00:00:00 2001 From: Daniel Hashmi <151331476+DanielHashmi@users.noreply.github.com> Date: Wed, 16 Jul 2025 23:09:23 +0500 Subject: [PATCH 18/19] Update agent.py --- src/agents/agent.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/agents/agent.py b/src/agents/agent.py index f025bdef5..45e707127 100644 --- a/src/agents/agent.py +++ b/src/agents/agent.py @@ -221,10 +221,6 @@ class Agent(AgentBase, Generic[TContext]): """Whether to reset the tool choice to the default value after a tool has been called. Defaults to True. This ensures that the agent doesn't enter an infinite loop of tool usage.""" - def __post_init__(self): - if not isinstance(self.name, str): - raise TypeError(f"Agent name must be a string, got {type(self.name).__name__}") - def clone(self, **kwargs: Any) -> Agent[TContext]: """Make a copy of the agent, with the given arguments changed. For example, you could do: ``` From 86260c89595fd1566338f2ef6a0cbc9f58a04811 Mon Sep 17 00:00:00 2001 From: Daniel Hashmi <151331476+DanielHashmi@users.noreply.github.com> Date: Wed, 23 Jul 2025 13:42:43 +0500 Subject: [PATCH 19/19] Update run.py --- src/agents/run.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/agents/run.py b/src/agents/run.py index a12fb1e74..97ca97dbd 100644 --- a/src/agents/run.py +++ b/src/agents/run.py @@ -528,7 +528,7 @@ async def run( finally: # Always reset the context variable if context_token is not None: - _current_run_config.set(context_token.old_value) + set_current_run_config(context_token.old_value) def run_sync( self, @@ -635,7 +635,7 @@ def run_streamed( finally: # Always reset the context variable if context_token is not None: - _current_run_config.set(context_token.old_value) + set_current_run_config(context_token.old_value) @classmethod async def _run_input_guardrails_with_queue(