Skip to content

Commit d11484b

Browse files
authored
fix!: Update the name of A2A headers (#709)
A2A-Version and A2A-Extensions are specified by the spec (as of dec790a) instead of the X-A2A-*. Also updates the gRPC context keys to get rid of the prefix. I did not change the `X-A2A-Notification-Token` header that is still present in the spec but I'll open a PR to verify if that's not an omission Signed-off-by: Jeff Mesnil <jmesnil@ibm.com>
1 parent 81d7eae commit d11484b

File tree

8 files changed

+45
-39
lines changed

8 files changed

+45
-39
lines changed

client/transport/grpc/src/main/java/io/a2a/client/transport/grpc/GrpcTransport.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,10 @@ public class GrpcTransport implements ClientTransport {
6161
AuthInterceptor.AUTHORIZATION,
6262
Metadata.ASCII_STRING_MARSHALLER);
6363
private static final Metadata.Key<String> EXTENSIONS_KEY = Metadata.Key.of(
64-
A2AHeaders.X_A2A_EXTENSIONS,
64+
A2AHeaders.A2A_EXTENSIONS.toLowerCase(),
6565
Metadata.ASCII_STRING_MARSHALLER);
6666
private static final Metadata.Key<String> VERSION_KEY = Metadata.Key.of(
67-
A2AHeaders.X_A2A_VERSION,
67+
A2AHeaders.A2A_VERSION.toLowerCase(),
6868
Metadata.ASCII_STRING_MARSHALLER);
6969
private final A2AServiceBlockingV2Stub blockingStub;
7070
private final A2AServiceStub asyncStub;
@@ -380,8 +380,8 @@ private io.a2a.grpc.SendMessageRequest createGrpcSendMessageRequest(MessageSendP
380380

381381
/**
382382
* Creates gRPC metadata from ClientCallContext headers.
383-
* Extracts headers like X-A2A-Extensions and sets them as gRPC metadata.
384-
*
383+
* Extracts headers like a2a-extensions and sets them as gRPC metadata.
384+
* The headers are lower-cased (compared to the HTTP headers).
385385
* @param context the client call context containing headers, may be null
386386
* @param payloadAndHeaders the payload and headers wrapper, may be null
387387
* @return the gRPC metadata
@@ -390,14 +390,14 @@ private Metadata createGrpcMetadata(@Nullable ClientCallContext context, @Nullab
390390
Metadata metadata = new Metadata();
391391

392392
if (context != null && context.getHeaders() != null) {
393-
// Set X-A2A-Version header if present
394-
String versionHeader = context.getHeaders().get(A2AHeaders.X_A2A_VERSION);
393+
// Set a2a-version header if present
394+
String versionHeader = context.getHeaders().get(A2AHeaders.A2A_VERSION.toLowerCase());
395395
if (versionHeader != null) {
396396
metadata.put(VERSION_KEY, versionHeader);
397397
}
398398

399-
// Set X-A2A-Extensions header if present
400-
String extensionsHeader = context.getHeaders().get(A2AHeaders.X_A2A_EXTENSIONS);
399+
// Set a2a-extensions header if present
400+
String extensionsHeader = context.getHeaders().get(A2AHeaders.A2A_EXTENSIONS.toLowerCase());
401401
if (extensionsHeader != null) {
402402
metadata.put(EXTENSIONS_KEY, extensionsHeader);
403403
}

common/src/main/java/io/a2a/common/A2AHeaders.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ public final class A2AHeaders {
99
* HTTP header name for A2A protocol version.
1010
* Used to communicate the protocol version that the client is using.
1111
*/
12-
public static final String X_A2A_VERSION = "X-A2A-Version";
12+
public static final String A2A_VERSION = "A2A-Version";
1313

1414
/**
1515
* HTTP header name for A2A extensions.
1616
* Used to communicate which extensions are requested by the client.
1717
*/
18-
public static final String X_A2A_EXTENSIONS = "X-A2A-Extensions";
18+
public static final String A2A_EXTENSIONS = "A2A-Extensions";
1919

2020
/**
2121
* HTTP header name for a push notification token.

reference/grpc/src/main/java/io/a2a/server/grpc/quarkus/A2AExtensionsInterceptor.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
*
2222
* <h2>Captured Information</h2>
2323
* <ul>
24-
* <li><b>A2A Protocol Version</b>: {@code X-A2A-Version} header</li>
25-
* <li><b>A2A Extensions</b>: {@code X-A2A-Extensions} header</li>
24+
* <li><b>A2A Protocol Version</b>: {@code a2a-version} header</li>
25+
* <li><b>A2A Extensions</b>: {@code a2a-extensions} header</li>
2626
* <li><b>Complete Metadata</b>: All request headers via {@link io.grpc.Metadata}</li>
2727
* <li><b>Method Name</b>: gRPC method being invoked</li>
2828
* <li><b>Peer Information</b>: Client connection details</li>
@@ -60,6 +60,13 @@
6060
@ApplicationScoped
6161
public class A2AExtensionsInterceptor implements ServerInterceptor {
6262

63+
private static final Metadata.Key<String> EXTENSIONS_KEY = Metadata.Key.of(
64+
A2AHeaders.A2A_EXTENSIONS.toLowerCase(),
65+
Metadata.ASCII_STRING_MARSHALLER);
66+
private static final Metadata.Key<String> VERSION_KEY = Metadata.Key.of(
67+
A2AHeaders.A2A_VERSION.toLowerCase(),
68+
Metadata.ASCII_STRING_MARSHALLER);
69+
6370
/**
6471
* Intercepts incoming gRPC calls to capture metadata and context information.
6572
*
@@ -68,8 +75,8 @@ public class A2AExtensionsInterceptor implements ServerInterceptor {
6875
*
6976
* <p><b>Extraction Process:</b>
7077
* <ol>
71-
* <li>Extract {@code X-A2A-Version} header from metadata</li>
72-
* <li>Extract {@code X-A2A-Extensions} header from metadata</li>
78+
* <li>Extract {@code a2a-version} header from metadata</li>
79+
* <li>Extract {@code a2a-extensions} header from metadata</li>
7380
* <li>Capture complete {@link Metadata} object</li>
7481
* <li>Capture gRPC method name from {@link ServerCall}</li>
7582
* <li>Map gRPC method to A2A protocol method name</li>
@@ -92,14 +99,9 @@ public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
9299
ServerCallHandler<ReqT, RespT> serverCallHandler) {
93100

94101
// Extract A2A protocol version header
95-
Metadata.Key<String> versionKey =
96-
Metadata.Key.of(A2AHeaders.X_A2A_VERSION, Metadata.ASCII_STRING_MARSHALLER);
97-
String version = metadata.get(versionKey);
98-
102+
String version = metadata.get(VERSION_KEY);
99103
// Extract A2A extensions header
100-
Metadata.Key<String> extensionsKey =
101-
Metadata.Key.of(A2AHeaders.X_A2A_EXTENSIONS, Metadata.ASCII_STRING_MARSHALLER);
102-
String extensions = metadata.get(extensionsKey);
104+
String extensions = metadata.get(EXTENSIONS_KEY);
103105

104106
// Create enhanced context with rich information (equivalent to Python's ServicerContext)
105107
Context context = Context.current()

reference/jsonrpc/src/main/java/io/a2a/server/apps/quarkus/A2AServerRoutes.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -514,11 +514,11 @@ public String getUsername() {
514514
state.put(TENANT_KEY, extractTenant(rc));
515515
state.put(TRANSPORT_KEY, TransportProtocol.JSONRPC);
516516

517-
// Extract requested protocol version from X-A2A-Version header
518-
String requestedVersion = rc.request().getHeader(A2AHeaders.X_A2A_VERSION);
517+
// Extract requested protocol version from A2A-Version header
518+
String requestedVersion = rc.request().getHeader(A2AHeaders.A2A_VERSION);
519519

520-
// Extract requested extensions from X-A2A-Extensions header
521-
List<String> extensionHeaderValues = rc.request().headers().getAll(A2AHeaders.X_A2A_EXTENSIONS);
520+
// Extract requested extensions from A2A-Extensions header
521+
List<String> extensionHeaderValues = rc.request().headers().getAll(A2AHeaders.A2A_EXTENSIONS);
522522
Set<String> requestedExtensions = A2AExtensions.getRequestedExtensions(extensionHeaderValues);
523523

524524
return new ServerCallContext(user, state, requestedExtensions, requestedVersion);

reference/rest/src/main/java/io/a2a/server/rest/quarkus/A2AServerRoutes.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -731,11 +731,11 @@ public String getUsername() {
731731
state.put(TENANT_KEY, extractTenant(rc));
732732
state.put(TRANSPORT_KEY, TransportProtocol.HTTP_JSON);
733733

734-
// Extract requested protocol version from X-A2A-Version header
735-
String requestedVersion = rc.request().getHeader(A2AHeaders.X_A2A_VERSION);
734+
// Extract requested protocol version from A2A-Version header
735+
String requestedVersion = rc.request().getHeader(A2AHeaders.A2A_VERSION);
736736

737-
// Extract requested extensions from X-A2A-Extensions header
738-
List<String> extensionHeaderValues = rc.request().headers().getAll(A2AHeaders.X_A2A_EXTENSIONS);
737+
// Extract requested extensions from A2A-Extensions header
738+
List<String> extensionHeaderValues = rc.request().headers().getAll(A2AHeaders.A2A_EXTENSIONS);
739739
Set<String> requestedExtensions = A2AExtensions.getRequestedExtensions(extensionHeaderValues);
740740

741741
return new ServerCallContext(user, state, requestedExtensions, requestedVersion);

transport/grpc/src/main/java/io/a2a/transport/grpc/context/GrpcContextKeys.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
package io.a2a.transport.grpc.context;
22

33

4+
import static java.util.Locale.ROOT;
5+
6+
import java.util.Locale;
47
import java.util.Map;
58

9+
import io.a2a.common.A2AHeaders;
610
import io.a2a.spec.A2AMethods;
711
import io.grpc.Context;
812

@@ -40,18 +44,18 @@
4044
public final class GrpcContextKeys {
4145

4246
/**
43-
* Context key for storing the X-A2A-Version header value.
47+
* Context key for storing the a2a-version header value.
4448
* Set by server interceptors and accessed by service handlers.
4549
*/
4650
public static final Context.Key<String> VERSION_HEADER_KEY =
47-
Context.key("x-a2a-version");
51+
Context.key(A2AHeaders.A2A_VERSION.toLowerCase(ROOT));
4852

4953
/**
50-
* Context key for storing the X-A2A-Extensions header value.
54+
* Context key for storing the a2a-extensions header value.
5155
* Set by server interceptors and accessed by service handlers.
5256
*/
5357
public static final Context.Key<String> EXTENSIONS_HEADER_KEY =
54-
Context.key("x-a2a-extensions");
58+
Context.key(A2AHeaders.A2A_EXTENSIONS.toLowerCase(ROOT));
5559

5660
/**
5761
* Context key for storing the complete gRPC Metadata object.

transport/grpc/src/main/java/io/a2a/transport/grpc/handler/CallContextFactory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
* <li>User authentication from security context</li>
1919
* <li>gRPC metadata (headers)</li>
2020
* <li>Method name and peer information</li>
21-
* <li>A2A protocol version from {@code X-A2A-Version} header</li>
22-
* <li>Required extensions from {@code X-A2A-Extensions} header</li>
21+
* <li>A2A protocol version from {@code A2A-Version} header</li>
22+
* <li>Required extensions from {@code A2A-Extensions} header</li>
2323
* <li>Response observer for gRPC streaming</li>
2424
* </ul>
2525
*

transport/grpc/src/main/java/io/a2a/transport/grpc/handler/GrpcHandler.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -600,8 +600,8 @@ public void deleteTaskPushNotificationConfig(io.a2a.grpc.DeleteTaskPushNotificat
600600
* <li>HTTP headers extracted from metadata</li>
601601
* <li>gRPC method name</li>
602602
* <li>Peer information (client connection details)</li>
603-
* <li>A2A protocol version from {@code X-A2A-Version} header (via context)</li>
604-
* <li>Required extensions from {@code X-A2A-Extensions} header (via context)</li>
603+
* <li>A2A protocol version from {@code A2A-Version} header (via context)</li>
604+
* <li>Required extensions from {@code A2A-Extensions} header (via context)</li>
605605
* </ul>
606606
*
607607
* <p><b>Custom Context Creation:</b>
@@ -901,7 +901,7 @@ public static void setStreamingSubscribedRunnable(Runnable runnable) {
901901
protected abstract Executor getExecutor();
902902

903903
/**
904-
* Attempts to extract the X-A2A-Version header from the current gRPC context.
904+
* Attempts to extract the A2A-Version header from the current gRPC context.
905905
* This will only work if a server interceptor has been configured to capture
906906
* the metadata and store it in the context.
907907
*
@@ -917,7 +917,7 @@ public static void setStreamingSubscribedRunnable(Runnable runnable) {
917917
}
918918

919919
/**
920-
* Attempts to extract the X-A2A-Extensions header from the current gRPC context.
920+
* Attempts to extract the A2A-Extensions header from the current gRPC context.
921921
* This will only work if a server interceptor has been configured to capture
922922
* the metadata and store it in the context.
923923
*

0 commit comments

Comments
 (0)