Puck.Response (Puck v0.2.11)

Copy Markdown View Source

Normalized response struct for LLM outputs.

Fields

  • content - Response content (text or structured data)
  • thinking - Thinking/reasoning content from extended thinking models (nil if not available)
  • finish_reason - Why the model stopped (:stop, :max_tokens, etc.)
  • usage - Token usage information (includes thinking_tokens if available)
  • metadata - Backend-specific data

Summary

Types

Standardized metadata keys for observability.

t()

Functions

Returns true if this response is complete (stopped naturally).

Creates a new response with the given attributes.

Gets the text content from the response.

Gets the thinking/reasoning content from the response.

Gets the total token count from usage, if available.

Types

finish_reason()

@type finish_reason() :: :stop | :max_tokens | :content_filter | :error | atom()

metadata()

@type metadata() :: %{
  optional(:response_id) => String.t(),
  optional(:model) => String.t(),
  optional(:provider) => String.t(),
  optional(:latency_ms) => non_neg_integer(),
  optional(atom()) => term()
}

Standardized metadata keys for observability.

These align with OpenTelemetry GenAI semantic conventions.

t()

@type t() :: %Puck.Response{
  content: term(),
  finish_reason: finish_reason() | nil,
  metadata: metadata(),
  thinking: String.t() | nil,
  usage: usage()
}

usage()

@type usage() :: %{
  optional(:input_tokens) => non_neg_integer(),
  optional(:output_tokens) => non_neg_integer(),
  optional(:total_tokens) => non_neg_integer(),
  optional(:thinking_tokens) => non_neg_integer()
}

Functions

complete?(response)

Returns true if this response is complete (stopped naturally).

Examples

iex> response = Puck.Response.new(finish_reason: :stop)
iex> Puck.Response.complete?(response)
true

iex> response = Puck.Response.new(finish_reason: :max_tokens)
iex> Puck.Response.complete?(response)
false

new(attrs \\ [])

Creates a new response with the given attributes.

Examples

iex> Puck.Response.new(content: "Hello!")
%Puck.Response{content: "Hello!", thinking: nil, finish_reason: nil, usage: %{}, metadata: %{}}

text(response)

Gets the text content from the response.

Returns the content if it's a string, or nil if content is nil or non-string. This is a convenience for the common case of extracting text responses.

Examples

iex> response = Puck.Response.new(content: "Hello, world!")
iex> Puck.Response.text(response)
"Hello, world!"

iex> response = Puck.Response.new(content: nil)
iex> Puck.Response.text(response)
nil

thinking(response)

Gets the thinking/reasoning content from the response.

Returns the thinking content if available, or nil if the model doesn't support extended thinking or thinking was not enabled.

Examples

iex> response = Puck.Response.new(thinking: "Let me think about this...")
iex> Puck.Response.thinking(response)
"Let me think about this..."

iex> response = Puck.Response.new(content: "Hello!")
iex> Puck.Response.thinking(response)
nil

total_tokens(response)

Gets the total token count from usage, if available.

Examples

iex> response = Puck.Response.new(usage: %{input_tokens: 10, output_tokens: 20})
iex> Puck.Response.total_tokens(response)
30

iex> response = Puck.Response.new(usage: %{total_tokens: 50})
iex> Puck.Response.total_tokens(response)
50

iex> response = Puck.Response.new()
iex> Puck.Response.total_tokens(response)
nil