π δΈζζζ‘£
A2A4J is a comprehensive Java implementation of the Agent2Agent (A2A) Protocol, providing an open standard for communication and interoperability between independent AI agent systems. Built with Spring Boot integration and reactive programming support, A2A4J enables agents to discover each other's capabilities, collaborate on tasks, and securely exchange information without needing access to each other's internal state.
- β Complete A2A Protocol Support - Full implementation of the Agent2Agent specification
- β JSON-RPC 2.0 Communication - Standards-based request/response messaging
- β Server-Sent Events Streaming - Real-time task updates and streaming responses
- β Task Lifecycle Management - Comprehensive task state management and monitoring
- β Spring Boot Integration - Easy integration with Spring Boot applications
- β Reactive Programming Support - Built on Reactor for scalable, non-blocking operations
- β Multiple Content Types - Support for text, files, and structured data exchange
- βͺοΈ Agent Card Discovery - Dynamic capability discovery mechanism
- βͺοΈ Push Notification Configuration - Asynchronous task updates via webhooks
- βͺοΈ Enterprise Security - Authentication and authorization support
- Java 17+ - Required for running the application
- Maven 3.6+ - Build tool
a2a4j/
βββ a2a4j-core/ # Core A2A protocol implementation
βββ a2a4j-spring-boot-starter/ # Spring Boot auto-configuration
β βββ a2a4j-server-spring-boot-starter/ # Server-side starter
β βββ a2a4j-client-spring-boot-starter/ # Client-side starter
βββ a2a4j-samples/ # Example implementations
β βββ server-hello-world/ # Hello World server example
βββ specification/ # A2A protocol specification
βββ tools/ # Development tools and configuration
git clone https://github.com/a2ap/a2a4j.git
cd a2a4j
mvn clean install
cd a2a4j-samples/server-hello-world
mvn spring-boot:run
The server will start at http://localhost:8089
.
curl http://localhost:8089/.well-known/agent.json
curl -X POST http://localhost:8089/a2a/server \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "message/send",
"params": {
"message": {
"role": "user",
"parts": [
{
"type": "text",
"kind": "text",
"text": "Hello, A2A!"
}
]
}
},
"id": "1"
}'
curl -X POST http://localhost:8089/a2a/server \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"jsonrpc": "2.0",
"method": "message/stream",
"params": {
"message": {
"role": "user",
"parts": [
{
"type": "text",
"kind": "text",
"text": "Hello, streaming A2A!"
}
]
}
},
"id": "1"
}'
The core module provides the fundamental A2A protocol implementation:
- Models: Data structures for Agent Cards, Tasks, Messages, and Artifacts
- Server: Server-side A2A protocol implementation
- Client: Client-side A2A protocol implementation
- JSON-RPC: JSON-RPC 2.0 request/response handling
- Exception Handling: Comprehensive error management
Auto-configuration for A2A servers with Spring Boot, providing:
- Automatic endpoint configuration
- Agent Card publishing
- Task management
- SSE streaming support
Auto-configuration for A2A clients with Spring Boot, providing:
- Agent discovery
- HTTP client configuration
- Reactive client support
Complete working examples demonstrating A2A4J usage:
- Hello World Server: Basic A2A server implementation
- Client Examples: Various client usage patterns
@RestController
public class MyA2AController {
@Autowired
private A2AServer a2aServer;
@Autowired
private final Dispatcher a2aDispatch;
@GetMapping(".well-known/agent.json")
public ResponseEntity<AgentCard> getAgentCard() {
AgentCard card = a2aServer.getSelfAgentCard();
return ResponseEntity.ok(card);
}
@PostMapping(value = "/a2a/server", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<JSONRPCResponse> handleA2ARequestTask(@RequestBody JSONRPCRequest request) {
return ResponseEntity.ok(a2aDispatch.dispatch(request));
}
@PostMapping(value = "/a2a/server", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<JSONRPCResponse>> handleA2ARequestTaskSubscribe(@RequestBody JSONRPCRequest request) {
return a2aDispatch.dispatchStream(request).map(event -> ServerSentEvent.<JSONRPCResponse>builder()
.data(event).event("task-update").build());
}
}
@Component
public class MyAgentExecutor implements AgentExecutor {
@Override
public Mono<Void> execute(RequestContext context, EventQueue eventQueue) {
// your agent logic code
TaskStatusUpdateEvent completedEvent = TaskStatusUpdateEvent.builder()
.taskId(taskId)
.contextId(contextId)
.status(TaskStatus.builder()
.state(TaskState.COMPLETED)
.timestamp(String.valueOf(Instant.now().toEpochMilli()))
.message(createAgentMessage("Task completed successfully! Hi you."))
.build())
.isFinal(true)
.metadata(Map.of(
"executionTime", "3000ms",
"artifactsGenerated", 4,
"success", true))
.build();
eventQueue.enqueueEvent(completedEvent);
return Mono.empty();
}
}
// Create agent card
AgentCard agentCard = AgentCard.builder()
.name("Target Agent")
.url("http://localhost:8089")
.version("1.0.0")
.capabilities(AgentCapabilities.builder().streaming(true).build())
.skills(List.of())
.build();
// Create client
A2AClient client = new A2AClientImpl(agentCard, new HttpCardResolver());
// Send message
TextPart textPart = new TextPart();
textPart.setText("Hello from Java client!");
Message message = Message.builder()
.role("user")
.parts(List.of(textPart))
.build();
MessageSendParams params = MessageSendParams.builder()
.message(message)
.build();
Task result = client.sendTask(params);
System.out.println("Task created: " + result.getId());
// Send message with streaming
Flux<SendStreamingMessageResponse> stream = client.sendTaskSubscribe(params);
stream.subscribe(
event -> {
if (event instanceof TaskStatusUpdateEvent) {
TaskStatusUpdateEvent statusEvent = (TaskStatusUpdateEvent) event;
System.out.println("Status: " + statusEvent.getStatus().getState());
} else if (event instanceof TaskArtifactUpdateEvent) {
TaskArtifactUpdateEvent artifactEvent = (TaskArtifactUpdateEvent) event;
System.out.println("Artifact: " + artifactEvent.getArtifact().getType());
}
},
error
80FA
span> -> System.err.println("Error: " + error.getMessage()),
() -> System.out.println("Stream completed")
);
message/send
- Send a message and create a taskmessage/stream
- Send a message with streaming updates
tasks/get
- Get task status and detailstasks/cancel
- Cancel a running tasktasks/resubscribe
- Resubscribe to task updates
tasks/pushNotificationConfig/set
- Configure push notificationstasks/pushNotificationConfig/get
- Get notification configuration
We welcome contributions! Please see our Contributing Guidelines for details.
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature
- Commit your changes:
git commit -am 'Add new feature'
- Push to the branch:
git push origin feature/my-feature
- Submit a Pull Request
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- CI/CD: GitHub Actions
Built with β€οΈ by the A2AP Community