Packages

fnord

0.9.36

AI code archaeology

Current section

Files

Jump to
fnord lib ai message reasoning.ex
Raw

lib/ai/message/reasoning.ex

defmodule AI.Message.Reasoning do
@moduledoc """
Opaque pass-through for reasoning items returned by the Responses API when
a reasoning model is in use. Wire shape (illustrative - fields vary by
model and may include `summary`, `encrypted_content`, internal IDs, etc.):
%{type: "reasoning", id: "...", summary: [...], encrypted_content: "..."}
We store the raw map verbatim and emit it back unchanged. Round-tripping is
what lets `store: false` callers preserve reasoning continuity across turns
without giving OpenAI server-side state.
Atom-table note: the raw map is held as-is. Because reasoning blobs may
contain arbitrary keys, do NOT pass these through `Util.string_keys_to_atoms/1`
or any other key-atomizer. Treat them as inert payload.
"""
@behaviour AI.Message
@enforce_keys [:raw]
defstruct [:raw]
@type t :: %__MODULE__{raw: map()}
@doc "Build a reasoning item from the raw map returned by the API."
@spec new(map()) :: t()
def new(raw) when is_map(raw), do: %__MODULE__{raw: raw}
@impl AI.Message
def text(%__MODULE__{}), do: nil
@impl AI.Message
def for_transcript(%__MODULE__{}), do: nil
@impl AI.Message
def to_map(%__MODULE__{raw: raw}), do: ensure_type(raw)
@doc "Hydrate from a raw map. Same as `new/1` - the struct is just a wrapper."
@spec from_map(map()) :: t()
def from_map(raw) when is_map(raw), do: new(ensure_type(raw))
defp ensure_type(%{type: "reasoning"} = raw), do: raw
defp ensure_type(%{"type" => "reasoning"} = raw), do: raw
defp ensure_type(raw) when is_map(raw), do: Map.put(raw, :type, "reasoning")
end