feat(server): restore FastAPI /docs visibility for A2A routes#1024
feat(server): restore FastAPI /docs visibility for A2A routes#1024martimfasantos wants to merge 11 commits into
Conversation
40cbe9c to
697db0d
Compare
🧪 Code Coverage (vs
|
| Base | PR | Delta | |
|---|---|---|---|
| src/a2a/server/events/event_queue_v2.py | 91.19% | 91.71% | 🟢 +0.52% |
| src/a2a/utils/telemetry.py | 90.63% | 91.41% | 🟢 +0.78% |
| src/a2a/server/routes/helpers/_proto_schema.py (new) | — | 94.23% | — |
| src/a2a/server/routes/helpers/fastapi.py (new) | — | 91.78% | — |
| src/a2a/server/routes/helpers/jsonrpc.py (new) | — | 100.00% | — |
| Total | 93.08% | 93.11% | 🟢 +0.02% |
Generated by coverage-comment.yml
There was a problem hiding this comment.
Code Review
This pull request introduces the add_a2a_routes_to_fastapi utility, which enables A2A endpoints (Agent Card, JSON-RPC, and REST) to be correctly registered and documented within FastAPI's auto-generated OpenAPI schema. The implementation includes a new Protobuf-to-JSON-Schema conversion module to provide detailed request body documentation derived from protocol definitions. Feedback was provided regarding the scalability of the oneOf generation logic in _proto_schema.py, which currently creates a Cartesian product of variants for messages containing multiple oneofs, potentially leading to an exponential explosion of schema variants.
…d inline component install Replace O(∏fields) Cartesian product oneof generation with O(∑fields) allOf+oneOf-per-group approach, and inline _install_components into add_a2a_routes_to_fastapi to remove a single-use wrapper function.
|
Thanks for putting this together, would love to see this feature merged. In our company, Swagger acts as the primary communication layer between the developers building the agents and the integration teams exposing them in or API gateway. Furthermore, it allows a new team to quickly understand and test requests to a new agent directly from the browser without having to write boilerplate client code first. |
Summary
src/a2a/server/routes/helpers/— a new subpackage of transport-specific route helpers mirroring the layout ofclient/transports/add_a2a_routes_to_fastapi()re-registers A2A Starlette routes asAPIRouteinstances so FastAPI's OpenAPI generator picks them up and they appear in/docsand/openapi.jsonA2A: Agent Card,A2A: JSON-RPC,A2A: REST) and annotated with proto-derived request-body schemas so Swagger UI's Try it out panel renders a typed, editable payloadA2A-Version: 1.0header is declared on every dispatcher route so Swagger pre-fills it and callers aren't blocked by the@validate_versionguardWhy
In v0.3,
A2AFastAPIApplicationwas a first-class FastAPI subclass, so all endpoints were automatically visible in/docs(see #280).The v1.0 rewrite dropped that wrapper in favour of bare Starlette route factories (
create_agent_card_routes,create_jsonrpc_routes,create_rest_routes). These returnstarlette.routing.Routeobjects; FastAPI's OpenAPI generator only enumeratesfastapi.routing.APIRouteinstances, so every A2A endpoint silently vanished from/docsand/openapi.json.This PR restores that capability without requiring callers to switch frameworks or restructure their apps — a single helper function wraps and enriches the routes in place.
Additional improvements over the v0.3 approach:
google.protobuf.descriptor) rather than Pydantic models, matching the proto-first v1.0 typesoneof→ JSON SchemaoneOfsoPart.contentvariants (text,raw,url,data) are correctly mutually exclusive in Swagger — prevents-32602 Invalid paramserrors from the auto-generated sample payloadparamsasoneOfover all 11 method types — every method is individually inspectable from a single endpoint rowA2A-Versionheader pre-filled to1.0on all dispatcher routes — removes the-32009version error that would otherwise block every "Try it out" callhelpers/mirrorsclient/transports/with one file per integration target; adding a new framework is a single new file that imports from_proto_schema.pyandjsonrpc.pyChanges
Usage
Validation
uv run pytest tests/server/routes/helpers/ -v— 25 tests, all passingScreenshots
Before

After


Continues #280 🦕