# zidane/providers

> The `Provider` contract, the shared provider helpers, OAuth credential handling and the Mistral, Z.ai and Cursor providers.

Import: `import { … } from 'zidane/providers'`. Source: [src/providers/index.ts](https://github.com/Tahul/zidane/blob/main/src/providers/index.ts).

Use `zidane/providers` to write your own provider or manage OAuth credentials. It holds the `Provider` interface and its types, the model catalog, prompt-cache key helpers and tool-schema sanitizing, plus `mistral()`, `zai()` and `cursor()`. The other providers, Neuralwatt included, are also exported here, and each has its own entry too. The agent passes its session id to every stream call (`StreamOptions.sessionId`), so a provider can route a conversation to one cache replica. See [Providers](https://zidane.si/docs/providers.md).

```ts
import { createAgent } from 'zidane'
import { mistral } from 'zidane/providers'

const provider = mistral()
const agent = createAgent({ provider })

console.log(provider.name, provider.meta.defaultModel)
await agent.run({ prompt: 'Say hello.' })
```

## Functions

### `credentialsFilePath`

Function.

Resolve the creds-file path at call time rather than module-load time, so
env changes between import and first OAuth use (test suites, multi-project
CLIs) are honored.

Order:

1. `ZIDANE_CREDENTIALS_PATH` — explicit override. The chat host sets this
   at launch to point at the credentials file in its storage directory, so
   the harness providers find the same file the host manages.
2. `~/.credentials.json` — home-anchored default.

The working directory is never consulted: launching zidane inside an
untrusted checkout would let that repo plant a `.credentials.json` and
become the credential source (and receive rotated refresh tokens on the next
refresh persist). Same trust model as the TUI's legacy-file migration in
`chat/credentials.ts`, which only honors the home-anchored location.

```ts
function credentialsFilePath(): string
```

**Returns** `string`

Source: [src/providers/oauth.ts:36](https://github.com/Tahul/zidane/blob/main/src/providers/oauth.ts#L36)

### `credentialsFromParams`

Function.

Builds OAuth credentials from the runtime `access`, `refresh` and `expires` params, plus any listed extra keys that are set. Returns `undefined` when one of the three is missing.

```ts
function credentialsFromParams<TParams extends OAuthParams>(
  params?: TParams,
  extraKeys?: (keyof TParams & string)[],
): OAuthCredentials | undefined
```

**Type parameters**

- `TParams` (`extends OAuthParams`)

**Parameters**

- `params?` (`TParams`): Provider params that may carry runtime credentials.
- `extraKeys?` (`(keyof TParams & string)[]`, default `[]`): Extra `params` keys to copy into the credentials.

**Returns** `OAuthCredentials | undefined`

Source: [src/providers/oauth.ts:475](https://github.com/Tahul/zidane/blob/main/src/providers/oauth.ts#L475)

### `cursor`

Function.

Cursor provider (OAuth).

Auth is fully wired: `bun run auth --cursor` (or the TUI wizard) logs in via
Cursor's poll-based PKCE flow and persists credentials; this provider resolves

- refreshes the OAuth token on every turn via [`resolveOAuthApiKey`](https://zidane.si/docs/reference/providers.md#resolveOAuthApiKey).

Inference is **not** wired yet. Cursor does not expose an OpenAI-compatible
HTTP endpoint — it speaks a protobuf/Connect agent protocol over HTTP/2 to
`api2.cursor.sh`. Implementing `stream()` requires porting that transport
(generated protobuf schemas + an HTTP/2 streaming client) in-process, which
is intentionally left as a follow-up. Until then `stream()` resolves the
token (proving auth works) and then throws a clear, actionable error.

The `openaiCompat` base supplies the message-format helpers (`formatTools`,
`userMessage`, `toolResultsMessage`, …) so the provider satisfies the full
`Provider` contract and slots into the registry; only `stream` is overridden.

```ts
function cursor(params?: CursorParams): Provider
```

**Parameters**

- `params?` (`CursorParams`): Optional token override, default model and extra headers.

**Returns** `Provider`

Source: [src/providers/cursor.ts:51](https://github.com/Tahul/zidane/blob/main/src/providers/cursor.ts#L51)

### `derivePromptCacheKey`

Function.

A key for what a session shares when no session id is available: the static
half of the system prompt plus the first user message.

Deliberately NOT the whole transcript — that grows every turn, which would
hand out a new key per request and defeat the point. Nor the dynamic half of
the system prompt (after `SYSTEM_PROMPT_BOUNDARY`, see `splitSystemPrompt`):
it carries the date and working directory, so hashing it would move the key
when the day rolls over mid-session. What remains stays byte-identical for a
session's life and moves only with a different agent profile, a new opener,
or a compaction that rewrites the head.

The message contribution is capped at its first 4 KiB of JSON: this runs on
every stream call, and a first message carrying inline media (multi-MB
base64) would pay a full stringify + hash per turn for no routing benefit —
the first few hundred bytes already distinguish sessions, and the servers
themselves only hash \~the first 256 tokens for routing. Two sessions that
agree on system + 4 KiB of opener share a routing bucket, which is exactly
when sharing a replica helps rather than hurts.

32 hex chars of sha256, matching the digest width used in
`src/attachment-handle.ts`.

```ts
function derivePromptCacheKey(
  system: string,
  messages: readonly SessionMessage[],
): string
```

**Parameters**

- `system` (`string`): System prompt of the session. Only the static half contributes.
- `messages` (`readonly SessionMessage[]`): Session messages. Only the first user message contributes.

**Returns** `string`

Source: [src/providers/prompt-cache-key.ts:117](https://github.com/Tahul/zidane/blob/main/src/providers/prompt-cache-key.ts#L117)

### `ensureBundledOAuthFlows`

Function.

OAuth registry surface.

`refreshAnthropicToken` / `refreshOpenAICodexToken` are zidane's local
reimplementations of functions pi-ai exported until 0.80.6 and dropped in
0.80.8. The runtime of its `@earendil-works/pi-ai/oauth` entrypoint is
`export {}` (it ships types only). They are exported HERE because consumers
that imported them from pi-ai otherwise have no supported replacement.

```ts
function ensureBundledOAuthFlows(): Promise<void>
```

**Returns** `Promise<void>`

Source: [src/providers/oauth-registry.ts:106](https://github.com/Tahul/zidane/blob/main/src/providers/oauth-registry.ts#L106)

### `extractRuntimeCredentials`

Function.

Pull a complete `{ access, refresh, expires }` triple out of provider params
when (and only when) all three OAuth fields are present and well-typed.
Returns `undefined` for the static-api-key path. Shared by the OAuth-capable
providers so the runtime-credential guard can't drift between them.

```ts
function extractRuntimeCredentials(
  params?: OAuthParams,
): { access: string; expires: number; refresh: string } | undefined
```

**Parameters**

- `params?` (`OAuthParams`): Provider params that may carry runtime OAuth credentials.

**Returns** `{ access: string; expires: number; refresh: string } | undefined`

Source: [src/providers/oauth.ts:160](https://github.com/Tahul/zidane/blob/main/src/providers/oauth.ts#L160)

### `getModelCatalog`

Function.

The process-wide catalog, normalized to source form.

```ts
function getModelCatalog(): ModelCatalogSource | undefined
```

**Returns** `ModelCatalogSource | undefined`

Source: [src/providers/model-catalog.ts:156](https://github.com/Tahul/zidane/blob/main/src/providers/model-catalog.ts#L156)

### `getOAuthApiKey`

Function.

Get an API key for a provider from OAuth credentials, refreshing expired
tokens through the registered flow. Same contract as the pi-ai original
(`null` when no credentials are stored for the provider, throws on unknown
provider or refresh failure), with two deliberate additions:

- refresh failures keep the underlying reason — the original discarded it,
  leaving invalid_grant (needs re-login) indistinguishable from a transient
  network error.
- `options.force` rotates regardless of the local expiry, for 401 recovery
  when the server revoked the grant before our stored timestamp said so.
  Expressed as a flag rather than by handing this function a credential
  with a doctored `expires`: callers persist whatever comes back, so a
  fabricated expiry that a provider echoes through would land in the
  credential store. See `resolveOAuthApiKey` in `./oauth.ts`.

```ts
function getOAuthApiKey(
  providerId: string,
  credentials: Record<string, OAuthCredentials>,
  options?: { force?: boolean },
): Promise<{ apiKey: string; newCredentials: OAuthCredentials } | null>
```

**Parameters**

- `providerId` (`string`): Id of the registered flow.
- `credentials` (`Record<string, OAuthCredentials>`): Stored credentials keyed by provider id.
- `options?` (`{ force?: boolean }`): Set `force` to refresh even when the credential has not expired.

**Returns** `Promise<{ apiKey: string; newCredentials: OAuthCredentials } | null>`

Source: [src/providers/oauth-registry.ts:346](https://github.com/Tahul/zidane/blob/main/src/providers/oauth-registry.ts#L346)

### `getOAuthProvider`

Function.

Get a registered OAuth provider by id.

```ts
function getOAuthProvider(id: string): OAuthProviderInterface | undefined
```

**Parameters**

- `id` (`string`): Id of the flow to look up.

**Returns** `OAuthProviderInterface | undefined`

Source: [src/providers/oauth-registry.ts:322](https://github.com/Tahul/zidane/blob/main/src/providers/oauth-registry.ts#L322)

### `isOAuthAccessToken`

Function.

Whether a credential string is an OAuth *access token* rather than a real,
static API key. Anthropic OAuth tokens are prefixed `sk-ant-oat`; OpenAI
Codex OAuth access tokens are JWTs (`eyJ...`). Used to decide whether an
env-provided value can be refreshed (OAuth) or must be sent verbatim (API key).

```ts
function isOAuthAccessToken(value: string): boolean
```

**Parameters**

- `value` (`string`): Credential string to classify.

**Returns** `boolean`

Source: [src/providers/oauth.ts:135](https://github.com/Tahul/zidane/blob/main/src/providers/oauth.ts#L135)

### `mistral`

Function.

Mistral provider (La Plateforme).

Thin wrapper around [`openaiCompat`](https://zidane.si/docs/reference/providers-openai-compat.md#openaiCompat) with Mistral-specific defaults
(base URL, default model, `reasoning_effort` planner). `supportsReasoning`
stays off: Mistral carries thinking inside `content` chunks rather than a
`reasoning_content` field, so there is nothing to echo back upstream —
thinking streams to the UI and is dropped from subsequent requests.

```ts
function mistral(params?: MistralParams): Provider
```

**Parameters**

- `params?` (`MistralParams`): API key, base URL, default model, capabilities and extra headers.

**Returns** `Provider`

Source: [src/providers/mistral.ts:92](https://github.com/Tahul/zidane/blob/main/src/providers/mistral.ts#L92)

### `openrouterImageModels`

Function.

OpenRouter's image models, from pi-ai's bundled catalog.

```ts
function openrouterImageModels(): readonly ImageModelInfo[]
```

**Returns** `readonly ImageModelInfo[]`

Source: [src/providers/images/openrouter.ts:28](https://github.com/Tahul/zidane/blob/main/src/providers/images/openrouter.ts#L28)

### `pinnedAccountMissingError`

Function.

Why a call pinned to `account` cannot run: the account is no longer stored.

```ts
function pinnedAccountMissingError(provider: string): string
```

**Parameters**

- `provider` (`string`): Provider name as the user knows it, put in the message.

**Returns** `string`

Source: [src/providers/oauth.ts:109](https://github.com/Tahul/zidane/blob/main/src/providers/oauth.ts#L109)

### `planMistralReasoning`

Function.

Map zidane's thinking level to Mistral's `reasoning_effort`. Only the two
documented values are emitted — `'none'` (thinking chunk omitted, `content`
stays a plain string) and `'high'` (full thinking chunk). `adaptive` sends
nothing so the model's own default applies.

Exported for tests.

```ts
function planMistralReasoning(
  ctx: { model: string; thinking?: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | 'adaptive' },
): Record<string, unknown> | undefined
```

**Parameters**

- `ctx` (`{ model: string; thinking?: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | 'adaptive' }`): Request model id and thinking level.

**Returns** `Record<string, unknown> | undefined`

Source: [src/providers/mistral.ts:71](https://github.com/Tahul/zidane/blob/main/src/providers/mistral.ts#L71)

### `planZaiReasoning`

Function.

Map zidane's thinking level to Z.ai's `extra_body.thinking` request shape.
GLM has no depth knob — thinking is a binary switch — so any non-`off`
level enables it and `off` explicitly disables it (GLM-5.x/4.7 think by
default, so a silent omission would not turn thinking off).

Exported for tests.

```ts
function planZaiReasoning(
  ctx: { thinking?: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | 'adaptive' },
): Record<string, unknown>
```

**Parameters**

- `ctx` (`{ thinking?: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | 'adaptive' }`): Request thinking level.

**Returns** `Record<string, unknown>`

Source: [src/providers/zai.ts:60](https://github.com/Tahul/zidane/blob/main/src/providers/zai.ts#L60)

### `readAccountOAuthCredential`

Function.

The stored OAuth credential of `baseKey` whose stable id is `account`, as
the provider-side reader sees it; `undefined` when no slot holds it.

```ts
function readAccountOAuthCredential(
  baseKey: string,
  account: string,
  path?: string,
): OAuthCredentials | undefined
```

**Parameters**

- `baseKey` (`string`): Provider key the credential is stored under (e.g. `anthropic`).
- `account` (`string`): Stable id of the account to read.
- `path?` (`string`): Credentials file; defaults to the user's.

**Returns** `OAuthCredentials | undefined`

Source: [src/providers/oauth.ts:121](https://github.com/Tahul/zidane/blob/main/src/providers/oauth.ts#L121)

### `readOAuthCredentials`

Function.

Read the shared credentials file.

Returns `{}` when the file is missing OR when the file exists but is corrupted
/ not valid JSON. Corrupt-file tolerance is important: the refresh-then-persist
path below writes atomically, but older builds wrote in place and could have
truncated the file on a crash. Treating corruption as "no stored creds" lets
users re-auth without manually deleting the file.

Supports two on-disk shapes:

1. **Legacy** (untagged): `{ "anthropic": { access, refresh, expires, ... } }`
   — written by older `bun run auth`.
2. **New** (kind-tagged): `{ "anthropic": { kind: 'oauth', access, refresh, expires, ... } }`
   — written by the TUI. Entries with `kind: 'apikey'` are skipped — those
   reach providers via env vars set at TUI launch (see `applyApiKeyEnv`).

```ts
function readOAuthCredentials(): Record<string, OAuthCredentials | undefined>
```

**Returns** `Record<string, OAuthCredentials | undefined>`

Source: [src/providers/oauth.ts:239](https://github.com/Tahul/zidane/blob/main/src/providers/oauth.ts#L239)

### `refreshAnthropicToken`

Function.

Refresh an Anthropic (Claude Pro/Max) OAuth token. Drop-in replacement for
the `refreshAnthropicToken` pi-ai exported until 0.80.6; delegates to the
canonical flow on `anthropicProvider().auth.oauth`.

```ts
function refreshAnthropicToken(refreshToken: string): Promise<OAuthCredentials>
```

**Parameters**

- `refreshToken` (`string`): Refresh token of the stored credentials.

**Returns** `Promise<OAuthCredentials>`

Source: [src/providers/oauth-registry.ts:124](https://github.com/Tahul/zidane/blob/main/src/providers/oauth-registry.ts#L124)

### `refreshOpenAICodexToken`

Function.

Refresh an OpenAI Codex (ChatGPT) OAuth token. Drop-in replacement for the
removed `refreshOpenAICodexToken`; the canonical flow still derives
`accountId` from the refreshed access token's JWT claims, so the returned
credentials keep the extra field older callers persisted.

```ts
function refreshOpenAICodexToken(refreshToken: string): Promise<OAuthCredentials>
```

**Parameters**

- `refreshToken` (`string`): Refresh token of the stored credentials.

**Returns** `Promise<OAuthCredentials>`

Source: [src/providers/oauth-registry.ts:138](https://github.com/Tahul/zidane/blob/main/src/providers/oauth-registry.ts#L138)

### `registerCustomOAuthProvider`

Function.

Register a custom OAuth flow with the local registry (`./oauth-registry`)
so lazy refresh through [`resolveOAuthApiKey`](https://zidane.si/docs/reference/providers.md#resolveOAuthApiKey) can resolve `providerId`.

Public because provider extensions need it: without registration,
`getOAuthApiKey('<id>', …)` throws `Unknown OAuth provider` the first time a
stored token expires. Idempotent per id (the registry is a keyed map).
Returns a promise for API stability.

```ts
function registerCustomOAuthProvider(provider: OAuthProviderInterface): Promise<void>
```

**Parameters**

- `provider` (`OAuthProviderInterface`): OAuth flow definition to register, keyed by its `id`.

**Returns** `Promise<void>`

Source: [src/providers/oauth.ts:75](https://github.com/Tahul/zidane/blob/main/src/providers/oauth.ts#L75)

### `registerOAuthProvider`

Function.

Register (or replace) an OAuth provider by id.

```ts
function registerOAuthProvider(provider: OAuthProviderInterface): void
```

**Parameters**

- `provider` (`OAuthProviderInterface`): Flow to register. Replaces any flow with the same `id`.

Source: [src/providers/oauth-registry.ts:296](https://github.com/Tahul/zidane/blob/main/src/providers/oauth-registry.ts#L296)

### `resolveOAuthApiKey`

Function.

Resolves the API key for an OAuth provider.
Returns a static `apiKey`, runtime `access` token or env key as is, otherwise reads the stored credentials and refreshes them when expired. Refreshed credentials are persisted and concurrent refreshes of the same credential are shared. Throws `missingError` when no credential exists and `refreshError` when the refresh fails.

```ts
function resolveOAuthApiKey<TParams extends OAuthParams>(
  options: ResolveOAuthApiKeyOptions<TParams>,
  callbacks?: Pick<StreamCallbacks, 'onOAuthRefresh'> & { onOAuthStage?: (stage: 'credentials' | 'refresh' | 'shared-refresh') => void },
): Promise<string>
```

**Type parameters**

- `TParams` (`extends OAuthParams`)

**Parameters**

- `options` (`ResolveOAuthApiKeyOptions<TParams>`): Provider identity, credential sources and error messages.
- `callbacks?` (`Pick<StreamCallbacks, 'onOAuthRefresh'> & { onOAuthStage?: (stage: 'credentials' | 'refresh' | 'shared-refresh') => void }`): Hooks called with refresh events and credential-resolution stages.

**Returns** `Promise<string>`

Source: [src/providers/oauth.ts:500](https://github.com/Tahul/zidane/blob/main/src/providers/oauth.ts#L500)

### `resolvePromptCacheKey`

Function.

Resolve a configured option into the key to send, or `undefined` to send
nothing. Empty strings (including an empty session id) are treated as "send
nothing" so a host threading through a possibly-unset id can pass it
straight in.

```ts
function resolvePromptCacheKey(
  option: PromptCacheKeyOption | undefined,
  ctx: PromptCacheKeyContext,
): string | undefined
```

**Parameters**

- `option` (`PromptCacheKeyOption | undefined`): Configured key option.
- `ctx` (`PromptCacheKeyContext`): Request context passed to function options and used for derivation.

**Returns** `string | undefined`

Source: [src/providers/prompt-cache-key.ts:132](https://github.com/Tahul/zidane/blob/main/src/providers/prompt-cache-key.ts#L132)

### `sanitizeToolSchema`

Function.

Sanitize a single tool's `inputSchema` for safe forwarding to the
provider. Returns the rewritten schema + a list of warnings describing
everything that changed.

Never mutates the input. Returns the **same reference** when no rewrite
was needed (clean-schema fast path) — `sanitizeToolSpecs` relies on
this to keep the formatTools hot loop allocation-free across turns
when the registered tool set is already wire-valid.

```ts
function sanitizeToolSchema(
  input: unknown,
  options?: SchemaSanitizeOptions,
): SchemaSanitizeResult
```

**Parameters**

- `input` (`unknown`): Raw tool `inputSchema`. A non-object input yields an empty object schema.
- `options?` (`SchemaSanitizeOptions`, default `{}`): Strictness profile and tool name for warning prefixes.

**Returns** `SchemaSanitizeResult`

Source: [src/providers/schema-sanitize.ts:398](https://github.com/Tahul/zidane/blob/main/src/providers/schema-sanitize.ts#L398)

### `sanitizeToolSpecs`

Function.

Convenience: sanitize a batch of tools and emit a single de-duped
`console.warn` per unique warning line. Returns the rewritten tools
preserving original ordering and reference identity for clean schemas
(no reallocation when nothing needed to change).

The sanitiser runs every request. The de-dupe set is local to one call,
so within a batch each warning line is logged once and the first
occurrence is kept.

Final name guard: a tool whose `name` violates the provider constraint
is DROPPED (not throwingly forwarded) with a one-time warning. An invalid
name 400s the entire `messages.create` — taking every other tool and the
turn down with it — so silently degrading one capability is the strictly
safer failure mode. Upstream aliasing already coerces MCP names to valid
wire names, so in practice this only fires for names that cannot be
represented at all; it's defense-in-depth that keeps a malformed name in
the list from reaching the wire.

```ts
function sanitizeToolSpecs<T extends { inputSchema?: unknown; name: string }>(
  tools: readonly T[],
  options?: { onWarning?: (line: string) => void; profile?: SchemaSanitizeProfile },
): T[]
```

**Type parameters**

- `T` (`extends { inputSchema?: unknown; name: string }`)

**Parameters**

- `tools` (`readonly T[]`): Tool specs to sanitize.
- `options?` (`{ onWarning?: (line: string) => void; profile?: SchemaSanitizeProfile }`, default `{}`): `profile` picks the strictness profile (default `'permissive'`). `onWarning` receives each unique warning line once (default `console.warn`).

**Returns** `T[]`

Source: [src/providers/schema-sanitize.ts:452](https://github.com/Tahul/zidane/blob/main/src/providers/schema-sanitize.ts#L452)

### `setModelCatalog`

Function.

Install (or clear, with `null`) the process-wide catalog. Latest call wins.

Prefer `behavior.modelCatalog` when you can: it needs no global state and
scopes to one agent or one run. Use this for a deployment-wide correction,
or when the host's model picker must see the override too.

```ts
function setModelCatalog(catalog: ModelCatalog | null): void
```

**Parameters**

- `catalog` (`ModelCatalog | null`): Catalog to install, or `null` to clear it.

Source: [src/providers/model-catalog.ts:151](https://github.com/Tahul/zidane/blob/main/src/providers/model-catalog.ts#L151)

### `writeOAuthCredentials`

Function.

Incoming entries are a provider-local patch, not a read-time snapshot.

```ts
function writeOAuthCredentials(
  credentials: Record<string, OAuthCredentials | undefined>,
): void
```

**Parameters**

- `credentials` (`Record<string, OAuthCredentials | undefined>`): Entries to merge into the credentials file. An `undefined` value removes that key.

Source: [src/providers/oauth.ts:464](https://github.com/Tahul/zidane/blob/main/src/providers/oauth.ts#L464)

### `zai`

Function.

Z.ai (Zhipu) GLM provider.

Thin wrapper around [`openaiCompat`](https://zidane.si/docs/reference/providers-openai-compat.md#openaiCompat) pinned to the `reasoning_content`
round-trip mode: thinking arrives in the `reasoning_content` delta field and
is echoed back on assistant messages under the same name, keeping GLM's
interleaved/preserved thinking coherent across tool calls.

```ts
function zai(params?: ZaiParams): Provider
```

**Parameters**

- `params?` (`ZaiParams`): API key, base URL, default model, capabilities and extra headers.

**Returns** `Provider`

Source: [src/providers/zai.ts:77](https://github.com/Tahul/zidane/blob/main/src/providers/zai.ts#L77)

## Constants

### `GOOGLE_IMAGE_MODELS`

Constant.

Gemini image models on the Gemini API.

```ts
const GOOGLE_IMAGE_MODELS: readonly ImageModelInfo[]
```

Source: [src/providers/images/google.ts:15](https://github.com/Tahul/zidane/blob/main/src/providers/images/google.ts#L15)

### `IMAGE_ASPECT_RATIOS`

Constant.

Aspect ratios every adapter accepts. Each adapter maps them to its API (OpenAI to the nearest of its three sizes).

```ts
const IMAGE_ASPECT_RATIOS: readonly ['1:1', '16:9', '9:16', '4:3', '3:4', '3:2', '2:3', '21:9']
```

Source: [src/providers/images/types.ts:9](https://github.com/Tahul/zidane/blob/main/src/providers/images/types.ts#L9)

### `MAX_IMAGES_PER_REQUEST`

Constant.

Most images one request returns.

```ts
const MAX_IMAGES_PER_REQUEST = 4
```

Source: [src/providers/images/types.ts:15](https://github.com/Tahul/zidane/blob/main/src/providers/images/types.ts#L15)

### `OPENAI_IMAGE_MODELS`

Constant.

OpenAI's GPT Image models.

```ts
const OPENAI_IMAGE_MODELS: readonly ImageModelInfo[]
```

Source: [src/providers/images/openai.ts:16](https://github.com/Tahul/zidane/blob/main/src/providers/images/openai.ts#L16)

### `XAI_IMAGE_MODELS`

Constant.

xAI's Grok Imagine image models.

```ts
const XAI_IMAGE_MODELS: readonly ImageModelInfo[]
```

Source: [src/providers/images/xai.ts:13](https://github.com/Tahul/zidane/blob/main/src/providers/images/xai.ts#L13)

## Interfaces

### `CursorParams`

Interface.

Options for [`cursor`](https://zidane.si/docs/reference/providers.md#cursor).

```ts
interface CursorParams
```

**Properties**

- `apiKey?` (`string`): Bypass OAuth resolution with an explicit token (mainly for tests).
- `defaultModel?` (`string`, default `'claude-4.6-sonnet'`): Model id reported by the provider.
- `extraHeaders?` (`Record<string, string>`): Extra HTTP headers for the eventual Cursor transport. Accepted for API
  parity with the other providers and forwarded to the openai-compat base,
  but inert until Cursor inference is implemented (the `stream` override
  currently throws before any request is made).

Source: [src/providers/cursor.ts:7](https://github.com/Tahul/zidane/blob/main/src/providers/cursor.ts#L7)

### `HistoryRepair`

Interface.

Request from a provider to repair canonical session history before it retries a rejected request.

```ts
interface HistoryRepair
```

**Properties**

- `type` (`'invalid-anthropic-thinking-signature'`): Anthropic rejected one or more opaque historical thinking signatures.
  The loop must remove Anthropic/legacy signed + redacted reasoning from
  canonical history before the provider retries, so future turns and
  session reloads don't pay the same rejected request again.
- `wireMessageIndex?` (`number`): Wire index of the message the API pinpointed (`messages.5.content.0:
  Invalid signature…`), when parseable. Bounds request-payload scrubbing
  to blocks at/before the failing message — later messages can carry
  STILL-VALID thinking the active tool-use chain must keep. Canonical
  history repair uses run identity instead (current-run turns are never
  touched), so this only tunes the in-flight payload cleanup.

Source: [src/providers/index.ts:181](https://github.com/Tahul/zidane/blob/main/src/providers/index.ts#L181)

### `ImageData`

Interface.

A base64 image, as sent to or returned by an image API.

```ts
interface ImageData
```

**Properties**

- `data` (`string`): Base64 bytes, without a `data:` prefix.
- `mediaType` (`string`): IANA media type, for example `image/png`.

Source: [src/providers/images/types.ts:30](https://github.com/Tahul/zidane/blob/main/src/providers/images/types.ts#L30)

### `ImageModelInfo`

Interface.

One image model of a provider.

```ts
interface ImageModelInfo
```

**Properties**

- `id` (`string`): Model id as the provider's API names it.
- `input` (`readonly ('text' | 'image')[]`): What the model takes as input. `image` means it accepts reference images to edit or match.
- `name?` (`string`): Display name.
- `transparency?` (`boolean`): The model can return a transparent background.

Source: [src/providers/images/types.ts:18](https://github.com/Tahul/zidane/blob/main/src/providers/images/types.ts#L18)

### `InputTransformation`

Interface.

One replayed `thinking` / `redacted_thinking` block the API discarded before
sampling, reported in the response's `input_transformations` array (requires
the `thinking-binding-controls-2026-08-01` beta; Anthropic-only today).

```ts
interface InputTransformation
```

**Properties**

- `path` (`string`): Wire locator of the dropped block, e.g. `messages.3.content.0`.
- `reason` (`string`): - `'prefix_binding_mismatch'`: something before the block (system, tools,
  an earlier message) changed since it was produced — a host-side edit.
  - `'model_binding_mismatch'`: the block came from a newer model than the
    one serving this request; not an integration bug.
- `type` (`string`): Currently always `'thinking_dropped'`.

Source: [src/providers/index.ts:205](https://github.com/Tahul/zidane/blob/main/src/providers/index.ts#L205)

### `MistralParams`

Interface.

Options for [`mistral`](https://zidane.si/docs/reference/providers.md#mistral).

```ts
interface MistralParams
```

**Properties**

- `apiKey?` (`string`): API key. Falls back to the `MISTRAL_API_KEY` environment variable.
- `baseURL?` (`string`): Override the base URL — e.g. point at a regional endpoint or a gateway in
  front of La Plateforme.
- `capabilities?` (`ProviderCapabilities`): Provider capability flags. The `mistral-medium` / `mistral-large` /
  `pixtral` families accept `image_url` parts — default:
  `{ vision: true, imageInToolResult: false }`. Set `vision: false` when
  pinning a text-only model (`codestral`, `devstral`, `ministral`).
- `defaultModel?` (`string`, default `'mistral-medium-latest'`): Model used when a request does not set one.
- `extraHeaders?` (`Record<string, string>`): Extra HTTP headers sent on every request. Forwarded to the underlying
  [`openaiCompat`](https://zidane.si/docs/reference/providers-openai-compat.md#openaiCompat) client.

Source: [src/providers/mistral.ts:14](https://github.com/Tahul/zidane/blob/main/src/providers/mistral.ts#L14)

### `ModelCatalogEntry`

Interface.

Metadata for one model. Every field is optional and merges FIELD-LEVEL over
the bundled entry, so `{ maxTokens: 128000 }` corrects the ceiling and
leaves pricing and context window to the registry.

```ts
interface ModelCatalogEntry
```

**Properties**

- `contextWindow?` (`number`): Total context window, in tokens (drives the host-layer context gauge).
- `cost?` (`{ cacheRead?: number; cacheWrite?: number; input?: number; output?: number }`): Per-MTok rates used for cost estimation. Merges PER-RATE over the bundled
  rates, so `{ cost: { output: 30 } }` corrects the output rate and keeps the
  registry's input / cache rates rather than zeroing them.
- `id?` (`string`): Model id. Required only for entries surfaced through `ModelCatalogSource.list`.
- `input?` (`readonly ('text' | 'image')[]`): Accepted input modalities.
- `maxTokens?` (`number`): Max output tokens — the provider's `max_tokens` default and hard clamp.
- `name?` (`string`): Display name for pickers.
- `reasoning?` (`boolean`): Whether the model supports reasoning/thinking.
- `tier?` (`ModelTier`): Size class; overrides the family heuristic.

Source: [src/providers/model-catalog.ts:59](https://github.com/Tahul/zidane/blob/main/src/providers/model-catalog.ts#L59)

### `ModelCatalogSource`

Interface.

Programmatic catalog. Both members are optional and both fall through on
`undefined`, which is what keeps overrides scoped to the providers you
actually own.

```ts
interface ModelCatalogSource
```

**Properties**

- `get?` (`(provider: string, modelId: string) => ModelCatalogEntry | undefined`): Resolve one model. Return `undefined` to fall through to the bundled
  entry for that `(provider, modelId)`.
- `list?` (`(provider: string) => readonly ModelCatalogEntry[] | undefined`): Enumerate a provider's models (model pickers, `modelsForDescriptor`).

  - `undefined` → use the bundled list for that provider (the default).
  - `[…]`       → you own that provider's list; bundled entries are not
    consulted, so this both adds and hides.
  - `[]`        → you own it and it has no models (hides the picker).

Source: [src/providers/model-catalog.ts:92](https://github.com/Tahul/zidane/blob/main/src/providers/model-catalog.ts#L92)

### `OAuthParams`

Interface.

Credential params shared by OAuth-capable providers: a static key or runtime OAuth credentials.

```ts
interface OAuthParams
```

**Properties**

- `access?` (`string`): OAuth access token supplied at runtime. Used together with `refresh` and `expires` to refresh without a credentials file.
- `account?` (`string`): Run on ONE stored account of the provider instead of its active one: the
  credential's stable id (`ProviderCredential.id`, see `chat/credentials`).
  Resolved to the slot holding it on every token read and refresh, so
  promoting another account mid-session never moves this provider to it.
  The provider's env key is ignored while pinned (it is the active
  credential's, not this account's). A missing account fails the call with
  [`pinnedAccountMissingError`](https://zidane.si/docs/reference/providers.md#pinnedAccountMissingError) — never a silent fallback to another
  account.
- `apiKey?` (`string`): Static API key or OAuth access token sent as is, bypassing credential lookup and refresh.
- `expires?` (`number`): Expiry of `access` as a Unix timestamp in milliseconds.
- `refresh?` (`string`): OAuth refresh token supplied at runtime.

Source: [src/providers/oauth.ts:82](https://github.com/Tahul/zidane/blob/main/src/providers/oauth.ts#L82)

### `OAuthProviderInterface`

Interface.

Provider-owned OAuth flow. Mirrors the interface pi-ai exported from
`@earendil-works/pi-ai/oauth` up to 0.80.6 — kept as a local type so
zidane's descriptor seam (`ProviderDescriptor.oauthProvider`) and provider
extensions (e.g. `extensions/bolt`) stay source-compatible across the
upstream removal.

```ts
interface OAuthProviderInterface
```

**Properties**

- `getApiKey` (`(credentials: OAuthCredentials) => string`): Convert credentials to an API key string for the provider.
- `id` (`string`, readonly): Unique id of the flow, used as the registry key and credentials-file key.
- `login` (`(callbacks: OAuthLoginCallbacks) => Promise<OAuthCredentials>`): Run the login flow, return credentials to persist.
- `name` (`string`, readonly): Display name of the provider.
- `refreshToken` (`(credentials: OAuthCredentials) => Promise<OAuthCredentials>`): Refresh expired credentials, return updated credentials to persist.
- `supportsRemoteCallback?` (`boolean`): Login honors zidane's `callbackServer: false`: for a client of a remote
  host it binds no loopback listener and reads the redirect from
  `onManualCodeInput` (`awaitAuthorizationCode` in `zidane/oauth` does
  both). Declaring it lets the flow run from another computer.
- `usesCallbackServer?` (`boolean`): Whether login uses a local callback server and supports manual code input.

Source: [src/providers/oauth-registry.ts:31](https://github.com/Tahul/zidane/blob/main/src/providers/oauth-registry.ts#L31)

### `PromptCacheKeyContext`

Interface.

What a request needs to expose for a key to be derived from it.

```ts
interface PromptCacheKeyContext
```

**Properties**

- `messages` (`readonly SessionMessage[]`): Messages of the request.
- `model` (`string`): Model id of the request.
- `sessionId?` (`string`): Id of the session the request belongs to, when the caller bound one.
- `system` (`string`): System prompt of the request.

Source: [src/providers/prompt-cache-key.ts:63](https://github.com/Tahul/zidane/blob/main/src/providers/prompt-cache-key.ts#L63)

### `Provider`

Interface.

A model backend. Converts messages and tools to the wire format, streams turns and reports capabilities.

```ts
interface Provider
```

**Properties**

- `assistantMessage` (`(content: string) => SessionMessage`): Create an assistant message (for priming)
- `classifyError?` (`(err: unknown) => ClassifiedError | null`): Classify a native provider error for downstream typed-error wrapping.

  Return `null` when the error is not recognized — the loop will wrap it in
  `AgentProviderError` with the provider's name. Return a `ClassifiedError` to
  route it to one of the typed error classes.
- `countTokens?` (`(payload: TokenCountPayload, signal?: AbortSignal) => Promise<number | null>`): Exact input-token count for a payload, WITHOUT running inference — backs
  the context-usage breakdown's exact mode. Implemented by providers with a
  free server-side count endpoint (Anthropic `messages.countTokens`, OpenAI
  `responses.input_tokens.count`).

  Returns the token count, or `null` when counting is unavailable/unreachable
  under the active auth (e.g. an OAuth backend that doesn't expose the
  endpoint) — callers fall back to the heuristic in that case. Absent on
  providers with no count endpoint (Cerebras, OpenRouter).
- `decisions?` (`ProviderDecisions`): Native Decisions endpoint (typed probability / choice / score answers).
  Absent on providers without one. Reached through `agent.decide` /
  `ctx.decide`, which own validation, timeouts and error classification.
- `formatTools` (`(tools: ToolSpec[]) => unknown[]`): Format tool specs for this provider
- `images?` (`ProviderImages`): Image generation endpoint. Absent on providers without one. Reached
  through the `generate_image` tool, which owns files and previews.
- `meta` (`ProviderMeta & Record<string, unknown>`, readonly): Provider metadata the agent core reads. See [`ProviderMeta`](https://zidane.si/docs/reference/providers.md#ProviderMeta).
- `name` (`string`, readonly): Provider name, such as `anthropic` or `openai`.
- `promptMessage?` (`(parts: PromptPart[]) => SessionMessage`): Build a user `SessionMessage` from multimodal prompt parts.

  Providers that cannot handle a particular part type (e.g. document) should throw.
  The agent loop always canonicalizes the run-level prompt into parts before calling
  this method; providers may fall back to `userMessage` for the text-only path if
  they do not implement this.
- `stream` (`(options: StreamOptions, callbacks: StreamCallbacks) => Promise<TurnResult>`): Stream a turn, calling onText for each text delta
- `toolResultsMessage` (`(results: ToolResult[]) => SessionMessage`): Create a tool results message to send back
- `userMessage` (`(content: string) => SessionMessage`): Create a text-only user message. Multimodal content goes through `promptMessage`.

Source: [src/providers/index.ts:440](https://github.com/Tahul/zidane/blob/main/src/providers/index.ts#L440)

### `ProviderCapabilities`

Interface.

Provider-level capability flags used by the agent loop to route tool results
and user messages appropriately.

Known providers should set these explicitly. For legacy compatibility,
omitted `vision` is still treated permissively in some tool-result paths;
newer media kinds (`audio`, `video`) and `documents` are opt-in and should
be set to `true` before bytes are forwarded natively.

```ts
interface ProviderCapabilities
```

**Properties**

- `adaptiveBudgetIsEnvelope?` (`boolean`): On `thinking: 'adaptive'`, this provider treats `thinkingBudget` as a cap
  on the WHOLE response envelope (text + tool-call JSON + thinking), not as
  a dedicated per-turn thinking budget. Anthropic adaptive is the case:
  `thinkingBudget` becomes `max_tokens`, since adaptive has no native
  budget knob (use `taskBudget` instead). The loop reads this to skip
  `thinkingDecay` for adaptive on such providers — decaying an envelope cap
  would strangle text/tool output, not just thinking. Providers where
  adaptive + `thinkingBudget` is a genuine per-turn thinking budget (e.g.
  openai-compat `reasoning.max_tokens`) leave this unset so decay applies.
- `audio?` (`boolean`): Model/provider accepts audio input blocks (user messages / tool results).
  Mapped to the OpenAI-compat `input_audio` content part on capable routes.
  When false or omitted, audio blocks are rejected (the harness throws rather
  than silently sending bytes a non-audio model would 400 on).
- `documents?` (`boolean`): Model/provider accepts document blocks in user messages (currently used for
  PDF attachments read from files). When false or omitted, document blocks
  are replaced by text markers before reaching the provider.
- `imageInToolResult?` (`boolean`): Provider wire format embeds images inside tool-role messages natively
  (Anthropic `tool_result.content` arrays, OpenAI Codex pi-ai `toolResult` blocks).

  When `false`, a vision-capable provider still gets images — but via a
  companion `user` message emitted immediately after the flattened
  `tool`/`tool_result` marker. This is the Claude Desktop / Cline pattern
  and works on any OpenAI Chat Completions endpoint that accepts image
  URLs in user messages.
- `maxMediaPerRequest?` (`number`): Most inline image / document blocks one request may carry, when the
  route caps it below the first-party API (Amazon Bedrock: 20). Lowers
  `AgentBehavior.mediaBudget.maxItems`; omitted = no extra cap.
- `messageEffort?` (`boolean`): The provider understands effort notes (`SystemNote.effort`): it applies
  them without changing the request's top-level effort where the model
  allows, which keeps the prompt cache (Anthropic's per-message
  `output_config`). Hosts that switch effort mid-conversation can keep the
  top-level level fixed and send a note instead.
- `nativeWebSearch?` (`{ maxUses?: number }`): Provider executes web search server-side as a "server tool" — the model
  issues searches and receives results without a `tool_use` / `tool_result`
  round-trip on our wire. When set, the provider's `formatTools` recognizes
  a canonical tool named `web_search` and rewrites it to the provider's
  native server-tool shape (e.g. Anthropic's `web_search_20250305`),
  dropping the client-side `ToolDef` from the function-tools list so the
  model uses the server-side path instead.

  The client-side `web_search` `ToolDef` remains the cross-provider
  fallback for providers that don't set this flag.
- `video?` (`boolean`): Model/provider accepts video input blocks. Mapped to the OpenAI-compat
  `video_url` content part (base64 data-URL) on capable routes — currently
  Gemini models via OpenRouter. When false or omitted, video blocks are
  rejected (the harness throws).
- `vision?` (`boolean`): Model accepts image input anywhere (user messages and tool results).

  When `false`, the loop replaces image blocks with
  `"[image omitted — model does not support vision]"` before they reach the provider.
  Gives the model an honest marker instead of letting JSON-stringified base64 slip
  through and get confabulated over.

Source: [src/providers/index.ts:95](https://github.com/Tahul/zidane/blob/main/src/providers/index.ts#L95)

### `ProviderDecisionRequest`

Interface.

Request passed to `ProviderDecisions.decide`.

```ts
interface ProviderDecisionRequest
```

**Properties**

- `input` (`DecisionInput`): Input the questions are about.
- `model` (`string`): Decision model id.
- `questions` (`DecisionQuestions`): Questions to answer.

Source: [src/providers/index.ts:511](https://github.com/Tahul/zidane/blob/main/src/providers/index.ts#L511)

### `ProviderDecisionResponse`

Interface.

Response of `ProviderDecisions.decide`.

```ts
interface ProviderDecisionResponse
```

**Properties**

- `answers` (`Record<string, DecisionAnswer>`): Canonical answers keyed by question name.
- `id?` (`string`): Provider response id, when reported.
- `model` (`string`): Model that served the request, as reported by the provider.
- `usage` (`DecisionUsage`): Token usage of the request.

Source: [src/providers/index.ts:521](https://github.com/Tahul/zidane/blob/main/src/providers/index.ts#L521)

### `ProviderDecisions`

Interface.

Native Decisions endpoint of a provider.

```ts
interface ProviderDecisions
```

**Properties**

- `approximate?` (`boolean`): Answers come from a chat model's tool call rather than a calibrated
  decisions endpoint (Anthropic): no choice probabilities, self-reported
  predicate probabilities. Automatic model selection prefers a native one.
- `availability` (`() => ProviderDecisionAvailability`): Synchronous credential check — no network.
- `decide` (`(request: ProviderDecisionRequest, signal: AbortSignal) => Promise<ProviderDecisionResponse>`): Translate and send one decisions request. Throw `DecisionHttpError` on
  non-2xx, `DecisionUnsupportedError` for inputs the wire can't carry, and
  `DecisionInvalidResponseError` for malformed bodies.
- `defaultModel` (`string`): Decision model used when a request does not name one.
- `models` (`readonly string[]`): Decision models this provider is known to serve (for pickers).

Source: [src/providers/index.ts:533](https://github.com/Tahul/zidane/blob/main/src/providers/index.ts#L533)

### `ProviderImageRequest`

Interface.

Request passed to `ProviderImages.generate`.

```ts
interface ProviderImageRequest
```

**Properties**

- `aspectRatio?` (`'1:1' | '16:9' | '9:16' | '4:3' | '3:4' | '3:2' | '2:3' | '21:9'`): Shape of the image. Omitted: the model's default.
- `count?` (`number`): How many images to return, 1 to [`MAX_IMAGES_PER_REQUEST`](https://zidane.si/docs/reference/providers.md#MAX_IMAGES_PER_REQUEST). Default 1.
- `model` (`string`): Model id, one of `ProviderImages.models`.
- `prompt` (`string`): What to draw.
- `references?` (`readonly ImageData[]`): Images to edit or to match the style of. Only for models whose `input` includes `image`.
- `transparent?` (`boolean`): Ask for a transparent background. Only for models with `transparency`.

Source: [src/providers/images/types.ts:38](https://github.com/Tahul/zidane/blob/main/src/providers/images/types.ts#L38)

### `ProviderImageResponse`

Interface.

Response of `ProviderImages.generate`.

```ts
interface ProviderImageResponse
```

**Properties**

- `costUsd?` (`number`): Cost in USD, when the provider reports it.
- `images` (`ImageData[]`): The images, in the order the provider returned them.
- `model` (`string`): Model that served the request, as reported by the provider.
- `text?` (`string`): Text the model returned with the images, when it returned any.

Source: [src/providers/images/types.ts:54](https://github.com/Tahul/zidane/blob/main/src/providers/images/types.ts#L54)

### `ProviderImages`

Interface.

Image generation endpoint of a provider.

```ts
interface ProviderImages
```

**Properties**

- `availability` (`() => ProviderImageAvailability`): Synchronous credential check, no network.
- `defaultModel` (`string`): Model used when a request does not name one.
- `generate` (`(request: ProviderImageRequest, signal: AbortSignal) => Promise<ProviderImageResponse>`): Send one request. Throws an `Error` whose message names the provider, the
  HTTP status and the provider's reason when the request fails or the
  provider refuses the prompt.
- `models` (`readonly ImageModelInfo[]`): Image models this provider serves.

Source: [src/providers/images/types.ts:69](https://github.com/Tahul/zidane/blob/main/src/providers/images/types.ts#L69)

### `ProviderMeta`

Interface.

Provider-level metadata the agent core reads.

Every field the core consumes is declared here. The open
`Record<string, unknown>` tail exists for provider-PRIVATE bookkeeping (a
provider stashing something only it reads back) — core code must never reach
into it through a structural cast, because a cast is an undeclared contract
between two modules that no compiler checks.

```ts
interface ProviderMeta
```

**Properties**

- `capabilities?` (`ProviderCapabilities`): Provider-level capability flags. See [`ProviderCapabilities`](https://zidane.si/docs/reference/providers.md#ProviderCapabilities).
- `clearsContextServerSide?` (`boolean`): The provider manages conversation context server-side and may drop earlier
  turns from its own view (e.g. Anthropic context management).

  When set, the core suppresses client-side transcript compaction: two
  independent parties pruning the same conversation produce a transcript
  neither of them can reason about.
- `contextWindow?` (`number`): Context window (in tokens) for this provider's default model.

  Read by the core as the fallback window for auto-compaction when the host
  has not supplied an explicit `autoCompact.contextWindow`.
- `defaultModel` (`string`): Model used when a request does not name one.

Source: [src/providers/index.ts:416](https://github.com/Tahul/zidane/blob/main/src/providers/index.ts#L416)

### `ResolveOAuthApiKeyOptions`

Interface.

Options for [`resolveOAuthApiKey`](https://zidane.si/docs/reference/providers.md#resolveOAuthApiKey).

```ts
interface ResolveOAuthApiKeyOptions<TParams extends OAuthParams = OAuthParams>
```

**Type parameters**

- `TParams` (`extends OAuthParams`, default `OAuthParams`)

**Properties**

- `authSource?` (`'provider' | 'mcp' | 'integration'`): What signs in with this credential, for the [`AgentAuthError`](https://zidane.si/docs/reference/errors.md#AgentAuthError) a failure throws. Defaults to `provider`.
- `credentialKey?` (`string`): Credentials-file key to read and persist, when it differs from
  `providerId`. A provider holding several OAuth accounts parks the
  non-active ones under sibling keys (`anthropic#account:1`); refreshing one
  of those must rotate THAT slot, under its own lock, while the registered
  flow is still looked up by `providerId`. Defaults to `providerId`.
- `credentialsPath?` (`string`): Credentials file to use instead of [`credentialsFilePath`](https://zidane.si/docs/reference/providers.md#credentialsFilePath). Callers that
  already know the data directory (the usage probes) pass it so the default
  store's locking and coalescing apply to the right file without depending
  on `ZIDANE_CREDENTIALS_PATH` having been exported.
- `envKey?` (`string`): Name of an environment variable holding a static key. Used when the value is not an OAuth access token, or when no stored credential exists.
- `extraCredentialKeys?` (`(keyof TParams & string)[]`): Extra keys of `params` copied into the runtime credentials, for providers whose credentials carry more than `access`, `refresh` and `expires`.
- `forceRefresh?` (`boolean`): Force a refresh even when the credential's local expiry is still in the
  future (for one-shot 401 recovery). Reaches the refresh helper as an
  explicit flag, so no credential with a fabricated expiry ever exists to
  leak into the store — see [`getOAuthApiKey`](https://zidane.si/docs/reference/providers.md#getOAuthApiKey).
- `getOAuthApiKey?` (`(providerId: string, credentials: Record<string, OAuthCredentials>, options?: { force?: boolean }) => Promise<{ apiKey: string; newCredentials: OAuthCredentials } | null>`): Replaces the registry lookup that exchanges stored credentials for an API key and refreshes them when expired.
- `missingError` (`string`): Message of the error thrown when no credential is found.
- `params?` (`TParams`): Provider params. A static `apiKey`, runtime credentials or a pinned `account` take precedence over the credentials file.
- `provider` (`string`): Provider name used in error messages and in the refresh event.
- `providerId` (`string`): Id of the registered OAuth flow and the default credentials-file key.
- `readCredentials?` (`() => Record<string, OAuthCredentials | undefined>`): Reads the credentials store. Defaults to the shared credentials file.
- `refreshError` (`(reason: string) => string`): Builds the message of the error thrown when refreshing fails. Receives the failure reason.
- `rejectedAccess?` (`string`): Access token rejected by the server; a different token found under lock is reused instead of rotated again.
- `writeCredentials?` (`(credentials: Record<string, OAuthCredentials | undefined>) => void`): Synchronous provider-local patch writer; injected stores own cross-process coordination.

Source: [src/providers/oauth.ts:174](https://github.com/Tahul/zidane/blob/main/src/providers/oauth.ts#L174)

### `SchemaSanitizeOptions`

Interface.

Options for [`sanitizeToolSchema`](https://zidane.si/docs/reference/providers.md#sanitizeToolSchema).

```ts
interface SchemaSanitizeOptions
```

**Properties**

- `profile?` (`SchemaSanitizeProfile`): Strictness profile. Defaults to `'permissive'`.
- `toolName?` (`string`): Tool name for context in warnings. Optional — when set, every warning
  is prefixed with `[tool:<name>] ` so log lines correlate to the tool.

Source: [src/providers/schema-sanitize.ts:49](https://github.com/Tahul/zidane/blob/main/src/providers/schema-sanitize.ts#L49)

### `SchemaSanitizeResult`

Interface.

Result of [`sanitizeToolSchema`](https://zidane.si/docs/reference/providers.md#sanitizeToolSchema).

```ts
interface SchemaSanitizeResult
```

**Properties**

- `schema` (`Record<string, unknown>`): Sanitized schema, safe to forward to the provider.
- `warnings` (`string[]`): Human-readable strings describing each rewrite the sanitizer performed.
  Empty on a clean schema. Consumers may log these (recommended) or
  thread them through a hook for observability.

Source: [src/providers/schema-sanitize.ts:60](https://github.com/Tahul/zidane/blob/main/src/providers/schema-sanitize.ts#L60)

### `StreamCallbacks`

Interface.

Callbacks a provider invokes while streaming a turn.

```ts
interface StreamCallbacks
```

**Properties**

- `onDiagnostic?` (`(event: ProviderDiagnostic) => void`): Called with provider diagnostics such as retries and request adjustments.
- `onHistoryRepair?` (`(repair: HistoryRepair) => void | Promise<void>`): Provider-requested canonical history repair. Unlike wire-only request
  shaping, the loop owns + persists this mutation. Providers await it
  before retrying the rejected request; hosts calling a provider directly
  may omit it (the provider still retries with a scrubbed wire payload).
- `onInputTransformations?` (`(transformations: InputTransformation[]) => void`): Fires when the provider reports replayed thinking blocks it dropped
  server-side before sampling (Anthropic `input_transformations`). Unlike
  `onHistoryRepair` nothing was mutated on our side: canonical history
  still holds the blocks, they just didn't reach the model this turn. A
  `prefix_binding_mismatch` entry means THIS host edited the prefix — the
  same event a prompt-cache break attributes.
- `onOAuthRefresh?` (`(ctx: OAuthRefreshHookContext) => void | Promise<void>`): Called after OAuth credentials were refreshed, so the host can persist or react to the new credentials.
- `onServerToolResult?` (`(block: { content: unknown; toolName: string; toolUseId: string }) => void`): Pairs with `onServerToolUse` — fires when the provider closes the
  matching server-tool-result block (e.g. Anthropic's
  `web_search_tool_result`). `content` is the raw block payload
  (either an error object or an array of result entries); consumers
  format it for display.
- `onServerToolUse?` (`(block: { id: string; input: Record<string, unknown>; name: string }) => void`): Fires mid-stream when a provider that executes tools server-side closes
  a server-tool-invocation content block (currently: Anthropic's
  `web_search_20250305`). Lets the loop surface the call into the
  transcript at the moment the model issued it — without waiting for the
  full assistant message to finalize. Shape is intentionally generic so
  future server tools (web_fetch, code_execution) reuse the same wire.
- `onText` (`(delta: string) => void`): Called with each text delta as it streams.
- `onThinking?` (`(delta: string) => void`): Called with each thinking delta as it streams.
- `onToolCallDelta?` (`() => void`): Fires when the provider observes incremental tool-call activity — a
  tool-use content block opening or its input-JSON streaming. Carries no
  payload: it exists purely as a liveness signal so the loop's
  first-response watchdog doesn't abort a turn that streams ONLY tool
  calls (no text / thinking deltas). Optional — providers that can't
  surface tool-call deltas simply don't call it (the watchdog then falls
  back to the total-stream timeout for such turns).
- `onUsage?` (`(usage: StreamUsageSnapshot) => void`): Cumulative in-flight usage, for providers whose wire reports token counts
  before the message completes (Anthropic: `message_start` carries the
  prompt side, each `message_delta` the running `output_tokens`). Each call
  REPLACES the previous snapshot. Optional — the loop estimates output
  tokens from streamed characters when a provider never calls it. Drives
  the `stream:progress` hook; the final `TurnResult.usage` stays the
  settle point.

Source: [src/providers/index.ts:220](https://github.com/Tahul/zidane/blob/main/src/providers/index.ts#L220)

### `StreamOptions`

Interface.

Options for one `Provider.stream` call.

```ts
interface StreamOptions
```

**Properties**

- `cache?` (`boolean`): Enable prompt caching on this call. When `true`, providers that support it
  insert `cache_control` breakpoints on the system prompt, last tool, and
  last stable message so the shared prefix is cached across turns.

  Default: `false` (providers opt callers in — the agent loop passes `true`).
- `cacheTtl?` (`CacheTtl`): Prompt-cache entry lifetime for the breakpoints inserted under `cache`.
  Honored by two provider paths:

  - native `anthropic` — `cache_control.ttl: '1h'` plus the
    `extended-cache-ttl-2025-04-11` beta header (api-key auth only);
  - `openai-compat` routes constructed with `cacheBreakpoints: true`
    (i.e. `openrouter`) — the `ttl` field is forwarded verbatim; OpenRouter
    accepts it on Anthropic-family routes and manages upstream headers
    itself (measured: normal cache writes/reads with the field present).

  Providers without a `cache_control` concept ignore it entirely. See
  `AgentBehavior.cacheTtl` for the economics and the retention caveat.

  Default: `'5m'`.
- `effortHint?` (`boolean`): Emit the level-derived `output_config.effort` hint (default: true).
  Anthropic-only — set `false` for models that reject the effort field
  while keeping the rest of the thinking shape. Other providers ignore it.
- `maxTokens?` (`number`): Max output tokens for this turn. When `undefined`, the provider picks a
  model-driven default: Anthropic (where `max_tokens` is a required request
  field) sends the model's max output; OpenAI-style providers omit the field
  entirely so the model generates until it stops naturally (bounded only by
  the context window). Set a number to impose a hard per-turn output cap.
- `messages` (`SessionMessage[]`): Conversation messages sent to the model.
- `model` (`string`): Model id to call.
- `modelCatalog?` (`ModelCatalog`): Per-run model-metadata override, forwarded from `behavior.modelCatalog`.
  Shadows the process-wide `setModelCatalog()` for this turn; providers pass
  it into every catalog lookup (output ceiling, cost rates, model
  resolution). See `./model-catalog`.
- `modelOptions?` (`Record<string, boolean>`): Enabled model-specific options (the `id`s of `ModelInfo.options` the
  user toggled on), e.g. `{ fast: true }` for Anthropic's fast mode. Each
  provider interprets the keys it recognizes and ignores the rest; an option
  the active model doesn't declare is a silent no-op.
- `sessionId?` (`string`): Id of the session this request belongs to, set by the agent loop when a
  session is bound. Providers that route by conversation use it as a
  stable affinity key so requests land on the replica that holds their
  cache (OpenAI `prompt_cache_key`, Neuralwatt `X-NW-Conversation-ID`).
- `signal?` (`AbortSignal`): Abort signal for cancellation
- `system` (`string`): System prompt.
- `taskBudget?` (`number`): Whole-task thinking budget in tokens. Anthropic adaptive-thinking only
  (`output_config.task_budget`); providers without the concept ignore it.
- `thinking?` (`'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | 'adaptive'`): Thinking/reasoning level (optional, default: off)
- `thinkingBudget?` (`number`): Exact thinking token budget — overrides the level-based default when set
- `toolChoice?` (`{ name?: string; type: 'auto' | 'required' | 'tool' }`): Force tool selection behavior
- `tools` (`unknown[]`): Tool specs already converted by `Provider.formatTools`.
- `wrapFetch?` (`(base: typeof fetch) => typeof fetch`): Wraps the fetch this call's HTTP requests go through. The agent loop
  sets it only when an `http.request` / `http.response` interceptor
  matches the provider (`./http-intercept`); absent, the provider uses
  its own fetch as before. Read by the openai-compat family, anthropic
  (not Bedrock), openai and the Google providers (google, google-vertex,
  googleCompatible routes).

Source: [src/providers/index.ts:315](https://github.com/Tahul/zidane/blob/main/src/providers/index.ts#L315)

### `TokenCountPayload`

Interface.

Payload for `Provider.countTokens` — the input half of a request whose
token footprint we want measured WITHOUT running inference. Mirrors the
subset of [`StreamOptions`](https://zidane.si/docs/reference/providers.md#StreamOptions) that contributes to input tokens.

```ts
interface TokenCountPayload
```

**Properties**

- `messages` (`SessionMessage[]`): Conversation messages to count.
- `model` (`string`): Model id to count against.
- `system` (`string`): System prompt as passed to `stream` (provider re-renders for the wire).
- `tools` (`unknown[]`): Wire-formatted tool specs (already through `provider.formatTools`).

Source: [src/providers/index.ts:303](https://github.com/Tahul/zidane/blob/main/src/providers/index.ts#L303)

### `ToolCall`

Interface.

A tool call requested by the model.

```ts
interface ToolCall
```

**Properties**

- `id` (`string`): Provider-assigned id of the call. The matching [`ToolResult`](https://zidane.si/docs/reference/providers.md#ToolResult) carries the same id.
- `input` (`Record<string, unknown>`): Parsed tool input.
- `malformedArgs?` (`MalformedToolArguments`): Set when the model's arguments were not valid JSON and no bounded repair
  fixed them (`input` is then `{}`). The loop never runs such a call: it
  answers it with an error tool result so the model can re-send it.
- `name` (`string`): Name of the tool to run.

Source: [src/providers/index.ts:26](https://github.com/Tahul/zidane/blob/main/src/providers/index.ts#L26)

### `ToolResult`

Interface.

The outcome of running a [`ToolCall`](https://zidane.si/docs/reference/providers.md#ToolCall), sent back to the model.

```ts
interface ToolResult
```

**Properties**

- `calls?` (`NestedToolCallRecord[]`): Calls this tool made through `ToolContext.callTool`, bounded. Provider-
  invisible: the loop copies it onto the persisted `tool_result` block.
- `content` (`string | ToolResultContent[]`): Tool output — plain string for text-only tools (the common case) or a structured
  array of content blocks for tools that return images or mixed content (e.g. an
  MCP browser server returning a screenshot).

  Use `toolResultToText(content)` when a downstream consumer only handles strings.
- `durationMs?` (`number`): Wall time of the call in milliseconds, measured by the loop. Provider-
  invisible: the loop copies it onto the persisted `tool_result` block.
- `id` (`string`): Id of the [`ToolCall`](https://zidane.si/docs/reference/providers.md#ToolCall) this result answers.
- `isError?` (`boolean`): Marks this result as an error. Propagates to `tool_result.is_error: true`
  on the Anthropic wire (and to the equivalent on every other provider that
  exposes the field). Models treat error-flagged results as "the tool tried
  but failed" — distinct from "the tool returned this string" — so they can
  decide whether to retry, fall back, or surface the error to the user.

  Set by the loop on:

  - Tool body throws (`tool:error` path).
  - Gate refusal (`Blocked: <reason>`).
  - Validation rejection (`Validation error: …`).
  - Mid-tool abort (`INTERRUPT_MESSAGE_FOR_TOOL_USE`).
  - Sequential-batch skips when a sibling threw / a steering message
    arrived.

  Custom tools may set it via the `tool:error` hook's `ctx.result`
  substitute when they want the framework to flag a structured error.
- `metadata?` (`ToolResultMetadata`): Provider/model-invisible metadata persisted with the session tool_result.

Source: [src/providers/index.ts:42](https://github.com/Tahul/zidane/blob/main/src/providers/index.ts#L42)

### `ToolSpec`

Interface.

Provider-neutral description of a tool the model can call.

```ts
interface ToolSpec
```

**Properties**

- `description` (`string`): What the tool does, shown to the model.
- `inputSchema` (`Record<string, unknown>`): JSON Schema of the tool input.
- `name` (`string`): Tool name the model uses to call it.
- `outputSchema?` (`Record<string, unknown>`): JSON Schema of the value the tool reports through
  `ToolContext.reportStructured`. Documentation for tools that call this
  one (codemode renders it as the call's TypeScript return type); never
  sent to providers — every `formatTools` maps fields explicitly.

Source: [src/providers/index.ts:9](https://github.com/Tahul/zidane/blob/main/src/providers/index.ts#L9)

### `TurnResult`

Interface.

Outcome of one streamed assistant turn.

```ts
interface TurnResult
```

**Properties**

- `assistantMessage` (`SessionMessage`): Full assistant turn as a SessionMessage
- `done` (`boolean`): Whether the model wants to stop
- `text` (`string`): Text content blocks concatenated
- `toolCalls` (`ToolCall[]`): Tool calls requested by the model
- `usage` (`TurnUsage`): Token usage and cost of the turn.

Source: [src/providers/index.ts:285](https://github.com/Tahul/zidane/blob/main/src/providers/index.ts#L285)

### `ZaiParams`

Interface.

Options for [`zai`](https://zidane.si/docs/reference/providers.md#zai).

```ts
interface ZaiParams
```

**Properties**

- `apiKey?` (`string`): API key. Falls back to the `ZAI_API_KEY` environment variable.
- `baseURL?` (`string`): Override the base URL — e.g. point at the dedicated Coding Plan endpoint
  instead of the standard API endpoint.
- `capabilities?` (`ProviderCapabilities`): Provider capability flags. GLM text models are text-only — default:
  `{ vision: false, imageInToolResult: false }`.
- `defaultModel?` (`string`, default `'glm-5.3-flash'`): Model used when a request does not set one.
- `extraHeaders?` (`Record<string, string>`): Extra HTTP headers sent on every request. Forwarded to the underlying
  [`openaiCompat`](https://zidane.si/docs/reference/providers-openai-compat.md#openaiCompat) client.

Source: [src/providers/zai.ts:14](https://github.com/Tahul/zidane/blob/main/src/providers/zai.ts#L14)

## Types

### `ImageAspectRatio`

Type.

One of [`IMAGE_ASPECT_RATIOS`](https://zidane.si/docs/reference/providers.md#IMAGE_ASPECT_RATIOS).

```ts
type ImageAspectRatio = typeof IMAGE_ASPECT_RATIOS[number]
```

Source: [src/providers/images/types.ts:12](https://github.com/Tahul/zidane/blob/main/src/providers/images/types.ts#L12)

### `ModelCatalog`

Type.

A catalog: either a [`ModelCatalogSource`](https://zidane.si/docs/reference/providers.md#ModelCatalogSource) or the table shorthand —
a plain record keyed `"<provider>:<modelId>"`.

The table form is a pure OVERLAY: entries patch or add models, and each
provider keeps every bundled model the table doesn't name. Hiding bundled
models requires the `list` function, so the easy path can't accidentally
blank a provider's picker.

```ts
setModelCatalog({ 'openai:gpt-5.6': { maxTokens: 128000 } })
```

```ts
type ModelCatalog = ModelCatalogSource | Readonly<Record<string, ModelCatalogEntry>>
```

Source: [src/providers/model-catalog.ts:122](https://github.com/Tahul/zidane/blob/main/src/providers/model-catalog.ts#L122)

### `ModelTier`

Type.

Size class of a model within its provider's lineup. Drives the automatic
text model (titles, suggestions): the smallest current model of the
session's provider. Bundled models get it from a family heuristic
(`src/chat/text-model.ts`); a catalog entry's value wins over it.

```ts
type ModelTier = 'small' | 'medium' | 'large'
```

Source: [src/providers/model-catalog.ts:52](https://github.com/Tahul/zidane/blob/main/src/providers/model-catalog.ts#L52)

### `PromptCacheKeyOption`

Type.

How to obtain the affinity key for a request.

- `undefined` / `false` — send nothing (default).
- `'session'` — the request's session id; send nothing when it has none.
- `true` — the request's session id when it has one, otherwise a hash of
  the cacheable prefix via [`derivePromptCacheKey`](https://zidane.si/docs/reference/providers.md#derivePromptCacheKey).
- any other `string` — use verbatim, for every request.
- function — compute per request; returning `undefined` omits the field for
  that request, so a host can key some traffic and not the rest.

```ts
type PromptCacheKeyOption =
  | boolean
  | 'session'
  | (string & {})
  | ((ctx: PromptCacheKeyContext) => string | undefined)
```

Source: [src/providers/prompt-cache-key.ts:85](https://github.com/Tahul/zidane/blob/main/src/providers/prompt-cache-key.ts#L85)

### `ProviderDecisionAvailability`

Type.

Whether a provider can serve decisions with the credentials it has: `available`, or unavailable with a `reason`.

```ts
type ProviderDecisionAvailability =
  | { available: true }
  | { available: false; reason: string }
```

Source: [src/providers/index.ts:508](https://github.com/Tahul/zidane/blob/main/src/providers/index.ts#L508)

### `ProviderImageAvailability`

Type.

Whether a provider can generate images with the credentials it has: `available`, or unavailable with a `reason`.

```ts
type ProviderImageAvailability =
  | { available: true }
  | { available: false; reason: string }
```

Source: [src/providers/images/types.ts:66](https://github.com/Tahul/zidane/blob/main/src/providers/images/types.ts#L66)

### `SchemaSanitizeProfile`

Type.

Strictness profile — picks which transformations to apply.

```ts
type SchemaSanitizeProfile = 'anthropic' | 'openai' | 'permissive'
```

Source: [src/providers/schema-sanitize.ts:46](https://github.com/Tahul/zidane/blob/main/src/providers/schema-sanitize.ts#L46)

## Re-exports

These names are documented on the entry point that owns them.

- [zidane/providers/anthropic](https://zidane.si/docs/reference/providers-anthropic.md): [`anthropic`](https://zidane.si/docs/reference/providers-anthropic.md#anthropic), [`AnthropicParams`](https://zidane.si/docs/reference/providers-anthropic.md#AnthropicParams), [`applyAnthropicCacheBreakpoints`](https://zidane.si/docs/reference/providers-anthropic.md#applyAnthropicCacheBreakpoints)
- [zidane/providers/arcee](https://zidane.si/docs/reference/providers-arcee.md): [`arcee`](https://zidane.si/docs/reference/providers-arcee.md#arcee), [`ArceeParams`](https://zidane.si/docs/reference/providers-arcee.md#ArceeParams)
- [zidane/providers/baseten](https://zidane.si/docs/reference/providers-baseten.md): [`baseten`](https://zidane.si/docs/reference/providers-baseten.md#baseten), [`BasetenParams`](https://zidane.si/docs/reference/providers-baseten.md#BasetenParams), [`planBasetenReasoning`](https://zidane.si/docs/reference/providers-baseten.md#planBasetenReasoning)
- [zidane/providers/cerebras](https://zidane.si/docs/reference/providers-cerebras.md): [`cerebras`](https://zidane.si/docs/reference/providers-cerebras.md#cerebras), [`CerebrasParams`](https://zidane.si/docs/reference/providers-cerebras.md#CerebrasParams)
- [zidane/providers/google](https://zidane.si/docs/reference/providers-google.md): [`classifyGoogleError`](https://zidane.si/docs/reference/providers-google.md#classifyGoogleError), [`GeminiContent`](https://zidane.si/docs/reference/providers-google.md#GeminiContent), [`GeminiFunctionDeclaration`](https://zidane.si/docs/reference/providers-google.md#GeminiFunctionDeclaration), [`GeminiGenerationConfig`](https://zidane.si/docs/reference/providers-google.md#GeminiGenerationConfig), [`GeminiPart`](https://zidane.si/docs/reference/providers-google.md#GeminiPart), [`GeminiRequest`](https://zidane.si/docs/reference/providers-google.md#GeminiRequest), [`GeminiResponseChunk`](https://zidane.si/docs/reference/providers-google.md#GeminiResponseChunk), [`GeminiThinkingConfig`](https://zidane.si/docs/reference/providers-google.md#GeminiThinkingConfig), [`GeminiTool`](https://zidane.si/docs/reference/providers-google.md#GeminiTool), [`GeminiToolConfig`](https://zidane.si/docs/reference/providers-google.md#GeminiToolConfig), [`google`](https://zidane.si/docs/reference/providers-google.md#google), [`googleCompatible`](https://zidane.si/docs/reference/providers-google.md#googleCompatible), [`GoogleCompatibleRoute`](https://zidane.si/docs/reference/providers-google.md#GoogleCompatibleRoute), [`GoogleParams`](https://zidane.si/docs/reference/providers-google.md#GoogleParams), [`GoogleSharedParams`](https://zidane.si/docs/reference/providers-google.md#GoogleSharedParams), [`GoogleTurnRequest`](https://zidane.si/docs/reference/providers-google.md#GoogleTurnRequest), [`googleVertex`](https://zidane.si/docs/reference/providers-google.md#googleVertex), [`GoogleVertexParams`](https://zidane.si/docs/reference/providers-google.md#GoogleVertexParams), [`GoogleWireModel`](https://zidane.si/docs/reference/providers-google.md#GoogleWireModel)
- [zidane/providers/openai-compat](https://zidane.si/docs/reference/providers-openai-compat.md): [`classifyOpenAICompatError`](https://zidane.si/docs/reference/providers-openai-compat.md#classifyOpenAICompatError), [`mapOAIFinishReason`](https://zidane.si/docs/reference/providers-openai-compat.md#mapOAIFinishReason), [`openaiCompat`](https://zidane.si/docs/reference/providers-openai-compat.md#openaiCompat), [`OpenAICompatAuthHeader`](https://zidane.si/docs/reference/providers-openai-compat.md#OpenAICompatAuthHeader), [`OpenAICompatHttpError`](https://zidane.si/docs/reference/providers-openai-compat.md#OpenAICompatHttpError), [`OpenAICompatParams`](https://zidane.si/docs/reference/providers-openai-compat.md#OpenAICompatParams)
- [zidane/providers/local](https://zidane.si/docs/reference/providers-local.md): [`local`](https://zidane.si/docs/reference/providers-local.md#local), [`LocalParams`](https://zidane.si/docs/reference/providers-local.md#LocalParams)
- [zidane/providers/neuralwatt](https://zidane.si/docs/reference/providers-neuralwatt.md): [`neuralwatt`](https://zidane.si/docs/reference/providers-neuralwatt.md#neuralwatt), [`NEURALWATT_DEFAULT_MODEL`](https://zidane.si/docs/reference/providers-neuralwatt.md#NEURALWATT_DEFAULT_MODEL), [`NeuralwattParams`](https://zidane.si/docs/reference/providers-neuralwatt.md#NeuralwattParams), [`planNeuralwattReasoning`](https://zidane.si/docs/reference/providers-neuralwatt.md#planNeuralwattReasoning)
- [zidane/providers/openai](https://zidane.si/docs/reference/providers-openai.md): [`openai`](https://zidane.si/docs/reference/providers-openai.md#openai), [`OpenAIParams`](https://zidane.si/docs/reference/providers-openai.md#OpenAIParams)
- [zidane/providers/openrouter](https://zidane.si/docs/reference/providers-openrouter.md): [`openrouter`](https://zidane.si/docs/reference/providers-openrouter.md#openrouter), [`OpenRouterParams`](https://zidane.si/docs/reference/providers-openrouter.md#OpenRouterParams)
- [zidane/providers/xai](https://zidane.si/docs/reference/providers-xai.md): [`xai`](https://zidane.si/docs/reference/providers-xai.md#xai), [`XaiParams`](https://zidane.si/docs/reference/providers-xai.md#XaiParams)
