Skip to content

fix: RemoteA2aAgent fails to send taskId in multi-turn scenarios#4944

Open
shriramThakare3 wants to merge 7 commits intogoogle:mainfrom
shriramThakare3:main
Open

fix: RemoteA2aAgent fails to send taskId in multi-turn scenarios#4944
shriramThakare3 wants to merge 7 commits intogoogle:mainfrom
shriramThakare3:main

Conversation

@shriramThakare3
Copy link

@shriramThakare3 shriramThakare3 commented Mar 21, 2026

Link to Issue or Description of Change

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

Problem:
RemoteA2aAgent only sends context_id on subsequent turns, never task_id, causing the remote server to spawn a new task every turn instead of resuming the paused one. A multi-turn flow (e.g. input-required → user replies) always creates stale orphaned tasks on the remote agent.

Solution:
In _construct_message_parts_from_session, after reading context_id from custom_metadata, also read the stored task state from the previous response metadata. Forward task_id only when the task is still open (input-required or auth-required). For terminal states (completed, failed, cancelled) task_id stays None so the server correctly starts a fresh task under the same context_id.

Testing Plan

Unit Tests:

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

  • All unit tests pass locally.

  • test_multiturn_sends_task_id_when_input_required — verifies task_id is included in the second-turn request when task state is input-required

  • test_multiturn_sends_task_id_when_auth_required — same for auth-required

  • test_first_turn_omits_task_id — verifies task_id is None on the first turn

  • test_completed_task_omits_task_id — verifies task_id is not forwarded when previous task state is completed

Manual End-to-End (E2E) Tests:

  1. Set up a RemoteA2aAgent pointing at the currency agent from a2a-samples
  2. Launch adk web and send How much is 10 USD?
  3. Agent responds with Provide the currency to convert to and task.status=input-required
  4. Send CAD as the second turn
  5. Verify the outgoing A2A request contains both contextId and taskId matching the first turn's task
  6. Verify the remote agent returns the conversion result without creating a new task

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

The same root cause was previously reported in #3765. That issue proposed a fix but it was not fully applied — task_id was still never populated because the state check was missing.

@adk-bot adk-bot added the core [Component] This issue is related to the core interface and implementation label Mar 21, 2026
@rohityan rohityan self-assigned this Mar 23, 2026
@rohityan
Copy link
Collaborator

Hi @shriramThakare3 , Thank you for your contribution! We appreciate you taking the time to submit this pull request. Can you please fix the failing unit tests , mypy-diff tests and formatting errors

@rohityan rohityan added request clarification [Status] The maintainer need clarification or more information from the author labels Mar 23, 2026
shriramThakare3 and others added 6 commits March 23, 2026 21:33
94 passed, 0 failed
Files changed: 2
  - src/google/adk/agents/remote_a2a_agent.py
  - tests/unittests/agents/test_remote_a2a_agent.py
```

**Changes:**
- `_construct_message_parts_from_session` now reads task state from response metadata and forwards `task_id` when state is `input-required` or `auth-required`
- Return type updated from 2-tuple to 3-tuple `(parts, context_id, task_id)`
- `_run_async_impl` unpacks 3 values and passes `task_id` to `A2AMessage`
- 9 test unpacking calls updated to 3-tuple
- 6 mock return values updated from 2-tuple to 3-tuple
@shriramThakare3
Copy link
Author

hello, @rohityan
made changes to fix failing tests

Comment on lines +404 to +411
response_meta = metadata.get(A2A_METADATA_PREFIX + "response", {})
task_state = None
if isinstance(response_meta, dict):
status = response_meta.get("status", {})
if isinstance(status, dict):
task_state = status.get("state")
if task_state in ("input-required", "auth-required"):
task_id = metadata.get(A2A_METADATA_PREFIX + "task_id")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue with this implementation is that it is not possible to define if the new user message is a follow up to the input-required event, or a request for a new task -> in this case the task_id should not be set

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The remote agent owns the task,it knows if the task_id is still valid or not. If the user starts a new request, the remote agent can handle it. Forwarding task_id on input-required is the right default behavior. If more control is needed, that can be a separate improvement.

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

Labels

core [Component] This issue is related to the core interface and implementation request clarification [Status] The maintainer need clarification or more information from the author

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RemoteA2AAgent fails to send taskId in multi-turn scenarios

4 participants