Skip to content
Get API key

Migrate from TypeSafe or OpenAI

POST https://api.mouse.dev/v1/decisions (primary) and POST https://api.mouse.dev/v1/systemone (alias) are wire-compatible with TypeSafe's System One API (jev-latest / jev-1.13.0), and also accept OpenAI's Decisions API (POST /v1/decisions on gpt-6-luna) field names directly.

Side-by-side comparison: Mouse vs TypeSafe Jev vs OpenAI Decisions

Section titled “Side-by-side comparison: Mouse vs TypeSafe Jev vs OpenAI Decisions”
Feature / FieldMouse (mouse-1)TypeSafe Jev (jev-1.13.0)OpenAI Decisions (gpt-6-luna)
EndpointPOST https://api.mouse.dev/v1/decisions (alias /v1/systemone)POST https://api.typesafe.ai/v1/systemonePOST https://api.openai.com/v1/decisions
Model name"mouse-1" (snapshot mouse-preview-2026-10-13)"jev-latest" (jev-1.13.0)"gpt-6-luna"
Input / context fieldstate (string, JSON object, or array)state (string, JSON object, or array)input (string or user message array)
Questions containerquestions object map ({ "<id>": Question })questions object map ({ "<id>": Question })questions array ([{ "name": "<id>", ... }])
Binary yes/no primitivetype: "noul" → answer.noul (0..1)type: "noul" → answer.noul (0..1)type: "predicate" → answer.probability (0..1)
Multi-option primitivetype: "choice", criteria: { key: desc } (up to 1,024 options)type: "choice", criteria: { key: desc } (up to 255 options)type: "choice", choices: [{ value, description }]
Choice probabilities shapeObject map: { "billing": 0.91, "shipping": 0.09 }Object map: { "billing": 0.91, "shipping": 0.09 }Array: [{ "value": "billing", "probability": 0.91 }, ...]
Ordinal rubric primitivetype: "score", criteria: [lvl0, lvl1, ...] (2–10 levels)type: "score", criteria: [lvl0, lvl1, ...] (2–10 levels)type: "score", levels: [{ label, description }]
Score probabilities shapeObject map: { "0": 0.1, "1": 0.7, "2": 0.2 } + legendObject map: { "0": 0.1, "1": 0.7, "2": 0.2 } + legendArray: [{ "value": 0, "label": "...", "probability": 0.1 }, ...]
Confidence formulasSystem One choice & score formulas + mouse.p_topSystem One choice & score formulasUndocumented internal confidence scalar
Refusal answer typeNever refuses (choice, noul, or score always returned)Never refusesCan return {"type": "refusal", "name": "..."}
First-party calibrationPOST /v1/calibrations → signed calp1. profile + mouse.abstainNone (manual thresholding only)None (manual thresholding only)
Max state / context65,536 state tokens (422 on overflow, never truncated)32k state+longest question / 64k requestNot published
Rate limits200 RPS (burst 400), 20M TPM published on every key80 RPS / 100K TPS ("adjusting dynamically")Tier-based RPM
Price per 1M tokens$0.10 input · $0.02 cached (5m) · $0 output$0.042 input · no cache tier · $0 output$0.10 input (+10% regional) · no cache discount · $0 output
Itemized usage & cost_usdinput_tokens, state_tokens, question_tokens, framing_tokens, cached_tokens, cost_usdinput_tokens, output_tokensToken counts only
Zero Data Retention (ZDR)Default for every customer (Mouse-Data-Retention: none)Enterprise plan via sales onlyEligible customers with prior approval

1. Migrating from TypeSafe Jev (POST /v1/systemone)

Section titled “1. Migrating from TypeSafe Jev (POST /v1/systemone)”

Because Mouse implements the exact /v1/systemone request, answer, and confidence specification, migrating from Jev requires changing only the base URL and model name:

const res = await fetch("https://api.typesafe.ai/v1/systemone", {
const res = await fetch("https://api.mouse.dev/v1/systemone", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TYPESAFE_API_KEY}`,
Authorization: `Bearer ${process.env.MOUSE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "jev-latest",
model: "mouse-1",
state,
questions,
}),
});

Or with @typesafe-ai/sdk / typesafe-sdk:

import { TypeSafeClient } from "@typesafe-ai/sdk";
const client = new TypeSafeClient({
apiKey: process.env.MOUSE_API_KEY,
baseURL: "https://api.mouse.dev",
defaultModel: "mouse-1",
});
  • Identical: questions (choice, noul, score), structured instructions and criteria, answers.<id>.choice, answers.<id>.noul, answers.<id>.score, probabilities, legend, and the exact confidence formulas.
  • Additional fields (ignored by existing SDKs): Each answer includes logits and mouse: { calibrated, p_top, abstain, confidence_winning, confidence_normalized } (noul answers also gain probabilities), and usage includes state_tokens, question_tokens, framing_tokens, cached_tokens, and cost_usd.
  • Re-calibrating thresholds & shadow replay: Even though confidence uses the same formula over probabilities, mouse-1 and jev-1.13.0 have different underlying model weights. A threshold tuned on Jev does not transfer. Replay your existing Jev or OpenAI JSONL logs with apps/decide/scripts/shadow_migrate.py (MOUSE_API_KEY=sk_mouse_... python scripts/shadow_migrate.py logs.jsonl --calibrate) to inspect top-1 agreement rate, confidence shift, 10-bin ECE, and fit a temperature and an out-of-fold cutoff for mouse-1 via POST /v1/calibrations, then branch on mouse.abstain.
  • Option order: If you saw answers flip when options were reordered, pass order_invariant: true and Mouse averages two passes server-side.

2. Migrating from OpenAI Decisions (POST /v1/decisions)

Section titled “2. Migrating from OpenAI Decisions (POST /v1/decisions)”

OpenAI's Decisions API uses the same three conceptual primitives under slightly different field names:

  1. Change the base URL to https://api.mouse.dev (POST /v1/decisions is served) and "model": "gpt-6-luna" to "model": "mouse-1".
  2. Send the request body unchanged. Mouse reads the OpenAI field names as aliases (input → state; the questions array keyed by name; predicate → noul; choices: [{ value, description }] and levels: [{ label, description }] → criteria). The canonical map form below is what the request becomes; you can convert at your own pace.
  3. Read the Mouse response shape: answers is a map keyed by your question names, a predicate comes back as answers.<name>.noul (not answers[i].probability), and choice probabilities are a map (answers.<name>.probabilities[value]).
  4. Remove answer.type === "refusal" branches—mouse-1 never refuses a valid schema and always returns a probability distribution over your options.
{
"model": "gpt-6-luna",
"input": "I was charged twice for my order.",
"questions": [
{
"type": "choice",
"name": "department",
"instructions": "Which department should handle this complaint?",
"choices": [
{ "value": "billing", "description": "Payments, invoices, and refunds." },
{ "value": "technical", "description": "Problems using the product." },
{ "value": "shipping", "description": "Delivery and tracking." },
{ "value": "other", "description": "Requests outside these categories." }
]
},
{
"type": "predicate",
"name": "refund_requested",
"instructions": "Does the customer ask for a refund or report a duplicate charge?"
}
]
}
{
"model": "mouse-1",
"state": "I was charged twice for my order.",
"questions": {
"department": {
"type": "choice",
"instructions": "Which department should handle this complaint?",
"criteria": {
"billing": "Payments, invoices, and refunds.",
"technical": "Problems using the product.",
"shipping": "Delivery and tracking.",
"other": "Requests outside these categories."
}
},
"refund_requested": {
"type": "noul",
"instructions": "Does the customer ask for a refund or report a duplicate charge?"
}
}
}

3. Migrating from generative LLM classifiers (chat/completions / responses)

Section titled “3. Migrating from generative LLM classifiers (chat/completions / responses)”

If you currently prompt a chat model (claude-haiku-4-5, gpt-5.6, gemini-flash) with a JSON schema or forced tool call to classify intents, gate actions, or score outputs:

  1. Move your dynamic prompt variables into state as a clean JSON object (no prompt template boilerplate needed).
  2. Turn each boolean schema field into a noul question, each enum field into a choice question, and each 1–5 rating field into a score question with concrete level descriptions.
  3. Delete your JSON parser and retry-on-malformed-output loop: mouse-1 evaluates all questions in one forward pass (~40–100 ms) with $0 output token cost and returns calibrated probabilities for every option.