Skip to content

fix(server): accept trailing-slash JSON-RPC endpoint; enqueue Task in TCK SUT - #1165

Open
kuangmi-bit wants to merge 2 commits into
a2aproject:mainfrom
kuangmi-bit:fix/jsonrpc-trailing-slash
Open

fix(server): accept trailing-slash JSON-RPC endpoint; enqueue Task in TCK SUT#1165
kuangmi-bit wants to merge 2 commits into
a2aproject:mainfrom
kuangmi-bit:fix/jsonrpc-trailing-slash

Conversation

@kuangmi-bit

Copy link
Copy Markdown

Summary

Two changes that let the A2A 1.0 TCK exercise the JSON-RPC SUT (part of the work tracked in #666):

  1. create_jsonrpc_routes accepts the trailing-slash endpoint variant. HTTP clients (httpx in particular) normalize an empty request path to a trailing slash, so POST /a2a/jsonrpc/ previously returned 404 even though /a2a/jsonrpc worked. The spec does not mandate one spelling over the other, and a 404 on the trailing-slash form breaks any spec-conformant client that does not strip it. Both variants now route to the same dispatcher.

  2. tck/sut_agent.py enqueues the Task itself before emitting TaskStatusUpdateEvents (via new_task_from_user_message). The SDK's active-task machinery requires this ordering (it raises InvalidAgentResponseError otherwise), and the 1.0 TCK CORE-SEND-* requirements assert it.

Verification

Ran the 1.0 TCK (a2a-tck tag 1.0.0.alpha2, jsonrpc transport, must level) against the SUT locally:

before: 53 failed, 16 passed
after:   6 failed, 67 passed

The remaining 6 failures are not transport issues — they are SUT feature gaps (artifact-carrying responses, DM-ART-001) and one SDK error-code mapping gap (ContentTypeNotSupportedError reported as ParseError). Those are follow-ups; this PR fixes the transport-level blockers.

Unit tests: tests/server/routes/ 96 passed. Ruff clean on touched files.

Related

… TCK SUT

Two changes that together let the 1.0 TCK exercise the JSON-RPC SUT:

1. create_jsonrpc_routes now registers both the exact rpc_url and its
   trailing-slash variant. HTTP clients (httpx in particular) normalize
   an empty request path to a trailing slash, so POST /a2a/jsonrpc/ was
   previously 404 even though /a2a/jsonrpc worked. This is a protocol
   compatibility fix: the spec does not mandate one spelling over the
   other, and a 404 on the trailing-slash form breaks any client that
   does not strip it.

2. tck/sut_agent.py now enqueues the Task itself (via
   new_task_from_user_message) before emitting TaskStatusUpdateEvents.
   The SDK's active-task machinery requires this ordering (InvalidAgentResponseError
   otherwise), and the 1.0 TCK CORE-SEND tests assert it.

Verified against a2a-tck 1.0.0.alpha2 (jsonrpc, must level):
53 failed -> 6 failed before this change, with the remaining failures
being SUT feature gaps (artifacts) and one SDK error-code mapping gap,
not transport issues.
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

🧪 Code Coverage (vs main)

⬇️ Download Full Report

Base PR Delta
src/a2a/server/events/event_queue_v2.py 91.79% 91.28% 🔴 -0.51%
src/a2a/utils/telemetry.py 91.47% 90.70% 🔴 -0.78%
Total 93.00% 92.97% 🔴 -0.02%

Generated by coverage-comment.yml

…card

Two more 1.0 compatibility fixes surfaced by running the REST and gRPC
rows of the TCK:

- protocolBinding 'REST' -> 'HTTP+JSON': the 1.0 TCK's protocol binding
  map only recognizes JSONRPC / GRPC / HTTP+JSON. The old name made the
  whole REST transport untestable ("No usable transports after filtering").
- gRPC interface url 'http://localhost:50051' -> 'localhost:50051': the
  gRPC client treats the url as a channel target; the http:// prefix
  fails DNS resolution in grpcio.

Verified against a2a-tck 1.0.0.alpha2 (must level):
- jsonrpc: 6 failed / 67 passed
- http_json (REST): 5 failed / 61 passed
- grpc: 7 failed / 48 passed
Remaining failures are SUT feature gaps (artifact-carrying responses,
MessageResponse variants) plus two status/error-code mappings.
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.

1 participant