Thomas Piacentini
← Workshop

Chapter

From 0.3 to 1.0

Original text · English

Version 1.0 renames every operation, changes every enum value, flattens the card and the parts, and rejects a request without A2A-Version, so a 0.3 client needs a compatibility layer.

The kit's error scenario sends two requests that a 0.3 client would send today. One omits A2A-Version and gets VersionNotSupportedError. The other calls message/send and gets MethodNotFoundError. When you finish this section, you can map a 0.3 request to its 1.0 form, and turn on the 0.3 layer in the reference SDK.

a 0.3 method name on a 1.0 endpointhttpFull source
POST /a2a/jsonrpc HTTP/1.1
Host: localhost:41241
Content-Type: application/json
A2A-Version: 1.0

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "message/send",
  …
}

HTTP/1.1 200 OK
Content-Type: application/json

{
  "jsonrpc": "2.0",
  "id": 3,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
The third record of the error scenario. The message in the params is cut.
Original source
title: a 0.3 method name on a 1.0 endpoint
source: capture/out/11-errors.http
lang: http
note: The third record of the error scenario. The message in the params is cut.
---
POST /a2a/jsonrpc HTTP/1.1
Host: localhost:41241
Content-Type: application/json
A2A-Version: 1.0

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "message/send",
  …
}

HTTP/1.1 200 OK
Content-Type: application/json

{
  "jsonrpc": "2.0",
  "id": 3,
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}

Before and after

The project's migration guide lists the changes {{docs whats-new-v1}}, because a major breaking change must come with migration guidance in a separate document {{spec §1.4}}. The table keeps the changes that reach code.

Area 0.3 1.0
Method names message/send, tasks/get, tasks/resubscribe SendMessage, GetTask, SubscribeToTask, the same PascalCase name on every binding {{spec §9.1}}
Push config methods tasks/pushNotificationConfig/set, and /get, /list, /delete CreateTaskPushNotificationConfig, and Get, List (plural Configs), Delete
Extended card agent/getAuthenticatedExtendedCard, REST GET /v1/card GetExtendedAgentCard, REST GET /extendedAgentCard, no /v1 prefix
Task states "working", "input-required" TASK_STATE_WORKING, TASK_STATE_INPUT_REQUIRED {{proto TaskState}}
Roles "user", "agent" ROLE_USER, ROLE_AGENT {{proto Role}}
Part shape TextPart, FilePart, DataPart, each with kind one Part whose text, raw, url, or data member names the type {{proto Part}}
File fields file.mimeType, file.name, file.fileWithUri mediaType, filename, url, flat on the part
Stream frames "kind": "status-update" a statusUpdate or artifactUpdate member {{proto StreamResponse}}
End of a stream final: true on the last status update the binding closes the stream
Card endpoint url, protocolVersion, preferredTransport, additionalInterfaces supportedInterfaces[], each with url, protocolBinding, protocolVersion {{proto AgentInterface}}
Extended card flag supportsAuthenticatedExtendedCard capabilities.extendedAgentCard
Card security security securityRequirements, each with a schemes map {{proto AgentCard}}
Errors RFC 9457 problem details google.rpc.Status with ErrorInfo, plus -32008 and -32009 {{spec §5.4}}
Version header none A2A-Version: 1.0 on every request {{spec §3.6.1}}
the five card fields that movedjsonFull source
{
  "protocolVersion": "0.3",
  "url": "https://agent.example.com/a2a",
  "preferredTransport": "JSONRPC",
  "supportsAuthenticatedExtendedCard": true,
  "additionalInterfaces": [...]
}
The 0.3 card example from the migration guide. The first four fields became supportedInterfaces, and the fifth became capabilities.extendedAgentCard.
Original source
title: the five card fields that moved
source: research/sources/docs.md
lang: json
note: The 0.3 card example from the migration guide. The first four fields became supportedInterfaces, and the fifth became capabilities.extendedAgentCard.
---
{
  "protocolVersion": "0.3",
  "url": "https://agent.example.com/a2a",
  "preferredTransport": "JSONRPC",
  "supportsAuthenticatedExtendedCard": true,
  "additionalInterfaces": [...]
}

The guide misses one change. The 0.3 flag blocking was false by default, so a send returned at once. Its replacement returnImmediately is also false by default, so a send now waits {{proto SendMessageConfiguration}} {{spec §3.2.2}}. SendMessage shows both modes.

The missing header

An agent must read an empty value as version 0.3 {{spec §3.6.2}}. A 1.0-only interface must then answer VersionNotSupportedError {{spec §5.4}}, as the kit does.

The SDKs differ. JS and Java treat a missing header as 0.3 and reject it on every binding {{sdk-js src/server/version.ts at v1.3.0}} {{sdk-java server-common/src/main/java/org/a2aproject/sdk/server/version/A2AVersionValidator.java at v1.4.0.Final}}. Python does so on JSON-RPC and REST {{sdk src/a2a/utils/version_validator.py}}, and Rust on JSON-RPC only {{sdk-rust a2a-server/src/jsonrpc.rs at a2a-server-lf-v0.5.1}}. Go never reads the header, and .NET accepts a missing one {{sdk-go a2a/svcparams.go at v2.6.0}} {{sdk-dotnet src/A2A.AspNetCore/A2AJsonRpcProcessor.cs at v1.0.0-preview2}}. The version header has the full table.

The 0.3 layer in each SDK

During the overlap period, a server can accept both the old and the current forms of a request message {{spec §A.2}}.

  • a2a-python 1.2.2. Pass enable_v0_3_compat=True to create_jsonrpc_routes and create_rest_routes, and add an AgentInterface with protocolVersion 0.3 to the card {{sdk src/a2a/server/routes/jsonrpc_routes.py}} {{sdk src/a2a/server/routes/rest_routes.py}}. The dispatcher routes by method name, so message/send reaches JSONRPC03Adapter before the version check {{sdk src/a2a/server/routes/jsonrpc_dispatcher.py}}. For gRPC it adds CompatGrpcHandler on the old package a2a.v1 {{sdk src/a2a/compat/v0_3/grpc_handler.py}}. The client needs no switch: ClientFactory picks a compat transport for an interface below 1.0 {{sdk src/a2a/client/client_factory.py}}.
  • a2a-js 1.3.0. Set legacyCompat: { enabled: true } on each handler. It routes by A2A-Version, with an absent header as 0.3 {{sdk-js src/server/express/json_rpc_handler.ts at v1.3.0}}.
  • a2a-go 2.6.0. Mount a second handler from a2acompat/a2av0 under its own URL and advertise a second interface. It routes by URL, never by header {{sdk-go a2acompat/a2av0/jsonrpc_server.go at v2.6.0}}.
  • a2a-java 1.4.0.Final. Add the multiversion-jsonrpc or multiversion-rest reference module. Its VersionRouter sends 0.3 or an absent header to the 0.3 handler {{sdk-java docs/content/dev/compatibility.md at v1.4.0.Final}}.
  • a2a-dotnet 1.0.0-preview2. Call MapA2AWithV03Compat instead of MapA2A. It routes by A2A-Version {{sdk-dotnet src/A2A.V0_3Compat/V03ServerCompatEndpointExtensions.cs at v1.0.0-preview2}}.
  • a2a-rs 0.5.1. None {{sdk-rust a2a-client/src/factory.rs at a2a-server-lf-v0.5.1}}.

Where the migration guide is wrong

The proto is normative {{spec §1.4}}, so follow it where the guide names a field or a value the proto lacks.

  • The guide named the stream members taskStatusUpdate and taskArtifactUpdate. The proto has statusUpdate and artifactUpdate (conflict D9). PR #2056 fixed it on main after v1.0.1, not yet released.
  • The guide added Task.createdAt, Task.lastModified, configId, and an artifact index that the proto lacks (conflict D10). The same PR removed all but index.
  • Appendix A.2.2 calls the old flag supportsExtendedAgentCard. The guide and the SDK say supportsAuthenticatedExtendedCard (conflict D40), and main has no fix.
  • The guide puts extensions at agentCard.extensions. The proto puts them at capabilities.extensions {{proto AgentCapabilities}}, as extensions explains.

After v1.0.1

No tag newer than v1.0.1 exists. Main has one proto change since the tag: the gRPC url comment, now hostname:port (PR #1997), which closes D34. It is the only entry in the pending 1.0.2 release (PR #2072). Documentation commits on main close D8, D9, D12, and D32, and part of D4, D5, D6, D10, and D23 (the conflict register). Main also adds §7.6.4 on in-task authorization scope (PR #2081), which security schemes quotes.

Branch dev-1.1 changes the task record. Task.generation counts every state change, and GetTaskRequest.currentGeneration lets a client wait for the next one. SendMessageConfiguration.ifGenerationMatch makes a send conditional, and a stale value gets TaskGenerationMismatchError, -32010 (PR #1810). Task.history is deprecated for a timeline of messages and statuses (PR #2129). None of this is released, and no 1.1 date is published.

Original source
- Send `A2A-Version: 1.0` on every request, and set `returnImmediately` where a 0.3 client relied on `blocking: false`.
- Turn on the SDK's 0.3 layer and add a `0.3` interface to the card while old clients remain.
- Follow the proto where the migration guide names a field the proto lacks.
- Treat `generation` and `timeline` as unreleased until a tag carries them.

Sources: spec §1.4, §3.2.2, §3.6.1, §3.6.2, §5.4, §9.1, §A.2 (research/sources/specification.md); proto TaskState, Role, Part, StreamResponse, AgentInterface, AgentCard, AgentCapabilities, SendMessageConfiguration (research/sources/a2a.proto); docs/whats-new-v1.md at v1.0.1 (research/sources/docs.md); sdk src/a2a/utils/version_validator.py, src/a2a/server/routes/jsonrpc_routes.py, src/a2a/server/routes/rest_routes.py, src/a2a/server/routes/jsonrpc_dispatcher.py, src/a2a/compat/v0_3/grpc_handler.py, src/a2a/client/client_factory.py at a2a-python 1.2.2; sdk-js src/server/version.ts, src/server/express/json_rpc_handler.ts at v1.3.0; sdk-go a2a/svcparams.go, a2acompat/a2av0/jsonrpc_server.go at v2.6.0; sdk-java server-common/src/main/java/org/a2aproject/sdk/server/version/A2AVersionValidator.java, docs/content/dev/compatibility.md at v1.4.0.Final; sdk-dotnet src/A2A.AspNetCore/A2AJsonRpcProcessor.cs, src/A2A.V0_3Compat/V03ServerCompatEndpointExtensions.cs at v1.0.0-preview2; sdk-rust a2a-server/src/jsonrpc.rs, a2a-client/src/factory.rs at a2a-server-lf-v0.5.1; capture/out/11-errors.http; capture/a2a_ref.py; a2aproject/A2A pull requests #1810, #1997, #2056, #2072, #2081, #2129, main at 679ab3a and branch dev-1.1 at db39eb5

Code and artifacts 1
What you take away

Saved in your notebook on this device.

Sources and limits

Reading checkpoints are self-reported. Test results are recorded separately and apply to the executed cases.

AI Engineering from Scratch · 3f9715c · MIT

Download this file ↓