A2A Server
The A2A Server exposes your RadarOS agents as standard A2A endpoints. Any A2A-compatible client — including agents built with LangGraph, CrewAI, AutoGen, or other frameworks — can discover and interact with your agents.
Setup
import express from "express";
import { Agent, openai, defineTool } from "@radaros/core";
import { createA2AServer } from "@radaros/transport";
import { z } from "zod";
const app = express();
const assistant = new Agent({
name: "assistant",
model: openai("gpt-4o"),
instructions: "You are a helpful assistant.",
});
const calculator = new Agent({
name: "calculator",
model: openai("gpt-4o-mini"),
instructions: "You are a calculator. Use the calculate tool.",
tools: [
defineTool({
name: "calculate",
description: "Evaluate a math expression",
parameters: z.object({
expression: z.string(),
}),
execute: async (args) => String(eval(args.expression)),
}),
],
});
createA2AServer(app, {
agents: { assistant, calculator },
basePath: "/",
provider: {
organization: "MyCompany",
url: "https://mycompany.com",
},
});
app.listen(3001, () => {
console.log("A2A Server running at http://localhost:3001");
});
Agent Card
The server automatically generates an Agent Card at /.well-known/agent.json:
{
"name": "RadarOS Agent Server",
"description": "Multi-agent server with 2 agents: assistant, calculator",
"url": "/",
"version": "1.0.0",
"provider": {
"organization": "MyCompany",
"url": "https://mycompany.com"
},
"capabilities": {
"streaming": true,
"pushNotifications": false,
"stateTransitionHistory": true
},
"skills": [
{ "id": "assistant", "name": "assistant", "description": "..." },
{ "id": "calculator", "name": "calculator", "description": "..." }
]
}
Each agent is listed as a skill. The card is auto-generated from agent metadata — no manual configuration needed.
JSON-RPC Methods
The server handles these A2A methods at the basePath:
message/send
Synchronous request/response. Runs the agent and returns the complete result.
curl -X POST http://localhost:3001/ \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "message/send",
"params": {
"message": {
"role": "user",
"parts": [{ "kind": "text", "text": "Hello!" }],
"metadata": { "agentName": "assistant" }
}
}
}'
message/stream
Server-Sent Events (SSE) streaming. Returns chunks as the agent generates output.
curl -X POST http://localhost:3001/ \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "message/stream",
"params": {
"message": {
"role": "user",
"parts": [{ "kind": "text", "text": "Tell me a story" }]
}
}
}'
tasks/get
Retrieve a task by ID, optionally limiting history length.
curl -X POST http://localhost:3001/ \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tasks/get",
"params": { "id": "task-uuid-here" }
}'
tasks/cancel
Cancel a running task.
curl -X POST http://localhost:3001/ \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tasks/cancel",
"params": { "id": "task-uuid-here" }
}'
Agent Routing
When multiple agents are registered, the server resolves which agent to use:
- Explicit — Set
metadata.agentName in the message to target a specific agent
- Name matching — The server checks if the message text mentions an agent name
- Default — Falls back to the first registered agent
Task Lifecycle
Each request creates a task that transitions through these states:
submitted → working → completed
→ failed
→ canceled
The task stores the full message history and any artifacts (tool results).
Configuration
agents
Record<string, Agent>
required
Map of agent name to Agent instance.
Base path for the JSON-RPC endpoint.
Provider information included in the Agent Card.
organization (string) — Organization name
url (string) — Organization URL
Version string for the Agent Card.