Skip to content

feat(a2a): add A2AAgentSession with reference_task_ids and input-required support#5980

Merged
giles17 merged 9 commits into
microsoft:mainfrom
giles17:a2a-reference-task-ids
May 28, 2026
Merged

feat(a2a): add A2AAgentSession with reference_task_ids and input-required support#5980
giles17 merged 9 commits into
microsoft:mainfrom
giles17:a2a-reference-task-ids

Conversation

@giles17

@giles17 giles17 commented May 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Introduces A2AAgentSession — a typed session class that tracks A2A conversation state (context_id, task_id, task_state) — and uses it to implement two features:

  1. Reference task IDs (Python: [A2A] Link follow-up messages to the existing task via reference_task_ids #5938): Follow-up messages link to previous tasks via reference_task_ids for task refinement
  2. Input-required support (Python: [A2A] First-class support for input-required user input #5937): When the remote agent needs user input, the framework:
    • Sets task_id (not reference_task_ids) on the next outgoing message to continue the same task
    • Gates status content to only surface INPUT_REQUIRED and terminal states (matches .NET GetUserInputRequests pattern)
    • Marks updates with additional_properties["input_required"] = True for caller distinction

Changes

A2AAgentSession (new class)

  • Subclasses AgentSession with typed context_id, task_id, task_state properties
  • Tracks state from all stream payload types (task, status_update, artifact_update, message)
  • Validates context_id consistency across responses
  • Exported from agent_framework.a2a (lazy-loaded)

_prepare_message_for_a2a

  • Accepts session parameter, reads A2A state internally
  • Branches on task_state: INPUT_REQUIRED → task_id, else → reference_task_ids

_updates_from_task_update_event

  • Gates TaskStatusUpdateEvent content: only emits parts for INPUT_REQUIRED and terminal states
  • Intermediate status text (WORKING, SUBMITTED) is not surfaced to callers
  • Sets input_required: True in additional_properties when state is INPUT_REQUIRED

Stream handler (_map_a2a_stream)

  • Tracks context_id from message payloads
  • Treats INPUT_REQUIRED as immediate-yield (not accumulated) in non-streaming mode
  • Persists session state on last_task_id or last_context_id

.NET Parity

Mirrors the behavior of A2AAgent.cs:

  • CreateA2AMessage (lines 362-382): INPUT_REQUIRED → task_id, else → reference_task_ids
  • GetUserInputRequests extension: content only for INPUT_REQUIRED state
  • UpdateSession (lines 323-342): context_id validation, task_id/state tracking

Testing

  • 139 tests passing (includes new tests for content gating, input_required flag, reference_task_ids, session state tracking)
  • Pyright clean

Closes

Track the task_id from A2A responses (task, status_update, artifact_update,
and message payloads) on session.state and include it as reference_task_ids
on subsequent outgoing messages. This enables remote agents to correlate
follow-up messages as task refinements per the A2A spec.

Resolves microsoft#5938

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 20, 2026 20:57
@moonbox3 moonbox3 added the python Usage: [Issues, PRs], Target: Python label May 20, 2026
@github-actions github-actions Bot changed the title feat(a2a): link follow-up messages via reference_task_ids Python: feat(a2a): link follow-up messages via reference_task_ids May 20, 2026
@giles17 giles17 changed the title Python: feat(a2a): link follow-up messages via reference_task_ids Python: feat(a2a): link follow-up messages via reference_task_ids May 20, 2026
@moonbox3

moonbox3 commented May 20, 2026

Copy link
Copy Markdown
Contributor

Python Test Coverage

Python Test Coverage Report •
FileStmtsMissCoverMissing
packages/a2a/agent_framework_a2a
   _agent.py3602293%254, 262, 453, 458, 460, 513–514, 544–545, 549, 691, 707, 719, 740, 761, 808, 824, 834, 845, 852–853, 904
TOTAL36363431288% 

Python Unit Test Overview

Tests Skipped Failures Errors Time
7254 34 💤 0 ❌ 0 🔥 1m 53s ⏱️

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds A2A task-refinement linking in the Python A2A agent by persisting the most recently observed task_id and attaching it to subsequent outbound messages via reference_task_ids, enabling remote agents to correlate follow-up turns to the prior task per the A2A “life of a task” refinement flow.

Changes:

  • Persist the last seen A2A task_id onto session.state["a2a_task_id"] while mapping A2A stream payloads (task, status_update, artifact_update, message).
  • When sending a new message with an existing session task id, append it to the outbound A2AMessage.reference_task_ids.
  • Add a focused test suite covering first-turn behavior, follow-ups, and task_id tracking across payload types.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
python/packages/a2a/agent_framework_a2a/_agent.py Tracks the last observed task id from incoming A2A stream items and includes it as reference_task_ids on follow-up outbound messages.
python/packages/a2a/tests/test_a2a_agent.py Adds tests validating reference_task_ids behavior and task id persistence across different response payload types and session/no-session flows.

giles17 and others added 2 commits May 21, 2026 10:43
Introduce A2AAgentSession (subclass of AgentSession) with context_id,
task_id, and task_state properties. This follows the DurableAgentSession
pattern and mirrors the .NET A2AAgentSession design.

- Track task_id, context_id, and task_state from all response payload types
- Validate context_id consistency (raise on mismatch)
- Auto-assign server-generated context_id when not set
- Only A2AAgentSession gets reference tracking (no state dict fallback)
- Plain AgentSession continues to work without reference tracking
- Add serialization support (to_dict/from_dict)
- Export via agent_framework.a2a and agent_framework_a2a

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@giles17 giles17 changed the title Python: feat(a2a): link follow-up messages via reference_task_ids feat(a2a): add A2AAgentSession and reference_task_ids linking May 21, 2026
Avoids importing private _deserialize_state, matching the
DurableAgentSession pattern.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@giles17 giles17 marked this pull request as draft May 21, 2026 17:58
@giles17 giles17 marked this pull request as ready for review May 21, 2026 17:58

@giles17 giles17 left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Automated Code Review

Reviewers: 4 | Confidence: 84% | Result: All clear

Reviewed: Correctness, Security Reliability, Test Coverage, Design Approach


Automated review by giles17's agents

Previously, context_id was only captured from task, status_update, and
artifact_update payloads. Message-only responses (which carry context_id
but may lack task_id) were silently lost. This fix:

- Captures msg.context_id in the message handler
- Persists session state when either last_task_id or last_context_id is
  present (not only when task_id is truthy)
- Only updates task_id/task_state when a task_id was actually returned
- Adds a test for message-only context_id tracking

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread python/packages/a2a/agent_framework_a2a/_agent.py Outdated
Comment thread python/packages/a2a/agent_framework_a2a/_agent.py Outdated
Comment thread python/packages/a2a/agent_framework_a2a/_agent.py
Comment thread python/packages/a2a/agent_framework_a2a/_agent.py Outdated
giles17 added 2 commits May 21, 2026 13:38
# Conflicts:
#	python/packages/a2a/agent_framework_a2a/_agent.py
@giles17 giles17 requested a review from SergeyMenshykh May 21, 2026 20:55
Match .NET's GetUserInputRequests pattern: only emit TaskStatusUpdateEvent
message content when state is INPUT_REQUIRED or terminal. Intermediate
status text (WORKING, SUBMITTED) is no longer surfaced to callers.

When state is INPUT_REQUIRED, set additional_properties['input_required']
= True so callers can distinguish input requests from final responses.

Closes microsoft#5937

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@giles17 giles17 changed the title feat(a2a): add A2AAgentSession and reference_task_ids linking feat(a2a): add A2AAgentSession with reference_task_ids and input-required support May 21, 2026
Comment thread python/packages/a2a/agent_framework_a2a/_agent.py Outdated
Comment thread python/packages/a2a/agent_framework_a2a/_agent.py Outdated
Comment thread python/packages/a2a/agent_framework_a2a/_agent.py Outdated
… and input_required flag

- Do not track task_id from Message payloads (simple interactions
  without task tracking)
- Remove 'or last_task_id' fallback from status_update and
  artifact_update handlers (spec guarantees task_id is always set)
- Remove additional_properties['input_required'] flag (content gating
  to INPUT_REQUIRED/terminal states is the signal itself)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@giles17 giles17 requested review from eavanvalkenburg and removed request for eavanvalkenburg May 26, 2026 06:44
This was referenced Jun 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants