> ## Documentation Index
> Fetch the complete documentation index at: https://openrouter.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Jev Router

> Let Jev pick the model and reasoning effort for each request, within model lists you control

The [Jev Router](https://openrouter.ai/typesafe/jev-router) (`typesafe/jev-router`) picks a model and reasoning effort for each request. [Jev](/docs/guides/community/jev), TypeSafe's decision model, reads the conversation and judges the task type, difficulty, and how much a stronger model would help. The router then chooses the cheapest candidate that meets that bar from a curated pool of models.

## Usage

Set `model` to `typesafe/jev-router`. No plugin is required:

```bash title="cURL" lines theme={null}
curl https://openrouter.ai/api/v1/chat/completions \
  -H "Authorization: Bearer $OPENROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "typesafe/jev-router",
    "messages": [
      {"role": "user", "content": "Explain the difference between a mutex and a semaphore."}
    ]
  }'
```

The response `model` field reports the model that served the request. The router works with Chat Completions, Responses, and Messages, streaming and non-streaming.

## Restricting the candidate models

Pass the `jev-router` plugin to narrow the pool Jev chooses from:

<CodeGroup>
  ```typescript title="TypeScript (fetch)" expandable lines theme={null}
  const response = await fetch('https://openrouter.ai/api/v1/chat/completions', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      model: 'typesafe/jev-router',
      plugins: [
        {
          id: 'jev-router',
          models: ['anthropic/*', 'google/*'],
          excluded_models: ['anthropic/claude-opus*'],
        },
      ],
      messages: [{ role: 'user', content: 'Summarize this incident report.' }],
    }),
  });

  const completion = await response.json();
  console.log('Model used:', completion.model);
  ```

  ```bash title="cURL" lines theme={null}
  curl https://openrouter.ai/api/v1/chat/completions \
    -H "Authorization: Bearer $OPENROUTER_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "typesafe/jev-router",
      "plugins": [
        {
          "id": "jev-router",
          "models": ["anthropic/*", "google/*"],
          "excluded_models": ["anthropic/claude-opus*"]
        }
      ],
      "messages": [
        {"role": "user", "content": "Summarize this incident report."}
      ]
    }'
  ```
</CodeGroup>

| Field | Description |
| - | - |
| `models` | Include list. Only pool models matching an entry are candidates. |
| `allowed_models` | Alias of `models`, using the [Auto Router](/docs/guides/routing/routers/auto-router) field name. Entries from both fields are combined. |
| `excluded_models` | Exclude list. Matching models are never used, even if they match `models`. |

Each entry can be:

* An exact model slug, such as `openai/gpt-6-luna`. It matches every dated revision of that slug.
* A dated revision, such as `openai/gpt-6-luna-20260922`, which matches only that revision.
* A wildcard pattern, such as `anthropic/*` or `*flash*`. Matching is case-sensitive.
* A `~author/family-latest` alias, such as `~openai/gpt-luna-latest`, which matches every revision of that family.

Each list takes up to 1,024 patterns. The plugin rejects unknown keys with a `400`, so a misspelled field such as `allowed_model` fails instead of being ignored.

### How the lists apply

The lists only narrow the router's pool. They do not add models, and they do not change how Jev ranks the candidates that remain.

* **An include list that matches nothing is ignored.** If no pool model matches `models`, the router uses the whole pool, and `excluded_models` still applies. This keeps requests working when an entry is misspelled or names a model outside the pool. The [pipeline stage](#seeing-what-the-router-did) reports `list_fallback: "models_ignored"`.
* **Exclusions are never ignored.** If `excluded_models` removes every pool model, the request fails with `404` instead of routing to an excluded model.
* **The lists can lower the tier.** When a hard request needs a stronger tier than the remaining models offer, the router uses the strongest tier the lists leave. The stage reports that tier as `list_tier_cap`.
* **The lists can remove the advisor.** For the hardest requests, the router can pair the chosen model with an expert advisor. If your lists remove every advisor, the router answers with a deep-tier model and no advisor, and the stage reports `max_fallback: "deep"`.

If the lists leave no model that is admitted for the request, for example because the only remaining models are excluded for that task type, the request fails with `404`. The error names the fields you sent, such as `widen allowed_models` or `remove excluded_models`.

## Seeing what the router did

Send `X-OpenRouter-Metadata: enabled` to get [router metadata](/docs/guides/features/router-metadata) on the response. The `jev-router` entry in `openrouter_metadata.pipeline` includes:

| Field | Meaning |
| - | - |
| `resolved_models` | Models the router selected, in fallback order. |
| `models`, `excluded_models` | The lists the router applied. `models` includes `allowed_models` entries. |
| `list_fallback` | `"models_ignored"` when the include list matched no pool model. |
| `list_tier_cap` | The tier the lists capped the request at, when they lowered it. |
| `max_fallback` | `"deep"` when a request that would get an advisor was served without one. |

```bash title="cURL" lines theme={null}
curl https://openrouter.ai/api/v1/chat/completions \
  -H "Authorization: Bearer $OPENROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -H "X-OpenRouter-Metadata: enabled" \
  -d '{
    "model": "typesafe/jev-router",
    "plugins": [{"id": "jev-router", "models": ["anthropic/*"]}],
    "messages": [{"role": "user", "content": "Reply with ok"}]
  }' | jq '.openrouter_metadata.pipeline[] | select(.name == "jev-router") | .data | {resolved_models, models, list_fallback}'
```

## Related

* [Jev](/docs/guides/community/jev): the decision model behind the router
* [Auto Router](/docs/guides/routing/routers/auto-router): classifier-based routing with `allowed_models`
* [Router metadata](/docs/guides/features/router-metadata): the `openrouter_metadata` response field
