Module 0 · 7 min read
Start here
By the end of this module you will have made one call to Jev, read every field of the answer, and know when to reach for it instead of an LLM.
The one-table version
Jev is the first System One model, made by TypeSafe AI. You send a state (text or JSON) and a map of typed questions. You get back one typed answer per question, with probabilities. Jev never writes a sentence. It picks, rates, or says yes or no.
| LLM (chat model) | Trained classifier | Jev | |
|---|---|---|---|
| Input | prompt | one text | state + typed questions |
| Output | prose you parse | one label | typed values with probabilities |
| Answer space | open | fixed at training | fixed per request, by you |
| Calibrated uncertainty | no | sometimes | yes, by design |
| Latency | seconds | milliseconds | 70 to 500 ms |
| Setup | a prompt | labeled data, training | a question, written in English |
| Cost per call | cents | fractions of a cent | fractions of a cent ($0.042 per million input tokens, output free) |
| Can explain, write, generate | yes | no | no |
The last row is the whole point. Jev cannot write a reply or summarize a document. It answers the question you wrote, inside the options you gave, and tells you how sure it is. Your code branches on the number.
The three primitives
Every question has an id you choose, a type, instructions, and for Choice and Score a criteria field.
| Type | Question shape | Returns |
|---|---|---|
| Choice | which one of these options? | choice, probabilities (one per option), confidence |
| Score | where on this ordered scale? | score (weighted position), legend, probabilities, confidence |
| Noul | is this true? | noul, a probability between 0 and 1 |
A Choice takes up to 255 options. A Score takes 2 to 10 levels, described as situations. A Noul has no separate confidence: the probability is the signal, and 0.5 means "as likely yes as no".
Your first call
Get a key at console.typesafe.ai. Then:
export TYPESAFE_API_KEY=ts_...
curl -s https://api.typesafe.ai/v1/systemone \
-H "Authorization: Bearer $TYPESAFE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"state": "Hi, my Stripe connection has failed for three days and I am losing sales. Please help today.",
"model": "jev-latest",
"questions": {
"department": { "type": "choice", "instructions": "Which team should handle this?",
"criteria": { "billing": "Payments, invoices, refunds", "technical": "Bugs, outages, integrations", "sales": "Pricing, upgrades, new accounts" } },
"frustration": { "type": "score", "instructions": "How frustrated is the customer?",
"criteria": ["Calm, stating facts", "Frustrated but civil", "Very angry, strong language"] },
"is_urgent": { "type": "noul", "instructions": "Does the message convey urgency or a deadline?" }
}
}'The answer, trimmed:
{
"model": "jev-1.13.0",
"answers": {
"department": { "type": "choice", "choice": "technical", "probabilities": { "billing": 0.19, "technical": 0.80, "sales": 0.01 }, "confidence": 0.62 },
"frustration": { "type": "score", "score": 1.1, "legend": { "0": "Calm, stating facts", "1": "Frustrated but civil", "2": "Very angry, strong language" }, "probabilities": { "0": 0.05, "1": 0.8, "2": 0.15 }, "confidence": 0.78 },
"is_urgent": { "type": "noul", "noul": 0.99 }
},
"usage": { "input_tokens": 312, "output_tokens": 48 }
}Read it like this:
department.choiceis the option with the highest probability.probabilitiesis the full distribution and always sums to 1.confidencemeasures how peaked that distribution is: 0.62 here, because billing took a fifth of the mass. A ticket about a failed payment integration really is between two teams.frustration.scoreis a weighted position on your scale. 1.1 sits at "frustrated but civil". Never read it as a precise magnitude; read it against a threshold.is_urgent.noulis 0.99. The customer said "three days", "losing sales", "today".modelis the versioned ID that answered. Log it.jev-latestis an alias that moves when TypeSafe ships a release.
The same call in TypeScript
The raw HTTP shape is the one you will paste everywhere in this course, because it works from any runtime and the question JSON is the deliverable. Here is a caller you can keep:
// jev.ts
const URL = 'https://api.typesafe.ai/v1/systemone'
export type Question =
| { type: 'choice'; instructions: unknown; criteria: Record<string, unknown> }
| { type: 'score'; instructions: unknown; criteria: unknown[] }
| { type: 'noul'; instructions: unknown; criteria?: { true?: unknown; false?: unknown } }
export async function ask<Q extends Record<string, Question>>(state: unknown, questions: Q, model = 'jev-latest') {
let res: Response | undefined
for (let attempt = 0; attempt < 4; attempt++) {
res = await fetch(URL, {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.TYPESAFE_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ state, model, questions }),
signal: AbortSignal.timeout(8000),
})
if (res.status !== 429 && res.status !== 529) break
await new Promise((r) => setTimeout(r, 300 * 2 ** attempt))
}
if (!res || !res.ok) throw new Error(`jev ${res?.status}: ${await res?.text()}`)
return res.json() as Promise<{ model: string; answers: Record<keyof Q, any>; usage: { input_tokens: number; output_tokens: number } }>
}import { ask } from './jev'
const r = await ask(
'Hi, my Stripe connection has failed for three days and I am losing sales. Please help today.',
{
department: { type: 'choice', instructions: 'Which team should handle this?', criteria: { billing: 'Payments, invoices, refunds', technical: 'Bugs, outages, integrations', sales: 'Pricing, upgrades, new accounts' } },
is_urgent: { type: 'noul', instructions: 'Does the message convey urgency or a deadline?' },
},
)
console.log(r.answers.department.choice, r.answers.is_urgent.noul, r.model)TypeSafe also ships an official SDK for JavaScript (npm install @typesafe-ai/sdk) with choice(), score(), noul() helpers and a TypeSafeClient that retries 429 and 529 for you. Use it if you like; the JSON you send is identical.
The same call in Python
pip install typesafe-sdkfrom typesafe_sdk import Choice, Noul, Score, TypeSafeClient
client = TypeSafeClient() # reads TYPESAFE_API_KEY, defaults to jev-latest
r = client.system_one(
state="Hi, my Stripe connection has failed for three days and I am losing sales. Please help today.",
questions={
"department": Choice(
instructions="Which team should handle this?",
criteria={"billing": "Payments, invoices, refunds", "technical": "Bugs, outages, integrations", "sales": "Pricing, upgrades, new accounts"},
),
"frustration": Score(instructions="How frustrated is the customer?", criteria=["Calm, stating facts", "Frustrated but civil", "Very angry, strong language"]),
"is_urgent": Noul(instructions="Does the message convey urgency or a deadline?"),
},
)
print(r.answers["department"].choice, r.answers["frustration"].score, r.answers["is_urgent"].noul)When to reach for Jev
Reach for it when all three hold:
- The answer is one of a set you can write down (options, levels, yes or no).
- A knowledgeable person would answer in about a second, given the right context.
- Your code needs the answer as a value, to branch, sort, gate or rank.
Keep an LLM when you need text: a reply, a summary, code, an explanation. The strongest products use both: Jev routes, gates and verifies; the LLM writes inside the boundary Jev drew.
Numbers to keep in mind
| Endpoint | POST https://api.typesafe.ai/v1/systemone |
| Model | jev-latest, currently jev-1.13.0 |
| Price | $0.042 per million input tokens, output free |
| Latency | 70 to 500 ms per request, whatever the number of questions |
| Limits | 64k tokens per request, 32k for the state plus the longest question, 1 200 requests per minute (adjusted with load) |
| Input | text only: string, JSON object, array of text |
| Errors | 401 key, 422 validation, 429 rate limit, 529 overloaded; back off exponentially on the last two |
Checklist
- You have a key and one successful call.
- You can point at
choice,probabilities,confidence,score,noulin an answer. - You can say in one sentence why Jev and an LLM are different tools.
Next: where a decision like this belongs in a real product.