A2A.Client (A2A v0.3.0)

Copy Markdown View Source

HTTP client for consuming remote A2A agents.

Provides discovery, synchronous messaging, SSE streaming, and task management using the A2A JSON-RPC protocol over HTTP.

Quick Start

# Discover an agent
{:ok, card} = A2A.Client.discover("https://agent.example.com")

# Create a client and send a message
client = A2A.Client.new(card)
{:ok, task} = A2A.Client.send_message(client, "Hello!")

# Stream a response
{:ok, stream} = A2A.Client.stream_message(client, "Count to 5")
Enum.each(stream, &IO.inspect/1)

Convenience Overloads

All functions that accept a %A2A.Client{} also accept a URL string or %A2A.AgentCard{}:

{:ok, task} = A2A.Client.send_message("https://agent.example.com", "Hello!")
{:ok, task} = A2A.Client.send_message(card, "Hello!")

Options

Functions that send messages accept these options:

  • :task_id — continue an existing task (multi-turn)
  • :context_id — set the context ID
  • :configuration — MessageSendConfiguration map
  • :metadata — arbitrary metadata map
  • :headers — additional HTTP headers
  • :timeout — HTTP request timeout in ms

Extensions

Pass :extensions to new/2 to declare A2A protocol extensions this client supports. Their declared URIs are sent in the A2A-Extensions request header on every call. Use parse_extensions_header/1 and activated/2 on the resulting Req.Response to find out which extensions the server activated.

Protocol version

Pass :version to new/2 to set the A2A-Version request header sent on every call. Defaults to A2A.Version.default/0 ("1.0"). Use version/1 on a Req.Response to read the version the server echoed back.

Summary

Functions

Returns the configured extension modules whose URI appears in the server's A2A-Extensions response header.

Cancels a task by ID via CancelTask.

Deletes a push notification config. Idempotent — deleting a config that is not registered succeeds.

Discovers an agent by fetching its agent card.

Retrieves a push notification config by task ID and config ID.

Retrieves a task by ID via GetTask.

Lists every push notification config registered for a task.

Creates a new client struct.

Parses the A2A-Extensions header from a Req.Response. Returns the list of extension URIs the server activated for the corresponding request, or [] if the header is absent.

Reattaches to a running task's event stream via SubscribeToTask.

Sends a message to an agent via SendMessage.

Registers a push notification config for a task.

Sends a message and returns a stream of decoded SSE events.

Returns the negotiated A2A protocol version from the server's A2A-Version response header, or nil if the header is absent.

Types

t()

@type t() :: %A2A.Client{
  extensions: [A2A.Extension.compiled()],
  req: Req.Request.t(),
  url: String.t()
}

target()

@type target() :: t() | A2A.AgentCard.t() | String.t()

Functions

activated(client, response)

@spec activated(t(), Req.Response.t()) :: [module()]

Returns the configured extension modules whose URI appears in the server's A2A-Extensions response header.

cancel_task(target, task_id, opts \\ [])

@spec cancel_task(target(), String.t(), keyword()) ::
  {:ok, A2A.Task.t()} | {:error, term()}

Cancels a task by ID via CancelTask.

Options

  • :headers — additional HTTP headers
  • :timeout — HTTP request timeout in ms

Examples

{:ok, task} = A2A.Client.cancel_task(client, "tsk-abc123")

delete_push_config(target, task_id, config_id, opts \\ [])

@spec delete_push_config(target(), String.t(), String.t(), keyword()) ::
  :ok | {:error, term()}

Deletes a push notification config. Idempotent — deleting a config that is not registered succeeds.

Options

  • :headers — additional HTTP headers
  • :timeout — HTTP request timeout in ms

discover(base_url, opts \\ [])

@spec discover(String.t(), keyword()) :: {:ok, A2A.AgentCard.t()} | {:error, term()}

Discovers an agent by fetching its agent card.

Sends GET /.well-known/agent-card.json and decodes the response into an %A2A.AgentCard{}.

Options

  • :headers — additional HTTP headers
  • :timeout — HTTP request timeout in ms
  • :agent_card_path — custom discovery path (default: "/.well-known/agent-card.json")

Examples

{:ok, card} = A2A.Client.discover("https://agent.example.com")
card.name #=> "my-agent"

get_push_config(target, task_id, config_id, opts \\ [])

@spec get_push_config(target(), String.t(), String.t(), keyword()) ::
  {:ok, A2A.PushNotificationConfig.t()} | {:error, term()}

Retrieves a push notification config by task ID and config ID.

Options

  • :headers — additional HTTP headers
  • :timeout — HTTP request timeout in ms

get_task(target, task_id, opts \\ [])

@spec get_task(target(), String.t(), keyword()) ::
  {:ok, A2A.Task.t()} | {:error, term()}

Retrieves a task by ID via GetTask.

Options

  • :history_length — number of history entries to include
  • :headers — additional HTTP headers
  • :timeout — HTTP request timeout in ms

Examples

{:ok, task} = A2A.Client.get_task(client, "tsk-abc123")

list_push_configs(target, task_id, opts \\ [])

@spec list_push_configs(target(), String.t(), keyword()) ::
  {:ok, [A2A.PushNotificationConfig.t()]} | {:error, term()}

Lists every push notification config registered for a task.

Options

  • :headers — additional HTTP headers
  • :timeout — HTTP request timeout in ms

new(url_or_card, opts \\ [])

@spec new(A2A.AgentCard.t() | String.t(), keyword()) :: t()

Creates a new client struct.

Accepts a URL string or %A2A.AgentCard{}. Options are forwarded to Req.new/1 for customizing the HTTP client (headers, timeouts, etc.).

Examples

client = A2A.Client.new("https://agent.example.com")
client = A2A.Client.new(card, headers: [{"authorization", "Bearer token"}])

parse_extensions_header(response)

@spec parse_extensions_header(Req.Response.t()) :: [String.t()]

Parses the A2A-Extensions header from a Req.Response. Returns the list of extension URIs the server activated for the corresponding request, or [] if the header is absent.

HTTP headers may appear as a single comma-separated value or as multiple repeated headers; both are handled.

resubscribe(target, task_id, opts \\ [])

@spec resubscribe(target(), String.t(), keyword()) ::
  {:ok, Enumerable.t()} | {:error, term()}

Reattaches to a running task's event stream via SubscribeToTask.

Returns {:ok, stream} for a task still in progress. The first element is the task as it stands; subsequent elements are %A2A.Event.StatusUpdate{} structs, and the stream ends when the task reaches a terminal state.

A task that does not exist answers TaskNotFoundError and one that has already finished answers UnsupportedOperationError — both come back as {:error, %A2A.JSONRPC.Error{}} rather than an empty stream.

Events produced before the subscription are not replayed, so a caller that needs the full history should pair this with get_task/3.

Options

  • :history_length — number of history entries to include in the snapshot
  • :headers — additional HTTP headers
  • :timeout — HTTP request timeout in ms

Examples

{:ok, stream} = A2A.Client.resubscribe(client, "tsk-abc123")
Enum.each(stream, &IO.inspect/1)

send_message(target, message, opts \\ [])

@spec send_message(target(), A2A.Message.t() | String.t(), keyword()) ::
  {:ok, A2A.Task.t() | A2A.Message.t()} | {:error, term()}

Sends a message to an agent via SendMessage.

Returns {:ok, task} on success, or {:ok, message} when the agent answers out-of-band with a bare %A2A.Message{} — SendMessageResponse is a Task/Message oneof, so match on the struct to tell them apart. Returns {:error, reason} on failure. The message can be a string, an %A2A.Message{}, or a list of parts.

Options

  • :task_id — continue an existing task
  • :context_id — set the context ID
  • :configuration — MessageSendConfiguration map
  • :metadata — arbitrary metadata map
  • :headers — additional HTTP headers
  • :timeout — HTTP request timeout in ms

Examples

{:ok, task} = A2A.Client.send_message(client, "Hello!")
{:ok, task} = A2A.Client.send_message(client, "More info", task_id: task.id)

set_push_config(target, config, opts \\ [])

@spec set_push_config(target(), A2A.PushNotificationConfig.t(), keyword()) ::
  {:ok, A2A.PushNotificationConfig.t()} | {:error, term()}

Registers a push notification config for a task.

The config's :task_id names the task; :id is assigned by the server when left nil. Returns the stored config.

Options

  • :headers — additional HTTP headers
  • :timeout — HTTP request timeout in ms

Examples

config = %A2A.PushNotificationConfig{
  task_id: "tsk-abc123",
  url: "https://example.com/webhook",
  authentication: %{scheme: "Bearer", credentials: "s3cret"}
}

{:ok, stored} = A2A.Client.set_push_config(client, config)

stream_message(target, message, opts \\ [])

@spec stream_message(target(), A2A.Message.t() | String.t(), keyword()) ::
  {:ok, Enumerable.t()} | {:error, term()}

Sends a message and returns a stream of decoded SSE events.

Uses SendStreamingMessage to receive server-sent events. Returns {:ok, stream} where the stream yields decoded structs (%A2A.Task{}, %A2A.Event.StatusUpdate{}, %A2A.Event.ArtifactUpdate{}, or %A2A.Message{}).

Options

Same as send_message/3.

Examples

{:ok, stream} = A2A.Client.stream_message(client, "Count to 5")
Enum.each(stream, fn
  %A2A.Event.StatusUpdate{final: true} -> :done
  event -> IO.inspect(event)
end)

version(response)

@spec version(Req.Response.t()) :: String.t() | nil

Returns the negotiated A2A protocol version from the server's A2A-Version response header, or nil if the header is absent.