# `ALLM.Request`
[🔗](https://github.com/cykod/ALLM/blob/v0.5.0/lib/allm/request.ex#L1)

A single LLM request — Layer A serializable data.

Carries the `:messages` list, optional `:model`, `:tools`, `:tool_choice`,
`:temperature`, `:max_tokens`, `:response_format`, and adapter-opaque
`:options` and `:metadata`.

## Fields

| Field | Type | Default | Notes |
|-------|------|---------|-------|
| `:messages` | `[%Message{}]` | (required) | The conversation. |
| `:model` | `String.t \| nil` | `nil` | Late-resolved against the engine. |
| `:tools` | `[%Tool{}]` | `[]` | Declared tools. |
| `:tool_choice` | `:auto \| :none \| :required \| String.t \| map \| nil` | `nil` | Provider-specific shapes pass through verbatim. |
| `:temperature` | `number \| nil` | `nil` | |
| `:max_tokens` | `non_neg_integer \| nil` | `nil` | Anthropic's adapter injects `1024` if `nil`. |
| `:response_format` | `nil \| :text \| %{type: :json_object} \| %{type: :json_schema, ...}` | `nil` | Build with `ALLM.json_schema/3`. |
| `:stream` | `boolean` | `false` | |
| `:structured_finalize` | `boolean` | `false` | Synthetic-tool fallback for providers without native JSON-schema mode. |
| `:options` | `map` | `%{}` | Adapter-opaque pass-through. |
| `:metadata` | `map` | `%{}` | Caller-owned. |

Validation lives in `ALLM.Validate.request/1`. `new/2` itself does not
validate — it stays composable so callers opt into validation
explicitly.

## Round-trip

    iex> req = ALLM.Request.new([%ALLM.Message{role: :user, content: "hi"}], model: "fake:x")
    iex> json = ALLM.Serializer.to_json!(req)
    iex> {:ok, ^req} = ALLM.Serializer.from_json(json)
    iex> req.model
    "fake:x"

See also `guides/getting_started.md`.

# `response_format`

```elixir
@type response_format() ::
  nil
  | :text
  | %{type: :json_object}
  | %{type: :json_schema, name: String.t(), schema: map(), strict: boolean()}
```

# `t`

```elixir
@type t() :: %ALLM.Request{
  max_tokens: non_neg_integer() | nil,
  messages: [ALLM.Message.t()],
  metadata: map(),
  model: String.t() | nil,
  options: map(),
  response_format: response_format(),
  stream: boolean(),
  structured_finalize: boolean(),
  temperature: number() | nil,
  tool_choice: tool_choice(),
  tools: [ALLM.Tool.t()]
}
```

# `tool_choice`

```elixir
@type tool_choice() :: :auto | :none | :required | String.t() | map() | nil
```

# `new`

```elixir
@spec new(
  [ALLM.Message.t()],
  keyword()
) :: t()
```

Build a `%Request{}` from a list of messages and keyword opts.

`messages` is required and becomes the `:messages` field. `opts` may set any
other struct field; unknown keys raise `ArgumentError` via `struct!/2`.

## Examples

    iex> req = ALLM.Request.new([%ALLM.Message{role: :user, content: "hi"}])
    iex> req.stream
    false
    iex> length(req.messages)
    1

    iex> req = ALLM.Request.new([%ALLM.Message{role: :user, content: "hi"}], model: "fake:x", temperature: 0.2)
    iex> {req.model, req.temperature}
    {"fake:x", 0.2}

---

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