Repository navigation
fix(server): run follow-up messages in the sender's contextvars - #1317
Merged
mykytanetipa merged 2 commits intoOct 6, 2026
Merged
Conversation
ActiveTask creates its producer once, during the first request for a task, so every later message on the task ran AgentExecutor.execute() with the first request's contextvars. Capture the caller's context in enqueue_request() and run execute() in it. Fixes a2aproject#1316
🧪 Code Coverage (vs
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
ActiveTaskcreates its producer once, during the first request for a task. Later messages on the same task are queued to that producer, soAgentExecutor.execute()ran with the first request's contextvars. Per-request values set by ASGI middleware or aServerCallContextBuilder(auth tokens, tenant identity, tracing) were stale on every follow-up turn, for example a reply afterinput-required.This change captures
contextvars.copy_context()inenqueue_request(), which runs in the sender's request, and runsexecute()in that context as a child task. Awaiting the child keeps cancellation working, because cancelling the producer cancels the child.Context.run(asyncio.create_task, ...)works on Python 3.10.Only
execute()changes context. Task-store writes and push notifications still run in the producer's context, as before.Tested:
New
test_follow_up_message_runs_in_sender_contextvars, for bothon_message_sendandon_message_send_stream. It fails onmainand passes with this change.The reproduction in [Bug]: DefaultRequestHandler runs follow-up messages on a task with the first request's contextvars #1316 prints
request-2for the follow-up../scripts/lint.shpasses.uv run pytest --cov=srcgives 2223 passed, 93% coverage.tests/integration/cross_version/client_server/test_client_server.pywas deselected because its server fails to start in my local environment onmaintoo.Follow the
CONTRIBUTINGGuide.Make your Pull Request title in the https://www.conventionalcommits.org/ specification.
Ensure the tests and linter pass (Run
bash scripts/format.shfrom the repository root to format)Appropriate docs were updated (if necessary)
Fixes #1316 🦕