The Provider (ADR 0002/0003/0019): the OpenAI Responses API dialect, reached with
either Credential kind. Pixir always sends store: false; the local Log remains the
source of truth. The HTTP/SSE path sends folded History as full input. The
WebSocket path may use connection-local previous_response_id and a late delta as an
optimization, but it never replaces Log replay.
stream/2 performs one streamed model call:
- ephemeral
text/reasoningdeltas are delivered to the:on_deltacallback as{:text_delta, chunk}/{:reasoning_delta, chunk}(the Turn loop turns these into ephemeral Events — keeping this module free of bus/Session deps); - the assembled result
%{text, reasoning, function_calls, finish_reason}is returned for the Turn loop to persist (the finalassistant_message) and to decide whether to run tools.
Errors are structured (ADR 0005). Tests may still inject :transport directly; the
production path uses Pixir.Provider.TransportPolicy (:auto | :websocket | :http_sse) so WebSocket can be preferred while HTTP/SSE remains fallback.
Summary
Functions
Resolve the model id (open knob). Precedence
Whether model_id is in the advertised catalog (models/0). Used to reject an
unknown per-turn _meta.model before it reaches the backend (epic A.5,
decision #8 — fail early with -32602 rather than passing through to a backend
model_not_supported).
The model catalog Pixir advertises to a client (epic A.5). A list of
%{"id" => slug, "name" => label, "default" => bool} (string-keyed so it
rides ACP _meta verbatim). Source: the built-in list (gpt-5.5 &
family), extended/overridden by a ~/.pixir/config.json "models" array of
slugs if present. The active default_model/0 is always included and flagged
default: true (so the client's picker has a default even if config narrows
the list).
Cheaply validate connectivity and the model id: a minimal streamed call (tiny
prompt, no tools). Returns {:ok, %{model: id}} if the backend accepts it, or the
structured error otherwise (e.g. a provider_http_error for a bad model id). Useful
before committing to a full Turn.
Build a Responses request body preview without auth or network.
Stream one Responses call, retrying transient failures (network, :rate_limited,
5xx) with capped exponential backoff. Terminal errors (:usage_limit_reached,
:model_not_supported, auth) are not retried. See the module doc for the result
shape. Options: :max_retries (default 2), :sleep (injectable for tests).
Map a tool definition from a __tool__/0 callback to a Responses function tool.
Normalize OpenAI usage payloads into the fields Pixir records as Provider evidence.
Types
@type request() :: %{ optional(:model) => String.t(), optional(:system_prompt) => String.t(), optional(:developer_context) => String.t(), optional(:history) => [map()], optional(:tools) => [map()], optional(:hosted_tools) => [map()], optional(:web_search) => map() | keyword() | boolean(), optional(:prompt_cache_key) => String.t(), optional(:prompt_cache_retention) => String.t(), optional(:output_schema) => map() }
@type result() :: %{ text: String.t(), reasoning: String.t(), reasoning_items: [map()], function_calls: [%{call_id: String.t(), name: String.t(), args: map()}], output_items: [ reasoning: map(), function_call: map(), provider_hosted_tool: map() ], provider_hosted_tools: map(), web_search: map(), finish_reason: :stop | :tool_calls, usage: map() | nil, usage_summary: map(), provider_metadata: map() }
Functions
Resolve the model id (open knob). Precedence:
config :pixir, :model(programmatic override)PIXIR_MODELenv var~/.pixir/config.json→"model"- the built-in default (
gpt-5.5)
Whether model_id is in the advertised catalog (models/0). Used to reject an
unknown per-turn _meta.model before it reaches the backend (epic A.5,
decision #8 — fail early with -32602 rather than passing through to a backend
model_not_supported).
The model catalog Pixir advertises to a client (epic A.5). A list of
%{"id" => slug, "name" => label, "default" => bool} (string-keyed so it
rides ACP _meta verbatim). Source: the built-in list (gpt-5.5 &
family), extended/overridden by a ~/.pixir/config.json "models" array of
slugs if present. The active default_model/0 is always included and flagged
default: true (so the client's picker has a default even if config narrows
the list).
Cheaply validate connectivity and the model id: a minimal streamed call (tiny
prompt, no tools). Returns {:ok, %{model: id}} if the backend accepts it, or the
structured error otherwise (e.g. a provider_http_error for a bad model id). Useful
before committing to a full Turn.
Build a Responses request body preview without auth or network.
This uses the same request-shaping path as stream/2, including Provider-hosted
tools, prompt-cache fields, and the px2 developer-context item. Smoke tasks should
still bound/redact the returned body before printing it.
Stream one Responses call, retrying transient failures (network, :rate_limited,
5xx) with capped exponential backoff. Terminal errors (:usage_limit_reached,
:model_not_supported, auth) are not retried. See the module doc for the result
shape. Options: :max_retries (default 2), :sleep (injectable for tests).
Map a tool definition from a __tool__/0 callback to a Responses function tool.
Normalize OpenAI usage payloads into the fields Pixir records as Provider evidence.
Supports the Responses shape (input_tokens_details.cached_tokens) and the legacy
prompt/completion naming used by older examples.