Skip to content

Commit 6177ce7

Browse files
committed
Revert "Add support for returning control in Handoffs"
This reverts commit 6fea778.
1 parent 6fea778 commit 6177ce7

4 files changed

Lines changed: 15 additions & 137 deletions

File tree

src/agents/_run_impl.py

Lines changed: 10 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -176,11 +176,6 @@ class NextStepHandoff:
176176
new_agent: Agent[Any]
177177

178178

179-
@dataclass
180-
class NextStepHandoffReturnControl:
181-
previous_agent: Agent[Any]
182-
183-
184179
@dataclass
185180
class NextStepFinalOutput:
186181
output: Any
@@ -206,9 +201,7 @@ class SingleStepResult:
206201
new_step_items: list[RunItem]
207202
"""Items generated during this current step."""
208203

209-
next_step: (
210-
NextStepHandoff | NextStepFinalOutput | NextStepRunAgain | NextStepHandoffReturnControl
211-
)
204+
next_step: NextStepHandoff | NextStepFinalOutput | NextStepRunAgain
212205
"""The next step to take."""
213206

214207
@property
@@ -245,7 +238,6 @@ async def execute_tools_and_side_effects(
245238
hooks: RunHooks[TContext],
246239
context_wrapper: RunContextWrapper[TContext],
247240
run_config: RunConfig,
248-
previous_agents: list[Agent],
249241
) -> SingleStepResult:
250242
# Make a copy of the generated items
251243
pre_step_items = list(pre_step_items)
@@ -294,7 +286,6 @@ async def execute_tools_and_side_effects(
294286
hooks=hooks,
295287
context_wrapper=context_wrapper,
296288
run_config=run_config,
297-
previous_agents=previous_agents,
298289
)
299290

300291
# Next, we'll check if the tool use should result in a final output
@@ -325,7 +316,6 @@ async def execute_tools_and_side_effects(
325316
final_output=check_tool_use.final_output,
326317
hooks=hooks,
327318
context_wrapper=context_wrapper,
328-
previous_agents=previous_agents,
329319
)
330320

331321
# Now we can check if the model also produced a final output
@@ -350,7 +340,6 @@ async def execute_tools_and_side_effects(
350340
final_output=final_output,
351341
hooks=hooks,
352342
context_wrapper=context_wrapper,
353-
previous_agents=previous_agents,
354343
)
355344
elif (
356345
not output_schema or output_schema.is_plain_text()
@@ -364,7 +353,6 @@ async def execute_tools_and_side_effects(
364353
final_output=potential_final_output_text or "",
365354
hooks=hooks,
366355
context_wrapper=context_wrapper,
367-
previous_agents=previous_agents,
368356
)
369357
else:
370358
# If there's no final output, we can just run again
@@ -675,7 +663,6 @@ async def execute_handoffs(
675663
hooks: RunHooks[TContext],
676664
context_wrapper: RunContextWrapper[TContext],
677665
run_config: RunConfig,
678-
previous_agents: list[Agent[TContext]],
679666
) -> SingleStepResult:
680667
# If there is more than one handoff, add tool responses that reject those handoffs
681668
multiple_handoffs = len(run_handoffs) > 1
@@ -697,8 +684,6 @@ async def execute_handoffs(
697684
actual_handoff = run_handoffs[0]
698685
with handoff_span(from_agent=agent.name) as span_handoff:
699686
handoff = actual_handoff.handoff
700-
if handoff.should_return_control:
701-
previous_agents.append(agent)
702687
new_agent: Agent[Any] = await handoff.on_invoke_handoff(
703688
context_wrapper, actual_handoff.tool_call.arguments
704689
)
@@ -840,21 +825,16 @@ async def execute_final_output(
840825
final_output: Any,
841826
hooks: RunHooks[TContext],
842827
context_wrapper: RunContextWrapper[TContext],
843-
previous_agents: list[Agent[TContext]],
844828
) -> SingleStepResult:
845-
is_returning_control = len(previous_agents) > 0
846829
# Run the on_end hooks
847-
await cls.run_final_output_hooks(
848-
agent, hooks, context_wrapper, final_output, is_returning_control
849-
)
830+
await cls.run_final_output_hooks(agent, hooks, context_wrapper, final_output)
831+
850832
return SingleStepResult(
851833
original_input=original_input,
852834
model_response=new_response,
853835
pre_step_items=pre_step_items,
854836
new_step_items=new_step_items,
855-
next_step=NextStepHandoffReturnControl(previous_agents.pop())
856-
if is_returning_control
857-
else NextStepFinalOutput(final_output),
837+
next_step=NextStepFinalOutput(final_output),
858838
)
859839

860840
@classmethod
@@ -864,19 +844,13 @@ async def run_final_output_hooks(
864844
hooks: RunHooks[TContext],
865845
context_wrapper: RunContextWrapper[TContext],
866846
final_output: Any,
867-
is_returning_control: bool,
868847
):
869-
# If the agent is not returning control, run the hooks
870-
if not is_returning_control:
871-
await asyncio.gather(
872-
hooks.on_agent_end(context_wrapper, agent, final_output),
873-
agent.hooks.on_end(context_wrapper, agent, final_output)
874-
if agent.hooks
875-
else _coro.noop_coroutine(),
876-
)
877-
# If the agent is returning control, only run the current agent's hooks
878-
elif agent.hooks:
879-
await agent.hooks.on_end(context_wrapper, agent, final_output)
848+
await asyncio.gather(
849+
hooks.on_agent_end(context_wrapper, agent, final_output),
850+
agent.hooks.on_end(context_wrapper, agent, final_output)
851+
if agent.hooks
852+
else _coro.noop_coroutine(),
853+
)
880854

881855
@classmethod
882856
async def run_single_input_guardrail(

src/agents/handoffs.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,6 @@ class Handoff(Generic[TContext]):
105105
agent and returns whether the handoff is enabled. You can use this to dynamically enable/disable
106106
a handoff based on your context/state."""
107107

108-
should_return_control: bool = False
109-
"""Whether the Agent that receives control during a handoff should return control to the
110-
original (previous) Agent upon completion of its work. If False, after the Agent that received
111-
the handoff completes its work, the interaction will end.
112-
"""
113-
114108
def get_transfer_message(self, agent: Agent[Any]) -> str:
115109
return json.dumps({"assistant": agent.name})
116110

@@ -134,7 +128,6 @@ def handoff(
134128
tool_description_override: str | None = None,
135129
input_filter: Callable[[HandoffInputData], HandoffInputData] | None = None,
136130
is_enabled: bool | Callable[[RunContextWrapper[Any], Agent[Any]], MaybeAwaitable[bool]] = True,
137-
should_return_control: bool = False,
138131
) -> Handoff[TContext]: ...
139132

140133

@@ -148,7 +141,6 @@ def handoff(
148141
tool_name_override: str | None = None,
149142
input_filter: Callable[[HandoffInputData], HandoffInputData] | None = None,
150143
is_enabled: bool | Callable[[RunContextWrapper[Any], Agent[Any]], MaybeAwaitable[bool]] = True,
151-
should_return_control: bool = False,
152144
) -> Handoff[TContext]: ...
153145

154146

@@ -161,7 +153,6 @@ def handoff(
161153
tool_name_override: str | None = None,
162154
input_filter: Callable[[HandoffInputData], HandoffInputData] | None = None,
163155
is_enabled: bool | Callable[[RunContextWrapper[Any], Agent[Any]], MaybeAwaitable[bool]] = True,
164-
should_return_control: bool = False,
165156
) -> Handoff[TContext]: ...
166157

167158

@@ -173,7 +164,6 @@ def handoff(
173164
input_type: type[THandoffInput] | None = None,
174165
input_filter: Callable[[HandoffInputData], HandoffInputData] | None = None,
175166
is_enabled: bool | Callable[[RunContextWrapper[Any], Agent[Any]], MaybeAwaitable[bool]] = True,
176-
should_return_control: bool = False,
177167
) -> Handoff[TContext]:
178168
"""Create a handoff from an agent.
179169
@@ -191,7 +181,7 @@ def handoff(
191181
hidden from the LLM at runtime.
192182
"""
193183
assert (on_handoff and input_type) or not (on_handoff and input_type), (
194-
"You must provide either both on_input and input_type, or neither"
184+
"You must provide either both on_handoff and input_type, or neither"
195185
)
196186
type_adapter: TypeAdapter[Any] | None
197187
if input_type is not None:
@@ -257,5 +247,4 @@ async def _invoke_handoff(
257247
input_filter=input_filter,
258248
agent_name=agent.name,
259249
is_enabled=is_enabled,
260-
should_return_control=should_return_control,
261250
)

0 commit comments

Comments
 (0)