Skip to content

Commit a45d770

Browse files
fjumaehsavoie
authored andcommitted
feat: add support for JSON+HTTP/REST
* Create JSON+HTTP/REST Client. * Integrate PR from @ronantakizawa using regexp for server routing. * Update server code to use proper JSON (de)serialization with Proto. * Create Reference Implementation * Removing the listTasks since it has been removed from the specs * Removing io.grpc:* as direct dependencies for a2a-java-sdk-spec-grpc. Signed-off-by: Emmanuel Hugonnet <[email protected]>
1 parent 0238c29 commit a45d770

File tree

46 files changed

+3665
-55
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+3665
-55
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,3 @@ nb-configuration.xml
4444
# TLS Certificates
4545
.certs/
4646
nbproject/
47-

client/base/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@
5454
<artifactId>mockserver-netty</artifactId>
5555
<scope>test</scope>
5656
</dependency>
57+
<dependency>
58+
<groupId>org.slf4j</groupId>
59+
<artifactId>slf4j-jdk14</artifactId>
60+
<scope>test</scope>
61+
</dependency>
5762
</dependencies>
5863

5964
</project>

client/transport/grpc/pom.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@
3333
<groupId>${project.groupId}</groupId>
3434
<artifactId>a2a-java-sdk-client-transport-spi</artifactId>
3535
</dependency>
36+
<dependency>
37+
<groupId>io.grpc</groupId>
38+
<artifactId>grpc-protobuf</artifactId>
39+
</dependency>
40+
<dependency>
41+
<groupId>io.grpc</groupId>
42+
<artifactId>grpc-stub</artifactId>
43+
</dependency>
3644
<dependency>
3745
<groupId>org.junit.jupiter</groupId>
3846
<artifactId>junit-jupiter-api</artifactId>

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import static io.a2a.client.transport.jsonrpc.JsonMessages.AGENT_CARD;
44
import static io.a2a.client.transport.jsonrpc.JsonMessages.AGENT_CARD_SUPPORTS_EXTENDED;
5-
import static io.a2a.client.transport.jsonrpc.JsonMessages.AUTHENTICATION_EXTENDED_AGENT_CARD;
65
import static io.a2a.client.transport.jsonrpc.JsonMessages.CANCEL_TASK_TEST_REQUEST;
76
import static io.a2a.client.transport.jsonrpc.JsonMessages.CANCEL_TASK_TEST_RESPONSE;
87
import static io.a2a.client.transport.jsonrpc.JsonMessages.GET_AUTHENTICATED_EXTENDED_AGENT_CARD_REQUEST;
@@ -50,7 +49,6 @@
5049
import io.a2a.spec.FilePart;
5150
import io.a2a.spec.FileWithBytes;
5251
import io.a2a.spec.FileWithUri;
53-
import io.a2a.spec.GetAuthenticatedExtendedCardResponse;
5452
import io.a2a.spec.GetTaskPushNotificationConfigParams;
5553
import io.a2a.spec.Message;
5654
import io.a2a.spec.MessageSendConfiguration;

client/transport/rest/pom.xml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?xml version="1.0"?>
2+
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
3+
xmlns="http://maven.apache.org/POM/4.0.0"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<parent>
8+
<groupId>io.github.a2asdk</groupId>
9+
<artifactId>a2a-java-sdk-parent</artifactId>
10+
<version>0.3.0.Beta1-SNAPSHOT</version>
11+
<relativePath>../../../pom.xml</relativePath>
12+
</parent>
13+
<artifactId>a2a-java-sdk-client-transport-rest</artifactId>
14+
<packaging>jar</packaging>
15+
16+
<name>Java SDK A2A Client Transport: JSON+HTTP/REST</name>
17+
<description>Java SDK for the Agent2Agent Protocol (A2A) - JSON+HTTP/REST Client Transport</description>
18+
19+
<dependencies>
20+
<dependency>
21+
<groupId>${project.groupId}</groupId>
22+
<artifactId>a2a-java-sdk-common</artifactId>
23+
</dependency>
24+
<dependency>
25+
<groupId>${project.groupId}</groupId>
26+
<artifactId>a2a-java-sdk-spec</artifactId>
27+
</dependency>
28+
<dependency>
29+
<groupId>${project.groupId}</groupId>
30+
<artifactId>a2a-java-sdk-spec-grpc</artifactId>
31+
</dependency>
32+
<dependency>
33+
<groupId>${project.groupId}</groupId>
34+
<artifactId>a2a-java-sdk-client-transport-spi</artifactId>
35+
</dependency>
36+
<dependency>
37+
<groupId>io.github.a2asdk</groupId>
38+
<artifactId>a2a-java-sdk-http-client</artifactId>
39+
</dependency>
40+
<dependency>
41+
<groupId>com.google.protobuf</groupId>
42+
<artifactId>protobuf-java-util</artifactId>
43+
</dependency>
44+
<dependency>
45+
<groupId>org.junit.jupiter</groupId>
46+
<artifactId>junit-jupiter-api</artifactId>
47+
<scope>test</scope>
48+
</dependency>
49+
50+
<dependency>
51+
<groupId>org.mock-server</groupId>
52+
<artifactId>mockserver-netty</artifactId>
53+
<scope>test</scope>
54+
</dependency>
55+
<dependency>
56+
<groupId>org.slf4j</groupId>
57+
<artifactId>slf4j-jdk14</artifactId>
58+
<scope>test</scope>
59+
</dependency>
60+
</dependencies>
61+
62+
</project>
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package io.a2a.client.transport.rest;
2+
3+
import com.fasterxml.jackson.core.JsonProcessingException;
4+
import com.fasterxml.jackson.databind.JsonNode;
5+
import com.fasterxml.jackson.databind.ObjectMapper;
6+
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
7+
import io.a2a.client.http.A2AHttpResponse;
8+
import io.a2a.spec.A2AClientException;
9+
import io.a2a.spec.AuthenticatedExtendedCardNotConfiguredError;
10+
import io.a2a.spec.ContentTypeNotSupportedError;
11+
import io.a2a.spec.InternalError;
12+
import io.a2a.spec.InvalidAgentResponseError;
13+
import io.a2a.spec.InvalidParamsError;
14+
import io.a2a.spec.InvalidRequestError;
15+
import io.a2a.spec.JSONParseError;
16+
import io.a2a.spec.MethodNotFoundError;
17+
import io.a2a.spec.PushNotificationNotSupportedError;
18+
import io.a2a.spec.TaskNotCancelableError;
19+
import io.a2a.spec.TaskNotFoundError;
20+
import io.a2a.spec.UnsupportedOperationError;
21+
import java.util.logging.Level;
22+
import java.util.logging.Logger;
23+
24+
/**
25+
* Utility class to A2AHttpResponse to appropriate A2A error types
26+
*/
27+
public class RestErrorMapper {
28+
29+
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper().registerModule(new JavaTimeModule());
30+
31+
public static A2AClientException mapRestError(A2AHttpResponse response) {
32+
return RestErrorMapper.mapRestError(response.body(), response.status());
33+
}
34+
35+
public static A2AClientException mapRestError(String body, int code) {
36+
try {
37+
if (body != null && !body.isBlank()) {
38+
JsonNode node = OBJECT_MAPPER.readTree(body);
39+
String className = node.findValue("error").asText();
40+
String errorMessage = node.findValue("message").asText();
41+
return mapRestError(className, errorMessage, code);
42+
}
43+
return mapRestError("", "", code);
44+
} catch (JsonProcessingException ex) {
45+
Logger.getLogger(RestErrorMapper.class.getName()).log(Level.SEVERE, null, ex);
46+
return new A2AClientException("Failed to parse error response: " + ex.getMessage());
47+
}
48+
}
49+
50+
public static A2AClientException mapRestError(String className, String errorMessage, int code) {
51+
switch (className) {
52+
case "io.a2a.spec.TaskNotFoundError":
53+
return new A2AClientException(errorMessage, new TaskNotFoundError());
54+
case "io.a2a.spec.AuthenticatedExtendedCardNotConfiguredError":
55+
return new A2AClientException(errorMessage, new AuthenticatedExtendedCardNotConfiguredError());
56+
case "io.a2a.spec.ContentTypeNotSupportedError":
57+
return new A2AClientException(errorMessage, new ContentTypeNotSupportedError(null, null, errorMessage));
58+
case "io.a2a.spec.InternalError":
59+
return new A2AClientException(errorMessage, new InternalError(errorMessage));
60+
case "io.a2a.spec.InvalidAgentResponseError":
61+
return new A2AClientException(errorMessage, new InvalidAgentResponseError(null, null, errorMessage));
62+
case "io.a2a.spec.InvalidParamsError":
63+
return new A2AClientException(errorMessage, new InvalidParamsError());
64+
case "io.a2a.spec.InvalidRequestError":
65+
return new A2AClientException(errorMessage, new InvalidRequestError());
66+
case "io.a2a.spec.JSONParseError":
67+
return new A2AClientException(errorMessage, new JSONParseError());
68+
case "io.a2a.spec.MethodNotFoundError":
69+
return new A2AClientException(errorMessage, new MethodNotFoundError());
70+
case "io.a2a.spec.PushNotificationNotSupportedError":
71+
return new A2AClientException(errorMessage, new PushNotificationNotSupportedError());
72+
case "io.a2a.spec.TaskNotCancelableError":
73+
return new A2AClientException(errorMessage, new TaskNotCancelableError());
74+
case "io.a2a.spec.UnsupportedOperationError":
75+
return new A2AClientException(errorMessage, new UnsupportedOperationError());
76+
default:
77+
return new A2AClientException(errorMessage);
78+
}
79+
}
80+
}

0 commit comments

Comments
 (0)