Skip to content

fix(a2a): do not forward a nested task hop's finish_task - #7869

Open
claxman wants to merge 1 commit into
google:mainfrom
claxman:fix/7745-nested-finish-task
Open

claxman wants to merge 1 commit into
google:mainfrom
claxman:fix/7745-nested-finish-task

Conversation

@claxman

@claxman claxman commented Oct 30, 2026

Copy link
Copy Markdown
Contributor

Please ensure you have read the contribution guide before creating a pull request.

Link to Issue or Description of Change

1. Link to an existing issue (if applicable):

Problem:
A task-mode RemoteA2aAgent treats any terminal finish_task response as the remote task completing. Both A2aAgentExecutor paths forward every event from runner.run_async, including a nested peer's finish_task. That nested event has branch set (inner@<run_id>), which is what the wire shows as adk_branch. The served agent's own finish_task leaves branch unset. The outer delegation then closes on the inner result.

Solution:
Skip a finish_task call or terminal response whose branch has a run id (name@run_id), in both executor loops, before conversion. That is what task delegation stamps, via override_branch on AgentTool and use_sub_branch on run_node. Other events on that branch are still forwarded. An unset branch is still forwarded, including a Workflow or SequentialAgent child whose author is not the served root. ParallelAgent stamps parent.child with no run id, and that child's finish_task is forwarded so a served parallel root still completes.

A client-side adk_branch check in RemoteA2aAgent is not in this change. The caller builds Event.branch from its own invocation context, not from the remote adk_branch metadata, so that check is a separate read of the A2A message.

Testing Plan

Unit Tests:

  • I have added or updated unit tests for my change.
  • All unit tests pass locally.

test_legacy_executor_forwards_finish_task_by_run_id and test_new_executor_forwards_finish_task_by_run_id each run four cases: a nested text event on inner@fc is forwarded while that hop's finish_task is dropped and the unset-branch finish_task is kept; author reporter against served root workflow with branch unset is kept; a chat root that ends in text keeps the text and drops the nested finish_task; par.child is kept. test_nested_branch_finish_task_requires_a_run_id checks the helper for unset branch, par.c, a text event on inner@fc, and a terminal finish_task on inner@fc.

pytest tests/unittests/a2a/executor/test_a2a_agent_executor.py::test_legacy_executor_forwards_finish_task_by_run_id tests/unittests/a2a/executor/test_a2a_agent_executor_impl.py::test_new_executor_forwards_finish_task_by_run_id tests/unittests/agents/llm/task/test_finish_task_tool.py::test_nested_branch_finish_task_requires_a_run_id

9 passed. mypy on _finish_task_tool.py, a2a_agent_executor.py, and a2a_agent_executor_impl.py: no issues.

Manual End-to-End (E2E) Tests:

Did not run the issue's three-agent ASGI script. The executor tests cover both _handle_request loops.

Checklist

  • I have read the CONTRIBUTING.md document.
  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • I have manually tested my changes end-to-end.
  • Any dependent changes have been merged and published in downstream modules.

Additional context

A non-terminal finish_task response on a sub-branch is still forwarded. It does not close the outer task.

A task-mode caller treats any terminal finish_task as the remote
task completing. Both executors skip that event only when the branch
carries a run id (name@run_id). ParallelAgent's parent.child branch
has no run id, so a served parallel root still completes. An unset
branch is kept, including a Workflow child with a different author.

Fixes google#7745
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RemoteA2aAgent(mode="task") closes a delegation on a nested peer's finish_task forwarded by A2aAgentExecutor

1 participant