# `Alloy.Provider`
[🔗](https://github.com/alloy-ex/alloy/blob/v0.10.1/lib/alloy/provider.ex#L1)

Behaviour for LLM providers.

Each provider translates between its native wire format and Alloy's
normalized `Alloy.Message` structs. The agent loop only sees normalized
messages - adding a new provider means implementing this behaviour.

## Completion Response

Providers return a map with:
- `:stop_reason` - `:tool_use` (continue looping) or `:end_turn` (done)
- `:messages` - list of `Alloy.Message` structs from the response
- `:usage` - map with `:input_tokens` and `:output_tokens`
- `:provider_state` - optional opaque map Alloy feeds back to the same provider
  on subsequent turns (for example, stored response IDs)
- `:response_metadata` - optional provider response metadata exposed to the app
  layer (for example, citations or server-side tool usage)

# `completion_response`

```elixir
@type completion_response() :: %{
  :stop_reason =&gt; stop_reason(),
  :messages =&gt; [Alloy.Message.t()],
  :usage =&gt; map(),
  optional(:provider_state) =&gt; map(),
  optional(:response_metadata) =&gt; map()
}
```

# `stop_reason`

```elixir
@type stop_reason() :: :tool_use | :end_turn
```

# `tool_def`

```elixir
@type tool_def() :: %{name: String.t(), description: String.t(), input_schema: map()}
```

# `complete`

```elixir
@callback complete(
  messages :: [Alloy.Message.t()],
  tool_defs :: [tool_def()],
  config :: map()
) :: {:ok, completion_response()} | {:error, term()}
```

Send messages to the provider and get a completion response.

## Parameters
- `messages` - Conversation history as normalized `Alloy.Message` structs
- `tool_defs` - Tool definitions (JSON Schema format)
- `config` - Provider-specific configuration (API keys, model, etc.)

## Returns
- `{:ok, completion_response()}` on success
- `{:error, term()}` on failure

# `stream`
*optional* 

```elixir
@callback stream(
  messages :: [Alloy.Message.t()],
  tool_defs :: [tool_def()],
  config :: map(),
  on_chunk :: (String.t() -&gt; :ok)
) :: {:ok, completion_response()} | {:error, term()}
```

Stream a completion, calling `on_chunk` for each text delta.

Returns the same `{:ok, completion_response()}` as `complete/3` once
the stream finishes -- the full accumulated response.

# `decode_body`

```elixir
@spec decode_body(binary() | map()) :: {:ok, map()} | {:error, String.t()}
```

Decode a JSON binary response body, passing through maps unchanged.

Returns `{:ok, decoded_map}` or `{:error, reason}`.

# `stringify_keys`

```elixir
@spec stringify_keys(term()) :: term()
```

Recursively convert atom keys to strings in maps.

Used by providers to prepare JSON-compatible request bodies.

---

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