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

# Models

> Declare model capabilities and understand eligibility filtering.

A router evaluates models in two stages. First Router Core filters out candidates that can't handle the request. Then your policy picks one.

## Declare Pi Models

Use `pi.model()` for models in Pi AI's catalog:

```ts theme={null}
const models = [
  pi.model("openai/gpt-5.4-mini"),
  pi.model("anthropic/claude-sonnet-4-6", {
    defaultReasoningEffort: "high",
    metadata: { tier: "premium" },
  }),
];
```

The ID uses `provider/native-model-id` form. Pi fills in capabilities and reasoning levels from its catalog. The second argument overrides defaults or adds metadata for custom policies.

### Declare Custom Models

For models outside Pi's catalog, declare capabilities manually:

```ts theme={null}
import type { RouterModel } from "@dari/router-core";

const customModel = {
  id: "acme/private-model",
  executor: "acme",
  provider: "acme",
  api: "private-rpc",
  reasoningEfforts: ["off", "high"],
  defaultReasoningEffort: "off",
  capabilities: {
    imageInput: true,
    toolUse: true,
    structuredOutput: true,
    streaming: true,
  },
} satisfies RouterModel;
```

Standalone declarations need the `satisfies RouterModel` ascription — without it, `reasoningEfforts` infers as `string[]` and fails to type-check when passed to `createRouter`. Objects written inline inside `models: [...]` are contextually typed and don't need it.

When omitted: provider defaults to the prefix before `/`, api defaults to the executor name, reasoning efforts default to `["off"]`, all capabilities default to `false`.

## Eligibility

Router Core removes candidates that can't satisfy the request's:

* image input
* declared tools or tool-call history
* structured response format
* streaming mode
* requested reasoning effort

A policy can't choose an ineligible model. If nothing remains, the request fails with `no_eligible_models`.

## Reasoning Efforts

Provider-independent levels: `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max` — ordered from none to highest. Pi maps each label to the provider's native control.

OpenAI callers can constrain selection with `reasoning_effort`. Anthropic callers use `output_config.effort` and `thinking`.

Without a request constraint, the policy may select any effort the candidate exposes.
