Skip to content

feat(tools): add transfer_reason argument to transfer_to_agent to prevent multi-agent transfer loops - #6590

Open
Srikanth-Saravanan wants to merge 2 commits into
google:mainfrom
Srikanth-Saravanan:main
Open

feat(tools): add transfer_reason argument to transfer_to_agent to prevent multi-agent transfer loops#6590
Srikanth-Saravanan wants to merge 2 commits into
google:mainfrom
Srikanth-Saravanan:main

Conversation

@Srikanth-Saravanan

Copy link
Copy Markdown

Add transfer_reason argument to transfer_to_agent

Problem

The built-in transfer_to_agent tool only accepts the target agent_name. When an agent hands off control, the full session context is carried over, but the tool call itself contains no explicit rationale for why the transfer is happening.

In multi-agent systems this causes agents to "ping-pong". Because the receiving agent has no stated reason for the handoff, it frequently cannot tell why it was given control and transfers straight back to the sender — in some cases looping between agents indefinitely.

Solution

This change adds a required transfer_reason: str argument to transfer_to_agent. The delegating agent must now provide a short, explicit reason whenever it hands off. That reason travels with the transfer, giving the receiving agent the context it needs to continue the task instead of bouncing control back — which breaks the loop.

Design notes:

  • The argument is required rather than optional. The ping-pong originates in the function call the model produces, so the reason needs to be present there every time; making it optional would let the model omit it and reintroduce the problem.
  • TransferToAgentTool picks up the new parameter automatically through reflection. The existing agent_name enum constraint (which restricts transfers to valid agent names) is unchanged.

Testing

Unit tests

  • Updated the tool-declaration assertions in test_transfer_to_agent_tool.py: the required parameters are now ['agent_name', 'transfer_reason'], the property count goes from 1 to 2, and a new assertion verifies transfer_reason is a string with no enum constraint.
  • Because transfer_reason is required, FunctionTool's mandatory-argument validation now enforces it. Every test that mocks a transfer_to_agent function call was updated to include the new argument.

pytest results — 154 passed, 9 skipped, 3 xfailed:

tests/unittests/tools/test_transfer_to_agent_tool.py
tests/unittests/workflow/test_agent_transfer.py
tests/unittests/workflow/test_llm_agent_as_node.py
tests/unittests/agents/test_resumable_llm_agent.py
tests/unittests/runners/test_pause_invocation.py
tests/unittests/runners/test_resume_invocation.py
tests/unittests/streaming/test_multi_agent_streaming.py
tests/unittests/flows/llm_flows/test_agent_transfer_system_instructions.py
tests/unittests/flows/llm_flows/test_base_llm_flow.py
tests/unittests/flows/llm_flows/test_functions_parallel.py

Manual verification

Confirmed the generated function declaration exposes the new parameter:

from google.adk.tools.transfer_to_agent_tool import TransferToAgentTool

tool = TransferToAgentTool(agent_names=["agent_a", "agent_b"])
schema = tool._get_declaration().parameters_json_schema

print(schema["properties"].keys())  # dict_keys(['agent_name', 'transfer_reason'])
print(schema["required"])           # ['agent_name', 'transfer_reason']
print(schema["properties"]["agent_name"]["enum"])  # ['agent_a', 'agent_b']

In a multi-agent run, the model now emits calls such as
transfer_to_agent(agent_name="billing_agent", transfer_reason="user asked about an invoice charge"),
and the receiving agent uses the stated reason to continue the task rather than transferring back.

Backward compatibility

transfer_reason is a required argument. LLM-driven callers populate it naturally from the function declaration, but any code that hand-crafts a transfer_to_agent function call (for example tests or replay fixtures) must now include it. All such call sites in the repository have been updated in this PR.

@adk-bot adk-bot added the tools [Component] This issue is related to tools label Aug 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tools [Component] This issue is related to tools

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants