# `ReqLLM.Response`
[🔗](https://github.com/agentjido/req_llm/blob/main/lib/req_llm/response.ex#L1)

High-level representation of an LLM response.

Always contains a Context. For chat generation, the context contains the full
conversation history, including new assistant and tool messages. For evaluation,
the context is empty and `object` contains the named answers. The response also
contains metadata and, when streaming, a lazy `Stream` of `ReqLLM.StreamChunk`s.

This struct eliminates the need for manual message extraction and context building
in multi-turn conversations and tool calling workflows.

## Examples

    # Basic response usage
    {:ok, response} = ReqLLM.generate_text("anthropic:claude-3-sonnet", context)
    ReqLLM.Response.text(response)  #=> "Hello! I'm Claude."
    ReqLLM.Response.usage(response)  #=> %{input_tokens: 12, output_tokens: 4, total_cost: 0.016}

    # Multi-turn conversation (no manual context building)
    {:ok, response2} = ReqLLM.generate_text("anthropic:claude-3-sonnet", response.context)

# `call_metadata`

```elixir
@type call_metadata() :: %{
  :response_id =&gt; String.t(),
  :model =&gt; String.t(),
  optional(:finish_reason) =&gt; atom(),
  optional(:usage) =&gt; map(),
  optional(:request_id) =&gt; String.t(),
  optional(:raw_finish_reason) =&gt; String.t() | atom(),
  optional(:warnings) =&gt; [String.t()],
  optional(:attempts) =&gt; non_neg_integer(),
  optional(:timings) =&gt; map(),
  optional(:provider_metadata) =&gt; map()
}
```

Computed metadata for one model interaction.

Optional keys are present only when their values were retained by the
provider path. `attempts` never includes separate model interactions from
the response context.

# `classify_result`

```elixir
@type classify_result() :: %{
  type: :tool_calls | :final_answer,
  text: String.t(),
  thinking: String.t(),
  tool_calls: [map()],
  finish_reason:
    :stop
    | :length
    | :tool_calls
    | :content_filter
    | :error
    | :cancelled
    | :incomplete
    | :unknown
    | nil
}
```

Result of classifying a non-streaming response.

- `type` - `:tool_calls` when tools should be executed, `:final_answer` otherwise
- `text` - Assistant text content
- `thinking` - Assistant thinking content
- `tool_calls` - Normalized tool call maps with `:id`, `:name`, and `:arguments`
- `finish_reason` - Normalized finish reason atom

# `t`

```elixir
@type t() :: %ReqLLM.Response{
  context: any(),
  error: nil | any(),
  finish_reason:
    nil
    | :stop
    | :length
    | :tool_calls
    | :content_filter
    | :error
    | :cancelled
    | :incomplete
    | :unknown
    | nil,
  id: binary(),
  message: nil | any(),
  model: binary(),
  object: nil | map() | nil,
  provider_meta: map(),
  stream: nil | any(),
  stream?: boolean(),
  usage: nil | map() | nil
}
```

# `annotations`

```elixir
@spec annotations(t()) :: [term()]
```

Returns annotation values retained by content or provider metadata.

# `call_metadata`

```elixir
@spec call_metadata(t()) :: call_metadata()
```

Return a redacted call-metadata projection over existing response values.

The projection includes response identity, normalized finish reason, usage,
and safe provider metadata when available. Request IDs, raw finish reasons,
warnings, attempt counts, and timings are omitted unless the provider path
already retained them. Credentials, prompts, file payloads, and hidden
reasoning metadata are redacted recursively.

This function does not enable additional provider capture or alter legacy
response serialization.

# `channel_items`

```elixir
@spec channel_items(t(), ReqLLM.Response.OutputItem.channel()) :: [
  ReqLLM.Response.OutputItem.t()
]
```

Returns canonical output items for one stable result channel.

# `channels`

```elixir
@spec channels(t()) :: %{
  required(ReqLLM.Response.OutputItem.channel()) =&gt; [
    ReqLLM.Response.OutputItem.t()
  ]
}
```

Returns canonical output items grouped into stable result channels.

# `classify`

```elixir
@spec classify(t()) :: classify_result()
```

Classify a non-streaming response for tool-calling workflows.

Returns a map with stream-parity shape:
`%{type, text, thinking, tool_calls, finish_reason}`.

# `decode_object`

```elixir
@spec decode_object(term(), ReqLLM.model_input(), keyword()) ::
  {:ok, t()} | {:error, term()}
```

Decode provider response data into a Response with structured object.

Similar to decode_response/2 but specifically for object generation responses.
Extracts the structured object from tool calls and validates it against the schema.

## Parameters

  * `raw_data` - Raw provider response data
  * `model_spec` - Model specification (supports all formats from ReqLLM.model/1)
  * `schema` - Schema definition for validation

## Returns

  * `{:ok, %ReqLLM.Response{}}` with object field populated on success
  * `{:error, reason}` on failure

# `decode_object_stream`

```elixir
@spec decode_object_stream(term(), ReqLLM.model_input(), keyword()) ::
  {:ok, t()} | {:error, term()}
```

Decode provider streaming response data into a Response with object stream.

Similar to decode_response/2 but for streaming object generation.
The response will contain a stream of structured objects.

## Parameters

  * `raw_data` - Raw provider streaming response data
  * `model_spec` - Model specification (supports all formats from ReqLLM.model/1)
  * `schema` - Schema definition for validation

## Returns

  * `{:ok, %ReqLLM.Response{}}` with stream populated on success
  * `{:error, reason}` on failure

# `decode_response`

```elixir
@spec decode_response(term(), ReqLLM.model_input()) :: {:ok, t()} | {:error, term()}
```

Decode provider response data into a canonical ReqLLM.Response.

This is a façade function that accepts raw provider data and a model specification,
and directly calls the provider's decode_response/1 callback for zero-ceremony decoding.

Supports inline model maps, `%LLMDB.Model{}` structs, strings, and tuples, automatically resolving model
specifications using ReqLLM.model/1.

## Parameters

  * `raw_data` - Raw provider response data or Stream
  * `model_spec` - Model specification in any format supported by ReqLLM.model/1:
    - String: `"anthropic:claude-3-sonnet"`
    - Tuple: `{:anthropic, "claude-3-sonnet", temperature: 0.7}`
    - Map: `%{provider: :openai, id: "gpt-6-mini"}`
    - LLMDB.Model struct: `%LLMDB.Model{provider: :anthropic, id: "claude-3-sonnet"}`

## Returns

  * `{:ok, %ReqLLM.Response{}}` on success
  * `{:error, reason}` on failure

## Examples

    {:ok, response} = ReqLLM.Response.decode_response(raw_json, "anthropic:claude-3-sonnet")
    {:ok, response} = ReqLLM.Response.decode_response(raw_json, model_struct)
    {:ok, response} = ReqLLM.Response.decode_response(raw_json, {:anthropic, "claude-3-sonnet"})

# `files`

```elixir
@spec files(t()) :: [ReqLLM.Message.ContentPart.t()]
```

Returns generated file content parts retained by this response.

# `finish_reason`

```elixir
@spec finish_reason(t()) ::
  :stop
  | :length
  | :tool_calls
  | :content_filter
  | :error
  | :cancelled
  | :incomplete
  | :unknown
  | nil
```

Get the finish reason for this response.

## Examples

    iex> ReqLLM.Response.finish_reason(response)
    :stop

# `image`

```elixir
@spec image(t()) :: ReqLLM.Message.ContentPart.t() | nil
```

Returns the first image content part (or nil if none).

# `image_data`

```elixir
@spec image_data(t()) :: binary() | nil
```

Returns the binary data of the first `:image` part (or nil).

# `image_url`

```elixir
@spec image_url(t()) :: String.t() | nil
```

Returns the URL of the first `:image_url` part (or nil).

# `images`

```elixir
@spec images(t()) :: [ReqLLM.Message.ContentPart.t()]
```

Extract image content parts from the response message.

Returns a list of `ReqLLM.Message.ContentPart` where `type` is `:image` or `:image_url`.

# `join_stream`

```elixir
@spec join_stream(t()) :: {:ok, t()} | {:error, term()}
```

Materialize a streaming response into a complete response.

Consumes the entire stream, builds the complete message, and returns
a new response with the stream consumed and message populated.

## Examples

    {:ok, complete_response} = ReqLLM.Response.join_stream(streaming_response)

# `object`

```elixir
@spec object(t()) :: map() | nil
```

Extracts the structured object from a Response. Evaluation responses contain
named answers in this field.

# `object_stream`

```elixir
@spec object_stream(t()) :: Enumerable.t()
```

Create a stream of structured objects from a streaming response.

Only yields valid objects from tool call stream chunks, filtering out
metadata and other chunk types.

## Examples

    response
    |> ReqLLM.Response.object_stream()
    |> Stream.each(&IO.inspect/1)
    |> Stream.run()

# `ok?`

```elixir
@spec ok?(t()) :: boolean()
```

Check if the response completed successfully without errors.

## Examples

    iex> ReqLLM.Response.ok?(response)
    true

# `output`

```elixir
@spec output(t(), ReqLLM.Output.t()) :: term()
```

Projects the value described by a `ReqLLM.Output` descriptor.

This is a computed view over the unchanged response. Plain text delegates to
`text/1`; object output uses the existing `object` value; array, choice, and
JSON outputs unwrap the private compatibility envelope used by providers that
require a top-level object schema.

Raw text, structured tool-call arguments, usage, and provider metadata remain
available through their existing accessors. This projection follows the
current V1 structured-output validation and repair behavior.

# `output_items`

```elixir
@spec output_items(t()) :: [ReqLLM.Response.OutputItem.t()]
```

Return a deterministic canonical projection of values retained by this response.

Message content keeps its existing order. Tool calls follow content because
the V1 `ReqLLM.Message` contract stores tool calls separately and does not
retain their original interleaving. Sources, annotations, refusals, and
provider-native items retained only in metadata follow the message values.

This function does not add fields to or mutate `ReqLLM.Response`.

# `output_result`

```elixir
@spec output_result(t(), ReqLLM.Output.t(), keyword()) :: ReqLLM.Output.Result.t()
```

Returns a visible final-value report for an output descriptor.

The report separates retained raw output, the projected value, final validity,
validation errors, warnings, extraction source, repair attempts, and provider
metadata. It is computed locally and never triggers another model call.

`:policy` defaults to the policy recorded by generation, or `:compatible` when
no policy was explicitly selected.

# `provider_items`

```elixir
@spec provider_items(t()) :: [term()]
```

Returns provider-native output values retained by this response.

# `reasoning_tokens`

```elixir
@spec reasoning_tokens(t()) :: integer()
```

Get reasoning token count from the response usage.

Returns the number of reasoning tokens used by reasoning models (GPT-5, o1, o3, etc.)
during their internal thinking process. Returns 0 if no reasoning tokens were used.

## Examples

    iex> ReqLLM.Response.reasoning_tokens(response)
    64

# `refusals`

```elixir
@spec refusals(t()) :: [term()]
```

Returns refusal values retained by content or provider metadata.

# `schema`

# `sources`

```elixir
@spec sources(t()) :: [term()]
```

Returns source values retained by content or provider metadata.

# `text`

```elixir
@spec text(t()) :: String.t() | nil
```

Extract text content from the response message.

Returns the concatenated text from all content parts in the assistant message.
Returns nil when no message is present. For streaming responses, this may be nil
until the stream is joined.

## Examples

    iex> ReqLLM.Response.text(response)
    "Hello! I'm Claude and I can help you with questions."

# `text_stream`

```elixir
@spec text_stream(t()) :: Enumerable.t()
```

Create a stream of text content chunks from a streaming response.

Only yields content from :content type stream chunks, filtering out
metadata and other chunk types.

## Examples

    response
    |> ReqLLM.Response.text_stream()
    |> Stream.each(&IO.write/1)
    |> Stream.run()

# `thinking`

```elixir
@spec thinking(t()) :: String.t() | nil
```

Extract thinking/reasoning content from the response message.

Returns the concatenated thinking content if the message contains thinking parts, empty string otherwise.

## Examples

    iex> ReqLLM.Response.thinking(response)
    "The user is asking about the weather..."

# `tool_calls`

```elixir
@spec tool_calls(t()) :: [ReqLLM.ToolCall.t()]
```

Extract tool calls from the response message.

Returns a list of tool calls if the message contains them, empty list otherwise.
Provider responses expose tool calls as `ReqLLM.ToolCall` structs. Use struct
field access such as `call.id` and `call.function.name`, or call
`ReqLLM.ToolCall.to_map/1` when you need decoded arguments in a plain map.
Use `classify/1` when you want response text, finish reason, and normalized
tool call maps in one value.

## Examples

    iex> ReqLLM.Response.tool_calls(response)
    [%ReqLLM.ToolCall{id: "call_123", type: "function", function: %{name: "get_weather", arguments: ~s({"location":"San Francisco"})}}]

# `unwrap_object`

```elixir
@spec unwrap_object(t(), keyword()) :: {:ok, map() | list()} | {:error, term()}
```

Unwraps the object from a structured output response, regardless of mode used.

Handles extraction from:
- json_schema mode: parses from content
- tool modes: extracts from tool call arguments

## Examples

    {:ok, object} = ReqLLM.Response.unwrap_object(response)
    #=> {:ok, %{"name" => "John", "age" => 30}}

# `usage`

```elixir
@spec usage(t()) :: map() | nil
```

Get usage statistics for this response.

Provider-native cache reads and writes are reported separately in
`usage.cache_read_tokens` and `usage.cache_write_tokens`. The
`usage.cached_tokens` and `usage.cache_creation_tokens` fields are
compatibility aliases. Application-layer response cache hits instead return
a zeroed usage map and set
`response.provider_meta.response_cache_hit` to `true`.

## Examples

    iex> ReqLLM.Response.usage(response)
    %{input_tokens: 12, output_tokens: 8, total_tokens: 20, reasoning_tokens: 64, input_cost: 0.01, output_cost: 0.02, total_cost: 0.03}

---

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