Skip to content

Add standalone native A2A session routing sample with same-user and real-user evidence - #1156

Open
Hameed Kunkanoor (Hameedkunkanoor) wants to merge 3 commits into
mainfrom
feature/a2a-session-routing-sample
Open

Hameed Kunkanoor (Hameedkunkanoor) wants to merge 3 commits into
mainfrom
feature/a2a-session-routing-sample

Conversation

@Hameedkunkanoor

Copy link
Copy Markdown
Contributor

Summary

Add one standalone native A2A 1.0 sample at
samples/python/hosted-agents/bring-your-own/a2a/session-routing.
No travel-planner, Flight, Hotel, web-search or other existing sample code is included.
The branch starts from upstream main, not the previous multi-sample branch.

The question we tested:

If a user calls A and B, and both agents call C, can both requests land in the same hosted session of C? What changes when two independently authenticated users make those calls?

U1 --> A --+
          +--> C --> session-local synthetic marker ledger
U1/U2 -> B+

Implementation

  • Three deterministic hosted agents selected by REPRO_ROLE, sharing one implementation.
  • No LLM, Copilot session, model deployment or external tool; this isolates routing from model behavior.
  • A/B use their own managed identities and forward the SDK's request-scoped platform call headers.
  • fresh: omit C's context; explicit: supply c_context_id; inherit: copy the incoming A2A context to C.
  • C reports actual hosted session ID/GUID, A2A context/task IDs, boot ID, hashed user fingerprint, sequence number and prior synthetic markers.
  • A single-user sequential/concurrent runner and a real-user client bound explicitly to AzureCliCredential.
  • A comparator that checks saved real-user receipts without invoking Azure.
  • A portable manifest with a configurable existing project endpoint; no live subscription/project endpoint is embedded.
  • Fully pinned dependencies and a supported Linux dependency-bundle helper. Bundled code deployment avoids the dependency-download TLS failures encountered during the original remote builds.

Important: an A2A context ID is not a hosted session ID. We compared C's platform-injected session ID and its stored history rather than inferring sharing from matching context labels.

What we tried and observed

1. Same real user calls A and B

Recorded run: repro-9af72d559e114a51864d528caabd0bf8.
The original deployment completed 18 parent invocations, 18 downstream calls and 57 passing assertions.

Scenario Observed at C
No downstream context ID, sequential + three concurrent pairs Eight distinct C contexts and eight distinct actual hosted C sessions
Same explicit downstream C context, sequential + concurrent Same hosted C session; distinct task IDs; markers from both callers visible in that session
Same incoming context copied by A and B to C A/B had separate hosted sessions but their C calls reused one hosted session
Different C context per branch, followed by repeat calls Separate C sessions, with each branch retaining its own context history

Concrete shared-context evidence:

Field Value
Resolved user fingerprint at C, both paths 3fa479bce41fc1b2a75d
C context ID repro-9af72d559e114a51864d528caabd0bf8-shared-c
Actual C hosted session ID, both paths eeac7b653964cc989c6b26e2143e08da4dbec8a18c752e35b6225f3d28c3e95
C ledger sequence 1, 2, 3, 4
History evidence B's sequential request saw A's earlier synthetic marker

These are not random collisions: the shared cases deliberately reused the same context ID. The fresh cases did not share sessions in this run.

2. Two independently authenticated users: U1 -> A -> C and U2 -> B -> C

Both users sent the identical downstream context: two-real-users-nov9-test01.
Both tasks completed successfully.

C receipt field U1 -> A -> C U2 -> B -> C
UTC timestamp 2026-11-09 16:08:50 2026-11-10 17:51:03
User fingerprint 3fa479bce41fc1b2a75d 8c98f58254de5d698ab0
Context ID two-real-users-nov9-test01 two-real-users-nov9-test01
Hosted session ID 48b40392d95634cce5818562c55536b8596fd2f5f6df2d34bf73de3368c0145 f6a0aac7845d438e7db4ad8745900a43892360d6620c1dfb34fbb839e3ed49f
Task ID 203fe03e-2ec8-4cec-b775-7ad760cfabb4 1a038aa4-9078-4ae0-bfca-158514e1b296
Sequence 1 1
Prior session/context messages Empty Empty

Each parent's user fingerprint matched C's fingerprint on that path. The equal context labels did not merge the two users' C sessions in these observations.
U1's response was captured directly; U2's completed response was supplied by the independently signed-in tester. The sample retains selected non-secret fields with provenance.

3. Attempts that did not establish a result

  • Synthetic x-ms-user-identity delegation: 403, "Caller is not authorized to delegate to another user." Normal access returned 200. No delegation permissions were changed and no isolation conclusion is drawn from that attempt.
  • U2's first inline-JSON attempt: HTTP 200 with JSON-RPC -32700. Parsing failed before B -> C completed; this was not counted as a pass. A corrected file-based request produced the completed receipt above.
  • Initial agent versions failed during code/dependency builds. The recorded cloud experiment used A version 2, B version 3 and C version 2. The generic manifest does not reference those existing deployed names.

Interpretation and limitations

For the configuration tested:

  • Same resolved user + same C context: C session reuse and shared synthetic state were observed.
  • Different resolved users + same C context: distinct C sessions were observed.
  • Different immediate caller agents alone did not separate the same user's shared downstream context.
  • Independent branches of one user's workflow should use distinct downstream context IDs, retaining each only for its own follow-ups.

The real-user requests were approximately 26 hours apart, not concurrent. They do not prove simultaneous cross-user isolation, repeat-call history isolation or cross-tenant isolation. We did not test LLM conversation mixing. Finite tests cannot establish the impossibility of all collisions or service bugs.

Session/context/task IDs and fingerprints are opaque diagnostic comparison values. No bearer tokens, raw user identifiers, private endpoint credentials, .azure state, virtual environments or dependency binaries are committed.

Reproduce

See the sample README for prerequisite access, unique agent naming, existing-project setup, C-then-A/B deployment, required forwarder roles, local tests and two real-user sign-ins.

Historical evidence:

  • evidence/same-user.json: the 18 observations and 57 checks.
  • evidence/real-user-u1.json: selected U1 receipt fields.
  • evidence/real-user-u2.json: selected tester-supplied U2 receipt fields.

Live runs write to ignored results/, not over the historical evidence.

Validation

  • Seven unit tests pass, including negative cases for shared users/sessions and cross-user history markers.
  • Fresh local three-agent integration run: 18 end-to-end calls, 29 passing context/history assertions; child servers cleaned up.
  • Historical real-user receipt comparison: all six checks pass.
  • Linux Python 3.13 dependency-bundle preparation succeeds with the fully pinned graph.
  • Repository cloud-contract policy passes.
  • Repository reproducible-dependency policy passes, including --resolve closure validation.

No new cloud deployment or real-user invocation is claimed for this PR preparation; the cloud results above are the recorded experiments.

Why one CI metadata line is included

The only change outside this sample is its exact-path entry in the shared hosted-agent cloud-deployment skiplist. The shared harness supports Responses/Invocations, not native A2A card discovery/JSON-RPC, ordered three-agent setup or separate human sign-ins. This sample uses its dedicated runners rather than claiming unsupported shared-harness coverage. No unrelated sample exclusion or code is changed.

Include deterministic A/B-to-C agents, dedicated local and real-user runners, fully pinned runtime dependencies, and recorded same-user and two-user evidence. Exclude only this sample from unsupported shared cloud A2A orchestration.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The remote-run assertion checks context-filtered history rather than full session history, allowing cross-context state leakage to go undetected.

1 open issue
What changed in this PR

Adds a standalone native A2A sample to the Python hosted-agent collection, demonstrating how downstream context IDs and authenticated users affect session reuse without involving a model.

Changes:

  • Implements deterministic A/B forwarders and a C observer with session-local marker history.
  • Adds local and remote runners, real-user receipt comparison, tests, and historical evidence with explicit limitations.
  • Provides bundled deployment setup and excludes the sample from the unsupported shared cloud harness.

Paths below are relative to samples/python/hosted-agents/bring-your-own/a2a/session-routing/, except the CI skiplist.

File Description
tests/​test_routing.py Tests routing modes, ledger history, and receipt comparison.
test_local.py Starts three local agents and runs the experiment.
src/​agent/​requirements.txt Pins the complete dependency graph.
src/​agent/​main.py Implements forwarding and session observation.
src/​agent/​client.py Handles native A2A discovery, authentication, and completed-task validation.
src/​agent/​.agentignore Excludes local artifacts from deployment uploads.
run_real_user.py Invokes agents using CLI credentials and compares saved receipts.
run_experiment.py Exercises sequential, concurrent, and follow-up routing scenarios.
README.md Documents setup, reproduction, findings, and limitations.
prepare_bundle.ps1 Prepares Linux Python dependency bundles.
evidence/​same-user.json Records same-user observations and checks.
evidence/​real-user-u2.json Preserves selected second-user receipt fields and provenance.
evidence/​real-user-u1.json Preserves selected first-user receipt fields and provenance.
azure.yaml Configures three hosted agents against an existing project.
AGENTS.md Documents sample-specific development and evidence guidance.
.gitignore Excludes generated results, bundles, and deployment state.
.azure-pipelines/​scripts/​hosted-agent-samples-ci-skiplist Adds the exact-path native A2A cloud-harness exclusion.

Review effort: Balanced

Comment on lines +65 to +67
check(f"{label}: no cross-caller context history",
all(item["marker"] not in markers - {receipt["marker"]}
for receipt in pair for item in receipt["prior_context_messages"]))

This branch was successfully deployed

1 active deployment
L4-validation — dfb6bb48 Deployed Nov 11, 2026 by Hameedkunkanoor via trusted #938
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants