Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 97 additions & 4 deletions docs/a2a.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ You can add A2A-compatible agents through the LiteLLM Admin UI.
1. Navigate to the **Agents** tab
2. Click **Add Agent**
3. Enter the agent name (e.g., `ij-local`) and the URL of your A2A agent
4. Choose a **Protocol Version** (`1.0` or `0.3`) - the wire format LiteLLM serves to clients for this agent

<Image
img={require('../img/add_agent_1.png')}
Expand All @@ -46,6 +47,17 @@ You can add A2A-compatible agents through the LiteLLM Admin UI.

The URL should be the invocation URL for your A2A agent (e.g., `http://localhost:10001`).

Set `protocolVersion` in `agent_card_params` when registering via API or config:

```yaml title="config.yaml"
agents:
- agent_name: my-agent
agent_card_params:
name: "My Agent"
url: "http://localhost:10001"
protocolVersion: "1.0" # or "0.3"
```


### Add Azure AI Foundry Agents

Expand All @@ -67,6 +79,48 @@ Follow [this guide to register a LangGraph agent and configure its agent card](.

Follow [this guide, to add your pydantic ai agent to LiteLLM Agent Gateway](./providers/pydantic_ai_agent#litellm-a2a-gateway)


## Protocol versioning

LiteLLM proxy routes A2A agents using **a2a-sdk 1.x** and can serve either **A2A 0.3** or **1.0** wire format to clients per agent. Upstream agents may speak either version; LiteLLM normalizes `message/send`, `message/stream`, and extended-card responses to the version you pin.

| Version | Wire shape | Example send result |
|---------|------------|---------------------|
| **0.3** | Objects discriminated by `kind` (`message`, `task`, `status-update`, …) | `{"kind": "message", "role": "user", "parts": [{"kind": "text", "text": "..."}]}` |
| **1.0** | Protobuf JSON envelopes (`message`, `task`, `statusUpdate`, `artifactUpdate`) | `{"message": {"role": "ROLE_USER", "parts": [{"text": "..."}]}}` |

### Pinning a version

Set `agent_card_params.protocolVersion` to `"0.3"` or `"1.0"` when registering an agent (UI dropdown or API). LiteLLM serves that version on the proxied agent card and converts upstream responses to match.

Only `"0.3"` and `"1.0"` are accepted; other values return HTTP 400 at registration.

### When `protocolVersion` is not pinned

If an agent has no pinned version, LiteLLM infers the served version from the client request:

| Client signal | Served version |
|---------------|----------------|
| JSON-RPC method `SendMessage` or `SendStreamingMessage` | `1.0` |
| Request header `a2a-version: 1.x` | `1.0` |
| Otherwise (e.g. `message/send` with no header) | `0.3` |

:::tip Always pin `protocolVersion`

The proxied agent card defaults to `1.0` when unset, but legacy `message/send` callers without an `a2a-version` header receive **0.3**-shaped responses. Pin `protocolVersion` explicitly so your card and responses always match.

:::

Task methods (`tasks/get`, `tasks/list`, …) are forwarded to the upstream agent unchanged. Version conversion applies to LiteLLM-integrated messaging paths only.

### Dependency

LiteLLM proxy A2A routes require **a2a-sdk >= 1.1.0** (included in the `proxy` / `proxy-dev` dependency groups). If you call agents from your own code, install the matching SDK version:

```bash
pip install "a2a-sdk>=1.1.0,<2.0"
```

## Invoking your Agents

See the [Invoking A2A Agents](./a2a_invoking_agents) guide to learn how to call your agents using:
Expand Down Expand Up @@ -233,7 +287,6 @@ Send any of these in the `method` field of `POST /a2a/{agent_id}`:
| `tasks/pushNotificationConfig/delete` | Delete push config |
| `agent/getAuthenticatedExtendedCard` | Extended agent card |

PascalCase SDK names (`GetTask`, `ListTasks`, …) are normalized to the slash form automatically.

**Routing:** `message/send` and `message/stream` go through LiteLLM's A2A client (logging, guardrails, spend). All other methods are forwarded to the upstream URL in `agent_card_params.url`. Task APIs require that URL; completion-bridge-only agents support messaging methods only.

Expand Down Expand Up @@ -283,9 +336,12 @@ The caller's **virtual key** and **end-user ID** are not automatically forwarded

### Request Format

LiteLLM follows the [A2A JSON-RPC 2.0 specification](https://github.com/google/A2A):
LiteLLM follows the [A2A JSON-RPC 2.0 specification](https://github.com/google/A2A). The message body shape depends on the agent's pinned `protocolVersion` (or the client signals above when unpinned).

```json title="Request Body"
<Tabs>
<TabItem value="v03" label="0.3 wire format" default>

```json title="Request Body (0.3)"
{
"jsonrpc": "2.0",
"id": "unique-request-id",
Expand All @@ -300,9 +356,24 @@ LiteLLM follows the [A2A JSON-RPC 2.0 specification](https://github.com/google/A
}
```

</TabItem>
<TabItem value="v10" label="1.0 wire format">

Use the [a2a-sdk 1.x client](./a2a_invoking_agents#a2a-sdk) (recommended) or send JSON-RPC with PascalCase methods / an `a2a-version: 1.0` header when the agent is pinned to `1.0`.

```json title="Request Body (1.0 SDK — protobuf types)"
// Build with a2a.types.Message, Part, Role, then wrap in SendMessageRequest
```

</TabItem>
</Tabs>

### Response Format

```json title="Response"
<Tabs>
<TabItem value="resp03" label="0.3 response" default>

```json title="Response (0.3 task result)"
{
"jsonrpc": "2.0",
"id": "unique-request-id",
Expand All @@ -322,6 +393,28 @@ LiteLLM follows the [A2A JSON-RPC 2.0 specification](https://github.com/google/A
}
```

</TabItem>
<TabItem value="resp10" label="1.0 response">

```json title="Response (1.0 message envelope)"
{
"jsonrpc": "2.0",
"id": "unique-request-id",
"result": {
"message": {
"role": "ROLE_AGENT",
"messageId": "msg-abc",
"parts": [{"text": "Agent response here"}]
}
}
}
```

Streaming events use `statusUpdate` / `artifactUpdate` keys instead of `kind: "status-update"`.

</TabItem>
</Tabs>

Agent JSON-RPC errors are returned in the `error` field with the same `id` as the request when possible. Poll long-running work with `tasks/get` after `message/send` returns a `submitted` task.

### Example: `tasks/get`
Expand Down
23 changes: 21 additions & 2 deletions docs/a2a_agent_card.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ The fields below mirror the A2A v1.0 specification ([§4.4 Agent Discovery Objec

| Field | Supported |
|---|---|
| `protocolVersion` | ✅ |
| `name` | ✅ |
| `description` | ✅ |
| `supportedInterfaces` | ✅ |
Expand Down Expand Up @@ -92,7 +93,7 @@ When you register an A2A agent in LiteLLM:

1. You provide a base URL (and, for some providers, an assistant identifier).
2. LiteLLM fetches the upstream agent card from the agent's `/.well-known/agent-card.json` (or the provider-specific equivalent).
3. You review the parsed card in the LiteLLM UI and choose which skills and fields to expose.
3. You review the parsed card in the LiteLLM UI, choose which skills and fields to expose, and pick a **Protocol Version** (`1.0` or `0.3`) for clients.
4. LiteLLM saves the curated card and serves it at:

```
Expand All @@ -107,6 +108,22 @@ When you register an A2A agent in LiteLLM:

using A2A JSON-RPC 2.0 (see [Supported A2A methods](#supported-a2a-methods) below).


## Protocol versioning

LiteLLM converts upstream agent responses to the `protocolVersion` pinned on each agent. Clients always see the version you choose, regardless of what the upstream agent speaks natively.

| `protocolVersion` | Served to clients |
|-------------------|-------------------|
| `"1.0"` (default on new cards) | Protobuf JSON envelopes — `result.message`, stream `statusUpdate` / `artifactUpdate` |
| `"0.3"` | Legacy `kind`-discriminated JSON — `result.kind == "message"` |

Set this in the agent card UI or in `agent_card_params` at registration. Unsupported values are rejected with HTTP 400.

Completion-bridge agents (LangGraph, Bedrock AgentCore, etc.) do not need extra provider config — pin `protocolVersion` only if your client expects a specific wire format.

See [Protocol versioning](./a2a#protocol-versioning) for client negotiation when `protocolVersion` is not pinned.

## Supported A2A methods

All methods below are accepted on `POST /a2a/{agent_id}` (and `POST /a2a/{agent_id}/message/send` for `message/send`). LiteLLM also accepts the PascalCase aliases from the A2A SDK (for example `GetTask` → `tasks/get`).
Expand All @@ -129,6 +146,8 @@ All methods below are accepted on `POST /a2a/{agent_id}` (and `POST /a2a/{agent_

| SDK / alias name | Wire method |
|---|---|
| `SendMessage` | `message/send` |
| `SendStreamingMessage` | `message/stream` |
| `GetTask` | `tasks/get` |
| `ListTasks` | `tasks/list` |
| `CancelTask` | `tasks/cancel` |
Expand All @@ -147,7 +166,7 @@ All methods below are accepted on `POST /a2a/{agent_id}` (and `POST /a2a/{agent_

### Example: two-step task flow

```bash title="1. Send a message"
```bash title="1. Send a message (0.3 wire format — pin protocolVersion: 0.3)"
curl -X POST "http://localhost:4000/a2a/my-agent" \
-H "Authorization: Bearer sk-1234" \
-H "Content-Type: application/json" \
Expand Down
Loading