TypeSafe (typesafe_ai v0.1.1)

Copy Markdown View Source

An Elixir client for the TypeSafe AI System One API.

Designed for latency-sensitive applications. Evaluate shared state with Choice, Score, and Noul questions, and receive validated, typed answers.

Start a TypeSafe.Client under your application's supervisor, then call system_one/2. Supervised connections, bounded concurrency and queues, request deadlines, configurable retries, and telemetry give you explicit control over how your application handles load. You receive TypeSafe.Response and typed answer structs. The client handles authentication and uses Mint directly. Elixir 1.18+ and Erlang/OTP 27+ are required; encoding uses native JSON.

Example

With a client registered as MyApp.TypeSafe:

TypeSafe.system_one(MyApp.TypeSafe,
  state: %{message: "Please refund the duplicate charge."},
  questions: %{
    "team" => TypeSafe.choice("Which team?", %{"billing" => nil, "technical" => nil}),
    "refund" => TypeSafe.noul("Is a refund requested?")
  }
)

Batch independent questions about the same state in one call. For separate states, use bounded tasks sharing a supervised client. See the getting started guide for complete setup, and TypeSafe.Client for capacity and lifecycle behavior.

Summary

Evaluation

Evaluates state and returns {:ok, response} or {:error, error}.

Question helpers

Builds a Choice question with 1–255 named options.

Builds a Noul question, whose answer estimates the probability of yes.

Builds a Score question with 2–10 ordered descriptive levels.

Evaluation

system_one(client, opts)

@spec system_one(GenServer.server(), keyword()) ::
  {:ok, TypeSafe.Response.t()} | {:error, TypeSafe.Error.t()}

Evaluates state and returns {:ok, response} or {:error, error}.

client is a PID or registered name on the calling node. Requests use local monotonic deadlines; remote-node client references return :unavailable.

Options

  • :state (required) — a string, map, or list of JSON-compatible values.
  • :questions (required) — a non-empty map from non-empty string IDs to TypeSafe.Question structs built with the question helpers.
  • :model — a non-empty model identifier overriding the client default.
  • :timeout — a positive overall deadline in milliseconds, overriding the client default. It starts after input encoding and includes queueing, connecting, uploads, response collection, and retry waits.
  • :retry — a TypeSafe.Retry struct or keyword policy. An override replaces the client policy; omitted fields use the retry defaults. Set retry: [max_attempts: 1] to disable retries.

Unknown options are rejected. API keys are configured per client, never per request. Invalid questions or unencodable inputs produce validation errors before contacting the client. Custom structs require a native JSON.Encoder implementation or conversion to plain JSON-compatible data.

Successful answers preserve question IDs and option labels as strings. The response type depends on each question; see TypeSafe.Response. Match the :kind and :status fields of TypeSafe.Error for failures, rather than matching message text. An ambiguous transport failure is not retried by default.

Examples

Invalid input is rejected without accessing a client:

iex> {:error, error} = TypeSafe.system_one(:unused_client, state: "Hello", questions: %{})
iex> error.kind
:validation

Question helpers

choice(instructions, criteria)

Builds a Choice question with 1–255 named options.

instructions can be a string, JSON-compatible map, or list. criteria is a map of non-empty string labels to descriptions; a description may be a string, map, list, or nil when the label needs no explanation.

Construction performs no network I/O or validation. system_one/2 validates the question before submitting it. Answers use TypeSafe.Answer.Choice.

Examples

iex> question = TypeSafe.choice("Which team?", %{"billing" => "Payments", "technical" => nil})
iex> question.type
:choice
iex> question.criteria["billing"]
"Payments"

noul(instructions, criteria \\ nil)

@spec noul(TypeSafe.Question.entry(), map() | nil) :: TypeSafe.Question.t()

Builds a Noul question, whose answer estimates the probability of yes.

Optional criteria must contain exactly the string keys "true" and "false". Omit criteria when the instructions alone explain the decision. The returned TypeSafe.Answer.Noul contains a value from 0 to 1, without a separate confidence. The caller chooses any threshold used to turn that probability into a decision.

Examples

iex> question = TypeSafe.noul("Is a refund requested?")
iex> {question.type, question.criteria}
{:noul, nil}

iex> question = TypeSafe.noul("Urgent?", %{"true" => "Work is blocked", "false" => "Can wait"})
iex> question.criteria["true"]
"Work is blocked"

score(instructions, criteria)

Builds a Score question with 2–10 ordered descriptive levels.

Level indices start at zero. A returned score is probability-weighted and may fall between levels; with three levels its range is 0–2, not 0–1 or 0–3. Instructions and level descriptions can contain structured JSON values.

Questions are validated by system_one/2. Answers use TypeSafe.Answer.Score.

Examples

iex> question = TypeSafe.score("How urgent?", ["Routine", "Today", "Immediately"])
iex> question.type
:score
iex> Enum.at(question.criteria, 2)
"Immediately"