# `A2A.JSON`
[🔗](https://github.com/actioncard/a2a-elixir/blob/main/lib/a2a/json.ex#L1)

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: %{}}

# `decode_type`

```elixir
@type decode_type() ::
  :task
  | :status
  | :message
  | :artifact
  | :part
  | :file_content
  | :event
  | :status_update_event
  | :artifact_update_event
  | :push_notification_config
```

# `encode_result`

```elixir
@type encode_result() :: {:ok, map()} | {:error, term()}
```

# `decode`

```elixir
@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.

# `decode!`

```elixir
@spec decode!(map(), decode_type()) :: struct()
```

Decodes a JSON map into an Elixir struct, raising on failure.

# `decode_agent_card`

```elixir
@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"

# `decode_state`

```elixir
@spec decode_state(String.t()) ::
  {:ok, atom()} | {:error, {:invalid_state, String.t()}}
```

Decodes a wire-format state string to an atom.

Accepts both v0.3 (`"TASK_STATE_WORKING"`) and legacy (`"working"`)
formats.

# `encode`

```elixir
@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.

# `encode!`

```elixir
@spec encode!(struct()) :: map()
```

Encodes an Elixir struct to a JSON-ready map, raising on failure.

# `encode_agent_card`

```elixir
@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 default `supportedInterfaces[0].url`
- `:capabilities` — `AgentCapabilities` map (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" => ...}`)

# `encode_known_keys`

```elixir
@spec encode_known_keys(map(), [{String.t(), atom()}]) :: map()
```

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.

# `encode_stream_response`

```elixir
@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.

# `valid_state_strings`

```elixir
@spec valid_state_strings() :: [String.t()]
```

Returns the list of valid v0.3 wire-format state strings.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
