Client for System One decision models: TypeSafe Jev, Cloudflare Clef, OpenAI's Decisions
API, OpenRouter's decisions endpoint, and any self-hosted /v1/systemone server such as CLM.
Ask typed questions (noul, choice, score) about arbitrary JSON state and get
typed answers back with their full probability distributions. SystemOneClient.HTTP
talks to a provider (see SystemOneClient.Provider); SystemOneClient.Stub returns
canned answers for tests. Question maps follow the API wire shape verbatim; this
library does not invent its own schema for them.
{:ok, answers, meta} = SystemOneClient.evaluate(state, questions, provider: :cloudflare)
answers["tool"].probabilities
Summary
Types
Errors returned by SystemOneClient.HTTP.
Options accepted by evaluate/3. See the README for defaults.
A question in the System One wire format, for example
%{"type" => "choice", "instructions" => "...", "criteria" => %{"a" => "...", "b" => "..."}}.
Keys may be strings or atoms.
A question id. Answers are keyed by its string form.
Functions
Evaluates questions with the configured client (opts[:client], else app env :client, else HTTP).
Checks every question has a known type. Ids may be atoms or strings.
Types
@type answers() :: %{required(String.t()) => SystemOneClient.Answer.t()}
@type error() :: :missing_api_key | :missing_account_id | :missing_url | {:unknown_provider, term()} | {:invalid_question, String.t(), :unknown_type | :not_a_map | :missing_criteria} | {:http, non_neg_integer(), term()} | {:transport, term()} | {:malformed_answers, term()} | {:malformed_envelope, term()} | {:provider_error, list()}
Errors returned by SystemOneClient.HTTP.
@type meta() :: %{ optional(:provider) => SystemOneClient.Provider.name(), model: String.t() | nil, usage: map() | nil, latency_ms: non_neg_integer() }
@type option() :: {:client, module()} | {:provider, SystemOneClient.Provider.name()} | {:api_key, String.t() | nil} | {:account_id, String.t()} | {:url, String.t()} | {:model, String.t()} | {:receive_timeout, timeout()} | {:max_retries, non_neg_integer()} | {:retry_delay_ms, non_neg_integer()} | {:plug, term()} | {:env, %{optional(String.t()) => String.t()}} | {:answers, map() | (term(), questions() -> map() | {:error, term()})}
Options accepted by evaluate/3. See the README for defaults.
@type options() :: [option()]
@type question() :: map()
A question in the System One wire format, for example
%{"type" => "choice", "instructions" => "...", "criteria" => %{"a" => "...", "b" => "..."}}.
Keys may be strings or atoms.
A question id. Answers are keyed by its string form.
@type questions() :: %{required(question_id()) => question()}
Callbacks
Functions
Evaluates questions with the configured client (opts[:client], else app env :client, else HTTP).
@spec validate_questions(map()) :: :ok | {:error, {:invalid_question, String.t(), :unknown_type | :not_a_map}}
Checks every question has a known type. Ids may be atoms or strings.
iex> SystemOneClient.validate_questions(%{"q" => %{"type" => "noul", "instructions" => "?"}})
:ok
iex> SystemOneClient.validate_questions(%{"q" => %{"type" => "guess"}})
{:error, {:invalid_question, "q", :unknown_type}}