# How the A2A Agent Protocol Works in OmniRoute: JSON-RPC Skills Architecture

> Explore how OmniRoute's A2A Agent Protocol uses JSON-RPC to let external agents invoke internal routing skills, enabling real-time task execution with synchronous responses and SSE streaming.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: architecture
- Published: 2026-08-27

---

**OmniRoute's A2A Agent Protocol enables external agents to invoke internal routing skills via JSON-RPC 2.0, supporting both synchronous responses and streaming Server-Sent Events for real-time task execution.**

The **A2A Agent Protocol** implementation in the `diegosouzapw/OmniRoute` repository provides a structured interface for agent-to-agent communication, exposing modular capabilities like smart routing and quota management through standardized endpoints. This protocol architecture separates concerns between task management, skill execution, and streaming delivery, allowing autonomous systems to programmatically access OmniRoute's AI gateway functionality with full observability.

## Core Architecture and Protocol Flow

The A2A implementation follows a layered architecture that processes JSON-RPC requests through dedicated TypeScript modules:

| Layer | File Path | Responsibility |
|-------|-----------|----------------|
| **Entry Point** | [`src/app/a2a/route.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/a2a/route.ts) | Exposes `POST /a2a` JSON-RPC endpoint and handles request routing |
| **Task Manager** | [`src/lib/a2a/taskManager.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/a2a/taskManager.ts) | Creates `A2ATask` objects with UUID assignment and TTL-based eviction (default 5 minutes) |
| **Execution Engine** | [`src/lib/a2a/taskExecution.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/a2a/taskExecution.ts) | Maintains `A2A_SKILL_HANDLERS` map to dispatch tasks to appropriate skill implementations |
| **Skill Modules** | `src/lib/a2a/skills/*.ts` | Individual skill implementations (e.g., [`smartRouting.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/smartRouting.ts), [`quotaManagement.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/quotaManagement.ts)) returning artifacts and metadata |
| **Streaming Layer** | [`src/lib/a2a/streaming.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/a2a/streaming.ts) | Wraps execution in Server-Sent Events for `message/stream` method delivery |
| **Discovery** | [`src/app/.well-known/agent.json/route.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/.well-known/agent.json/route.ts) | Serves Agent Card describing available skills for remote agent discovery |
| **Observability** | [`src/lib/a2a/routingLogger.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/a2a/routingLogger.ts) | Logs state transitions and resilience layer activity during task lifecycle |

### Request Processing Pipeline

1. **Authentication**: Requests to `POST /a2a` require an `Authorization: Bearer <API_KEY>` header unless authentication is explicitly disabled in configuration.

2. **Task Creation**: The `A2ATaskManager` instantiates a task record with unique UUID, storing execution state, artifacts, and metadata in memory with configurable TTL eviction.

3. **Skill Dispatch**: [`taskExecution.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/taskExecution.ts) resolves the JSON-RPC `method` against `A2A_SKILL_HANDLERS` to select the appropriate skill module.

4. **Execution**: Skills invoke OmniRoute's internal pipelines (e.g., combo routing) and return structured results containing artifacts and rich metadata.

5. **Response Delivery**: Synchronous methods return complete JSON-RPC responses, while streaming methods emit incremental SSE chunks until task completion.

## Protocol Authentication and Endpoint Structure

All A2A interactions require Bearer token authentication passed via the `Authorization` header. The primary JSON-RPC endpoint resides at `POST /a2a`, with auxiliary REST endpoints available under `/api/a2a/*` for dashboard and management tooling.

The protocol supports three primary interaction patterns:
- **Synchronous execution** via `message/send` for complete responses
- **Streaming execution** via `message/stream` for real-time chunk delivery
- **Task management** via `tasks/get` and `tasks/cancel` for lifecycle operations

## Synchronous Skill Invocation with message/send

The `message/send` method executes skills and returns complete results in a single JSON-RPC response. This method is ideal for routing requests that require immediate, structured output including cost envelopes and routing explanations.

```bash
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 in Python"}],
          "metadata":{"model":"auto","combo":"fast-coding"}
        }
      }'

```

The response includes the task state, generated artifacts, and detailed metadata:

```json
{
  "jsonrpc":"2.0",
  "id":"1",
  "result":{
    "task":{"id":"c1e7…","state":"completed"},
    "artifacts":[{"type":"text","content":"print('Hello, world!')"}],
    "metadata":{
      "routing_explanation":"Selected claude-sonnet via provider \"anthropic\" (latency: 1200ms, cost: $0.003)",
      "cost_envelope":{"estimated":0.005,"actual":0.003,"currency":"USD"}
    }
  }
}

```

## Real-Time Streaming with message/stream

For long-running generation tasks, the `message/stream` method delivers incremental output via Server-Sent Events. The [`streaming.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/streaming.ts) module manages SSE connections, emitting chunked data while the skill executes against OmniRoute's routing pipeline.

```bash
curl -N -X POST http://localhost:20128/a2a \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_KEY" \
  -d '{
        "jsonrpc":"2.0",
        "id":"2",
        "method":"message/stream",
        "params":{
          "skill":"smart-routing",
          "messages":[{"role":"user","content":"Explain quantum computing"}]
        }
      }'

```

Stream events follow this structure:

```

data: {"jsonrpc":"2.0","method":"message/stream","params":{"task":{"id":"…","state":"working"},"chunk":{"type":"text","content":"Quantum computing…"}}}
: heartbeat 2026-03-03T17:00:00Z
data: {"jsonrpc":"2.0","method":"message/stream","params":{"task":{"id":"…","state":"completed"},"metadata":{…}}}

```

## Task Lifecycle Management

Individual tasks persist for a configurable TTL (defaulting to 5 minutes) within the `A2ATaskManager`. External agents can query task status or cancel pending operations using dedicated JSON-RPC methods.

### Retrieving Task Status

```bash
curl -X POST http://localhost:20128/a2a \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_KEY" \
  -d '{"jsonrpc":"2.0","id":"3","method":"tasks/get","params":{"taskId":"c1e7…"}}'

```

### Canceling Active Tasks

```bash
curl -X POST http://localhost:20128/a2a \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_KEY" \
  -d '{"jsonrpc":"2.0","id":"4","method":"tasks/cancel","params":{"taskId":"c1e7…"}}'

```

## Skill Implementation and Metadata Architecture

Skills reside in `src/lib/a2a/skills/*.ts` as async functions receiving an `A2ATask` object and returning structured results. Each skill implementation follows a consistent contract:

- **Input**: Task parameters including conversation messages and routing metadata
- **Processing**: Direct invocation of OmniRoute's internal engines (e.g., combo routing via [`smartRouting.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/smartRouting.ts))
- **Output**: Object containing `artifacts` (generated content) and `metadata` (routing explanations, cost envelopes, policy verdicts, resilience traces)

The `A2A_SKILL_HANDLERS` map in [`taskExecution.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/taskExecution.ts) provides the routing layer between JSON-RPC method names and their corresponding skill implementations.

## Agent Discovery and Capabilities

The Agent Card endpoint at [`src/app/.well-known/agent.json/route.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/.well-known/agent.json/route.ts) publishes machine-readable skill descriptions, enabling autonomous discovery by remote agents. This discovery mechanism allows external systems to query available capabilities—including supported models, routing policies, and quota constraints—before initiating task execution.

## Summary

- **OmniRoute's A2A Agent Protocol** implements JSON-RPC 2.0 standards with Bearer token authentication to expose internal routing capabilities as discrete skills.
- **Task management** in [`src/lib/a2a/taskManager.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/a2a/taskManager.ts) maintains stateful execution contexts with 5-minute TTL eviction and UUID-based tracking.
- **Skill dispatch** occurs through the `A2A_SKILL_HANDLERS` registry in [`taskExecution.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/taskExecution.ts), routing requests to modular implementations in `src/lib/a2a/skills/*.ts`.
- **Streaming support** via `message/stream` delivers real-time chunks using Server-Sent Events managed by [`src/lib/a2a/streaming.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/a2a/streaming.ts).
- **Full observability** is provided through [`src/lib/a2a/routingLogger.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/a2a/routingLogger.ts), capturing resilience layer interactions including circuit breakers and provider cooldowns.

## Frequently Asked Questions

### What authentication method does the OmniRoute A2A protocol require?

The protocol requires Bearer token authentication via the `Authorization` header on all requests to `POST /a2a`. If the server configuration explicitly disables API key requirements, authentication is bypassed, though this is not recommended for production deployments.

### How long do tasks persist in the A2A system?

Tasks remain in memory for a configurable TTL period defaulting to 5 minutes, after which the `A2ATaskManager` automatically evicts them. During this window, clients can query task status using `tasks/get` or cancel operations using `tasks/cancel`.

### What is the difference between message/send and message/stream methods?

The `message/send` method returns complete skill execution results in a single JSON-RPC response, suitable for short operations requiring immediate structured data. The `message/stream` method establishes a Server-Sent Events connection that emits incremental content chunks during generation, ideal for long-form text production where real-time feedback is required.

### Where are skill implementations located in the OmniRoute codebase?

Skill implementations reside in the `src/lib/a2a/skills/` directory, with individual modules like [`smartRouting.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/smartRouting.ts) and [`quotaManagement.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/quotaManagement.ts) exporting async functions that process `A2ATask` objects. These are registered in the `A2A_SKILL_HANDLERS` map within [`src/lib/a2a/taskExecution.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/a2a/taskExecution.ts) for JSON-RPC method resolution.