A2A.JSONRPC behaviour (A2A v0.3.0)

Copy Markdown View Source

Transport-agnostic JSON-RPC 2.0 dispatch layer for the A2A protocol.

Defines a handler behaviour and a handle/3 function that parses JSON-RPC envelopes, validates params, and dispatches to the handler module.

Handler behaviour

Three callbacks are required — every A2A server answers these methods:

defmodule MyHandler do
  @behaviour A2A.JSONRPC

  @impl true
  def handle_send(message, params, context) do
    # process the message, return {:ok, task}, {:ok, message}, or
    # {:error, error} — `SendMessageResponse` is a Task/Message oneof
  end

  @impl true
  def handle_get(task_id, params, context) do
    # look up the task
  end

  @impl true
  def handle_cancel(task_id, params, context) do
    # cancel the task
  end
end

Five more are optional, and each has a defined answer when absent:

Presence is checked per request with Code.ensure_loaded?/1 and function_exported?/3, so a handler implementing none of the optional callbacks behaves exactly as it did before they existed.

Dispatching

case A2A.JSONRPC.handle(decoded_body, MyHandler) do
  {:reply, response_map} -> send_json(response_map)
  {:stream, method, params, id} -> start_sse(method, params, id)
end

The third argument to handle/3 is a context map, threaded unchanged to every callback, which transports use to pass per-request data.

Summary

Callbacks

Called for tasks/cancel requests.

Called for tasks/pushNotificationConfig/delete requests. Optional.

Called for tasks/get requests.

Called for tasks/pushNotificationConfig/get requests. Optional.

Called for tasks/list requests. Optional.

Called for tasks/pushNotificationConfig/list requests. Optional.

Called for message/send and message/stream requests.

Called for tasks/pushNotificationConfig/set requests. Optional.

Functions

Parses a JSON-RPC 2.0 request map and dispatches to the handler.

Types

result()

@type result() ::
  {:reply, map()} | {:stream, String.t(), map(), String.t() | integer() | nil}

Callbacks

handle_cancel(task_id, params, context)

@callback handle_cancel(task_id :: String.t(), params :: map(), context :: map()) ::
  {:ok, A2A.Task.t()} | {:error, A2A.JSONRPC.Error.t()}

Called for tasks/cancel requests.

handle_delete_push_config(task_id, config_id, params, context)

(optional)
@callback handle_delete_push_config(
  task_id :: String.t(),
  config_id :: String.t(),
  params :: map(),
  context :: map()
) :: :ok | {:error, A2A.JSONRPC.Error.t()}

Called for tasks/pushNotificationConfig/delete requests. Optional.

handle_get(task_id, params, context)

@callback handle_get(task_id :: String.t(), params :: map(), context :: map()) ::
  {:ok, A2A.Task.t()} | {:error, A2A.JSONRPC.Error.t()}

Called for tasks/get requests.

handle_get_push_config(task_id, config_id, params, context)

(optional)
@callback handle_get_push_config(
  task_id :: String.t(),
  config_id :: String.t(),
  params :: map(),
  context :: map()
) :: {:ok, A2A.PushNotificationConfig.t()} | {:error, A2A.JSONRPC.Error.t()}

Called for tasks/pushNotificationConfig/get requests. Optional.

handle_list(params, context)

(optional)
@callback handle_list(params :: map(), context :: map()) ::
  {:ok, map()} | {:error, A2A.JSONRPC.Error.t()}

Called for tasks/list requests. Optional.

handle_list_push_configs(task_id, params, context)

(optional)
@callback handle_list_push_configs(
  task_id :: String.t(),
  params :: map(),
  context :: map()
) ::
  {:ok, [A2A.PushNotificationConfig.t()]} | {:error, A2A.JSONRPC.Error.t()}

Called for tasks/pushNotificationConfig/list requests. Optional.

handle_send(t, params, context)

@callback handle_send(A2A.Message.t(), params :: map(), context :: map()) ::
  {:ok, A2A.Task.t() | A2A.Message.t()} | {:error, A2A.JSONRPC.Error.t()}

Called for message/send and message/stream requests.

handle_set_push_config(t, params, context)

(optional)
@callback handle_set_push_config(
  A2A.PushNotificationConfig.t(),
  params :: map(),
  context :: map()
) ::
  {:ok, A2A.PushNotificationConfig.t()} | {:error, A2A.JSONRPC.Error.t()}

Called for tasks/pushNotificationConfig/set requests. Optional.

Functions

handle(raw, handler, context \\ %{})

@spec handle(map(), module(), map()) :: result()

Parses a JSON-RPC 2.0 request map and dispatches to the handler.

An optional context map is threaded through to every handler callback, letting transports like A2A.Plug pass per-request data (agent pid, metadata, etc.) without the process dictionary.

Returns {:reply, response_map} for synchronous methods, or {:stream, method, params, id} for streaming methods.