Client and hooks

A2AClient, useA2ARuntime options, hooks, task states, artifacts, errors.

Reference for the A2A client, the useA2ARuntime options, and the hooks. Start with overview and quickstart if you have not already.

A2AClient

A2AClient handles communication with the A2A server: JSON serialization, SSE streaming, ProtoJSON enum normalization, and structured errors.

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"],
  fetchOptions: { credentials: "include" },
});

Pass a pre-built client to useA2ARuntime, created once outside the component or in useState; the runtime keeps its session per client, so a client built inline on every render never settles:

const runtime = useA2ARuntime({ client });

Client options

OptionTypeDescription
baseUrlstringBase URL of the A2A server.
basePathstringOptional path prefix for API endpoints (e.g. "/v1"). Does not affect agent card discovery.
headersRecord<string, string>, or a sync or async function returning oneStatic or dynamic headers (e.g. for auth tokens).
tenantstringTenant ID for multi-tenant servers (prepended to URL paths).
extensionsstring[]Extension URIs to negotiate via A2A-Extensions header.
fetchOptionsRequestInit (partial)Extra fetch options applied to every request (e.g. { credentials: "include" }). headers, body, method, and signal are managed internally.

Client methods

MethodDescription
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, options?)List push notification configs. options takes pageSize and pageToken.
deleteTaskPushNotificationConfig(taskId, configId)Delete a push notification config.

useA2ARuntime options

Pass either a pre-built client or a baseUrl, from which the runtime creates a client. The hook throws when neither is set.

OptionTypeDescription
clientA2AClientPre-built A2A client instance (provide this OR baseUrl).
baseUrlstringA2A server URL (creates a client automatically).
basePathstringPath prefix for API endpoints. Only used with baseUrl.
tenantstringTenant ID for multi-tenant servers. Only used with baseUrl.
headersRecord<string, string>, or a sync or async function returning oneHeaders for the auto-created client.
extensionsstring[]Extension URIs to negotiate. Only used with baseUrl.
fetchOptionsRequestInit (partial)Extra fetch options for the auto-created client (e.g. { credentials: "include" }). headers, body, method, and signal are managed internally. Only used with baseUrl.
contextIdstringInitial context ID for the conversation.
configurationA2ASendMessageConfigurationDefault send message configuration.
onError(error: Error) => voidError callback.
onCancel() => voidCancellation callback.
onArtifactComplete(artifact: A2AArtifact) => voidFired when an incremental artifact finishes.
adapters.attachmentsAttachmentAdapterCustom attachment handling. See adapters.
adapters.speechSpeechSynthesisAdapterText-to-speech. See adapters.
adapters.dictationDictationAdapterSpeech-to-text input. See adapters.
adapters.voiceRealtimeVoiceAdapterRealtime voice session. See voice.
adapters.feedbackFeedbackAdapterFeedback collection. See adapters.
adapters.historyThreadHistoryAdapterMessage persistence. See adapters.
adapters.threadListUseA2AThreadListAdapterThread 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.

The assistant message also stores the merged artifact list at metadata.custom.a2a.artifacts, so a history adapter preserves it with the response rather than only in the current-task hook state. A2UI DataParts become replayable present tool-call artifacts on that same assistant message. See A2UI surfaces and stored conversations for the detection and history behavior.

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 stateDescriptionMessage status
unspecifiedUnknown or default state.running
submittedTask acknowledged.running
workingTask in progress.running
completedTask finished.complete
failedTask errored.incomplete (error)
canceledTask cancelled.incomplete (cancelled)
rejectedAgent declined task.incomplete (error)
input_requiredAgent needs user input.requires-action
auth_requiredAuthentication needed.requires-action

Info

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 handles artifacts as follows:

  • An artifact update with append set adds its parts to the artifact that has the same artifactId.
  • An update with lastChunk set fires the onArtifactComplete callback.
  • Each new run clears the artifact list.
const runtime = useA2ARuntime({
  baseUrl: "http://localhost:9999",
  onArtifactComplete: (artifact) => {
    console.log("Artifact ready:", artifact.name);
  },
});

Streaming vs non-streaming

The runtime selects the communication mode from the agent card:

  • If the agent card indicates capabilities.streaming: true (or the field is unset), the runtime uses POST /message:stream with SSE.
  • If capabilities.streaming: false, the runtime falls back to POST /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

FeatureSupported
Streaming (SSE)Yes
Non-streaming fallbackYes
All 9 task statesYes
Artifacts (text, data, file)Yes
Agent card discoveryYes
Multi-tenancyYes
Structured errorsYes
Push notifications CRUDYes
Extension negotiationYes
Task cancellationYes
Message editingYes
Message reloadYes
History persistenceVia history adapter
Thread list managementVia thread list adapter