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 <[email protected]> Claude-Session: https://claude.ai/code/session_01G8ikz8xdWuTP5yun8DZ1hk
This commit is contained in:
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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": "<id-1>",
|
||||
"contextId": "<id-2>",
|
||||
"status": {
|
||||
"state": "TASK_STATE_COMPLETED",
|
||||
"timestamp": "<time>"
|
||||
},
|
||||
"artifacts": [
|
||||
{
|
||||
"artifactId": "definition",
|
||||
"name": "definition",
|
||||
"description": "",
|
||||
"parts": [
|
||||
{
|
||||
"text": "A record is a final class that is a transparent",
|
||||
"metadata": {},
|
||||
"filename": "",
|
||||
"mediaType": ""
|
||||
},
|
||||
{
|
||||
"text": " carrier for its components.",
|
||||
"metadata": {},
|
||||
"filename": "",
|
||||
"mediaType": ""
|
||||
}
|
||||
],
|
||||
"metadata": {},
|
||||
"extensions": []
|
||||
}
|
||||
],
|
||||
"history": [],
|
||||
"metadata": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
Same question, "record", asked twice.
|
||||
|
||||
Blocking (streaming off): 1 event
|
||||
TaskEvent state=COMPLETED artifacts=1
|
||||
answer: A record is a final class that is a transparent carrier for its components.
|
||||
|
||||
Streaming: 5 events
|
||||
TaskStatusUpdate state=SUBMITTED final=false
|
||||
TaskStatusUpdate state=WORKING final=false
|
||||
TaskArtifactUpdate append=false lastChunk=false text="A record is a final class that is a transparent"
|
||||
TaskArtifactUpdate append=true lastChunk=true text=" carrier for its components."
|
||||
TaskStatusUpdate state=COMPLETED final=true
|
||||
answer: A record is a final class that is a transparent carrier for its components.
|
||||
|
||||
GetTask for the streamed task afterwards: state TASK_STATE_COMPLETED, artifacts 1, artifact text "A record is a final class that is a transparent carrier for its components."
|
||||
@@ -0,0 +1,9 @@
|
||||
Turn 1: message with no term.
|
||||
task <id-1> state INPUT_REQUIRED
|
||||
agent says: Which term should I define?
|
||||
|
||||
Turn 2: message "sealed class" sent with taskId <id-1>.
|
||||
task <id-1> state COMPLETED
|
||||
answer: A sealed class restricts which other classes may extend it.
|
||||
|
||||
Same task id both turns: true
|
||||
@@ -0,0 +1,17 @@
|
||||
Caller -> Brief Agent -> Glossary Agent.
|
||||
|
||||
Request: "record, sealed class"
|
||||
Brief Agent task state: COMPLETED
|
||||
result:
|
||||
- record: A record is a final class that is a transparent carrier for its components.
|
||||
- sealed class: A sealed class restricts which other classes may extend it.
|
||||
Calls the Brief Agent made to the Glossary Agent:
|
||||
SendMessage "record" -> COMPLETED "A record is a final class that is a transparent carrier for its components."
|
||||
SendMessage "sealed class" -> COMPLETED "A sealed class restricts which other classes may extend it."
|
||||
|
||||
Request: "record, monad"
|
||||
Brief Agent task state: FAILED
|
||||
message: Glossary Agent could not help: I do not know the term 'monad'.
|
||||
Calls the Brief Agent made to the Glossary Agent:
|
||||
SendMessage "record" -> COMPLETED "A record is a final class that is a transparent carrier for its components."
|
||||
SendMessage "monad" -> FAILED "I do not know the term 'monad'."
|
||||
@@ -0,0 +1,42 @@
|
||||
mvn dependency:tree for the a2a module (compile scope):
|
||||
com.ankurm.agents:a2a:jar:1.0.0
|
||||
io.github.a2asdk:a2a-java-sdk-server-common:jar:1.0.0.Alpha3:compile
|
||||
io.github.a2asdk:a2a-java-sdk-spec:jar:1.0.0.Alpha3:compile
|
||||
io.github.a2asdk:a2a-java-sdk-jsonrpc-common:jar:1.0.0.Alpha3:compile
|
||||
io.github.a2asdk:a2a-java-sdk-spec-grpc:jar:1.0.0.Alpha3:compile
|
||||
com.google.protobuf:protobuf-java:jar:4.33.1:compile
|
||||
com.google.api.grpc:proto-google-common-protos:jar:2.63.1:compile
|
||||
io.github.a2asdk:a2a-java-sdk-http-client:jar:1.0.0.Alpha3:compile
|
||||
io.smallrye.reactive:mutiny-zero:jar:1.1.1:compile
|
||||
jakarta.enterprise:jakarta.enterprise.cdi-api:jar:4.1.0:compile
|
||||
jakarta.enterprise:jakarta.enterprise.lang-model:jar:4.1.0:compile
|
||||
jakarta.annotation:jakarta.annotation-api:jar:3.0.0:compile
|
||||
jakarta.el:jakarta.el-api:jar:6.0.0:compile
|
||||
jakarta.interceptor:jakarta.interceptor-api:jar:2.2.0:compile
|
||||
jakarta.inject:jakarta.inject-api:jar:2.0.1:compile
|
||||
org.slf4j:slf4j-api:jar:2.0.17:compile
|
||||
io.github.a2asdk:a2a-java-sdk-transport-jsonrpc:jar:1.0.0.Alpha3:compile
|
||||
com.google.protobuf:protobuf-java-util:jar:4.32.1:compile
|
||||
com.google.code.findbugs:jsr305:jar:3.0.2:runtime
|
||||
com.google.errorprone:error_prone_annotations:jar:2.18.0:compile
|
||||
com.google.guava:guava:jar:32.0.1-jre:runtime
|
||||
com.google.guava:failureaccess:jar:1.0.1:runtime
|
||||
com.google.guava:listenablefuture:jar:9999.0-empty-to-avoid-conflict-with-guava:runtime
|
||||
com.google.j2objc:j2objc-annotations:jar:2.8:runtime
|
||||
com.google.code.gson:gson:jar:2.13.2:compile
|
||||
io.github.a2asdk:a2a-java-sdk-client:jar:1.0.0.Alpha3:compile
|
||||
io.github.a2asdk:a2a-java-sdk-client-transport-spi:jar:1.0.0.Alpha3:compile
|
||||
io.github.a2asdk:a2a-java-sdk-common:jar:1.0.0.Alpha3:compile
|
||||
io.github.a2asdk:a2a-java-sdk-client-transport-jsonrpc:jar:1.0.0.Alpha3:compile
|
||||
org.slf4j:slf4j-simple:jar:2.0.17:test
|
||||
org.junit.jupiter:junit-jupiter:jar:6.1.3:test
|
||||
org.junit.jupiter:junit-jupiter-api:jar:6.1.3:test
|
||||
org.opentest4j:opentest4j:jar:1.3.0:test
|
||||
org.junit.platform:junit-platform-commons:jar:6.1.3:test
|
||||
org.apiguardian:apiguardian-api:jar:1.1.2:test
|
||||
org.jspecify:jspecify:jar:1.0.0:test
|
||||
org.junit.jupiter:junit-jupiter-params:jar:6.1.3:test
|
||||
org.junit.jupiter:junit-jupiter-engine:jar:6.1.3:test
|
||||
org.junit.platform:junit-platform-engine:jar:6.1.3:test
|
||||
org.assertj:assertj-core:jar:3.27.6:test
|
||||
net.bytebuddy:byte-buddy:jar:1.17.7:test
|
||||
@@ -0,0 +1,5 @@
|
||||
The agent accepts the task at once, then works for 400 ms before finishing.
|
||||
|
||||
SendMessage with configuration.blocking = false: task state TASK_STATE_WORKING, returned in under 400 ms: true
|
||||
SendMessage with configuration.blocking = true: task state TASK_STATE_COMPLETED, returned in at least 400 ms: true
|
||||
SendMessage with no configuration at all: task state TASK_STATE_WORKING, returned in under 400 ms: true
|
||||
Reference in New Issue
Block a user