import type { ModelIdentity } from "./compat/types.js"; import type { Effort } from "./effort.js"; import type { DatedCostCard } from "./pricing.js"; export type { FetchImpl } from "@oh-my-pi-zen/pi-utils"; export type { KnownProvider } from "./provider-models/descriptors.js"; export type KnownApi = "openai-completions" | "openai-responses" | "openrouter" | "openai-codex-responses" | "azure-openai-responses" | "anthropic-messages" | "bedrock-converse-stream" | "google-generative-ai" | "google-gemini-cli" | "google-vertex" | "ollama-chat" | "cursor-agent" | "factory-droid-agent" | "gitlab-duo-agent" | "devin-agent" | "apple-foundation-models"; export type Api = KnownApi | (string & {}); /** Catalog kinds used to isolate role-specific runners from session chat models. */ export declare const MODEL_KINDS: readonly ["chat", "tiny", "image", "tts", "stt", "search", "judge", "embedding", "rerank", "video"]; /** Technical capability of a catalog model; absent model kinds mean chat. */ export type ModelKind = (typeof MODEL_KINDS)[number]; /** Kinds a provider maps to a runner transport through `kind-apis` in its KDL; discovery drops rows of these kinds when the provider declares no API. */ export declare const KIND_API_KINDS: readonly ["image", "tts", "stt", "embedding", "rerank", "video"]; export type KindApiKind = (typeof KIND_API_KINDS)[number]; /** Grounding transport available to chat models selected by the web role. */ export type WebSearchGrounding = "gemini" | "anthropic" | "codex" | "xai" | "openrouter" | "openai"; /** Non-chat runner protocols accepted by catalog seeds, outside the chat dispatch union. */ export declare const RUNNER_APIS: readonly ["local-inference", "web-search", "typesafe", "openrouter-decisions", "openai-decisions", "workers-ai-systemone", "openai-images", "openrouter-images", "xai-tts", "openai-speech", "openai-embeddings", "openrouter-rerank", "openrouter-video", "openai-transcriptions"]; /** Kind each single-purpose runner API serves; `local-inference` hosts several kinds. */ export declare const RUNNER_API_KINDS: Record, ModelKind>; /** Kind a runner API serves; `undefined` for chat transports and multi-kind `local-inference`. */ export declare function runnerApiKind(api: Api): ModelKind | undefined; /** Catalog APIs `generate_image` runs through a pi-ai image client; the hosted Responses pair needs a carrier model. */ export declare const IMAGE_GENERATION_APIS: readonly ["openai-images", "openrouter-images", "google-generative-ai", "google-gemini-cli", "openai-responses", "openai-codex-responses", "factory-droid-agent"]; export type ImageGenerationApi = (typeof IMAGE_GENERATION_APIS)[number]; /** * Kinds a model on `api` may declare: a runner api serves its own kind; a chat * transport serves `chat` and `tiny`, plus `image` when `generate_image` runs it * (hosted Responses image tool, Gemini and Factory Droid image models). `undefined` for * `local-inference`, which hosts several kinds chosen by the model itself. */ export declare function servedKinds(api: Api): readonly ModelKind[] | undefined; /** Whether a model of `kind` can run on `api`. */ export declare function apiServesKind(api: Api, kind: ModelKind): boolean; /** Resolve a model's kind while preserving chat semantics for existing catalog rows. */ export declare function modelKind(model: Pick): ModelKind; /** Canonical thinking transport used by a model. */ export type ThinkingControlMode = "effort" | "budget" | "google-level" | "anthropic-adaptive" | "anthropic-budget-effort"; /** Per-model thinking capabilities used to clamp and map user-facing effort levels. */ export interface ThinkingConfig { /** Provider-specific transport used to encode the selected effort. */ mode: ThinkingControlMode; /** * Supported user-facing efforts, ordered least → most intensive. Never * empty: a reasoning model without a controllable effort surface carries * `thinking: undefined` instead of an empty list. */ efforts: readonly Effort[]; /** Optional default effort applied when this model is selected. Falls back to global default if absent. */ defaultLevel?: Effort; /** * Effort → provider wire-value remap, baked at build time. Identity for * efforts the map omits. Used by Anthropic adaptive thinking, OpenAI- * compatible `reasoning_effort`, and Responses-style reasoning params. */ effortMap?: Partial>; /** * Adaptive thinking accepts the `display` field (Opus 4.7+, Fable/Mythos * 5). Also implies native interleaved thinking — no beta header needed. */ supportsDisplay?: boolean; /** * Thinking signatures bind each block to its preceding conversation prefix. * Requests that rewrite the prefix must opt into the provider's drop/error control. */ prefixBinding?: boolean; /** * Per-effort upstream wire-id routing for collapsed effort-tier variants * (`compat/collapse.ts`). Keyed by pi effort; `"off"` applies when * thinking is disabled. Missing keys fall back to `requestModelId ?? id`. */ effortRouting?: Readonly>>; /** * Per-effort thinking budget in tokens, baked at build time for collapsed * variants whose upstream expects an explicit `thinkingBudget` instead of a * value derived from the generic ladder (Antigravity Cloud Code Assist * gemini-3.x). Request mapping prefers caller `thinkingBudgets`, then this * map, then the provider default ladder. Only meaningful for `mode: "budget"`. */ effortBudgets?: Readonly>>; /** * When true, a thinking-off request MUST explicitly suppress thinking on * the wire (google-level: `thinkingLevel: "MINIMAL"` + `includeThoughts: * false`; budget: `thinkingBudget: 0`) instead of omitting thinkingConfig — * Cloud Code Assist re-applies the per-id baked server default when the * config is absent. */ suppressWhenOff?: boolean; /** * Reasoning is mandatory upstream: the endpoint rejects disabled or * omitted thinking (e.g. OpenRouter Gemini 3.x — "Reasoning is mandatory * for this endpoint and cannot be disabled"). Request mapping clamps * thinking-off to the lowest supported effort unless `suppressWhenOff` * provides an explicit wire off-path. */ requiresEffort?: boolean; /** * The catalog has no evidence this model reasons (unclassified id, no * capability metadata). The ladder is offered for the user to opt into: * sessions leave thinking unset until the user picks an effort, and a * request without an effort goes out as non-reasoning (see * `withoutUnverifiedThinking`). */ unverified?: boolean; } export type Provider = string; /** Token budgets for each thinking level (token-based providers only) */ export type ThinkingBudgets = { [key in Effort]?: number; }; export interface Usage { /** Non-cached conversation input tokens (matches the bucket the provider bills as new input). */ input: number; /** Total conversation output tokens for the turn, including thinking, assistant text, and tool-call argument tokens. */ output: number; /** Conversation tokens read from the prompt cache. */ cacheRead: number; /** Conversation tokens written to the prompt cache (cache creation). */ cacheWrite: number; /** Sum of input + output + cacheRead + cacheWrite plus provider-side orchestration tokens when reported. */ totalTokens: number; /** Provider-reported occupied context tokens when the value is authoritative but not a billable input/output bucket. */ contextTokens?: number; /** Provider-side orchestration tokens, billed but not part of the conversation prompt/cache buckets. */ orchestration?: { /** Non-cached orchestration input tokens. */ input?: number; /** Orchestration tokens read from provider-side cache. */ cacheRead?: number; /** Orchestration output tokens. */ output?: number; }; /** Copilot premium-request counter, when applicable. */ premiumRequests?: number; /** * Reasoning/thinking tokens included in `output`, when the provider reports them * (OpenAI `output_tokens_details.reasoning_tokens`, Google `thoughtsTokenCount`). * Always a subset of `output` — non-reasoning output is `output - reasoningTokens`. * * Providers that don't expose this leave it undefined rather than guessing; * `undefined` means unknown, NOT zero. */ reasoningTokens?: number; /** * Cache-write TTL breakdown (Anthropic only). When set, the components sum to * `cacheWrite`. Absent providers do not populate this. */ cttl?: { ephemeral5m?: number; ephemeral1h?: number; }; /** * Server-side tool invocations made during this turn (Anthropic web_search / * web_fetch, OpenAI built-in tools when reported). Counts requests, not tokens. */ server?: { webSearch?: number; webFetch?: number; }; /** Provider-reported credit meter values for credit-based billing APIs. */ credits?: { /** Uncommitted per-response credit cost, when reported. */ cost?: number; /** Final committed credit cost, when reported. */ committedCost?: number; /** Final committed ACU cost, when reported. */ acuCost?: number; }; cost: { input: number; output: number; cacheRead: number; cacheWrite: number; total: number; }; } export type OpenAIReasoningFormat = "openai" | "openrouter" | "zai" | "kimi" | "qwen" | "qwen-chat-template" | "chat-template"; export type OpenAIReasoningDisableMode = "omit" | "lowest-effort" | "none-effort" | "openrouter-enabled-false" | "cline-enabled-false" | "venice-disable-thinking" | "zai-thinking-disabled" | "qwen-enable-thinking-false" | "qwen-template-false" | "chat-template-thinking-false"; export type OpenAIStreamMarkupHealingPattern = "kimi" | "dsml" | "qwen" | "thinking"; /** * Compatibility settings for openai-completions API. * Use this to override URL-based auto-detection for custom providers. */ export interface OpenAICompat { /** Whether the provider supports the `store` field. Default: auto-detected from URL. */ supportsStore?: boolean; /** Whether the provider supports the `developer` role (vs `system`). Default: auto-detected from URL. */ supportsDeveloperRole?: boolean; /** * Whether the provider's chat-completions endpoint accepts multiple * leading `system`/`developer` messages. When false, ordered system * prompts are coalesced into a single message joined by `\n\n` so * strict chat templates (e.g. Qwen-served via vLLM, MiniMax) accept * the request. Default: detected per provider/baseUrl. Canonical * OpenAI/Azure/OpenRouter/Cerebras/Together/Fireworks/Groq/DeepSeek/ * Mistral/xAI/Z.ai/GitHub Copilot/Zenmux are treated as `true`; * unknown or strict-template hosts default to `false`. Setting this * to `true` preserves separate blocks, which is preferred for * KV-cache reuse when the trailing prompt changes between calls. */ supportsMultipleSystemMessages?: boolean; /** Whether the provider supports `reasoning_effort`. Default: auto-detected from URL. */ supportsReasoningEffort?: boolean; /** Do not infer a thinking dial when discovery supplies no explicit thinking configuration. */ trustExplicitThinkingOnly?: boolean; /** Optional mapping from pi-ai reasoning levels to provider/model-specific `reasoning_effort` values. */ reasoningEffortMap?: Partial>; /** Whether the provider supports `stream_options: { include_usage: true }` for token usage in streaming responses. Default: true. */ supportsUsageInStreaming?: boolean; /** Which field to use for max tokens. Default: auto-detected from URL. */ maxTokensField?: "max_completion_tokens" | "max_tokens"; /** Whether tool results require the `name` field. Default: auto-detected from URL. */ requiresToolResultName?: boolean; /** Whether a user message after tool results requires an assistant message in between. Default: auto-detected from URL. */ requiresAssistantAfterToolResult?: boolean; /** Whether thinking blocks must be converted to text blocks with delimiters. Default: auto-detected from URL. */ requiresThinkingAsText?: boolean; /** Whether tool call IDs must be normalized to Mistral format (exactly 9 alphanumeric chars). Default: auto-detected from URL. */ requiresMistralToolIds?: boolean; /** Format for reasoning/thinking parameter. `"kimi"` uses `thinking: { type, effort }`; other values select their provider-native reasoning fields. Default: `"openai"`. */ thinkingFormat?: OpenAIReasoningFormat; /** Kimi Code transport selected by live per-model protocol metadata. User settings take precedence. */ kimiApiFormat?: "openai" | "anthropic"; /** Request-time disable encoding for the selected reasoning/thinking format. Default: derived from `thinkingFormat`. */ reasoningDisableMode?: OpenAIReasoningDisableMode; /** Whether the provider rejects `reasoning.effort`/`reasoning_effort` even when the model reasons natively. Default: false unless reasoning effort is unsupported. */ omitReasoningEffort?: boolean; /** Whether Responses requests should ask for encrypted reasoning replay items. Default: true. */ includeEncryptedReasoning?: boolean; /** Whether replayed Responses history should strip native `type: "reasoning"` items before request encoding. Default: false. */ filterReasoningHistory?: boolean; /** Optional `thinking.keep` value for Z.ai/Moonshot-style thinking params. Set false to suppress auto-detected keep. Default: auto-detected. */ thinkingKeep?: "all" | false; /** Which reasoning content field to emit on assistant messages. Default: auto-detected. */ reasoningContentField?: "reasoning_content" | "reasoning" | "reasoning_text"; /** Decode Mistral thinking parts in streamed content and replay them as typed assistant content. */ mistralReasoningContentParts?: boolean; /** Whether assistant tool-call messages must include reasoning content. Default: false. */ requiresReasoningContentForToolCalls?: boolean; /** Whether all assistant messages must include reasoning content. Default: false. */ requiresReasoningContentForAllAssistantTurns?: boolean; /** Whether the provider accepts a synthetic placeholder (e.g. ".") for missing reasoning_content on tool-call turns. Default: true. Set to false for providers like DeepSeek that validate the exact reasoning_content value. */ allowsSyntheticReasoningContentForToolCalls?: boolean; /** * Value emitted for the reasoning field on tool-call turns when the provider * requires it (`requiresReasoningContentForToolCalls`) but no reasoning was * captured. Default: "". Some upstreams validate the exact value — the droid * proxy's DeepSeek family requires a single space. */ syntheticReasoningContentFallback?: string; /** * Replay preserved thinking blocks as `reasoning_content` (or the configured * `reasoningContentField`) on EVERY assistant turn that carried reasoning, * regardless of whether the upstream provider validates the field. Local * llama.cpp-style servers (llama.cpp, LM Studio, vLLM, sglang, Ollama in * openai-completions mode) re-tokenize the full chat-template prompt every * request; Qwen3 / DeepSeek-R1 / GLM templates reconstruct the `` * block from `reasoning_content`. Dropping the field re-renders the * assistant turn without ``, diverging from the slot's KV cache state * and forcing full prompt re-processing (#3528). Default: auto-detected * (loopback/private baseUrl or local provider id with thinking-enabled * models). */ replayReasoningContent?: boolean; /** * Send `preserve_thinking: true` so the Qwen3.6+ chat template renders * `...` markup for EVERY assistant turn (not just turns * after the last user message). Without it, the template strips the think * block from older assistant turns: * * ```jinja * {%- if (preserve_thinking is defined and preserve_thinking is true) * or (loop.index0 > ns.last_query_index) %} * <|im_start|>assistant\n\n{rc}\n\n\n{content} * {%- else %} * <|im_start|>assistant\n{content} * ``` * * The cache from the original generation has `...` tokens, * so once a new user message arrives the prior assistant turns become * "older" and the stripped re-render diverges — full prompt re-processing * on SWA models (#3541). Default: auto-detected (Qwen thinking format on * a local llama.cpp-style backend, paired with `replayReasoningContent`). * Non-Qwen templates ignore the flag, so the auto-detection is safe. */ qwenPreserveThinking?: boolean; /** * Route the requested thinking effort onto the Qwen 3.8+ chat template's * `reasoning_effort` kwarg (`low`/`medium`/`xhigh`; template default * `xhigh`). Emitted inside `chat_template_kwargs` for both Qwen dialects * (plus the top-level field on the `qwen` dialect, which newer llama.cpp * builds map natively). Without it the qwen dialects only toggle * `enable_thinking` and the template always thinks at its `xhigh` default. * Default: auto-detected (Qwen 3.8+ id on a local llama.cpp-style backend). */ qwenTemplateReasoningEffort?: boolean; /** Whether assistant tool-call messages must include non-empty content. Default: false. */ requiresAssistantContentForToolCalls?: boolean; /** Whether the provider supports the `tool_choice` parameter. Default: true. */ supportsToolChoice?: boolean; /** * Whether forced `tool_choice` values (`"required"` or named tools) are accepted. * When false, request builders keep tools available but downgrade forced choices * to provider-default auto selection. Default: true. */ supportsForcedToolChoice?: boolean; /** * Whether the chat-completions endpoint accepts the object form that pins one * named function (`{ type: "function", function: { name } }`). Some * OpenAI-compatible hosts such as llama.cpp only accept string * `tool_choice` values; request builders downgrade a named force to * `"required"` when this is false. Default: true. */ supportsNamedToolChoice?: boolean; /** * Drop reasoning fields (`reasoning_effort`, OpenRouter `reasoning`) for * the request when `tool_choice` forces a tool call. Mirrors the Anthropic * `disableThinkingIfToolChoiceForced` rule for backends like Kimi that * 400 with `tool_choice 'specified' is incompatible with thinking * enabled` whenever both are present. Default: auto-detected (Kimi). */ disableReasoningOnForcedToolChoice?: boolean; /** * Drop reasoning fields (`reasoning_effort`, OpenRouter `reasoning`) for * any request that sends `tool_choice`. Use for providers/models that accept * tools and `tool_choice`, but reject `tool_choice` while thinking is enabled. * Default: auto-detected (DeepSeek reasoning models). */ disableReasoningOnToolChoice?: boolean; /** * Disable reasoning whenever the request advertises function tools. * Use for model surfaces that reject every tools-plus-reasoning combination. * Default: false. */ disableReasoningWithTools?: boolean; /** OpenRouter-specific routing preferences. Only used when baseUrl points to OpenRouter. */ openRouterRouting?: OpenRouterRouting; /** Vercel AI Gateway routing preferences. Only used when baseUrl points to Vercel AI Gateway. */ vercelGatewayRouting?: VercelGatewayRouting; /** * Provider-specific wire model-id transform applied to the base id, overriding * the provider-detected default. Discovery layers set this per model when the * upstream roster declares the id's namespace (e.g. ClinePass free-tier models * arrive pre-namespaced and use `"raw"`), so wire form follows data rather * than id shape. */ wireModelIdMode?: "raw" | "cline-pass" | "firepass" | "fireworks" | "openrouter"; /** Extra fields to include in request body (e.g. gateway routing hints for OpenClaw-style proxies). */ extraBody?: Record; /** Request-session header that should mirror the normalized prompt-cache key. Default: unset. */ promptCacheSessionHeader?: "x-grok-conv-id" | "x-session-id"; /** Request header carrying the conversation session id, independent of prompt caching. Default: unset. */ sessionHeader?: "x-litellm-session-id"; /** Whether chat-completions payloads should include provider-specific prompt-cache markers. */ cacheControlFormat?: "anthropic" | undefined; /** * Whether this endpoint/model accepts OpenAI's explicit * `prompt_cache_breakpoint` content markers and `prompt_cache_options`. * Defaults to the exact first-party model generation allowlist. */ supportsPromptCacheBreakpoints?: boolean; /** The only currently supported minimum lifetime for explicit OpenAI cache breakpoints. */ promptCacheBreakpointTtl?: "30m"; /** Whether the provider supports the `strict` field in tool definitions. Default: auto-detected per provider/baseUrl (conservative for unknown providers). */ supportsStrictMode?: boolean; /** * Tool-schema dialect the endpoint validates `tools.function.parameters` * against. * * `"moonshot-mfjs"` triggers Moonshot Flavored JSON Schema normalization * (collapse `const`→`enum`, infer `type` on bare enums, strip unsupported * validators/`prefixItems`) because Moonshot/Kimi native hosts reject * standard JSON Schema constructs with HTTP 400. * * `"grammar"` triggers grammar-sampler normalization (widen bare boolean * `true`/`{}` subschemas in genuine subschema slots into a value-accepting * union of primitives) because grammar-constrained backends (llama.cpp, LM * Studio, vLLM) build a GBNF grammar from the JSON Schema and 400 with * `Unrecognized schema: true` on a bare boolean subschema (issue #5914). * Boolean `additionalProperties`/`unevaluatedProperties` are preserved — the * grammar converter reads them as closed/open-object semantics, and * `additionalProperties: false` pins the strict object shape. * * Default: auto-detected — `"moonshot-mfjs"` on Moonshot native hosts * (api.moonshot.ai / api.kimi.com) and Kimi-family model ids on any host, * since proxies (OpenRouter, custom gateways) forward schemas to Moonshot * verbatim; `"grammar"` on local OpenAI-compatible backends. Set `"none"` * to opt a host out. */ toolSchemaFlavor?: "moonshot-mfjs" | "grammar" | "none"; /** * Stream-watchdog first-event timeout in ms. * Set to `0` to allow unbounded prompt processing. Default: auto-detected * (disabled for local OpenAI-compatible backends). */ streamFirstEventTimeoutMs?: number; /** * Stream-watchdog idle-timeout floor in ms for slow reasoning hosts. * Default: auto-detected (GLM coding-plan hosts, direct DeepSeek reasoning). */ streamIdleTimeoutMs?: number; /** Whether the host honors `prompt_cache_retention: "24h"` on the Responses API. Default: auto-detected (api.openai.com). */ supportsLongPromptCacheRetention?: boolean; /** Whether tool schemas must be sent either all strict or all non-strict. Undefined keeps the existing per-tool mixed behavior. */ toolStrictMode?: "all_strict" | "none"; /** Whether request shaping may send reasoning params at all. Default: auto-detected (disabled for GitHub Copilot chat-completions). */ supportsReasoningParams?: boolean; /** Whether Responses requests may include `reasoning.summary`. Default: true except on known incompatible hosts. */ supportsReasoningSummary?: boolean; /** Whether to chain OpenAI Responses turns using stored response ids. Unset uses the official-endpoint default; env and call options take precedence. */ statefulResponses?: boolean; /** * Whether the endpoint accepts explicit sampling parameters (`temperature`, * `top_p`, `top_k`, `min_p`, penalties). OpenAI proprietary reasoning models * (o-series, gpt-5+) reject them with `400 Unsupported parameter: * 'temperature' is not supported with this model` on every serving host * (official, Azure, GitHub Copilot). When unset, auto-detected from the * model id. Default: true. Issue #5606. */ supportsSamplingParams?: boolean; /** * Whether presence/frequency penalties and stop sequences may be sent. * First-party xAI `/v1/responses` rejects penalty fields for every model. * xAI reasoning models also reject them (and `stop`) on chat completions. * When unset, auto-detected. Default: true. */ supportsPenaltyAndStopParams?: boolean; /** Always send a max-token field when the caller did not provide one. Default: auto-detected (Kimi-family models derive TPM limits from max_tokens). */ alwaysSendMaxTokens?: boolean; /** Whether Responses-API tool-call/result history must be strictly paired. Default: auto-detected (Azure OpenAI, GitHub Copilot). */ strictResponsesPairing?: boolean; /** Whether the Responses API accepts the `detail: "original"` image hint. Default: true for OpenAI, Azure OpenAI, and Codex; false for other hosts. Explicit overrides win. */ supportsImageDetailOriginal?: boolean; /** * Whether the Responses endpoint accepts `configuration_update` input items * that change `reasoning.effort` mid-conversation while the request-level * effort stays pinned for prompt caching (GPT-6 family). Default: * rule-detected (`true` for GPT-6 models on any host, `false` otherwise). * Set `false` for custom `openai-responses` / `openai-codex-responses` * endpoints that reject the item type with HTTP 400; effort changes are then * sent as the top-level `reasoning.effort`. */ supportsConfigurationUpdate?: boolean; /** * Whether the Responses WebSocket accepts `response.steer`, which queues user * input into the in-flight response (GPT-6 family). Default: rule-detected. * Set `false` for proxies that reject the event; steering then waits for the * next request boundary. */ supportsSteering?: boolean; /** Whether streamed reasoning deltas for the same field may repeat the full cumulative text snapshot. Default: false. */ reasoningDeltasMayBeCumulative?: boolean; /** Strip leaked DeepSeek chat-template special tokens from visible content deltas. Default: auto-detected. */ stripDeepseekSpecialTokens?: boolean; /** Drop assistant thinking blocks from replayed chat-completions history. Default: false. */ stripThinkingHistory?: boolean; /** Heal leaked chat-template/tool-call/thinking markup from visible content deltas. Default: auto-detected. */ streamMarkupHealingPattern?: OpenAIStreamMarkupHealingPattern; /** Whether this wire may revise already-streamed text (`stream-revision` axis). Unassigned: append-only. */ streamRevision?: "none" | "possible"; /** Treat an empty length-finished stream as a context-window error. Default: auto-detected. */ emptyLengthFinishIsContextError?: boolean; /** Normalize tool call ids to OpenAI's 40-character limit. Default: auto-detected. */ usesOpenAIToolCallIdLimit?: boolean; /** * Compat deltas applied when a request actually engages thinking mode * (reasoning requested and not disabled, model reasoning-capable, and not * suppressed by a forced tool choice). `buildModel` materializes the full * alternate view as `compat.whenThinking`; handlers pointer-swap, never * spread. Default: auto-detected (OpenCode gateways, #1071/#1484). */ whenThinking?: Partial>; /** Kimi K3 drives reasoning through native `reasoning_effort` on Moonshot-native hosts. */ nativeKimiK3Reasoning?: boolean; /** GLM-5.2 accepts Z.ai's `reasoning_effort` dialect alongside binary thinking. */ zaiReasoningEffortDialect?: boolean; /** Clamp the requested max output tokens to the model's advertised ceiling. */ clampOutputToModelMax?: boolean; /** Strip image inputs before encoding (text-only serving of a multimodal id). */ stripImageInput?: boolean; } /** * Compatibility settings for anthropic-messages API. * Use this to disable features that strict-by-default Anthropic accepts but * that proxy gateways (Vertex AI, AWS Bedrock-style fronts, etc.) reject. */ export interface AnthropicCompat { /** Whether thinking requests may include `context_management` and its beta header. Default: true. */ supportsContextManagement?: boolean; /** * Whether the model and host support Anthropic on-demand compaction * (`compact-2026-09-04` requests and signed replay). Enabled on Opus 4.6+, * Sonnet 4.6+, Fable/Mythos 5+ on supported hosts. Default: false. */ supportsServerCompaction?: boolean; /** * Whether the model supports message threads (`message-threads-2026-08-12`): * later turns continue a server-held conversation and send only new * messages. Enabled on Claude 4.5+ for the first-party provider; the * transport still requires the official endpoint unless the caller opts in. * Default: false. */ supportsMessageThreads?: boolean; /** * Whether the model is served by the first-party Anthropic provider (its * default route is the official API). Rule-owned on the provider; the * compaction transport pairs it with a per-request effective-URL check * because reroutes leave it stale-true. Vertex is selected by its provider * contract instead. Default: false. */ firstPartyProvider?: boolean; /** * Whether the provider honors Claude Code's `CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS` * kill switch, which withholds pre-release fields (`context_management`, beta * tool fields, task budgets, structured-output format, `thinking.block_binding`, * server compaction) with their betas. Rule-owned on the * provider whose `ANTHROPIC_*` env routing Claude Code shares. Default: false. */ honorsClaudeCodeBetaKillSwitch?: boolean; /** * Whether requests may carry `output_config.effort` (and its effort beta * header). Vertex AI rejects the field/header. Default: true. */ supportsOutputEffort?: boolean; /** * Stream-watchdog idle-timeout fallback in ms for slow reasoning hosts. * Set to 0 to disable the inter-event idle watchdog entirely, matching * `OpenAICompat.streamIdleTimeoutMs`. * * When unset, direct Anthropic streams use `PI_STREAM_IDLE_TIMEOUT_MS`, * then the legacy `PI_OPENAI_STREAM_IDLE_TIMEOUT_MS` alias, then 300s. */ streamIdleTimeoutMs?: number; /** * Drop the top-level `strict: true` field on tool definitions. Vertex AI's * Anthropic-compatible endpoint rejects unknown tool fields with * `tools..custom.strict: Extra inputs are not permitted`. */ disableStrictTools?: boolean; /** * The endpoint is Amazon Bedrock's Anthropic Messages API (`/anthropic` on * bedrock-runtime or bedrock-mantle). Requests drop tool `strict`, fit * `metadata.user_id` to Bedrock's request-metadata pattern, and may use * on-demand compaction. Detected from the model `baseUrl`; set it in * models.yml `compat` for a route the URL check cannot see (a proxy, an * `ANTHROPIC_BASE_URL` reroute) or to `false` to opt out. */ bedrockMessagesApi?: boolean; /** * Map adaptive thinking (`thinking: { type: "adaptive" }`) to * `{ type: "enabled", budget_tokens }`. Vertex AI rejects the `adaptive` * tag with `Input tag 'adaptive' ... does not match any of the expected * tags: 'disabled', 'enabled'`. */ disableAdaptiveThinking?: boolean; /** Whether tools may include Anthropic's per-tool eager_input_streaming flag. Default: true for the canonical Anthropic API. */ supportsEagerToolInputStreaming?: boolean; /** Whether long prompt-cache retention (`ttl: "1h"`) is supported. Default: true for canonical Anthropic API. */ supportsLongCacheRetention?: boolean; /** Whether a `ttl: "1h"` breakpoint on API-key requests adds the `extended-cache-ttl-2025-04-11` beta. Unset: true (Vertex rawPredict URLs never send it). */ extendedCacheTtlBeta?: boolean; /** * Whether mid-conversation `role: "system"` messages are accepted in the * `messages` array. When unset, auto-detected from model and deployment policy. */ supportsMidConversationSystem?: boolean; /** Whether turn-scoped system messages accept `clear_at`. */ supportsTurnScopedSystem?: boolean; /** Whether tool availability can change through system-message tool references. */ supportsMidConversationToolChanges?: boolean; /** Whether effort can change through a per-message `output_config`. */ supportsPerMessageEffort?: boolean; /** * Whether the endpoint accepts `thinking.block_binding` and reports * `input_transformations` under the thinking-binding-controls beta. */ supportsThinkingBindingControls?: boolean; /** * Whether the model replaces `thinking: { type: "disabled" }` with * `thinking: { type: "between_tools" }` (Claude Sonnet 5.5). The disabled * form is rejected with a 400; `between_tools` skips up-front thinking and * only allows progress updates between tool calls. */ supportsBetweenToolsThinking?: boolean; /** * Whether the model accepts a forced `tool_choice` (`{ type: "any" }` or * `{ type: "tool", name }`). Claude Fable/Mythos 5 reject forced tool use * outright ("tool_choice forces tool use is not compatible with this model"); * the request builder downgrades forced choices to `auto` when this is false. * When unset, auto-detected from the model id. Default: true. */ supportsForcedToolChoice?: boolean; /** * Whether the model accepts sampling parameters (`temperature`, `top_p`, * `top_k`). Opus 4.7+ and Fable/Mythos reject them with a 400. When unset, * auto-detected from the model id. Default: true. */ supportsSamplingParams?: boolean; /** * Include a non-standard `id` field (aliasing `tool_use_id`) on * `tool_result` blocks. Z.AI's Anthropic-compatible proxy deserializes * tool results into a class that reads `.id` (issue #814). Default: * auto-detected (Z.AI hosts). */ requiresToolResultId?: boolean; /** * Allow configured Claude Code fingerprint headers to replace generated * OAuth defaults on non-official Anthropic endpoints. */ allowAnthropicHeaderOverrides?: boolean; /** * Replay unsigned `thinking` blocks from prior assistant turns as native * thinking instead of demoting them to text. Official Anthropic enforces * signature-based thinking-chain integrity, so unsigned blocks must stay * text there; compatible reasoning endpoints (Z.AI, DeepSeek, …) emit * unsigned blocks and expect them back as `type: "thinking"` (#2005). * Default: auto-detected from provider/baseUrl and `model.reasoning`. */ replayUnsignedThinking?: boolean; /** * Whether a thinking-mode history must carry a `thinking` block on EVERY * assistant turn of the current turn. DeepSeek's Anthropic endpoint rejects * the whole request (`The content[].thinking in the thinking mode must be * passed back to the API.`) when any assistant turn after the last user text * lacks one, including turns another upstream in the same gateway model group * produced without reasoning. Presence is all it validates (the block text may * be a placeholder, the signature may be empty), and only `thinking` counts — * `redacted_thinking` does not, and that endpoint rejects the block outright. * A model group that may fail over to such an endpoint must set this: the * stricter member defines the replay contract for the group. * Default: false (official Anthropic and lax proxies tolerate a turn without * thinking and the block is not invented for them). */ requiresThinkingPresence?: boolean; /** * Whether the endpoint requires `thinking.type: "enabled"` whenever the * model reasons. Use for models that reject omitted or disabled thinking. */ requiresThinkingEnabled?: boolean; /** * Prefix Anthropic built-in tool names (`web_search`, `code_execution`, ...) * when they are ordinary client tools. Some Anthropic-compatible gateways * intercept those exact names as server tools and return raw search/result * blocks instead of normal `tool_use` calls. */ escapeBuiltinToolNames?: boolean; /** * The configured endpoint enforces Anthropic's signature protocol on * replayed thinking blocks — either the official API itself or a proxy * that forwards to it (GitHub Copilot, ZenMux, Cloudflare AI Gateway's * `/anthropic` route, Google Vertex's `publishers/anthropic/…`). * Downstream transforms strip stale cross-model thinking signatures on * these endpoints so the signing proxy doesn't 400 with * `Invalid signature in thinking block` (#4297), and adaptive-thinking * models keep the interleaved-thinking beta on them (#6717). Known hosts * are auto-detected from provider id and baseUrl; set this to mark an * opaque signing proxy the URL list can't recognize. Superset of * {@link ResolvedAnthropicCompat.officialEndpoint}. */ signingEndpoint?: boolean; /** * Inject the Claude Code identity instruction on OAuth requests. Haiku 3.5 * predates the framing and rejects it; class rules set `false` there. */ injectClaudeCodeInstruction?: boolean; /** Strip image inputs before encoding (text-only serving of a multimodal id). */ stripImageInput?: boolean; /** * Largest width or height a single image block may carry. The canonical * Anthropic API rejects anything larger with `At least one of the image * dimensions exceed max allowed size: 8000 pixels`, and the rejection * poisons every retry and model fallback because the block stays in * context, so the request builder downscales to this value first. Hosts * with a different image contract override it. Default: 8000. */ maxImageDimension?: number; /** * Largest base64 payload a single image block may carry, in bytes. The * canonical Anthropic API measures the encoded string, not the decoded * bytes (`image exceeds 10 MB maximum: 14012300 bytes > 10485760 bytes`), * and an image inside {@link maxImageDimension} can still cross it, so * payload size is clamped on its own. Hosts with a different image * contract override it. Default: 10485760. */ maxImagePayloadBytes?: number; /** * Drop the enabled `thinking` config and replayed thinking blocks when the * conversation is not thinking-led (a proxy contract for non-interleaved * budget models), and replay history without thinking blocks on every turn * that sends `thinking: { type: "disabled" }`. Default: false. */ stripThinkingHistory?: boolean; /** * Send the `effort-2025-11-24` beta exactly when `output_config.effort` * rides the request. Unset keeps the transport's legacy heuristic. */ effortBeta?: boolean; /** * Wire form of a disabled-thinking turn: omit the field, send * `{ type: "disabled" }`, keep adaptive thinking, or send * `{ type: "between_tools" }`. Unset keeps the direct-provider behavior. */ disabledThinking?: "omit" | "disabled" | "adaptive" | "between-tools"; /** * `output_config.effort` pinned on a `between_tools` turn. Unset leaves * the turn's effort untouched. */ betweenToolsEffort?: "low" | "medium" | "high"; /** The model is a fast-mode SKU: send `speed: "fast"` with the fast-mode beta. Default: false. */ fastMode?: boolean; } /** * Compatibility settings for Bedrock Converse requests and native streaming * side-compaction. Cache pricing does not imply these capabilities. */ export interface BedrockCompat { /** Explicit disabled-thinking wire form; unset preserves the provider's existing behavior. */ disabledThinking?: AnthropicCompat["disabledThinking"]; /** Whether this endpoint accepts no checkpoints, automatic caching, or explicit cachePoint blocks. */ promptCacheMode?: "none" | "automatic" | "explicit"; /** Whether this wire may revise already-streamed text (`stream-revision` axis). Unassigned: append-only. */ streamRevision?: "none" | "possible"; /** Whether explicit cachePoint blocks accept `ttl: "1h"`; omitted TTL means Bedrock's 5-minute default. */ supportsLongPromptCacheRetention?: boolean; /** * Bedrock-enforced minimum prompt-prefix tokens for an effective checkpoint. * Capability metadata only: emitters must not estimate local token counts. * Zero means no explicit checkpoints. */ promptCacheMinimumTokens?: number; /** * Bedrock-enforced maximum explicit cache checkpoints per request. * Capability metadata only; zero means no explicit checkpoints. */ promptCacheMaximumCheckpoints?: number; /** * Stream-watchdog idle-timeout fallback in ms; 0 disables the idle watchdog. * Undefined defers to `PI_STREAM_IDLE_TIMEOUT_MS`, then the legacy * `PI_OPENAI_STREAM_IDLE_TIMEOUT_MS` alias, then the 300s default. */ streamIdleTimeoutMs?: number; /** * Whether the served model accepts explicit sampling parameters * (`temperature`, `topP`, …). Class rules set `false` for model lines that * reject them on every host. Unassigned: accepted. */ supportsSamplingParams?: boolean; /** * Whether the model accepts a forced `toolChoice` (`any` / `tool`). Claude * Opus/Sonnet 5.5 reject it outright; the request builder downgrades forced * choices to `auto` when this is false. Default: true. */ supportsForcedToolChoice?: boolean; /** * Whether the endpoint accepts thinking-binding controls (`thinking.block_binding`, * the `thinking-binding-controls-2026-08-01` beta and the `/input_transformations` * response path) on prefix-bound models. Only consulted when * `thinking.prefixBinding` is set; `false` omits the controls while keeping the * local prefix-binding safeguards. Default: true. */ supportsThinkingBindingControls?: boolean; /** * Whether the model supports a compaction-only Bedrock Runtime * InvokeModelWithResponseStream request. Ordinary turns still use Converse. */ supportsServerCompaction?: boolean; } /** Fully-resolved Bedrock Converse and side-compaction capabilities, materialized once by `buildModel`. */ export interface ResolvedBedrockCompat { /** See {@link BedrockCompat.disabledThinking}. */ disabledThinking?: BedrockCompat["disabledThinking"]; promptCacheMode: NonNullable; /** See {@link BedrockCompat.streamRevision}. */ streamRevision?: BedrockCompat["streamRevision"]; supportsLongPromptCacheRetention: boolean; promptCacheMinimumTokens: number; promptCacheMaximumCheckpoints: number; /** See {@link BedrockCompat.supportsSamplingParams}. */ supportsSamplingParams?: boolean; supportsForcedToolChoice: boolean; /** See {@link BedrockCompat.supportsThinkingBindingControls}. */ supportsThinkingBindingControls: boolean; /** See {@link BedrockCompat.supportsServerCompaction}; false unless the Bedrock model-card policy opts in. */ supportsServerCompaction: boolean; /** * Stream-watchdog idle-timeout fallback in ms for hosts with no keepalive * events; 0 disables the idle watchdog. Undefined defers to * `PI_STREAM_IDLE_TIMEOUT_MS`, then the legacy * `PI_OPENAI_STREAM_IDLE_TIMEOUT_MS` alias, then the 300s default. */ streamIdleTimeoutMs?: number; } /** * OpenRouter provider routing preferences. * Controls which upstream providers OpenRouter routes requests to. * @see https://openrouter.ai/docs/provider-routing */ export interface OpenRouterRouting { /** List of provider slugs to exclusively use for this request (e.g., ["amazon-bedrock", "anthropic"]). */ only?: string[]; /** List of provider slugs to try in order (e.g., ["anthropic", "openai"]). */ order?: string[]; } /** * Vercel AI Gateway routing preferences. * Controls which upstream providers the gateway routes requests to. * @see https://vercel.com/docs/ai-gateway/models-and-providers/provider-options */ export interface VercelGatewayRouting { /** List of provider slugs to exclusively use for this request (e.g., ["bedrock", "anthropic"]). */ only?: string[]; /** List of provider slugs to try in order (e.g., ["anthropic", "openai"]). */ order?: string[]; /** Enables Vercel AI Gateway's provider-aware automatic prompt caching. */ caching?: "auto"; /** Stable Responses input-item prefix to anchor for automatic caching. */ cacheAnchorItems?: number; /** Requested automatic-cache lifetime for the Responses API. */ cacheTtl?: "5m" | "1h"; } type ResolvedToolStrictMode = NonNullable | "mixed"; /** * Fields whose meaning is identical across chat-completions and Responses surfaces. * Each builder still computes its own per-surface value when defaults diverge. */ export interface ResolvedOpenAISharedCompat { supportsDeveloperRole: boolean; supportsStrictMode: boolean; supportsReasoningEffort: boolean; trustExplicitThinkingOnly?: boolean; reasoningEffortMap: Partial>; supportsReasoningParams: boolean; supportsSamplingParams: boolean; supportsPenaltyAndStopParams: boolean; thinkingFormat: OpenAIReasoningFormat; /** Kimi Code transport selected by live per-model protocol metadata. */ kimiApiFormat?: OpenAICompat["kimiApiFormat"]; reasoningDisableMode: OpenAIReasoningDisableMode; omitReasoningEffort: boolean; includeEncryptedReasoning: boolean; filterReasoningHistory: boolean; disableReasoningOnForcedToolChoice: boolean; disableReasoningOnToolChoice: boolean; disableReasoningWithTools?: boolean; supportsToolChoice: boolean; supportsForcedToolChoice: boolean; supportsNamedToolChoice: boolean; reasoningContentField?: OpenAICompat["reasoningContentField"]; mistralReasoningContentParts?: boolean; requiresReasoningContentForToolCalls: boolean; requiresReasoningContentForAllAssistantTurns: boolean; allowsSyntheticReasoningContentForToolCalls: boolean; /** See {@link OpenAICompat.syntheticReasoningContentFallback}. */ syntheticReasoningContentFallback?: string; replayReasoningContent: boolean; qwenPreserveThinking: boolean; qwenTemplateReasoningEffort: boolean; requiresThinkingAsText: boolean; requiresMistralToolIds: boolean; requiresToolResultName: boolean; requiresAssistantAfterToolResult: boolean; requiresAssistantContentForToolCalls: boolean; stripDeepseekSpecialTokens: boolean; streamMarkupHealingPattern?: OpenAIStreamMarkupHealingPattern; /** See {@link OpenAICompat.streamRevision}. */ streamRevision?: OpenAICompat["streamRevision"]; /** See {@link OpenAICompat.streamFirstEventTimeoutMs}. */ streamFirstEventTimeoutMs?: number; reasoningDeltasMayBeCumulative: boolean; emptyLengthFinishIsContextError: boolean; usesOpenAIToolCallIdLimit: boolean; promptCacheSessionHeader?: OpenAICompat["promptCacheSessionHeader"]; sessionHeader?: OpenAICompat["sessionHeader"]; /** * Whether this model accepts explicit OpenAI prompt-cache breakpoints. * Built catalog models always materialize this false-by-default value; * optionality preserves hand-authored resolved compat fixtures. */ supportsPromptCacheBreakpoints?: boolean; /** Minimum cache lifetime supported by explicit OpenAI prompt-cache breakpoints. */ promptCacheBreakpointTtl?: "30m"; /** The model sits behind OpenRouter (routing prefs and max-token omission apply). */ isOpenRouterHost: boolean; /** Whether this endpoint needs a max-token field even when caller did not set one. */ alwaysSendMaxTokens: boolean; /** Clamp a requested output-token count to the model's advertised ceiling. */ clampOutputToModelMax: boolean; openRouterRouting?: OpenAICompat["openRouterRouting"]; /** Provider-specific wire model-id transform applied to the base id. */ wireModelIdMode: "raw" | "cline-pass" | "firepass" | "fireworks" | "openrouter"; /** See {@link OpenAICompat.toolSchemaFlavor}. Read by both wire paths when converting tools. */ toolSchemaFlavor?: OpenAICompat["toolSchemaFlavor"]; /** Strip image inputs before encoding (text-only serving of a multimodal id). */ stripImageInput: boolean; /** Flatten/reject leftover root `anyOf`/`oneOf` unions in strict tool schemas (xAI's function-calling validator 400s on them). */ rejectRootObjectUnion: boolean; /** Retry without strict tools when the host rejects a strict grammar as too large (OpenRouter-Anthropic compiled-grammar overflow). */ retryWithoutStrictOnGrammarError: boolean; } /** * Fully-resolved chat-completions compat view: every detected default * materialized and user overrides applied. Built once per model by * `buildModel`; request handlers read fields and never detect, resolve, or * allocate. */ export type ResolvedOpenAICompat = ResolvedOpenAISharedCompat & Required> & { vercelGatewayRouting?: OpenAICompat["vercelGatewayRouting"]; extraBody?: OpenAICompat["extraBody"]; cacheControlFormat?: OpenAICompat["cacheControlFormat"]; thinkingKeep?: OpenAICompat["thinkingKeep"]; streamIdleTimeoutMs?: number; stripThinkingHistory?: boolean; /** The configured `baseUrl` is the official OpenAI API (provider `openai`); unset otherwise. */ officialEndpoint?: boolean; toolStrictMode: ResolvedToolStrictMode; /** The model sits behind Vercel AI Gateway. */ isVercelGatewayHost: boolean; /** Send the normalized prompt-cache key as top-level `prompt_cache_key` on chat completions. */ supportsPromptCacheKey: boolean; dropThinkingWhenReasoningEffort: boolean; /** Complete alternate view for thinking-engaged requests; swap pointers, never spread. */ whenThinking?: ResolvedOpenAICompat; }; /** Fully-resolved Responses-API compat view (same contract as `ResolvedOpenAICompat`). */ export interface ResolvedOpenAIResponsesCompat extends ResolvedOpenAISharedCompat { supportsLongPromptCacheRetention: boolean; strictResponsesPairing: boolean; supportsImageDetailOriginal: boolean; supportsObfuscationOptOut: boolean; /** * Whether `reasoning.context: "all_turns"` (full cross-turn reasoning * replay) is accepted. Rule-owned: gpt-5.4+ wire generation on the Codex * transport; earlier ids reject the value. */ supportsAllTurnsReasoningContext: boolean; /** * Whether a `configuration_update` input item may change `reasoning.effort` * mid-conversation while the request-level effort stays byte-stable for * prompt caching. Rule-owned: the GPT-6 family; earlier models do not * support the item type. */ supportsConfigurationUpdate: boolean; /** * Whether the WebSocket transport may send `response.steer` to deliver user * input into the in-flight response. Rule-owned: GPT-6 family. */ supportsSteering: boolean; /** Inject the `# Juice: 0 !important` developer item when reasoning is forced off (gpt-5.6+). */ requiresReasoningOffJuiceInstruction: boolean; /** * Whether `reasoning.summary` may be sent. First-party xAI `/v1/responses` * rejects the field; handlers pass `null` so the wire omits it instead of * filling `"auto"`. */ supportsReasoningSummary: boolean; /** Optional chaining override; unset falls back to officialEndpoint at request time. */ statefulResponses?: boolean; /** * Whether the host can store Responses results server-side (`store: true`). * Rule-owned: hosts that keep generating after a client disconnect so a * dropped stream can resume via `GET /responses/{id}`. Storage is opt-in * per request (`storeResponses` stream option, else * `PI_MUSE_STORE_RESPONSES`); stored runs retain prompts and outputs on the provider. */ storeResponses: boolean; /** * Prefix the `openai-responses` handler puts on every function-tool name it * declares or replays, and strips from returned calls through the request's * wire-name table. Rule-owned: hosts that reject requests declaring certain * exact tool names (Muse Code). Unset sends names unchanged. Other * Responses-family handlers do not read it. */ toolNamePrefix?: string; /** * Whether the host binds native history items (`encrypted_content`, item * ids) to the connection that issued them, so a new process must rebuild * prior turns from message content until its first successful response. * Rule-owned: GitHub Copilot. */ connectionBoundNativeHistory: boolean; streamIdleTimeoutMs?: number; vercelGatewayRouting?: OpenAICompat["vercelGatewayRouting"]; /** The model sits behind Vercel AI Gateway's Responses endpoint. */ isVercelGatewayHost: boolean; /** * The configured endpoint is first-party OpenAI (`provider === "openai"` on * an `api.openai.com` or unset baseUrl), or the Codex backend * (`openai-codex-responses` on the default Codex baseUrl). Gates platform * OpenAI's official-only Responses behavior (default-on stateful * `previous_response_id` chaining and the `text.verbosity` field; the Codex * adapter is not governed by either gate) and host request-size budgets. */ officialEndpoint: boolean; /** Run Harmony-protocol leak detection/mitigation on streamed output. */ harmonyLeakMitigation: boolean; /** Responses-surface prompt-cache marker dialect (OpenRouter-Anthropic `cache_control`). */ cacheControlFormat?: OpenAICompat["cacheControlFormat"]; } /** * OpenRouter is a pseudo API: runtime dispatch can use either Responses * (default) or Chat Completions (`PI_OPENROUTER_RESPONSES=0`) with the same * model object, so its resolved compat must satisfy both handlers. */ export type ResolvedOpenRouterCompat = ResolvedOpenAICompat & ResolvedOpenAIResponsesCompat; /** Fully-resolved anthropic-messages compat view (same contract as `ResolvedOpenAICompat`). */ export type ResolvedAnthropicCompat = Required> & { /** Effort-beta override; undefined keeps the transport's legacy heuristic. */ effortBeta?: AnthropicCompat["effortBeta"]; /** Extended-cache-ttl beta opt-out; undefined sends it where a 1h breakpoint needs it. */ extendedCacheTtlBeta?: AnthropicCompat["extendedCacheTtlBeta"]; /** Disabled-thinking wire form; undefined keeps the direct-provider behavior. */ disabledThinking?: AnthropicCompat["disabledThinking"]; /** Effort pinned on `between_tools` turns; undefined leaves effort untouched. */ betweenToolsEffort?: AnthropicCompat["betweenToolsEffort"]; /** Strip thinking history on non-thinking-led and disabled-thinking turns; undefined behaves as false. */ stripThinkingHistory?: AnthropicCompat["stripThinkingHistory"]; /** Fast-mode SKU; undefined behaves as false. */ fastMode?: AnthropicCompat["fastMode"]; /** * Largest width or height a single image block may carry. Undefined defers * to the canonical Anthropic API limit applied by the request builder. */ maxImageDimension?: number; /** * Largest base64 image payload a single block may carry, in bytes. * Undefined defers to the canonical Anthropic API limit applied by the * request builder. */ maxImagePayloadBytes?: number; /** * Bedrock's Anthropic Messages API (see {@link AnthropicCompat.bedrockMessagesApi}). * `true` when detected or configured; otherwise unset, so rows baked before * this field keep matching. */ bedrockMessagesApi?: boolean; /** * Stream-watchdog idle-timeout fallback in ms for slow reasoning hosts; 0 disables the idle watchdog. * Undefined defers to `PI_STREAM_IDLE_TIMEOUT_MS`, then the legacy * `PI_OPENAI_STREAM_IDLE_TIMEOUT_MS` alias, then 300s. */ streamIdleTimeoutMs?: number; /** * The configured endpoint is the official first-party Anthropic API * (https + exact `api.anthropic.com` host; a missing baseUrl counts as * official because dispatch defaults there). Gates OAuth framing, custom * env headers, and cache-TTL shaping without per-request URL parsing. */ officialEndpoint: boolean; /** * The model is served by the first-party Anthropic provider. Unlike * `officialEndpoint` (URL-derived per deployment), this is provider * identity for compaction gating, always paired with a per-request * effective-URL check. */ firstPartyProvider: boolean; }; /** * Compatibility settings for the devin-agent (Codeium Cascade) API. Cascade * selects reasoning effort only by routing to a sibling model id (the * `thinking.effortRouting` baked by the compat collapse engine), never by a wire * reasoning/effort field, so the model-thinking deriver must not invent an * effort ladder from identity for these models. */ export interface DevinCompat { /** * Trust only explicit `thinking` metadata; never derive a thinking surface * from model identity. A reasoning model with no explicit routed thinking * resolves to `thinking: undefined` (`reasoning: true`, no controllable * effort) instead of a fabricated minimal/low/medium/high ladder. */ trustExplicitThinkingOnly?: boolean; /** * Server-side router model. Providers must resolve the router through * `AssignModel` and send the returned assignment JWT with the chat request. */ modelRouter?: boolean; /** Whether the upstream model supports native parallel tool calls. */ supportsParallelToolCalls?: boolean; /** See {@link BedrockCompat.supportsSamplingParams}. */ supportsSamplingParams?: boolean; } /** Fully-resolved devin-agent compat view. */ export type ResolvedDevinCompat = Required> & Pick; /** * Compatibility settings for the Google API family (google-generative-ai, * google-vertex, google-gemini-cli). Class-driven defaults come from the * compat cascade; sparse overrides follow the same shape. */ export interface GoogleCompat { /** Whether functionCall/functionResponse parts carry the `id` field. */ supportsFunctionPartId?: boolean; /** Add the bypass sentinel to every unsigned Gemini function call. */ requiresSkipThoughtSignature?: boolean; /** Add the bypass sentinel when a Gemini turn's first function call is unsigned. */ requiresSkipThoughtSignatureOnFirstFunctionCall?: boolean; /** * Send the bypass sentinel base64-encoded. For gateways that decode * `thoughtSignature` as bytes and reject the raw literal. */ base64SkipThoughtSignature?: boolean; /** Drop unsigned thinking blocks from replayed history (Antigravity Claude). */ dropUnsignedThinking?: boolean; /** Cloud Code Assist legacy `parameters` schema field instead of `parametersJsonSchema`. */ ccaLegacyParametersSchema?: boolean; /** Whether multimodal (non-text) functionResponse parts are accepted (Gemini 3+). */ multimodalFunctionResponse?: boolean; /** Stream-watchdog first-event timeout in ms; 0 disables it. */ streamFirstEventTimeoutMs?: number; /** Stream-watchdog idle-timeout floor in ms. */ streamIdleTimeoutMs?: number; /** Work around the Flash streaming leak (duplicate first chunk) on gemini-cli. */ flashStreamLeakWorkaround?: boolean; /** Send the Claude thinking beta header on Antigravity Claude requests. */ claudeThinkingBetaHeader?: boolean; /** Antigravity Claude tool-mode request framing. */ antigravityClaudeToolMode?: boolean; /** Usage-label bucket Antigravity reports this model under. */ antigravityUsageLabel?: string; /** Strip image inputs before encoding (text-only serving of a multimodal id). */ stripImageInput?: boolean; /** * Largest width or height a single image may carry for a Claude reader on * this host (see {@link AnthropicCompat.maxImageDimension}). Setting this or * {@link maxImagePayloadBytes} turns on Claude's image clamp, many-image * cap included; unset leaves images as sent. */ maxImageDimension?: number; /** * Largest base64 payload a single image may carry, in bytes (see * {@link AnthropicCompat.maxImagePayloadBytes}). */ maxImagePayloadBytes?: number; /** See {@link BedrockCompat.supportsSamplingParams}. */ supportsSamplingParams?: boolean; } /** Fully-resolved google-API compat view, materialized once by `buildModel`. */ export type ResolvedGoogleCompat = Required> & { streamFirstEventTimeoutMs?: number; streamIdleTimeoutMs?: number; antigravityUsageLabel?: string; supportsSamplingParams?: boolean; base64SkipThoughtSignature?: boolean; maxImageDimension?: number; maxImagePayloadBytes?: number; }; /** Ollama chat history compatibility resolved by the catalog. */ export interface OllamaCompat { /** Omit assistant thinking when the deployment rejects it in history. */ stripThinkingHistory?: boolean; } export type ResolvedOllamaCompat = Required; /** Sparse, user-authored compat overrides for a given API (models.json / config vocabulary). */ export type CompatConfigOf = TApi extends "openai-completions" | "openrouter" | "openai-responses" | "azure-openai-responses" | "openai-codex-responses" ? OpenAICompat : TApi extends "anthropic-messages" ? AnthropicCompat : TApi extends "bedrock-converse-stream" ? BedrockCompat : TApi extends "devin-agent" ? DevinCompat : TApi extends "google-generative-ai" | "google-vertex" | "google-gemini-cli" ? GoogleCompat : TApi extends "ollama-chat" ? OllamaCompat : undefined; /** Resolved compat for a given API: complete record, materialized once by `buildModel`. */ export type CompatOf = TApi extends "openrouter" ? ResolvedOpenRouterCompat : TApi extends "openai-completions" ? ResolvedOpenAICompat : TApi extends "openai-responses" | "azure-openai-responses" | "openai-codex-responses" ? ResolvedOpenAIResponsesCompat : TApi extends "anthropic-messages" ? ResolvedAnthropicCompat : TApi extends "bedrock-converse-stream" ? ResolvedBedrockCompat : TApi extends "devin-agent" ? ResolvedDevinCompat : TApi extends "google-generative-ai" | "google-vertex" | "google-gemini-cli" ? ResolvedGoogleCompat : TApi extends "ollama-chat" ? ResolvedOllamaCompat : undefined; /** Provider-native compaction endpoint configuration for one model. */ export interface RemoteCompactionConfig { /** Enables provider-native compaction for providers not enabled by built-in policy. */ enabled?: boolean; /** Adapter family used by the configured compaction endpoint. */ api?: TApi; /** Absolute V1 compact endpoint URL; when omitted, the adapter derives it from the model base URL. */ endpoint?: string; /** Enables Responses-stream V2 compaction for models verified to support `compaction_trigger`. */ v2StreamingEnabled?: boolean; /** Absolute Responses-stream endpoint URL for V2 compaction; overrides `streamingEndpoint`. */ v2Endpoint?: string; /** Absolute provider streaming endpoint URL used by V2 compaction when no dedicated endpoint is set. */ streamingEndpoint?: string; /** Model id sent to the compaction endpoint when it differs from the active model id. */ model?: string; } /** Per-million-token rates for one model pricing tier. */ export interface TokenCost { input: number; output: number; cacheRead: number; cacheWrite: number; } /** User-facing interpretation of a model's token-rate card. */ export type ModelPricingStatus = "fixed" | "free" | "included" | "variable" | "unknown"; /** * Rates applied to the full request when its prompt exceeds `inputThreshold`, * or reaches it when `inputThresholdInclusive` is true. Prompt input is the * sum of uncached, cached-read, cache-write, and provider-orchestration input * tokens. */ export interface LongContextTokenCost extends TokenCost { inputThreshold: number; /** Whether the long-context tier starts exactly at `inputThreshold`. */ inputThresholdInclusive?: boolean; } /** Recurring UTC peak interval; weekdays use Sunday = 0, and the end is exclusive. */ export interface PeakPricingWindow { weekdays: readonly number[]; startMinute: number; endMinute: number; } /** Complete replacement rate card effective from a Unix-millisecond timestamp. */ export interface EffectiveTokenCost extends TokenCost { effectiveFrom: number; longContext?: LongContextTokenCost; } /** Scheduled discounts applied after selecting the effective rate card and context tier. */ export interface TimeBasedCost { offPeakMultiplier: number; peakWindows: readonly PeakPricingWindow[]; effectiveRates?: readonly EffectiveTokenCost[]; } /** * Best-effort prompt-cache entry lifetime in seconds for each retention tier a * request can ask for. A missing tier means the lifetime is unknown; consumers * must not schedule cache warming against unknown lifetimes. */ export type ModelPromptCache = Partial>; /** Base token rates plus optional long-context and time-based pricing. */ export interface ModelCost extends TokenCost { longContext?: LongContextTokenCost; timeBased?: TimeBasedCost; } /** * Exact local content tokenizer family for a model. * * Absent means no first-party local tokenizer is known and consumers count * in o200k_base. The values name tokenizer * generations rather than providers: DeepSeek V3 through V4 share * `"deepseek-v3"`; Kimi K2 through K3 share `"kimi-k2"`. */ export type ModelTokenizer = "claude-v3" | "claude-v47" | "claude-v5" | "claude-v5-sonnet" | "qwen3" | "deepseek-v3" | "kimi-k2" | "glm5" | "cl100k" | "o200k"; /** One account's discovered entitlements on a model; see {@link Model.accountAccess}. */ export interface ModelAccountAccess { /** * Codex `available_access_programs.cyber`: cyber access programs this account * may request on the model (`standard`, `daybreak_blue`, `daybreak_red`). * Absent when the backend reported no program metadata. */ cyberPrograms?: readonly string[]; /** * Antigravity request constants this account's `fetchAvailableModels` * roster advertised, keyed by upstream SKU id. Takes precedence over * {@link Model.antigravityWireProfiles}, which keeps only the first * account's values when multi-account rosters are unioned. */ antigravityWireProfiles?: Readonly>; } /** One Cursor `RequestedModel.parameters` entry recovered from rich discovery. */ export interface CursorModelParameter { id: string; value: string; } /** Cursor wire target selected after local effort/variant routing. */ export interface CursorModelRoute { modelId: string; parameters: readonly CursorModelParameter[]; maxMode?: boolean; } /** * Antigravity Cloud Code Assist request constants for one upstream SKU, as the * native client sends them; see {@link Model.antigravityWireProfiles}. */ export interface AntigravityModelWireProfile { /** Opaque `labels.model_enum` token (`fetchAvailableModels` `model`). */ modelEnum?: string; /** Fixed `generationConfig.maxOutputTokens` the client always sends. */ maxOutputTokens?: number; /** SKU thinking level; the native client sends it in preference to a budget. */ thinkingLevel?: "LOW" | "MEDIUM" | "HIGH"; /** SKU thinking budget (`-1` is dynamic), sent when no level is advertised. */ thinkingBudget?: number; } export interface Model { id: string; /** Role-specific runner capability; omitted for ordinary chat models. */ kind?: ModelKind; /** * Verbatim configured kind (models.yml, `modelOverrides`, runtime * registrations). `buildModel` applies it over catalog `kind` rules on every * rebuild, so a configured runner keeps its role. */ kindConfig?: ModelKind; /** Grounding transport supported by this chat model. */ webSearch?: WebSearchGrounding; /** Cheaper same-provider model to run hosted web search in this model's place (model id or provider/id). */ webSearchModel?: string; /** Whether this chat model can carry the Responses `image_generation` tool itself. */ hostedImage?: boolean; /** Same-provider image model to generate images in this model's place (model id or provider/id). */ imageModel?: string; /** * Structured model identity resolved by the compat engine: vendor lineage * class, product family, and revision. Baked into models.json rows and * materialized by `buildModel` for discovered/custom specs. */ identity: ModelIdentity; /** * Whether provider-bound private-use glyphs require reversible ASCII tokenization. * Materialized by `buildModel`; request handlers read this capability instead of * inferring it from the transport API. */ requiresGlyphTokenization?: boolean; /** Whether this model requires Cursor's tool-schema combiner projection. */ requiresCursorToolSchemaProjection?: boolean; /** Whether advertised tool schemas occupy every model request's context (false for deferred catalogs). */ toolSchemasInContext?: boolean; /** Whether this model requires tool-result images hoisted into sibling user content blocks. */ requiresToolResultImageHoisting?: boolean; /** * Whether the host continues a trailing assistant message verbatim instead of * treating it as a completed turn (Ollama, on both its native and OpenAI-compat * endpoints). Callers that need a committed output prefix (session titling) * read this before appending one. Rule-owned via `supports-assistant-prefill`. */ supportsAssistantPrefill?: boolean; /** * Model id to send on the wire when it differs from `id`. Used by catalog * variants that present one upstream model under several local entries — * e.g. GitHub Copilot long-context variants (`claude-opus-4.7-1m` requests * upstream `claude-opus-4.7`; the tier is a client-side context budget, not * a served model id). Providers MUST serialize `requestModelId ?? id`; * everything local (selection, caching, usage attribution) keys on `id`. */ requestModelId?: string; /** * `reasoning.mode` to send on OpenAI Responses-family requests. Set on * generated pro aliases (`gpt-5.6-*-pro` on `openai`/`openai-codex`) that * pair a base wire id (`requestModelId`) with OpenAI's pro reasoning * serving path. Absent everywhere else; providers omit the wire field. */ reasoningMode?: "pro"; name: string; api: TApi; provider: Provider; /** * Discovery backend whose catalog policy applies when it differs from the * credential-bearing provider id. Persisted so cached and rebuilt custom * providers retain their transport backend's policy. */ providerType?: string; baseUrl: string; reasoning: boolean; /** * Exact local tokenizer family resolved from the model identity or supplied * explicitly by a catalog/discovery source. Absent leaves local counting to * the consumer's fallback policy. */ tokenizer?: ModelTokenizer; input: ("text" | "image")[]; /** * Decoder family used for image inputs when it has narrower format support * than OMP's general image pipeline. `stb` local backends reject WebP. */ imageInputDecoder?: "stb"; /** * Most images one request may carry, from user configuration. Replaces the * catalog's `image-count-budget` for hosts no rule names, such as a custom * gateway in front of a vendor with a higher limit. */ imageCountBudget?: number; /** * Native provider tool-call support. `false` is the only unsupported signal: * `true` and `undefined` both mean callers may use native tools. Catalog and * discovery sources should set this sparsely when an upstream explicitly * reports that native tool calling is unsupported. */ supportsTools?: boolean; /** Whether this model accepts the GA OpenAI Responses `{ type: "computer" }` native tool. */ supportsComputerUse?: boolean; /** Verbatim explicit computer-use support from the spec; undefined when `buildModel` inferred the runtime value. */ supportsComputerUseConfig?: boolean; /** GitLab Duo Workflow root namespace selected during catalog discovery. */ gitlabDuoWorkflowRootNamespaceId?: string; /** Cursor `max_mode` request flag returned by `GetUsableModels` for premium models that require max mode. */ cursorMaxMode?: boolean; /** * Per-wire-id `max_mode` markers for the members a collapsed Cursor row * routes to, recorded by `collapseVariants` from live `GetUsableModels` * rows. {@link cursorMaxMode} on a collapsed row is an OR across members, * so it cannot tell a `-low` route that needs no max mode from an Opus * `-fast` route that does; transports look the routed wire id up here * first. Absent on raw rows (their own `cursorMaxMode` already describes * their single wire id) and on bundled snapshots that predate discovery. */ cursorMaxModeRoutes?: Readonly>; /** * Per-wire-id Antigravity request constants recorded from the account's * `fetchAvailableModels` roster, keyed by upstream SKU id. A collapsed row * carries one entry per member it routes to; a raw row carries its own. * Absent on bundled snapshots that predate discovery. */ antigravityWireProfiles?: Readonly>; /** * Per-account availability recorded by multi-account discovery: provider * account key (Codex: ChatGPT `chatgpt_account_id`; Antigravity: login * email) → that account's entitlements on this model. An account appears * only when its own catalog lists the model, so credential selection can * route account-gated models (e.g. `gpt-daybreak-blue-latest`, Antigravity * Claude 5.5) straight to eligible accounts. Absent on bundled/config rows. */ accountAccess?: Readonly>; /** Cursor `RequestedModel.parameters` for this model's default variant. */ cursorModelParameters?: readonly CursorModelParameter[]; /** * Per-wire-id Cursor routes recovered from `AvailableModels`. Generic effort * collapse retains these while routing selects one key at request time. */ cursorModelRoutes?: Readonly>; /** Cursor's account-relative model price/multiplier; not a per-token USD rate. */ cursorPrice?: number; /** Cursor requires data retention to invoke this model. */ cursorRequiresDataRetention?: boolean; /** Cursor explicitly reports support for its Agent surface. */ cursorSupportsAgent?: boolean; /** Cursor explicitly reports support for sandboxed execution. */ cursorSupportsSandboxing?: boolean; /** Factory Droid: account-resolved upstream rotation (first entry is the default `x-api-provider`). */ factoryDroidApiProviders?: string[]; /** Factory Droid: `configured_order` when live routing chose the rotation; absent means registry order. */ factoryDroidRoutingSource?: "configured_order"; /** Factory Droid: server-side refusal fallbacks the account can run; absent when none are named. */ factoryDroidRefusalFallbacks?: string[]; /** Factory Droid Standard Credits base rate (relative per-token weight, not dollars). */ factoryDroidCredits?: number; /** Factory Droid dated `credit-rates` cards, ascending; `getFactoryDroidCreditRate` picks the one due now. */ factoryDroidCreditCards?: readonly DatedCostCard[]; /** Canonical organization resolved during Factory discovery. */ factoryDroidOrgId?: string; cost: ModelCost; /** * Prompt-cache entry lifetime per retention tier, in seconds. Populated only * for providers whose cache-expiry and replay behavior has been validated * for cache warming (direct Anthropic: 5m / 1h). A missing entry means the * provider's cache behavior is unknown — such models are never warmed. * Custom models and provider overrides opt in via models.yml `promptCache`. */ promptCache?: ModelPromptCache; /** * Verbatim configured lifetimes (models.yml, `modelOverrides`, runtime * registrations). `buildModel` applies them over catalog `prompt-cache` * rules on every rebuild; `{}` keeps warming disabled. */ promptCacheConfig?: ModelPromptCache; /** * Interpretation of an all-zero token-rate card. Omitted zero-rate cards * are unknown; any non-zero rate is always treated as fixed pricing. */ pricingStatus?: Exclude; /** Premium Copilot requests charged per user-initiated request (defaults to 1). */ premiumMultiplier?: number; contextWindow: number | null; /** Preserve the host's supplied window instead of applying inferred expansion or reference-price caps. */ contextWindowAuthoritative?: boolean; /** The long-context price tier does not cap the runtime context window when extended context is off. */ longContextWindowUncapped?: boolean; /** Optional larger prompt window available when extended context is enabled. */ maxContextWindow?: number; maxTokens: number | null; /** * When `true`, providers MUST omit `max_output_tokens` (Responses) / * `max_tokens` / `max_completion_tokens` (Completions) from the outbound * request and let the upstream API decide the per-response cap. `maxTokens` * is still used locally for budgeting (compaction, context promotion); only * the wire field is suppressed. * * Use this for proxies (notably Ollama) that forward to a backend whose true * output limit OMP cannot discover — sending the wrong value triggers 400s * from the upstream provider. */ omitMaxOutputTokens?: boolean; headers?: Record; /** * Materialize config-backed headers immediately before a request. Catalog * inspection never invokes this hook; transports receive a cloned model * whose `headers` is a plain resolved record and whose hook is removed. */ resolveHeaders?: (signal?: AbortSignal) => Promise | undefined>; /** * Streaming transport override. When `"pi-native"`, `streamSimple` routes * the request to the model's `baseUrl` via the auth-gateway's * `POST /v1/pi/stream` endpoint instead of dispatching the per-API * provider client. The `baseUrl` must point at an `omp auth-gateway` * (or compatible) host; `headers.Authorization` (or `apiKey` resolved by * the registry) carries the gateway bearer. * * Used by containerized omp installs (e.g. robomp slots) to route every * LLM call through a sidecar gateway that holds the real provider * credentials. The model's other metadata (pricing, context window, * thinking config, …) still resolves locally; only the streaming * dispatch is redirected. */ transport?: "pi-native"; /** Standard Responses is opt-in and catalog-gated; either model/request false vetoes true. Codex keeps its independent policy. */ preferWebsockets?: boolean; /** Codex Responses Lite transport: send the lite marker and carry instructions/tools as input items (mirrors codex-rs `use_responses_lite`). */ useResponsesLite?: boolean; /** * Service-tier ids the provider advertises for this model (Codex discovery * `service_tiers[].id`, or an OpenAI-compatible `/v1/models` row's * `service_tiers`, e.g. `priority`, `ultrafast`). Absent when the provider * publishes no per-model tier list. */ serviceTiers?: readonly string[]; /** Preferred model to switch to when context promotion is triggered (model id or provider/id). */ contextPromotionTarget?: string; /** Preferred model to use only for compaction (model id or provider/id); the active session model is unchanged. */ compactionModel?: string; /** Provider-native compaction endpoint configuration. */ remoteCompaction?: RemoteCompactionConfig; /** Provider-assigned priority value (lower = higher priority). */ priority?: number; /** * Per-service-tier cost multipliers baked from the `service-tier-cost` * catalog axis (e.g. `{ priority: 2.5 }`). Absent tiers use the API-generic * defaults, and a tier with no published price stays at 1x. */ serviceTierCost?: Readonly>>; /** * Provider-supplied one-line blurb for this model. Set only when an upstream * ships one (Devin's `GetCliModelConfigs`); never synthesized locally. */ description?: string; /** Upstream marks this model as newly released. */ isNew?: boolean; /** Upstream marks this model as beta / preview quality. */ isBeta?: boolean; /** Authenticated catalog marks this as the account's default; the startup pick prefers it over `default-model`. */ isProviderDefault?: boolean; /** Upstream marks this model as one of its recommended picks. */ isRecommended?: boolean; /** Canonical thinking capability metadata for this model. */ thinking?: ThinkingConfig; /** Intelligence score delivered by the model catalog. */ int?: number | null; /** Catalog-estimated output speed in tokens per second. */ tps?: number | null; /** * Fully-resolved compatibility record, materialized once by `buildModel`. * Protocol handlers read fields; they never detect, resolve, or allocate. */ compat: CompatOf; /** Verbatim sparse compat from the spec (user/config intent), for introspection only. */ compatConfig?: CompatConfigOf; /** * Which shape to use when exposing the Codex `apply_patch` tool to this model. * Generated catalog policy sets `"freeform"` for first-party GPT-5 Responses * models that support OpenAI custom tools with a Lark grammar. The freeform * variant sends a raw patch string with no JSON envelope. * - `"function"` or undefined: JSON function-tool with `{input: string}` (spec §1.2). */ applyPatchToolType?: "freeform" | "function"; /** * Edit-tool description density for this model. `"compact"` selects the * terse mode prompt (all operations and invariants preserved) for hosts * where per-request prompt bytes are the dominant cost. Generated catalog * policy sets it; the edit tool falls back to the full prompt when unset. */ editPromptVariant?: "full" | "compact"; /** * Force OAuth-style request shaping for providers whose API key prefix doesn't * match an OAuth token (e.g. routing Anthropic traffic through a proxy that * expects Claude Code framing). When true, the streaming layer sets * `options.isOAuth = true` for the underlying provider call. */ isOAuth?: boolean; /** * Amazon Bedrock Guardrail id or ARN attached to every Converse request for * this model. Set from `providers.amazon-bedrock.guardrailIdentifier`; the * streaming layer forwards it as `options.guardrailIdentifier` so accounts * that gate `bedrock:InvokeModel*` on the `bedrock:GuardrailIdentifier` * condition key stop returning an explicit deny. */ guardrailIdentifier?: string; /** Bedrock guardrail version. Defaults to `"DRAFT"` at request time when unset. */ guardrailVersion?: string; /** Bedrock guardrail trace verbosity. */ guardrailTrace?: "enabled" | "disabled" | "enabled_full"; /** * Bedrock invocation-log tags attached to every Converse request for this * model. Set from `providers..requestMetadata`; the Bedrock * transport reads it directly and validates it against AWS's limits. */ requestMetadata?: Record; } /** * A model as authored by configs, bundled catalogs, and discovery — the input * vocabulary of `buildModel`. Identical to `Model` except `compat` carries the * sparse override shape and nothing is resolved yet. */ export interface ModelSpec extends Omit, "compat" | "identity" | "compatConfig" | "requiresGlyphTokenization" | "requiresCursorToolSchemaProjection" | "toolSchemasInContext" | "requiresToolResultImageHoisting" | "supportsAssistantPrefill" | "supportsComputerUseConfig"> { /** Sparse compatibility overrides; resolved into `Model.compat` by `buildModel`. */ compat?: CompatConfigOf; } /** * The model facts the catalog policy cascade reads: the resolve-target inputs * (`providerType ?? provider`, the request adapter, the wire model id, the * reasoning flag) plus the unverified-thinking correction applied before the * cascade. Callers holding a reduced model view — request adapters that only * need policy — supply exactly these instead of asserting a full `Model`. */ export type CatalogPolicyInputs = Pick, "provider" | "providerType" | "api" | "id" | "reasoning" | "requestModelId" | "thinking">;