feat: A2A Protocol v1.0 compliance with backward compat for v0.3 agents - #145
Conversation
## A2A Protocol v1.0 Compliance Audit & Migration
### Breaking changes addressed
**SDK upgrade**
- Bump a2a-sdk[all] from >=0.3.10 to >=1.0.0a0
**JSON-RPC method names (PascalCase)**
- v0.3: message/send, tasks/get, tasks/cancel, message/stream, etc.
- v1.0: SendMessage, GetTask, CancelTask, SendStreamingMessage, etc.
- Backend debug_log now shows 'SendMessage' (v1.0 PascalCase)
**Part type restructure**
- v0.3: TextPart(text=), FilePart(file=FileWithBytes(...)), DataPart(data=...)
wrapped in a discriminated union Part(root=...)
- v1.0: Flat protobuf Part with oneof content: text=, raw=bytes, url=, data=
- Backend: _make_text_part / _make_file_part helpers handle both versions
- Frontend processPart: handles v0.3 {file:{bytes,uri,mimeType}} AND
v1.0 {url, mediaType} / {raw, mediaType} flat format
**AgentCard restructure**
- v0.3: top-level 'url', 'preferredTransport', 'additionalInterfaces'
- v1.0: 'supportedInterfaces' array replaces url+preferredTransport
- Backend: _get_transport_from_card() and _get_agent_card_dict() normalize
- Validators: accept either 'url' (v0.3) or 'supportedInterfaces' (v1.0)
**TaskStatusUpdateEvent**
- v1.0 removes the 'final' boolean field (was in v0.3)
- Validators updated: 'final' is no longer validated or required
**TaskState values**
- v0.3: lowercase strings ('working', 'completed', 'canceled', etc.)
- v1.0: SCREAMING_SNAKE_CASE ('TASK_STATE_WORKING', 'TASK_STATE_COMPLETED', etc.)
or integer enum values
- Backend: _normalize_task_state() converts v1.0 → lowercase for frontend
- Frontend: normalizeTaskState() handles display, TASK_STATE_DISPLAY map
**Role values**
- v0.3: Role.user ('user' string)
- v1.0: Role.ROLE_USER (int 1), serializes as 'ROLE_USER' in JSON
- Validators: accept 'agent', 'ROLE_AGENT', or 2 as valid agent roles
- Frontend types updated to accept TaskState as string (both formats)
**ClientConfig API**
- v0.3: ClientConfig(supported_transports=[...])
- v1.0: ClientConfig(supported_protocol_bindings=[...])
- TransportProtocol enum: v0.3 lowercase (.jsonrpc), v1.0 UPPER (.JSONRPC)
- _make_client_config() tries v1.0 first, falls back to v0.3
**Serialization**
- v0.3: Pydantic model_dump(exclude_none=True)
- v1.0: Protobuf MessageToDict(preserve_proto_field_name=False) (camelCase)
- _to_dict() helper handles both
**ClientEvent / StreamResponse**
- v0.3: ClientEvent = Message | (TaskStatusUpdateEvent | TaskArtifactUpdateEvent, Task)
- v1.0: ClientEvent = (StreamResponse, Task | None)
StreamResponse has oneof: task, message, status_update, artifact_update
- _process_a2a_response() unwraps both formats
- 'kind' field synthesized from class name for v1.0 protobuf events
### New tests (49 total, all passing)
- TestValidateAgentCardV10: v1.0 card validation
- test_valid_task_v10: SCREAMING_SNAKE_CASE state accepted
- test_valid_status_update_v10: no 'final' field required
- test_status_update_no_final_field_required: explicit regression
- test_valid_message_v10_role_enum: ROLE_AGENT accepted
- test_valid_message_v10_role_int: int role (2) accepted
### Frontend changes
- processPart(): handles v1.0 {url, raw, mediaType, filename} Part fields
- normalizeTaskState(): TASK_STATE_* → display name
- status-update handler: shows state label even with no message parts
- message handler: renders all parts (not just first text part)
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly upgrades the A2A Inspector to align with version 1.0 of the A2A Protocol. The primary goal was to integrate the new protocol specifications while meticulously preserving full backward compatibility for existing v0.3 agents. This involved extensive refactoring in both the backend and frontend to adapt to changes in data structures, serialization, and API calls, ensuring a smooth transition and continued functionality across different protocol versions. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
The pull request successfully migrates the A2A Inspector to protocol v1.0 while maintaining backward compatibility with v0.3 agents. The changes are well-structured, utilizing helper functions to encapsulate version-specific logic in the backend and updating the frontend to handle new data structures and naming conventions. The test suite has also been expanded to cover the new v1.0 formats, which is a good practice for ensuring robustness.
- _to_dict: raise TypeError instead of broad dict() fallback - Narrow except Exception to specific types (TypeError, AttributeError, ImportError) - Replace A2APart Record<string, any> with proper interface definition - Fix event typing from Any to object - Update validator error message for protocolBinding vs transport
|
@lkawka — could you review this when you get a chance? It brings the inspector up to A2A Protocol v1.0 compliance (PascalCase methods, protobuf Part types, AgentCard restructure, SCREAMING_SNAKE_CASE enums) while keeping backward compat with v0.3 agents. Just pushed a follow-up commit addressing the Code Assist feedback (narrower exception handling, better typing). Thanks! |
- _get_transport_from_card: wrap in try/except to handle v0.3 cards that don't have supported_interfaces; fall back to preferred_transport (fixes 'AttributeError: transport' on client init) - _send_message_compat: fix SendMessageRequest field name from 'request' to 'message' (the actual protobuf field name in v1.0.0a0); add ValueError to caught exceptions since protobuf raises ValueError for unknown field names, not TypeError/AttributeError (fixes 'Failed to send message: configuration' on every chat message)
|
Follow-up: found 2 critical runtime bugs during live testing with the helloworld sample agent (connecting to a v0.3 agent + sending messages both failed). Fixed in commit
With these fixes, end-to-end testing works: helloworld agent connects, agent card validates as ✅, chat sends messages, and "Hello World" comes back correctly. |
Testing SummaryAutomated Tests
Live End-to-End Testing (Headless Chromium + Playwright)Ran the full inspector against the
Bugs Found & Fixed During TestingThree critical runtime bugs were discovered that only surfaced during live E2E testing (not caught by unit tests):
Pre-existing UX Issues Noted (not addressed in this PR)
These are pre-existing issues unrelated to the v1.0 migration. |
- Error responses now show ❌ instead of ✅ compliant badge (errors can be protocol-compliant but marking them with a green checkmark is confusing for users) - Attach button: changed from '+' to 📎 icon, added aria-label - Chat empty state: improved placeholder text with 💬 emoji and clearer wording about chatting with the agent - Added .validation-status.error CSS class for error badge styling Closes a2aproject#146
|
Just putting a comment in support of this work - having a validator for the new 1.0 spec, especially an official one from the project itself, would inspire a lot more confidence as the community updates their implementations. |
Thanks @bookernath . Did you know that we have an https://github.com/a2aproject/a2a-tck from the Red Hat team who own the Java SDK, which has a dev branch for v1.0, and we have an https://github.com/a2aproject/a2a-samples/tree/main/itk from Google team owning some of the SDKs. We are in a period flux right now, migrating to 1.0 and making sure 0.3 is backwards compatible at the SDK level, but the spec is rock solid and these other tools like this inspector will be brought up to speed soon. |
|
Thanks for putting this PR together. I’m currently hoping to use an I also saw that it is currently based on If that would help, I’d be glad to contribute. |
|
I have now prepared the follow-up stable SDK refresh here: It is now ready for review on top of If continuing from #145 is still the preferred route, I would appreciate any feedback on that follow-up PR when convenient. |
|
@zeroasterisk I see you have an approval, do you plan to merge soon? I'd love to have this and I'm sure others in the community would love to see the fruits of your labor as well |
|
Pushed |
Review follow-up + rebase statusRebase: All local gates green (Python 3.13,
All CI checks passing: Lint Code Base ✓, Test (3.12) ✓, Test (3.13) ✓, Validate PR Title ✓ Review comments addressed (all were already resolved in earlier commits
|
|
I don't seem to have merge rights, @darrelmiller ? |
|
@darrelmiller Will this be merged soon? I'm preparing a talk on A2A for a user group and wanted to show the inspector as part of the demo with an A2A agent on V1. |
|
An independent data point in support of this PR, in case it helps prioritise it. I hit exactly the The card is v1.0-correct — The practical effect today is that the inspector cannot be used to debug any v1.0 agent, whatever SDK it was written with — connection fails before the chat or the compliance checks are ever reached. That also makes it hard for people to tell a genuine non-compliance in their own agent from the tool being a protocol version behind: the error message reads as "your card is invalid", which is the opposite of what is happening. It is plausible that #119 and #104 are the same root cause seen from further downstream. Nothing to act on beyond what this PR already does — just confirming the breakage is not limited to the sample agents, and that it is now reachable by anyone building against the current specification. Prepared with AI assistance; the error output above is verbatim, and each claim was verified against the pinned SDK versions. |
|
@allen-stephen Can you review this one and merge if things look good? Is there an alternate path for v1 coming? |
- Fixes Ruff and Mypy errors in backend/app.py and backend/validators.py. - Resolves issues around multi-line imports and version-specific type fallbacks.
…ponse handling) - Bump a2a-sdk[all] from >=1.0.0a0 (alpha) to >=1.1.2 (stable) - Add explicit fastapi>=0.115.0 dependency (no longer transitive in stable) - Remove ClientEvent import (removed in stable SDK) - Extract _unwrap_stream_response() helper to handle all SDK variants: * stable 1.0.x+: StreamResponse yielded directly from send_message() * v1.0 alpha: tuple[StreamResponse, Task|None] * v0.3: tuple[TaskStatusUpdateEvent|TaskArtifactUpdateEvent, Task] | Message - Fix _process_a2a_response() to route through new helper (reduces branch count) - All 49 tests pass; ruff + mypy clean
5d1325a to
744c546
Compare
Remove the redundant 'if Part is not None' checks in _make_text_part and _make_file_part, resolving pyright type narrowing issues where Part is incorrectly inferred as None.
Summary
The A2A Inspector was frozen at A2A protocol v0.3. This PR migrates to v1.0 (a2a-sdk 1.0.0a0) while maintaining backward compat with v0.3 agents.
Breaking Changes in A2A v1.0 (addressed)
Method names → PascalCase
Part type restructure
AgentCard restructure
TaskStatusUpdateEvent: final field removed
TaskState → SCREAMING_SNAKE_CASE
Role → SCREAMING_SNAKE_CASE
SDK API changes
Files Changed
Tests
49 tests pass (all existing + 12 new v1.0-specific tests)