Skip to content

fix(a2a): run follow-up task messages in their own request contextvars - #693

Open
tejaskash wants to merge 1 commit into
mainfrom
fix/a2a-per-message-contextvars
Open

tejaskash wants to merge 1 commit into
mainfrom
fix/a2a-per-message-contextvars

Conversation

@tejaskash

Copy link
Copy Markdown
Contributor

What

build_a2a_app and serve_a2a on a2a-sdk 1.x now run each message of a task in the contextvars of the request that sent it.

Why

Fixes #690. a2a-sdk 1.x creates one producer task per task id during the first request, and later messages are queued to it. A follow-up message, such as a reply after input-required, ran execute() with the first request's contextvars. BedrockAgentCoreContext (workload access token, request and session ids, OAuth2 callback URL, forwarded headers) and any middleware contextvars returned the first request's values. That means @requires_access_token and identity propagation used a stale, possibly expired token.

No a2a-sdk release fixes this (verified on 1.2.2).

How

  • _ContextvarsSnapshotRequestContextBuilder wraps a2a's SimpleRequestContextBuilder and stores contextvars.copy_context() in call_context.state for every message.
  • _PerMessageContextvarsExecutor runs the user's execute() in that snapshot, in a child task, so cancellation still reaches it.

The snapshot is taken in the request handler and not in BedrockCallContextBuilder, so it works with a custom context_builder and with every transport. The a2a-sdk 0.3 path is unchanged because it already runs the executor per request.

The ultimate fix belongs upstream: ActiveTask.enqueue_request should capture the sender's context. Filed as a2aproject/a2a-python#1316 with a patch I verified on 1.2.2. Once it lands and our minimum a2a-sdk includes it, both wrapper classes can be deleted.

How tested

  • New regression test, run for both SendMessage and SendStreamingMessage, checks a middleware contextvar and the workload access token on the follow-up turn. It fails on main and passes with this change.
  • The reproduction from [BUG] A2A (a2a-sdk 1.x): follow-up messages on an existing task run the executor with the first request's contextvars #690 prints request-2 for turn 2 on a2a-sdk 1.1.2 and 1.2.2, for send and stream.
  • 40 concurrent two-turn tasks showed no token mixing between tasks. CancelTask still cancels the user's executor.
  • Runtime tests pass on a2a-sdk 1.1.2 (348 passed). The a2a tests pass on 0.3.26 (36 passed, 1 skipped). ruff and mypy are clean.

a2a-sdk 1.x runs every message of a task in one producer task created by
the first request, so follow-up messages saw the first request's
contextvars, including BedrockAgentCoreContext and the workload access
token. Snapshot contextvars per message in the request context builder
and run the executor in that snapshot.

Fixes #690
@tejaskash
tejaskash requested a review from a team October 5, 2026 19:03
@github-actions github-actions Bot added the size/m PR size: M label Oct 5, 2026
@tejaskash
tejaskash deployed to auto-approve October 5, 2026 19:20 — with GitHub Actions Active
@tejaskash
tejaskash deployed to auto-approve October 5, 2026 19:20 — with GitHub Actions Active
@tejaskash
tejaskash deployed to auto-approve October 5, 2026 19:20 — with GitHub Actions Active
@tejaskash
tejaskash deployed to auto-approve October 5, 2026 19:20 — with GitHub Actions Active
@tejaskash
tejaskash deployed to auto-approve October 5, 2026 19:20 — with GitHub Actions Active
@tejaskash
tejaskash deployed to auto-approve October 5, 2026 19:20 — with GitHub Actions Active
@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

✅ No Breaking Changes Detected

No public API breaking changes found in this PR.

This branch was successfully deployed

1 active deployment
auto-approve — e7665cc0 Deployed Oct 5, 2026 by tejaskash via Test (gateway) #1618
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m PR size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] A2A (a2a-sdk 1.x): follow-up messages on an existing task run the executor with the first request's contextvars

1 participant