What Is the A2A v0.3 Protocol in OmniRoute for Agent-to-Agent Communication?

OmniRoute implements the A2A v0.3 protocol as a lightweight JSON-RPC 2.0 service that enables autonomous agents to discover, invoke, and stream results from one another through a standardized interface.

The A2A (Agent-to-Agent) Protocol version 0.3 is the core mechanism that allows OmniRoute to function as both a client and server in multi-agent systems. Built on three interconnected components—a JSON-RPC endpoint, a task lifecycle manager, and a pluggable skill dispatcher—this protocol transforms OmniRoute nodes into interoperable, autonomous services that any compliant agent can interact with programmatically.

Core Architecture of A2A v0.3

The protocol implementation in OmniRoute centers on three architectural layers:

Component Role Source Location
JSON-RPC 2.0 endpoint Canonical entry point (POST /a2a) for all A2A methods src/app/a2a/route.ts
Task manager Tracks task lifecycle (submitted → working → completed/failed/cancelled) with UUID assignment and 5-minute TTL src/lib/a2a/taskManager.ts
Skill dispatcher Maps skill names to concrete handlers via A2A_SKILL_HANDLERS registry src/lib/a2a/taskExecution.ts

Supported JSON-RPC Methods

The endpoint in src/app/a2a/route.ts exposes four primary methods:

  • message/send — Synchronous request-response for single-shot tasks
  • message/stream — Initiates Server-Sent Events (SSE) for incremental results
  • tasks/get — Retrieves current state and artifacts for an existing task
  • tasks/cancel — Aborts an in-progress task and updates state to cancelled

Agent Discovery via the Agent Card

Before invoking capabilities, agents must discover what a node offers. OmniRoute exposes this through the Agent Card at /.well-known/agent.json.

This JSON document contains:

  • Node name and version derived from package.json
  • Complete catalog of available A2A skills
  • Authentication requirements
  • Endpoint URLs

The card is cached for one hour and generated dynamically in src/app/.well-known/agent.json/route.ts, ensuring discovery information stays current with deployed capabilities.

Request Processing Flow

Every A2A v0.3 request traverses seven validation and execution stages:

  1. Authentication check — The authenticate function validates Authorization: Bearer <token> headers against OMNIROUTE_API_KEY when configured
  2. Enabled toggle verificationrejectIfA2ADisabled returns error code -32000 if a2aEnabled is false in settings
  3. JSON-RPC parsing — Strict validation of "jsonrpc": "2.0" and supported methods; malformed requests trigger standard codes (-32700, -32600, -32601, -32602)
  4. Task creationtaskManager.createTask instantiates an A2ATask with UUID, skill selection, message array, and metadata
  5. Skill execution — The appropriate handler from A2A_SKILL_HANDLERS receives the full task object
  6. State transitions — Manager updates status through working to terminal states (completed, failed, or cancelled)
  7. Response formatting — Single JSON-RPC response for message/send, or SSE stream via createA2AStream for message/stream

This flow is fully documented in docs/frameworks/A2A-SERVER.md, which serves as the authoritative reference for method signatures and error handling.

Built-in A2A Skills in OmniRoute

Skills are the executable capabilities exposed through the A2A v0.3 protocol. OmniRoute ships with six default skills in src/lib/a2a/skills/:

Skill File Purpose
Smart Routing smartRouting.ts Selects optimal provider/combo based on prompt characteristics and constraints
Quota Management quotaManagement.ts Reports per-provider quota usage and limits
Provider Discovery providerDiscovery.ts Enumerates installed providers with their capabilities
Cost Analysis costAnalysis.ts Estimates monetary cost for requests or full conversations
Health Report healthReport.ts Summarizes circuit-breaker status and provider health metrics
List Capabilities listCapabilities.ts Returns the complete skills catalog for dynamic discovery

New skills are added by creating a TypeScript module under src/lib/a2a/skills/ and registering the handler in A2A_SKILL_HANDLERS within src/lib/a2a/taskExecution.ts.

Streaming with Server-Sent Events

The A2A v0.3 protocol supports real-time result delivery through message/stream. When invoked, OmniRoute:

  • Opens an SSE connection with headers defined in SSE_HEADERS (from src/lib/a2a/streaming.ts)
  • Pushes incremental artifacts as chunks become available
  • Transmits final metadata upon completion
  • Ensures the calling agent receives partial results without blocking on full operation completion

This streaming mechanism is essential for long-running operations like large language model generation, where intermediate tokens provide value before final aggregation.

Practical Code Examples

Synchronous Skill Invocation

curl -X POST http://localhost:20128/a2a \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_KEY" \
  -d '{
    "jsonrpc": "2.0",
    "id": "1",
    "method": "message/send",
    "params": {
      "skill": "smart-routing",
      "messages": [{"role": "user", "content": "Write a hello world program in Python"}],
      "metadata": {"model": "auto", "combo": "fast-coding"}
    }
  }'

This pattern from docs/frameworks/A2A-SERVER.md (lines 55-68) demonstrates the canonical request structure: JSON-RPC envelope with skill selection, message history, and execution metadata.

Streaming Response Consumption

import fetch from "node-fetch";

const resp = await fetch("http://localhost:20128/a2a", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: "Bearer YOUR_KEY",
  },
  body: JSON.stringify({
    jsonrpc: "2.0",
    id: "stream-1",
    method: "message/stream",
    params: {
      skill: "smart-routing",
      messages: [{ role: "user", content: "Explain quantum computing in simple terms" }],
    },
  }),
});

for await (const line of resp.body) {
  console.log(line.toString());
}

The streaming implementation in src/lib/a2a/streaming.ts handles chunked encoding and connection lifecycle management automatically.

Task Status Querying

curl -X POST http://localhost:20128/a2a \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_KEY" \
  -d '{"jsonrpc":"2.0","id":"2","method":"tasks/get","params":{"taskId":"<TASK_UUID>"}}'

The tasks/get method, implemented around lines 90-110 of src/app/a2a/route.ts, returns full task state including current status, accumulated artifacts, and execution metadata.

Capability Discovery

curl http://localhost:20128/a2a \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_KEY" \
  -d '{"jsonrpc":"2.0","id":"cap","method":"list-capabilities","params":{}}'

This invocation of the list-capabilities skill, defined in src/lib/a2a/skills/listCapabilities.ts, enables dynamic capability negotiation between agents without hardcoded assumptions.

Observability and Monitoring

The A2A v0.3 protocol implementation includes built-in telemetry:

  • logRoutingDecision (src/lib/a2a/routingLogger.ts) records every smart-routing choice with context for audit and optimization
  • getStats on the task manager exposes counters per state, total task volume, and active stream count

These mechanisms enable operators to monitor A2A traffic, detect bottlenecks, and analyze skill utilization patterns across their OmniRoute deployment.

Summary

  • A2A v0.3 in OmniRoute is a JSON-RPC 2.0 protocol enabling standardized agent-to-agent communication through POST /a2a
  • Three core components—endpoint router, task manager, and skill dispatcher—provide complete request lifecycle management
  • Discovery happens via /.well-known/agent.json, returning node capabilities and authentication requirements
  • Six built-in skills cover routing, quotas, providers, costs, health, and capability enumeration
  • Streaming support via SSE allows real-time result delivery for long-running operations
  • Extensibility through the A2A_SKILL_HANDLERS registry enables custom business logic without protocol modification

Frequently Asked Questions

How does A2A v0.3 authentication work in OmniRoute?

Authentication is optional and environment-driven. When OMNIROUTE_API_KEY is configured, the authenticate function in src/app/a2a/route.ts requires matching Authorization: Bearer headers; otherwise, the endpoint operates unauthenticated. This design supports both open development environments and production deployments requiring credential validation.

What is the default task timeout in A2A v0.3?

Tasks receive a 5-minute TTL (time-to-live) by default, enforced by the task manager in src/lib/a2a/taskManager.ts. After expiration, tasks transition to a terminal failure state and are eligible for cleanup. This prevents resource accumulation from abandoned or hung operations.

Can I add custom skills to the A2A v0.3 protocol implementation?

Yes. Create a TypeScript module under src/lib/a2a/skills/ implementing the skill handler interface, then register it in A2A_SKILL_HANDLERS within src/lib/a2a/taskExecution.ts. The skill becomes immediately available through message/send and message/stream invocations with your chosen identifier.

How does streaming differ from synchronous calls in A2A v0.3?

Synchronous calls (message/send) block until completion and return a single JSON-RPC response containing all artifacts. Streaming calls (message/stream) return immediately with SSE headers, then push incremental chunks through an open connection as the skill produces output. Streaming is implemented in src/lib/a2a/streaming.ts and is essential for responsive user experiences with generation-heavy skills.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →