A2AClient, useA2ARuntime options, hooks, task states, artifacts, errors.
Deep dive on the runtime's API surface. Start with overview and quickstart if you have not already.
A2AClient
The built-in A2AClient handles all communication with the A2A server: JSON serialization, SSE streaming, ProtoJSON enum normalization, and structured error handling.
import { A2AClient } from "@assistant-ui/react-a2a";
const client = new A2AClient({
baseUrl: "https://my-agent.example.com",
headers: { Authorization: "Bearer <token>" },
tenant: "my-org",
extensions: ["urn:a2a:ext:my-extension"],
});Pass a pre-built client to useA2ARuntime:
const runtime = useA2ARuntime({ client });Client options
| Option | Type | Description |
|---|---|---|
baseUrl | string | Base URL of the A2A server. |
basePath | string | Optional path prefix for API endpoints (e.g. "/v1"). Does not affect agent card discovery. |
headers | Record<string, string> or () => Record<string, string> | 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
| 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
Pass either a pre-built client or a baseUrl (the runtime creates a client for you). Other options layer on top.
| Option | Type | Description |
|---|---|---|
client | A2AClient | Pre-built A2A client instance (provide this OR baseUrl). |
baseUrl | string | A2A server URL (creates a client automatically). |
basePath | string | Path prefix for API endpoints. Only used with baseUrl. |
tenant | string | Tenant ID for multi-tenant servers. Only used with baseUrl. |
headers | Record<string, string> or () => Record<string, string> | Headers for the auto-created client. |
extensions | string[] | Extension URIs to negotiate. Only used with baseUrl. |
contextId | string | Initial context ID for the conversation. |
configuration | A2ASendMessageConfiguration | Default send message configuration. |
onError | (error: Error) => void | Error callback. |
onCancel | () => void | Cancellation callback. |
onArtifactComplete | (artifact: A2AArtifact) => void | Fired when an incremental artifact finishes. |
adapters.attachments | AttachmentAdapter | Custom attachment handling. See adapters. |
adapters.speech | SpeechSynthesisAdapter | Text-to-speech. See adapters. |
adapters.feedback | FeedbackAdapter | Feedback collection. See adapters. |
adapters.history | ThreadHistoryAdapter | Message persistence. See adapters. |
adapters.threadList | UseA2AThreadListAdapter | Thread switching. See threads. |
Hooks
Task state
useA2ATask returns the current A2A task object, including task state and status message.
import { useA2ATask } from "@assistant-ui/react-a2a";
function TaskStatus() {
const task = useA2ATask();
if (!task) return null;
return (
<div>
Task {task.id}: {task.status.state}
</div>
);
}Artifacts list
useA2AArtifacts returns the artifacts generated by the current task.
import { useA2AArtifacts } from "@assistant-ui/react-a2a";
function ArtifactList() {
const artifacts = useA2AArtifacts();
return (
<ul>
{artifacts.map((artifact) => (
<li key={artifact.artifactId}>
{artifact.name}: {artifact.parts.length} parts
</li>
))}
</ul>
);
}Agent card
useA2AAgentCard returns the agent card fetched from the server on initialization.
import { useA2AAgentCard } from "@assistant-ui/react-a2a";
function AgentInfo() {
const card = useA2AAgentCard();
if (!card) return null;
return (
<div>
<h3>{card.name}</h3>
<p>{card.description}</p>
<div>Skills: {card.skills.map((s) => s.name).join(", ")}</div>
</div>
);
}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 or 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 sends the next message with the same taskId to resume the task.
Artifacts
A2A agents can produce artifacts (files, code, data) alongside their responses. Artifacts are accumulated during streaming and accessible via useA2AArtifacts.
The runtime supports:
- Incremental artifact streaming via
appendmode. - Artifact completion notification via the
onArtifactCompletecallback. - Automatic reset of artifacts on each new run.
const runtime = useA2ARuntime({
baseUrl: "http://localhost:9999",
onArtifactComplete: (artifact) => {
console.log("Artifact ready:", artifact.name);
},
});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 the field is unset), the runtime usesPOST /message:streamwith SSE. - If
capabilities.streaming: false, the runtime falls back toPOST /message:send.
Error handling
The client throws A2AError instances with structured error information following the google.rpc.Status format:
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
For multi-tenant A2A servers, pass a tenant option:
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).
Feature support
| 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 | Via history adapter |
| Thread list management | Via thread list adapter |