Intent routing with Jev
Intent routing sends each incoming request to the handler that should take it: a piece of deterministic code, a specialist model or a person. With Jev it is one Choice question whose options are the handlers, returning a choice, a probability per option and a confidence number. This page covers how to write the options, what to do when the list is longer than the 255-option limit, how TypeSafe's skill-suggestion cookbook picks one of 182 skills in two stages, how to handle the request that fits none of the options, and what a route costs at the public price.
Published September 22, 2026. Editorial.
Key takeaways
- A route is a Choice question whose options are the handlers, each described by what it covers, what it excludes and an example.
- Always include an option for none of these; TypeSafe's Choice docs recommend it so the model can say that nothing fits.
- Confidence below 0.5 means send the request to a person or ask for clarification, in TypeSafe's own intent-routing example.
- For long option lists, rank every option with short descriptions, then re-check the top few with full descriptions; TypeSafe's cookbook does this over 182 skills and cut wrong loads from 16.8 to 7.3 percent on its own 488-request test.
- At the public price of $0.042 per million input tokens, a route over a 500-token message costs $0.000021.
TypeSafe's intent-routing pattern uses a customer-service example with four intents: order_status, product_question, return_exchange and complaint, each with a one-line description [1]. The request text is the state, the intents are the options of a Choice question, and the answer comes back as a choice, a probability per option and a confidence number. Code then does one check before it trusts the answer: if confidence is below 0.5, the request goes to a human agent [1]. Everything else in the pattern is detail on those two sentences.
The reason the pattern matters is where the expensive work happens. TypeSafe's description is that the classification happens in "a single quick call" and the expensive resources are used only for requests that need them [1]. The specialist model, the reasoning model or the person is called after the route, and only for the share of traffic the route sends there.
Writing the options
A Choice question accepts up to 255 options [2]. Each option is a name plus a description, and the description is what the model reads, so it carries the whole meaning. TypeSafe's Choice docs recommend that when options are often confused with each other, the description should say what the option covers, what it excludes, and give an example, instead of a single phrase [2].
In practice that means writing the options the way you would write a routing rule for a new employee. "return_exchange: the customer wants to send an item back or swap it. Excludes questions about whether a product can be returned before buying, which is product_question. Example: I want to return the second one, the first was fine." The exclusion line is what stops two neighbouring options from splitting the probability between them, which is what lowers confidence.
The jaggedness page adds a rule that applies to every option description: the model answers exactly the question you wrote, and scoping words, negations and implied conditions are read literally [3]. So an option described as "anything about billing" will attract a message about a wrong shipping address if the message mentions a charge. Write the boundary explicitly.
The none of these option
TypeSafe's Choice docs say to include an "other" or "none of the above" option whenever the list might not cover every input, so the model can say that none of the others fit [2]. We treat this as mandatory for a router. Without it, a request that matches nothing is forced into the nearest option with a flat probability distribution, and the only signal you get is low confidence. With it, you get two signals: a low confidence on a real option means the model is split between handlers, and a confident "none" means the request is outside what the product handles.
Those two cases need different handling. A split answer can go to a person with the top two options shown, so the person's choice becomes a label for later. A confident "none" is a product question: either a new handler is needed, or the request should be answered with a fixed message. Log them separately, because the counts drive different decisions.
Confidence and the human path
The confidence number on a Choice answer is computed from how concentrated the probabilities are: a single peak means high confidence and probability spread across several options means low [2]. TypeSafe's confidence page gives the general bands, 0.9 and above to act automatically and below 0.5 to route to a human, ask for clarification or use a different system [4]. The intent-routing example uses 0.5 as its cutoff for the human path [1].
For a router the middle band has a specific meaning. A confidence of 0.7 with the probability split between return_exchange and complaint is a request that is both, and a good product handles both: route to the returns handler and flag the complaint. That is why we keep the full probability map in the log and in the handler's input, and why TypeSafe's confidence page says the fuller probabilities property is always available when the single number does not fit your case [4]. Confidence-gated routing covers the bands in detail, and the point here is only that the router should pass the probabilities on rather than the choice alone.
Long lists: rank every option, then re-check the top few
Two limits push a router towards two stages. The first is the 255-option cap. The second is that a Choice over many options with long descriptions makes a large state, and accuracy falls as the state grows [3].
TypeSafe's skill-suggestion cookbook is the reference example. The task is to pick which one of 182 skills, from Nous Research's Hermes catalogue, a coding agent should load for a request, or none [5]. Stage one asks a single Choice question over all 182 skills using truncated descriptions, plus three Noul questions about whether the request needs an action, a documented procedure, or only an explanation; if the mean of those three is below 0.30 nothing is suggested, and otherwise the top three candidates go on. TypeSafe reports 0.16 to 0.31 seconds for this stage. Stage two re-checks those three with their full descriptions and opening sections, asks a "fits" question for each, and rejects all of them if the best fits score is below 0.30; TypeSafe reports 0.09 to 0.12 seconds [5].
On TypeSafe's own test of 488 requests (315 covered by exactly one skill, 173 by none), wrong skill loads fell from 16.8 percent to 7.3 percent and needless loads from 9.8 percent to 4.0 percent, with the agent running on a Claude Haiku model [5]. The cookbook also reports the cost of a wrong suggestion: 37 requests that used to fail now succeed, and 7 that used to succeed now fail because of an incorrect suggestion. That trade is the thing to measure in your own router, because a confident wrong route is worse than a request that waits for a person.
The shape generalises. Stage one is cheap and wide: short descriptions, one Choice, a probability per option. Stage two is narrow and careful: the top few candidates with everything the model needs to tell them apart, and a threshold under which the answer is "none". Both stages are one request each, so the whole route is two round trips of under a third of a second each in TypeSafe's measurements.
Routing to a model rather than a handler
A router can pick a model as well as a handler. LangChain's harness post describes a ModelRouterMiddleware that assesses each request with Jev and selects a model on stated criteria, in its example between a fast model for direct lookups and a powerful one for complex decisions, choosing the least costly model that can complete the task [6]. The mechanics are the same Choice question; the options are models instead of queues.
We use this shape inside agents where most turns are simple and a few are hard. The route runs on every turn at decision-model cost, and the expensive model is called for the share of turns that need it. Single agent or multi-agent in our agents guide covers when that split is worth the added complexity.
What a route costs
TypeSafe's public price is $0.042 per million input tokens, and output tokens are free [7]. A route over a 500-token message with a 200-token option list costs $0.0000294 at that price. Over a million requests a month that is $29.40. The two-stage router costs the same twice plus the larger stage-two state. These are arithmetic on the list price and say nothing about discounts or future changes, and TypeSafe's own benchmark comparison against language models was written by TypeSafe's capabilities team [8], so treat the list price as the one number you can rely on and measure your own request sizes.
Latency is TypeSafe's reported 70 to 500 milliseconds end to end [9]; Openlayer measured a p50 of 244 milliseconds and a p95 of 371 milliseconds on its own guardrail benchmark, where a p50 is the time half of requests beat and a p95 the time 95 percent beat [10]. A router on the request path adds that to every request, so Rate limits, retries and latency covers timeouts and the fallback route when the model is unreachable.
How we build a router
Reveneau builds the router as code with the options in a versioned file next to the handlers, so a new handler and its option description land in the same change and the eval suite checks both. Every route is logged with the model version, the full probability map, the confidence and the handler chosen. Requests that went to a person keep the person's choice as a label, and that labelled set is re-run on every model version change before the pin moves. Versions, drift and monitoring covers that loop. For the person deciding whether a router belongs in the product at all, decision models for product teams is the shorter version.
Best for
- A fixed set of handlers, queues, workflows or models, each describable in a few sentences.
- Traffic where most requests are simple and a few need an expensive model or a person.
- Replacing a language-model prompt that returns a category name as text.
Avoid if
- The handlers change daily and nobody maintains the option descriptions.
- The request needs facts outside the message to route, and those are not fetched into the state.
- More than 255 options and no way to shortlist them in a first stage.
Check before you decide
- Every option has a coverage line, an exclusion line and an example.
- A none of these option exists and its count is tracked separately.
- Confidence below the cutoff goes to a person, and the person's choice is kept as a label.
- The full probability map is logged and passed to the handler.
Common questions
How many options can one Jev Choice question have?
Up to 255, per TypeSafe's Choice docs. Past that, or when the descriptions make the state large enough to hurt accuracy, use two stages: a wide Choice with short descriptions to shortlist, then a second request over the top few with full descriptions and a threshold under which the answer is none. TypeSafe's skill-suggestion cookbook does this over 182 skills with a 0.30 cutoff at each stage.
What should each routing option contain?
A name, a line saying what the option covers, a line saying what it excludes, and an example message. TypeSafe's Choice docs recommend that structure for options that are often confused, because the exclusion line stops two neighbouring options splitting the probability. Write the boundary explicitly: the jaggedness page says the model reads scoping words and implied conditions literally, so an option described as anything about billing will attract messages that merely mention a charge.
Why include a none of these option in a router?
Because without it a request that matches nothing is forced into the nearest option and the only signal is low confidence. TypeSafe's Choice docs recommend an other or none of the above option so the model can say that nothing fits. With it you get two separate signals: low confidence on a real option means the model is split between handlers, while a confident none means the request is outside the product, which is a product decision rather than a routing one.
What confidence cutoff should a router use for the human path?
TypeSafe's intent-routing example sends anything below 0.5 confidence to a human agent, and its confidence page marks 0.9 and above as safe to act automatically. Use 0.5 as the starting point, then adjust from logged outcomes: if people overturn routes that passed the cutoff, raise it; if the human queue is full of routes a person confirms unchanged, lower it. A different cutoff per handler is normal, higher where a wrong route costs more.
How does the two-stage skill-suggestion router work?
Stage one asks one Choice over all 182 skills with truncated descriptions, plus three Noul questions on whether the request needs an action, a procedure or only an explanation; if their mean is under 0.30 nothing is suggested, otherwise the top three go on. Stage two re-checks those three with full descriptions and a fits score, rejecting all if the best is under 0.30. TypeSafe reports 0.16 to 0.31 seconds and 0.09 to 0.12 seconds for the two stages.
What did the skill-suggestion router change in TypeSafe's test?
On TypeSafe's own 488-request test, wrong skill loads fell from 16.8 percent to 7.3 percent and needless loads from 9.8 to 4.0 percent. The same page reports the cost: 37 requests that used to fail now succeed, and 7 that used to succeed now fail because of an incorrect suggestion. That second number is the one to measure in your own router, because a confident wrong route is worse than a request that waits for a person.
Can Jev route between language models instead of between handlers?
Yes, with the same Choice question and models as the options. LangChain's harness post describes a ModelRouterMiddleware that assesses each request with Jev and picks between a fast model for direct lookups and a powerful one for complex decisions, choosing the least costly model that can complete the task. The route runs on every turn at decision-model cost and the expensive model is called only for the share of turns the router sends there.
What does one route cost?
At TypeSafe's list price of $0.042 per million input tokens with output free, a 500-token message plus a 200-token option list costs $0.0000294, or $29.40 per million routes. A two-stage router pays that twice plus the larger second-stage state. Those figures are arithmetic on the public price and say nothing about discounts or future changes, so measure your own request sizes rather than relying on the vendor's benchmark comparisons.
What should a router log?
The model version from the response, the full probability map, the confidence, the handler chosen and, when a person took the route, the person's choice. The probability map matters because a 0.7 confidence split between returns and complaint is a request that is both, and the handler can act on that only if it receives the map. The person's choices become the labelled set that is re-run before any model version change.
How much latency does a router add to a request?
TypeSafe reports 70 to 500 milliseconds end to end, and Openlayer measured a p50 of 244 milliseconds and a p95 of 371 milliseconds on its own guardrail benchmark, meaning half of requests beat 244 and 95 percent beat 371. A two-stage router adds two of those. Set a timeout and a default route for when the model does not answer, because a router on the request path is a dependency the request cannot wait on forever.
How does Reveneau maintain a router after launch?
The options live in a versioned file next to the handlers, so a new handler and its description ship in the same change and the eval suite checks both. Every route is logged with version, probabilities and outcome, human overrides are kept as labels, and the labelled set is re-run against a new model version before the production pin moves. Reveneau builds the router this way so a routing error is fixed by editing a description or a threshold, in one reviewed change.
References
- [1] TypeSafe docs, Intent routing pattern: a Choice over order_status, product_question, return_exchange and complaint; if confidence is below 0.5 route to a human agent; classification in a single quick call with expensive resources used only where needed.
- [2] TypeSafe docs, Choice: accepts up to 255 options; describe confusable options with coverage, exclusions and examples; include an other or none of the above option; confidence reflects the shape of the distribution.
- [3] TypeSafe docs, Model jaggedness jev-1.13: answers exactly the question you wrote; accuracy falls as the state grows with content unrelated to the decision.
- [4] TypeSafe docs, Confidence: 0.9 and above act automatically, below 0.5 route to a human; the fuller probabilities property is always available.
- [5] TypeSafe docs, Skill suggestion cookbook: 182 skills; stage one ranks all with truncated descriptions plus three Nouls with a 0.30 mean threshold (0.16 to 0.31 s); stage two re-checks the top three with full descriptions and a 0.30 fits threshold (0.09 to 0.12 s); on 488 requests wrong loads 16.8% to 7.3%, needless loads 9.8% to 4.0%; 37 requests fixed and 7 broken.
- [6] LangChain, Building a harness with Jev (17 September 2026): ModelRouterMiddleware selects between a fast and a powerful model using the least costly model that can complete the task.
- [7] TypeSafe docs, Models: $0.042 per million input tokens, output tokens free.
- [8] MarkTechPost, TypeSafe AI releases Jev (19 September 2026): TypeSafe's benchmark workflows were written by its own capabilities team; TypeSafe says it cannot prove the price is unsubsidised.
- [9] TypeSafe, Introducing System One models and Jev: 70 to 500 ms end to end.
- [10] Openlayer, jevals README: Jev latency p50 244 ms and p95 371 ms per request on Openlayer's benchmark.
Related reading
How to tell a System One task from a System Two task
If the possible answers can be written down before you ask, the task repeats at volume, and nobody needs a written reason, a fast decision model can do it. Everything else needs a language model or a person. Here is the rule, with three features walked through it.
How to add LLM integration to an existing product without breaking it
Most teams do not need a complete AI rebuild. They need one strong feature, added in a way that cannot cause the rest of the product to fail.
How to decide if a feature needs a human in the loop
Most teams answer this based on how they feel, then discover the rule in an incident review. Four questions decide it properly, and only one of them is about accuracy.
More in Patterns
Confidence-gated routing: act, confirm, or escalate
A decision model returns two things: the answer, and how concentrated the probability was behind it. Confidence-gated routing uses the second as its own axis. TypeSafe's bands are the starting point: act automatically at 0.9 and above, send anything below 0.5 to a person or another system, and proceed with caution in between. This page turns those bands into a gate per action, sized by what a wrong answer would cost, shows the pattern of escalating to an expensive reasoning model only in the uncertain band, and lists what to log so the gates can be tuned from real outcomes.
Extraction and verification with Jev
Jev answers a fixed question with a choice, a score or a probability, so to extract a date or an amount from a document you give it the candidates. It picks one from a list your code built, and it can say whether a statement is true of a document. That makes extraction a two-step job: code over-finds candidates with a parser or a regular expression (a text pattern), and a Choice question selects the right one or none. This page covers that pattern from TypeSafe's cookbooks, date extraction done as parts with the arithmetic in code, citation checking against a source, entity matching across 450 catalogue pairs, and the counting and date weaknesses that shape all of it.