Lesson 02 · TypeSafe Jev — System One models
Now we turn the mental model into working code. By the end you'll have one function —
routeTicket() — that sends a ticket to Jev, gets a typed decision back, and either
auto-routes it or escalates to a human based on confidence.
That escalation logic is the whole reason to reach for a typed decision model.
POST a ticket → get { choice, probabilities, confidence }
→ your code decides "confident enough to act, or hand to a human?". The model judges; you decide.
fetch, so no HTTP library needed. Check with node -v.export TYPESAFE_API_KEY="sk-..."routeTicket.ts and either ts-node or tsx to run it (npx tsx routeTicket.ts).TypeScript's payoff: describe the request and response once, and every field is checked and autocompleted. This mirrors the shapes from the cheat-sheet.
// jev.ts — types + a tiny client
// ---- Request ----
interface ChoiceQuestion {
type: "choice";
instructions: string;
criteria: Record<string, string>; // option name -> description
}
interface JevRequest {
model: string; // "jev-latest"
state: string; // the context to judge
questions: Record<string, ChoiceQuestion>; // keyed by names you pick
}
// ---- Response ----
interface ChoiceAnswer {
type: "choice";
choice: string; // the winning option
probabilities: Record<string, number>;
confidence: number; // 0..1 — gate on this
}
interface JevResponse {
model: string;
answers: Record<string, ChoiceAnswer>;
usage: { input_tokens: number; output_tokens: number };
}
fetchNo SDK required. This is the entire transport layer:
const ENDPOINT = "https://api.typesafe.ai/v1/systemone";
async function callJev(req: JevRequest): Promise<JevResponse> {
const res = await fetch(ENDPOINT, {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.TYPESAFE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(req),
});
if (!res.ok) {
// Fail loud: bad key, malformed question, rate limit, etc.
throw new Error(`Jev ${res.status}: ${await res.text()}`);
}
return res.json() as Promise<JevResponse>;
}
This is the heart of the lesson. Jev gives you a choice and a confidence.
You decide the threshold. Below it, a human looks; above it, the ticket flows automatically.
const CONFIDENCE_THRESHOLD = 0.75; // your call, tune it to your risk
type Routing =
| { action: "auto"; team: string; confidence: number }
| { action: "escalate"; reason: string; top: string; confidence: number };
async function routeTicket(message: string): Promise<Routing> {
const response = await callJev({
model: "jev-latest",
state: message,
questions: {
department: {
type: "choice",
instructions: "Which team should handle this ticket?",
criteria: {
billing: "Payments, invoicing, refunds",
technical: "Bugs, outages, integrations",
sales: "Pricing, upgrades, new accounts",
},
},
},
});
const a = response.answers.department;
// The gate: trust the model only when it's sure enough.
if (a.confidence >= CONFIDENCE_THRESHOLD) {
return { action: "auto", team: a.choice, confidence: a.confidence };
}
return {
action: "escalate",
reason: "Low confidence — needs a human",
top: a.choice,
confidence: a.confidence,
};
}
const decision = await routeTicket(
"Help! My payouts have been failing for 3 days."
);
console.log(decision);
// -> { action: "auto", team: "technical", confidence: 0.82 }
const vague = await routeTicket("hey, quick question about my account");
console.log(vague);
// -> { action: "escalate", reason: "Low confidence ...", top: "billing", confidence: 0.41 }
The clear ticket auto-routes; the vague one gets a human. Same model call — the difference is your threshold. That branch is impossible to do cleanly when an LLM hands you a paragraph.
| Want to… | Change |
|---|---|
| Ask more than one thing | Add keys to questions (e.g. a priority Score, an is_urgent Noul). They run in parallel — that's Lesson 03. |
| Also consider the margin, not just confidence | Escalate when the top two probabilities are close (e.g. 0.44 vs 0.41), even if confidence looks okay. |
Retrieval, not recognition — answer before revealing.
Primary source to read next: docs.typesafe.ai — the Quick Start & patterns pages (you now have the client to try them against).
Reference: Glossary & cheat-sheet · Prev: Lesson 01 · Next: Lesson 03 — composing multiple questions (ask me to build it).