Skip to content

docs: PRD for A2A protocol 0.3 backward compatibility layer#785

Open
jmesnil wants to merge 3 commits intoa2aproject:compat_0.3from
jmesnil:compat_0.3
Open

docs: PRD for A2A protocol 0.3 backward compatibility layer#785
jmesnil wants to merge 3 commits intoa2aproject:compat_0.3from
jmesnil:compat_0.3

Conversation

@jmesnil
Copy link
Copy Markdown
Collaborator

@jmesnil jmesnil commented Apr 9, 2026

This relates to #762

jmesnil and others added 2 commits April 9, 2026 13:54
Define the architecture and implementation plan for a compat-0.3 module
that enables v1.0 SDK users to interoperate with v0.3 agents across all
three transports (JSON-RPC, gRPC, REST).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…0.3 compat PRD

Add sections covering how server operators enable dual v0.3/v1.0 support
(separate URLs recommended), how clients select the right API based on
protocolVersion, error hierarchy mapping between versions, and why
server-common internal changes don't impact the compat wire-boundary layer.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jmesnil jmesnil changed the base branch from main to compat_0.3 April 9, 2026 12:16
@jmesnil jmesnil requested review from ehsavoie and kabir April 9, 2026 12:17
@jmesnil jmesnil changed the title PRD for A2A protocol 0.3 backward compatibility layer docs: PRD for A2A protocol 0.3 backward compatibility layer Apr 9, 2026
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces an architecture document for a backward compatibility layer, enabling the A2A Java SDK to interoperate with v0.3 agents. The review feedback highlights the need for more precise logic regarding the mapping of AgentCard interfaces and suggests providing a more robust, version-preference-aware example for client instantiation to better guide developers.

| `SendMessageConfiguration` | `a2a.v1.SendMessageConfiguration` | `return_immediately` ↔ `!blocking`, `task_push_notification_config` ↔ `push_notification` |
| `Task` | `a2a.v1.Task` | `CANCELED` ↔ `CANCELLED`, no `REJECTED` in v0.3 |
| `TaskState.TASK_STATE_REJECTED` | `TaskState.TASK_STATE_FAILED` | Map to FAILED + metadata `"original_state": "REJECTED"` |
| `AgentCard` | `a2a.v1.AgentCard` | `supported_interfaces` → `url` + `preferred_transport` + `additional_interfaces` |
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.

medium

The mapping from a v1.0 AgentCard to a v0.3 AgentCard is not fully specified. The v1.0 supported_interfaces is a list, while v0.3 has a single url and preferred_transport plus additional_interfaces. The document should clarify the logic for selecting which interface from the v1.0 list becomes the primary one in v0.3.

For example, does it use the first interface in the list? Or is there some other selection criteria? Clarifying this will prevent ambiguity during implementation.

Comment on lines +346 to +358
for (AgentInterface iface : card.supportedInterfaces()) {
if ("0.3".equals(iface.protocolVersion())) {
// Use the compat client for v0.3 agents
Compat03Client client = Compat03ClientBuilder.forUrl(iface.url())
.transport("JSONRPC")
.build();
} else if ("1.0".equals(iface.protocolVersion())) {
// Use the standard client for v1.0 agents
Client client = ClientBuilder.forUrl(iface.url())
.transport("JSONRPC")
.build();
}
}
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.

medium

The example code for choosing the client is a bit simplistic and could be misleading. It iterates through all interfaces and could potentially instantiate multiple clients if an agent supports both v0.3 and v1.0. A more realistic example would show how to select a preferred version (e.g., v1.0) and fall back to the other if necessary.

Consider improving the example to demonstrate a version preference logic, which would be more helpful for developers implementing this.

For example:

AgentCard card = // ... fetch agent card from /.well-known/agent-card.json

// Find the best available interface, preferring v1.0
Optional<AgentInterface> v1_iface = card.supportedInterfaces().stream()
    .filter(iface -> "1.0".equals(iface.protocolVersion()) && "JSONRPC".equals(iface.protocolBinding()))
    .findFirst();

Optional<AgentInterface> v03_iface = card.supportedInterfaces().stream()
    .filter(iface -> "0.3".equals(iface.protocolVersion()) && "JSONRPC".equals(iface.protocolBinding()))
    .findFirst();

if (v1_iface.isPresent()) {
    // Use the standard client for v1.0 agents
    Client client = ClientBuilder.forUrl(v1_iface.get().url())
            .transport("JSONRPC")
            .build();
    // ... use v1.0 client
} else if (v03_iface.isPresent()) {
    // Use the compat client for v0.3 agents
    Compat03Client client = Compat03ClientBuilder.forUrl(v03_iface.get().url())
            .transport("JSONRPC")
            .build();
    // ... use v0.3 client
} else {
    // No compatible JSONRPC interface found
}

Document that the agent card is produced in v1.0 format only, with pros
and cons for the user experience.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

**2. Declare both protocol versions in the AgentCard with separate URLs:**

Each protocol version should use a distinct URL to avoid any dispatch ambiguity. The recommended pattern is to use a `/v0.3` path prefix for compat endpoints:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

0.3.0 requires /v1/* as the path prefix. Also 1.0 has an optional tenant which could be confused with this prefix

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@ehsavoie My understanding is that with 0.3.0, you append the /v1 prefix to the agent interface so this would not be a problem: you'd end up with: http://example.org/v0.3/v1/message:send for the HTTP+JSON endpoint.

Likewise for tenancy in the 1.0 spec.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Well in the RI the routing is done on /v1/ so http://example.org/v0.3/v1/ wouldn't match (maybe if there is a virtual host).
JSONRPC routing is on / for the RI.
Why the tenant was introduced then for 1.0 if we could have used any prefix ?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I'm not sure we are talking about the same thing. Nothing should prevent a remote agent to be hosted on any URL. It does not have to be at the root of a domain.
My agent interfaces could be http://example.org/agents/echo. Any resolution of the endpoints should be relative to this context (ie POST http://example.org/agents/echo/v1/message:send).
The quarkus reference can be limited but that's not mandated by the spec.


```
compat-0.3/
├── pom.xml # Parent POM for all compat-0.3 submodules
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We also will need the spec/ module


### Java Package Convention

All compat-0.3 code uses the `io.a2a.compat03` package root to avoid classpath collisions with the v1.0 modules:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Package should now be org.a2aproject.sdk.compat03

</dependency>
```

The same pattern applies for gRPC and REST transports.
Copy link
Copy Markdown
Collaborator

@kabir kabir Apr 10, 2026

Choose a reason for hiding this comment

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

You are mentioning transports here, but the examples a bit above are for the reference/ modules (rather than transport/)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I'll fix it

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.

3 participants