fix(a2a): namespace forwarded session context_id by app/user - #7306
chelsealong wants to merge 2 commits into
Conversation
RemoteA2aAgent.forward_session_id_as_context_id forwarded the raw ctx.session.id as the remote A2A context_id. Local ADK session identity also includes user_id and app_name, so two distinct users (or apps) that happen to reuse the same session ID were mapped to the same remote context, letting one user's conversation history leak to another on a remote server that keys state off context_id. Derive the forwarded context_id from a hash of app_name, user_id, and session id instead of the raw session id, so distinct local identities never collapse onto the same remote context. Fixes google#7305
This change would largely kill the utility of the forwarding feature, which is to have a consistent id that can be easily correlated across agents. A single SHA-256 digest can't be decomposed into its component parts, so downstream there is no functional difference between sending this and a random string. |
|
Good point. I dropped the hash: the forwarded |
Summary
Fixes #7305.
RemoteA2aAgentwithforward_session_id_as_context_id=Trueforwarded theraw
ctx.session.idas the remote A2Acontext_id. Local ADK sessionidentity also includes
user_idandapp_name, so two distinct local users(or apps) that happen to reuse the same session ID were mapped to the same
remote context. Against a remote implementation that keys conversation state
off
context_id, this let one user's conversation history leak to anotheruser.
Fix
Added
_namespaced_session_context_id()insrc/google/adk/a2a/agent/_remote_a2a_agent.py, which derives the forwardedcontext_idfrom a SHA-256 digest ofapp_name,user_id, andsession.id(joined with a separator byte that cannot appear in the inputs), instead of
the raw session ID.
RemoteA2aAgent._run_async_implnow calls this helperwherever it previously read
ctx.session.iddirectly. Updated theforward_session_id_as_context_iddocstring insrc/google/adk/a2a/agent/config.pyto describe the namespaced derivation.This only changes the derivation of the default
context_idused when nocontext ID has already been established by a prior remote response
(
context_idfrom_construct_message_parts_from_sessionstill takesprecedence, preserving existing conversation continuity).
Test plan
Updated
tests/unittests/a2a/agent/test_remote_a2a_agent.py:test_run_async_impl_uses_session_id_when_opted_innow asserts thenamespaced (hashed) context_id is used, not the raw session id.
test_run_async_impl_namespaces_context_id_by_user, a regressiontest asserting that two sessions with the same
session.idbut differentuser_idproduce different derivedcontext_idvalues (this is the exactcollision scenario in the issue).
Confirmed the new/updated tests fail without the fix:
With the fix applied:
Also ran
pre-commit run --files <changed files>(ruff, isort, pyink,addlicense, ADK compliance checks, doc-link checks, codespell): all passed.
AI-assistance disclosure
This change was authored with the help of an AI coding agent (Claude Code),
which investigated the issue, wrote the fix and the regression test, and ran
the test suite and pre-commit checks locally. All output was reviewed before
submission.