Skip to content
New in v0.1.3

A2A Protocol Adapter

Connect to any agent implementing Google's Agent-to-Agent (A2A) protocol : a standard for agent interoperability using JSON-RPC 2.0 over HTTP.

Configuration

Ts
1const llmConfig: LocalLLMConfig = {
2  provider: "a2a",
3  baseUrl: "https://your-a2a-agent.example.com/a2a",
4  model: "mental-coach-agent",  // agent identifier: sent as metadata
5  apiKey: "bearer-token",        // optional
6  timeoutMs: 60_000,
7};

Key differences from other adapters

๐Ÿ”„

Stateful: server manages history

Unlike Ollama/OpenAI which receive the full message history on every turn, A2A agents track conversation state server-side via a contextId. The adapter only sends the latest user message each turn.

๐Ÿ’ฌ

No system prompt suffix needed

A2A agents are pre-configured on the server. Skip systemPromptSuffix when using this provider.

๐Ÿ“ฆ

Structured output via DataPart

A2A agents return wireai-rn JSON in a DataPart (data field). The adapter extracts DataPart first, then falls back to TextPart.

โณ

Async task polling

If the agent returns SUBMITTED or WORKING state, the adapter polls tasks/get every 1 second, up to 30 polls.

WireAIProvider setup for A2A

Tsx
1// Skip system prompt suffix for A2A: agent is pre-configured server-side
2const systemPromptSuffix = config.provider === "a2a" ? undefined : MY_APP_PROMPT;
3
4<WireAIProvider
5  key={`${config.provider}:${config.baseUrl}:${config.model}`}
6  llm={config}
7  components={components}
8  systemPromptSuffix={systemPromptSuffix}
9>
10  {children}
11</WireAIProvider>

Wire format

The adapter sends message/send JSON-RPC 2.0:

Request
1POST https://your-agent.com/a2a
2Content-Type: application/json
3
4{
5  "jsonrpc": "2.0",
6  "id": 1,
7  "method": "message/send",
8  "params": {
9    "message": {
10      "role": "user",
11      "parts": [{ "text": "Start my check-in" }]
12    },
13    "contextId": "ctx-abc123",
14    "metadata": { "model": "mental-coach-agent" }
15  }
16}
Response
1{
2  "jsonrpc": "2.0",
3  "id": 1,
4  "result": {
5    "id": "task-xyz",
6    "contextId": "ctx-abc123",
7    "status": { "state": "COMPLETED" },
8    "messages": [
9      {
10        "role": "agent",
11        "parts": [
12          {
13            "data": {
14              "action": "render",
15              "component": "SelectionCard",
16              "props": { "title": "How are you feeling?", "options": ["Great", "OK", "Stressed"] }
17            }
18          }
19        ]
20      }
21    ]
22  }
23}

Task lifecycle

StateBehavior
SUBMITTED / WORKINGAdapter polls tasks/get every 1s (max 30 polls)
COMPLETEDContent extracted from DataPart โ†’ TextPart โ†’ artifacts
INPUT_REQUIREDContent extracted and rendered (interactive component)
FAILED / CANCELED / REJECTEDThrows an error with the status message

Advertise your components to A2A agents

Use buildAgentCard() to tell your A2A agent server which components your mobile client can render:

Ts
1import { buildAgentCard, createComponentRegistry } from "wireai-rn";
2import { defaultComponents } from "wireai-rn/components";
3
4const registry = createComponentRegistry(defaultComponents);
5
6const card = buildAgentCard(registry, {
7  name: "My App Client",
8  url: "https://bff.myapp.com/a2a/client",
9  version: "1.0.0",
10});
11
12// Send this card to your agent server so it knows which components to use
13// POST https://your-agent.com/register-client
14await fetch("https://your-agent.com/register-client", {
15  method: "POST",
16  headers: { "Content-Type": "application/json" },
17  body: JSON.stringify(card),
18});

For a deep dive into the A2A protocol and the full buildAgentCard format, see the A2A Deep Dive page.