Skip to content

Commit a1cf9c9

Browse files
authored
Merge pull request #58 from kabir/align-main
Align with latest a2a-java SNAPSHOT
2 parents f5fdd3f + 097f81b commit a1cf9c9

File tree

5 files changed

+61
-12
lines changed

5 files changed

+61
-12
lines changed

impl/jsonrpc/src/main/java/org/wildfly/extras/a2a/server/apps/jsonrpc/A2AServerResource.java

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
import java.io.IOException;
88
import java.io.PrintWriter;
9+
import java.time.ZoneId;
10+
import java.time.ZonedDateTime;
11+
import java.time.format.DateTimeFormatter;
912
import java.util.ArrayList;
1013
import java.util.Enumeration;
1114
import java.util.HashMap;
@@ -148,10 +151,7 @@ public Response handleNonStreamingRequests(
148151
// Serialize response using protobuf conversion
149152
String serialized = serializeResponse(response);
150153

151-
// Set Content-Type according to A2A spec: application/problem+json for errors, application/json for success
152-
String contentType = response.getError() != null
153-
? io.a2a.common.MediaType.APPLICATION_PROBLEM_JSON
154-
: io.a2a.common.MediaType.APPLICATION_JSON;
154+
String contentType = io.a2a.common.MediaType.APPLICATION_JSON;
155155

156156
// Return Response with explicit content-type header
157157
return Response.status(Response.Status.OK)
@@ -233,15 +233,36 @@ public void handleStreamingRequests(
233233

234234
/**
235235
* Handles incoming GET requests to the agent card endpoint.
236-
* Returns the agent card in JSON format.
236+
* Returns the agent card in JSON format with appropriate caching headers.
237237
*
238-
* @return the agent card
238+
* <p>Per A2A specification section 8.6, Agent Card HTTP endpoints SHOULD include:
239+
* <ul>
240+
* <li>Cache-Control header with max-age directive (CARD-CACHE-001)</li>
241+
* <li>ETag header for conditional request support (CARD-CACHE-002)</li>
242+
* <li>Last-Modified header in RFC 1123 format (CARD-CACHE-003)</li>
243+
* </ul>
244+
*
245+
* @return the agent card with caching headers
239246
*/
240247
@GET
241248
@Path("/.well-known/agent-card.json")
242249
@Produces(MediaType.APPLICATION_JSON)
243-
public AgentCard getAgentCard() {
244-
return jsonRpcHandler.getAgentCard();
250+
public Response getAgentCard() {
251+
AgentCard agentCard = jsonRpcHandler.getAgentCard();
252+
253+
// Generate ETag based on agent card content hash
254+
String etag = "\"" + Integer.toHexString(agentCard.hashCode()) + "\"";
255+
256+
// Set Last-Modified to current time in RFC 1123 format
257+
// In production, this should reflect actual last modification time
258+
ZonedDateTime now = ZonedDateTime.now(ZoneId.of("GMT"));
259+
String lastModified = now.format(DateTimeFormatter.RFC_1123_DATE_TIME);
260+
261+
return Response.ok(agentCard)
262+
.header(HttpHeaders.CACHE_CONTROL, "max-age=3600")
263+
.header(HttpHeaders.ETAG, etag)
264+
.header("Last-Modified", lastModified)
265+
.build();
245266
}
246267

247268
private A2AResponse<?> processNonStreamingRequest(NonStreamingJSONRPCRequest<?> request,

impl/rest/src/main/java/org/wildfly/extras/a2a/server/apps/rest/A2ARestServerResource.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88

99
import java.io.IOException;
1010
import java.io.PrintWriter;
11+
import java.time.ZoneId;
12+
import java.time.ZonedDateTime;
13+
import java.time.format.DateTimeFormatter;
1114
import java.util.ArrayList;
1215
import java.util.Enumeration;
1316
import java.util.HashMap;
@@ -153,17 +156,36 @@ public void resubscribeTask(@PathParam("taskId") String taskId, @Context HttpSer
153156

154157
/**
155158
* Handles incoming GET requests to the agent card endpoint.
156-
* Returns the agent card in JSON format.
159+
* Returns the agent card in JSON format with appropriate caching headers.
157160
*
158-
* @return the agent card
161+
* <p>Per A2A specification section 8.6, Agent Card HTTP endpoints SHOULD include:
162+
* <ul>
163+
* <li>Cache-Control header with max-age directive (CARD-CACHE-001)</li>
164+
* <li>ETag header for conditional request support (CARD-CACHE-002)</li>
165+
* <li>Last-Modified header in RFC 1123 format (CARD-CACHE-003)</li>
166+
* </ul>
167+
*
168+
* @return the agent card with caching headers
159169
*/
160170
@GET
161171
@Path(".well-known/agent-card.json")
162172
@Consumes(MediaType.APPLICATION_JSON)
163173
public Response getAgentCard() {
164174
RestHandler.HTTPRestResponse response = jsonRestHandler.getAgentCard();
175+
176+
// Generate ETag based on response body content hash
177+
String etag = "\"" + Integer.toHexString(response.getBody().hashCode()) + "\"";
178+
179+
// Set Last-Modified to current time in RFC 1123 format
180+
// In production, this should reflect actual last modification time
181+
ZonedDateTime now = ZonedDateTime.now(ZoneId.of("GMT"));
182+
String lastModified = now.format(DateTimeFormatter.RFC_1123_DATE_TIME);
183+
165184
return Response.status(response.getStatusCode())
166185
.header(CONTENT_TYPE, response.getContentType())
186+
.header("Cache-Control", "max-age=3600")
187+
.header("ETag", etag)
188+
.header("Last-Modified", lastModified)
167189
.entity(response.getBody())
168190
.build();
169191
}

tests/grpc/src/test/java/org/wildfly/extras/a2a/test/server/grpc/WildFlyA2AGrpcTestCase.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,12 @@ static JavaArchive getJarForClass(Class<?> clazz) throws Exception {
135135
return ShrinkWrap.createFromZipFile(JavaArchive.class, f);
136136
}
137137

138+
@Override
139+
public void testAgentCardHeaders() {
140+
// Skip - gRPC doesn't use HTTP caching headers for Agent Card
141+
// The A2A spec section 8.6 caching requirements apply only to HTTP endpoints
142+
}
143+
138144
@AfterAll
139145
public static void closeChannel() {
140146
channel.shutdownNow();

tests/jsonrpc/src/test/java/org/wildfly/extras/a2a/test/server/apps/jsonrpc/JakartaA2AServerTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ public void testErrorResponseContentType() {
148148
// Validate content-type header
149149
String contentType = response.getContentType();
150150
assertNotNull(contentType, "Content-Type header should be present");
151-
assertEquals(MediaType.APPLICATION_PROBLEM_JSON, contentType,
151+
assertEquals(MediaType.APPLICATION_JSON, contentType,
152152
"Error responses must use application/problem+json content-type");
153153

154154
// Validate it's actually an error response

tests/rest/src/test/java/org/wildfly/extras/a2a/test/server/apps/rest/JakartaA2AServerTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ public void testErrorResponseContentType() {
145145
// Validate content-type header for error responses
146146
String contentType = response.getContentType();
147147
assertNotNull(contentType, "Content-Type header should be present on error responses");
148-
assertEquals(MediaType.APPLICATION_PROBLEM_JSON, contentType,
148+
assertEquals(MediaType.APPLICATION_JSON, contentType,
149149
"Error responses must use application/problem+json content-type");
150150
}
151151
}

0 commit comments

Comments
 (0)