# A2A Protocol URL: /docs/runtimes/a2a Connect to A2A (Agent-to-Agent) v1.0 protocol servers. `@assistant-ui/react-a2a` provides a runtime adapter for the [A2A (Agent-to-Agent) v1.0 protocol](https://github.com/a2aproject/A2A), enabling your assistant-ui frontend to communicate with any A2A-compliant agent server. Requirements \[#requirements] * An A2A v1.0 compatible agent server * React 18 or 19 Installation \[#installation] Getting Started \[#getting-started] Set up the Runtime Provider \[#set-up-the-runtime-provider] Create a runtime provider component that connects to your A2A server. ```tsx title="app/MyRuntimeProvider.tsx" "use client"; import { AssistantRuntimeProvider } from "@assistant-ui/react"; import { useA2ARuntime } from "@assistant-ui/react-a2a"; export function MyRuntimeProvider({ children, }: { children: React.ReactNode; }) { const runtime = useA2ARuntime({ baseUrl: "http://localhost:9999", }); return ( {children} ); } ``` Add the Thread component \[#add-the-thread-component] ```tsx title="app/page.tsx" import { Thread } from "@assistant-ui/react"; import { MyRuntimeProvider } from "./MyRuntimeProvider"; export default function Page() { return ( ); } ``` Setup UI Components \[#setup-ui-components] Follow the [UI Setup](/docs/ui) guide to setup the UI components. A2AClient \[#a2aclient] The built-in `A2AClient` handles all communication with the A2A server, including JSON serialization, SSE streaming, ProtoJSON enum normalization, and structured error handling. ```ts import { A2AClient } from "@assistant-ui/react-a2a"; const client = new A2AClient({ baseUrl: "https://my-agent.example.com", headers: { Authorization: "Bearer " }, tenant: "my-org", // optional, for multi-tenant servers extensions: ["urn:a2a:ext:my-extension"], // optional }); ``` You can pass a pre-built client to `useA2ARuntime`: ```tsx const runtime = useA2ARuntime({ client }); ``` Client Options \[#client-options] | Option | Type | Description | | ------------ | ---------------------------------------------------------- | ----------------------------------------------------------- | | `baseUrl` | `string` | Base URL of the A2A server | | `headers` | `Record` or `() => Record` | Static or dynamic headers (e.g. for auth tokens) | | `tenant` | `string` | Tenant ID for multi-tenant servers (prepended to URL paths) | | `extensions` | `string[]` | Extension URIs to negotiate via `A2A-Extensions` header | Client Methods \[#client-methods] | Method | Description | | ---------------------------------------------------- | -------------------------------------------------------- | | `sendMessage(message, configuration?, metadata?)` | Send a message (non-streaming) | | `streamMessage(message, configuration?, metadata?)` | Send a message with SSE streaming | | `getTask(taskId, historyLength?)` | Get a task by ID | | `listTasks(request?)` | List tasks with filtering and pagination | | `cancelTask(taskId, metadata?)` | Cancel an in-progress task | | `subscribeToTask(taskId)` | Subscribe to SSE updates for a task | | `getAgentCard()` | Fetch the agent card from `/.well-known/agent-card.json` | | `getExtendedAgentCard()` | Fetch the extended (authenticated) agent card | | `createTaskPushNotificationConfig(config)` | Create a push notification config | | `getTaskPushNotificationConfig(taskId, configId)` | Get a push notification config | | `listTaskPushNotificationConfigs(taskId)` | List push notification configs | | `deleteTaskPushNotificationConfig(taskId, configId)` | Delete a push notification config | useA2ARuntime Options \[#usea2aruntime-options] | Option | Type | Description | | ---------------------- | ----------------------------- | --------------------------------------------------------- | | `client` | `A2AClient` | Pre-built A2A client instance (provide this OR `baseUrl`) | | `baseUrl` | `string` | A2A server URL (creates a client automatically) | | `headers` | see above | Headers for the auto-created client | | `contextId` | `string` | Initial context ID for the conversation | | `configuration` | `A2ASendMessageConfiguration` | Default send message configuration | | `onError` | `(error: Error) => void` | Error callback | | `onCancel` | `() => void` | Cancellation callback | | `adapters.attachments` | `AttachmentAdapter` | Custom attachment handling | | `adapters.speech` | `SpeechSynthesisAdapter` | Text-to-speech | | `adapters.feedback` | `FeedbackAdapter` | Feedback collection | | `adapters.history` | `ThreadHistoryAdapter` | Message persistence | | `adapters.threadList` | `UseA2AThreadListAdapter` | Thread switching | Hooks \[#hooks] useA2ATask \[#usea2atask] Returns the current A2A task object, including task state and status message. ```tsx import { useA2ATask } from "@assistant-ui/react-a2a"; function TaskStatus() { const task = useA2ATask(); if (!task) return null; return
Task {task.id}: {task.status.state}
; } ``` useA2AArtifacts \[#usea2aartifacts] Returns the artifacts generated by the current task. ```tsx import { useA2AArtifacts } from "@assistant-ui/react-a2a"; function ArtifactList() { const artifacts = useA2AArtifacts(); return (
    {artifacts.map((artifact) => (
  • {artifact.name}: {artifact.parts.length} parts
  • ))}
); } ``` useA2AAgentCard \[#usea2aagentcard] Returns the agent card fetched from the server on initialization. ```tsx import { useA2AAgentCard } from "@assistant-ui/react-a2a"; function AgentInfo() { const card = useA2AAgentCard(); if (!card) return null; return (

{card.name}

{card.description}

Skills: {card.skills.map((s) => s.name).join(", ")}
); } ``` Task States \[#task-states] The A2A protocol defines 9 task states. The runtime maps them to assistant-ui message statuses: | A2A Task State | Description | Message Status | | ---------------- | ---------------------- | ------------------------ | | `unspecified` | Unknown/default state | `running` | | `submitted` | Task acknowledged | `running` | | `working` | Task in progress | `running` | | `completed` | Task finished | `complete` | | `failed` | Task errored | `incomplete (error)` | | `canceled` | Task cancelled | `incomplete (cancelled)` | | `rejected` | Agent declined task | `incomplete (error)` | | `input_required` | Agent needs user input | `requires-action` | | `auth_required` | Authentication needed | `requires-action` | When a task enters `input_required`, the user can continue the conversation normally. The runtime will send the next message with the same `taskId` to resume the task. Artifacts \[#artifacts] A2A agents can produce artifacts (files, code, data) alongside their responses. Artifacts are accumulated during streaming and accessible via the `useA2AArtifacts` hook. The runtime supports: * **Incremental artifact streaming** via `append` mode * **Artifact completion notification** via `onArtifactComplete` callback * **Automatic reset** of artifacts on each new run ```tsx const runtime = useA2ARuntime({ baseUrl: "http://localhost:9999", onArtifactComplete: (artifact) => { console.log("Artifact ready:", artifact.name); }, }); ``` Streaming vs Non-Streaming \[#streaming-vs-non-streaming] The runtime automatically selects the communication mode based on the agent's capabilities: * If the agent card indicates `capabilities.streaming: true` (or unset), the runtime uses `POST /message:stream` with SSE * If `capabilities.streaming: false`, the runtime falls back to `POST /message:send` Error Handling \[#error-handling] The client throws `A2AError` instances with structured error information following the `google.rpc.Status` format: ```tsx import { A2AError } from "@assistant-ui/react-a2a"; const runtime = useA2ARuntime({ baseUrl: "http://localhost:9999", onError: (error) => { if (error instanceof A2AError) { console.log(error.code); // HTTP status code console.log(error.status); // e.g. "NOT_FOUND" console.log(error.details); // google.rpc.ErrorInfo details } }, }); ``` Multi-Tenancy \[#multi-tenancy] For multi-tenant A2A servers, pass a `tenant` option to the client: ```ts const client = new A2AClient({ baseUrl: "https://agent.example.com", tenant: "my-org", }); ``` This prepends `/{tenant}` to all API paths (e.g. `/my-org/message:send`). Features \[#features] | Feature | Supported | | ---------------------------- | --------- | | Streaming (SSE) | Yes | | Non-streaming fallback | Yes | | All 9 task states | Yes | | Artifacts (text, data, file) | Yes | | Agent card discovery | Yes | | Multi-tenancy | Yes | | Structured errors | Yes | | Push notifications CRUD | Yes | | Extension negotiation | Yes | | Task cancellation | Yes | | Message editing | Yes | | Message reload | Yes | | History persistence | Yes | | Thread list management | Yes |