Codec for converting between Elixir structs and the A2A v1.0 camelCase JSON wire format.
Produces intermediate maps (not JSON strings) suitable for composing with
JSON-RPC envelopes. Use Jason.encode!/1 on the result when you need a string.
Encoding emits the v1.0 flat shape (no kind discriminator, flat Part
with text/data/raw/url + mediaType/filename). Decoding accepts
both v1.0 and the legacy v0.3 shape (nested file: {bytes|uri, mimeType}
and kind-tagged parts) so v0.3 clients keep working.
Encoding
iex> part = A2A.Part.Text.new("hello")
iex> {:ok, map} = A2A.JSON.encode(part)
iex> map
%{"text" => "hello"}Decoding
iex> {:ok, part} = A2A.JSON.decode(%{"text" => "hello"}, :part)
iex> part
%A2A.Part.Text{text: "hello", metadata: %{}}
Summary
Functions
Decodes a JSON map into an Elixir struct of the given type.
Decodes a JSON map into an Elixir struct, raising on failure.
Decodes a JSON map into an %A2A.AgentCard{} struct.
Decodes a wire-format state string to an atom.
Encodes an Elixir struct to a JSON-ready map.
Encodes an Elixir struct to a JSON-ready map, raising on failure.
Encodes an agent card into the AgentCard JSON format.
Converts an Elixir map with atom keys to a camelCase JSON map.
Encodes a streaming event into the v1.0 StreamResponse wrapper.
Returns the list of valid v0.3 wire-format state strings.
Types
Functions
@spec decode(map(), decode_type()) :: {:ok, struct()} | {:error, term()}
Decodes a JSON map into an Elixir struct of the given type.
Returns {:ok, struct} on success or {:error, reason} on failure.
The :part type dispatches on the "kind" field, or infers the type
from content fields ("text", "file", "data") when "kind" is
absent (v0.3 format). The :event type dispatches on the v1.0
StreamResponse wrapper key — "task", "message", "statusUpdate" or
"artifactUpdate" — falling back to the v0.3 "kind" discriminator.
@spec decode!(map(), decode_type()) :: struct()
Decodes a JSON map into an Elixir struct, raising on failure.
@spec decode_agent_card(map()) :: {:ok, A2A.AgentCard.t()} | {:error, term()}
Decodes a JSON map into an %A2A.AgentCard{} struct.
Returns {:ok, agent_card} on success or {:error, reason} on failure.
Example
iex> map = %{
...> "name" => "test",
...> "description" => "A test agent",
...> "url" => "https://example.com",
...> "version" => "1.0.0",
...> "skills" => [
...> %{"id" => "s1", "name" => "Skill", "description" => "Does things", "tags" => []}
...> ]
...> }
iex> {:ok, card} = A2A.JSON.decode_agent_card(map)
iex> card.name
"test"
Decodes a wire-format state string to an atom.
Accepts both v0.3 ("TASK_STATE_WORKING") and legacy ("working")
formats.
@spec encode(struct()) :: encode_result()
Encodes an Elixir struct to a JSON-ready map.
Returns {:ok, map} on success or {:error, reason} on failure.
Optional nil fields and empty collections are omitted from the output.
Encodes an Elixir struct to a JSON-ready map, raising on failure.
@spec encode_agent_card(A2A.AgentCard.t() | A2A.Agent.card(), keyword()) :: map()
Encodes an agent card into the AgentCard JSON format.
Accepts either a plain map (as returned by A2A.Agent.agent_card/0) or a
fully-populated %A2A.AgentCard{} struct. When a struct is passed, fields
like capabilities, provider, documentation_url, etc. are read from
the struct and used as defaults. Options in opts always take precedence
over struct fields.
In v1.0 the top-level url and protocolVersion fields are gone from the
wire format — both are per-interface. The :url option is still required
because it seeds the default supportedInterfaces entry; pass
:supported_interfaces directly to override.
Options
All options override the corresponding struct field when a
%A2A.AgentCard{} is passed as card.
:url— agent endpoint URL, used as the defaultsupportedInterfaces[0].url:capabilities—AgentCapabilitiesmap (default:%{}):default_input_modes— list of MIME types (default:["text/plain"]):default_output_modes— list of MIME types (default:["text/plain"]):provider—%{organization: ..., url: ...}map:documentation_url— URL string:icon_url— URL string:supported_interfaces— list of%{url: ..., protocol_binding: ..., protocol_version: ...}maps. Defaults to a single JSON-RPC interface derived from:url.:security_schemes—%{name => %SecurityScheme.X{}}map:security— list of%{name => scopes}maps (OpenAPI-style):signatures— list of JWS signature maps (each%{"protected" => ..., "signature" => ..., "header" => ...})
Converts an Elixir map with atom keys to a camelCase JSON map.
Each mapping is a {json_key, atom_key} pair. Keys whose values are nil
(or absent) are omitted from the result. Looks up both the atom key and the
JSON-string key so the function works with either representation.
@spec encode_stream_response(struct()) :: encode_result()
Encodes a streaming event into the v1.0 StreamResponse wrapper.
Streaming operations and push notification payloads carry exactly one of
task, message, statusUpdate or artifactUpdate. The wrapper key is
the discriminator, which is why the wrapped objects carry no kind of
their own — the schema rejects unknown properties at both levels.
@spec valid_state_strings() :: [String.t()]
Returns the list of valid v0.3 wire-format state strings.