Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
7bb58f8
feat: Add A2AClient test variants for server-side testing
misselvexu Jul 11, 2025
eeab344
Update tests/server-common/src/test/java/io/a2a/server/apps/common/Ab…
misselvexu Jul 11, 2025
d9ea203
Update tests/server-common/src/test/java/io/a2a/server/apps/common/Ab…
misselvexu Jul 11, 2025
04a7a43
Update tests/server-common/src/test/java/io/a2a/server/apps/common/Ab…
misselvexu Jul 11, 2025
c2aea7f
Update sdk-jakarta/src/test/java/io/a2a/server/apps/jakarta/JakartaA2…
misselvexu Jul 11, 2025
8d31ddf
feat: Externalise sdk-jakarta, add list of integrations and make Quar…
kabir Jul 11, 2025
d121d5c
fix: Incorporate latest feedback from https://github.com/a2aproject/a…
fjuma Jul 11, 2025
afe5b9e
refactor: unify e2e test base and remove redundant ClientTest variants
misselvexu Jul 12, 2025
fc409e3
fix conflicts
misselvexu Jul 12, 2025
284f665
fix conflicts
misselvexu Jul 12, 2025
c3e7f9e
fix: client sse (#177)
ChenKangQiang Jul 14, 2025
f902f18
feat: Rework tests so they don't rely on running in container (#185)
kabir Jul 14, 2025
d726d0f
chore: Clean up AbstractA2AServerTest (#187)
kabir Jul 17, 2025
93d6bae
feat: Implement the spec updates for v0.2.4 and v0.2.5 (#192)
fjuma Jul 17, 2025
da6e49d
fix: Fix JSONRPCVoidResponseSerializer constructor (#193)
fjuma Jul 18, 2025
b420b52
fix: Remove unnecessary check in the tck AgentExecutor implementation…
fjuma Jul 18, 2025
bc3c8cb
chore: Release 0.2.5.Beta1 and move to next snapshot (#196)
kabir Jul 21, 2025
6f5c8be
chore: automate releasing to Maven central when a tag happens. (#197)
kabir Jul 21, 2025
b5c08bd
Prepare 0.2.5.Beta2 so we can check the release to maven job
kabir Jul 21, 2025
b568d03
Bump to next SNAPSHOT
kabir Jul 21, 2025
865ee63
chore: make workflows manually runnable (#195)
kabir Jul 21, 2025
483760f
chore: release 0.2.5
fjuma Jul 21, 2025
c6627e4
chore: Next is 0.2.5
fjuma Jul 21, 2025
d34844d
chore: release 0.2.5
fjuma Jul 21, 2025
f4ea4ba
chore: Release 0.2.5
fjuma Jul 21, 2025
6caee8e
chore: Next is 0.2.6.Beta1-SNAPSHOT
fjuma Jul 21, 2025
65f4c93
Fix: this is a fix for a2a-tck issue 36 (#202)
maeste Jul 25, 2025
ea56419
feat: Implement ServerCallContext (#206)
kabir Jul 28, 2025
76cc03a
chore: add logging to TaskManager (#205)
kabir Jul 29, 2025
7ff5985
feat: Add A2AClient test variants for server-side testing
misselvexu Jul 11, 2025
dcfbf69
refactor: unify e2e test base and remove redundant ClientTest variants
misselvexu Jul 12, 2025
150d9c2
fix conflicts
misselvexu Jul 30, 2025
237e623
fix AbstractA2AServerTest code review issues .
misselvexu Jul 30, 2025
95656ed
Re-optimise unit tests according to Code review recommendations .
misselvexu Jul 30, 2025
c11b684
Re-optimise unit tests according to Code review recommendations .
misselvexu Jul 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
# Handle all branches for now
push:
pull_request:
workflow_dispatch:

# Only run the latest job
concurrency:
Expand Down
52 changes: 52 additions & 0 deletions .github/workflows/release-to-maven-central.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Publish release to Maven Central

on:
push:
tags:
- 'v?[0-9]+.[0-9]+.[0-9]+*' # Trigger on tags like v1.0.0, 1.2.3, v1.2.3.Alpha1 etc.

jobs:
publish:
# Only run this job for the main repository, not for forks
if: github.repository == 'a2aproject/a2a-java'
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: maven

# Use secrets to import GPG key
- name: Import GPG key
uses: crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.GPG_SIGNING_KEY }}
passphrase: ${{ secrets.GPG_SIGNING_PASSPHRASE }}

# Create settings.xml for Maven since it needs the 'central-a2asdk-temp' server.
# Populate wqith username and password from secrets
- name: Create settings.xml
run: |
mkdir -p ~/.m2
echo "<settings><servers><server><id>central-a2asdk-temp</id><username>${{ secrets.CENTRAL_TOKEN_USERNAME }}</username><password>${{ secrets.CENTRAL_TOKEN_PASSWORD }}</password></server></servers></settings>" > ~/.m2/settings.xml

# Deploy to Maven Central
# -s uses the settings file we created.
- name: Publish to Maven Central
run: >
mvn -B deploy
-s ~/.m2/settings.xml
-P release
-DskipTests
-Drelease.auto.publish=true
env:
# GPG passphrase is set as an environment variable for the gpg plugin to use
GPG_PASSPHRASE: ${{ secrets.GPG_SIGNING_PASSPHRASE }}
3 changes: 2 additions & 1 deletion .github/workflows/run-tck.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ on:
pull_request:
branches:
- main
workflow_dispatch:

env:
# Tag of the TCK
TCK_VERSION: v0.2.3
TCK_VERSION: v0.2.5
# Tells uv to not need a venv, and instead use system
UV_SYSTEM_PYTHON: 1

Expand Down
15 changes: 15 additions & 0 deletions CONTRIBUTING_INTEGRATIONS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Contributing A2A SDK Integrations

To add your A2A SDK Integration for your chosen runtime to the list of integrations in the [README](README.md#server-integrations), open a pull request adding it to the list.

The pull request should contain a link to your project page.

Then the project page itself needs to contain the following information as a minimum:

* How to use the integration.
* Ideally there should be a sample demonstrating how to use it
* The integration should have tests, extending [AbstractA2AServerTest](tests/server-common/src/test/java/io/a2a/server/apps/common/AbstractA2AServerTest.java)
* The integration should pass the [TCK](https://github.com/a2aproject/a2a-tck), and make it obvious how to see that it has passed.
* Ideally, the integration should be deployed in Maven Central. If that is not possible, provide clear instructions for how to build it.

If some of the above points are problematic, feel free to point that out in your pull request, and we can discuss further. For example, AbstractA2AServerTest is currently written with only the initial runtimes in mind, and might need some tweaking.
61 changes: 42 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,32 +33,23 @@ The A2A Java SDK provides a Java server implementation of the [Agent2Agent (A2A)
- [Add a class that creates an A2A Agent Card](#2-add-a-class-that-creates-an-a2a-agent-card)
- [Add a class that creates an A2A Agent Executor](#3-add-a-class-that-creates-an-a2a-agent-executor)

### 1. Add an A2A Java SDK Server Maven dependency to your project
### 1. Add the A2A Java SDK Server Maven dependency to your project

Adding a dependency on an A2A Java SDK Server will provide access to the core classes that make up the A2A specification
and allow you to run your agentic Java application as an A2A server agent.

The A2A Java SDK provides two A2A server endpoint implementations, one based on Jakarta REST (`a2a-java-sdk-server-jakarta`) and one based on Quarkus Reactive Routes (`a2a-java-sdk-server-quarkus`). You can choose the one that best fits your application.
The A2A Java SDK provides a [reference A2A server implementation](reference-impl/README.md) based on [Quarkus](https://quarkus.io) for use with our tests and examples. However, the project is designed in such a way that it is trivial to integrate with various Java runtimes.

Add **one** of the following dependencies to your project:
[Server Integrations](#server-integrations) contains a list of community contributed integrations of the server with various runtimes. You might be able to use one of these for your target runtime, or you can use them as inspiration to create your own.

> *⚠️ The `io.github.a2asdk` `groupId` below is temporary and will likely change for future releases.*

```xml
<dependency>
<groupId>io.github.a2asdk</groupId>
<artifactId>a2a-java-sdk-server-jakarta</artifactId>
<!-- Use a released version from https://github.com/a2aproject/a2a-java/releases -->
<version>${io.a2a.sdk.version}</version>
</dependency>
```
To use the reference implementation add the following dependency to your project:

OR
> *⚠️ The `io.github.a2asdk` `groupId` below is temporary and will likely change for future releases.*

```xml
<dependency>
<groupId>io.github.a2asdk</groupId>
<artifactId>a2a-java-sdk-server-quarkus</artifactId>
<artifactId>a2a-java-reference-server</artifactId>
<!-- Use a released version from https://github.com/a2aproject/a2a-java/releases -->
<version>${io.a2a.sdk.version}</version>
</dependency>
Expand Down Expand Up @@ -98,6 +89,7 @@ public class WeatherAgentCardProducer {
.tags(Collections.singletonList("weather"))
.examples(List.of("weather in LA, CA"))
.build()))
.protocolVersion("0.2.5")
.build();
}
}
Expand Down Expand Up @@ -264,18 +256,21 @@ Map<String, Object> metadata = ...
CancelTaskResponse response = client.cancelTask(new TaskIdParams("task-1234", metadata));
```

#### Get the push notification configuration for a task
#### Get a push notification configuration for a task

```java
// Get task push notification configuration
GetTaskPushNotificationConfigResponse response = client.getTaskPushNotificationConfig("task-1234");

// You can also specify additional properties using a map
// The push notification configuration ID can also be optionally specified
GetTaskPushNotificationConfigResponse response = client.getTaskPushNotificationConfig("task-1234", "config-4567");

// Additional properties can be specified using a map
Map<String, Object> metadata = ...
GetTaskPushNotificationConfigResponse response = client.getTaskPushNotificationConfig(new TaskIdParams("task-1234", metadata));
GetTaskPushNotificationConfigResponse response = client.getTaskPushNotificationConfig(new GetTaskPushNotificationConfigParams("task-1234", "config-1234", metadata));
```

#### Set the push notification configuration for a task
#### Set a push notification configuration for a task

```java
// Set task push notification configuration
Expand All @@ -286,6 +281,26 @@ PushNotificationConfig pushNotificationConfig = new PushNotificationConfig.Build
SetTaskPushNotificationResponse response = client.setTaskPushNotificationConfig("task-1234", pushNotificationConfig);
```

#### List the push notification configurations for a task

```java
ListTaskPushNotificationConfigResponse response = client.listTaskPushNotificationConfig("task-1234");

// Additional properties can be specified using a map
Map<String, Object> metadata = ...
ListTaskPushNotificationConfigResponse response = client.listTaskPushNotificationConfig(new ListTaskPushNotificationConfigParams("task-123", metadata));
```

#### Delete a push notification configuration for a task

```java
DeleteTaskPushNotificationConfigResponse response = client.deleteTaskPushNotificationConfig("task-1234", "config-4567");

// Additional properties can be specified using a map
Map<String, Object> metadata = ...
DeleteTaskPushNotificationConfigResponse response = client.deleteTaskPushNotificationConfig(new DeleteTaskPushNotificationConfigParams("task-1234", "config-4567", metadata));
```

#### Send a streaming message

```java
Expand Down Expand Up @@ -372,5 +387,13 @@ This project is licensed under the terms of the [Apache 2.0 License](LICENSE).

See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines.

## Server Integrations
The following list contains community contributed integrations with various Java Runtimes.

To contribute an integration, please see [CONTRIBUTING_INTEGRATIONS.md](CONTRIBUTING_INTEGRATIONS.md).

* [reference-impl/README.md](reference-impl/README.md) - Reference implementation, based on Quarkus.
* https://github.com/wildfly-extras/a2a-java-sdk-server-jakarta - This integration is based on Jakarta EE, and should work in all runtimes supporting the [Jakarta EE Web Profile](https://jakarta.ee/specifications/webprofile/).



2 changes: 1 addition & 1 deletion client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>io.github.a2asdk</groupId>
<artifactId>a2a-java-sdk-parent</artifactId>
<version>0.2.3.Beta2-SNAPSHOT</version>
<version>0.2.6.Beta1-SNAPSHOT</version>
</parent>
<artifactId>a2a-java-sdk-client</artifactId>

Expand Down
27 changes: 16 additions & 11 deletions client/src/main/java/io/a2a/client/A2ACardResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import static io.a2a.util.Utils.unmarshalFrom;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;

import com.fasterxml.jackson.core.JsonProcessingException;
Expand All @@ -18,14 +20,16 @@ public class A2ACardResolver {
private final String url;
private final Map<String, String> authHeaders;

static String DEFAULT_AGENT_CARD_PATH = "/.well-known/agent.json";
private static final String DEFAULT_AGENT_CARD_PATH = "/.well-known/agent.json";

private static final TypeReference<AgentCard> AGENT_CARD_TYPE_REFERENCE = new TypeReference<>() {};

static final TypeReference<AgentCard> AGENT_CARD_TYPE_REFERENCE = new TypeReference<>() {};
/**
* @param httpClient the http client to use
* @param baseUrl the base URL for the agent whose agent card we want to retrieve
* @throws A2AClientError if the URL for the agent is invalid
*/
public A2ACardResolver(A2AHttpClient httpClient, String baseUrl) {
public A2ACardResolver(A2AHttpClient httpClient, String baseUrl) throws A2AClientError {
this(httpClient, baseUrl, null, null);
}

Expand All @@ -34,8 +38,9 @@ public A2ACardResolver(A2AHttpClient httpClient, String baseUrl) {
* @param baseUrl the base URL for the agent whose agent card we want to retrieve
* @param agentCardPath optional path to the agent card endpoint relative to the base
* agent URL, defaults to ".well-known/agent.json"
* @throws A2AClientError if the URL for the agent is invalid
*/
public A2ACardResolver(A2AHttpClient httpClient, String baseUrl, String agentCardPath) {
public A2ACardResolver(A2AHttpClient httpClient, String baseUrl, String agentCardPath) throws A2AClientError {
this(httpClient, baseUrl, agentCardPath, null);
}

Expand All @@ -45,17 +50,17 @@ public A2ACardResolver(A2AHttpClient httpClient, String baseUrl, String agentCar
* @param agentCardPath optional path to the agent card endpoint relative to the base
* agent URL, defaults to ".well-known/agent.json"
* @param authHeaders the HTTP authentication headers to use. May be {@code null}
* @throws A2AClientError if the URL for the agent is invalid
*/
public A2ACardResolver(A2AHttpClient httpClient, String baseUrl, String agentCardPath, Map<String, String> authHeaders) {
public A2ACardResolver(A2AHttpClient httpClient, String baseUrl, String agentCardPath,
Map<String, String> authHeaders) throws A2AClientError {
this.httpClient = httpClient;
if (!baseUrl.endsWith("/")) {
baseUrl += "/";
}
agentCardPath = agentCardPath == null || agentCardPath.isEmpty() ? DEFAULT_AGENT_CARD_PATH : agentCardPath;
if (agentCardPath.startsWith("/")) {
agentCardPath = agentCardPath.substring(1);
try {
this.url = new URI(baseUrl).resolve(agentCardPath).toString();
} catch (URISyntaxException e) {
throw new A2AClientError("Invalid agent URL", e);
}
this.url = baseUrl + agentCardPath;
this.authHeaders = authHeaders;
}

Expand Down
Loading