Skip to content

Python: fix: A2AAgent.run() ignores session parameter for context_id propagation#5213

Open
LEDazzio01 wants to merge 2 commits intomicrosoft:mainfrom
LEDazzio01:fix/a2a-agent-session-context-id-v2
Open

Python: fix: A2AAgent.run() ignores session parameter for context_id propagation#5213
LEDazzio01 wants to merge 2 commits intomicrosoft:mainfrom
LEDazzio01:fix/a2a-agent-session-context-id-v2

Conversation

@LEDazzio01
Copy link
Copy Markdown
Contributor

Summary

Fixes #4663 — Supersedes #4713 (rebased onto current main).

A2AAgent.run() accepts a session parameter but never uses session.session_id when constructing
the outbound A2A message. This means the remote agent cannot correlate multiple messages belonging
to the same conversation.

Changes

  1. Derive context_id from sessionsession.session_id is used as the A2A context_id
    when a session is provided.
  2. Update _prepare_message_for_a2a signature — accepts an optional context_id keyword argument.
  3. Fallback chaincontext_id priority: session → message.additional_properties["context_id"] → random UUID.
  4. Docstring updates — documented the session parameter's new behavior and the context_id parameter.
+ context_id: str | None = session.session_id if session else None
  ...
- a2a_message = self._prepare_message_for_a2a(normalized_messages[-1])
+ a2a_message = self._prepare_message_for_a2a(normalized_messages[-1], context_id=context_id)
  ...
- context_id=message.additional_properties.get("context_id"),
+ context_id=context_id or message.additional_properties.get("context_id") or uuid.uuid4().hex,

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • Is this a breaking change? No

Copilot AI review requested due to automatic review settings April 10, 2026 21:53
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes Python A2A agent session continuity by ensuring the outbound A2A context_id is derived from the provided AgentSession (or falls back to message metadata / a generated UUID), enabling remote agents to correlate multi-turn conversations.

Changes:

  • Propagate session.session_id into outbound A2A messages via a new context_id kwarg on _prepare_message_for_a2a.
  • Add a context_id fallback chain (session → message.additional_properties["context_id"] → random UUID) and filter context_id out of wire metadata.
  • Extend streaming/run plumbing to pass SessionContext/AgentSession through _map_a2a_stream and optionally emit intermediate task content.

Comment on lines 33 to 46
from agent_framework import (
AgentResponse,
AgentResponseUpdate,
AgentSession,
BaseAgent,
Content,
ContinuationToken,
HistoryProvider,
Message,
ResponseStream,
SessionContext,
normalize_messages,
prepend_agent_framework_to_user_agent,
)
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

HistoryProvider is imported from agent_framework, but the core package exports BaseHistoryProvider (and InMemoryHistoryProvider) rather than a HistoryProvider symbol. This will raise an ImportError at runtime. Use BaseHistoryProvider here and update the isinstance(provider, ...) check accordingly.

Copilot uses AI. Check for mistakes.
Comment on lines +308 to +326
provider_session = session
if provider_session is None and self.context_providers:
provider_session = AgentSession()

session_context = SessionContext(
session_id=provider_session.session_id if provider_session else None,
service_session_id=provider_session.service_session_id if provider_session else None,
input_messages=normalized_messages or [],
options={},
)

response = ResponseStream(
self._map_a2a_stream(a2a_stream, background=background),
self._map_a2a_stream(
a2a_stream,
background=background,
emit_intermediate=stream,
session=provider_session,
session_context=session_context,
),
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

The PR description focuses on context_id propagation, but this change also introduces new behavior around context provider lifecycle (SessionContext, auto-creating AgentSession, invoking before_run/after_run) and streaming intermediate task updates. If this is intentional, it should be called out in the PR description (and ideally split if it’s unrelated), since it changes observable behavior beyond context_id handling.

Copilot uses AI. Check for mistakes.
Comment on lines +292 to 306
normalized_messages = normalize_messages(messages)

# Derive context_id from session when available so the remote agent
# can correlate messages belonging to the same conversation.
context_id: str | None = session.session_id if session else None

if continuation_token is not None:
a2a_stream: AsyncIterable[A2AStreamItem] = self.client.resubscribe(
TaskIdParams(id=continuation_token["task_id"])
)
else:
normalized_messages = normalize_messages(messages)
a2a_message = self._prepare_message_for_a2a(normalized_messages[-1])
if not normalized_messages:
raise ValueError("At least one message is required when starting a new task (no continuation_token).")
a2a_message = self._prepare_message_for_a2a(normalized_messages[-1], context_id=context_id)
a2a_stream = self.client.send_message(a2a_message)
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

This adds context_id derivation from session.session_id and new fallback behavior in _prepare_message_for_a2a, but there are existing unit tests for A2AAgent and none currently validate that run(..., session=...) actually sends an A2AMessage with the expected context_id (or that additional_properties['context_id'] is honored/filtered from metadata). Add focused tests to prevent regressions in session/context correlation.

Copilot uses AI. Check for mistakes.
@LEDazzio01
Copy link
Copy Markdown
Contributor Author

Addressing Copilot's review comments:

1. HistoryProvider import — This import is unchanged from main. The HistoryProvider symbol is already imported and used in the existing _map_a2a_stream method on the current main branch (line 360: if isinstance(provider, HistoryProvider) and not provider.load_messages:). This is not a change introduced by this PR.

2. SessionContext/provider lifecycle scope — Same situation. The SessionContext, provider_session auto-creation, and before_run/after_run lifecycle code all exist on main already. The diff appears large because the fork's main was slightly behind upstream when the branch was created. The only changes in this PR are:

  • Line 295: context_id: str | None = session.session_id if session else None
  • Line 303: context_id=context_id parameter added to _prepare_message_for_a2a()
  • Lines 576-577: _prepare_message_for_a2a signature updated with *, context_id: str | None = None
  • Lines 585-591: Docstring for context_id parameter
  • Line 668: Fallback chain context_id=context_id or message.additional_properties.get("context_id") or uuid.uuid4().hex
  • Line 276: Session docstring enhancement

3. Missing tests — Valid feedback. I'll push a dedicated test file for context_id propagation.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: [agent-framework-a2a] A2AAgent.run() ignores session parameter - context_id not propagated to A2A protocol

3 participants