Tolerate empty context IDs when updating A2A session state - #606
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the A2A provider’s session reconciliation logic to treat empty streamed ContextID values as “no update” (instead of an error or a clobber), matching the expected streaming behavior and aligning with the existing setTaskID empty-guard pattern.
Changes:
- Prevent
updateSessionContextIDfrom erroring on context mismatches when the incomingcontextIDis empty. - Prevent
setContextIDfrom overwriting an existing session context ID with an empty string. - Add streaming-focused black-box tests that cover empty-context streamed messages and initial context assignment, via an extended transport mock.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| provider/a2aprovider/session.go | Adds an early return so empty context IDs do not clobber the session’s stored context. |
| provider/a2aprovider/a2a.go | Updates the mismatch guard to ignore empty incoming context IDs during session reconciliation. |
| provider/a2aprovider/a2a_test.go | Extends the streaming transport mock and adds tests validating empty-context streaming behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
d1bfa91 to
32d8a9f
Compare
This comment has been minimized.
This comment has been minimized.
32d8a9f to
8ed7e66
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
A bare streamed message can carry an empty ContextID. The mismatch guard in updateSessionContextID fired whenever the session already held a context ID and the incoming one was empty, spuriously erroring the whole run, and setContextID then clobbered the stored value with the empty string. Skip the mismatch check when the incoming context ID is empty and avoid overwriting a stored context ID with an empty value, matching the .NET semantics where ContextId is only assigned when unset (ContextId ??= contextId) and mirroring the existing empty-guard in setTaskID.
a1be096 to
434c973
Compare
Parity Review: ✅ ApprovedThis PR makes internal corrections to Parity assessment: This fix improves alignment with the upstream .NET implementation. As noted in the PR description, the .NET SDK uses
No exported API changes — The Warning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "awmgmcpg"See Network Configuration for more information.
|
What
updateSessionContextIDinprovider/a2aprovider/a2a.goreconciles the A2A response's context ID with the one stored in the session. Two problems when the incoming context ID is empty:currentContextID != "" && currentContextID != contextID) fires whenever the session already holds a context ID and the incoming one is empty, returningmismatched context IDand erroring the whole run.setContextIDunconditionally overwrote the stored context ID with the empty string.A bare streamed
Messagelegitimately carries an emptyContextID(sendMsgreadstaskInfo.ContextID), so both paths are reachable in normal streaming.This is fixed by adding
contextID != ""to the mismatch condition and adding an earlyif contextID == "" { return }guard insidesetContextID, so empty streamed values neither error nor clobber the stored context ID.Why
This aligns with .NET, where the context ID is only assigned when currently unset (
ContextId ??= contextId), and restores internal consistency:setTaskIDalready guardsif taskID == "" { return }, whilesetContextIDdid not. The asymmetry is what let the empty case slip through.Testing
Added two black-box tests in
a2a_test.godriven through the existing streaming harness (extended the shared mock with arawStreamingResponseflag so a bare message's empty context ID is not backfilled from the request):TestRunStreamingWithEmptyContextIDKeepsSessionContext: session holdsctx-1, a streamed message with emptyContextIDproduces no error and leavesServiceID()asctx-1. Fails before the fix (mismatched context ID: session has "ctx-1" but A2A response has ""), passes after.TestRunStreamingWithEmptyInitialContextStoresResponseContext: session starts with no context ID, first event carriesctx-1, which is stored.go build ./...,go vet ./provider/a2aprovider/..., andgo test ./provider/a2aprovider/...all pass.