Repository navigation
Jev
Living page: the reference for Jev, the typed-decision model this project calls through OpenRouter. Written from the vendors' documentation and from the user's own working client, read on 2026-09-29. Every claim carries its source in square brackets (the list is at the end), or says "not documented". Nothing here was measured by a call from this project.
Jev is a model from TypeSafe AI that answers typed questions about some text and returns a probability. It writes no text and no explanation [S1, S6]. The project calls it with scripts/jev-ask.ps1. When to use it, and when never, is in the operating guide (§2.1 Router row, §3 Jev preference). This page holds the facts behind that choice.
- TypeSafe calls it a System One model: fast, structured decisions for software. You send a state (the text to judge) and named questions; you get back one typed answer per question, with probabilities [S6].
- It is trained to give calibrated probabilities. TypeSafe says calibration is measured across groups of answers and does not guarantee that any one answer is right [S6]. It does not write replies, code or explanations [S6].
- TypeSafe's announcement (Sep 15, 2026) claims answers in 70 ms to 500 ms, and a price of $0.042 per million input tokens with free output [S1]. Those are the vendor's own claims.
| Item | Value | Source |
|---|---|---|
| OpenRouter model id |
typesafe/jev-1.13 (pinned) |
[S3, S4] |
| Dated snapshot that answers |
typesafe/jev-1.13-20260917, reported in the response's model field |
[S4, S5] |
| Alias that moves |
~typesafe/jev-latest, currently an alias of typesafe/jev-1.13
|
[S3] |
| Bare ids |
jev-1.13 and jev-latest are accepted and mapped onto the typesafe/ namespace on the System One endpoint |
[S4] |
| TypeSafe's own id |
jev-1.13.0; aliases jev-latest and jev-preview both point to it |
[S7] |
| Released | September 18, 2026 (OpenRouter's model page) | [S2] |
-
The model is missing from the default model list.
GET https://openrouter.ai/api/v1/modelsreturns text-output models, and Jev's output type is "decisions", so it is absent (and absent from OpenCode's OpenRouter list for the same reason).GET https://openrouter.ai/api/v1/models?output_modalities=all(or=decisions) lists it [S3]. This is my reading of the two responses, not a sentence in the documentation. -
Nothing newer than
jev-1.13is documented.jev-latestpoints at 1.13, andjev-previewpoints at the same model asjev-latest("There is no preview build available right now") [S3, S7]. A model namedtypesafe/jev-routeralso exists, but it is a text-output router that "runs on Jev", not a decision model [S3]. Other decision-output models are on OpenRouter (upstage/solar-decide,respan/span-01,jaredpalmer/kev-4b); this page does not assess them [S3]. - The pinned id is the one to use for thresholds: TypeSafe says an alias moves when a release ships and that thresholds tuned on one version should pin its id [S7].
Two OpenRouter routes take the same body:
-
POST https://openrouter.ai/api/v1/systemone, the System One route, compatible with TypeSafe's SDKs; the SDK appends/v1/systemoneto the base URLhttps://openrouter.ai/api[S4, S8]. The user's client uses this one [S9]. -
POST https://openrouter.ai/api/alpha/decisions, the alpha Decisions route, which OpenRouter's own tutorial uses [S10].
Both answer an unauthenticated request with HTTP 401 (checked with a key-less POST on 2026-09-29), so both exist. Which is steadier is not documented; the alpha route is labelled alpha. Sources disagree on nothing else about the request.
TypeSafe's direct route is POST https://api.typesafe.ai/v1/systemone with TYPESAFE_API_KEY [S7, S11]. TypeSafe's own signups were paused on 2026-09-26, which is why the user's client goes through OpenRouter [S9].
- Headers:
Authorization: Bearer <OpenRouter key>andContent-Type: application/json[S4, S10]. Other headers (OpenRouter's attribution headers, for example): not documented for this route. A request may carry anx-session-idheader or asession_idbody field,user,traceand aproviderpreferences object; none is needed [S4]. - Body:
model,stateandquestionsare required [S4]. -
stateis a string, a JSON object or a JSON array, text only [S4, S12]. -
questionsis a map from a name you choose to a question. The name is not sent to the model [S11].
A minimal request (the shape is from the OpenRouter and TypeSafe references [S4, S11]; the values are mine, and no call was made with it):
{
"model": "typesafe/jev-1.13",
"state": "Bug: the army panel's order buttons show no text.",
"questions": {
"breaks_play": {
"type": "noul",
"instructions": "Does this bug stop a player from playing?"
}
}
}The response has this shape (fields from the OpenRouter reference and its example [S4]; the numbers are illustrative):
{
"id": "gen-dec-...",
"model": "typesafe/jev-1.13-20260917",
"provider": "TypeSafe",
"answers": {
"breaks_play": { "type": "noul", "noul": 0.93 }
},
"usage": { "input_tokens": 60, "output_tokens": 20, "cost": 0.0000025 }
}Every question has type and instructions (a string, or an object or array of structured guidance) [S11]. All questions in one request see the same state, are answered in parallel and cannot see each other's answers [S10].
| Type | Question extra | Answer | Source |
|---|---|---|---|
noul (yes or no) |
optional criteria: {"true": ..., "false": ...}
|
{"type": "noul", "noul": p}, where p is the probability of yes, from 0 to 1 |
[S11] |
choice |
required criteria: a map from each option to its description (or null) |
{"type": "choice", "choice": "<option>", "probabilities": {option: p, ...}, "confidence": c}; the probabilities sum to 1 |
[S11] |
score |
required criteria: an ordered array of level descriptions |
{"type": "score", "score": x, "probabilities": {"0": p, ...}, "legend": {"0": "<level text>", ...}, "confidence": c}; x is the probability-weighted level, index 0 being the first criterion |
[S11] |
- A Noul has no confidence field. A Choice's or Score's
confidenceis derived from how concentrated its distribution is [S11, S13]. - Do not compare a Noul with a Choice. TypeSafe warns that a threshold tuned on a Noul should not be carried to a Choice, and that a question and its negation as two Nouls need not sum to 1 [S14].
- The OpenRouter reference describes the Noul
criteriaas optional; the user's client sends onlyinstructions[S4, S9].
| Limit | Value | Source |
|---|---|---|
| Options in one Choice | at most 255 | [S11] |
| Levels in one Score | at least 2; at most 10 | [S11] |
| Questions in one request | no number documented; TypeSafe advises putting every question you need into one request, and its cookbook batches 13 | [S15, S16] |
| Text per request | 64k tokens for the state plus all questions; 32k tokens for the state plus the longest single question | [S7] |
| Context length on OpenRouter | 32,000 tokens (max_completion_tokens is listed as 28,800) |
[S3] |
| Request body size in bytes | not documented (OpenRouter lists a 413 Payload Too Large error) |
[S4] |
| Input types | text only: string, object or array of text. No images, audio or video | [S12] |
When the state is too big. What the API returns for a state over the limit is not documented. The error tables list 400, 401, 402, 403, 404, 413, 429 and 500 on OpenRouter [S4], and 401, 422, 429 and 529 at TypeSafe [S11]. No tokenizer is documented either. Size matters before the limit too: accuracy falls as the state fills with detail the question does not need, and TypeSafe's advice is to filter first and send only what the question needs [S14].
For a 2,000-line diff, my estimate (not a documented figure) is 20,000 to 40,000 tokens, which can pass the 32k line. scripts/jev-ask.ps1 therefore does not send an over-limit state: it estimates 4 characters per token and refuses a state over 96,000 characters (about 24k tokens) with a one-line reason, and it truncates nothing. Send the diffstat, or only the hunks the question is about.
What Jev is weak at, from TypeSafe's list for jev-1.13 (reviewed 2026-09-17) [S14]: reading a question literally rather than by intent; arithmetic and counting; comparing dates (it reads them as text); questions that need several hops; a large state with irrelevant detail; content written to steer it (the state is data, and injected instructions can move the answer); and generating text. English is the primary language [S7]. The user's client found dates helped its task, against this advice [S9]; test on the real task.
-
Rate limit (TypeSafe): 250,000 tokens per second and 1,200 requests per minute, over which a request returns
429; TypeSafe says the limits "are adjusting dynamically" and can change without notice [S7]. Whether these limits apply to traffic that arrives through OpenRouter is not documented. OpenRouter documents no Jev-specific limit; its own limits are free-model caps, protection against floods and an in-flight spending budget [S17]. -
Price as OpenRouter bills it: $0.042 per million input tokens, $0 for output tokens [S2, S3]. OpenRouter charges "at the input price shown on the Jev model page", and each response reports the call's cost in USD in
usage.cost[S10]. One example response bills 476 input tokens at $0.000019992 [S4], which is exactly 476 × $0.042 / 1,000,000. Any OpenRouter fee on top of the model price: not documented on these pages. - Speed: 0.4 to 0.8 seconds per call in the user's runs [S9]. TypeSafe claims 70 to 500 ms [S1].
The user's client is nc bench-jev (PR #85) and nc judge --backend jev (PR #87) in diegoami/newscollection2027. It asks one Noul, "do these two articles report the same event", about a pair of news articles. It pins jev-1.13, calls OpenRouter's System One route with the standard library only, times out after 30 seconds, and retries 429, 5xx and timeouts up to four attempts [S9, S18].
-
Key variable:
OPENROUTER_API_KEY(set inconfig/judge.yamlasjev.api_key_env). Without it, the pipeline step prints "skipped" and does nothing [S9, S18]. To go direct to TypeSafe it would change the base URL and useTYPESAFE_API_KEY[S18]. -
Thresholds: act on a yes at 0.9 or above; discard below 0.1; give everything between to the Claude judge (
auto_yes_atandprefilter_belowin the same file) [S9, S18]. - Item count: 280 human-labelled pairs, 117 of them matches (2026-09-26). The cutoff was picked on one half of the labels and scored on the other, each half with about 55 matches, so one or two pairs move precision by 0.02 to 0.04 [S9].
- Accuracy at the ends (with dates): pairs Jev scored below 0.1 were 2% matches, and pairs at 0.9 or above were 97% matches (without dates: 3% and 100%). The middle was rough: the 0.1 to 0.3 bin was 50% matches. At a 0.9 cutoff, held out: precision 0.964, recall 0.509. At 0.6, the cutoff the rule picked: precision 0.891, recall 0.925, against the Claude judge's 0.931 and 0.870 on the 104 pairs both answered. Verdict of the trial: not yet good enough to replace the judge; good as a pre-filter [S9].
- The three-way split, on the labels (queue range, with dates): 42 pairs in Jev's no lane (3 matches lost, all three look like label errors), 79 for the judge, 59 in the yes lane (2 wrong links) [S9].
- On the live queue (2026-09-26): of 1,059 unjudged pairs, 31 confident yeses (30 agreed with the Claude judge) and 40 confident nos (all 40 agreed); the owner agreed with 31 of 31 confident yeses in the tail the judge had not reached [S18]. Wired into the pipeline, the judge's queue fell from 906 to 346 pairs [S18].
- Cost: 560 calls for $0.015 in the trial; the live-queue run of 1,059 pairs cost $0.03 [S9].
The measurements are on a different task from ours (news pairs, not bug reports or sweep tables). They support the 0.9 and 0.1 split; they do not measure our questions.
Our states derive from private evidence and leave for OpenRouter and TypeSafe. That is the user's decision (operating guide §3). What the sources say:
- OpenRouter itself: it does not store prompts or responses unless you turn on Private Input and Output Logging, or "OpenRouter use of inputs/outputs" (a 1% discount for letting OpenRouter use them); both are off by default. It always stores request metadata (token counts, latency), not content [S19]. A small sample of prompts is categorised anonymously by a model with zero data retention [S19].
-
OpenRouter's record of the TypeSafe provider:
training: false,retainsPrompts: false,canPublish: false[S3, S20]. The endpointTypeSafe | typesafe/jev-1.13-20260917is on OpenRouter's public list of zero-data-retention endpoints (GET https://openrouter.ai/api/v1/endpoints/zdr), so a request that demands ZDR (provider: {"zdr": true}) can still reach it [S21, S4].scripts/jev-ask.ps1does not send that field. - TypeSafe's models page: "Jev is not trained on customer requests or responses"; zero data retention is offered "for enterprise customers" (contact sales) [S7, S22].
- TypeSafe's privacy policy: it will not train or fine-tune models on your input, and will not disclose input to a third party other than its service providers. It keeps personal data "for as long as reasonably necessary" [S23]. Its data processing agreement says customer personal data is kept "for as long as necessary" for the purpose of processing [S24].
- A tension that is not resolved in the sources: OpenRouter lists the endpoint as not retaining prompts, while TypeSafe's own documents describe zero retention as an enterprise option and give an open-ended retention rule for input. Whether traffic through OpenRouter is covered by a zero-retention arrangement beyond that listing is not documented. Do not send states that must never persist at either company.
Fetched 2026-09-29.
- S1: TypeSafe blog, "Introducing System One Models & Jev", https://typesafe.ai/blog/introducing-system-one-models-and-jev
- S2: OpenRouter model page for Jev 1.13, https://openrouter.ai/typesafe/jev-1.13
- S3: OpenRouter model list and endpoint data: https://openrouter.ai/api/v1/models?output_modalities=all, https://openrouter.ai/api/v1/models/typesafe/jev-1.13/endpoints, https://openrouter.ai/api/v1/models/typesafe/jev-router/endpoints, https://openrouter.ai/api/v1/models/~typesafe/jev-latest/endpoints
- S4: OpenRouter API reference, "Submit a System One request", https://openrouter.ai/docs/api/api-reference/systemone/submit-a-system-one-request
- S5: OpenRouter Jev hub, https://openrouter.ai/docs/guides/community/jev
- S6: TypeSafe docs, "System One", https://docs.typesafe.ai/concepts/system-one
- S7: TypeSafe docs, "Models", https://docs.typesafe.ai/models
- S8: OpenRouter, "Jev SDK for TypeScript and Python", https://openrouter.ai/docs/guides/community/typesafe-sdk
- S9:
diegoami/newscollection2027PR #85, "nc bench-jev" (body,src/nc/jevtrial.py,config/judge.yaml,prompts/jev.md) - S10: OpenRouter, "Jev Tutorial", https://openrouter.ai/docs/guides/community/jev-tutorial
- S11: TypeSafe docs, "API reference", https://docs.typesafe.ai/api
- S12: TypeSafe docs, "State", https://docs.typesafe.ai/concepts/state
- S13: TypeSafe docs, "Confidence", https://docs.typesafe.ai/confidence
- S14: TypeSafe docs, "Jev 1.13 jaggedness", https://docs.typesafe.ai/model-jaggedness/jev-1.13
- S15: TypeSafe docs, "Speculative fan-out", https://docs.typesafe.ai/patterns/fan-out
- S16: TypeSafe docs, "Primitives (Questions)", https://docs.typesafe.ai/primitives
- S17: OpenRouter, "Limits", https://openrouter.ai/docs/api/reference/limits
- S18:
diegoami/newscollection2027PR #87, "Let Jev answer the confident ends of the judge queue" (body,src/nc/jevjudge.py) - S19: OpenRouter, "Data Collection", https://openrouter.ai/docs/guides/privacy/data-collection
- S20: OpenRouter provider data, https://openrouter.ai/api/frontend/v1/all-providers and the data policy on S2
- S21: OpenRouter, "Zero Data Retention" and its endpoint list, https://openrouter.ai/docs/guides/features/zdr, https://openrouter.ai/api/v1/endpoints/zdr
- S22: TypeSafe docs, "Legal", https://docs.typesafe.ai/legal
- S23: TypeSafe privacy policy, https://typesafe.ai/legal/privacy-policy
- S24: TypeSafe data processing agreement, https://typesafe.ai/legal/data-processing