# zidane/providers/anthropic

> The Anthropic provider for the Messages API, with API keys, Claude OAuth credentials or Amazon Bedrock.

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

Use `anthropic()` when your agent talks to Claude. With no key passed, it reads `ANTHROPIC_API_KEY`, then the stored OAuth credentials. It sets prompt-cache breakpoints and maps thinking levels to Anthropic's effort and adaptive thinking. System notes (`systemNotes` on a run) go out as native `role: "system"` messages on the models that accept them, and as `<system-reminder>` text elsewhere. An effort note becomes a per-message effort setting, so changing effort mid-conversation keeps the prompt cache. The other exports are the pieces it is built from, for custom gateways and tests.

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

const agent = createAgent({ provider: anthropic({ defaultModel: 'claude-fable-5-1' }) })
const stats = await agent.run({ prompt: 'Summarize README.md in three bullets.' })
console.log(stats.turns)
```

## Functions

### `anthropic`

Function.

Creates the Anthropic provider for the Messages API.
Authenticates with an API key or Claude OAuth credentials, and can route through Amazon Bedrock via `bedrock`. Without `apiKey`, reads `ANTHROPIC_API_KEY` or stored OAuth credentials: a snapshot at construction, then again on every call.
Outside Bedrock mode, throws at construction when no credential is found.

```ts
function anthropic(anthropicParams?: AnthropicParams): Provider
```

**Parameters**

- `anthropicParams?` (`AnthropicParams`): API key or OAuth credentials, default model, Bedrock mode, base URL, headers and beta flags.

**Returns** `Provider`

**Example**

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

const agent = createAgent({
  provider: anthropic({ apiKey: process.env.ANTHROPIC_API_KEY }),
})
await agent.run({ prompt: 'Say hello.' })
```

Source: [src/providers/anthropic.ts:103](https://github.com/Tahul/zidane/blob/main/src/providers/anthropic.ts#L103)

### `applyAnthropicCacheBreakpoints`

Function.

Mutate an Anthropic request in place to add cache breakpoints on the three
stable prefixes:

1. System prompt — `cache_control` on the static prefix only (see below).
2. Tool definitions — last tool.
3. Conversation — last content block of the last message with content
   (an effort-only system message has none).

A fourth, lookback breakpoint goes on the message right before the latest
assistant turn, whatever its role, when the request carries fewer than 4
markers (see the comment in the body).

Each breakpoint tells Anthropic to cache the prefix ending at that block;
subsequent turns reuse the cached prefix and pay only for the delta. Safe
no-op when any prefix is empty (no tools, empty system, etc.).

System-prompt boundary handling (`SYSTEM_PROMPT_BOUNDARY`):

- When `originalSystem` is provided AND carries the marker, the system
  block is rewritten as a 2-block array: static (cached) then dynamic
  (uncached). The caller is expected to have already stripped the marker
  from `params.system` via [`renderSystemForWire`](https://zidane.si/docs/reference/prompt.md#renderSystemForWire) — this helper
  only re-splits to apply `cache_control` cleanly.
- When `originalSystem` is omitted or marker-free, the existing single-
  block treatment applies: `cache_control` on the whole system string.
- Array system prompts: existing semantics — `cache_control` lands on the
  last block. Callers building their own multi-block layout own the
  breakpoint placement.

```ts
function applyAnthropicCacheBreakpoints(
  params: MessageCreateParamsStreaming,
  originalSystem?: string,
  ttl?: CacheTtl,
): void
```

**Parameters**

- `params` (`MessageCreateParamsStreaming`): Streaming request to mutate.
- `originalSystem?` (`string`): System prompt before boundary rendering, used to split the static and dynamic parts.
- `ttl?` (`CacheTtl`): Cache lifetime for the breakpoints. Uses the API default when omitted.

Source: [src/providers/anthropic-cache.ts:58](https://github.com/Tahul/zidane/blob/main/src/providers/anthropic-cache.ts#L58)

### `buildAnthropicClientOptions`

Function.

SDK constructor options for a resolved credential — the single place that
decides which auth header goes on the wire.

Exported (and pure) so the header shape is test-pinned without a network
round-trip: `authToken` → `Authorization: Bearer …`, `apiKey` → `x-api-key`,
and `apiKey: null` alongside `authToken` is what suppresses `x-api-key` so a
gateway sees exactly one credential.

```ts
function buildAnthropicClientOptions(
  apiKey: string,
  auth: { bearer: boolean; claudeCode: boolean },
  baseURL?: string,
  extraBetas?: readonly string[],
  extraHeaders?: Record<string, string>,
): Record<string, unknown>
```

**Parameters**

- `apiKey` (`string`): Resolved API key or bearer token.
- `auth` (`{ bearer: boolean; claudeCode: boolean }`): Wire auth shape from [`resolveAnthropicAuthShape`](https://zidane.si/docs/reference/providers-anthropic.md#resolveAnthropicAuthShape).
- `baseURL?` (`string`): Optional SDK base URL override.
- `extraBetas?` (`readonly string[]`): Extra `anthropic-beta` flags.
- `extraHeaders?` (`Record<string, string>`): Extra request headers. Reserved header names are dropped.

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

Source: [src/providers/anthropic-client.ts:282](https://github.com/Tahul/zidane/blob/main/src/providers/anthropic-client.ts#L282)

### `cacheWriteTtlMultiplier`

Function.

Returns the factor to apply to the cache write cost of a turn that wrote under the 1h TTL, or `1` when no 1h writes are reported.

```ts
function cacheWriteTtlMultiplier(
  usage: { cache_creation?: { ephemeral_1h_input_tokens?: number; ephemeral_5m_input_tokens?: number } | null; cache_creation_input_tokens?: number | null },
): number
```

**Parameters**

- `usage` (`{ cache_creation?: { ephemeral_1h_input_tokens?: number; ephemeral_5m_input_tokens?: number } | null; cache_creation_input_tokens?: number | null }`): Usage block of the response, with the optional per-TTL cache write split.

**Returns** `number`

Source: [src/providers/anthropic-usage.ts:56](https://github.com/Tahul/zidane/blob/main/src/providers/anthropic-usage.ts#L56)

### `classifyAnthropicError`

Function.

Classify an Anthropic SDK / HTTP error for typed-error wrapping.

- `prompt is too long` (400 invalid_request_error) → `context_exceeded`.
- `'tool_use' ids were found without 'tool_result' blocks` /
  `'tool_result must be preceded by a tool_call'` (400) →
  `tool_pairing_corruption`. The local repair pass should have caught
  this — the typed error tells consumers their pre-send pipeline is
  shipping orphaned blocks somehow (custom `context:transform` hook,
  bypassed loop, mid-stream session edit) so they can patch the root
  cause instead of chasing 400s.
- A rate limit, spent credit or overload (429, 529, `billing_error`, also
  mid-stream) → `provider_error` worded by `describeProviderLimit`, with the
  server's reset (see `classifyProviderLimit` for when it stops retrying).
- Any other Anthropic `APIError`-shaped value → `provider_error` with the
  native status/type code.
- Unknown errors → `null` (loop wraps in `AgentProviderError` generically).

Anthropic's wire error shape is `{ type: 'error', error: { type, message } }` — the
SDK stores the parsed body on `err.error`. We walk both levels so callers see the
most specific `providerCode` we can find.

```ts
function classifyAnthropicError(err: unknown, label?: string): ClassifiedError | null
```

**Parameters**

- `err` (`unknown`): Error thrown by the SDK or the HTTP layer.
- `label?` (`string`, default `'Claude'`): Product a limit's message names; providers built on this wire (Bolt) pass their own.

**Returns** `ClassifiedError | null`

Source: [src/providers/anthropic-errors.ts:107](https://github.com/Tahul/zidane/blob/main/src/providers/anthropic-errors.ts#L107)

### `credentialIdentity`

Function.

Credential-resolution identity for `resolveOAuthApiKey`. Anthropic's
own unless the caller pointed the provider at a gateway with its own
credentials via `AnthropicParams.credentialSource`.

```ts
function credentialIdentity(
  anthropicParams?: AnthropicParams,
): { envKey?: string; missingError: string; providerId: string; refreshError: (reason: string) => string }
```

**Parameters**

- `anthropicParams?` (`AnthropicParams`): Provider params, read for `credentialSource`.

**Returns** `{ envKey?: string; missingError: string; providerId: string; refreshError: (reason: string) => string }`

Source: [src/providers/anthropic-client.ts:162](https://github.com/Tahul/zidane/blob/main/src/providers/anthropic-client.ts#L162)

### `defaultAnthropicMaxTokens`

Function.

Conservative per-family output ceiling, used ONLY as a fallback when pi-ai's
model registry doesn't know the model (or pi-ai is externalized) — see
[`resolveAnthropicMaxOutput`](https://zidane.si/docs/reference/providers-anthropic.md#resolveAnthropicMaxOutput), which is the primary path. These are
non-beta floors we can always send without a 400; the registry reports the
real (often much higher, e.g. Opus 4.x = 128K native) max when available.

```ts
function defaultAnthropicMaxTokens(modelId: string): number
```

**Parameters**

- `modelId` (`string`): Model id. Matched by family name (`haiku`, `sonnet`, other).

**Returns** `number`

Source: [src/providers/anthropic-request.ts:35](https://github.com/Tahul/zidane/blob/main/src/providers/anthropic-request.ts#L35)

### `planAnthropicThinking`

Function.

Decide how to translate a `ThinkingLevel` into Anthropic's request shape.
Pure / synchronous — exported so tests can assert routing without standing
up the SDK.

Routing rules:

- `'off'` → `null` (no thinking field, no effort hint).
- `'adaptive'` → adaptive thinking with no effort hint (model decides
  everything). When `taskBudget` is set, it is carried as
  `taskBudgetTokens` and emitted as `output_config.task_budget` — the
  native whole-task thinking cap. LEGACY: when `customBudget` is set, it
  is carried as `maxTokensCap` so the request builder caps `max_tokens`
  accordingly — this clamps the whole response envelope (text and
  tool-call JSON included), which is the wrong knob for bounding thinking
  now that `taskBudget` exists; kept only for callers who already depend
  on it. Prefer `taskBudget`.
- Budgeted levels → adaptive thinking with an `effort` hint (plus
  `taskBudgetTokens` when `taskBudget` is set), unless `customBudget` is
  provided.
- Any level + `customBudget` → explicit-budget `enabled` path, carrying
  the level's `effort` hint alongside the budget. The caller has opted
  into precise budget control and accepts the Anthropic deprecation
  warning that comes with it on opus 4.6+. `'adaptive'` is the sole
  exception: it never falls back to enabled, since adaptive is the
  current Anthropic API surface for self-budgeted thinking. `taskBudget`
  is adaptive-only and ignored on this path.
- `effortHint: false` (default `true`) strips the `effort` hint from
  every shape — budgeted levels plan plain adaptive and the
  `customBudget` path plans `enabled` with no `output_config.effort` —
  for Anthropic models that reject the effort field.

```ts
function planAnthropicThinking(
  level: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | 'adaptive',
  customBudget?: number,
  taskBudget?: number,
  effortHint?: boolean,
): AnthropicThinkingPlan | null
```

**Parameters**

- `level` (`'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | 'adaptive'`): Thinking level.
- `customBudget?` (`number`): Explicit thinking token budget.
- `taskBudget?` (`number`): Whole-task thinking budget, for adaptive thinking.
- `effortHint?` (`boolean`, default `true`): Set `false` to drop the effort hint.

**Returns** `AnthropicThinkingPlan | null`

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

### `resolveAnthropicAuthShape`

Function.

Whether the wire auth is a bearer token, and whether the Claude Code
persona (betas + `x-app` headers + system-prompt folding) applies. Only the
default `'auto'` mode infers both from the token shape — see
`AnthropicParams.authMode`.

```ts
function resolveAnthropicAuthShape(
  apiKey: string,
  authMode: 'auto' | 'bearer' | 'api-key' | undefined,
): { bearer: boolean; claudeCode: boolean }
```

**Parameters**

- `apiKey` (`string`): Resolved credential. Tokens containing `sk-ant-oat` count as OAuth in `auto` mode.
- `authMode` (`'auto' | 'bearer' | 'api-key' | undefined`): Auth mode from the provider params. Defaults to `auto` when undefined.

**Returns** `{ bearer: boolean; claudeCode: boolean }`

Source: [src/providers/anthropic-client.ts:194](https://github.com/Tahul/zidane/blob/main/src/providers/anthropic-client.ts#L194)

### `resolveAnthropicBetas`

Function.

Build the `anthropic-beta` header value — OAuth defaults plus caller-supplied
extras, de-duped while preserving order. Returns `undefined` when no betas
apply (non-OAuth, no extras).

```ts
function resolveAnthropicBetas(
  isOAuth: boolean,
  extraBetas?: readonly string[],
): string | undefined
```

**Parameters**

- `isOAuth` (`boolean`): Whether the Claude Code persona applies, which adds the OAuth default betas.
- `extraBetas?` (`readonly string[]`): Extra beta flags to append.

**Returns** `string | undefined`

Source: [src/providers/anthropic-client.ts:133](https://github.com/Tahul/zidane/blob/main/src/providers/anthropic-client.ts#L133)

### `resolveAnthropicMaxOutput`

Function.

Resolve a model's max output tokens. Prefers pi-ai's bundled registry — the
authoritative source the SDK itself uses to build requests, so e.g. Opus 4.x
reports its full native 128K (no extended-output beta required) — and falls
back to [`defaultAnthropicMaxTokens`](https://zidane.si/docs/reference/providers-anthropic.md#defaultAnthropicMaxTokens) only when the registry lacks the
model. Used as BOTH the default (when the caller leaves `maxTokens` unset)
and a hard clamp, since a `max_tokens` above the model's max would 400.

The clamp is only as good as the ceiling's provenance, so an explicit caller
`maxTokens` can RAISE the fallback: models the registry doesn't know are
mostly ids that never appear in pi-ai's anthropic registry — Bedrock ids
(`global.anthropic.claude-*`) and non-Anthropic models served over the
Anthropic wire (`openai.gpt-*` on Bedrock, gateway aliases). For the
latter the fallback degrades to the 32000 catch-all; for the former the
family match yields a deliberately conservative non-beta floor. Clamping a
caller who knows the real ceiling down to either silently truncates long
generations mid-write (observed as turns pinned at exactly 32000 tokens).

It can only raise, never lower: the caller's `maxTokens` is a cap on the
VISIBLE response, already enforced as `max_tokens` itself, whereas this
value is the model's physical ceiling. Letting it lower the ceiling would
break the `enabled` thinking path's invariant that the budget sits ON TOP
of the response cap — the budget would be shrunk to share the caller's cap,
or dropped entirely once no satisfiable budget fits.

A registry-backed max always wins over the caller — above it the provider
400s. A CATALOG entry (`behavior.modelCatalog` / `setModelCatalog`) outranks
even that: it's an explicit claim about a model whose registry entry may be
absent, stale, or an alias for something else entirely.

```ts
function resolveAnthropicMaxOutput(
  modelId: string,
  explicitMaxTokens?: number,
  catalog?: ModelCatalog,
): Promise<number>
```

**Parameters**

- `modelId` (`string`): Model id to resolve.
- `explicitMaxTokens?` (`number`): Caller token cap. Can raise the fallback ceiling, never lower it.
- `catalog?` (`ModelCatalog`): Per-run model catalog that outranks the registry.

**Returns** `Promise<number>`

Source: [src/providers/anthropic-request.ts:97](https://github.com/Tahul/zidane/blob/main/src/providers/anthropic-request.ts#L97)

### `resolveThinkingBinding`

Function.

Effective `AnthropicParams.thinkingBinding`: the explicit param wins,
then the shell's `ZIDANE_THINKING_BINDING`, then the chat host's setting
channel ([`THINKING_BINDING_SETTING_ENV`](https://zidane.si/docs/reference/providers-anthropic.md#THINKING_BINDING_SETTING_ENV)), then `'drop_block'`. Read
per request so a flip lands on the next call without rebuilding the
provider (the factory is no-arg in the chat host). Unrecognized values are
ignored at each level.

```ts
function resolveThinkingBinding(
  param: ThinkingBindingBehavior | undefined,
  env?: ProcessEnv,
): ThinkingBindingBehavior
```

**Parameters**

- `param` (`ThinkingBindingBehavior | undefined`): Explicit `thinkingBinding` param.
- `env?` (`ProcessEnv`, default `process.env`): Environment to read the fallbacks from.

**Returns** `ThinkingBindingBehavior`

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

## Constants

### `EXTENDED_CACHE_TTL_BETA`

Constant.

Beta flag Anthropic requires before it honors `ttl: '1h'` on `cache_control`.

```ts
const EXTENDED_CACHE_TTL_BETA = 'extended-cache-ttl-2025-04-11'
```

Source: [src/providers/anthropic-cache.ts:20](https://github.com/Tahul/zidane/blob/main/src/providers/anthropic-cache.ts#L20)

### `THINKING_BINDING_SETTING_ENV`

Constant.

Env channel the chat host writes the user's `thinkingBinding` SETTING to.
Distinct from `ZIDANE_THINKING_BINDING` (the shell override) so the two
never read each other back: a host recreated in-process must not mistake
an earlier host's setting write for a shell value.

```ts
const THINKING_BINDING_SETTING_ENV = 'ZIDANE_THINKING_BINDING_SETTING'
```

Source: [src/providers/anthropic-thinking.ts:17](https://github.com/Tahul/zidane/blob/main/src/providers/anthropic-thinking.ts#L17)

## Interfaces

### `AnthropicBedrockConfig`

Interface.

Amazon Bedrock mode for the anthropic provider.

Routes the identical Messages wire shape through `@anthropic-ai/bedrock-sdk`
(`AnthropicBedrock`), which signs requests with SigV4 instead of an
Anthropic API key. Credentials resolve through the standard AWS chain —
`AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` (+ `AWS_SESSION_TOKEN`) env
vars, shared config, instance roles — so no `ANTHROPIC_API_KEY` is needed
or consulted.

Model ids are Bedrock-shaped (e.g.
`global.anthropic.claude-haiku-4-5-20251001-v1:0`); pass one as
`defaultModel` or per run.

```ts
interface AnthropicBedrockConfig
```

**Properties**

- `region?` (`string`): AWS region for the Bedrock runtime endpoint. Resolution order:
  this field → `AWS_REGION` env → `us-west-2`.
- `sdk?` (`(options: Record<string, unknown>) => unknown`): Bring-your-own client constructor. The default lazily imports
  `@anthropic-ai/bedrock-sdk` (an optional peer dependency); override for
  runtimes where that default cannot work — edge workers needing a custom
  `providerChainResolver`, pre-configured credentials objects — or to
  inject a fake in tests without module-level mocking (Bun's
  `mock.module` leaks across test files).

  Receives the resolved client options (`awsRegion`, plus `baseURL` /
  `defaultHeaders` passthrough) and must return an object exposing the
  Anthropic `messages` surface.

Source: [src/providers/anthropic-params.ts:34](https://github.com/Tahul/zidane/blob/main/src/providers/anthropic-params.ts#L34)

### `AnthropicContextManagement`

Interface.

Server-side context-management config — the body of `context_management` on
the Messages API. Typed loosely (Record-of-unknown) so we don't pin a specific
SDK schema version: the SDK's non-beta Messages types do not include this
field, but the wire format is stable behind the `context-management-2025-06-27` beta.

See: [https://docs.anthropic.com/en/docs/build-with-claude/context-management](https://docs.anthropic.com/en/docs/build-with-claude/context-management)

```ts
interface AnthropicContextManagement
```

**Properties**

- `edits?` (`Record<string, unknown>[]`): Context-editing strategies the API applies server-side, such as clearing old tool results.

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

### `AnthropicParams`

Interface.

Options of the `anthropic` provider: Anthropic API, Claude subscription OAuth, gateway or Bedrock.

```ts
interface AnthropicParams extends OAuthParams
```

**Properties**

- `access?` (`string`, from `OAuthParams`): OAuth access token supplied at runtime. Used together with `refresh` and `expires` to refresh without a credentials file.
- `account?` (`string`, from `OAuthParams`): 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`, from `OAuthParams`): Static API key or OAuth access token sent as is, bypassing credential lookup and refresh.
- `authMode?` (`'auto' | 'bearer' | 'api-key'`): How the resolved credential reaches the wire.

  - `'auto'` (default) — bearer iff the token is an Anthropic OAuth access
    token (`sk-ant-oat…`), which also turns on the **Claude Code persona**
    (`claude-code-*` betas, `x-app: cli`, the canonical Claude Code system
    block). Otherwise `x-api-key`.
  - `'bearer'` — always `Authorization: Bearer <token>`, WITHOUT the Claude
    Code persona. This is the mode for an Anthropic-Messages-compatible
    gateway behind `AnthropicParams.baseURL` that authenticates with
    its own bearer token (Bolt's `bex_…`, an internal router, …).
  - `'api-key'` — always `x-api-key`, no persona. Forces a proxy that
    expects Anthropic's native header even when the token happens to look
    like an OAuth one.

  Only `'auto'` can enable the persona: an explicit mode means "this is not
  Anthropic's own OAuth", and sending Claude Code's betas / system block to
  a third-party gateway is at best noise and at worst a 400.
- `baseURL?` (`string`): Optional override for the Anthropic SDK base URL. Honored end-to-end — headers and
  routing pass through to the forwarded host. Useful for proxies (e.g. corporate
  gateways, internal router).
- `bedrock?` (`boolean | AnthropicBedrockConfig`): Run against Amazon Bedrock instead of the Anthropic API. `true` uses
  env-resolved AWS credentials and region defaults; pass an
  [`AnthropicBedrockConfig`](https://zidane.si/docs/reference/providers-anthropic.md#AnthropicBedrockConfig) to set the region or inject a client
  constructor. See the config type for credential resolution and model-id
  shape.

  Bedrock has no `count_tokens` endpoint (the provider's `countTokens`
  returns `null` and callers fall back to the heuristic) and no Claude
  Code persona; beta headers are not sent. Thinking degrades to the
  legacy explicit-budget shape — Bedrock rejects the 4.6 surface
  (`output_config.effort`, adaptive) — with per-effort budgets from
  `BEDROCK_THINKING_BUDGETS` clamped under the model's output ceiling;
  an explicit `thinkingBudget` wins. Server-side web search
  (`nativeWebSearch`) is not advertised: AWS doesn't host Anthropic's
  search tool, so the canonical `web_search` ToolDef runs client-side
  like on other non-Anthropic routes.

  Caveats: `AnthropicParams.contextManagement` is DROPPED in bedrock
  mode — Bedrock's translation layer rejects the field, so sending it would
  guarantee a 400. Any `extraBodyParams` from the 4.6+ API surface are
  forwarded verbatim and will fail the same way; don't combine them with
  bedrock mode. `baseURL` is
  honored but must point at a genuine Bedrock endpoint (e.g. a VPC
  endpoint): SigV4 signs the request for that host, so a rewriting proxy
  breaks the signature.
- `capabilities?` (`Partial<ProviderCapabilities>`): Override advertised capabilities (merged over the Anthropic defaults).
  For gateways behind `AnthropicParams.baseURL` that don't implement
  a native affordance — e.g. `{ nativeWebSearch: undefined }` to fall back
  to the client-side `web_search` tool when the proxy rejects Anthropic's
  `web_search_20250305` server tool.
- `contextManagement?` (`AnthropicContextManagement`): Server-side context-management directive. Sent on the request body as
  `context_management`. Requires the `context-management-2025-06-27` beta —
  add it to `AnthropicParams.extraBetas`.

  Typed loosely so future Anthropic schema additions land without an SDK
  bump. A typical compaction edit:

  ```ts
  contextManagement: {
    edits: [{
      type: 'clear_tool_uses_20250919',
      trigger: { type: 'input_tokens', value: 180_000 },
      clear_at_least: { type: 'input_tokens', value: 140_000 },
      clear_tool_inputs: ['Read', 'Bash', 'Grep'],
    }],
  }
  ```
- `credentialSource?` (`{ envKey?: string; missingError?: string; providerId: string; refreshError?: (reason: string) => string }`): Override the credential identity used to resolve (and lazily refresh) the
  token on every call. Defaults to Anthropic's own
  (`providerId: 'anthropic'`, env `ANTHROPIC_API_KEY`).

  Set this when `AnthropicParams.baseURL` points at a gateway that
  issues its own OAuth credentials under a different key in
  `credentials.json`. The whole shared machinery — refresh-on-expiry,
  cross-process lock, atomic persist, the `onOAuthRefresh` callback — then
  applies to that provider instead, with no reimplementation. Pair with
  `authMode: 'bearer'` for a bearer-token gateway.

  `providerId` must be registered in zidane's OAuth registry
  (`registerOAuthProvider`) for refresh to resolve.
- `defaultModel?` (`string`, default `DEFAULT_MODEL_PICK.modelId`): Model used when a request does not set one.
- `expires?` (`number`, from `OAuthParams`): Expiry of `access` as a Unix timestamp in milliseconds.
- `extraBetas?` (`readonly string[]`): Additional `anthropic-beta` flags to opt into. Merged with the OAuth-path
  defaults (the Claude Code set, `CLAUDE_CODE_BETAS`); duplicates are
  de-duped. Examples:

  - `'context-management-2025-06-27'` — server-side context compaction
    (token-accurate; pair with `AnthropicParams.contextManagement`).
  - `'token-efficient-tools-2026-03-28'` — terser tool_use wire format.
  - `'interleaved-thinking-2025-05-14'` — think between tool calls within
    one turn.
  - `'redact-thinking-2026-02-12'` — replace large thinking blocks with
    stubs server-side.
  - `'prompt-caching-scope-2026-01-05'` — extended prompt-cache scope.

  Honored on both the OAuth and API-key paths.
- `extraBodyParams?` (`Record<string, unknown>`): Generic pass-through for fields on the Messages API request body that the
  SDK does not yet type. Spread into the request before the typed fields,
  so explicit options (`AnthropicParams.contextManagement` and the
  built-in fields like `model` / `tools` / `messages`) win on collision.

  Forward-compat escape hatch for new Anthropic betas — when a future flag
  ships before zidane has a dedicated typed knob, set it here without
  waiting on a release. Most fields will still need the matching beta in
  `AnthropicParams.extraBetas`.
- `extraHeaders?` (`Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>)`): Extra HTTP headers sent on every request, merged into the SDK's
  `defaultHeaders`. Honored on both the OAuth and API-key paths.

  Use for routing/attribution headers a proxy or gateway in front of the
  `baseURL` consumes (e.g. a target-provider selector). On the OAuth path the
  Claude Code client headers (`anthropic-beta`, `user-agent`, `x-app`,
  `x-stainless-*`, `accept` and others) take precedence on collision. On
  other paths only `anthropic-beta` is reserved.

  May be a **function** resolved per request (awaited) instead of a static
  map — the seam for gateways minting short-lived/signed auth tokens that a
  long, suspended, or replayed durable run outlives. The resolver runs on
  every `stream()` / `countTokens()` call, so it can return a freshly-minted
  token each turn (e.g. `{ authorization: \`Bearer ${await mintWorkToken()}\` }\`)
  without rebuilding the provider.
- `label?` (`string`, default `'Claude'`): Product a rate-limit, quota or overload message names, for services
  that speak this wire (`Bolt`).
- `promptCacheKey?` (`PromptCacheKeyOption`): Prompt-cache affinity key — an opt-in routing hint carried on the request as
  `metadata.user_id`. See [`PromptCacheKeyOption`](https://zidane.si/docs/reference/providers.md#PromptCacheKeyOption) for the shapes and
  `./prompt-cache-key.ts` for which routes honor it.

  On 1P Anthropic this is effectively a no-op: cache entries are scoped per
  organization/workspace and matched purely by prefix, with no client-side
  routing knob, and `metadata.user_id`'s documented purpose is abuse
  detection. It is plumbed here for the case `AnthropicParams.baseURL`
  already serves — a proxy or AI gateway in front of the Messages API, which
  CAN route on a stable session key — and so a host sets one flag regardless
  of which provider is behind it.

  The derived default is a hash, which also satisfies Anthropic's guidance
  that this field not carry PII.

  Default: unset — no `metadata` is added and requests stay byte-identical.
- `promptCacheKeyHeader?` (`string`): Additionally send the affinity key as this HTTP header, for gateways that
  route on a header rather than a body field. Defers to any same-named entry
  in `AnthropicParams.extraHeaders`.

  Default: unset — no header is added.
- `refresh?` (`string`, from `OAuthParams`): OAuth refresh token supplied at runtime.
- `thinkingBinding?` (`ThinkingBindingBehavior`): Preserved-thinking prefix binding (`thinking.block_binding`). Newer
  models validate that nothing before a replayed `thinking` block — system,
  tools, earlier messages — changed since the block was produced; an edited
  prefix invalidates that block and every later one. This picks what the
  API does with invalid blocks:

  - `'drop_block'` (default): drop them server-side, unbilled, and report
    each in `input_transformations` (surfaced via
    `StreamCallbacks.onInputTransformations`). History stays intact
    for a later model that can read the blocks again.
  - `'error'`: the API rejects the request with a 400 and that 400
    PROPAGATES — the signature-scrub ladder deliberately stands down for
    the prefix-mismatch shape here, since the caller asked to see the
    failure, not to have history rewritten around it. Fail-loud for CI.
  - `'off'`: send nothing; the account default applies (`'error'` on
    accounts created after 2026-08-31, silent tolerance before).

  Unset falls back to the `ZIDANE_THINKING_BINDING` env var (shell), then
  `ZIDANE_THINKING_BINDING_SETTING` (written by the chat host from the
  user's setting), then `'drop_block'` — see `resolveThinkingBinding`.

  Rides with the `thinking-binding-controls-2026-08-01` beta, injected only
  on requests that enable thinking so thinking-off requests stay
  byte-stable. Not sent on Bedrock (its translation layer rejects unknown
  `thinking` fields).

Source: [src/providers/anthropic-params.ts:56](https://github.com/Tahul/zidane/blob/main/src/providers/anthropic-params.ts#L56)

## Types

### `AnthropicThinkingPlan`

Type.

Description of the Anthropic-side thinking configuration derived from a
ThinkingLevel. `null` means no thinking-related field should be set on the
request.

Two shapes:

- `adaptive` — `thinking.type='adaptive'`. The model self-budgets per turn.
  When `effort` is set, also emits `output_config.effort` to hint at the
  level of reasoning the caller wants. This is the post-Claude-4.6 default
  for level-based control and avoids the `thinking.type='enabled'`
  deprecation warning. When `maxTokensCap` is set, the request builder
  reduces `max_tokens` to `min(max_tokens, maxTokensCap)` — adaptive thinks
  and replies inside one envelope, so capping the envelope soft-bounds the
  thinking too.
- `enabled` — explicit-budget path: `thinking.type='enabled'` with an
  explicit `budget_tokens`. `maxTokensBump` is added to the request's
  `max_tokens` so the budget sits on top of the response cap. When the
  caller's level maps to an effort tier, `effort` is carried too and
  emitted as `output_config.effort` alongside the explicit budget —
  both fields are valid together on 4.6+ models. The only way to pin a
  precise token budget; Anthropic emits a deprecation warning for this
  shape on opus 4.6+, so we only route here when the caller explicitly
  sets `behavior.thinkingBudget`.

In both shapes Anthropic requires `temperature` to be `1`.

```ts
type AnthropicThinkingPlan =
  | { budgetTokens: number; effort?: 'low' | 'medium' | 'high' | 'xhigh' | 'max'; kind: 'enabled'; maxTokensBump: number }
  | { effort?: 'low' | 'medium' | 'high' | 'xhigh' | 'max'; kind: 'adaptive'; maxTokensCap?: number; taskBudgetTokens?: number }
```

Source: [src/providers/anthropic-thinking.ts:120](https://github.com/Tahul/zidane/blob/main/src/providers/anthropic-thinking.ts#L120)

### `ThinkingBindingBehavior`

Type.

What the API does with replayed thinking blocks whose prefix changed: `drop_block`, `error` or `off`. See `AnthropicParams.thinkingBinding`.

```ts
type ThinkingBindingBehavior = 'drop_block' | 'error' | 'off'
```

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