docs/concepts/model-routing.md

Model routing with Jev

Add a Jev key and each run starts on the right model, at the right effort, from the options you allow. Remove the key and every run is exactly as it was.

Jev is TypeSafe's decision model. It doesn't write answers. It answers a typed question ("which of these should do the work?", "how much effort?") with a probability, in well under a second, for a fraction of a cent. Vocion asks Jev before a run starts and then does the work itself, so Jev can choose for engines that run their own model loop, like OpenHands.

What Jev decides

WhereJev picksFrom
A chat turn on Autothe effort (Quick, Standard or Deep) and, when you've listed options, the modelthe agent's routeModels, plus its configured model
A mission, automation or other agent runthe model and, on a model that thinks, the effortthe same list
A Software Factory runthe engine, its model and the effortthe seat's routeModels
A first message in a workspacewhich agent answers itthe agents on the roster
A new record, when the workspace opts inwhether it duplicates an existing recordthe type's shortlist

With no list, the configured model is the only option and Jev sets only the effort. Jev never moves work onto a model or engine the workspace didn't name.

Turn it on

  1. Create an API key in the TypeSafe console.
  2. Paste it into System → System Keys → Jev by TypeSafe for the whole installation, or into Developers → Workspace Keys to override it for one workspace. A self-hosted install can set TYPESAFE_API_KEY instead.
  3. Optionally, give agents something to choose between:
# workspace.yaml
defaults:
  routeModels:
    - model: claude-haiku-4-5
      about: lookups, short replies, one system
      cost: low
    - model: claude-sonnet-5-5
      about: most questions and drafts
      cost: medium
    - model: claude-opus-5-5
      about: research, plans, ranking many items, anything risky
      cost: high

An agent's own harness.routeModels replaces the workspace list. A factory seat lists engines instead (engine: openhands, model, about, cost). Each list holds at most 12 entries.

The System Keys section with the Jev by TypeSafe card connected, the key masked to its last four characters

The key

  • A workspace key overrides the instance key. Without either, routing is off.
  • Keys are encrypted with the credential vault, never written to workspace YAML or git, and the settings screens show only the last four characters.
  • A workspace with its own key is billed and tracked on its own TypeSafe account. A workspace key that can't be decrypted never falls back to the instance key. The run takes the configured route and says why.
  • An OpenRouter key (sk-or-…) also works: Vocion sends it to OpenRouter's copy of the same API. The provider is recorded on every run.

Limits come first

Jev only chooses among options that are already allowed:

  • A candidate is dropped before Jev sees it if its vendor has no credential in the workspace, or if it's outside VOCION_ALLOWED_MODELS (or VOCION_ALLOWED_ENGINES for the factory).
  • Budgets, turn ceilings, approvals, tools and trust rules apply after the choice, exactly as they do without Jev.
  • A task or turn that names its own engine, model or effort keeps it. Jev isn't asked. In chat, a level you pick yourself is never overridden, and Auto's floors still hold: a turn that drafts something you'll send, or checks two or more systems, never drops to Quick.

When Jev isn't sure

Jev's answer is used only if it's one of the options and its confidence is at least VOCION_JEV_MIN_CONFIDENCE (0.6 by default). In every other case the run takes its configured route, with the reason recorded:

  • Jev isn't sure;
  • it answers "none of these";
  • it errors or times out (1.5 seconds in chat, 3 seconds elsewhere);
  • it has failed three times in a row, in which case it's skipped for a minute.

No run fails because of Jev, and Vocion installs nothing of Jev's: it makes plain HTTPS requests.

What Jev sees

To route a turn, Jev gets the first 2,000 characters of the request, the agent's description and each option's about. To check a duplicate, it gets titles and the compared fields, shortened, and no ids, people or dates. Turning routing on for a workspace makes TypeSafe a subprocessor for that content, so treat it as a data-sharing decision.

Where to see it

  • Observability → Routing: whether routing is on and on whose key, the turns Jev routed against the turns that ran the configured model, the most common reasons for a fallback, first messages Jev assigned, and spend by model and by who chose it.
  • The Engines page: each factory run shows whether Jev or the fixed routing picked its engine, with Jev's reason and confidence.
  • Every model call of a routed turn carries the decision on its ledger row.

The Routing section of Observability: 412 turns Jev routed, 58 on the configured model, the reasons, and spend by model and who chose it

Duplicate check

A workspace that sets defaults.jev.duplicateCheck: true (and has a key) gets a cheaper first read when a record comes in:

  1. An exact match on the title and compared fields settles it.
  2. Otherwise Jev answers one yes/no per shortlisted record.
  3. The classifier decides anything Jev leaves unsure.

The link is written the way it always was, with Undo. Any type can opt in through the built-in record-duplicate-check job.

Settings

VariableDefaultPurpose
TYPESAFE_API_KEY—Instance key, when none is saved in System
TYPESAFE_BASE_URLhttps://api.typesafe.aiTypeSafe's API, or a proxy (https only)
TYPESAFE_DEFAULT_MODELjev-1.13.0The Jev version, pinned so thresholds don't move when TypeSafe ships
VOCION_JEV_MIN_CONFIDENCE0.6Below this, the configured route runs
VOCION_JEV_CHAT_TIMEOUT_MS1500How long a chat turn waits (250–5000)
VOCION_JEV_TIMEOUT_MS3000How long other runs wait
VOCION_ALLOWED_MODELS—Optional fence on chat models (comma-separated, trailing * allowed)
VOCION_ALLOWED_ENGINES—Optional fence on factory engines

Roll back

Remove the key. The next run takes its configured route, and the routing history stays where it was recorded.