> ## 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.

# Pi Runtime And Credentials

> Execute selected models through Pi AI while keeping credentials in the host.

Router Core includes a first-party runtime built on [`@mupt-ai/pi-ai`](https://www.npmjs.com/package/@mupt-ai/pi-ai). Pi translates normalized router requests into provider API calls and converts output back into the framework's completion or stream contract.

Supports OpenAI, Anthropic, Google, Bedrock, OpenRouter, Fireworks-hosted models, and any OpenAI-compatible API in Pi's catalog.

## Inject Credentials

<Tabs>
  <Tab title="Single Key">
    When all models use the same credential:

    ```ts theme={null}
    const pi = await createPiRuntime({
      apiKey: process.env.OPENAI_API_KEY!,
    });
    ```
  </Tab>

  <Tab title="Per Provider">
    A resolver receives provider, model, API dialect, and call purpose:

    ```ts theme={null}
    const pi = await createPiRuntime({
      apiKey: async ({ provider, model, api, purpose }) => {
        const key = await loadApiKey({ provider, model, api, purpose });
        if (!key) throw new Error(`No key for ${provider}`);
        return key;
      },
      timeoutMs: 120_000,
      maxRetries: 2,
    });
    ```

    `purpose` is `execution` or `selector` — use different keys per purpose.
  </Tab>
</Tabs>

Router Core never reads environment variables. The host reads keys and injects them.

## Declare Catalog Models

`pi.model()` validates a model exists in Pi's catalog and creates a `RouterModel` declaration:

```ts theme={null}
const models = [
  pi.model("openai/gpt-5.4-mini"),
  pi.model("anthropic/claude-sonnet-4-6", { defaultReasoningEffort: "high" }),
];
// Omit executor → uses the runtime from createRouter()
const router = createRouter({ models, policy, runtime: pi });
```

## What Gets Translated

Pi carries these normalized features into provider calls:

* Messages, images, tool calls, tool results
* Prior-turn reasoning and hosted `web_search` calls
* Function tools, named/required tool choice, strict/parallel tools
* Temperature, top-p, token limits, stop sequences
* Provider-independent reasoning effort and token budgets
* Text, JSON object, and JSON Schema output formats
* Cache keys, streaming, cancellation

Base64 images work out of the box. Remote image URLs are rejected — download and validate them in the host, or use a custom executor.

## Retries And Errors

`maxRetries` controls Pi's same-model retries. Provider failures, malformed output, invalid streams, and cancellation become `RouterFrameworkError`.

Cross-model fallback belongs to `createRouter`, not the runtime: enable it with the [`fallback` option](/framework/custom-executors#retry-and-fallback) and it works with the Pi executor like any other. For fully managed retries and fallback chains, use [Dari's managed platform](/router/overview).

## Per-API Option Gating

Some normalized options can't be expressed on every provider API. Pi rejects those combinations up front as `invalid_request` (HTTP 400) instead of surfacing a provider 5xx:

* `stop` sequences on `openai-responses` / `azure-openai-responses`
* `top_p` on `anthropic-messages`
* Forcing a specific tool with `tool_choice` on `google-generative-ai` / `google-vertex`
* `response_format: json_object` on `bedrock-converse-stream`
* Non-`auto` image `detail` on APIs that can't preserve it (details are `auto`, `low`, or `high` and pass through on the OpenAI APIs)

Two options degrade instead of failing: `json_object` on `anthropic-messages` becomes a permissive JSON Schema (Anthropic has no native JSON-object mode), and `metadata` is never forwarded — only `user`, which maps to Anthropic's `metadata.user_id` and nothing on other APIs.

## Mix Pi And Custom Executors

```ts theme={null}
const models = [
  pi.model("openai/gpt-5.4-mini"),
  { id: "acme/private-model", executor: "acme", capabilities: { streaming: true } },
];
const router = createRouter({ models, policy, runtime: pi, executors: { acme } });
```

See [Custom Executors](/framework/custom-executors) for the output contracts.
