From 10545299f88c6e38233bdceff173610ebbb12f5e Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 11 Oct 2026 08:25:15 +0000 Subject: [PATCH] Add a2a module: agent card, tasks, streaming, input-required and agent-to-agent calls on the A2A Java SDK, served over the JDK HTTP server Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01G8ikz8xdWuTP5yun8DZ1hk --- README.md | 6 +- a2a/output/01-agent-card.txt | 40 ++++ a2a/output/02-raw-send-message.txt | 61 +++++ a2a/output/03-streaming.txt | 15 ++ a2a/output/04-input-required.txt | 9 + a2a/output/05-agent-to-agent.txt | 17 ++ a2a/output/06-dependencies.txt | 42 ++++ a2a/output/07-blocking.txt | 5 + a2a/pom.xml | 54 +++++ .../java/com/ankurm/agents/a2a/A2aCaller.java | 160 +++++++++++++ .../com/ankurm/agents/a2a/A2aHttpServer.java | 224 ++++++++++++++++++ .../com/ankurm/agents/a2a/BriefAgent.java | 79 ++++++ .../com/ankurm/agents/a2a/GlossaryAgent.java | 70 ++++++ .../a2a/JdkJsonRpcTransportMetadata.java | 16 ++ .../services/io.a2a.server.TransportMetadata | 1 + .../java/com/ankurm/agents/a2a/A2aTest.java | 203 ++++++++++++++++ .../com/ankurm/agents/a2a/Transcript.java | 39 +++ .../test/resources/simplelogger.properties | 1 + pom.xml | 2 + 19 files changed, 1042 insertions(+), 2 deletions(-) create mode 100644 a2a/output/01-agent-card.txt create mode 100644 a2a/output/02-raw-send-message.txt create mode 100644 a2a/output/03-streaming.txt create mode 100644 a2a/output/04-input-required.txt create mode 100644 a2a/output/05-agent-to-agent.txt create mode 100644 a2a/output/06-dependencies.txt create mode 100644 a2a/output/07-blocking.txt create mode 100644 a2a/pom.xml create mode 100644 a2a/src/main/java/com/ankurm/agents/a2a/A2aCaller.java create mode 100644 a2a/src/main/java/com/ankurm/agents/a2a/A2aHttpServer.java create mode 100644 a2a/src/main/java/com/ankurm/agents/a2a/BriefAgent.java create mode 100644 a2a/src/main/java/com/ankurm/agents/a2a/GlossaryAgent.java create mode 100644 a2a/src/main/java/com/ankurm/agents/a2a/JdkJsonRpcTransportMetadata.java create mode 100644 a2a/src/main/resources/META-INF/services/io.a2a.server.TransportMetadata create mode 100644 a2a/src/test/java/com/ankurm/agents/a2a/A2aTest.java create mode 100644 a2a/src/test/java/com/ankurm/agents/a2a/Transcript.java create mode 100644 a2a/src/test/resources/simplelogger.properties diff --git a/README.md b/README.md index 63b7281..0e30b50 100644 --- a/README.md +++ b/README.md @@ -7,12 +7,14 @@ facts, so the build fails when a claim stops being true. | Module | Post | What it shows | |---|---|---| | `embabel` | Embabel: Goal-Oriented AI Agents on the JVM | actions, goals, conditions and cost-based planning with GOAP, compared with plain Spring AI | +| `a2a` | A2A Protocol in Java: Agents That Talk to Each Other | agent card, tasks, streaming, input-required and agent-to-agent calls with the A2A Java SDK | ## Versions (verified on Maven Central, 2026-10-11) | Component | Version | Note | |---|---|---| | Embabel `embabel-agent-api` | 1.5.3 | brings Spring AI 2.0.1 and Spring Boot 4.1.1 transitively | +| A2A Java SDK `io.github.a2asdk` | 1.0.0.Alpha3 | alpha; targets A2A protocol 1.0. The newest stable release, 0.3.3.Final, targets the 0.3 protocol and its API differs | | JDK | 25 LTS | | | JUnit | 6.1.3 | | @@ -21,9 +23,9 @@ facts, so the build fails when a claim stops being true. ```bash export JAVA_HOME=/path/to/jdk-25 mvn test # everything -mvn test -pl embabel -am # one module +mvn test -pl a2a -am # one module ``` -No API key is needed. The Embabel tests use `ScriptedLlmOperations`, the scripted stand-in shipped inside +No API key is needed. The A2A agents contain no model call, because the protocol is the subject. The Embabel tests use `ScriptedLlmOperations`, the scripted stand-in shipped inside `embabel-agent-api`, and the Spring AI comparison uses a small scripted `ChatModel`. Each module writes its transcripts to `/output/` when you run the tests. diff --git a/a2a/output/01-agent-card.txt b/a2a/output/01-agent-card.txt new file mode 100644 index 0000000..960aa82 --- /dev/null +++ b/a2a/output/01-agent-card.txt @@ -0,0 +1,40 @@ +GET /.well-known/agent-card.json + +{ + "name": "Glossary Agent", + "description": "Defines Java terms", + "version": "1.0.0", + "capabilities": { + "streaming": true, + "pushNotifications": false, + "extendedAgentCard": false + }, + "defaultInputModes": [ + "text/plain" + ], + "defaultOutputModes": [ + "text/plain" + ], + "skills": [ + { + "id": "define", + "name": "Define a term", + "description": "Returns a one-sentence definition", + "tags": [ + "java", + "glossary" + ], + "examples": [ + "record" + ] + } + ], + "supportedInterfaces": [ + { + "protocolBinding": "JSONRPC", + "url": "http://127.0.0.1:PORT", + "tenant": "", + "protocolVersion": "1.0" + } + ] +} diff --git a/a2a/output/02-raw-send-message.txt b/a2a/output/02-raw-send-message.txt new file mode 100644 index 0000000..286853d --- /dev/null +++ b/a2a/output/02-raw-send-message.txt @@ -0,0 +1,61 @@ +POST / +{ + "jsonrpc": "2.0", + "id": "1", + "method": "SendMessage", + "params": { + "message": { + "messageId": "m-1", + "role": "ROLE_USER", + "parts": [ + { + "text": "record" + } + ] + }, + "configuration": { + "blocking": true + } + } +} + +Response: +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "task": { + "id": "", + "contextId": "", + "status": { + "state": "TASK_STATE_COMPLETED", + "timestamp": "