diff --git a/README.md b/README.md
index 4e58db1d3..9339b08e5 100644
--- a/README.md
+++ b/README.md
@@ -34,7 +34,7 @@ The A2A Java SDK provides a Java server implementation of the [Agent2Agent (A2A)
- [Add a class that creates an A2A Agent Executor](#3-add-a-class-that-creates-an-a2a-agent-executor)
- [Add an A2A Java SDK Server Maven dependency to your project](#4-add-an-a2a-java-sdk-server-maven-dependency-to-your-project)
-### 1. Add the A2A Java SDK Core Maven dependency to your project
+### 1. Add the A2A Java SDK Maven dependencies to your project
> **Note**: The A2A Java SDK isn't available yet in Maven Central but will be soon. For now, be
> sure to check out the latest tag (you can see the tags [here](https://github.com/a2aproject/a2a-java/tags)), build from the tag, and reference that version below. For example, if the latest tag is `0.2.3`, you can use the following dependency.
@@ -42,7 +42,12 @@ The A2A Java SDK provides a Java server implementation of the [Agent2Agent (A2A)
```xml
io.a2a.sdk
- a2a-java-sdk-core
+ a2a-java-sdk-client
+ 0.2.3
+
+
+ io.a2a.sdk
+ a2a-java-sdk-server-common
0.2.3
```
diff --git a/client/pom.xml b/client/pom.xml
new file mode 100644
index 000000000..975fb2928
--- /dev/null
+++ b/client/pom.xml
@@ -0,0 +1,45 @@
+
+
+ 4.0.0
+
+
+ io.a2a.sdk
+ a2a-java-sdk-parent
+ 0.2.4-SNAPSHOT
+
+ a2a-java-sdk-client
+
+ jar
+
+ Java SDK A2A Client
+ Java SDK for the Agent2Agent Protocol (A2A) - Client
+
+
+
+ ${project.groupId}
+ a2a-java-sdk-common
+ ${project.version}
+
+
+
+ ${project.groupId}
+ a2a-java-sdk-spec
+ ${project.version}
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+
+ org.mock-server
+ mockserver-netty
+ test
+
+
+
+
\ No newline at end of file
diff --git a/core/src/main/java/io/a2a/spec/A2A.java b/client/src/main/java/io/a2a/A2A.java
similarity index 79%
rename from core/src/main/java/io/a2a/spec/A2A.java
rename to client/src/main/java/io/a2a/A2A.java
index 4f3d2381c..c8dca80e4 100644
--- a/core/src/main/java/io/a2a/spec/A2A.java
+++ b/client/src/main/java/io/a2a/A2A.java
@@ -1,4 +1,4 @@
-package io.a2a.spec;
+package io.a2a;
import java.util.Collections;
import java.util.Map;
@@ -6,6 +6,11 @@
import io.a2a.client.A2ACardResolver;
import io.a2a.http.A2AHttpClient;
import io.a2a.http.JdkA2AHttpClient;
+import io.a2a.spec.A2AClientError;
+import io.a2a.spec.A2AClientJSONError;
+import io.a2a.spec.AgentCard;
+import io.a2a.spec.Message;
+import io.a2a.spec.TextPart;
/**
@@ -13,17 +18,6 @@
*/
public class A2A {
- public static final String CANCEL_TASK_METHOD = "tasks/cancel";
- public static final String GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD = "tasks/pushNotificationConfig/get";
- public static final String GET_TASK_METHOD = "tasks/get";
- public static final String SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD = "tasks/pushNotificationConfig/set";
- public static final String SEND_TASK_RESUBSCRIPTION_METHOD = "tasks/resubscribe";
- public static final String SEND_STREAMING_MESSAGE_METHOD = "message/stream";
- public static final String SEND_MESSAGE_METHOD = "message/send";
-
- public static final String JSONRPC_VERSION = "2.0";
-
-
/**
* Convert the given text to a user message.
*
@@ -133,16 +127,4 @@ public static AgentCard getAgentCard(A2AHttpClient httpClient, String agentUrl,
A2ACardResolver resolver = new A2ACardResolver(httpClient, agentUrl, relativeCardPath, authHeaders);
return resolver.getAgentCard();
}
-
- protected static boolean isValidMethodName(String methodName) {
- return methodName != null && (methodName.equals(CANCEL_TASK_METHOD)
- || methodName.equals(GET_TASK_METHOD)
- || methodName.equals(GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD)
- || methodName.equals(SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD)
- || methodName.equals(SEND_TASK_RESUBSCRIPTION_METHOD)
- || methodName.equals(SEND_MESSAGE_METHOD)
- || methodName.equals(SEND_STREAMING_MESSAGE_METHOD));
-
- }
-
}
diff --git a/core/src/main/java/io/a2a/client/A2ACardResolver.java b/client/src/main/java/io/a2a/client/A2ACardResolver.java
similarity index 100%
rename from core/src/main/java/io/a2a/client/A2ACardResolver.java
rename to client/src/main/java/io/a2a/client/A2ACardResolver.java
diff --git a/core/src/main/java/io/a2a/client/A2AClient.java b/client/src/main/java/io/a2a/client/A2AClient.java
similarity index 94%
rename from core/src/main/java/io/a2a/client/A2AClient.java
rename to client/src/main/java/io/a2a/client/A2AClient.java
index 3a35f0b67..ea08baea4 100644
--- a/core/src/main/java/io/a2a/client/A2AClient.java
+++ b/client/src/main/java/io/a2a/client/A2AClient.java
@@ -1,16 +1,6 @@
package io.a2a.client;
-import static io.a2a.spec.A2A.CANCEL_TASK_METHOD;
-import static io.a2a.spec.A2A.GET_TASK_METHOD;
-import static io.a2a.spec.A2A.GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD;
-import static io.a2a.spec.A2A.JSONRPC_VERSION;
-import static io.a2a.spec.A2A.SEND_MESSAGE_METHOD;
-import static io.a2a.spec.A2A.SEND_STREAMING_MESSAGE_METHOD;
-import static io.a2a.spec.A2A.SEND_TASK_RESUBSCRIPTION_METHOD;
-import static io.a2a.spec.A2A.SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD;
import static io.a2a.util.Assert.checkNotNullParam;
-import static io.a2a.util.Utils.OBJECT_MAPPER;
-import static io.a2a.util.Utils.unmarshalFrom;
import java.io.IOException;
import java.util.Map;
@@ -24,7 +14,7 @@
import io.a2a.http.A2AHttpClient;
import io.a2a.http.A2AHttpResponse;
import io.a2a.http.JdkA2AHttpClient;
-import io.a2a.spec.A2A;
+import io.a2a.A2A;
import io.a2a.spec.A2AClientError;
import io.a2a.spec.A2AClientJSONError;
import io.a2a.spec.A2AServerException;
@@ -36,6 +26,7 @@
import io.a2a.spec.GetTaskRequest;
import io.a2a.spec.GetTaskResponse;
import io.a2a.spec.JSONRPCError;
+import io.a2a.spec.JSONRPCMessage;
import io.a2a.spec.JSONRPCResponse;
import io.a2a.spec.MessageSendParams;
import io.a2a.spec.PushNotificationConfig;
@@ -49,6 +40,7 @@
import io.a2a.spec.TaskPushNotificationConfig;
import io.a2a.spec.TaskQueryParams;
import io.a2a.spec.TaskResubscriptionRequest;
+import io.a2a.util.Utils;
/**
* An A2A client.
@@ -158,8 +150,8 @@ public SendMessageResponse sendMessage(MessageSendParams messageSendParams) thro
*/
public SendMessageResponse sendMessage(String requestId, MessageSendParams messageSendParams) throws A2AServerException {
SendMessageRequest.Builder sendMessageRequestBuilder = new SendMessageRequest.Builder()
- .jsonrpc(JSONRPC_VERSION)
- .method(SEND_MESSAGE_METHOD)
+ .jsonrpc(JSONRPCMessage.JSONRPC_VERSION)
+ .method(SendMessageRequest.METHOD)
.params(messageSendParams);
if (requestId != null) {
@@ -210,8 +202,8 @@ public GetTaskResponse getTask(TaskQueryParams taskQueryParams) throws A2AServer
*/
public GetTaskResponse getTask(String requestId, TaskQueryParams taskQueryParams) throws A2AServerException {
GetTaskRequest.Builder getTaskRequestBuilder = new GetTaskRequest.Builder()
- .jsonrpc(JSONRPC_VERSION)
- .method(GET_TASK_METHOD)
+ .jsonrpc(JSONRPCMessage.JSONRPC_VERSION)
+ .method(GetTaskRequest.METHOD)
.params(taskQueryParams);
if (requestId != null) {
@@ -260,8 +252,8 @@ public CancelTaskResponse cancelTask(TaskIdParams taskIdParams) throws A2AServer
*/
public CancelTaskResponse cancelTask(String requestId, TaskIdParams taskIdParams) throws A2AServerException {
CancelTaskRequest.Builder cancelTaskRequestBuilder = new CancelTaskRequest.Builder()
- .jsonrpc(JSONRPC_VERSION)
- .method(CANCEL_TASK_METHOD)
+ .jsonrpc(JSONRPCMessage.JSONRPC_VERSION)
+ .method(CancelTaskRequest.METHOD)
.params(taskIdParams);
if (requestId != null) {
@@ -310,8 +302,8 @@ public GetTaskPushNotificationConfigResponse getTaskPushNotificationConfig(TaskI
*/
public GetTaskPushNotificationConfigResponse getTaskPushNotificationConfig(String requestId, TaskIdParams taskIdParams) throws A2AServerException {
GetTaskPushNotificationConfigRequest.Builder getTaskPushNotificationRequestBuilder = new GetTaskPushNotificationConfigRequest.Builder()
- .jsonrpc(JSONRPC_VERSION)
- .method(GET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD)
+ .jsonrpc(JSONRPCMessage.JSONRPC_VERSION)
+ .method(GetTaskPushNotificationConfigRequest.METHOD)
.params(taskIdParams);
if (requestId != null) {
@@ -353,8 +345,8 @@ public SetTaskPushNotificationConfigResponse setTaskPushNotificationConfig(Strin
public SetTaskPushNotificationConfigResponse setTaskPushNotificationConfig(String requestId, String taskId,
PushNotificationConfig pushNotificationConfig) throws A2AServerException {
SetTaskPushNotificationConfigRequest.Builder setTaskPushNotificationRequestBuilder = new SetTaskPushNotificationConfigRequest.Builder()
- .jsonrpc(JSONRPC_VERSION)
- .method(SET_TASK_PUSH_NOTIFICATION_CONFIG_METHOD)
+ .jsonrpc(JSONRPCMessage.JSONRPC_VERSION)
+ .method(SetTaskPushNotificationConfigRequest.METHOD)
.params(new TaskPushNotificationConfig(taskId, pushNotificationConfig));
if (requestId != null) {
@@ -403,8 +395,8 @@ public void sendStreamingMessage(String requestId, MessageSendParams messageSend
checkNotNullParam("failureHandler", failureHandler);
SendStreamingMessageRequest.Builder sendStreamingMessageRequestBuilder = new SendStreamingMessageRequest.Builder()
- .jsonrpc(JSONRPC_VERSION)
- .method(SEND_STREAMING_MESSAGE_METHOD)
+ .jsonrpc(JSONRPCMessage.JSONRPC_VERSION)
+ .method(SendStreamingMessageRequest.METHOD)
.params(messageSendParams);
if (requestId != null) {
@@ -462,8 +454,8 @@ public void resubscribeToTask(String requestId, TaskIdParams taskIdParams, Consu
checkNotNullParam("failureHandler", failureHandler);
TaskResubscriptionRequest.Builder taskResubscriptionRequestBuilder = new TaskResubscriptionRequest.Builder()
- .jsonrpc(JSONRPC_VERSION)
- .method(SEND_TASK_RESUBSCRIPTION_METHOD)
+ .jsonrpc(JSONRPCMessage.JSONRPC_VERSION)
+ .method(TaskResubscriptionRequest.METHOD)
.params(taskIdParams);
if (requestId != null) {
@@ -502,13 +494,13 @@ private A2AHttpClient.PostBuilder createPostBuilder(Object value) throws JsonPro
return httpClient.createPost()
.url(agentUrl)
.addHeader("Content-Type", "application/json")
- .body(OBJECT_MAPPER.writeValueAsString(value));
+ .body(Utils.OBJECT_MAPPER.writeValueAsString(value));
}
private T unmarshalResponse(String response, TypeReference typeReference)
throws A2AServerException, JsonProcessingException {
- T value = unmarshalFrom(response, typeReference);
+ T value = Utils.unmarshalFrom(response, typeReference);
JSONRPCError error = value.getError();
if (error != null) {
throw new A2AServerException(error.getMessage() + (error.getData() != null ? ": " + error.getData() : ""));
diff --git a/core/src/main/java/io/a2a/client/sse/SSEEventListener.java b/client/src/main/java/io/a2a/client/sse/SSEEventListener.java
similarity index 100%
rename from core/src/main/java/io/a2a/client/sse/SSEEventListener.java
rename to client/src/main/java/io/a2a/client/sse/SSEEventListener.java
diff --git a/core/src/main/java/io/a2a/http/A2AHttpClient.java b/client/src/main/java/io/a2a/http/A2AHttpClient.java
similarity index 100%
rename from core/src/main/java/io/a2a/http/A2AHttpClient.java
rename to client/src/main/java/io/a2a/http/A2AHttpClient.java
diff --git a/core/src/main/java/io/a2a/http/A2AHttpResponse.java b/client/src/main/java/io/a2a/http/A2AHttpResponse.java
similarity index 100%
rename from core/src/main/java/io/a2a/http/A2AHttpResponse.java
rename to client/src/main/java/io/a2a/http/A2AHttpResponse.java
diff --git a/core/src/main/java/io/a2a/http/JdkA2AHttpClient.java b/client/src/main/java/io/a2a/http/JdkA2AHttpClient.java
similarity index 100%
rename from core/src/main/java/io/a2a/http/JdkA2AHttpClient.java
rename to client/src/main/java/io/a2a/http/JdkA2AHttpClient.java
diff --git a/client/src/main/resources/META-INF/beans.xml b/client/src/main/resources/META-INF/beans.xml
new file mode 100644
index 000000000..e69de29bb
diff --git a/core/src/test/java/io/a2a/client/A2ACardResolverTest.java b/client/src/test/java/io/a2a/client/A2ACardResolverTest.java
similarity index 100%
rename from core/src/test/java/io/a2a/client/A2ACardResolverTest.java
rename to client/src/test/java/io/a2a/client/A2ACardResolverTest.java
diff --git a/core/src/test/java/io/a2a/client/A2AClientStreamingTest.java b/client/src/test/java/io/a2a/client/A2AClientStreamingTest.java
similarity index 100%
rename from core/src/test/java/io/a2a/client/A2AClientStreamingTest.java
rename to client/src/test/java/io/a2a/client/A2AClientStreamingTest.java
diff --git a/core/src/test/java/io/a2a/client/A2AClientTest.java b/client/src/test/java/io/a2a/client/A2AClientTest.java
similarity index 100%
rename from core/src/test/java/io/a2a/client/A2AClientTest.java
rename to client/src/test/java/io/a2a/client/A2AClientTest.java
diff --git a/core/src/test/java/io/a2a/client/JsonMessages.java b/client/src/test/java/io/a2a/client/JsonMessages.java
similarity index 100%
rename from core/src/test/java/io/a2a/client/JsonMessages.java
rename to client/src/test/java/io/a2a/client/JsonMessages.java
diff --git a/core/src/test/java/io/a2a/client/JsonStreamingMessages.java b/client/src/test/java/io/a2a/client/JsonStreamingMessages.java
similarity index 100%
rename from core/src/test/java/io/a2a/client/JsonStreamingMessages.java
rename to client/src/test/java/io/a2a/client/JsonStreamingMessages.java
diff --git a/core/src/test/java/io/a2a/client/sse/SSEEventListenerTest.java b/client/src/test/java/io/a2a/client/sse/SSEEventListenerTest.java
similarity index 100%
rename from core/src/test/java/io/a2a/client/sse/SSEEventListenerTest.java
rename to client/src/test/java/io/a2a/client/sse/SSEEventListenerTest.java
diff --git a/common/pom.xml b/common/pom.xml
new file mode 100644
index 000000000..3b6aabc36
--- /dev/null
+++ b/common/pom.xml
@@ -0,0 +1,26 @@
+
+
+ 4.0.0
+
+
+ io.a2a.sdk
+ a2a-java-sdk-parent
+ 0.2.4-SNAPSHOT
+
+ a2a-java-sdk-common
+
+ jar
+
+ Java SDK A2A Common
+ Java SDK for the Agent2Agent Protocol (A2A) - Common
+
+
+
+ org.slf4j
+ slf4j-api
+
+
+
+
\ No newline at end of file
diff --git a/core/src/main/java/io/a2a/util/Assert.java b/common/src/main/java/io/a2a/util/Assert.java
similarity index 100%
rename from core/src/main/java/io/a2a/util/Assert.java
rename to common/src/main/java/io/a2a/util/Assert.java
diff --git a/core/src/main/java/io/a2a/util/NotNull.java b/common/src/main/java/io/a2a/util/NotNull.java
similarity index 100%
rename from core/src/main/java/io/a2a/util/NotNull.java
rename to common/src/main/java/io/a2a/util/NotNull.java
diff --git a/core/src/main/resources/META-INF/beans.xml b/core/src/main/resources/META-INF/beans.xml
deleted file mode 100644
index 9dfae34df..000000000
--- a/core/src/main/resources/META-INF/beans.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/core/src/test/java/io/a2a/util/AssertTest.java b/core/src/test/java/io/a2a/util/AssertTest.java
deleted file mode 100644
index 247764dac..000000000
--- a/core/src/test/java/io/a2a/util/AssertTest.java
+++ /dev/null
@@ -1,100 +0,0 @@
-package io.a2a.util;
-
-import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import org.junit.jupiter.api.Test;
-
-/**
- * Tests for Assert utility class
- */
-class AssertTest {
-
- @Test
- void testCheckNotNullParam_WithValidValue() {
- // Test normal case
- String testValue = "test";
- String result = Assert.checkNotNullParam("testParam", testValue);
- assertEquals(testValue, result);
- }
-
- @Test
- void testCheckNotNullParam_WithNullValue() {
- // Test that null value throws exception
- assertThrows(IllegalArgumentException.class, () -> {
- Assert.checkNotNullParam("testParam", null);
- });
- }
-
- @Test
- void testCheckNotNullParam_WithNullName() {
- // Test that null name parameter throws exception
- assertThrows(IllegalArgumentException.class, () -> {
- Assert.checkNotNullParam(null, "testValue");
- });
- }
-
- @Test
- void testCheckNotNullParam_WithEmptyName() {
- // Test empty string name parameter
- String testValue = "test";
- String result = Assert.checkNotNullParam("", testValue);
- assertEquals(testValue, result);
- }
-
- @Test
- void testIsNullOrStringOrInteger_WithNull() {
- // Test null value
- assertDoesNotThrow(() -> {
- Assert.isNullOrStringOrInteger(null);
- });
- }
-
- @Test
- void testIsNullOrStringOrInteger_WithString() {
- // Test String type
- assertDoesNotThrow(() -> {
- Assert.isNullOrStringOrInteger("test");
- });
- }
-
- @Test
- void testIsNullOrStringOrInteger_WithInteger() {
- // Test Integer type
- assertDoesNotThrow(() -> {
- Assert.isNullOrStringOrInteger(123);
- });
- }
-
- @Test
- void testIsNullOrStringOrInteger_WithLong() {
- // Test that Long type throws exception
- assertThrows(IllegalArgumentException.class, () -> {
- Assert.isNullOrStringOrInteger(123L);
- });
- }
-
- @Test
- void testIsNullOrStringOrInteger_WithDouble() {
- // Test that Double type throws exception
- assertThrows(IllegalArgumentException.class, () -> {
- Assert.isNullOrStringOrInteger(123.45);
- });
- }
-
- @Test
- void testIsNullOrStringOrInteger_WithBoolean() {
- // Test that Boolean type throws exception
- assertThrows(IllegalArgumentException.class, () -> {
- Assert.isNullOrStringOrInteger(true);
- });
- }
-
- @Test
- void testIsNullOrStringOrInteger_WithObject() {
- // Test that Object type throws exception
- assertThrows(IllegalArgumentException.class, () -> {
- Assert.isNullOrStringOrInteger(new Object());
- });
- }
-}
diff --git a/core/src/test/java/io/a2a/util/UtilsTest.java b/core/src/test/java/io/a2a/util/UtilsTest.java
deleted file mode 100644
index a9f7953f3..000000000
--- a/core/src/test/java/io/a2a/util/UtilsTest.java
+++ /dev/null
@@ -1,169 +0,0 @@
-package io.a2a.util;
-
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import com.fasterxml.jackson.core.type.TypeReference;
-import org.junit.jupiter.api.Test;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * Tests for Utils utility class
- */
-class UtilsTest {
-
- @Test
- void testDefaultIfNull_WithNullValue() {
- // Test that null value returns default value
- String result = Utils.defaultIfNull(null, "default");
- assertEquals("default", result);
- }
-
- @Test
- void testDefaultIfNull_WithNonNullValue() {
- // Test that non-null value returns original value
- String value = "test";
- String result = Utils.defaultIfNull(value, "default");
- assertEquals(value, result);
- }
-
- @Test
- void testDefaultIfNull_WithNullDefault() {
- // Test case where default value is null
- String value = "test";
- String result = Utils.defaultIfNull(value, null);
- assertEquals(value, result);
- }
-
- @Test
- void testDefaultIfNull_WithBothNull() {
- // Test case where both value and default are null
- String result = Utils.defaultIfNull(null, null);
- assertNull(result);
- }
-
- @Test
- void testDefaultIfNull_WithDifferentTypes() {
- // Test with different types
- Integer intValue = 123;
- Integer result = Utils.defaultIfNull(intValue, 456);
- assertEquals(intValue, result);
- }
-
- @Test
- void testUnmarshalFrom_WithValidJson() throws Exception {
- // Test with valid JSON string
- String json = "{\"name\":\"test\",\"value\":123}";
- TypeReference