Jev · System One · explained Docs Français
Interactive course · docs.typesafe.ai read 20 Sept. 2026

Jev and System One, explained step by step

A LLM writes text for humans. Jev, the TypeSafe AI model, does something else: we send it a state and typed questions, it returns structured answers, with probabilities and a level of confidence, which your code uses directly. This course starts from zero and builds, notion after notion, up to patterns, SDKs and known limits.

One request, three questions, one typed answer

Click on a question to see what Jev returns (example of Quick start Documentation).

3
types of questions: Choice Score Noul
≈ 100 ms
for most requests, depending on page How to build
0,042 $ / Mtok
entry for jev-1.13.0 ; output tokens are free of charge
0
generated text: decisions, probabilities, never prose to parse
How to read this course

Modules marked Interactive use values from documentation (recorded replies from jev-1.13.0, tables, examples of code). Illustration Simplify a principle with fictitious values or a calculation reported as such. no network call It never questions the TypeSafe API. The terms of the API remain in English ("state", "choice", "confidence"...). When a point is not documented, the course says so.

Chapter 1

Why a decision model?

You know the LLM by the use: you type a question, you read an answer. code which must consume a judgment, the text becomes an obstacle. It is from this shift that TypeSafe leaves.

In this chapter
  • The gap between "producing text" and "making a decision that can be used by code".
  • Three ways of architecture software with AI: traditional, agent, AI powered software.
  • What Jev promises: typified values, probabilities, confidence.

Text offset / decision

The document introductory page summarizes the problem in one sentence: the large language models are designed for produce text that humans read. As soon as you want a model to render a judgment that the code will consume ("is this ticket urgent?", "what service should treat it?"), you force a text generation system to exit a structured decision, then you re-spend the result to do something that the code may depend on.

Everyone has already written this kind of code: a prompt that begs the model to "respond only by a valid JSON", a regular expression to recover the value, a try/except for the day when the model adds a phrase of politeness. And even when the JSON is clean, one thing is missing: how safe the model is. A LLM can write "urgent" with the same aplomb, whether it is obvious or dice.

Illustration

The same ticket, two ways to make a decision

To the left, a conversational LLM: text to interpret. To the right, Jev: a typed answer. Choose a ticket, then observe what the code receives in each case. The values on the right are those on the right. Quick start and the page Choice The text on the left is a plausible reconstitution, not a real output.

What Jev does instead

Jev is the flagship model of TypeSafe and the first model said System OneIt evaluates the questions typed against one state (the content to be judged) and returns structured results: no text generation, no parsing. The code receives typed values and probability distributions on which it can connect, sort, route. Choice and Score questions also refer to a "confidence", a number between 0 and 1 that the code uses to decide if it does, and how.

state + typed questions one request TypeSafe model (Jev) Choice: which department? Score: what level of frustration? Noul: is it urgent? each question is evaluated in parallel against the same state typed responses + probabilities + confidence (Choice, Score) → your code branches, sorts, and routes
Redrawed diagram from the diagram of the page Introduction : a request, an answer, and the code keeps its hand.

Three software architectures

Page How to build with TypeSafe Jev place in a three-box landscape. We must understand which Jev is aiming, because it is not not the agent's.

Interactive

Traditional, agent, or software powered by AI?

Click on each architecture to see who decides the next step and where the AI slides. The descriptions take up the three tabs of the documentation.

Doc · How to build Traditional software, agents, and AI-powered software shown as three different system architectures. Traditional software, agents, and AI-powered software shown as three different system architectures.
Original illustration (page /concepts/how-to-build-with-system-one) : traditional software, LLM agents and software powered by AI, seen as three different architectures.
To be retained

Jev is designed to build software powered by AIHe doesn't generate code, he doesn't choose his next action, he doesn't write anything. AI primitives The code keeps control of the flow, the model renders judgment of common sense on unstructured data.

Quiz · chapter 1
What does Jev ever do?
Chapter 2

System One: the idea and training

Where the name comes from, what "calibrated" means, and why TypeSafe invented a third post-training path next to the RLHF and RLVR.

In this chapter
  • System 1 / System 2: quick judgments, not long reasoning.
  • Calibration: A probability of 0.8 must be verified 80% of the time over a set of predictions.
  • RLHF, RLVR, RLCD: three training objectives, three types of models.

The name comes from Kahneman

Page System One explains: the name takes over the concept popularized by Daniel Kahneman in Thinking, Fast and Slow. System 1 is fast and intuitive; System 2 is slow and deliberate. Jev is firmly placed in the first: judgments rapid and targeted, the kind of thing that a competent person decides in a second when it is given the right context.

It is a design rule as well as a name. "Is this message urgent?" is a good question. "Analysing this message and determining the best course of action" is not one: it requires slow reasoning, and the documentation sees it as the signal that needs to be done. cut the task in small questions, then compose the answers in the code.

Like an LLM, a System One model includes natural language in the input. Unlike an LLM, it returns typed decisions and probabilities, not text. Two documented limits: Jev accepts only text (chains, JSON objects, text tables; neither image, audio, or video "for now"), and its main training language is English, with other languages being accepted with less precision.

Calibrated: what it means, and what it does not guarantee

The word comes back everywhere in the documentation: Jev is trained for calibrated decisions. Its probabilities are optimized against real results to reflect uncertainty. Specifically, on a large number of predictions of a well calibrated model:

  • the outcomes to which it attributes a probability of 0.2 occur about 20% of the time;
  • those to 0.8, about 80% of the time;
  • those to 1.0100% of the time.

The documentation immediately adds the nuance that counts: these rates describe groups The calibration of predictions. does not guarantee a response taken in isolation. A confidence of 1.0 describes the model's response, not proof that it is fair.

Illustration

What does "calibrated" mean on a set of predictions?

Choose an announced probability and a number of predictions: the module draws fictional outcomes at random with this rate and compares the observed frequency with the predicted probability. It is a pedagogical simulation of the definition, not a measure of Jev.

Three post-training paths

L'AI primer TypeSafe bet: large-scale automation will be dominated by interactions IA-to-IA and IA-to-software, about 99% machine-to-machine and 1% human. The machine interface therefore counts more than the chat interface. TypeSafe calls this Machine Native Intelligence : an AI with software properties, structure, reliability, observability, testability, speed, consistency, low cost. The formula of the page: " Building prod, not God build for production, not a model that does everything.

RLHF
Learning by human return

Transformed pre-entry models into chatbots: they learn how to produce the answers people prefer. The page recalls that the RLHF was co-invented by Diogo Almeida, co-founder of TypeSafe.

RLVR
Verifiable awards

Produced the models of reasoning, strong in mathematics for example, but slower and more expensive.

RLCD
Calibrated decisions

The Path of TypeSafe: Reinforcement Learning for Calibrated Decisions. The model does not generate text; it returns decisions and probabilities, and a higher probability must correspond to a greater chance of being right.

Doc · AI primer Pretrained language models branch into muted RLHF and RLVR paths and an emphasized RLCD decision-model path. Pretrained language models branch into muted RLHF and RLVR paths and an emphasized RLCD decision-model path.
Original illustration (page /introduction/machine-learning-primer) : from a pre-entry language model, the RLHF and RLVR paths in retreat, and the RLCD path to a prominent decision model.

The problem of the RLHF, seen by TypeSafe

The RLHF teaches a model to say what people prefer. This goal works well for a chatbot, but it can also reward the sycophancy and the hallucinations said with confidence. Optimizing preferences also causes what the page calls the mode dropping : the model learns to favor a style (follow instructions, for example) and reduces the probability of other possible outputs. It is an attenuated version of the mode collapse GAN, where a generator ends up always producing the same type of output because it continues to deceive the discriminator.

The conclusion of the page is measured: the RLHF remains a good choice for conversational models. But an output can be convincing for a person without being reliable enough for unsupervised automation. Human preference and machine reliability are two different optimization targets; automation in production requires, according to TypeSafe, an objective centered on constraints and calibrated uncertainty.

Doc · AI primer The probability distribution of a base model compared with a narrowed, mode-dropped distribution after RLHF. The probability distribution of a base model compared with a narrowed, mode-dropped distribution after RLHF.
Original illustration (same page): the probability distribution of a basic model, compared to the narrow distribution after RLHF (mode dropping).
What the documentation does not say

The documentation describes the objective of the LCDR (decisions + calibrated probabilities) but not the training recipe : neither the data, nor the reward function, nor Jev's architecture, nor its size. The course does not invent anything about it. The page Models only specifies that Jev is neither fine-tuned nor adapted by LoRA with customer data: the same weights serve all accounts, and the adaptation to the domain passes through the request (state, instructions, criteria).

Quiz · chapter 2
Jev returns a probability of 0.8. What does calibration guarantee?
Chapter 3

Anatomy of a request and an answer

Before detailing each type of question, let's look at the form of a full exchange with the API: three input fields, one answer per question in output.

In this chapter
  • The three fields of any request: state, model, questions.
  • Question IDs: selected by you, never seen by the model.
  • The answer: model, answers, usage.

One request

Everything goes through a single point of entry, POST https://api.typesafe.ai/v1/systemone, with a header API key Authorization: BearerThe JSON body always has the same high-level shape:

  • state : the content to be evaluated. A string, object or table (Chapter 4).
  • model : the model that processes the request, for example "jev-latest" (chapter 17).
  • questions : one map You choose each key; the answers return under the same keys.

Each question has a type (choice, score or noul), the instructions (the question asked) and, depending on the type, criteria (options, levels, or definition of yes and no).

Interactive

The request and answer of the Quick Start, annotated

Click on an item in the list to highlight it in the JSON and read what it does. Query and answer are reproduced as is from the page Quick start.

The identifier is not sent to the model

The documentation repeats it on each primitive page: the key you choose (department, is_urgent...) is used for your code to find the answer. The model doesn't see it. Write the complete question in instructionsEven when the identifier seems to be talking about himself.

Answer

The answer contains three fields: model, the versioned identifier of the model that responded (e.g. jev-1.13.0, even if you asked jev-latest) ; answers, one entry per question, under your identifiers; and usage, the number of tokens in and out. Each response has a type which corresponds to the type of the question, then to the fields specific to the type:

TypeWhat he answersFields returnedHow to read it
ChoiceWhich of these options?choice, probabilities, confidencechoice is the most likely option; probabilities distribution on all options; confidence sums up the extent to which this distribution is piqued.
ScoreWhich level?score, legend, probabilities, confidencescore is a position along your levels, which can fall between two; legend Reminds the levels by number.
NoulIs that true?noulThe probability that the answer is yes. Nearly 1 : yes frank ; near 0 : no frank ; close to 0.5 : uncertain. confidence Separated.

Two properties make these responses composing, and the literature highlights them:

  • Each response is constrained by the options provided. The model returns a distribution on your options or levels, never a value outside. The code never has to recover a value in prose.
  • Each response is independent. The answer to one question is not a hidden context for another. You can add or remove questions without changing the results of others.
Doc · Quick start (cURL)
curl -X POST https://api.typesafe.ai/v1/systemone \
  -H "Authorization: Bearer $TYPESAFE_API_KEY" \
  -H "Content-Type: application/json" \
  -d @- <<'EOF'
  {
    "state": "Hi, I've been trying to connect my Stripe account for 3 days and the integration keeps failing. I'm losing sales. Please help ASAP.",
    "model": "jev-latest",
    "questions": {
      "urgency": {
        "type": "noul",
        "instructions": "Does this message express urgency?"
      }
    }
  }
EOF
Quiz · chapter 3
What the key is for "is_urgent" in the map questions ?
Chapter 4

The "state": what we give to judge

The state is the raw material: a message, a passage, or the current state of your application. The documentation advises to structure it, to put only the necessary, and to point the questions to its parts by paths.

In this chapter
  • Three formats: string, object, array, and when to use each.
  • Separate the content (state) from the judgements (questions).
  • Reference a specific field with a path between serious accents: `ticket.messages[0].text`.

Chain, object or table

The simplest state is a chain: "My card was charged twice.". But it can also be a JSON object or table containing context, examples, linked records. The image proposed by the page State : think of the status as the file you would present to a panel of experts before asking them for a judgment.

FormatUseful forExample (documentation)
ChainA message, an article, a passage"My card was charged twice."
ObjectNamed fields, linked records, status of application{"message": "My card was charged twice.", "order_id": "A-104"}
ArrayA sequence of messages or recordings["Hi", "My customer number is TS1337.", "My card was charged twice."]

The Documentation Board: use an object for most queries, so that each part of the state has a descriptive name and its relationships remain clear. The chain is suitable when the case is simple and requires only one text. A query evaluates one against one or more questions; all questions see the same state and are assessed independently.

Interactive

Compose a state and point to a question

Choose a format, then click on a part of the structured state: the question that is about it appears, with the path between serious accents that the documentation recommends to include as is in the instructions. The example is the page support conversation State.

Separate the content of the questions

The state contains the content and the supporting facts; the questions define the judgements to be carried on. The example of the doc: keep the claim for reimbursement and the refund policy in the state, then ask on one side whether the client requests a refund, on the other side if the policy allows. Two Nols, only one state.

Refer to a specific field

When the state is a multi-party object, a question often relates to one of them. Primitives request to appoint her in the instructions with a "point and index" path to its key, including backticks : `ticket.messages[0].text`, `order.charges`. The model then knows what part of the state to judge.

Doc · Primitives, « Reference specific fields »
questions = {
    "refund_requested": {
        "type": "noul",
        "instructions": "Does `ticket.messages[0].text` request a refund?",
    },
    "policy_supports_refund": {
        "type": "noul",
        "instructions": (
            "Does `refund_policy` support the refund requested "
            "in `ticket.messages[0].text`, given `order.charges`?"
        ),
    },
}
Two rules from the "How to build" page on the state

Unpack the entrance : include only context relevant to the questions being asked. This prevents distractions and what the documentation calls context rot, the loss of precision when the state grows with unrelated content. Do not rely on the memory of the model : when an up-to-date information exists in your knowledge base, put it in the state rather than hope it is in the weight.

Quiz · chapter 4
You must judge a ticket in the light of an order and a refund policy.
Chapter 5

Choice : choose an option from a set

The first primitive. You give the list of possible options; Jev returns the one he retains, a probability for each, and a confidence.

In this chapter
  • When to use a Choice: an answer among a fixed set, without order between options.
  • The form of the question (criteria = map option → description) and the answer.
  • Read a shared distribution between two teams, and what the code does with it.

When

A Choice serves when the answer is one of a fixed set of options : which team processes a ticket, which category of a product belongs to, in which language is written a code extract. If the answer is a position on a spectrum, it is a Score; if it is yes or no, a Noul. Examples of questions given by the page:

  • « What programming language is this code written in » → python, javascript, typescript, go, rust, other
  • « What type of meeting is this based on the title and description » → standup, planning, retrospective, one on one, brainstorm, none of the above
  • « Which product category does this item belong to » → electronics, clothing, home garden, food and beverage

Note the options other and none of the above The doc recommends adding one when the list may not cover all entries, so that the model can say that none is appropriate.

The form

A Choice has three fields: type (always "choice"), instructions (the question) and criteria, a map whose each key is an option name and each value a description. Both names and descriptions are sent to the model : Write descriptions that separate the options from each other. A description may be null when the name is sufficient (example of the doc: {"calm": None, "frustrated": None, "angry": None}) A Choice accepts up to 255 options.

Doc · Choice, basic example (Python); JavaScript version derived from the Quickstart SDK JS
from typesafe_sdk import Choice, TypeSafeClient

with TypeSafeClient() as client:
    response = client.system_one(
        state="My running shoes arrived in the wrong size. Can I swap them for a size 10?",
        questions={
            "department": Choice(
                instructions="Which team should handle this?",
                criteria={
                    "returns": "Exchanges, wrong or damaged items",
                    "shipping": "Delivery status, delays, lost packages",
                    "billing": "Charges, invoices, payment problems",
                },
            ),
        },
    )

    print(response.answers["department"].choice)
import { choice, TypeSafeClient } from "@typesafe-ai/sdk";

const client = new TypeSafeClient();
const response = await client.systemOne({
  state: "My running shoes arrived in the wrong size. Can I swap them for a size 10?",
  questions: {
    department: choice("Which team should handle this?", {
      returns: "Exchanges, wrong or damaged items",
      shipping: "Delivery status, delays, lost packages",
      billing: "Charges, invoices, payment problems",
    }),
  },
});

console.log(response.answers.department.choice);
{
  "state": "My running shoes arrived in the wrong size. Can I swap them for a size 10?",
  "model": "jev-latest",
  "questions": {
    "department": {
      "type": "choice",
      "instructions": "Which team should handle this?",
      "criteria": {
        "returns": "Exchanges, wrong or damaged items",
        "shipping": "Delivery status, delays, lost packages",
        "billing": "Charges, invoices, payment problems"
      }
    }
  }
}
Interactive

Explore Saved Choice Responses

Choose a ticket and a question: the bars show probabilities, the value used choice and the confidence, as the documentation reports for jev-1.13.0. The second ticket (five questions including two speculative questions) is the "more complex example" of the Choice page; its exact text is not in the doc's Markdown, only its description is.

Read a shared answer

In the five-question example, department returns returns at 0.61, but billing a 0.35 due to a double rate mentioned in the ticket. The ticket belongs to two teams, and the confidence of 0.42 reflects this sharing. requested_resolution is even more indecisive: refund 0.40, replacement 0.34, exchange 0.24, confidence 0.20; the client does not say what he wants. The code of the doc has three consequences:

  • under 0.3 confidence over department, we do not assign : a person sorted ;
  • a second team that has more than 0.25 probability receives a copy;
  • under 0.5 confidence over requested_resolution, on asks the customer Instead of guessing.
Doc · Choice, "A more complex example" (extract from the sorting function)
def triage(ticket: str) -> None:
    with TypeSafeClient() as client:
        response = client.system_one(
            state=ticket,
            questions=TRIAGE_QUESTIONS,
        )
    answers = response.answers

    department = answers["department"]
    if department.confidence < 0.3:
        # Not clear which team to send to. Let a person decide.
        send_to_manual_triage(ticket)
        return

    if department.choice == "returns":
        # return_reason answer is only used here
        assign(ticket, team="returns", issue=answers["return_reason"].choice)
    elif department.choice == "shipping":
        # shipping_issue answer is only used here
        assign(ticket, team="shipping", issue=answers["shipping_issue"].choice)
    else:
        assign(ticket, team="billing")

    # A second team with a real share of the probability gets a copy
    for team, probability in department.probabilities.items():
        if team != department.choice and probability > 0.25:
            notify(ticket, team=team)

    resolution = answers["requested_resolution"]
    if resolution.confidence < 0.5:
        # The customer hasn't said what they want. Ask, don't guess.
        ask_customer_what_they_want(ticket)
    elif resolution.choice == "refund":
        flag_for_refund_approval(ticket)

    if answers["tone"].choice == "angry":
        flag_for_senior_agent(ticket)
One request, five replies, and the if ordinary

Two of the five questions are: Speculative : return_reason only if the service is returns, shipping_issue that if he is shipping. They are asked anyway, because the questions are evaluated in parallel and the code does not know what it does not need. If tomorrow you need the language of the client or the product concerned, you add an Choice: the number of requests remains at one. It's the pattern Speculative fan-out of chapter 12.

Structured descriptions

Start with one line of description per option. When two options are similar and the model confuses them, the doc advises to describe each one by one. object rather than a string: a field for what the option covers, one for what belongs to the next option, some examples. Field names (what, not_for, examples, question, focus...) are not part of the API and are not reserved: you choose them, the model sees them with values, so prefer short names that label the following. return_policy and return_status, two options that both talk about returns; with contrasting objects, the answer is return_status 1.0%.

Quiz · chapter 5
In criteria of a Choice, what does the model see?
Chapter 6

Score : situate the state on ordered levels

The second primitive answers "what level?". You describe bearings, from the lowest to the highest; Jev returns a position, which may fall between two, plus one probability per level.

In this chapter
  • Levels: an orderly array of descriptions, numbered 0, 1, 2... by their position.
  • score = average of the level numbers weighted by their probability.
  • Write good levels, and cut a composite judgment into several Scores.

When

A Score serves when the answer is a position on a spectrum that you can describe in steps : the severity of a bug, the satisfaction of a client, the Python experience of a candidate. criteria is a level, described in words. The number of a level is its position in the table from 0: three entries make levels 0, 1 and 2. It takes at least two levels; the API accepts up to 10.

Important detail given by the page: the model receives descriptions and nothing else, and each level is judged separately He sees neither the level number nor his neighbors. "Worse than the previous level" means nothing to him.

Doc · Score, basic example (Python); JavaScript derived with the helper score() of SDK JS
from typesafe_sdk import Score, TypeSafeClient

with TypeSafeClient() as client:
    response = client.system_one(
        state="The export button crashes the settings page in Safari. It works in Chrome, but a few of our customers only use Safari.",
        questions={
            "bug_severity": Score(
                instructions="How severe is the reported issue?",
                criteria=[
                    "Cosmetic; no impact to functionality",
                    "Broken or degraded feature, but workaround exists",
                    "Blocking issue; no workaround exists",
                ],
            ),
        },
    )

    print(response.answers["bug_severity"].score)
import { score, TypeSafeClient } from "@typesafe-ai/sdk";

const client = new TypeSafeClient();
const response = await client.systemOne({
  state: "The export button crashes the settings page in Safari. It works in Chrome, but a few of our customers only use Safari.",
  questions: {
    bug_severity: score("How severe is the reported issue?", [
      "Cosmetic; no impact to functionality",
      "Broken or degraded feature, but workaround exists",
      "Blocking issue; no workaround exists",
    ]),
  },
});

console.log(response.answers.bug_severity.score);
{
  "model": "jev-1.13.0",
  "answers": {
    "bug_severity": {
      "type": "score",
      "score": 1.43,
      "confidence": 0.35,
      "legend": {
        "0": "Cosmetic; no impact to functionality",
        "1": "Broken or degraded feature, but workaround exists",
        "2": "Blocking issue; no workaround exists"
      },
      "probabilities": { "0": 0.0, "1": 0.57, "2": 0.43 }
    }
  },
  "usage": { "input_tokens": 332, "output_tokens": 18 }
}
score = Σlevel number × probability = 0 × 0.0 + 1 × 0.57 + 2 × 0.43 = 1.43 The score is the average of the level numbers weighted by their probability (page ScoreA score of 1.43 means that the model is shared between levels 1 and 2, leaning towards the 1: Export is broken, switching to Chrome is a bypass for most customers, but not for those who only have Safari.
Interactive

Five bug reports, five scores

The reports and values are those of the "Reading a Score" table in the documentation. Click on a report: the score position on the level axis and the distribution are updated. The last button shows what happens when the levels are only numbers.

A score is not a measure of the thing

In the third and fourth example, the probability is divided between levels 1 and 2. More weight on the 2 makes the score rise, but it does not measure the fraction of customers without circumventionAnd different distributions can give the same score: 1.0 can mean "all on Level 1" or "half on the 0, half on the 2". Read probabilities and confidence next to the score to distinguish them. Jaggedness adds: do not use the score to reconstruct an exact size between two levels; a threshold, yes, an interpolation, no.

Write good levels

  • Describe situations, not degrees. "Function broken or degraded, but a bypass exists" gives the model something to compare to the state. "Moderately serious" does not give anything.
  • No numbers. With criteria: ["0", "1", "2"] and the "Rate severity from 0 to 2" statement, the report of the misaligned button gets 0.55 at confidence 0.33 (shared probability between 0 and 1). With the three descriptive levels, it gets 0.0 at confidence 1.0.
  • As many levels as you can describe separately, up to 10. Three is good. Do not add a level that you can't distinguish.
  • A dimension by Score. "Punctual and brilliant and experienced" measures three things; a high entry on one and bass on the other cannot be placed, confidence falls, the score loses meaning. Separate and combine in the code.
  • Give your own level to a rare extreme case On which you have to act differently: a feeling scale that ends up "very angry" can add "undue or threatening".
  • Test your data. Two formulations on the same scale can behave differently. Higher confidence alone does not prove that a description is better.

Cut a complex judgment into multiple Scores

A judgment that depends on several things breaks down into one Score per thing, sent in the same request (they are evaluated in parallel, it costs a few tokens of question). The code then combines the scores with weights that belong to it. The example of the doc: priority of a ticket from three Scores, gravity (3 levels), frustration (3 levels) and quality of the ratio (4 levels). normalizes each score by dividing it by its maximum level number, len(criteria) - 1, to bring everything back from 0 to 1.

Interactive

Priority of a ticket = weighted sum of three standardized Scores

The three scores (1.24 / 1.28 / 3.0) are those which the documentation returns for the ticket of the spinner. Move weights: priority is recalculated as in function priority() With the weight of the doc (0.6 / 0.3 / 0.1), it is 0.664, rounded 0.66.

Doc · Score, « Splitting a complex judgment into several Score questions »
def normalized(answers, question_id: str) -> float:
    """Put a score on 0 to 1 by dividing by its top level number."""
    top_level = len(TRIAGE_QUESTIONS[question_id].criteria) - 1
    return answers[question_id].score / top_level

def priority(ticket: str) -> float:
    with TypeSafeClient() as client:
        response = client.system_one(
            state=ticket,
            questions=TRIAGE_QUESTIONS,
        )
    answers = response.answers

    severity = normalized(answers, "severity")
    frustration = normalized(answers, "frustration")
    report_quality = normalized(answers, "report_quality")

    # A detailed report helps an engineer investigate, so it raises priority a little.
    return 0.6 * severity + 0.3 * frustration + 0.1 * report_quality

Structured levels

When the model continues to place between two levels adjacent to the entries that you think are clear, give each level one object: one field for what the level covers, another with some example situations, the same field names on all levels. The doc's picture on the Safari report is eloquent:

Description of levelsscoreconfidence
Single strings, not applicable or examples1.430.35
Objects with a useful example: "export fails in one browser but works in another"1.030.96
Objects with an unrelated example: « search fails, but browsing categories still works »1.430.35

The example that looks like real entries concentrates almost all probability on a level; the unconnected example does not change anything. And the caution of the page: a higher confidence does not establish what answer is correct. Choose examples of which you know the expected level, then test the revised descriptions on other entries before keeping them.

Quiz · chapter 6
Why criteria: ["0", "1", "2"] Is there a bad idea for a Score?
Chapter 7

Noul : the probability that the answer is yes

The third primitive is the simplest in appearance: a closed question, a number between 0 and 1. Its subtlety lies in what this number measures, and in the threshold that your code chooses.

In this chapter
  • A Noul returns noul, the probability of yes. confidence separated, and why.
  • The threshold depends on the cost of the error; the values of the medium can go to a person.
  • A Noul is not a scale: "Is the candidate strong in Python?" does not measure the experience.

When

A Noul serves when the answer is yes or no: does this message require a refund, does this CV mention distributed systems, does this comment contain personal data. Fields: type ("noul"), instructions (the question, or a statement to be judged) and, as an option, criteria, an object with descriptions true and false what a yes and a no mean.

Doc · Noul, basic example (Python); JavaScript derived with the helper noul() of SDK JS
from typesafe_sdk import Noul, NoulCriteria, TypeSafeClient

with TypeSafeClient() as client:
    response = client.system_one(
        model="jev-latest",
        state="I have asked three times now. Can I please just talk to a real person?",
        questions={
            "is_human_escalation": Noul(
                instructions="Is the customer asking for a human agent?",
            ),
            "is_repeat_contact": Noul(
                instructions="Has the customer contacted support about this before?",
                criteria=NoulCriteria(
                    true="Mentions a prior attempt, ticket, or that they have asked before",
                    false="No sign of any previous contact",
                ),
            ),
        },
    )

    print(response.answers["is_human_escalation"].noul)
    print(response.answers["is_repeat_contact"].noul)
import { noul, TypeSafeClient } from "@typesafe-ai/sdk";

const client = new TypeSafeClient();
const response = await client.systemOne({
  state: "I have asked three times now. Can I please just talk to a real person?",
  questions: {
    is_human_escalation: noul("Is the customer asking for a human agent?"),
    is_repeat_contact: noul("Has the customer contacted support about this before?", {
      true: "Mentions a prior attempt, ticket, or that they have asked before",
      false: "No sign of any previous contact",
    }),
  },
});

console.log(response.answers.is_human_escalation.noul);
console.log(response.answers.is_repeat_contact.noul);
{
  "model": "jev-1.13.0",
  "answers": {
    "is_human_escalation": { "type": "noul", "noul": 0.99 },
    "is_repeat_contact": { "type": "noul", "noul": 0.93 }
  },
  "usage": { "input_tokens": 360, "output_tokens": 39 }
}

Read a Noul: the answer and the certainty in one number

Nearly 1, a frank yes. Nearly 0, a non-france. Nearly 0.5, the model gives the yes and the no a similar probability. no confidence separated, unlike Choice and Score : the distribution of a Noul has only two issues, so the only value noul The page gives six saved messages for the question "Is the customer asking for a human agent?"; the module below reproduces them.

Interactive

Six messages, one threshold, three destinations

Values noul are those in the "Reading a Noul" table of the documentation. Move the thresholds NO and YES page code (0.2 and 0.8 by default) and look at what messages go to the bot, an agent, or a person who slices.

Doc · Noul, « Handling multiple Noul answers in code »
YES = 0.8
NO = 0.2

def route(message: str) -> None:
    with TypeSafeClient() as client:
        response = client.system_one(
            model="jev-latest",
            state=message,
            questions=SUPPORT_QUESTIONS,
        )
    answers = response.answers

    wants_human = answers["is_human_escalation"].noul
    repeat = answers["is_repeat_contact"].noul

    if NO < wants_human < YES or NO < repeat < YES:
        # The model isn't sure either way. Let a person decide.
        send_to_review(message)
        return

    priority = "high" if repeat > YES else "normal"
    if wants_human > YES:
        route_to_agent(message, priority=priority)
    else:
        route_to_bot(message, priority=priority)
Where to place the threshold

The rule on the page: it depends on the cost of the error. 0.5 when yes and no are as easy to assume each other. Higher when acting on a false yes is expensive (call someone on demand, pay back). Lower when missing a real yes is expensive (do not report a security problem). And the values of the environment can go to one person rather than to one of the two ways of code. If the readers see too many messages, narrow the gap between NO and YES ; if too many bad routings pass, it is enlarged.

A Noul is not a ladder

The value ranges from 0 to 1, but this is not a measure of the requested thing: it is the probability that the answer is yes. If the question is actually a question of degree, the value does not measure the degree. The doc compares, out of four candidates, the Noul "Is the candidate strong in Python?" and a Four Level Score (no experience, some familiarity, regular use at work, deep expertise):

Interactive

Four candidates: Noul "strong" against "experience" score

Click on a candidate. Noul judges a single proposal, "strong in Python", and returns its probability; the Score judges each level you wrote. Values of the page Noul.

One could, in the code, cut the 0–1 interval into slices ("0.3 to 0.7 = some experience"), but the model would not see them: nothing in its answer was judged against them. A median value may mean "average experience" or "miscellaneous case", and the spacing between candidates is not something you have chosen. With the Score, each candidate lands on or near a level you have written, and if you do not agree, you reformulate a level and restart.

Write a question Noul

  • A question by Noul. "Is the client angry? and Does he ask for a refund?" forces the model to judge two things at a time. Two Nouls, combined in the code.
  • A high value must mean yes. "Does the message contain personal data?" is clear. "Is the message free of personal data?" reverses the meaning and code that reads it will be wrong.
  • A statement works as well. For "The customer is requesting a refund", a value close to 1 means that the statement is true. Try both on your data.
  • Make the border clear. « Does this candidate have any Python experience?" does not leave a middle. When the border is subtle, add criteria with true and false ; otherwise, the instruction alone is often enough.

Structured instructions, code-generated questions

The instructions can be an object: the question in one field, reference data in the others. The example of the page compares a CV that has just arrived at records of a candidate database, one question Noul per sheet, all in a single request, with the card identifier in the key to the question. Answers reported: sheet 18 (name spelled differently, same city, same employer) gets 0.74; sheet 42 (same name, other city, other employer) 0.09; sheet 77 (near name, same place, other employer) 0.08.

Doc · Noul, « Structured instructions »
SAME_PERSON = "Is the resume for the same person as `potential_duplicate`?"

def duplicate_questions(candidates: list[dict]) -> dict[str, Noul]:
    """One Noul per candidate record, all asking the same question."""
    return {
        f"same_as_record_{candidate['id']}": Noul(
            instructions={
                "potential_duplicate": {
                    "name": candidate["name"],
                    "location": candidate["location"],
                    "last_employer": candidate["last_employer"],
                },
                "question": SAME_PERSON,
            },
        )
        for candidate in candidates
    }

def find_duplicates(resume: dict, candidates: list[dict]) -> list[str]:
    with TypeSafeClient() as client:
        response = client.system_one(
            model="jev-latest",
            state={"resume": resume},
            questions=duplicate_questions(candidates),
        )
    return [
        question_id
        for question_id, answer in response.answers.items()
        if answer.noul > 0.7
    ]
Quiz · chapter 7
Why does a Noul answer have no field confidence ?
Chapter 8

Choose the right type, and structure when needed

Three primitives, so three forms of response. The rule of documentation is in one sentence: take the one whose answer is directly actionable by your code. Then, when a string is not enough, put the JSON structure in the questions.

Interactive

What kind of question?

Describe the form of the expected answer; the module proposes the primitive and recalls the corresponding advice from the page Primitives. It only applies the rules of documentation.

The rule

  • Choice when the answer is an option of a known set, without order between them. Give the complete list, more other if she can't cover it all.
  • Score when the answer falls on a spectrum that you can describe each point.
  • Noul for a net yes/no where the probability itself is the useful signal.

If two types seem to be suitable, prefer the one whose answer is used directly: a Choice between refund, rebook and information connects on three paths of code; a frustration score compares to a threshold; a Noul plugs in on a if.

Where the structure is accepted

Page Advanced: structure says System One models are trained to understand the structure, and lists the fields that accept it. EntryType : string, object, array or null.

FieldApplies toForm accepted
instructionsChoice, Score, Noulstring, object, array or null
values of criteria (option descriptions)Choicesame
entries of criteria (level descriptions)Scoresame
criteria.true and criteria.falseNoulsame

When to use structure

Page How to build gives three situations: the question needs context or examples (a long sentence of context or a list of examples goes into fields named next to the question, which the code can modify without rewriting the question); part of the question comes from the code (a value read in the base goes into its own field rather than in a string template); several questions have neighbouring instructions (additional data make them separate). remains a chain.

A table also works, when the instruction is a list of things to check or compare:

Doc · Advanced: structure
"instructions": {
  "question": "Does the claimed sender identity conflict with the sending domain?",
  "compare": ["ticket.sender.display_name", "ticket.sender.email"],
  "focus": "Compare the named organization with the email domain."
}

Browse a taxonomy with Choices

To classify in a deep taxonomy, the doc proposes One Choice by Level, by browsing the tree in the code : at each step, the options are the children of the current node, and the value of each option is the subtree of the child. The model thus sees what lives under a branch before committing itself to it, which counts when the article belongs to a leaf whose name does not guess from the branch. The example : a gourd that can go under Sporting Goods > Cycling > Bike Bottles & Cages or Home & Kitchen > Drinkware > Water Bottles ; the probabilities If a subtree is too large, it is reduced to its direct children and to a sample of leaves.

Illustration

Descending a taxonomy, one Choice at a time

Click on a branch to descend: at each level, the code builds a new Choice whose options are the children of the node. The tree and probabilities are fictitious; the principle, the branch selection by the code, is that of the page Advanced and cookbook Hierarchical classification.

Quiz · chapter 8
"Is this candidate strong in Python?" in Noul returns 0.5. What to do?
Chapter 9

"Confidence": the form of distribution, in a number

Any Choice or Score answer contains probabilities. The form of this distribution says how safe the model is; confidence sum it up in a number of 0 to 1 so that the code can set a threshold without doing the calculation.

In this chapter
  • Focus on an exit = confident; spread = uncertain.
  • confidence is derived from probabilities ; the doc does not publish the formula and leaves you free to calculate another one.
  • "I don't know" is a useful signal: that's what makes a system reliable.

Derivation of probabilities

Page Confidence Says it straight away: confidence is a statistics calculated from the distribution TypeSafe calculates it and returns it on each Choice and each Score, so the current case does not require anything more. For a Choice, the distribution is about your options; for a Score, about your levels. In both cases, the more flat it is, the lower the confidence: on a Choice, no option clearly outweighs it; on a Score, the levels are ambiguous, the question measures several things, or the state does not say enough.

The formula is not documented

Documentation confidence as a "solid defect" that is suitable for most cases, but specifies that you are never locked in its definition : depending on what you assess, another measure can serve better, and that is why the answer contains the probabilities The advantages and disadvantages of the different calculations are referred to a future cookbook. The module below does not invent a formula: it shows the couples (distribution, confidence) as the doc reports them, and a measure of pedagogical concentration clearly indicated as such.

Interactive

Registered distributions and their confidence

Each line is a real answer cited in the documentation (choice pages, Score, Quick start, API). Click to see the distribution. Below, a sandbox Illustration : spread the probability between three options and observe a fictitious concentration measurement, which is not TypeSafe formula.

"I don't know" is a useful signal

The sentence on the page is worth mentioning: if an intelligent system, human or machine, cannot express an honest uncertainty, it cannot be trusted. confidence is the integrated mechanism by which the model says "not safe for that one". This is what allows the code to have different behaviours depending on the degree of certainty, and it is, according to TypeSafe, the foundation of the systems on which we can really rely.

Keep the limit: a confidence of 1.0 means that the returned distribution puts all the probability on an exit. It describes the model's response, not a guarantee that it is fair.

Quiz · chapter 9
Where the value comes from confidence a Choice answer?
Chapter 10

Act, confirm, climb: thresholds follow the risk

The answer says: what ; confidence says if action is needed. A starting point: three beaches. Then a rule: a threshold is not a single number, it depends on the consequences of the error.

Three paths

  • High confidence: act automatically. The model has a clear reading.
  • Medium confidence: proceed with caution. Request confirmation from the user, report for rereading, or collect more information before taking action.
  • Low confidence: do not act. Route to a person, ask for clarification, or switch to another system. The model says that he lacks information or that the question is not right for him.

Where to trace these borders depends on the stakes. And in the same system, different actions must be kept at different levels. The page Confidence-gated routing the watch with a voice banking interface: consult a balance of 0.6 confidence, it is acceptable (at worst, the user hears a balance he has not requested); approve a transfer requests more than 0.85, otherwise we have confirmed.

Interactive

Trusted Routing: Voice Bank

Choose the intention chosen by the Choice and move its confidence. The two thresholds (floor 0.6, high threshold 0.85) are those of the code of the page; you can move them to see how the system behaves. No real confidence value is given by the doc for this example: confidence is here a cursor.

Doc · Patterns, Confidence-gated routing (step 2)
action = response.answers["intent"]

# Below 0.6 confidence on any action, route to a human
if action.confidence < 0.6:
    route_to_support_agent(account_id)

elif action.choice == "check_balance":
    # Low stakes. 0.6 confidence is sufficient.
    show_balance(account_id)

elif action.choice == "approve_transfer":
    if action.confidence > 0.85:
        # High stakes, but high confidence. Safe to act automatically.
        approve_transfer(account_id)
    else:
        # High stakes, moderate confidence. Verify intent first.
        ask_user_to_confirm("Just to confirm: you would like to approve this transfer, is that correct?")

else:
    route_to_support_agent(account_id)
voice command “transfer €200 to…” TypeSafe evaluates Choice : intent confidence high enough? < 0.6 or another intent → human agent check_balance ≥ 0.6 → display balance approve_transfer 0.6–0.85 → confirm approve_transfer > 0.85 → approve one request, one response: intent + confidence your code
Redrawed diagram from the diagram of the page Confidence-gated routing. The floor of 0.6 catches everything of which the model is not sure; above, each action has its own threshold depending on the consequences of a bad classification.
Thresholds live in your code

The right values depend on your domain and the performance of the model on your case. start careful, test on your data, adjust by observing the results, and checking the thresholds by tracing confidence against accuracy on your own examples. Agent skill adds a caution: if all you care about is taking the best option, simply take the most likely option, without a confidence threshold; and if you have a precise statistical algorithm in mind, work instead on probabilities.

Quiz · chapter 10
In the voice bank, why do not "show balance" and "approve transfer" have the same threshold?
Chapter 11

Building with System One: the code keeps your hand

Page How to build with TypeSafe is the design guide. Its summary: Build a normal software stream and insert System One only where AI is needed. Here are its eight steps, then the complete example that ends them.

In this chapter
  • This makes System One composing: structured, parallel, comparable, fast, calibrated, constant.
  • The eight steps of designing a stream, from "use code when you can" to "route on uncertainty".
  • The complete ticket sorting of the doc, with its weighted spam score.
Structured

Typed by construction: decisions and probabilities respect the types and JSON schema that the code is waiting for. It never has to recover a value in prose.

Parallel

The questions are evaluated independently and in parallel. The result of one primitive does not become a hidden context that changes the result of another.

Comparable

The exits are sorted out and feed if Smart, thresholds, comparisons.

Fast

Most queries end in about 100 ms: enough for a real-time query path or interface.

Sizing confidence

The LCDN communicates uncertainty by calibrated probabilities, rather than tending to excess confidence.

Self-coherent

Designed to return stable responses from one evaluation to another (see the cookbook) Self-consistency, chapter 19).

The page adds a target: a report of intelligence / (speed and cost) greater than 100×, with the bet that cheaper intelligence will create much more demand.

Designing an eight-step flow

Interactive

The eight stages of "Design a System One workflow"

Click on a step to read the rule and its example. The order and content are those of the page; the interactive examples of Playground, absent from the Markdown, are replaced by their description.

The most important step, according to the

Unpack the questions. Ask the most explicit, narrow, specific and atomic questions possible. A broad question hides several judgments behind an answer; atomic questions expose them, so that they can be inspected, settled and combined in the code. And decomposition does not cost going back and forth: questions about the same state run in parallel.

The complete example: sort a ticket

The flow triage_ticket.py of the page keeps determinism in the code (a closed ticket comes out immediately, without a model), only sends the useful structured context (message, sender, links, customer plan, open orders, list of sensitive identifiers), asks seven atomic questions in a single query (a Subject Choice, five Nouls, a Frustration Score), then composes the answers with explicit trusted doors. The following module isolates the part "Spam Risk": three Nouls weighted in the code.

Interactive

Compose three Nouls at a risk of spam

The weights (0.45 / 0.30 / 0.25) and the uncertainty zone (0.4 to 0.6) are those of the code of the page. The values of the three Nouls are sliders: the doc does not give a recorded answer for this flow. Observe the path taken: human editing, quarantine, or subsequent sorting.

Doc · How to build, "Putting it all together" (end of sorting_ticket.py)
    with TypeSafeClient() as client:
        response = client.system_one(
            state=state,
            questions=questions,
        )

    # Compose independent spam signals with weights controlled by code.
    answers = response.answers
    spam_risk = (
        0.45 * answers["requests_credentials"].noul
        + 0.30 * answers["sender_identity_mismatch"].noul
        + 0.25 * answers["unexpected_reward"].noul
    )

    # Escalate uncertain judgments instead of guessing.
    spam_is_uncertain = 0.4 < spam_risk < 0.6
    if spam_is_uncertain or answers["topic"].confidence < 0.75:
        return route_to_human_review(ticket)
    if spam_risk >= 0.6:
        return quarantine_as_spam(ticket)

    # Let code decide which speculative answers matter on this path.
    if answers["topic"].choice == "billing":
        return route_to_billing(
            ticket,
            refund_requested=answers["refund_requested"].noul >= 0.7,
        )
    if answers["topic"].choice == "orders":
        return route_to_orders(
            ticket,
            mentions_open_order=answers["mentions_open_order"].noul >= 0.7,
        )

    priority = (
        "high"
        if answers["frustration"].confidence >= 0.7
        and answers["frustration"].score >= 1.5
        else "normal"
    )
    return route_to_account_support(ticket, priority=priority)

Two details of the same file deserve attention. The questions are all there Structured : each Noul has an object instructions with question, compare or inspect, and focusand the criteria including true and false are objects with what, not_for, examples. And the paths to the state are quoted between serious accents (`ticket.message`, `policy.sensitive_credentials`), as in Chapter 4.

Quiz · chapter 11
An invoice is 45 days late and has to go to the collection.
Chapter 12

The four architectural patterns

TypeSafe is designed to live within a larger system. Thinking about atomic decisions that consist of complex behavior is, says the documentation, the key skill. Four patterns named summarize it.

PatternWhat he doesProfits (doc)
Speculative fan-outSend a lot of questions in one appeal, including speculative ones, and let the code decide what countsCost, speed
Confidence-gated routingUse confidence as a second axis of decision-making to build safer systemsReliability, security
Composite scoringCombine multiple analysis dimensions into a single scoreCost, reliability, speed
Intent routingSort a user's intention and route to the right managerCost, speed

1 · Speculative fan-out

Because a request accepts a lot of questions, the doc recommends putting it all those that the system might need, then sort in the code. All are evaluated in parallel, so add little changes in response time. The example: sort a support ticket. Instead of asking the category, then gravity in a second call if it's a bug, you ask both at a time; if it's not a bug, you ignore gravity.

Interactive

Five questions asked in advance, the code reads those that count

Choose the category returned by the Choice: the answers that the code of the page Speculative fan-out The five questions are those of the diagram of the page; the exact text of the ticket and the values of the answers are not in the Markdown, so the answers displayed are fictitious.

Doc · Patterns, Speculative fan-out (triage.py)
category = response.answers["category"]
bug_severity = response.answers["bug_severity"]
bug_repro = response.answers["has_reproducible_steps"]
refund = response.answers["refund_requested"]
frustration = response.answers["frustration"]

if category.choice == "bug_report":
    if bug_severity.score > 1.5 and bug_repro.noul > 0.6:
        escalate_to_engineering(ticket_id, severity="high")
    else:
        add_to_bug_backlog(ticket_id)

elif category.choice == "billing":
    if refund.noul > 0.7:
        route_to_billing_with_flag(ticket_id, refund_likely=True)
    else:
        route_to_billing(ticket_id)

elif category.choice == "feature_request":
    log_feature_request(ticket_id)

# Frustration is useful regardless of category
if frustration.score > 1.5:
    flag_for_priority_response(ticket_id)

All that is needed for the full decision tree comes from a single call. Speculative questions are ignored when they are not serving, and save a round-trip when they are serving. Primitives returns to the cookbook Parallel questions : thirteen questions in one appeal against thirteen calls, about ten times cheaper and ten times faster, without changing the answers (both pages give slightly different multipliers, 11.5×/9.6× and 12.2×/10.0×, probably two executions).

2 · Confidence-gated routing

It's chapter 10: the answer says what, confidence says if you have to act, and every action has its threshold. Nothing to add here, if not the place of this pattern in the list: it's the one that brings reliability and security, not cost or speed.

3 · Composite scoring

We often want to classify elements according to several criteria at the same time. The pattern: to cut the judgment into independent dimensions, to note each separately (one Score per dimension, in a single query), to normalize between 0 and 1, then combine with weights that the control code. The example of the page: CVs of engineers rated on four dimensions (Python depth, leadership, system design, versatility), with two sets of weights depending on the position.

Interactive

One CV, two posts, two weights

The four scores are sliders (the doc does not give recorded values for this example; its scales have five levels, hence division by 4). scoring.py : 40/10/40/10 for an individual senior, 15/40/20/25 for a manager. Compare the two composite scores.

Doc · Patterns, Composite scoring (scoring.py)
py      = response.answers["python_depth"].score / 4
lead    = response.answers["team_leadership"].score / 4
arch    = response.answers["system_design"].score / 4
general = response.answers["generalist"].score / 4

# Senior IC
ic_score = (0.40 * py) + (0.10 * lead) + (0.40 * arch) + (0.10 * general)

# Engineering Manager
em_score = (0.15 * py) + (0.40 * lead) + (0.20 * arch) + (0.25 * general)

What the page points out: beyond the rankings, we see exactly how the final score is made. If the top ranked ones do not meet expectations, we adjust the weights, without losing the shade of individual scores.

4 · Intent routing

Not all requests deserve the same manager: some are settled by a basic request, others by a specialized LLM with its context, others by a human. TypeSafe stands ahead, as a fast and inexpensive classifier who decides which handler to invoke, instead of passing every message through an expensive LLM just to know what it's talking about.

Interactive

Intent routing: four paths, two questions

Choose intent, confidence, and for a complaint the complexity score and confidence: the module applies the function route_ticket() page Intent routing. Thresholds (0.5 for intent, complexity > 1 or confidence < 0.5) are those of code; values, sliders.

Doc · Patterns, Intent routing (routing.py)
def route_ticket(ticket_id, response):
    intent = response.answers["intent"]
    complexity = response.answers["complexity"]

    if intent.confidence < 0.5:
        # If we don't have enough confidence to classify, route to a human agent
        return route_to_human_agent(ticket_id)

    if intent.choice == "order_status":
        handle_order_status(ticket_id)

    elif intent.choice == "product_question":
        handle_with_llm(ticket_id, PRODUCT_SPECIALIST)

    elif intent.choice == "return_exchange":
        handle_with_llm(ticket_id, RETURNS_SPECIALIST)

    elif intent.choice == "complaint":
        low_confidence = complexity.confidence < 0.5
        # A higher complexity.score leans toward the "escalation needed" end of the scale.
        if complexity.score > 1 or low_confidence:
            # Too complex for safe automation, or we're not sure about the complexity; route to a human.
            route_to_human_agent(ticket_id)
        else:
            handle_with_llm(ticket_id, COMPLAINT_RESOLUTION)
When a second request is legitimate

The questions of the same request are independent; one answer does not become the context of another. If a subsequent judgment depends on an earlier answer, one makes one second query in codeBut the doc insists: this is the exception. Dependence is real only if the code cannot build the second query without the first answer (it needs to go to get more data, to decide what the state is made of, or to choose the options of the following question). Three cookbooks do so for real reasons: Skill suggestion (classify 182 skills and then reread the top three in full text), Structure recovery (paste the lines, then classify blocks that did not exist before), Hierarchical classification (Each Choice decides on the following options).

Quiz · chapter 12
You must know the category of a ticket and, if it is a bug, its gravity. How many requests?
Chapter 13

Demo: the home automation assistant

The only demo listed by the documentation is a connected home assistant. It shows the speculative fan-out to its maximum, and how TypeSafe associates with a LLM when you still need to generate text.

Take the "Turn off all of the lights in the house" request. The code only needs four answers: the category of the request (domotic control), the target domain (the whole house), the type of device (lights), the action (off). The last question is written. assuming that the user is controlling lights, and it is asked before we know whether that is the case. It is a speculative question: it is evaluated in parallel with the others, and the code filters the results afterward. Each user request is thus evaluated against a long list of issues, many of which will not be applicable.

The wrong way, says the page, would be to cut into successive calls: the category first; then, once sure that it is a command, the domain and the device; then, once sure that they are lights, the action. This minimizes the number of questions, but it is much slower and more expensive than a single grouped call.

Illustration

Three serial calls, or one bundled call

Run the animation. Durations are fictitious (the doc only says that most requests take about 100 ms and that the additional questions do not change the response time); what counts is the number of round-trips.

TypeSafe + LLM

The demo also shows two ways to associate Jev with a generic model, for a system that sometimes needs a text generation step:

  • Cut a composite request. A Noul asks if the request requires more than one separate action. If so, an LLM cuts the sentence into a list of atomic commands, which TypeSafe then evaluates one by one.
  • Switch to a conversational LLM. When TypeSafe determines that the request is a general information request or a conversation request, the system calls a LLM to generate a free response. Known deterministic behaviors are processed quickly and at low cost; the flexibility of a LLM remains available when needed. TypeSafe's initial response is so fast compared to that of the LLM that it adds negligible latency.

The page indicates that the demo is a Quick/React application whose full source code "will be available on GitHub at the output"; on the date of playback, only a video recording is offered. The course therefore does not describe its code.

Quiz · chapter 13
What is a « speculative question » in the demo?
Chapter 14

Where to place Jev: the use case map

Page Example use cases is made to brainstorm: open the nearest sector, browse the decisions of example, adapt them to its own documents and actions. It starts with five large families.

Automation software

Interlacing AI with reliable software, so that it can run one million times in the background without human co-driver. The code has the control stream, TypeSafe semantic decisions.

Real time applications

A state-of-the-art intelligence at real-time speed (the page says 150 ms): fast enough and smart enough to be programmed in a game or integrated into an interface.

Map-reduce on large volumes

One hundred times cheaper, so able to process giant data sets: searching in huge corpus, classifying trace agents, extracting characteristics.

Universal verification

Check for promptness, extractions, traces of reasoning, tool calls from any other AI: jailbreaks, citation errors, hallucinations, at a fraction of the cost of the LLM call.

Harness engineering

Make the harness of an agent smarter: model routing, semantic context recovery, error detection and safeguards, classification of traces of reasoning.

By sector

Nineteen accords in the page. Each list of typical decisions; here is the content, condensed but faithful.

Research and recovery
  • Replace or supplement the embeddings of a RAG pipeline with semantic research, scoring and grading.
  • Note the relevance of the request → candidate; reclassify by comparison; cross-encoder for more precision.
  • Select the context that is useful for downstream AI streams.
Scientific discovery
  • Filter articles according to inclusion and exclusion criteria for a systematic review.
  • Label transcripts, open answers, field notes.
  • Verify that a cited passage supports an assertion; identify missing methodological details; link entities between articles.
Model Routing
  • Build a router that chooses which LLM receives each prompt; rank intention and domain; estimate difficulty and risk; climb to a more expensive model when necessary.
LLM guardrails
  • Place semantic checks on each LLM input, output and tool call at a fraction of the cost of the call.
  • Detect yellowbreaks and prompt injections, policy violations, exposure of sensitive data, errors in tool calls; log structured results and probabilities.
Code semantic lint
  • Add automated semantic lints to the code and text, according to the team's conventions, executed in IC.
Extraction of characteristics for prediction
  • Extract probabilistic characteristics from texts, combine them with structured data, train models on known results; loops autoresearch propose and evaluate the definitions of characteristics.
Recruitment
  • Evaluate CV, applications and interview returns against explicit job-related criteria; identify relevant experience; record skills; route and climb uncertain cases.
Lead generation
  • Compare company profiles, executive biographies and incoming messages to an ideal customer profile; rate suitability; detect purchase intent and pain points; prioritize.
Customer support
  • Sort tickets by problem, product, intention; extract problems and commitments from call transcripts; detect urgency, frustration, risk of departure, claims for reimbursement; route; check responses against policies.
Insurance claims
  • File declarations, expert notes and exhibits; detect complexity, missing information, fraud clues; prioritize for direct processing or specialized review.
Financial crime
  • Evaluate transaction stories, KYC documents, alert histories; bring entities with inconsistent names closer together; prioritize alerts; route ambiguous cases.
Legal and compliance
  • Classify contracts, policies, regulatory repositories, marketing claims; detect missing clauses and prohibited claims; climb to lawyers.
e-commerce market places
  • Normalize heterogeneous product sheets; extract attributes; detect counterfeits, abuse of opinions, policy violations; classify and route for human review.
Moderation, confidence and security
  • Apply company-specific criteria; detect toxicity, harassment, spam, fraud, dangerous advice, personal data, unsubscribe requests; combine gravity and confidence to authorize, warn, review or block.
Advertising
  • Evaluate creations, campaign texts, landing pages and placement context; classify brand security and audience suitability; verify compliance and alignment ad / page.
Video game
  • Evaluate alerts, chat at stake, opinions and support conversations; moderate; annotate frustration and engagement; detect starting signals.
Risk assessment
  • Convert incident reports, claims notes, transaction descriptions and vendor evaluations into probabilistic indicators; classify types of risk; note severity; feed into broader models.
Forecast of demand
  • Enrich models for predicting semantic signals from customer requests, sales notes, notices, tickets and market reports; extract intent, urgency, product interest; detect supply tensions and competitive pressure.
Knowledge Graphs
  • Annotate and verify graphs with typical semantic decisions; classify relationships and types of entities; detect contradictions; probabilistic path and hierarchical classification.

By form of decision

FormWhen to use itExamples
ClassificationA known category must prevailIntention, subject, service, type of risk, type of entity
DetectionIt takes the probability that a property is present.Spam, fraud, emergency, jailbreaks, sensitive data
ScoringThe answer belongs to an ordered gridGravity, relevance, quality, frustration, adequacy
RoutingA category chooses the next code pathUse of tools, climbing, model routing, support lines
SearchFind the elements that respond to a natural language requestSemantic research, discovery of documents, generation of candidates
RecoveryA stream needs the most relevant context or recordsBackground RAG, Evidence, Knowledge Consultation
RankingOrder by relevance or semantic qualitySearch results, recommendations, prioritisation of candidates
VerificationControl an artifact against specific failure modesCitation support, policy violations, tool call errors
Extraction of ML characteristicsA classic ML model needs semantic signalsIntention to buy, product interest, competitive pressure, departure
Extraction of structured dataKnown fields must be recovered from an unstructured inputAttributes of candidates, order fields, document labels
Chapter 15

Practice: the HTTP API

An entry point, a JSON body, standard error codes. Here is the condensed reference, such as the page API reference I don't know.

The point of entry

Doc · API reference
POST https://api.typesafe.ai/v1/systemone
Authorization: Bearer <API_KEY>
Content-Type: application/json

The API key is created in the console (console.typesafe.ai/keys) The body has the three fields seen in Chapter 3, all required: state (string | object | array), model (string) and questions (map<string, Question>). Question is one of the three types; all share type and instructions, each has its own criteria.

TypeinstructionscriteriaConstraints
noulrequired, string | object | arrayoptional: object {true, false}
choicerequiredrequired: map<option, string | object | array | null>not more than 255 options
scorerequiredrequired: array<string | object | array>, ordered from the bottom upat least 2 levels, not more than 10
Doc · API reference, request examples (the three types)
{
  "state": "Help! My payouts have been failing for 3 days.",
  "model": "jev-latest",
  "questions": {
    "is_urgent": {
      "type": "noul",
      "instructions": "Does this convey urgency?",
      "criteria": {
        "true": "Explicitly time-sensitive",
        "false": "No urgency expressed"
      }
    }
  }
}
{
  "state": "Help! My payouts have been failing for 3 days.",
  "model": "jev-latest",
  "questions": {
    "department": {
      "type": "choice",
      "instructions": "Which team should handle this?",
      "criteria": {
        "billing": "Payments, invoicing, refunds",
        "technical": "Bugs, outages, integrations",
        "sales": "Pricing, upgrades, new accounts"
      }
    }
  }
}
{
  "state": "Help! My payouts have been failing for 3 days.",
  "model": "jev-latest",
  "questions": {
    "frustration": {
      "type": "score",
      "instructions": "How frustrated is the customer?",
      "criteria": ["Calm", "Frustrated", "Very angry"]
    }
  }
}
Doc · API reference, sample answers
{
  "model": "jev-1.13.0",
  "answers": {
    "is_urgent": { "type": "noul", "noul": 0.95 }
  },
  "usage": { "input_tokens": 307, "output_tokens": 20 }
}
{
  "model": "jev-1.13.0",
  "answers": {
    "department": {
      "type": "choice",
      "choice": "billing",
      "probabilities": { "billing": 0.88, "technical": 0.12, "sales": 0.0 },
      "confidence": 0.81
    }
  },
  "usage": { "input_tokens": 318, "output_tokens": 34 }
}
{
  "model": "jev-1.13.0",
  "answers": {
    "frustration": {
      "type": "score",
      "score": 1.05,
      "legend": { "0": "Calm", "1": "Frustrated", "2": "Very angry" },
      "probabilities": { "0": 0.0, "1": 0.95, "2": 0.05 },
      "confidence": 0.92
    }
  },
  "usage": { "input_tokens": 304, "output_tokens": 18 }
}

Errors and flow limits

StatusMeaning
401 UnauthorizedAPI key absent or invalid. Check the header Authorization.
422 Unprocessable EntityThe body failed to validate: missing required field, poorly formed question. The body of the answer refers to the wrongdoing field.
429 Too Many RequestsExceeded flow limit. Wait and try again.
529 OverloadedTypeSafe is temporarily overloaded. Try again after a short time.

On 429 and 529, the instruction is to try again with a exponential backoff, not immediately. SDKs do it by default and respect the header retry-after when it is present. One final API detail: GET /v1/models returns the list of names your account can send to model, with description and date of release; it currently lists aliases, but versioned identifiers as jev-1.13.0 are accepted whether or not they appear.

Quiz · chapter 15
You receive a 422What to look at first?
Chapter 16

Practical: Python and JavaScript SDKs

Two official clients, both very recent at the read date: Python typesafe-sdk (first public version v0.5.7 on September 14, 2026, v0.7.0 on 18) and JavaScript @typesafe-ai/sdk (v0.5.7 on 11 September, v0.6.0 on 15).

In this chapter
  • Install, configure by environment variables, call system_one / systemOne.
  • Python : sync and async clients, answers typed by response_model, retrieving, logging, ascending compatibility.
  • JavaScript : helpers choice(), score(), noul(), inference of the types of response, retry policy.

Python

Request Python 3.10 or more. The client reads TYPESAFE_API_KEY in the environment and calls for jev-latest by default. Two customers: TypeSafeClient (synchronous) and AsyncTypeSafeClient. The answer shows answers (all responses, by ID) and three typed views, nouls, choices, scores.

Doc · SDK Python, Quickstart
pip install typesafe-sdk
# ou
uv add typesafe-sdk
export TYPESAFE_API_KEY="..."
from typesafe_sdk import Choice, Noul, Score, TypeSafeClient

with TypeSafeClient() as client:
    response = client.system_one(
        state={"document": "I was charged twice. Please fix this ASAP."},
        questions={
            "billing": Noul(instructions="Is this ticket about billing?"),
            "tone": Choice(
                instructions="What is the customer's tone?",
                criteria={"calm": None, "frustrated": None, "angry": None},
            ),
            "urgency": Score(
                instructions="How urgent is this ticket?",
                criteria=["can wait", "this week", "today"],
            ),
        },
    )

print(response.nouls["billing"].noul)
print(response.choices["tone"].choice)
print(response.scores["urgency"].score)
from typesafe_sdk import AsyncTypeSafeClient, Choice, Noul, Score

async def main() -> None:
    async with AsyncTypeSafeClient() as client:
        response = await client.system_one(
            state={"document": "I was charged twice. Please fix this ASAP."},
            questions={
                "billing": Noul(instructions="Is this ticket about billing?"),
                "tone": Choice(
                    instructions="What is the customer's tone?",
                    criteria={"calm": None, "frustrated": None, "angry": None},
                ),
                "urgency": Score(
                    instructions="How urgent is this ticket?",
                    criteria=["can wait", "this week", "today"],
                ),
            },
        )

    print(response.nouls["billing"].noul)
    print(response.choices["tone"].choice)
    print(response.scores["urgency"].score)

Typed answers with response_model

Since v0.7.0 (which replaced msgspec by pydantic), system_one accept one response_model : a subclass of SystemOneResponse which declares the expected answers, or even a pydantic model entirely to you. The result then exposes each answer as a typed attribute, and the query identifier via request_id.

Doc · SDK Python, Usage, « Typed system_one responses »
from typesafe_sdk import Noul, NoulAnswer, SystemOneResponse, TypeSafeClient

class BillingResponse(SystemOneResponse):
    billing: NoulAnswer

with TypeSafeClient() as client:
    result = client.system_one(
        "I was charged twice.",
        {"billing": Noul(instructions="Is this about billing?")},
        response_model=BillingResponse,
    )
    assert 0 <= result.billing.noul <= 1
    assert result.billing == result.nouls["billing"]
    print(result.request_id)

Retries, errors, logging, environment

One RetryPolicy is done to the customer or by call (RetryPolicy(max_retries=3, backoff_max=0.2, timeout=1.0) in the example). API errors remove TypeSafeAPIError, status and request_id. The SDK logs on the logger typesafe_sdk ; TYPESAFE_LOG_LEVEL accepts debug, info, warning, error or off. In debug, headers and bodies are journaled; secret headers are masked, bodies are not..

VariableConfigureDefault
TYPESAFE_API_KEYAPI key (required)
TYPESAFE_BASE_URLAPI Roothttps://api.typesafe.ai
TYPESAFE_DEFAULT_MODELDefault modeljev-latest
TYPESAFE_LOG_LEVELLogger level, applied to importUndefined (Python) · warn (JS)

Upward compatibility

The SDK continues to work when the API evolves: extra_body send query fields that the version of the SDK does not know yet; dictionaries of raw questions pass as they are; unknown types of answer are ignored with a warning, and raw_http_response The doc states that these are emergency exits and that it is better to update the SDK.

JavaScript / TypeScript

Request Node.js 20 or more. The package provides ESM, CommonJS and TypeScript declarations. Three helpers build the questions, choice(instructions, criteria), score(instructions, criteria) and noul(instructions?, criteria?), and the types of answers are inferred from the questions : answers.department.choice is typed as one of the keys to your options.

Doc · SDK JavaScript, Quickstart
npm install @typesafe-ai/sdk
export TYPESAFE_API_KEY="..."
import { choice, TypeSafeClient } from "@typesafe-ai/sdk";

const client = new TypeSafeClient();
const response = await client.systemOne({
  state: { document: "I was charged twice. Please fix this ASAP." },
  questions: {
    category: choice("What is this ticket about?", {
      billing: null,
      technical: null,
      other: null,
    }),
  },
});

console.log(response.answers.category.choice);
// Dérivé de la référence du SDK JS : les trois helpers dans une requête.
import { choice, noul, score, TypeSafeClient } from "@typesafe-ai/sdk";

const client = new TypeSafeClient({ timeout: 10000, retry: { maxRetries: 2 } });
const { answers, model, usage } = await client.systemOne({
  state: "I was charged twice. Please help ASAP.",
  questions: {
    billing: noul("Is this about billing?"),
    tone: choice("What is the tone?", { calm: null, angry: null }),
    urgency: score("How urgent is this?", ["low", "medium", "high"]),
  },
});

console.log(answers.billing.noul, answers.tone.choice, answers.urgency.score);
console.log(model, usage.input_tokens);

The manufacturer TypeSafeClient(config) accepts apiKey, baseURL, defaultModel, timeout (by default, 10 000 ms), retry, logLevel, logger, defaultHeaders, fetch, and dangerouslyAllowBrowser (false by default: using the SDK in a browser exposes the key to visitors). Explicit options override environment variables, which override SDK defaults. The default retry policy allows 2 additional attempts, with an initial 500 ms backoff doubling up to 5,000 ms and 25% jitter, for status codes 408, 429, and 500–599, respecting Retry-After up to 60 seconds. Errors are dedicated classes (AuthenticationError, RateLimitError, UnprocessableEntityError, APITimeoutError...), all derived from TypeSafeError.

Recent breaking change on the Scores

In both SDKs, versions 0.6.0 (15 September 2026) have changed Score.criteria : one ordered table instead of an integer indexed dictionary. Examples of this course use the current form. If you come across code with {0: "...", 1: "..."}, he's from before.

Quiz · chapter 16
Why does JavaScript SDK have an option named dangerouslyAllowBrowser ?
Chapter 17

Models, prices and limits

Only one current model, two aliases, one price per input token, context and flow limits. Everything fits in a table, taken from the page Models.

Jev 1.13jev-1.13.0
Price (per Btok / per Mtok)$42 / $0.042, billed on entrance tokens; tokens are free of charge
Flow limits250,000 tokens per second / 1,200 queries per minute; beyond, 429
Context length64k tokens per request; 32k tokens for the state the longer question
InputText only: channel, JSON object or text array. No image, no audio, no video
Changing limits

Page prevents flow limits change without notice while TypeSafe absorbs a high demand and allows more users to enter; more stable limits will come "once things are calmed". Higher limits exist on personalized and corporate plans.

Interactive

Estimate a cost

A calculation derived from the documented price: input tokens per query × number of queries × $0.042 per million. Output costs nothing. The number of tokens of a real state depends on the Jev tokenizer, which the doc does not describe; the doc examples consume between 296 and 589 tokens in entry.

Alias

An alias is a name that resolves to a versioned identifier. jev-latest points to jev-1.13.0 : the most recent stable version, the default of SDKs and the name used in the examples. jev-preview points to the most recent version, official or not; it passes ahead jev-latest when a preversion exists. On the read date, both point to the same model: there is no preversion available.

Practical consequence highlighted by the page: an alias moves at each exit, so the answers behind can change nothing at home. The field model of the answer gives the versioned identifier that responded, to log. And if you have set confidence thresholds on a specific version, pin his ID rather than the alias, and migrate at your own pace.

Customizing Jev

Jev is neither fine-tuned nor adapted by LoRA with customer data; the same weights serve all accounts. by the request : owner content, records and references in the state ; business rules and limit cases in instructions and criteria ; large judgments decomposed into atomic questions combined in the code ; and, to go further, a classical model trained on Jev probabilities (cookbook) AutoResearch).

Languages and data

English is the main language of training, the language where precision is the best. Other languages, including CJK scripts, are processed but less well: test your content before you rely on it, and monitor the confidence in routing. Jev is not trained on customer requests and answers; the page Legal refers to the data processing agreement, to the privacy policy, and offers zero retention (ZDR) to business customers.

Quiz · chapter 17
You've calibrated your production confidence thresholds. model send?
Chapter 18

Write integration by an agent: the skill TypeSafe

TypeSafe publishes a skill for Claude Code, Codex and other code agents: the three types of questions, patterns and good practices, so that the agent knows the forms of request and answer instead of inventing them.

Doc · Agent skill, Installation
claude plugin marketplace add typesafe-ai/skills
claude plugin install typesafe@typesafe-ai

# mise à jour
claude plugin marketplace update typesafe-ai
claude plugin update typesafe@typesafe-ai
npx skills add typesafe-ai/skills --skill typesafe-ai
# -g pour une installation globale ; npx skills update pour mettre à jour

Choose a single installation method to avoid duplicates. SKILL.md is readable on GitHub (typesafe-ai/skills) In a hurry, name the skill ("use the TypeSafe skill") works with any agent; with the Claude Code plugin, one can also invoke /typesafe:typesafe-ai.

Three prompts suggested

  • Explorer : « Using the TypeSafe skill, explore the project and find opportunities for using intelligent judgement to stand in for complex parsing or other fragile code. »
  • Experiment with a key exported in TYPESAFE_API_KEY "run some experiments... Proposes changes based on the most promising results."
  • Refactor from the cookbooks: « analyze my code and see if there are any applicable cookbooks... »

Principles of vibe coding according to page

  1. Discuss with the agent, starting from the above prompts.
  2. Read the plan before implementing it.
  3. Put constants (questions and thresholds) in one place, easy to read: agents are not very good at writing questions, expect to edit them with them.
  4. Do not take statements for cash; push the agent to validate his assumptions.

Common problems

  • The agent does not use the skill : explicitly invoke it, check that the installation targeted this agent well, restart.
  • Routing does not behave as planned Check questions and thresholds. Too high, false negatives; too low, false positives.
  • Confidence thresholds everywhere : if one wants only the best option, take the one of higher probability, without threshold; for a precise statistical algorithm, use the probabilities.
  • TypeSafe code is hard to read What humans need to read again are the questions and threshold constants; group them into a single file.
  • The agent invents fields of request or response : an outdated skill; update and try again.

Page Primitives adds one more reason to install the skill: code agents fall more than humans in the habit of "a question by call." The skill tells them to group a lot of questions by call, including those that only matter for some entries.

Chapter 19

Cookbooks: eighteen complete applications

The cookbooks are executed notebooks, with their numbers. They show Jev in real pipelines: extraction, classification, reclassification, verification, safeguards, self-coherence. Here is the map, filterable by primitive and technique, with the result announced by each.

Interactive

Explore the cookbooks

Filter by primitive or technique. The numbers are those announced by each cookbook in its summary; several specify that their measurements come from jev-1.12The links open the page online.

What the cookbooks teach, in five ideas

  1. Find, then choose. Jev does not generate: when the answer is a text value, a regex or another model finds the candidates and a Choice chooses (Pre-parsed value extraction, Date extraction, Function callingThe returned value is copied as it is, never invented.
  2. One request per document, as many questions as necessary. Parallel questions measures group gain: about ten times cheaper and faster on a 54,000-character document, with the same answers.
  3. confidence separates easy cases from hard cases. Classification using confidence class 60 annual reports in 75 industrial groups: at the threshold 0.9, the confident half is just 90 %, the other 40 %; up one step in the hierarchy, this half increases to 70 %, without second call.
  4. Check, cheaper than producing. SDE cascade extract with a small model, check each field with Nouls TypeSafe, and climb to the big model of reasoning only if a signal lights up. Citation check and Guardrails apply the same idea to quotes and messages from an LLM.
  5. Stable answers. The two cookbooks Self-consistency play 15 times the same rubric and compare the dispersion of Jev's responses with those of LLM, including at temperature 0.
Doc · CookbookOverview diagram: the regex find candidates values in the document, TypeSafe picks one, and downstream code normalizes it and acts on it.
Original illustration (page /cookbooks/pre_parsed_value_extraction_cookbook) : the regex finds the candidate values, TypeSafe chooses one, the code normalizes it and acts.
Doc · CookbookOverview diagram: TypeSafe reads how the date is written and which parts the text names; code turns those answers into a date and either accepts it or sends it to review.
Original illustration (page /cookbooks/date_extraction_cookbook) : TypeSafe reads how the date is written and which parts the text names; the code assembles the date, counts from today if it is relative, and accepts it or sends it to reread.
Doc · CookbookPareto chart of the SDE cascade over 100 prompts: quality against cost for the mini model, the reasoning model, and the cascade.
Original illustration (page /cookbooks/sde_cascade) : the quality / cost compromise over 100 prompts between the small model, the reasoning model, and the cascade verified by TypeSafe.
Doc · CookbookDiagram of the two-step search: a fast BM25 search builds a shortlist, then TypeSafe re-ranks each candidate against the query.
Original illustration (page /cookbooks/rerank_typesafe) : Quick search (BM25) for the short list, then reclassification by a TypeSafe question per request-candidate pair.
Reproduce without key

Several cookbooks (Classification using confidence, Line-by-line search, among others) deliver a JSON cache of their API calls (json_cache.json, or class JsonCache of the package cooksafe), so that the notebook replays without key or expense. Delete the cache restarts all live. The installation type: pip install "typesafe-sdk>=0.5.7" cooksafe --extra-index-url https://pypi.typesafe.ai/.

Quiz · chapter 19
How do cookbooks extract a phone number from an e-mail with Jev?
Chapter 20

The known limits: Jev 1.13's jaggedness

The documentation keeps an honest page of what jev-1.13 does poorly, reviewed on September 17, 2026. Fast, calibrated, and good at common-sense judgment; but literal, poor at arithmetic, and fragile with indirection. Nine failure modes, with an alternative for each.

#Mode of failureDoing more
1Literal readingWrite the exact condition, criteria for each option
2Mathematics and NumbersKeep arithmetic in code
3Comparison of dates and hoursExtract components; compare in code
4IndirectionReduce jumps; point the relevant state
5Great state full of unnecessary detailsFilter first; send only what the question needs
6Adversarial contentWrite accurate prompts, test limit cases before deploying
7Contradictory instructions and criteriaAlign criteria and instruction
8Common sense structural invariantsSet each decision in one way; impose identities in the code
9GenerationUse a generic model
1 · Literal reading

jev-1.13 answers the written question, not the one you meant. Words of scope, negations, implicit conditions are read at the foot of the letter, where a person would have read the intention.

Instead : write the exact condition in instructions, put the limit cases in the criteria. When, in the face of a bad answer, you discover to explain "what I really wanted to say", this explanation is the missing half of the instruction. If the interpretation is inevitable, divide it into two literal questions combined in the code.

2 · Mathematics and numbers

Jev is not a calculator. Three documented cases:

  • Counting : characters of a word, occurrences of a term, elements of a long list. The model recognizes the form of an answer rather than it counts, and the error grows with the size. Instead: iterate in the code on the candidates, place a Noul per element, add yourself (example of the page: " items[i] Is it a fruit name?" for each element).
  • Digital representations : hexadecimal colors work less well than color names; Jev can't judge whether two RGB triplets are close; the assembler or binary less well than a high-level language. Instead: convert in code, pass a calculated number or a named category, keep the model for judgment ("does this color read as a warning?").
  • Calculation from score : do not use a score to reconstruct the exact size between two levels; a threshold, yes, an interpolation, no.
3 · Comparison of dates and hours

Jev reads the dates as text, not as ordered quantities: which comes first, what deviation, in which window. Worse with mixed formats, relative references and domain terminals (quarters, settlement windows).

Instead The extraction is a judgment, the model takes care of it; the arithmetic remains in the code. Each part of a date is a small closed set (twelve months, thirty-one days, a range of years): the extraction becomes a Choice on listed options, with an explicit option "not indicated". Date extraction Makes the full version.

4 · Indirection

Double denials, complex indirection, question about property ownership, several leaps of reasoning: so much lost precision. Instead : instructions as direct as possible, and name the parts of the state concerned.

5 · Great state full of unnecessary details

Accuracy declines when the state grows with content unrelated to the decision: unnecessary detail distracts, and a large state makes it difficult to know which part produced a bad answer. Instead : retrieve and filter in the code, only send the necessary fields; when you can't filter, a relevant Noul can do so (cookbook Classifying RAG passages) Reminder of the limits: 64k tokens per request, 32k for the longest question.

6 · Adversarial content

The state is data, and Jev does not treat it as hostile by default. A written content to guide the model (injected instruction, misleading framing, text that pleads for its own classification) can move the answer. TypeSafe says it expects to improve on this point. Instead : explicit criteria, and in-depth tests before exposing integration to many users.

7 · Contradictory instructions and criteria

When instructions and criteria ask for different things, the model can be lost. true corresponds to "no" and false to "yes" will work less well. Instead : treat the criteria as an extension of instruction, with a language that the average person reads effortlessly.

8 · Common sense structural invariants

jev-1.13 is very constant: semantically close entries give quantitatively close outputs. But many of the invariants that one would imagine holding are not guaranteed. Two measurements of the page:

"Is the customer asking for a refund?" on "I'm not happy with the fit. What are my options here?"Noul noulChoice yesChoice noChoice confidence
Same question, two types0.220.010.990.97
On "I was charged twist for the same order. Can someone look inside this?"refundnot_refundSum
One question and its denial, two Nouls0.720.471.19

Instead : do not rely on an expected invariance ; formulate the questions so that they say directly what one wants ; do not transpose a threshold set on a Noul to a Choice ; do not require the model of arithmetic identities between separate questions. A Choice is relative (it slices out) which one), a Noul is absolute (it can be low for all options); the cookbook Skill suggestion Use both on the same list.

9 · Generation

Jev is not trained to generate text. We can force it by chaining Choices, but it works badly and very slowly. Instead When the response space is limited, turn extraction into Choice on options rather than asking for the value itself; and to really generate text, "there are other models for that."

To avoid, in summary (page box)
  • Ask the model something the code can calculate exactly.
  • cache several judgments in one question.
  • "System 2" tasks: more indirection layers.
  • Give more context in the state that the question needs it: Jev suffers from the context rot, the unrelated material costs precision.
Quiz · chapter 20
You want the number of fruits in a list of eight words.
Chapter 21

Summary, glossary and final quiz

What to keep from the course, in one page. Then five questions that go through all the chapters.

System OneA class of models for fast and structured decisions, consumable by software. Jev is the first. No text generated; typed decisions and calibrated probabilities (RLCD).
Requeststate (string, object or table) + model + questions (map of identifiers to typed questions) One entry point: POST /v1/systemone.
ChoiceAn option from a fixed set (up to 255). choice, probabilities, confidence. Add other if the list may not cover everything.
ScoreA position on ordered levels (2 to 10), described as situations. score (weighted average of level numbers), legend, probabilities, confidence.
NoulThe probability of a yes, from 0 to 1. No separate confidence. The threshold depends on the cost of the error; the environment can go to one person.
ConfidenceDerived from the form of probabilities Three ranges: act, confirm, climb. Thresholds follow the risk of each action and live in the code.
BuildCode when one can ; decomposed and structured state ; atomic questions, structured if necessary ; many questions per request ; composition in the code ; routing on uncertainty.
PatternsSpeculative fan-out, Confidence-gated routing, Composite scoring, Intent routing. A second query only when the first answer is necessary to build the second.
Modeljev-1.13.0 ; alias jev-latest and jev-preview (same as the read date). $0.042 per Mtok in entry, free output; 64k / 32k tokens; text only; English first.
LimitationsLiteral, no calculator, text dates, fragile to indirection and noise in the state, sensitive to adversarial content, no invariants between types, does not generate.

Glossary

  • state : the content to be evaluated, sent in the field state.
  • question : a typical judgment requested of the model; answer : the typed value returned under the same identifier.
  • instructions : the question asked; criteria : options (Choice), levels (Score) or definition of yes and no (Noul).
  • probabilities : distribution on options or levels, sum 1 ; legend : the levels of a Score recalled by number.
  • confidence : summary of the concentration of the distribution (Choice and Score) from 0 to 1.
  • speculative question : placed in advance, in the same call, before knowing if it will serve.
  • context rot : loss of precision when the state contains matter unrelated to the question.
  • RLCD : Reinforcement Learning for Calibrated Decisions, TypeSafe post-training.
  • calibration - on a batch of predictions, a predicted probability of p is determined in a proportion close to p.
  • jaggedness : "irregular edges", tasks on which the model is much less good than on others.
Final quiz · 1/5
Sort a support ticket with a topic (Choice), three spam signals (Nouls) and frustration (Score) requires...
Final quiz · 2/5
Two three-tiered Scores return 1.0. probabilities {0: 0, 1: 1, 2: 0}, the second {0: 0.5, 1: 0, 2: 0.5}.
Final quiz · 3/5
You replace a Noul with a Choice {yes, no} on the same question. Do your thresholds remain valid?
Final quiz · 4/5
You want to classify product photos and sheets written in French. What does the doc say?
Final quiz · 5/5
Which sentence best sums up how to build with System One?

To go further

  • The Playground : paste a text, add questions, see answers. This is the starting point recommended by the Quick start.
  • The documentation, whose index llms.txt ; each page exists in Markdown by adding .md to his URL.
  • The manifest TypeSafe, and the community Discord where the page Jaggedness calls for new methods of failure to be reported.

© 2026 Yann ZINENBERG. All rights reserved. Course generated on September 20, 2026 from the official documentation of TypeSafe AI (docs.typesafe.ai, index llms.txt, pages read in Markdown ; dates of updating the pages according to the sitemap : from 26 August to 20 September 2026). assets/origin/ No value has been invented: the interactive modules reproduce recorded answers cited by the documentation, or are marked as illustrations. Nothing is sent on the network to the execution.