Skip to content

Commit 8aa5fc9

Browse files
committed
Fixing error json serialization
Signed-off-by: Emmanuel Hugonnet <[email protected]>
1 parent 1069cd8 commit 8aa5fc9

File tree

11 files changed

+187
-42
lines changed

11 files changed

+187
-42
lines changed

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import io.a2a.grpc.A2AServiceGrpc.A2AServiceBlockingV2Stub;
1818
import io.a2a.grpc.A2AServiceGrpc.A2AServiceStub;
1919
import io.a2a.grpc.CancelTaskRequest;
20-
import io.a2a.grpc.DeleteTaskPushNotificationConfigRequest;
2120
import io.a2a.grpc.GetTaskPushNotificationConfigRequest;
2221
import io.a2a.grpc.GetTaskRequest;
2322
import io.a2a.grpc.ListTaskPushNotificationConfigRequest;
@@ -271,7 +270,7 @@ public void deleteTaskPushNotificationConfigurations(DeleteTaskPushNotificationC
271270
@Nullable ClientCallContext context) throws A2AClientException {
272271
checkNotNullParam("request", request);
273272

274-
DeleteTaskPushNotificationConfigRequest grpcRequest = DeleteTaskPushNotificationConfigRequest.newBuilder()
273+
io.a2a.grpc.DeleteTaskPushNotificationConfigRequest grpcRequest = io.a2a.grpc.DeleteTaskPushNotificationConfigRequest.newBuilder()
275274
.setName(getTaskPushNotificationConfigName(request.id(), request.pushNotificationConfigId()))
276275
.build();
277276
PayloadAndHeaders payloadAndHeaders = applyInterceptors(io.a2a.spec.DeleteTaskPushNotificationConfigRequest.METHOD,

client/transport/jsonrpc/src/main/java/io/a2a/client/transport/jsonrpc/JSONRPCTransport.java

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ public TaskPushNotificationConfig setTaskPushNotificationConfiguration(TaskPushN
185185
@Nullable ClientCallContext context) throws A2AClientException {
186186
checkNotNullParam("request", request);
187187
PayloadAndHeaders payloadAndHeaders = applyInterceptors(SetTaskPushNotificationConfigRequest.METHOD,
188-
ProtoUtils.ToProto.taskPushNotificationConfig(request), agentCard, context);
188+
ProtoUtils.ToProto.setTaskPushNotificationConfigRequest(request), agentCard, context);
189189

190190
try {
191191
String httpResponseBody = sendPostRequest(payloadAndHeaders, SetTaskPushNotificationConfigRequest.METHOD);
@@ -223,14 +223,8 @@ public List<TaskPushNotificationConfig> listTaskPushNotificationConfigurations(
223223
ListTaskPushNotificationConfigParams request,
224224
@Nullable ClientCallContext context) throws A2AClientException {
225225
checkNotNullParam("request", request);
226-
ListTaskPushNotificationConfigRequest listTaskPushNotificationRequest = new ListTaskPushNotificationConfigRequest.Builder()
227-
.jsonrpc(JSONRPCMessage.JSONRPC_VERSION)
228-
.method(ListTaskPushNotificationConfigRequest.METHOD)
229-
.params(request)
230-
.build(); // id will be randomly generated
231-
232226
PayloadAndHeaders payloadAndHeaders = applyInterceptors(ListTaskPushNotificationConfigRequest.METHOD,
233-
listTaskPushNotificationRequest, agentCard, context);
227+
ProtoUtils.ToProto.listTaskPushNotificationConfigRequest(request), agentCard, context);
234228

235229
try {
236230
String httpResponseBody = sendPostRequest(payloadAndHeaders, ListTaskPushNotificationConfigRequest.METHOD);
@@ -248,14 +242,8 @@ public List<TaskPushNotificationConfig> listTaskPushNotificationConfigurations(
248242
public void deleteTaskPushNotificationConfigurations(DeleteTaskPushNotificationConfigParams request,
249243
@Nullable ClientCallContext context) throws A2AClientException {
250244
checkNotNullParam("request", request);
251-
DeleteTaskPushNotificationConfigRequest deleteTaskPushNotificationRequest = new DeleteTaskPushNotificationConfigRequest.Builder()
252-
.jsonrpc(JSONRPCMessage.JSONRPC_VERSION)
253-
.method(DeleteTaskPushNotificationConfigRequest.METHOD)
254-
.params(request)
255-
.build(); // id will be randomly generated
256-
257245
PayloadAndHeaders payloadAndHeaders = applyInterceptors(DeleteTaskPushNotificationConfigRequest.METHOD,
258-
deleteTaskPushNotificationRequest, agentCard, context);
246+
ProtoUtils.ToProto.deleteTaskPushNotificationConfigRequest(request), agentCard, context);
259247

260248
try {
261249
String httpResponseBody = sendPostRequest(payloadAndHeaders,DeleteTaskPushNotificationConfigRequest.METHOD);

client/transport/jsonrpc/src/test/java/io/a2a/client/transport/jsonrpc/JSONRPCTransportTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ public void testA2AClientSetTaskPushNotificationConfig() throws Exception {
339339
TaskPushNotificationConfig taskPushNotificationConfig = client.setTaskPushNotificationConfiguration(
340340
new TaskPushNotificationConfig("de38c76d-d54c-436c-8b9f-4c2703648d64",
341341
new PushNotificationConfig.Builder()
342+
.id("c295ea44-7543-4f78-b524-7a38915ad6e4")
342343
.url("https://example.com/callback")
343344
.authenticationInfo(new AuthenticationInfo(Collections.singletonList("jwt"),
344345
null))

client/transport/jsonrpc/src/test/java/io/a2a/client/transport/jsonrpc/JsonMessages.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -415,13 +415,17 @@ public class JsonMessages {
415415
"jsonrpc":"2.0",
416416
"method":"SetTaskPushNotificationConfig",
417417
"params":{
418-
"name":"tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs",
419-
"pushNotificationConfig":{
420-
"url":"https://example.com/callback",
421-
"authentication":{
422-
"schemes":[
423-
"jwt"
424-
]
418+
"parent":"tasks/de38c76d-d54c-436c-8b9f-4c2703648d64",
419+
"configId":"c295ea44-7543-4f78-b524-7a38915ad6e4",
420+
"config":{
421+
"name":"tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/c295ea44-7543-4f78-b524-7a38915ad6e4",
422+
"pushNotificationConfig":{
423+
"url":"https://example.com/callback",
424+
"authentication":{
425+
"schemes":[
426+
"jwt"
427+
]
428+
}
425429
}
426430
}
427431
}
@@ -431,7 +435,7 @@ public class JsonMessages {
431435
{
432436
"jsonrpc": "2.0",
433437
"result": {
434-
"name":"tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/10",
438+
"name":"tasks/de38c76d-d54c-436c-8b9f-4c2703648d64/pushNotificationConfigs/c295ea44-7543-4f78-b524-7a38915ad6e4",
435439
"pushNotificationConfig": {
436440
"url": "https://example.com/callback",
437441
"authentication": {

reference/jsonrpc/src/test/java/io/a2a/server/apps/quarkus/A2AServerRoutesTest.java

Lines changed: 84 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,18 @@
99
import static org.mockito.Mockito.verify;
1010
import static org.mockito.Mockito.when;
1111

12+
import java.util.Collections;
13+
import java.util.List;
1214
import java.util.concurrent.Executor;
1315
import java.util.concurrent.Flow;
1416

1517
import jakarta.enterprise.inject.Instance;
1618

1719
import io.a2a.server.ServerCallContext;
20+
import io.a2a.spec.AgentCapabilities;
21+
import io.a2a.spec.AgentCard;
22+
import io.a2a.spec.AgentInterface;
23+
import io.a2a.spec.AuthenticationInfo;
1824
import io.a2a.spec.CancelTaskRequest;
1925
import io.a2a.spec.CancelTaskResponse;
2026
import io.a2a.spec.DeleteTaskPushNotificationConfigRequest;
@@ -24,7 +30,9 @@
2430
import io.a2a.spec.GetTaskPushNotificationConfigRequest;
2531
import io.a2a.spec.GetTaskPushNotificationConfigResponse;
2632
import io.a2a.spec.GetTaskRequest;
33+
import io.a2a.spec.PushNotificationConfig;
2734
import io.a2a.spec.GetTaskResponse;
35+
import io.a2a.spec.ListTaskPushNotificationConfigParams;
2836
import io.a2a.spec.ListTaskPushNotificationConfigRequest;
2937
import io.a2a.spec.ListTaskPushNotificationConfigResponse;
3038
import io.a2a.spec.SendMessageRequest;
@@ -34,6 +42,10 @@
3442
import io.a2a.spec.SetTaskPushNotificationConfigRequest;
3543
import io.a2a.spec.SetTaskPushNotificationConfigResponse;
3644
import io.a2a.spec.SubscribeToTaskRequest;
45+
import io.a2a.spec.Task;
46+
import io.a2a.spec.TaskPushNotificationConfig;
47+
import io.a2a.spec.TaskState;
48+
import io.a2a.spec.TaskStatus;
3749
import io.a2a.transport.jsonrpc.handler.JSONRPCHandler;
3850
import io.vertx.core.MultiMap;
3951
import io.vertx.core.http.HttpServerRequest;
@@ -120,9 +132,15 @@ public void testSendMessage_MethodNameSetInContext() {
120132
}""";
121133
when(mockRequestBody.asString()).thenReturn(jsonRpcRequest);
122134

123-
SendMessageResponse mockResponse = mock(SendMessageResponse.class);
135+
// Create a real response with a Task
136+
Task responseTask = new Task.Builder()
137+
.id("task-123")
138+
.contextId("context-1234")
139+
.status(new TaskStatus(TaskState.SUBMITTED))
140+
.build();
141+
SendMessageResponse realResponse = new SendMessageResponse("1", responseTask);
124142
when(mockJsonRpcHandler.onMessageSend(any(SendMessageRequest.class), any(ServerCallContext.class)))
125-
.thenReturn(mockResponse);
143+
.thenReturn(realResponse);
126144

127145
ArgumentCaptor<ServerCallContext> contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class);
128146

@@ -195,9 +213,15 @@ public void testGetTask_MethodNameSetInContext() {
195213
}""";
196214
when(mockRequestBody.asString()).thenReturn(jsonRpcRequest);
197215

198-
GetTaskResponse mockResponse = mock(GetTaskResponse.class);
216+
// Create a real response with a Task
217+
Task responseTask = new Task.Builder()
218+
.id("de38c76d-d54c-436c-8b9f-4c2703648d64")
219+
.contextId("context-1234")
220+
.status(new TaskStatus(TaskState.SUBMITTED))
221+
.build();
222+
GetTaskResponse realResponse = new GetTaskResponse("1", responseTask);
199223
when(mockJsonRpcHandler.onGetTask(any(GetTaskRequest.class), any(ServerCallContext.class)))
200-
.thenReturn(mockResponse);
224+
.thenReturn(realResponse);
201225

202226
ArgumentCaptor<ServerCallContext> contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class);
203227

@@ -224,9 +248,15 @@ public void testCancelTask_MethodNameSetInContext() {
224248
}""";
225249
when(mockRequestBody.asString()).thenReturn(jsonRpcRequest);
226250

227-
CancelTaskResponse mockResponse = mock(CancelTaskResponse.class);
251+
// Create a real response with a Task
252+
Task responseTask = new Task.Builder()
253+
.id("de38c76d-d54c-436c-8b9f-4c2703648d64")
254+
.contextId("context-1234")
255+
.status(new TaskStatus(TaskState.CANCELED))
256+
.build();
257+
CancelTaskResponse realResponse = new CancelTaskResponse("1", responseTask);
228258
when(mockJsonRpcHandler.onCancelTask(any(CancelTaskRequest.class), any(ServerCallContext.class)))
229-
.thenReturn(mockResponse);
259+
.thenReturn(realResponse);
230260

231261
ArgumentCaptor<ServerCallContext> contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class);
232262

@@ -294,9 +324,18 @@ public void testSetTaskPushNotificationConfig_MethodNameSetInContext() {
294324
}""";
295325
when(mockRequestBody.asString()).thenReturn(jsonRpcRequest);
296326

297-
SetTaskPushNotificationConfigResponse mockResponse = mock(SetTaskPushNotificationConfigResponse.class);
327+
// Create a real response with a TaskPushNotificationConfig
328+
TaskPushNotificationConfig responseConfig = new TaskPushNotificationConfig(
329+
"de38c76d-d54c-436c-8b9f-4c2703648d64",
330+
new PushNotificationConfig.Builder()
331+
.id("config-123")
332+
.url("https://example.com/callback")
333+
.authenticationInfo(new AuthenticationInfo(Collections.singletonList("jwt"), null))
334+
.build()
335+
);
336+
SetTaskPushNotificationConfigResponse realResponse = new SetTaskPushNotificationConfigResponse("1", responseConfig);
298337
when(mockJsonRpcHandler.setPushNotificationConfig(any(SetTaskPushNotificationConfigRequest.class),
299-
any(ServerCallContext.class))).thenReturn(mockResponse);
338+
any(ServerCallContext.class))).thenReturn(realResponse);
300339

301340
ArgumentCaptor<ServerCallContext> contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class);
302341

@@ -324,9 +363,17 @@ public void testGetTaskPushNotificationConfig_MethodNameSetInContext() {
324363
}""";
325364
when(mockRequestBody.asString()).thenReturn(jsonRpcRequest);
326365

327-
GetTaskPushNotificationConfigResponse mockResponse = mock(GetTaskPushNotificationConfigResponse.class);
366+
// Create a real response with a TaskPushNotificationConfig
367+
TaskPushNotificationConfig responseConfig = new TaskPushNotificationConfig(
368+
"de38c76d-d54c-436c-8b9f-4c2703648d64",
369+
new PushNotificationConfig.Builder()
370+
.id("config-456")
371+
.url("https://example.com/callback")
372+
.build()
373+
);
374+
GetTaskPushNotificationConfigResponse realResponse = new GetTaskPushNotificationConfigResponse("1", responseConfig);
328375
when(mockJsonRpcHandler.getPushNotificationConfig(any(GetTaskPushNotificationConfigRequest.class),
329-
any(ServerCallContext.class))).thenReturn(mockResponse);
376+
any(ServerCallContext.class))).thenReturn(realResponse);
330377

331378
ArgumentCaptor<ServerCallContext> contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class);
332379

@@ -354,9 +401,17 @@ public void testListTaskPushNotificationConfig_MethodNameSetInContext() {
354401
}""";
355402
when(mockRequestBody.asString()).thenReturn(jsonRpcRequest);
356403

357-
ListTaskPushNotificationConfigResponse mockResponse = mock(ListTaskPushNotificationConfigResponse.class);
404+
// Create a real response with a list of TaskPushNotificationConfig
405+
TaskPushNotificationConfig config = new TaskPushNotificationConfig(
406+
"de38c76d-d54c-436c-8b9f-4c2703648d64",
407+
new PushNotificationConfig.Builder()
408+
.id("config-123")
409+
.url("https://example.com/callback")
410+
.build()
411+
);
412+
ListTaskPushNotificationConfigResponse realResponse = new ListTaskPushNotificationConfigResponse("1", Collections.singletonList(config));
358413
when(mockJsonRpcHandler.listPushNotificationConfig(any(ListTaskPushNotificationConfigRequest.class),
359-
any(ServerCallContext.class))).thenReturn(mockResponse);
414+
any(ServerCallContext.class))).thenReturn(realResponse);
360415

361416
ArgumentCaptor<ServerCallContext> contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class);
362417

@@ -384,9 +439,10 @@ public void testDeleteTaskPushNotificationConfig_MethodNameSetInContext() {
384439
}""";
385440
when(mockRequestBody.asString()).thenReturn(jsonRpcRequest);
386441

387-
DeleteTaskPushNotificationConfigResponse mockResponse = mock(DeleteTaskPushNotificationConfigResponse.class);
442+
// Create a real response with id
443+
DeleteTaskPushNotificationConfigResponse realResponse = new DeleteTaskPushNotificationConfigResponse("1");
388444
when(mockJsonRpcHandler.deletePushNotificationConfig(any(DeleteTaskPushNotificationConfigRequest.class),
389-
any(ServerCallContext.class))).thenReturn(mockResponse);
445+
any(ServerCallContext.class))).thenReturn(realResponse);
390446

391447
ArgumentCaptor<ServerCallContext> contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class);
392448

@@ -408,10 +464,22 @@ public void testGetAuthenticatedExtendedCard_MethodNameSetInContext() {
408464
+ "\",\"id\":1}";
409465
when(mockRequestBody.asString()).thenReturn(jsonRpcRequest);
410466

411-
GetAuthenticatedExtendedCardResponse mockResponse = mock(GetAuthenticatedExtendedCardResponse.class);
467+
// Create a real response with an AgentCard
468+
AgentCard agentCard = new AgentCard.Builder()
469+
.name("Test Agent")
470+
.description("Test agent description")
471+
.version("1.0.0")
472+
.protocolVersion("0.4.0")
473+
.capabilities(new AgentCapabilities.Builder().build())
474+
.defaultInputModes(Collections.singletonList("text"))
475+
.defaultOutputModes(Collections.singletonList("text"))
476+
.skills(Collections.emptyList())
477+
.supportedInterfaces(Collections.singletonList(new AgentInterface("jsonrpc", "http://localhost:9999")))
478+
.build();
479+
GetAuthenticatedExtendedCardResponse realResponse = new GetAuthenticatedExtendedCardResponse(1, agentCard);
412480
when(mockJsonRpcHandler.onGetAuthenticatedExtendedCardRequest(
413481
any(GetAuthenticatedExtendedCardRequest.class), any(ServerCallContext.class)))
414-
.thenReturn(mockResponse);
482+
.thenReturn(realResponse);
415483

416484
ArgumentCaptor<ServerCallContext> contextCaptor = ArgumentCaptor.forClass(ServerCallContext.class);
417485

spec-grpc/src/main/java/io/a2a/grpc/mapper/DeleteTaskPushNotificationConfigParamsMapper.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,11 @@ public interface DeleteTaskPushNotificationConfigParamsMapper {
2525
@Mapping(target = "pushNotificationConfigId", expression = "java(ResourceNameParser.parseTaskPushNotificationConfigName(proto.getName())[1])")
2626
@Mapping(target = "metadata", ignore = true)
2727
DeleteTaskPushNotificationConfigParams fromProto(io.a2a.grpc.DeleteTaskPushNotificationConfigRequest proto);
28+
29+
/**
30+
* Converts domain DeleteTaskPushNotificationConfigParams to proto DeleteTaskPushNotificationConfigRequest.
31+
* Constructs the name field from task ID and config ID.
32+
*/
33+
@Mapping(target = "name", expression = "java(ResourceNameParser.defineTaskPushNotificationConfigName(domain.id(), domain.pushNotificationConfigId()))")
34+
io.a2a.grpc.DeleteTaskPushNotificationConfigRequest toProto(DeleteTaskPushNotificationConfigParams domain);
2835
}

spec-grpc/src/main/java/io/a2a/grpc/mapper/ListTaskPushNotificationConfigParamsMapper.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,13 @@ public interface ListTaskPushNotificationConfigParamsMapper {
2424
@Mapping(target = "id", expression = "java(ResourceNameParser.extractParentId(proto.getParent()))")
2525
@Mapping(target = "metadata", ignore = true)
2626
ListTaskPushNotificationConfigParams fromProto(io.a2a.grpc.ListTaskPushNotificationConfigRequest proto);
27+
28+
/**
29+
* Converts domain ListTaskPushNotificationConfigParams to proto ListTaskPushNotificationConfigRequest.
30+
* Constructs the parent field from task ID.
31+
*/
32+
@Mapping(target = "parent", expression = "java(ResourceNameParser.defineTaskName(domain.id()))")
33+
@Mapping(target = "pageSize", ignore = true)
34+
@Mapping(target = "pageToken", ignore = true)
35+
io.a2a.grpc.ListTaskPushNotificationConfigRequest toProto(ListTaskPushNotificationConfigParams domain);
2736
}

spec-grpc/src/main/java/io/a2a/grpc/mapper/ResourceNameParser.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,19 @@ public static String defineGetTaskPushNotificationConfigName(String taskId, Stri
8181
return name;
8282
}
8383

84+
/**
85+
* Constructs a task push notification config resource name from task ID and config ID.
86+
* <p>
87+
* Format: "tasks/{taskId}/pushNotificationConfigs/{configId}"
88+
*
89+
* @param taskId the task identifier
90+
* @param configId the push notification config identifier
91+
* @return the formatted resource name
92+
*/
93+
public static String defineTaskPushNotificationConfigName(String taskId, String configId) {
94+
return "tasks/" + taskId + "/pushNotificationConfigs/" + configId;
95+
}
96+
8497
/**
8598
* Extracts the parent ID (task ID) from a parent resource name like "tasks/{taskId}".
8699
*

spec-grpc/src/main/java/io/a2a/grpc/mapper/SetTaskPushNotificationConfigMapper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ default PushNotificationConfig mapPushNotificationConfigWithId(SetTaskPushNotifi
107107

108108
return result;
109109
}
110-
110+
111111
/**
112112
* Maps the protobuf PushNotificationConfig to domain, injecting config_id from request.
113113
* <p>

0 commit comments

Comments
 (0)