|
1 | | -# Java A2A SDK (WIP) |
| 1 | +# A2A Java SDK |
2 | 2 |
|
3 | | -This project (currently WIP) will provide a Java SDK implementation of Google's [Agent2Agent protocol (A2A)](https://google.github.io/A2A/). |
| 3 | +<html> |
| 4 | + <h3 align="center">A Java library that helps run agentic applications as A2AServers following Google's <a href="https://google-a2a.github.io/A2A">Agent2Agent (A2A) Protocol</a>.</h3> |
| 5 | +</html> |
4 | 6 |
|
5 | | -## Specification |
| 7 | +## Installation |
6 | 8 |
|
7 | | -The majority of the classes required by the specification can currently be found in the [src/main/java/io/a2a/spec](https://github.com/fjuma/a2a-java-sdk/tree/main/src/main/java/io/a2a/spec) directory. |
| 9 | +You can build the A2A Java SDK using `mvn`: |
| 10 | + |
| 11 | +```bash |
| 12 | +mvn clean install |
| 13 | +``` |
| 14 | + |
| 15 | +## Examples |
| 16 | + |
| 17 | +You can find an example of how to use the A2A Java SDK [here](https://github.com/fjuma/a2a-samples/tree/java-sdk-example/samples/multi_language/python_and_java_multiagent/weather_agent). |
| 18 | + |
| 19 | +More examples will be added soon. |
| 20 | + |
| 21 | +## A2A Server |
| 22 | + |
| 23 | +The A2A Java SDK provides a Java server implementation of the [Agent2Agent (A2A) Protocol](https://google-a2a.github.io/A2A). To run your agentic Java application as an A2A server, simply follow the steps below. |
| 24 | + |
| 25 | +- [Add the A2A Java SDK Core Maven dependency to your project](#1-add-the-a2a-java-sdk-core-maven-dependency-to-your-project) |
| 26 | +- [Add a class that creates an A2A Agent Card](#2-add-a-class-that-creates-an-a2a-agent-card) |
| 27 | +- [Add a class that creates an A2A Agent Executor](#3-add-a-class-that-creates-an-a2a-agent-executor) |
| 28 | +- [Add an A2A Java SDK Server Maven dependency to your project](#4-add-an-a2a-java-sdk-server-maven-dependency-to-your-project) |
| 29 | + |
| 30 | +### 1. Add the A2A Java SDK Core Maven dependency to your project |
| 31 | + |
| 32 | +> **Note**: The A2A Java SDK isn't available yet in Maven Central but will be soon. For now, be |
| 33 | +> sure to check out the latest tag (you can see the tags [here](https://github.com/fjuma/a2a-java-sdk/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. |
| 34 | +
|
| 35 | +```xml |
| 36 | +<dependency> |
| 37 | + <groupId>io.a2a.sdk</groupId> |
| 38 | + <artifactId>a2a-java-sdk-core</artifactId> |
| 39 | + <version>0.2.3</version> |
| 40 | +</dependency> |
| 41 | +``` |
| 42 | + |
| 43 | +### 2. Add a class that creates an A2A Agent Card |
| 44 | + |
| 45 | +```java |
| 46 | +import io.a2a.spec.AgentCapabilities; |
| 47 | +import io.a2a.spec.AgentCard; |
| 48 | +import io.a2a.spec.AgentSkill; |
| 49 | +import io.a2a.spec.PublicAgentCard; |
| 50 | +... |
| 51 | + |
| 52 | +@ApplicationScoped |
| 53 | +public class WeatherAgentCardProducer { |
| 54 | + |
| 55 | + @Produces |
| 56 | + @PublicAgentCard |
| 57 | + public AgentCard agentCard() { |
| 58 | + return new AgentCard.Builder() |
| 59 | + .name("Weather Agent") |
| 60 | + .description("Helps with weather") |
| 61 | + .url("http://localhost:10001") |
| 62 | + .version("1.0.0") |
| 63 | + .capabilities(new AgentCapabilities.Builder() |
| 64 | + .streaming(true) |
| 65 | + .pushNotifications(false) |
| 66 | + .stateTransitionHistory(false) |
| 67 | + .build()) |
| 68 | + .defaultInputModes(Collections.singletonList("text")) |
| 69 | + .defaultOutputModes(Collections.singletonList("text")) |
| 70 | + .skills(Collections.singletonList(new AgentSkill.Builder() |
| 71 | + .id("weather_search") |
| 72 | + .name("Search weather") |
| 73 | + .description("Helps with weather in city, or states") |
| 74 | + .tags(Collections.singletonList("weather")) |
| 75 | + .examples(List.of("weather in LA, CA")) |
| 76 | + .build())) |
| 77 | + .build(); |
| 78 | + } |
| 79 | +} |
| 80 | +``` |
| 81 | + |
| 82 | +### 3. Add a class that creates an A2A Agent Executor |
| 83 | + |
| 84 | +```java |
| 85 | +import io.a2a.server.agentexecution.AgentExecutor; |
| 86 | +import io.a2a.server.agentexecution.RequestContext; |
| 87 | +import io.a2a.server.events.EventQueue; |
| 88 | +import io.a2a.server.tasks.TaskUpdater; |
| 89 | +import io.a2a.spec.JSONRPCError; |
| 90 | +import io.a2a.spec.Message; |
| 91 | +import io.a2a.spec.Part; |
| 92 | +import io.a2a.spec.Task; |
| 93 | +import io.a2a.spec.TaskNotCancelableError; |
| 94 | +import io.a2a.spec.TaskState; |
| 95 | +import io.a2a.spec.TextPart; |
| 96 | +... |
| 97 | + |
| 98 | +@ApplicationScoped |
| 99 | +public class WeatherAgentExecutorProducer { |
| 100 | + |
| 101 | + @Inject |
| 102 | + WeatherAgent weatherAgent; |
| 103 | + |
| 104 | + @Produces |
| 105 | + public AgentExecutor agentExecutor() { |
| 106 | + return new WeatherAgentExecutor(weatherAgent); |
| 107 | + } |
| 108 | + |
| 109 | + private static class WeatherAgentExecutor implements AgentExecutor { |
| 110 | + |
| 111 | + private final WeatherAgent weatherAgent; |
| 112 | + |
| 113 | + public WeatherAgentExecutor(WeatherAgent weatherAgent) { |
| 114 | + this.weatherAgent = weatherAgent; |
| 115 | + } |
| 116 | + |
| 117 | + @Override |
| 118 | + public void execute(RequestContext context, EventQueue eventQueue) throws JSONRPCError { |
| 119 | + TaskUpdater updater = new TaskUpdater(context, eventQueue); |
| 120 | + |
| 121 | + // mark the task as submitted and start working on it |
| 122 | + if (context.getTask() == null) { |
| 123 | + updater.submit(); |
| 124 | + } |
| 125 | + updater.startWork(); |
| 126 | + |
| 127 | + // extract the text from the message |
| 128 | + String userMessage = extractTextFromMessage(context.getMessage()); |
| 129 | + |
| 130 | + // call the weather agent with the user's message |
| 131 | + String response = weatherAgent.chat(userMessage); |
| 132 | + |
| 133 | + // create the response part |
| 134 | + TextPart responsePart = new TextPart(response, null); |
| 135 | + List<Part<?>> parts = List.of(responsePart); |
| 136 | + |
| 137 | + // add the response as an artifact and complete the task |
| 138 | + updater.addArtifact(parts, null, null, null); |
| 139 | + updater.complete(); |
| 140 | + } |
| 141 | + |
| 142 | + private String extractTextFromMessage(Message message) { |
| 143 | + StringBuilder textBuilder = new StringBuilder(); |
| 144 | + if (message.getParts() != null) { |
| 145 | + for (Part part : message.getParts()) { |
| 146 | + if (part instanceof TextPart textPart) { |
| 147 | + textBuilder.append(textPart.getText()); |
| 148 | + } |
| 149 | + } |
| 150 | + } |
| 151 | + return textBuilder.toString(); |
| 152 | + } |
| 153 | + |
| 154 | + @Override |
| 155 | + public void cancel(RequestContext context, EventQueue eventQueue) throws JSONRPCError { |
| 156 | + Task task = context.getTask(); |
| 157 | + |
| 158 | + if (task.getStatus().state() == TaskState.CANCELED) { |
| 159 | + // task already cancelled |
| 160 | + throw new TaskNotCancelableError(); |
| 161 | + } |
| 162 | + |
| 163 | + if (task.getStatus().state() == TaskState.COMPLETED) { |
| 164 | + // task already completed |
| 165 | + throw new TaskNotCancelableError(); |
| 166 | + } |
| 167 | + |
| 168 | + // cancel the task |
| 169 | + TaskUpdater updater = new TaskUpdater(context, eventQueue); |
| 170 | + updater.cancel(); |
| 171 | + } |
| 172 | + } |
| 173 | +} |
| 174 | +``` |
| 175 | + |
| 176 | +### 4. Add an A2A Java SDK Server Maven dependency to your project |
| 177 | + |
| 178 | +> **Note**: The A2A Java SDK isn't available yet in Maven Central but will be soon. For now, be |
| 179 | +> sure to check out the latest tag (you can see the tags [here](https://github.com/fjuma/a2a-java-sdk/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. |
| 180 | +
|
| 181 | +Adding a dependency on an A2A Java SDK Server will allow you to run your agentic Java application as an A2A server. |
| 182 | + |
| 183 | +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. |
| 184 | + |
| 185 | +Add **one** of the following dependencies to your project: |
| 186 | + |
| 187 | +```xml |
| 188 | +<dependency> |
| 189 | + <groupId>io.a2a.sdk</groupId> |
| 190 | + <artifactId>a2a-java-sdk-server-jakarta</artifactId> |
| 191 | + <version>${io.a2a.sdk.version}</version> |
| 192 | +</dependency> |
| 193 | +``` |
| 194 | + |
| 195 | +OR |
| 196 | + |
| 197 | +```xml |
| 198 | +<dependency> |
| 199 | + <groupId>io.a2a.sdk</groupId> |
| 200 | + <artifactId>a2a-java-sdk-server-quarkus</artifactId> |
| 201 | + <version>${io.a2a.sdk.version}</version> |
| 202 | +</dependency> |
| 203 | +``` |
8 | 204 |
|
9 | 205 | ## Client |
10 | 206 |
|
|
0 commit comments