vern-llm 2.4.0 → 2.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +10 -4923
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +189 -51
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +189 -51
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -4838
- package/dist/index.js.map +1 -1
- package/package.json +14 -6
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["NON_RETRYABLE_TOOL_CONTRACT_CODES: ReadonlySet<LLMErrorCode>","LOCAL_RATE_LIMIT_CODES: ReadonlySet<LLMErrorCode>","NON_RETRYABLE_TYPES: ReadonlySet<LLMErrorType>","type: LLMErrorType","code: LLMErrorCode | undefined","issues: unknown","body: unknown","headers: Record<string, string> | undefined","out: Record<string, string>","attempts: RetryAttempt[] | undefined","provider: string","model: string","headers?: Record<string, string>","startedAt: number","message: string","options: LLMErrorOptions","err: unknown","err: LLMError","code: C","key: string","value: T","ttl: number","inner: CacheAdapter<T>","l1: CacheAdapter<T>","l2: CacheAdapter<T>","l1Ttl?: number","result: unknown","defaultFallbackOn: FallbackOn","attempts: FallbackAttempt[]","err: unknown","params: UsageHooks","coalesced: boolean","signal: AbortSignal | undefined","onRefundError: (logMessage: string, error: unknown) => void","logMessage: string","getResult: () => Promise<T>","result: T","openStream: () => Promise<{ chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> }>","opened: { chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> }","value: unknown","value: T | CallWithToolsResult<T>","hasTools: boolean","items: StreamChunk[]","promise: Promise<T | CallWithToolsResult<T>>","cache: CacheAdapter<unknown>","logger: Logger","key: string","logMessage: string","error: unknown","params: InternalCacheParams<T>","params: InternalCacheStreamParams<T>","hasTools: boolean","resolveInFlight!: (value: T) => void","rejectInFlight!: (error: unknown) => void","trackedResult: Promise<T>","options: CircuitBreakerOptions","model: string | undefined","bucket: CircuitBucket","to: CircuitState","model?: string","onEvent: ((event: VernLLMEvent) => void) | undefined","logger: Logger","circuitBreakerOption: boolean | CircuitBreakerOptions | undefined","providerName: string","defaultModel: string","ms: number | undefined","ms: number","fn: (signal: AbortSignal) => Promise<T>","timeoutMs: number","externalSignal?: AbortSignal","next: () => Promise<IteratorResult<T>>","timeoutMs: number | undefined","onIdle?: () => void","logger?: Pick<Logger, 'debug'>","error: unknown","err: unknown","baseDelayMs: number","attempt: number","delay: number","signal?: AbortSignal","err: unknown","error: unknown","value: unknown","status: number","value: object","signal?: AbortSignal","attempts?: RetryAttempt[]","content: string","tools: ToolDefinition[]","toolCalls: ToolCall[]","wireToolCalls: WireToolCall[]","parsedArgs: unknown","content: AssistantContent","options: RequestBuilderOptions","params: CallParams<T>","history: ConversationTurn[]","previousTurn: ConversationTurn | undefined","toolChoice: CallParams<unknown>['toolChoice']","turn: ConversationTurn","jsonSchema: CallParams<unknown>['jsonSchema']","useJson: boolean","iterator: AsyncIterator<WireStreamChunk>","first: IteratorResult<WireStreamChunk>","options: StreamAccumulatorOptions<T>","resolveFinal!: (value: T | CallWithToolsResult<T>) => void","rejectFinal!: (error: unknown) => void","buffered: StreamChunk[]","pending: Array<{\n resolve: (result: IteratorResult<StreamChunk>) => void;\n reject: (error: unknown) => void;\n }>","streamError: unknown","chunk: StreamChunk","error: unknown","chunks: AsyncIterable<StreamChunk>","usage: TokenUsage | undefined","result: IteratorResult<WireStreamChunk>","wireToolCalls: WireToolCall[] | undefined","snapshot: LLMRequestSnapshot | undefined","providerName: string","client: LLMClient","model: string","options: CallExecutorOptions","model?: string","params: CallParams<T>","requestId: string","onAttempt?: () => void","attempts: RetryAttempt[]","attempt: number","onRequest?: OnRequest","release: ((actualTokens?: number) => void) | undefined","text: string","content: string | undefined","wireToolCalls: WireToolCall[] | undefined","rawContent: string | null | undefined","useJson: boolean","usage: TokenUsage | undefined","toolCalls: { id: string; name: string; arguments: unknown }[]","tools: NonNullable<CallParams<unknown>['tools']>","toolIssues: ToolIssue[]","fn: (attempt: number, onRequest: OnRequest) => Promise<T>","signal?: AbortSignal","attempts?: RetryAttempt[]","lastError: unknown","lastRequestForAttempt: LLMRequestSnapshot | undefined","response: Awaited<ReturnType<LLMClient['chat']['completions']['create']>>","usage: TokenUsage","error: LLMError","content: string","schema?: CallParams<T>['schema']","parsed: unknown","error: unknown","logger: Logger","method: M","value: unknown","result: unknown","debugEnabled: boolean","message: string","meta?: Record<string, unknown>","request: WireRequest","capacity: number","refillPerMs: number","amount: number","options: RateLimitOptions","estimatedTokens: number","signal?: AbortSignal","initialReason: RateLimitReason | undefined","waiter: Waiter","queueTimer: ReturnType<typeof setTimeout> | undefined","taken: Array<{ bucket: TokenBucket; amount: number }>","bucket: TokenBucket | undefined","reason: RateLimitReason","actualTokens?: number","options: VernLLMOptions","primaryTarget: FallbackTarget","declaredFallbacks: FallbackTarget[]","logMessage: string","error: unknown","params: Pick<CallParams<unknown>, 'model' | 'signal'>","requestId: string","attempt: (executor: CallExecutor, onAttempt: () => void) => Promise<R>","attempts: FallbackAttempt[]","params: CallParams<T>","params: InternalCacheParams<T>","key: string","params:\n | CachedCallParams<T>\n | CachedToolCallParams<T>\n | CachedConditionalToolCallParams<T>\n | CachedStreamCallParams<T>\n | CachedStreamToolCallParams<T>\n | CachedStreamConditionalToolCallParams<T>\n | CachedJsonModeDisabledCallParams\n | CachedJsonModeEnabledCallParams\n | CachedStreamJsonModeDisabledCallParams\n | CachedStreamJsonModeEnabledCallParams","target?: CircuitTarget","model?: string","index: number","caller: string","isolateByModel: boolean","model: string | undefined","params: P","source: AsyncIterable<Uint8Array | string>","text: string","boundary","frame: string","dataLines: string[]","mimeType: string","model: string","override?: ModelCapabilityOverride","DEFAULT_EFFORT_TOKENS: EffortTokenTable","override?: Partial<EffortTokenTable>","effort: 'minimal' | 'low' | 'medium' | 'high'","table: EffortTokenTable","budgetTokens: number","model: string","override?: ModelCapabilityOverride","maxTokens: number","forcedChoiceDescription: string | undefined","level: GeminiThinkingLevel","blocks: ContentBlock[]","schema: Record<string, unknown>","toolName: string","toolChoice: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice']","tools: NonNullable<Parameters<LLMClient['chat']['completions']['create']>[0]['tools']>","toolChoiceParam: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice']","params: Parameters<LLMClient['chat']['completions']['create']>[0]","nativeStructuredOutputModels?: ModelCapabilityOverride","effortTokenTable?: EffortTokenTable","adaptiveOnlyModels?: ModelCapabilityOverride","toolName: string | undefined","outputFormat: NonNullable<AnthropicRequestBody['output_config']>['format'] | undefined","tools: NonNullable<Parameters<AnthropicClient['messages']['create']>[0]['tools']> | undefined","toolChoice: Parameters<AnthropicClient['messages']['create']>[0]['tool_choice']","thinking: AnthropicRequestBody['thinking']","effort: ClaudeAdaptiveEffort | undefined","body: AnthropicRequestBody","anthropicClient: AnthropicClient","options?: AnthropicAdapterOptions","options","text: string","wireToolCalls: WireToolCall[] | undefined","mergeConsecutiveToolResults","messages: { role: 'user' | 'assistant'; content: string | AnthropicContentBlock[] }[]","m: (typeof messages)[number]","merged: (typeof messages)[number][]","m: Extract<\n Parameters<LLMClient['chat']['completions']['create']>[0]['messages'][number],\n { role: 'user' | 'assistant' | 'tool' }\n >","blocks: AnthropicContentBlock[]","input: unknown","blocks: ContentBlock[]","toolChoice: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice']","m: Extract<\n Parameters<LLMClient['chat']['completions']['create']>[0]['messages'][number],\n { role: 'user' | 'assistant' | 'tool' }\n >","parts: GeminiPart[]","text: string","toolName: string","parsed: unknown","contents: { role: 'user' | 'model'; parts: GeminiPart[] }[]","c: (typeof contents)[number]","merged: (typeof contents)[number][]","params: Parameters<LLMClient['chat']['completions']['create']>[0]","effortTokenTable?: EffortTokenTable","thinkingLevelModels?: ModelCapabilityOverride","config: GeminiConfig","client: GeminiClient","options?: GeminiAdapterOptions","options","wireToolCalls: WireToolCall[] | undefined","lastUsage:\n | NonNullable<\n Awaited<ReturnType<NonNullable<GeminiClient['generateContent']>>>['usageMetadata']\n >\n | undefined","model: string","mimeType: string","data: string","blocks: ContentBlock[]","tools: NonNullable<Parameters<LLMClient['chat']['completions']['create']>[0]['tools']>","toolChoiceParam: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice']","params: Parameters<LLMClient['chat']['completions']['create']>[0]","toolUseSupportedModels: BedrockAdapterOptions['toolUseSupportedModels']","nativeStructuredOutputModels: BedrockAdapterOptions['nativeStructuredOutputModels']","effortTokenTable?: EffortTokenTable","adaptiveOnlyModels?: ModelCapabilityOverride","toolName: string | undefined","toolConfig: NonNullable<BedrockRequest['toolConfig']> | undefined","outputConfig: NonNullable<BedrockRequest['outputConfig']> | undefined","additionalModelRequestFields: BedrockRequest['additionalModelRequestFields']","effort: ClaudeAdaptiveEffort | undefined","request: BedrockRequest","client: BedrockConverseClient | AwsSendClient","raw: RawBedrockStreamEvent","rawStream: AsyncIterable<RawBedrockStreamEvent>","client: AwsSendClient","commandsPromise: Promise<BedrockRuntimeCommands> | undefined","bedrockClient: BedrockConverseClient | AwsSendClient","options?: BedrockAdapterOptions","client: BedrockConverseClient","text: string","wireToolCalls: WireToolCall[] | undefined","toolChoice: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice']","m: Extract<\n Parameters<LLMClient['chat']['completions']['create']>[0]['messages'][number],\n { role: 'user' | 'assistant' | 'tool' }\n >","blocks: BedrockContentBlock[]","input: unknown","messages: { role: 'user' | 'assistant'; content: BedrockContentBlock[] }[]","m: (typeof messages)[number]","merged: (typeof messages)[number][]","stream: ReadableStream<Uint8Array>","url: string","init: { method: string; headers: Record<string, string>; body?: string; signal?: AbortSignal }","config: FetchAdapterConfig","params: ChatRequest","requestBody: unknown","wireToolCalls: WireToolCall[] | undefined","params: P","effortTokenTable?: EffortTokenTable","blocks: ContentBlock[]","params: Parameters<LLMClient['chat']['completions']['create']>[0]","chunk: OpenAIStreamChunk","client: unknown","options: OpenAICompatibleAdapterOptions","options"],"sources":["../src/types/errors.ts","../src/types/cache.ts","../src/types/tools.ts","../src/types/fallback.ts","../src/internal/execution/usage.utils.ts","../src/internal/cache/replay.utils.ts","../src/internal/cache/cacheOrchestrator.ts","../src/circuitBreaker.ts","../src/internal/circuitBreaker.utils.ts","../src/internal/execution/retry.utils.ts","../src/internal/execution/errors.utils.ts","../src/internal/execution/parse.utils.ts","../src/internal/execution/wire.utils.ts","../src/internal/execution/requestBuilder.ts","../src/internal/execution/streamAccumulator.ts","../src/internal/execution/callExecutor.ts","../src/internal/logger.utils.ts","../src/logger.ts","../src/rateLimit.ts","../src/vernLLM.ts","../src/adapters/internal/sse.ts","../src/adapters/internal/imageFormat.ts","../src/adapters/internal/nativeStructuredOutput.ts","../src/adapters/internal/reasoningBudget.utils.ts","../src/adapters/anthropic.ts","../src/adapters/gemini.ts","../src/adapters/bedrock.ts","../src/adapters/fetch.ts","../src/adapters/openaiCompatible.ts"],"sourcesContent":["export type LLMErrorType =\n | 'timeout'\n | 'api'\n | 'network'\n | 'parse'\n | 'validation'\n | 'invalid_params'\n | 'rate_limited'\n | 'quota_exceeded'\n | 'circuit_open'\n | 'fallback_exhausted'\n | 'aborted'\n | 'unknown';\n\n/**\n * Machine readable discriminator within a `type`, for cases where `type`\n * alone is too coarse to act on. Optional and additive: errors thrown\n * before a given code existed simply omit it. Not owned by a single type;\n * e.g. `authentication`/`authorization` apply the same way regardless of\n * which type wraps them.\n */\nexport type LLMErrorCode =\n // Tool contract (validation)\n | 'unknown_tool'\n | 'duplicate_tool_call_id'\n | 'tool_choice_none_violated'\n | 'unexpected_tool_calls'\n // Caller input (invalid_params)\n | 'unsupported_capability'\n | 'duplicate_tool_names'\n | 'unknown_tool_choice'\n | 'duplicate_tool_result_ids'\n | 'unknown_tool_result_ids'\n | 'missing_tool_results'\n // Rate limiting (rate_limited)\n | 'rate_limit_queue_full'\n | 'rate_limit_queue_timeout'\n | 'rate_limit_capacity_exceeded'\n | 'provider_rate_limited'\n // Timeouts (timeout)\n | 'request_timeout'\n | 'idle_timeout'\n // HTTP status (api)\n | 'authentication'\n | 'authorization'\n | 'not_found'\n | 'payload_too_large'\n | 'server_error'\n | 'empty_response'\n // Connectivity (network)\n | 'connection_failed'\n // Circuit breaker (circuit_open)\n | 'circuit_cooling_down'\n | 'circuit_trial_in_flight'\n // Fallback (fallback_exhausted)\n | 'fallback_exhausted'\n // Parsing (parse)\n | 'tool_arguments_parse_failed'\n | 'stream_frame_invalid';\n\n/**\n * Tool contract codes: a model or provider response defect, not a\n * transient provider fault. Deterministic on the wire request, so\n * retrying can't change the outcome and it shouldn't count toward the\n * circuit breaker either. Shared by `LLMError.retryable` below and by\n * `CallExecutor`'s own retry/breaker accounting, so the two can't drift\n * apart.\n */\nexport const NON_RETRYABLE_TOOL_CONTRACT_CODES: ReadonlySet<LLMErrorCode> = new Set([\n 'unknown_tool',\n 'duplicate_tool_call_id',\n 'tool_choice_none_violated',\n 'unexpected_tool_calls',\n]);\n\n/**\n * Local rate-limit codes: the call never reached the provider, so it says\n * nothing about the provider's health, and retrying either just requeues\n * behind the same limit (the two queue codes) or can never succeed at all\n * (`rate_limit_capacity_exceeded`). Shared for the same reason as\n * {@link NON_RETRYABLE_TOOL_CONTRACT_CODES}.\n */\nexport const LOCAL_RATE_LIMIT_CODES: ReadonlySet<LLMErrorCode> = new Set([\n 'rate_limit_queue_full',\n 'rate_limit_queue_timeout',\n 'rate_limit_capacity_exceeded',\n]);\n\n/**\n * Types that are never worth retrying on their own: deterministic\n * caller-input, model-response, or cancellation failures rather than a\n * transient provider fault.\n */\nconst NON_RETRYABLE_TYPES: ReadonlySet<LLMErrorType> = new Set([\n 'parse',\n 'validation',\n 'invalid_params',\n 'aborted',\n]);\n\n/**\n * Shared retryability rule behind both `LLMError.retryable` and\n * `LLMErrorSnapshot.retryable`. Pulled out so the two can't drift apart:\n * a snapshot is a point-in-time copy of an error's fields, and this is\n * one of them, so it has to be computed the same way in both places.\n */\nfunction computeRetryable(type: LLMErrorType, code: LLMErrorCode | undefined): boolean {\n if (NON_RETRYABLE_TYPES.has(type)) return false;\n if (code && NON_RETRYABLE_TOOL_CONTRACT_CODES.has(code)) return false;\n if (code && LOCAL_RATE_LIMIT_CODES.has(code)) return false;\n return true;\n}\n\n/**\n * Returns `issues` unchanged when it can survive `JSON.stringify`.\n * Most `issues` values are VernLLM's own structured shapes (see\n * `LLMErrorIssuesByCode`) and always safe. The one exception is a\n * schema validation failure, where `issues` is a caller supplied\n * `SchemaLike` validator's own `error: unknown`, not controlled by\n * VernLLM and not guaranteed to be circular free. Rather than silently\n * dropping it in that case, this returns a marker string so a reader\n * of serialized output can tell \"no issues data\" apart from \"issues\n * existed but could not be shown\".\n */\nfunction safeIssues(issues: unknown): unknown {\n if (issues === undefined) return undefined;\n try {\n JSON.stringify(issues);\n return issues;\n } catch {\n return '[Unserializable: issues contained a circular reference]';\n }\n}\n\n/**\n * Returns a JSON safe, independent copy of `body`, or a marker string if\n * `body` can't survive `JSON.stringify` (e.g. a circular reference). A\n * request body built from adapter-transformed messages is normally\n * always plain data, but tool call arguments or a caller supplied\n * `cause`-adjacent value could in principle carry a circular reference,\n * so this guards the same way `safeIssues` does rather than assuming it\n * can't happen. Unlike `safeIssues`, this clones rather than returning\n * the same reference: the object backing a request body can still be\n * mutated by adapter code between when a request is dispatched and when\n * an attempt is later recorded as failed (e.g. `fromGemini` sets\n * `request.config` in place), so returning the same reference here could\n * make a stored snapshot silently reflect a later, different state than\n * what was actually sent.\n */\nfunction safeBody(body: unknown): unknown {\n if (body === undefined) return undefined;\n try {\n return JSON.parse(JSON.stringify(body)) as unknown;\n } catch {\n return '[Unserializable: request body contained a circular reference]';\n }\n}\n\nconst AUTH_HEADER_NAMES = new Set(['authorization', 'x-api-key', 'x-goog-api-key', 'api-key']);\n\n/** Removes auth headers before a request snapshot is built. Case insensitive on header names. */\nfunction stripAuthHeaders(\n headers: Record<string, string> | undefined,\n): Record<string, string> | undefined {\n if (headers === undefined) return undefined;\n const out: Record<string, string> = {};\n for (const [key, value] of Object.entries(headers)) {\n if (!AUTH_HEADER_NAMES.has(key.toLowerCase())) out[key] = value;\n }\n return out;\n}\n\n/**\n * Depth cap for `safeAttempts`, guarding against a pathological,\n * self referential `attempts` array. `attempts` is a public\n * `LLMErrorOptions` field, so a caller can construct one by hand; this\n * keeps that path bounded the same way a circular `issues` value is\n * bounded, rather than assuming well formed input.\n */\nconst MAX_ATTEMPTS_DEPTH = 20;\n\n/**\n * Returns a copy of `attempts` with every nested snapshot's `issues`\n * re-checked through `safeIssues`, recursively through each snapshot's\n * own `attempts`. Needed for two reasons: `safeIssues` returns a safe\n * `issues` value by reference, so a shared object can be mutated into a\n * circular one after the snapshot was created, and `attempts` is a\n * public constructor option, so a caller can hand build a `RetryAttempt`\n * (or a whole `LLMErrorSnapshot`) with a circular `issues` and pass it\n * in directly, never touching `toSnapshot()` at all. The same applies to\n * `request`: its `body` is re-checked through `safeBody`, and its\n * `headers` are re-stripped through `stripAuthHeaders`, so a hand built\n * `RetryAttempt.request` can't smuggle an auth header past `toSnapshot()`\n * either. Extra fields on an attempt (e.g. `FallbackAttempt`'s\n * `provider`/`model`) are preserved.\n */\nfunction safeAttempts(attempts: RetryAttempt[] | undefined, depth = 0): RetryAttempt[] | undefined {\n if (attempts === undefined) return undefined;\n if (depth >= MAX_ATTEMPTS_DEPTH) return [];\n\n return attempts.map((attempt) => ({\n ...attempt,\n error: {\n ...attempt.error,\n issues: safeIssues(attempt.error.issues),\n attempts: safeAttempts(attempt.error.attempts, depth + 1),\n },\n request: attempt.request && {\n ...attempt.request,\n body: safeBody(attempt.request.body),\n headers: stripAuthHeaders(attempt.request.headers),\n },\n }));\n}\n\n/** One tool call's contract failure, used to report every bad call in a response at once. */\nexport interface ToolIssue {\n name: string;\n toolCallId: string;\n code: LLMErrorCode;\n detail?: unknown;\n}\n\n/**\n * The specific values behind a `duplicate_tool_names` failure: the\n * offending call's `tools` array had more than one entry sharing a name.\n */\nexport interface DuplicateToolNamesIssue {\n names: string[];\n}\n\n/**\n * The specific values behind an `unknown_tool_choice` failure: `toolChoice`\n * named a tool that wasn't in the call's own `tools` array.\n */\nexport interface UnknownToolChoiceIssue {\n requested: string;\n available: string[];\n}\n\n/**\n * The specific values behind a `duplicate_tool_result_ids` /\n * `unknown_tool_result_ids` / `missing_tool_results` failure: which\n * `history` turn was affected, and which `toolCallId`s were the problem.\n */\nexport interface HistoryToolResultIssue {\n historyIndex: number;\n ids: string[];\n}\n\n/**\n * The specific values behind an `unsupported_capability` failure: which\n * capability the current adapter/client/model doesn't support.\n */\nexport interface UnsupportedCapabilityIssue {\n capability: string;\n}\n\n/**\n * Maps each `LLMErrorCode` that carries structured `issues` to that\n * payload's exact shape. Not every code appears here: most `invalid_params`\n * failures are a single deterministic fact the `message` already states in\n * full, so adding a typed `issues` entry for them would only duplicate the\n * message into a field, the same near-duplicate-code problem `code` itself\n * avoids. Codes that repeat here are exactly the ones whose `message`\n * already string-joins a list a caller might want to consume directly\n * rather than re-parse out of prose, or that otherwise want a place to\n * report the exact captured values of a failure.\n *\n * Deliberately not a mapped type over the whole `LLMErrorCode` union: a\n * schema-validation failure's `issues` (the caller's own Zod-compatible\n * validator's error object) has no code and no shape VernLLM could know in\n * advance, so it stays untyped on `LLMError.issues` itself rather than\n * forcing every code into this table.\n */\nexport interface LLMErrorIssuesByCode {\n unknown_tool: ToolIssue[];\n duplicate_tool_call_id: ToolIssue[];\n duplicate_tool_names: DuplicateToolNamesIssue;\n unknown_tool_choice: UnknownToolChoiceIssue;\n duplicate_tool_result_ids: HistoryToolResultIssue;\n unknown_tool_result_ids: HistoryToolResultIssue;\n missing_tool_results: HistoryToolResultIssue;\n unsupported_capability: UnsupportedCapabilityIssue;\n}\n\n/**\n * Point-in-time copy of an `LLMError`'s fields, produced by\n * `LLMError.toSnapshot()`. This is what `RetryAttempt.error` holds\n * instead of a live `LLMError`.\n *\n * A past attempt only needs to be describable (message, type, code,\n * whether it was retryable), never thrown again. So it skips `Error`'s\n * behavior, `instanceof` identity, and any live getter. Using the full\n * `LLMError` class here would also make the type self referential\n * through its own `attempts` field.\n *\n * Has no `cause`. `cause` is `unknown` and never validated by VernLLM,\n * and it is meant to be read directly on the live error you just\n * caught, not carried indefinitely inside history. `type`, `code`,\n * `status`, and `issues` are the structured fields a snapshot carries\n * instead.\n *\n * `attempts` is still present, since a recorded attempt can itself be\n * the terminal failure of an inner retry loop with its own history (see\n * `FallbackAttempt`). That's a tree of past data, not a cycle.\n */\nexport interface LLMErrorSnapshot {\n message: string;\n type: LLMErrorType;\n status?: number;\n issues?: unknown;\n retryAfterMs?: number;\n code?: LLMErrorCode;\n /** Computed once, at snapshot time, since a snapshot has no live getter. */\n retryable: boolean;\n /** This attempt's own prior attempts, if it was itself the terminal failure of a retry loop. */\n attempts?: RetryAttempt[];\n}\n\n/**\n * Point-in-time copy of the request an attempt sent, produced by\n * `toRequestSnapshot()`. This is what `RetryAttempt.request` holds.\n * Mirrors `LLMErrorSnapshot`: plain data, never thrown or dispatched\n * again, safe to serialize and store.\n */\nexport interface LLMRequestSnapshot {\n /** Provider id this attempt targeted, e.g. \"openai\". */\n provider: string;\n /** Model id this attempt targeted. */\n model: string;\n /** The payload as actually sent for this attempt, after any transform/repair. Passed through `safeBody`. */\n body: unknown;\n /** Non sensitive request headers. Auth headers are stripped before the snapshot is built, never included. */\n headers?: Record<string, string>;\n /** Wall clock time the attempt started, ms since epoch. */\n startedAt: number;\n}\n\n/**\n * Builds a point-in-time, plain data copy of one attempt's outgoing\n * request. Mirrors `LLMError.toSnapshot()`: never thrown or dispatched\n * again, safe to serialize and store. A plain function rather than a\n * method, since unlike `LLMError` a request has no throwable identity or\n * derived state worth wrapping in a class.\n *\n * `startedAt` is optional so existing call sites (and tests) that don't\n * care about exact timing keep working, but a caller that has a real\n * capture time should always pass it: this function may run well after\n * the request was actually dispatched (e.g. `callExecutor` only builds\n * the snapshot once an attempt has failed), so defaulting to `Date.now()`\n * here would record failure-handling time, not request-start time.\n */\nexport function toRequestSnapshot(\n provider: string,\n model: string,\n body: unknown,\n headers?: Record<string, string>,\n startedAt: number = Date.now(),\n): LLMRequestSnapshot {\n return {\n provider,\n model,\n body: safeBody(body),\n headers: stripAuthHeaders(headers),\n startedAt,\n };\n}\n\n/**\n * One failed attempt on the way to a terminal error: which attempt index\n * it was, and a snapshot of the error it failed with. The base shape\n * every richer attempt record (e.g. `FallbackAttempt`) extends, rather\n * than duplicates.\n */\nexport interface RetryAttempt {\n index: number;\n error: LLMErrorSnapshot;\n /** What was sent for this attempt. Optional: absent for attempts predating this field. */\n request?: LLMRequestSnapshot;\n}\n\n/** Optional fields for constructing an {@link LLMError}. `message` and `type` stay positional since every throw site sets both. */\nexport interface LLMErrorOptions {\n status?: number;\n issues?: unknown;\n cause?: unknown;\n retryAfterMs?: number;\n /** Stable discriminator within `type`. Absent on errors predating it. */\n code?: LLMErrorCode;\n /** Every attempt made before this error was thrown, in order. Absent when nothing was retried. */\n attempts?: RetryAttempt[];\n}\n\nexport class LLMError extends Error {\n public status?: number;\n public issues?: unknown;\n public cause?: unknown;\n public retryAfterMs?: number;\n /** Stable discriminator within `type`. Absent on errors predating it. */\n public code?: LLMErrorCode;\n /** Every attempt made before this error was thrown, in order. Absent when nothing was retried. */\n public attempts?: RetryAttempt[];\n\n constructor(\n message: string,\n public type: LLMErrorType,\n options: LLMErrorOptions = {},\n ) {\n super(message);\n this.name = 'LLMError';\n this.status = options.status;\n this.issues = options.issues;\n this.cause = options.cause;\n this.retryAfterMs = options.retryAfterMs;\n this.code = options.code;\n this.attempts = options.attempts;\n }\n\n /**\n * Computed purely from `type`/`code`, independent of any specific call's\n * `nonRetryableStatus` list. False for `parse`/`validation`/\n * `invalid_params`/`aborted` types (the caller's own input, the model's\n * own response, or intentional cancellation, none of which are the\n * provider being unhealthy), the tool contract codes, and the local\n * rate limit codes. Subclasses (see `FallbackExhaustedError`) may\n * override this when `type` alone carries no retry signal.\n */\n get retryable(): boolean {\n return computeRetryable(this.type, this.code);\n }\n\n /**\n * Copies this error's fields into an {@link LLMErrorSnapshot}, for\n * recording as a `RetryAttempt`/`FallbackAttempt`. `retryable` is\n * captured here since a snapshot has no getter of its own. `cause` is\n * not copied, see `LLMErrorSnapshot`'s own doc. `issues` and every\n * nested `attempts` entry's own `issues` go through `safeAttempts`,\n * since a schema validation failure's `issues` is a caller supplied\n * value, not controlled by VernLLM, and `attempts` is itself a public\n * constructor option a caller can hand build.\n */\n toSnapshot(): LLMErrorSnapshot {\n return {\n message: this.message,\n type: this.type,\n status: this.status,\n issues: safeIssues(this.issues),\n retryAfterMs: this.retryAfterMs,\n code: this.code,\n retryable: this.retryable,\n attempts: safeAttempts(this.attempts),\n };\n }\n\n /**\n * Controls what `JSON.stringify(err)` produces. Omits `cause` for the\n * same reason `toSnapshot()` does: `cause` is `unknown` and never\n * validated by VernLLM, and some SDK errors carry circular structures\n * `JSON.stringify` cannot serialize at all. Read `err.cause` directly\n * instead. `issues`, including every nested `attempts` entry's own\n * `issues`, goes through `safeAttempts` for the same reason: a schema\n * validation failure's `issues` is caller supplied and not guaranteed\n * circular free. Also includes `message` and `retryable`, which a\n * plain property walk would otherwise miss: `message` is\n * non-enumerable on `Error`, and `retryable` is a getter, not an own\n * property.\n */\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n type: this.type,\n status: this.status,\n issues: safeIssues(this.issues),\n retryAfterMs: this.retryAfterMs,\n code: this.code,\n retryable: this.retryable,\n attempts: safeAttempts(this.attempts),\n };\n }\n}\n\nexport function isLLMError(err: unknown): err is LLMError {\n return err instanceof LLMError;\n}\n\n/**\n * Narrows `err.issues` to the exact shape {@link LLMErrorIssuesByCode} maps\n * `code` to, for any code listed there. `code` stays the only discriminator\n * VernLLM uses; this just gives that existing check a typed return instead\n * of requiring a manual cast of `issues`:\n *\n * ```ts\n * if (isLLMError(err) && hasIssues(err, 'duplicate_tool_names')) {\n * console.log(err.issues.names); // string[], no cast needed\n * }\n * ```\n */\nexport function hasIssues<C extends keyof LLMErrorIssuesByCode>(\n err: LLMError,\n code: C,\n): err is LLMError & { code: C; issues: LLMErrorIssuesByCode[C] } {\n return err.code === code && err.issues !== undefined;\n}\n","export interface CacheAdapter<T = unknown> {\n get(key: string): Promise<{ hit: boolean; value: T | null }>;\n set(key: string, value: T, ttl: number): Promise<void>;\n delete?(key: string): Promise<void>;\n resolveKey?(key: string): Promise<string>;\n}\n\n/**\n * Trivial default so the package works out of the box with no external deps\n * Not shared across processes, swap in Redis/Upstash/etc for production\n */\nexport class InMemoryCacheAdapter<T = unknown> implements CacheAdapter<T> {\n private store = new Map<string, { value: T; expiresAt: number }>();\n\n constructor(private readonly maxSize = 1000) {}\n\n async get(key: string): Promise<{ hit: boolean; value: T | null }> {\n const entry = this.store.get(key);\n\n if (!entry) return { hit: false, value: null };\n\n if (Date.now() >= entry.expiresAt) {\n this.store.delete(key);\n return { hit: false, value: null };\n }\n\n return { hit: true, value: entry.value };\n }\n\n async set(key: string, value: T, ttl: number): Promise<void> {\n this.cleanupExpiredEntries();\n\n this.store.set(key, {\n value,\n expiresAt: Date.now() + ttl * 1000,\n });\n\n this.enforceSizeLimit();\n }\n\n async delete(key: string): Promise<void> {\n this.store.delete(key);\n }\n\n private cleanupExpiredEntries(): void {\n const now = Date.now();\n\n for (const [key, entry] of this.store) {\n if (now >= entry.expiresAt) {\n this.store.delete(key);\n }\n }\n }\n\n private enforceSizeLimit(): void {\n while (this.store.size > this.maxSize) {\n const oldestKey = this.store.keys().next().value;\n\n if (oldestKey === undefined) break;\n\n this.store.delete(oldestKey);\n }\n }\n}\n\n/**\n * Normalizes keys before caching to avoid duplicate entries from formatting differences.\n */\nexport class NormalizedCacheAdapter<T = unknown> implements CacheAdapter<T> {\n constructor(private readonly inner: CacheAdapter<T> = new InMemoryCacheAdapter<T>()) {}\n\n private normalize(key: string): string {\n return key\n .toLowerCase()\n .trim()\n .replace(/[^\\p{L}\\p{N}\\s]/gu, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n }\n\n async resolveKey(key: string): Promise<string> {\n return this.normalize(key);\n }\n\n async get(key: string): Promise<{ hit: boolean; value: T | null }> {\n return this.inner.get(this.normalize(key));\n }\n\n async set(key: string, value: T, ttl: number): Promise<void> {\n await this.inner.set(this.normalize(key), value, ttl);\n }\n\n async delete(key: string): Promise<void> {\n await this.inner.delete?.(this.normalize(key));\n }\n}\n\n/**\n * Two-tier cache with fast local L1 and shared L2.\n * L2 hits are promoted back to L1.\n */\nexport class TieredCacheAdapter<T = unknown> implements CacheAdapter<T> {\n constructor(\n private readonly l1: CacheAdapter<T>,\n private readonly l2: CacheAdapter<T>,\n private readonly l1Ttl?: number,\n ) {}\n\n /**\n * Forwards to L1's `resolveKey` if it has one, otherwise L2's. L1 is\n * preferred since `get()` checks L1 first, so its notion of \"the same\n * key\" is the one that determines whether a lookup can skip L2 entirely.\n */\n async resolveKey(key: string): Promise<string> {\n if (this.l1.resolveKey) return this.l1.resolveKey(key);\n if (this.l2.resolveKey) return this.l2.resolveKey(key);\n return key;\n }\n\n async get(key: string): Promise<{ hit: boolean; value: T | null }> {\n const l1Result = await this.l1.get(key);\n if (l1Result.hit) return l1Result;\n\n const l2Result = await this.l2.get(key);\n\n if (l2Result.hit) {\n await this.l1.set(key, l2Result.value as T, this.l1Ttl ?? 60);\n }\n\n return l2Result;\n }\n\n async set(key: string, value: T, ttl: number): Promise<void> {\n await Promise.all([this.l1.set(key, value, this.l1Ttl ?? ttl), this.l2.set(key, value, ttl)]);\n }\n\n async delete(key: string): Promise<void> {\n await Promise.all([this.l1.delete?.(key), this.l2.delete?.(key)]);\n }\n}\n","import type { SchemaLike } from './schema.js';\n\n/**\n * Describes a capability the model may request, not the capability\n * itself. VernLLM transports this to the provider and parses what comes\n * back; it never executes anything.\n */\nexport interface ToolDefinition {\n name: string;\n description: string;\n /** JSON Schema for the tool's input. */\n parameters: Record<string, unknown>;\n /**\n * Optional client-side validator run on the parsed `arguments` before\n * they're handed back to the caller, mirroring the `schema: SchemaLike<T>`\n * pattern already used for response validation (see `types/schema.ts`).\n * Reuses that zero-dependency, `safeParse`-compatible shape instead of\n * requiring a JSON Schema validator (e.g. ajv) as a new dependency.\n * Failed validation throws `LLMError('validation')`. If omitted, VernLLM\n * parses arguments as JSON but does not validate them further.\n */\n argumentsSchema?: SchemaLike<unknown>;\n}\n\n/** A single tool invocation requested by the model. */\nexport interface ToolCall {\n id: string;\n name: string;\n /** Parsed JSON arguments (and validated, if `argumentsSchema` was set). */\n arguments: unknown;\n}\n\n/** The application's result of executing a `ToolCall`, sent back to the model. */\nexport interface ToolResult {\n toolCallId: string;\n content: unknown;\n /**\n * Signals a failed tool execution back to the model (matches Anthropic's\n * native `is_error` on tool_result blocks). Only `fromAnthropic` honors\n * this today, Gemini and Bedrock have no equivalent wire concept, so\n * other adapters ignore it silently.\n */\n isError?: boolean;\n}\n\n/** `call()` result when `tools` was set and the model produced a normal answer. */\nexport interface ContentResult<T> {\n type: 'content';\n content: T;\n}\n\n/** `call()` result when `tools` was set and the model requested one or more tools. */\nexport interface ToolCallResult {\n type: 'tool_calls';\n toolCalls: ToolCall[];\n /** Any text the model produced alongside the tool request, if present. */\n content?: string;\n}\n\nexport type CallWithToolsResult<T> = ContentResult<T> | ToolCallResult;\n\n/**\n * Runtime-safe check for whether a `call()` result is a `tool_calls`\n * result. Prefer this over relying on TypeScript's static narrowing\n * whenever `params` passed to `call()` wasn't a literal with `tools`\n * inlined (see the \"note on the overload\" in `VernLLM.call`'s docs), in\n * that case TS may have typed the result as plain `T` even though it's\n * actually a `CallWithToolsResult<T>` at runtime, and this check works\n * either way.\n */\nexport function isToolCallResult(result: unknown): result is ToolCallResult {\n return (\n typeof result === 'object' &&\n result !== null &&\n 'type' in result &&\n (result as { type: unknown }).type === 'tool_calls' &&\n Array.isArray((result as { toolCalls?: unknown }).toolCalls)\n );\n}\n\n/** What the model should do about tools on a given call. */\nexport type ToolChoice = 'auto' | 'none' | 'required' | { name: string };\n","import { LLMError, type RetryAttempt } from './errors.js';\n\nimport type { CircuitBreakerOptions, CircuitState } from '../circuitBreaker.js';\nimport type { RateLimitOptions } from '../rateLimit.js';\nimport type { LLMClient } from './client.js';\n\n/**\n * One provider to try after the primary (or after an earlier fallback\n * target) fails. Order is the policy: VernLLM never reorders, scores, or\n * selects a target, it only walks the list as given.\n *\n * Most per-target overrides fall back to the parent `VernLLM` instance's\n * own option when omitted, so a target only needs to specify what's\n * actually different about it (a different client/model is the common\n * case). `circuitBreaker` and `rateLimit` are the exception: they are\n * never inherited from the parent, since a breaker or limiter tuned for\n * the primary provider's limits is rarely right for a fallback's. Leave\n * them unset on a target to run it without one, even if the parent has\n * one configured.\n */\nexport interface FallbackTarget {\n client: LLMClient;\n model: string;\n /** Label for events, errors, and `TokenUsage.provider`. Default `` `fallback[${index}]` ``. */\n name?: string;\n\n maxRetries?: number;\n timeoutMs?: number;\n chunkIdleTimeoutMs?: number;\n baseDelayMs?: number;\n defaultMaxTokens?: number;\n defaultTemperature?: number | null;\n defaultReasoningEffort?: 'minimal' | 'low' | 'medium' | 'high';\n defaultBudgetTokens?: number;\n nonRetryableStatus?: number[];\n /** This target's own circuit breaker, independent of every other target's. Not inherited from the parent's `circuitBreaker`. */\n circuitBreaker?: boolean | CircuitBreakerOptions;\n /** This target's own rate limiter, independent of every other target's. Not inherited from the parent's `rateLimit`. */\n rateLimit?: RateLimitOptions;\n}\n\n/**\n * Written into `CallParams['meta']` once `call()` resolves, so a caller\n * who wants provider identity on the same line as the result doesn't need\n * to read it back out of `onUsage`.\n */\nexport interface CallMeta {\n provider: string;\n model: string;\n /** `-1` if the primary target answered, otherwise the index into `fallback`. */\n fallbackIndex: number;\n usedFallback: boolean;\n /** Attempts made against the target that ultimately answered, including the successful one. */\n attempts: number;\n}\n\n/** One target's circuit state, as returned by `VernLLM.getCircuitStates()`. */\nexport interface TargetCircuitState {\n provider: string;\n /** Position in the chain: `0` for the primary, `1`+ for fallback targets. */\n index: number;\n isFallback: boolean;\n /** Whether this target tracks failures per model. `false` means `model` on `getCircuitStates` had no effect on this entry. */\n isolateByModel: boolean;\n /** `undefined` if that target has no circuit breaker configured. */\n state: CircuitState | undefined;\n}\n\n/** Which target/model `VernLLM.getCircuitState`, `openCircuit`, and `closeCircuit` act on. */\nexport interface CircuitTarget {\n /** Which target to act on. `0` is the primary, `1`+ are fallbacks. Defaults to `0`. */\n index?: number;\n /** Which model bucket to act on, if the resolved target isolates by model. */\n model?: string;\n}\n\n/**\n * One target's failure, recorded on the way to either the next target or\n * `FallbackExhaustedError`. Extends `RetryAttempt`: `index` is `-1` for\n * the primary target here (rather than a plain retry count), and\n * `provider`/`model` identify which target failed.\n */\nexport interface FallbackAttempt extends RetryAttempt {\n provider: string;\n model: string;\n}\n\n/**\n * Decides what happens after a target's own retries are exhausted or\n * abandoned early. Called once per failed target. `'retry'` is not a\n * valid return here: retrying already happened inside the target, this\n * only decides whether to move on to the next one or stop.\n */\nexport type FallbackOn = (error: LLMError, context: { isLastTarget: boolean }) => 'next' | 'stop';\n\n/** Tool contract failures are the model ignoring the request, not a sick provider: repeating it elsewhere can't help. */\nconst TOOL_CONTRACT_CODES = new Set([\n 'unknown_tool',\n 'duplicate_tool_call_id',\n 'tool_choice_none_violated',\n 'unexpected_tool_calls',\n]);\n\n/**\n * The default `fallbackOn` policy. Exported so a caller can wrap rather\n * than replace it, e.g. `fallbackOn: (e, ctx) => myCheck(e) ? 'stop' : defaultFallbackOn(e, ctx)`.\n */\nexport const defaultFallbackOn: FallbackOn = (error) => {\n if (error.type === 'parse' || error.type === 'validation' || error.type === 'aborted') {\n return 'stop';\n }\n\n if (error.type === 'quota_exceeded') return 'stop';\n\n if (error.code && TOOL_CONTRACT_CODES.has(error.code)) return 'stop';\n\n return 'next';\n};\n\n/**\n * Thrown when the chain gives up, whether because the last target failed\n * or `fallbackOn` chose to stop early. Carries each attempt in order so\n * an outage across providers stays debuggable without reproducing it.\n * Extends `LLMError` so `isLLMError` and any `instanceof LLMError` check\n * still passes, inheriting the last failure's `type`/`status`/`retryAfterMs`\n * so existing type-based handling, including reading `retryAfterMs` on an\n * `'api'`-typed error, keeps working on a fallback-exhausted error too.\n */\nexport class FallbackExhaustedError extends LLMError {\n constructor(public override readonly attempts: FallbackAttempt[]) {\n const last = attempts[attempts.length - 1]?.error;\n\n // `type` is always `'fallback_exhausted'`, never inherited from the last\n // target's own type: every target failing is a meaningfully different\n // event from any single target's own failure. `status` and\n // `retryAfterMs` still inherit from the last attempt.\n super(\n `${attempts.length} provider${attempts.length === 1 ? '' : 's'} attempted and failed: ${attempts\n .map((a) => `${a.provider}(${a.error.type})`)\n .join(' then ')}`,\n 'fallback_exhausted',\n {\n status: last?.status,\n // `last` is an `LLMErrorSnapshot`, not the live `LLMError` that\n // target actually threw, so `cause` here is the same descriptive\n // data a caller would get from `err.attempts.at(-1)!.error`\n // rather than a distinct object.\n cause: last,\n retryAfterMs: last?.retryAfterMs,\n code: 'fallback_exhausted',\n attempts,\n },\n );\n }\n\n /**\n * `type: 'fallback_exhausted'` by itself says nothing about whether\n * retrying could help; the reason the last target failed does. Defers to\n * that attempt's own `retryable` instead of anything about this class's\n * own type.\n */\n override get retryable(): boolean {\n const last = this.attempts[this.attempts.length - 1]?.error;\n return last ? last.retryable : super.retryable;\n }\n}\n\n/** Narrows `err` to {@link FallbackExhaustedError}, for direct access to its `attempts` (`provider`/`model` per failed target) without a manual `instanceof` check. */\nexport function isFallbackExhaustedError(err: unknown): err is FallbackExhaustedError {\n return err instanceof FallbackExhaustedError;\n}\n","import { LLMError, type StreamChunk, type UsageHooks } from '../../types/index.js';\n\n/**\n * Calls `params.reserveUsage`, if present, mapping any failure to a\n * `quota_exceeded` LLMError (or an aborted error, if the signal fired\n * during reservation). Returns whether a reservation was actually made,\n * so callers know whether a later refund is needed. Shared by\n * `withReservedUsage` and `withReservedUsageForStream`, which differ only\n * in whether `coalesced` is caller-supplied or always `false`.\n */\nasync function reserve(\n params: UsageHooks,\n coalesced: boolean,\n signal: AbortSignal | undefined,\n): Promise<boolean> {\n if (!params.reserveUsage) return false;\n\n try {\n await params.reserveUsage({ coalesced, signal });\n return true;\n } catch (error) {\n if (signal?.aborted) {\n throw new LLMError('LLM request aborted', 'aborted');\n }\n\n throw new LLMError(\n error instanceof Error ? error.message : 'Usage reservation failed',\n 'quota_exceeded',\n { cause: error },\n );\n }\n}\n\n/**\n * Builds a `(logMessage) => Promise<void>` refund function bound to the\n * given hooks/coalesced/signal, reporting (instead of throwing) any error\n * the refund hook itself raises, so a broken refund hook never masks the\n * original error it was called to clean up after.\n */\nfunction makeRefund(\n params: UsageHooks,\n coalesced: boolean,\n signal: AbortSignal | undefined,\n onRefundError: (logMessage: string, error: unknown) => void,\n): (logMessage: string) => Promise<void> {\n return async (logMessage: string) => {\n try {\n await params.refundUsage?.({ coalesced, signal });\n } catch (refundError) {\n onRefundError(logMessage, refundError);\n }\n };\n}\n\n/**\n * Runs `getResult` after reserving usage, if a `reserveUsage` hook was\n * provided. `refundUsage` fires only if a reservation was actually made.\n * `onRefundError` is called (instead of throwing) whenever a refund attempt\n * itself fails, so a broken refund hook never masks the original error.\n */\nexport async function withReservedUsage<T>(\n params: UsageHooks,\n coalesced: boolean,\n getResult: () => Promise<T>,\n signal: AbortSignal | undefined,\n onRefundError: (logMessage: string, error: unknown) => void,\n): Promise<T> {\n if (signal?.aborted) {\n throw new LLMError('LLM request aborted', 'aborted');\n }\n\n const reserved = await reserve(params, coalesced, signal);\n\n const refund = makeRefund(params, coalesced, signal, onRefundError);\n\n if (signal?.aborted) {\n if (reserved) await refund('[VernLLM] refundUsage failed after abort');\n throw new LLMError('LLM request aborted', 'aborted');\n }\n\n let result: T;\n\n try {\n result = await getResult();\n } catch (error) {\n if (reserved) await refund('[VernLLM] refundUsage failed');\n throw error;\n }\n\n if (signal?.aborted) {\n if (reserved) await refund('[VernLLM] refundUsage failed after abort');\n throw new LLMError('LLM request aborted', 'aborted');\n }\n\n return result;\n}\n\n/**\n * Streaming counterpart to `withReservedUsage`. `withReservedUsage` assumes\n * `getResult()` settling *is* the operation's final outcome, awaiting it\n * synchronously before reserve/refund resolve. Streaming can't satisfy that:\n * `call()` must return `{ chunks, finalResult }` as soon as the stream\n * opens, well before the real outcome (validation, schema/tool-call checks)\n * is known.\n *\n * Reserves usage before `openStream` runs, same failure mode as the\n * non-streaming path if `reserveUsage` itself throws (mapped to\n * `quota_exceeded`, nothing opened). If `openStream` itself throws (stream\n * never opened), refunds synchronously and rethrows, exactly like\n * `withReservedUsage` does today. If it succeeds, returns `{ chunks,\n * finalResult }` immediately, refund/report is deferred onto\n * `finalResult`'s continuation, since that's the only point the real\n * outcome is known. This means `onUsageFailure` (and any refund) can fire\n * well after this function itself has returned.\n */\nexport async function withReservedUsageForStream<T>(\n params: UsageHooks,\n openStream: () => Promise<{ chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> }>,\n signal: AbortSignal | undefined,\n onRefundError: (logMessage: string, error: unknown) => void,\n): Promise<{ chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> }> {\n if (signal?.aborted) {\n throw new LLMError('LLM request aborted', 'aborted');\n }\n\n const reserved = await reserve(params, false, signal);\n const refund = makeRefund(params, false, signal, onRefundError);\n\n if (signal?.aborted) {\n if (reserved) await refund('[VernLLM] refundUsage failed after abort');\n throw new LLMError('LLM request aborted', 'aborted');\n }\n\n let opened: { chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> };\n\n try {\n opened = await openStream();\n } catch (error) {\n if (reserved) await refund('[VernLLM] refundUsage failed after stream-open failure');\n throw error;\n }\n\n // Stream opened. The real outcome is only known once finalResult settles,\n // so refund is attached there instead of awaited inline, this is the\n // structural difference from withReservedUsage, not an optional variant.\n const finalResult = opened.finalResult.then(\n (value) => value,\n async (error) => {\n if (reserved) await refund('[VernLLM] refundUsage failed after stream error');\n throw error;\n },\n );\n\n // Same rationale as the no-op catch attached where finalResult is first\n // constructed: mark this derived promise observed too, so a caller that\n // only reads `chunks` doesn't get an unhandled-rejection warning from\n // this wrapper promise either.\n finalResult.catch(() => {});\n\n return { chunks: opened.chunks, finalResult };\n}\n","import type { StreamChunk } from '../../types/stream.js';\nimport type { CallWithToolsResult } from '../../types/tools.js';\n\n/**\n * Converts an already-known cache value back into a plausible \"text\" form\n * for a one-shot replay chunk: passed through unchanged if it's already a\n * string (the `jsonMode: false` case), otherwise `JSON.stringify`'d (the\n * `jsonMode: true` case, where the cached value is the *parsed* result, not\n * the original raw text). This is a reasonable reconstruction, not a\n * byte-identical replay of whatever text the model originally streamed,\n * good enough for `for await (const c of chunks)` call sites that don't\n * branch on hit vs. miss, which is the only thing a cache-hit replay needs\n * to support.\n */\nfunction toReplayText(value: unknown): string {\n return typeof value === 'string' ? value : (JSON.stringify(value) ?? '');\n}\n\n/**\n * Builds a trivially-exhausted one-shot `chunks` iterable from an\n * already-known value, used for a `cachedCall` cache hit, where there's no\n * live generation to relay (see `VernLLM.cachedCall`'s docs). No `usage`\n * chunk is emitted: a cache hit spent no real tokens, so there's nothing to\n * report, matching how non-streaming `cachedCall` never calls `onUsage` on\n * a hit either.\n *\n * `hasTools` must reflect whether the *original* call that produced this\n * cached value had `tools` set, that's what determines whether `value` is\n * `T` directly or a `CallWithToolsResult<T>` wrapper, and it isn't\n * something that can be reliably guessed from the value's shape alone\n * (a `schema`-validated `T` could coincidentally look like a\n * `CallWithToolsResult`).\n */\nexport function buildReplayChunks<T>(\n value: T | CallWithToolsResult<T>,\n hasTools: boolean,\n): AsyncIterable<StreamChunk> {\n const items: StreamChunk[] = [];\n\n if (hasTools) {\n const result = value as CallWithToolsResult<T>;\n\n if (result.type === 'tool_calls') {\n result.toolCalls.forEach((toolCall, index) => {\n items.push({\n type: 'tool_call_delta',\n index,\n id: toolCall.id,\n name: toolCall.name,\n argsDelta: JSON.stringify(toolCall.arguments ?? {}),\n // A replay is always the whole value in one shot, never a\n // fragment, same as Gemini's one-shot tool_call_delta chunks.\n complete: true,\n });\n });\n\n if (result.content) items.push({ type: 'text-delta', delta: result.content });\n } else {\n items.push({ type: 'text-delta', delta: toReplayText(result.content) });\n }\n } else {\n items.push({ type: 'text-delta', delta: toReplayText(value) });\n }\n\n return {\n async *[Symbol.asyncIterator]() {\n for (const item of items) yield item;\n },\n };\n}\n\n/**\n * Streaming counterpart to `buildReplayChunks` for a `cachedCall` that\n * *joined* an already-in-flight call for the same key rather than\n * triggering one itself (see `runCachedStream`'s in-flight-coalescing\n * path): there's no live stream to relay (it isn't this call's stream to\n * relay, see the joiner-path comment in `runCachedStream`), but there's\n * also no value yet, only a pending promise for one. Waits for `promise`,\n * then delegates to `buildReplayChunks`. If `promise` rejects, iterating\n * `chunks` throws that same error, consistent with how a live stream's\n * `chunks` throws on a mid-stream failure.\n */\nexport function buildReplayChunksFromPromise<T>(\n promise: Promise<T | CallWithToolsResult<T>>,\n hasTools: boolean,\n): AsyncIterable<StreamChunk> {\n return {\n async *[Symbol.asyncIterator]() {\n const value = await promise;\n\n yield* buildReplayChunks(value, hasTools);\n },\n };\n}\n","import { withReservedUsage, withReservedUsageForStream } from '../execution/usage.utils.js';\nimport { buildReplayChunks, buildReplayChunksFromPromise } from './replay.utils.js';\n\nimport type { Logger } from '../../logger.js';\nimport type { CacheAdapter, StreamChunk } from '../../types/index.js';\nimport type { InternalCacheParams, InternalCacheStreamParams } from './cache.utils.js';\n\n/**\n * Owns cache key resolution, cache reads/writes, and in-flight coalescing\n * for concurrent misses on the same key. Doesn't know about `CallExecutor`,\n * retries, or providers at all: `fn`/`openStream` are opaque callbacks\n * (`VernLLM.cachedCall` passes `() => this.call(...)`), so this class only\n * needs the cache adapter and a logger. Extracted from `VernLLM` since\n * caching and per-target call mechanics are independent concerns that\n * happened to live on the same class.\n */\nexport class CacheOrchestrator {\n private readonly inFlight = new Map<string, Promise<unknown>>();\n\n constructor(\n private readonly cache: CacheAdapter<unknown>,\n private readonly logger: Logger,\n ) {}\n\n /** Resolves a cache key through the adapter when it supports normalization. */\n async resolveCacheKey(key: string): Promise<string> {\n return this.cache.resolveKey ? await this.cache.resolveKey(key) : key;\n }\n\n /**\n * Removes a cached response by key when the configured cache adapter\n * supports deletion. Cache invalidation is the caller's responsibility;\n * only the application knows when cached data is stale.\n */\n async deleteCache(key: string): Promise<void> {\n if (!this.cache.delete) return;\n\n try {\n await this.cache.delete(await this.resolveCacheKey(key));\n } catch (error) {\n this.logger.warn(\n `[VernLLM] cache delete failed: ${error instanceof Error ? error.message : 'unknown'}`,\n );\n }\n }\n\n /** Logs a failed refundUsage attempt via the configured logger. */\n private logRefundError(logMessage: string, error: unknown): void {\n this.logger.error(logMessage, {\n message: error instanceof Error ? error.message : 'unknown',\n });\n }\n\n /**\n * Reads from the cache, treating a failed adapter read as a miss rather\n * than letting it fail the call. The request still falls through to a\n * real provider call, but that fallback is now logged instead of silent.\n */\n private async getCached(key: string): Promise<{ hit: boolean; value?: unknown }> {\n try {\n return await this.cache.get(key);\n } catch (error) {\n this.logger.warn(\n `[VernLLM] cache read failed: ${error instanceof Error ? error.message : 'unknown'}`,\n );\n\n return { hit: false };\n }\n }\n\n /**\n * Internal cache primitive around caller-supplied logic. Concurrent misses\n * for the same `cacheKey` share a single in-flight call, avoiding cache\n * stampedes.\n *\n * Backs the public `VernLLM.cachedCall()`, which always composes this\n * with `call()` so cached results get the same retry/timeout/\n * circuit-breaker guarantees as any other LLM call.\n *\n * @param params `cacheKey`, `ttl`, `fn` (the work to run on a cache\n * miss, typically `() => this.call(...)`), and optional\n * `reserveUsage`/`refundUsage`/`signal`. See `InternalCacheParams`.\n * @returns The cached value on a hit, or the result of `fn()` on a miss.\n */\n async runCached<T>(params: InternalCacheParams<T>): Promise<T> {\n const resolvedKey = await this.resolveCacheKey(params.cacheKey);\n const resolvedParams =\n resolvedKey === params.cacheKey ? params : { ...params, cacheKey: resolvedKey };\n\n const cached = await this.getCached(resolvedKey);\n\n if (cached.hit) return cached.value as T;\n\n const existing = this.inFlight.get(resolvedKey) as Promise<T> | undefined;\n\n if (existing) {\n return withReservedUsage(\n resolvedParams,\n true,\n () => existing,\n params.signal,\n (logMessage, error) => this.logRefundError(logMessage, error),\n );\n }\n\n return this.registerTrigger(resolvedParams);\n }\n\n /** Starts the shared fn() call for a cache miss and tracks it in the in-flight map until it settles. */\n private registerTrigger<T>(params: InternalCacheParams<T>): Promise<T> {\n const resultPromise = withReservedUsage(\n params,\n false,\n () => this.runAndCache(params),\n params.signal,\n (logMessage, error) => this.logRefundError(logMessage, error),\n );\n\n this.inFlight.set(params.cacheKey, resultPromise);\n\n void resultPromise\n .catch(() => {})\n .finally(() => {\n this.inFlight.delete(params.cacheKey);\n });\n\n return resultPromise;\n }\n\n /** Runs `fn` and writes its result to the cache. */\n private async runAndCache<T>(params: InternalCacheParams<T>): Promise<T> {\n const result = await params.fn();\n\n try {\n await this.cache.set(params.cacheKey, result, params.ttl);\n } catch (error) {\n this.logger.warn(\n `[VernLLM] cache write failed: ${error instanceof Error ? error.message : 'unknown'}`,\n );\n }\n\n return result;\n }\n\n /**\n * Streaming counterpart to `runCached`. Three cases:\n *\n * - Hit: no live generation to relay. Returns immediately with\n * `finalResult` resolved to the cached value and a one-shot `chunks`\n * replay built from it, so `for await (const c of chunks)` call sites\n * work identically on a hit or a miss. No usage hooks fire, since\n * nothing was actually spent.\n * - Miss, nothing else in flight for this key: delegates to\n * `registerStreamTrigger`, which opens the stream and relays its\n * `chunks` live.\n * - Miss, but another call for the same key is already in flight: this\n * call has no live chunks of its own to relay, so it's treated like a\n * delayed hit. `finalResult` shares the trigger's in-flight promise\n * (the same in-flight map non-streaming `runCached` uses, so\n * streaming and non-streaming calls for the same key coalesce\n * against each other too), and `chunks` is a one-shot replay built\n * once that promise resolves.\n */\n async runCachedStream<T>(\n params: InternalCacheStreamParams<T>,\n hasTools: boolean,\n ): Promise<{ chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> }> {\n const resolvedKey = await this.resolveCacheKey(params.cacheKey);\n const resolvedParams =\n resolvedKey === params.cacheKey ? params : { ...params, cacheKey: resolvedKey };\n\n const cached = await this.getCached(resolvedKey);\n\n if (cached.hit) {\n const value = cached.value as T;\n\n return { chunks: buildReplayChunks(value, hasTools), finalResult: Promise.resolve(value) };\n }\n\n const existing = this.inFlight.get(resolvedKey) as Promise<T> | undefined;\n\n if (existing) {\n const finalResult = withReservedUsage(\n resolvedParams,\n true,\n () => existing,\n params.signal,\n (logMessage, error) => this.logRefundError(logMessage, error),\n );\n\n // Mirror the no-op catch in withReservedUsageForStream: buildReplayChunksFromPromise\n // doesn't await this promise until `chunks` is iterated, so a caller that only reads\n // `finalResult` eagerly (or never reads `chunks`) could otherwise trigger an\n // unhandled-rejection warning.\n finalResult.catch(() => {});\n\n return { chunks: buildReplayChunksFromPromise(finalResult, hasTools), finalResult };\n }\n\n return this.registerStreamTrigger(resolvedParams);\n }\n\n /**\n * Opens the shared stream for a cache miss and tracks its settled value\n * in the in-flight map until it resolves or rejects. Writes to the cache\n * on success only, matching `runAndCache`.\n *\n * Registers the in-flight promise synchronously, before anything async\n * runs, so a concurrent `cachedCall` for the same key always sees it in\n * time to join instead of triggering its own stream. Settlement is\n * wired onto the whole `withReservedUsageForStream` call rather than a\n * line inside its callback, so any failure point (reserving usage,\n * opening the stream, or the stream itself) reliably settles the\n * in-flight entry instead of leaving it stuck.\n */\n private registerStreamTrigger<T>(\n params: InternalCacheStreamParams<T>,\n ): Promise<{ chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> }> {\n let resolveInFlight!: (value: T) => void;\n let rejectInFlight!: (error: unknown) => void;\n\n const inFlightResult = new Promise<T>((resolve, reject) => {\n resolveInFlight = resolve;\n rejectInFlight = reject;\n });\n\n this.inFlight.set(params.cacheKey, inFlightResult);\n\n void inFlightResult\n .catch(() => {})\n .finally(() => {\n this.inFlight.delete(params.cacheKey);\n });\n\n const streamPromise = withReservedUsageForStream(\n params,\n async () => {\n const opened = await params.openStream();\n\n const trackedResult: Promise<T> = opened.finalResult.then(\n async (value) => {\n try {\n await this.cache.set(params.cacheKey, value, params.ttl);\n } catch (error) {\n this.logger.warn(\n `[VernLLM] cache write failed: ${error instanceof Error ? error.message : 'unknown'}`,\n );\n }\n\n return value;\n },\n (error: unknown) => {\n // Failed calls aren't cached, matching `runAndCache`, which\n // only calls `cache.set` after `fn()` succeeds. Rethrown\n // unchanged so both the refund logic attached downstream and\n // `inFlightResult` see the real failure.\n throw error;\n },\n );\n\n return { chunks: opened.chunks, finalResult: trackedResult };\n },\n params.signal,\n (logMessage, error) => this.logRefundError(logMessage, error),\n );\n\n // Settles `inFlightResult` (registered above) based on `streamPromise`'s\n // own outcome, not a line inside its callback. See this function's\n // docs for why.\n streamPromise.then(\n (opened) => {\n opened.finalResult.then(resolveInFlight, rejectInFlight);\n },\n (error: unknown) => {\n rejectInFlight(error);\n },\n );\n\n return streamPromise;\n }\n}\n","import { LLMError } from './types/errors.js';\n\nexport interface CircuitBreakerOptions {\n /** Consecutive failures before the circuit opens, default 5 */\n threshold?: number;\n /** How long the circuit stays open before allowing a trial request, in ms. Default 30000 */\n cooldownMs?: number;\n /**\n * Called after every real state change, never for a no-op transition\n * (e.g. open to open). `model` is the resolved model of whichever call\n * triggered this specific transition (the `model` passed to whichever\n * of `assertClosed`/`recordSuccess`/`recordFailure` caused it).\n *\n * With `isolateByModel` off (the default), this is a label only: the\n * breaker still counts failures across every model together, so a\n * threshold crossing can be the sum of several different models'\n * failures even though only the triggering call's `model` is reported\n * here. With `isolateByModel` on, it's exact: each model has its own\n * counter, so the transition really was caused solely by that model.\n */\n onStateChange?: (\n from: CircuitState,\n to: CircuitState,\n consecutiveFailures: number,\n model?: string,\n ) => void;\n /**\n * Track a separate circuit per resolved model instead of one shared\n * circuit for the whole instance. A failure on one model then never\n * opens another model's circuit, at the cost of slower detection for\n * an outage spread across many distinct models (each model's counter\n * must independently cross `threshold`). Default false: one shared\n * circuit, matching every version before this option existed.\n *\n * A call that omits `model` (only possible calling `CircuitBreaker`\n * directly, `VernLLM` always passes one) falls into one shared bucket\n * alongside every other call that also omits it.\n */\n isolateByModel?: boolean;\n}\n\nexport type CircuitState = 'closed' | 'open' | 'half-open';\n\n/** Mutable state for one circuit, either the single shared one or one model's bucket under `isolateByModel`. */\ninterface CircuitBucket {\n state: CircuitState;\n consecutiveFailures: number;\n openedAt: number;\n /**\n * True while a single half-open trial call is in flight. Guards against\n * multiple concurrent callers all treating themselves as \"the\" trial once\n * the cooldown elapses\n */\n trialInFlight: boolean;\n}\n\nfunction newBucket(): CircuitBucket {\n return { state: 'closed', consecutiveFailures: 0, openedAt: 0, trialInFlight: false };\n}\n\n/** Key a bucket lookup falls into when the call omitted `model` under `isolateByModel`. */\nconst UNLABELED_MODEL = '';\n\n/**\n * Per retry VernLLM-instance circuit breaker. Tracks consecutive failures across\n * calls. Once the threshold is hit, short-circuits new calls with an\n * LLMError('circuit_open') instead of hitting the provider, until the\n * cooldown elapses and a single trial call is allowed through\n */\nexport class CircuitBreaker {\n private readonly threshold: number;\n private readonly cooldownMs: number;\n private readonly onStateChange?: CircuitBreakerOptions['onStateChange'];\n /** Whether this breaker tracks failures per model instead of one shared circuit. Read by `CallExecutor`/`VernLLM` to report per-target in `getCircuitStates`. */\n readonly isolateByModel: boolean;\n\n // Exactly one of these is used, chosen once at construction by\n // `isolateByModel`, so every method has a single, unambiguous place to\n // resolve a bucket from instead of branching on the flag repeatedly.\n private readonly sharedBucket: CircuitBucket = newBucket();\n private readonly bucketsByModel = new Map<string, CircuitBucket>();\n\n constructor(options: CircuitBreakerOptions = {}) {\n this.threshold = options.threshold ?? 5;\n this.cooldownMs = options.cooldownMs ?? 30_000;\n this.onStateChange = options.onStateChange;\n this.isolateByModel = options.isolateByModel ?? false;\n }\n\n /** Returns the bucket for a model if one already exists, without allocating. */\n private lookupBucket(model: string | undefined): CircuitBucket | undefined {\n if (!this.isolateByModel) return this.sharedBucket;\n\n const key = model ?? UNLABELED_MODEL;\n return this.bucketsByModel.get(key);\n }\n\n /** Creates and stores a bucket for a model when the first mutation needs one. */\n private ensureBucketFor(model: string | undefined): CircuitBucket {\n if (!this.isolateByModel) return this.sharedBucket;\n\n const key = model ?? UNLABELED_MODEL;\n let bucket = this.bucketsByModel.get(key);\n\n if (!bucket) {\n bucket = newBucket();\n this.bucketsByModel.set(key, bucket);\n }\n\n return bucket;\n }\n\n /** Every state mutation routes through here, so `onStateChange` fires exactly once per real change. */\n private transition(bucket: CircuitBucket, to: CircuitState, model: string | undefined): void {\n if (to === bucket.state) return;\n\n const from = bucket.state;\n bucket.state = to;\n this.onStateChange?.(from, to, bucket.consecutiveFailures, model);\n }\n\n /**\n * Throws if the circuit is open and the cooldown hasn't elapsed, or if\n * the circuit is half-open and a trial call is already in flight.\n * Otherwise, if the circuit just became eligible for a trial (cooldown\n * elapsed, or half-open with no trial currently running), this call\n * becomes that trial\n */\n assertClosed(model?: string): void {\n const bucket = this.ensureBucketFor(model);\n\n if (bucket.state === 'closed') return;\n\n if (bucket.state === 'open') {\n const elapsed = Date.now() - bucket.openedAt;\n if (elapsed < this.cooldownMs) {\n throw new LLMError(\n `Circuit open, provider has failed ${bucket.consecutiveFailures} times in a row. Retry in ${Math.ceil((this.cooldownMs - elapsed) / 1000)}s.`,\n 'circuit_open',\n { code: 'circuit_cooling_down' },\n );\n }\n\n // Set before transition(): a synchronous onStateChange observer\n // that re-enters (e.g. calls assertClosed again) must see this\n // call as already claiming the trial, not still eligible for one.\n bucket.trialInFlight = true;\n this.transition(bucket, 'half-open', model);\n return;\n }\n\n // state === 'half-open'\n if (bucket.trialInFlight) {\n throw new LLMError(\n 'Circuit half-open. A trial request is already in flight. Try again shortly.',\n 'circuit_open',\n { code: 'circuit_trial_in_flight' },\n );\n }\n\n bucket.trialInFlight = true;\n }\n\n recordSuccess(model?: string): void {\n const bucket = this.lookupBucket(model);\n\n if (!bucket) {\n return;\n }\n\n bucket.consecutiveFailures = 0;\n bucket.trialInFlight = false;\n this.transition(bucket, 'closed', model);\n\n if (this.isolateByModel && bucket.state === 'closed' && bucket.consecutiveFailures === 0) {\n this.bucketsByModel.delete(model ?? UNLABELED_MODEL);\n }\n }\n\n recordFailure(model?: string): void {\n const bucket = this.ensureBucketFor(model);\n\n bucket.consecutiveFailures += 1;\n bucket.trialInFlight = false;\n\n if (bucket.state === 'half-open') {\n // Trial call failed: reopen and reset the cooldown window. Set\n // before transition() for the same reason as assertClosed above:\n // a synchronous observer must see the fresh cooldown, not a stale\n // or zeroed one.\n bucket.openedAt = Date.now();\n this.transition(bucket, 'open', model);\n return;\n }\n\n if (bucket.consecutiveFailures >= this.threshold) {\n bucket.openedAt = Date.now();\n this.transition(bucket, 'open', model);\n }\n }\n\n /**\n * With `isolateByModel` off (the default), `model` is ignored and the\n * one shared circuit's state is returned, unchanged from every version\n * before this option existed. With `isolateByModel` on, returns that\n * model's own state, `'closed'` for a model never seen yet, same as a\n * fresh breaker.\n */\n getState(model?: string): CircuitState {\n return this.lookupBucket(model)?.state ?? 'closed';\n }\n\n /**\n * Manually opens the circuit, as if `threshold` consecutive failures had\n * just happened, e.g. to pull a provider out of rotation ahead of known\n * maintenance. Resets the cooldown window from now, same as a real\n * threshold-crossing failure would, and clears any in-flight half-open\n * trial since it no longer applies once the circuit is (re)opened.\n */\n open(model?: string): void {\n const bucket = this.ensureBucketFor(model);\n\n bucket.openedAt = Date.now();\n bucket.trialInFlight = false;\n this.transition(bucket, 'open', model);\n }\n\n /**\n * Manually closes the circuit and resets its failure count, e.g. once a\n * provider is confirmed healthy again without waiting out the cooldown.\n * Mirrors `recordSuccess`'s bookkeeping (including dropping the\n * per-model bucket under `isolateByModel`, once idle) but without\n * requiring an actual successful call first.\n */\n close(model?: string): void {\n const bucket = this.ensureBucketFor(model);\n\n bucket.consecutiveFailures = 0;\n bucket.trialInFlight = false;\n this.transition(bucket, 'closed', model);\n\n // transition() may have synchronously re-entered (e.g. an\n // onStateChange callback that calls open(model) on this same\n // bucket), so re-check state/consecutiveFailures rather than\n // assuming they still hold the values set above, same as\n // recordSuccess does.\n if (this.isolateByModel && bucket.state === 'closed' && bucket.consecutiveFailures === 0) {\n this.bucketsByModel.delete(model ?? UNLABELED_MODEL);\n }\n }\n}\n","import { CircuitBreaker, type CircuitBreakerOptions } from '../circuitBreaker.js';\n\nimport type { Logger } from '../logger.js';\nimport type { VernLLMEvent } from '../types/events.js';\n\n/**\n * Builds a `(event) => void` reporter that no-ops when `onEvent` is unset,\n * and otherwise calls it, swallowing and logging any error the handler\n * throws so a broken `onEvent` can't break the call that triggered it.\n * Shared by `buildCircuitBreaker` (which needs to report before any\n * executor exists) and `CallExecutor.reportEvent`, kept independent of the\n * executor for that reason.\n */\nexport function makeEventReporter(\n onEvent: ((event: VernLLMEvent) => void) | undefined,\n logger: Logger,\n): (event: VernLLMEvent) => void {\n return (event) => {\n if (!onEvent) return;\n\n try {\n onEvent(event);\n } catch (error) {\n logger.error('[VernLLM] onEvent failed', {\n message: error instanceof Error ? error.message : 'unknown',\n });\n }\n };\n}\n\n/**\n * Builds the optional circuit breaker for one provider target, wiring its\n * `onStateChange` to emit a `circuit_state` event and chain any\n * caller-supplied `onStateChange`. Returns `undefined` when\n * `circuitBreakerOption` is falsy, matching the option's own semantics.\n *\n * Lives outside `CallExecutor` (and outside `VernLLM`, once this were\n * inlined) because the breaker has to exist *before* the executor it's\n * passed into, so its construction can't be an executor concern.\n * `onEvent` is called directly rather than through the executor for the\n * same reason: nothing executor-shaped exists yet at this point.\n *\n * Takes the specific fields it needs (rather than a full `VernLLMOptions`)\n * so it works identically for the primary target and for each fallback\n * target, which carry their own `circuitBreaker` override alongside the\n * shared `onEvent`.\n */\nexport function buildCircuitBreaker(\n circuitBreakerOption: boolean | CircuitBreakerOptions | undefined,\n providerName: string,\n defaultModel: string,\n onEvent: ((event: VernLLMEvent) => void) | undefined,\n logger: Logger,\n): CircuitBreaker | undefined {\n if (!circuitBreakerOption) return undefined;\n\n const breakerOptions =\n typeof circuitBreakerOption === 'object' ? circuitBreakerOption : undefined;\n const userOnStateChange = breakerOptions?.onStateChange;\n\n const reportEvent = makeEventReporter(onEvent, logger);\n\n return new CircuitBreaker({\n ...breakerOptions,\n onStateChange: (from, to, consecutiveFailures, model) => {\n reportEvent({\n kind: 'circuit_state',\n provider: providerName,\n model: model ?? defaultModel,\n from,\n to,\n consecutiveFailures,\n });\n\n // A caller-supplied onStateChange would otherwise be silently\n // discarded, since the spread above is overwritten by this\n // property. Chain it instead, same try/catch treatment as every\n // other user-supplied callback so it can't break breaker\n // bookkeeping or the call that triggered it.\n if (!userOnStateChange) return;\n\n try {\n userOnStateChange(from, to, consecutiveFailures, model);\n } catch (error) {\n logger.error('[VernLLM] circuitBreaker.onStateChange failed', {\n message: error instanceof Error ? error.message : 'unknown',\n });\n }\n },\n });\n}\n","import { LLMError } from '../../types/errors.js';\n\nimport type { Logger } from '../../logger.js';\n\n/**\n * Default cap (ms) for both exponential backoff and honored Retry-After\n * values, so a misbehaving/adversarial Retry-After can't stall a caller\n * indefinitely\n */\nexport const DEFAULT_MAX_DELAY_MS = 10_000;\n\n/**\n * `setTimeout` silently clamps any delay above this (~24.8 days) or\n * `Infinity` down to ~1ms instead of erroring, so a caller passing\n * `Infinity` as \"no timeout\" gets the opposite of what they asked for.\n * Both timeout helpers below guard against this explicitly.\n */\nconst MAX_SETTIMEOUT_MS = 2_147_483_647;\n\n/**\n * Resolves a timeout value to the number `setTimeout` should actually use,\n * or `undefined` when the timeout should be treated as disabled (0,\n * negative, or `Infinity`). Returning the resolved value directly, rather\n * than a boolean, lets callers narrow `number | undefined` to `number`\n * without an `as number` cast.\n */\nfunction resolveActiveTimeoutMs(ms: number | undefined): number | undefined {\n return !ms || ms <= 0 || ms === Infinity ? undefined : ms;\n}\n\n/** Caps a timeout at the largest delay `setTimeout` actually honors. */\nfunction clampTimeoutMs(ms: number): number {\n return Math.min(ms, MAX_SETTIMEOUT_MS);\n}\n\n/**\n * Runs an async function and cancels it if it takes longer than the given\n * timeout. Creates an internal abort controller that fires after the\n * timeout elapses, and combines it with any external signal the caller\n * passed in so either one can cancel the underlying call. If the internal\n * timeout triggers and the underlying operation aborts, the error is\n * converted into an LLMError with type \"timeout\". External cancellations\n * continue to propagate as aborted errors. The internal timer is always\n * cleared afterward, whether the function succeeds, fails, or is aborted,\n * so nothing is left running in the background.\n *\n * `timeoutMs` of `Infinity` (or any value beyond what `setTimeout` can\n * represent) disables the timeout rather than firing almost immediately.\n */\nexport async function withTimeout<T>(\n fn: (signal: AbortSignal) => Promise<T>,\n timeoutMs: number,\n externalSignal?: AbortSignal,\n): Promise<T> {\n const controller = new AbortController();\n\n const activeTimeoutMs = resolveActiveTimeoutMs(timeoutMs);\n\n const timer =\n activeTimeoutMs === undefined\n ? undefined\n : setTimeout(() => {\n controller.abort();\n }, clampTimeoutMs(activeTimeoutMs));\n\n const signal = externalSignal\n ? AbortSignal.any([externalSignal, controller.signal])\n : controller.signal;\n\n try {\n return await fn(signal);\n } catch (err) {\n if (\n controller.signal.aborted &&\n !externalSignal?.aborted &&\n err instanceof DOMException &&\n err.name === 'AbortError'\n ) {\n throw new LLMError('Request timed out', 'timeout', { code: 'request_timeout' });\n }\n\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Races one `iterator.next()` call against a per-call idle timer, to\n * bound the gap *between* chunks (unlike `withTimeout`, which only bounds\n * opening the stream and its first chunk). Without this, a connection\n * that streams one chunk then hangs would never fail.\n *\n * `timeoutMs` of 0/undefined/`Infinity` disables the check. Otherwise\n * rejects with `LLMError('timeout')` if `next()` doesn't settle in time.\n * The clock resets on every call, so the window is measured from the most\n * recent chunk, not from stream start.\n *\n * `onIdle`, if given, is called the moment the timer fires (before the\n * rejection), so callers can abort the underlying transport instead of\n * just walking away from an unread promise. `logger`, if given, records a\n * debug line if `next()` still settles *after* the idle timeout already\n * rejected. `resolve`/`reject` on an already-settled promise is otherwise\n * a silent no-op, so without this the late chunk (possibly the final\n * usage chunk) would vanish with no trace.\n */\nexport function withChunkIdleTimeout<T>(\n next: () => Promise<IteratorResult<T>>,\n timeoutMs: number | undefined,\n onIdle?: () => void,\n logger?: Pick<Logger, 'debug'>,\n): Promise<IteratorResult<T>> {\n const activeTimeoutMs = resolveActiveTimeoutMs(timeoutMs);\n\n if (activeTimeoutMs === undefined) {\n return next();\n }\n\n let settled = false;\n\n return new Promise<IteratorResult<T>>((resolve, reject) => {\n const timer = setTimeout(() => {\n settled = true;\n onIdle?.();\n reject(\n new LLMError(\n `No stream chunk received for ${activeTimeoutMs}ms (idle timeout)`,\n 'timeout',\n {\n code: 'idle_timeout',\n },\n ),\n );\n }, clampTimeoutMs(activeTimeoutMs));\n\n next().then(\n (result) => {\n clearTimeout(timer);\n if (settled) {\n logger?.debug('[VernLLM] chunk resolved after idle timeout already fired; discarding');\n return;\n }\n settled = true;\n resolve(result);\n },\n (error: unknown) => {\n clearTimeout(timer);\n if (settled) {\n logger?.debug(\n '[VernLLM] chunk rejection arrived after idle timeout already fired; discarding',\n );\n return;\n }\n settled = true;\n reject(error);\n },\n );\n });\n}\n\n/**\n * Looks inside an unknown error value for a Retry-After header and\n * converts it to milliseconds. Checks `.headers` first (fetch-style,\n * Headers-like with `.get()`), then `.response.headers` (axios-style,\n * plain object) since different client libraries surface headers\n * differently. Supports both the delta-seconds form (\"30\") and the\n * HTTP-date form (\"Wed, 21 Oct 2015 07:28:00 GMT\"). The result is capped\n * at maxDelayMs. Returns undefined when no usable Retry-After is present\n */\nexport function extractRetryAfterMs(\n err: unknown,\n maxDelayMs = DEFAULT_MAX_DELAY_MS,\n): number | undefined {\n if (!err || typeof err !== 'object') return undefined;\n\n const error = err as { headers?: unknown; response?: { headers?: unknown } };\n const headers = error.headers ?? error.response?.headers;\n\n if (!headers || typeof headers !== 'object') return undefined;\n\n const getter = headers as { get?: (name: string) => string | null };\n\n const raw =\n typeof getter.get === 'function'\n ? getter.get('Retry-After')\n : Object.entries(headers as Record<string, string>)\n .find(([name]) => name.toLowerCase() === 'retry-after')\n ?.at(1);\n\n if (typeof raw !== 'string' || raw.trim() === '') return undefined;\n\n const trimmed = raw.trim();\n\n if (/^\\d+$/.test(trimmed)) {\n return Math.max(0, Math.min(Number(trimmed) * 1000, maxDelayMs));\n }\n\n const dateMs = Date.parse(trimmed);\n if (!Number.isNaN(dateMs)) {\n return Math.max(0, Math.min(dateMs - Date.now(), maxDelayMs));\n }\n\n return undefined;\n}\n\n/**\n * Exponential backoff with jitter, capped at maxDelayMs.\n * Jitter avoids thundering-herd retries when many callers back off in lockstep,\n * the cap prevents unbounded delays when maxRetries is high\n */\nexport function getBackoffDelay(\n baseDelayMs: number,\n attempt: number,\n maxDelayMs = DEFAULT_MAX_DELAY_MS,\n): number {\n const exp = Math.min(baseDelayMs * 2 ** attempt, maxDelayMs);\n return exp / 2 + Math.random() * (exp / 2);\n}\n\n/**\n * Pauses execution for the given delay before a retry attempt. If an\n * abort signal is provided and it fires while waiting, the pending\n * timer is cancelled immediately and the wait rejects right away with\n * an aborted error instead of continuing to sit idle until the delay\n * would have finished on its own\n */\nexport async function waitForRetry(delay: number, signal?: AbortSignal): Promise<void> {\n if (signal?.aborted) {\n throw new LLMError('Operation aborted', 'aborted');\n }\n\n await new Promise<void>((resolve, reject) => {\n const onAbort = () => {\n clearTimeout(timer);\n reject(new LLMError('Operation aborted', 'aborted'));\n };\n\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, delay);\n\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n","import { LLMError, type LLMErrorCode, type RetryAttempt } from '../../types/errors.js';\nimport { extractRetryAfterMs } from './retry.utils.js';\n\n/**\n * Looks inside an unknown error value and pulls out an http status code\n * if one is present. Checks the status field first then the status code\n * field since different client libraries use different names for this,\n * falling back to AWS SDK v3's `$metadata.httpStatusCode` (e.g. Bedrock's\n * `ThrottlingException`), which doesn't set either of the other two.\n * Returns undefined when the error is not an object or carries no status\n */\nexport function extractStatus(err: unknown): number | undefined {\n if (!err || typeof err !== 'object') return undefined;\n\n const error = err as {\n status?: unknown;\n statusCode?: unknown;\n $metadata?: { httpStatusCode?: unknown };\n };\n\n if (typeof error.status === 'number') return error.status;\n if (typeof error.statusCode === 'number') return error.statusCode;\n if (typeof error.$metadata?.httpStatusCode === 'number') return error.$metadata.httpStatusCode;\n\n return undefined;\n}\n\n/**\n * POSIX/libuv error codes libuv (and so Node's `fetch`/undici) attaches to\n * genuine transport-level failures: connection refused, DNS lookup\n * failure, connection reset mid-request, a connect that never completed,\n * DNS server unreachable, broken pipe, or host/network unreachable.\n * Deliberately narrow: only codes that can only mean \"the connection\n * itself failed,\" not anything that could also indicate an application\n * error.\n */\nconst NETWORK_ERROR_CODES = new Set([\n 'ECONNREFUSED',\n 'ENOTFOUND',\n 'ECONNRESET',\n 'ETIMEDOUT',\n 'EAI_AGAIN',\n 'EPIPE',\n 'ECONNABORTED',\n 'EHOSTUNREACH',\n 'ENETUNREACH',\n]);\n\n/** `fetch`'s own wording for a transport-level failure, across runtimes/browsers. */\nconst NETWORK_ERROR_MESSAGES = new Set([\n 'fetch failed', // Node/undici\n 'failed to fetch', // Chromium\n 'load failed', // Safari\n 'networkerror when attempting to fetch resource.', // Firefox\n]);\n\n/**\n * Whether `error` is, with reasonable confidence, a transport-level\n * failure (never reached the provider, as opposed to the provider itself\n * responding with an error) rather than some other unexpected exception.\n * Checked via explicit, well-known signals only, so a genuinely unknown\n * error never gets misclassified as a connection failure just because it\n * also lacked an HTTP status.\n */\nfunction isNetworkError(error: unknown): boolean {\n if (!error || typeof error !== 'object') return false;\n\n const err = error as { code?: unknown; message?: unknown; cause?: unknown };\n\n if (typeof err.code === 'string' && NETWORK_ERROR_CODES.has(err.code)) return true;\n\n if (typeof err.message === 'string' && NETWORK_ERROR_MESSAGES.has(err.message.toLowerCase())) {\n return true;\n }\n\n // undici/Node's `fetch` wraps the real libuv error one level down, as\n // TypeError('fetch failed', { cause: <the real error, with .code> }).\n // The message check above already catches that wrapper by itself if\n // the cause is missing or unrecognized, this catches it by the cause's\n // code when the wrapper's own message wasn't matched (e.g. a runtime\n // that phrases the wrapper differently but still sets `cause.code`).\n if (err.cause && typeof err.cause === 'object') {\n const cause = err.cause as { code?: unknown };\n if (typeof cause.code === 'string' && NETWORK_ERROR_CODES.has(cause.code)) return true;\n }\n\n return false;\n}\n\nfunction formatSafely(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2) ?? String(value);\n } catch {\n try {\n return String(value);\n } catch {\n return '[unprintable error]';\n }\n }\n}\n\n/**\n * Looks inside an unknown thrown value and pulls out a human-readable\n * description of it. Checks the `error` field first (the provider's raw\n * rejection body, JSON-stringified if possible) then falls back to the\n * message` field. Always returns a safe string, even when the thrown value\n * has hostile properties or cannot be serialized normally.\n */\nexport function describeError(err: unknown): string {\n if (err && typeof err === 'object') {\n try {\n const error = err as { message?: unknown; error?: unknown };\n\n if (error.error !== undefined) {\n return formatSafely(error.error);\n }\n\n if (typeof error.message === 'string') {\n return error.message;\n }\n } catch {\n // Fall through to safe string.\n }\n }\n\n return formatSafely(err);\n}\n\n/**\n * Maps an HTTP status to its corresponding `LLMErrorCode`, derived purely\n * from the status itself so it applies the same way regardless of which\n * adapter or client raised the error. Used both when building a fresh\n * `LLMError` and when filling in a `code` on an already-normalized one\n * that doesn't have one yet, so the two paths can't drift apart.\n */\nfunction codeForStatus(status: number): LLMErrorCode | undefined {\n switch (status) {\n case 429:\n return 'provider_rate_limited';\n case 401:\n return 'authentication';\n case 403:\n return 'authorization';\n case 404:\n return 'not_found';\n case 413:\n return 'payload_too_large';\n default:\n return status >= 500 ? 'server_error' : undefined;\n }\n}\n\n/**\n * Whether a provider's error response actually contains anything a person\n * could act on. Some providers return a non-2xx status with **no body at\n * all** for certain field-validation failures (Mistral's OpenAI-compatible\n * endpoint does this, for example, when a request includes a field the\n * target model doesn't support). SDKs built on top of `openai` render that\n * specific case as a message like `\"400 status code (no body)\"`.\n *\n * Derived from the object's own `error`/`message` fields directly, rather\n * than from whatever `describeError` rendered, because `describeError`\n * falls back to serializing the *whole* thrown value when neither field is\n * present or meaningful. That fallback is local echo (e.g. just the\n * `status` a caller passed in), not provider diagnostic content, and\n * treating it as \"detail\" defeats the whole point of this check.\n */\nconst NO_BODY_MESSAGE_PATTERN = /\\(no body\\)/i;\n\nfunction isEmptyObject(value: object): boolean {\n return Object.keys(value).length === 0;\n}\n\nfunction hasNoDiagnosticDetail(error: unknown): boolean {\n if (error && typeof error === 'object') {\n const { error: errorField, message } = error as { error?: unknown; message?: unknown };\n\n // A present, non-null, non-empty `.error` is the provider's raw\n // structured error body, genuine diagnostic content whenever it's\n // present, regardless of how describeError ends up phrasing it.\n // `error: null`, `error: ''`, and `error: {}` are all placeholders,\n // not real content, and fall through to the message check below like\n // a missing field would.\n if (errorField !== undefined && errorField !== null) {\n const isEmptyString = typeof errorField === 'string' && errorField.trim().length === 0;\n const isEmptyStruct = typeof errorField === 'object' && isEmptyObject(errorField);\n\n if (!isEmptyString && !isEmptyStruct) {\n return false;\n }\n }\n\n if (typeof message === 'string') {\n const trimmed = message.trim();\n return trimmed.length === 0 || NO_BODY_MESSAGE_PATTERN.test(trimmed);\n }\n\n // Neither a meaningful `.error` nor a `.message` string: describeError\n // has nothing of the provider's own to report and falls back to\n // stringifying the whole object instead.\n return true;\n }\n\n // A non-object thrown value (string, number, etc.) has no `.error`/\n // `.message` fields to check at all.\n return true;\n}\n\n/**\n * Converts any thrown value into a well-typed LLMError. `attempts`, when\n * given, is the accumulated record of every attempt made before `error`\n * was thrown; it's passed straight into the constructed error's options\n * rather than assigned onto the error afterward, so `attempts` is always\n * settled once, through the constructor, like every other field on\n * `LLMError`.\n */\nexport function normalizeError(\n error: unknown,\n signal?: AbortSignal,\n attempts?: RetryAttempt[],\n): LLMError {\n if (signal?.aborted) {\n return new LLMError('LLM request aborted', 'aborted', { attempts });\n }\n\n if (error instanceof LLMError) {\n // A caller or adapter can throw an already-built LLMError directly\n // (bypassing the generic-SDK-error path below), so a status reaching\n // us this way still needs the same `code` a generic error with that\n // status gets, without overwriting a `code` that error already carries.\n if (error.code === undefined && error.status !== undefined) {\n error.code = codeForStatus(error.status);\n }\n\n // Same rule for `attempts`: fill it in if this already-built error\n // doesn't carry one of its own, without overwriting one it does.\n if (error.attempts === undefined && attempts !== undefined) {\n error.attempts = attempts;\n }\n\n return error;\n }\n\n const status = extractStatus(error);\n const retryAfterMs = extractRetryAfterMs(error);\n\n if (status !== undefined) {\n const description = describeError(error);\n\n // The generic \"LLM request failed\" message previously never carried\n // any of the detail describeError() already extracts (that function\n // was only ever used for debug logging, gated behind `debug: true`),\n // so a caught LLMError's own .message told you nothing beyond \"it\n // failed with this status,\" even when the provider's response did\n // include a real, readable description. Folding that description into\n // the thrown message means the detail is there unconditionally, not\n // only when debug logging happens to be on.\n const code = codeForStatus(status);\n\n // The \"probably an unsupported field/value\" guidance is only accurate\n // for statuses that don't already have a more specific, known meaning\n // (auth, rate limiting, not-found, payload-too-large, server errors);\n // for those, a no-body response is just a no-body response and the\n // field-validation explanation would be actively misleading.\n const isRequestValidationStatus = code === undefined;\n\n const message = hasNoDiagnosticDetail(error)\n ? isRequestValidationStatus\n ? `LLM request failed with status ${status} and no error detail from the provider. This usually means a field or value in the request isn't supported by the specific model (for example, a reasoning/thinking parameter the model doesn't accept), rather than a transport or auth problem.`\n : `LLM request failed with status ${status} and no error detail from the provider.`\n : `LLM request failed: ${description}`;\n\n return new LLMError(message, 'api', {\n status,\n cause: error,\n retryAfterMs,\n code,\n attempts,\n });\n }\n\n // No extractable HTTP status: distinguish a genuine transport-level\n // failure (DNS, connection refused, connection reset) from any other\n // unexpected exception via explicit signals only, rather than assuming\n // every status-less error reaching here is a connection failure.\n if (isNetworkError(error)) {\n return new LLMError('LLM request failed', 'network', {\n cause: error,\n retryAfterMs,\n code: 'connection_failed',\n attempts,\n });\n }\n\n return new LLMError('LLM request failed', 'unknown', { cause: error, retryAfterMs, attempts });\n}\n","/** Default `parseJson`: `JSON.parse` wrapped in try/catch, returning `undefined` on failure. */\nexport function defaultParseJson(content: string): unknown {\n try {\n return JSON.parse(content);\n } catch {\n return undefined;\n }\n}\n","import { LLMError } from '../../types/errors.js';\n\nimport type { LLMClient, WireToolCall } from '../../types/client.js';\nimport type { ToolCall, ToolDefinition } from '../../types/tools.js';\n\n/** Translates app-facing `ToolDefinition[]` into the OpenAI-shaped wire tools array. */\nexport function toWireTools(\n tools: ToolDefinition[],\n): NonNullable<Parameters<LLMClient['chat']['completions']['create']>[0]['tools']> {\n return tools.map((tool) => ({\n type: 'function' as const,\n function: {\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters,\n },\n }));\n}\n\n/** Translates app-facing `ToolCall[]` (e.g. from a replayed assistant turn) into wire tool_calls. */\nexport function toWireToolCalls(toolCalls: ToolCall[]): WireToolCall[] {\n return toolCalls.map((tc) => ({\n id: tc.id,\n type: 'function' as const,\n function: {\n name: tc.name,\n arguments: JSON.stringify(tc.arguments ?? {}),\n },\n }));\n}\n\n/**\n * Parses the provider's wire-shaped `tool_calls` back into VernLLM's\n * `ToolCall[]`. Malformed argument JSON is a `'parse'` error, same\n * convention as malformed JSON response bodies elsewhere in VernLLM.\n */\nexport function parseWireToolCalls(wireToolCalls: WireToolCall[]): ToolCall[] {\n return wireToolCalls.map((wc) => {\n let parsedArgs: unknown;\n\n try {\n parsedArgs = wc.function.arguments.trim() ? JSON.parse(wc.function.arguments) : {};\n } catch {\n throw new LLMError(`Invalid JSON arguments for tool call \"${wc.function.name}\"`, 'parse', {\n code: 'tool_arguments_parse_failed',\n });\n }\n\n return { id: wc.id, name: wc.function.name, arguments: parsedArgs };\n });\n}\n","import { LLMError } from '../../types/errors.js';\nimport { toWireTools, toWireToolCalls } from './wire.utils.js';\n\nimport type {\n AssistantContent,\n CallParams,\n ConversationTurn,\n WireMessage,\n WireToolChoice,\n} from '../../types/index.js';\n\n/**\n * Serializes `ConversationTurn` assistant content for the wire. Strings\n * pass through unchanged. Parsed JSON values are `JSON.stringify`'d.\n */\nfunction serializeAssistantContent(content: AssistantContent): string {\n return typeof content === 'string' ? content : JSON.stringify(content);\n}\n\n/** Everything `RequestBuilder` needs beyond a single call's own `CallParams`. */\nexport interface RequestBuilderOptions {\n model: string;\n defaultMaxTokens: number;\n defaultTemperature: number | null;\n defaultReasoningEffort?: 'minimal' | 'low' | 'medium' | 'high';\n defaultBudgetTokens?: number;\n /**\n * Whether the target client honors `response_format: { type: 'json_object' }`\n * as a real constraint (see `LLMClient.supportsJsonObjectMode`'s docs).\n * `true` for every built-in adapter except `fromAnthropic`/`fromBedrock`.\n */\n supportsJsonObjectMode: boolean;\n}\n\n/**\n * Builds the wire request object for one call, applying per-instance\n * defaults (model, max tokens, temperature) and per-call overrides.\n * Owns every check that depends only on the caller's own input shape, not\n * on execution: history alternation, duplicate/empty tool lists,\n * `toolChoice` naming a real tool. All deterministic on the call site's\n * own input and never touch the network, so every throw here is\n * `type: 'invalid_params'`, not `'validation'` (which is reserved for the\n * model/provider's own response failing a contract check). Has no\n * knowledge of retry, timeouts, or the breaker, only\n * the three defaults a `FallbackTarget` can override per-target (see the\n * `defaultMaxTokens`/`defaultTemperature` overrides in the fallback\n * design), which is what keeps it separable from `CallExecutor`.\n */\nexport class RequestBuilder {\n private readonly model: string;\n private readonly defaultMaxTokens: number;\n private readonly defaultTemperature: number | null;\n private readonly defaultReasoningEffort?: 'minimal' | 'low' | 'medium' | 'high';\n private readonly defaultBudgetTokens?: number;\n private readonly supportsJsonObjectMode: boolean;\n\n constructor(options: RequestBuilderOptions) {\n this.model = options.model;\n this.defaultMaxTokens = options.defaultMaxTokens;\n this.defaultTemperature = options.defaultTemperature;\n this.defaultReasoningEffort = options.defaultReasoningEffort;\n this.defaultBudgetTokens = options.defaultBudgetTokens;\n this.supportsJsonObjectMode = options.supportsJsonObjectMode;\n }\n\n /** Applies per-call defaults and shapes params into the client's request object. */\n build<T>(params: CallParams<T>) {\n const {\n systemPrompt,\n userContent,\n history = [],\n maxTokens = this.defaultMaxTokens,\n model = this.model,\n jsonSchema,\n tools,\n toolChoice,\n } = params;\n\n const temperature =\n params.temperature === undefined ? this.defaultTemperature : params.temperature;\n const reasoningEffort =\n params.reasoningEffort === undefined ? this.defaultReasoningEffort : params.reasoningEffort;\n const budgetTokens =\n params.budgetTokens === undefined ? this.defaultBudgetTokens : params.budgetTokens;\n\n if (tools && tools.length === 0) {\n throw new LLMError(\n '`tools` was an empty array. This is almost always a bug (e.g. a filtered tool list ' +\n 'that ended up empty). An empty `tools` array still switches on tool-call mode ' +\n '(response shape, jsonMode default, wire format) with nothing for the model to call. ' +\n 'Omit `tools` entirely for a normal call, or make sure the array is non-empty.',\n 'invalid_params',\n );\n }\n\n if (tools) {\n const seen = new Set<string>();\n const duplicates = new Set<string>();\n\n for (const tool of tools) {\n if (seen.has(tool.name)) duplicates.add(tool.name);\n seen.add(tool.name);\n }\n\n if (duplicates.size) {\n throw new LLMError(\n `\\`tools\\` has duplicate name(s): [${[...duplicates].join(', ')}]. Tool names must be unique.`,\n 'invalid_params',\n { code: 'duplicate_tool_names', issues: { names: [...duplicates] } },\n );\n }\n }\n\n if (toolChoice && !tools) {\n throw new LLMError(\n '`toolChoice` was set without `tools`. There is nothing for it to choose between. ' +\n 'Set `tools`, or remove `toolChoice`.',\n 'invalid_params',\n );\n }\n\n if (tools && typeof toolChoice === 'object' && !tools.some((t) => t.name === toolChoice.name)) {\n throw new LLMError(\n `toolChoice names \"${toolChoice.name}\", which is not in \\`tools\\` ([${tools.map((t) => t.name).join(', ')}]).`,\n 'invalid_params',\n {\n code: 'unknown_tool_choice',\n issues: { requested: toolChoice.name, available: tools.map((t) => t.name) },\n },\n );\n }\n\n // Defaults to false when tools are set and the caller didn't say otherwise,\n // since forcing a JSON response format alongside tool calling is unreliable\n // across providers.\n const jsonModeExplicit = params.jsonMode;\n const jsonMode = jsonModeExplicit ?? (tools ? false : true);\n\n // A client that can't honor `json_object` as a real constraint\n // (`supportsJsonObjectMode: false`, currently `fromAnthropic`/\n // `fromBedrock`) never receives it. An *explicit* `jsonMode: true`\n // still throws here, before the request ever reaches the client: the\n // caller asked for a guarantee this target can't provide, and staying\n // silent about that would be worse than the plain-text fallback below.\n if (!this.supportsJsonObjectMode && !jsonSchema && jsonModeExplicit === true) {\n throw new LLMError(\n 'jsonMode: true was set explicitly, but this client does not support ' +\n '`response_format: \"json_object\"` (see LLMClient.supportsJsonObjectMode). Neither ' +\n 'Anthropic nor Bedrock has a field that mechanically guarantees JSON output for this ' +\n 'mode. Use `jsonSchema` instead, which maps to a real constraint on both.',\n 'invalid_params',\n );\n }\n\n // `schema` needs JSON parsing to run against something, so a *default*\n // (unset) `jsonMode` here is a real, if implicit, request for JSON\n // output, not a caller who's indifferent to it. Downgrading it to\n // plain text the way a schema-less default call is downgraded below\n // would silently skip validation instead of running it, and then blame\n // it on a `jsonMode: false` the caller never actually set (see the\n // `params.schema && !useJson` check further down, whose message\n // assumes the caller chose `jsonMode: false`). Fail loudly instead,\n // before the request is sent, naming the real cause.\n if (\n !this.supportsJsonObjectMode &&\n !jsonSchema &&\n jsonModeExplicit === undefined &&\n params.schema\n ) {\n throw new LLMError(\n '`schema` was provided, which requires JSON output to validate against, but this client ' +\n 'does not support `response_format: \"json_object\"` (see LLMClient.supportsJsonObjectMode) ' +\n 'and no `jsonSchema` was set. Neither Anthropic nor Bedrock has a field that mechanically ' +\n 'guarantees JSON output without one. Use `jsonSchema` instead, which maps to a real ' +\n 'constraint on both and still runs `schema` against its parsed result.',\n 'invalid_params',\n );\n }\n\n // A *default* (unset) `jsonMode` with no `schema` to satisfy, which\n // resolves to `true` on every plain call with no `tools`, is silently\n // downgraded to plain text instead of throwing: this is what keeps\n // `llm.call({ userContent })` working out of the box on\n // Anthropic/Bedrock exactly as it did before `json_object` support was\n // removed from those two adapters, for anyone not relying on JSON\n // output they never actually asked for.\n const jsonModeEffective =\n !this.supportsJsonObjectMode && !jsonSchema && jsonModeExplicit === undefined\n ? false // downgrade: default jsonMode, no jsonSchema, no schema to validate either\n : jsonMode;\n\n const useJson = jsonModeEffective || Boolean(jsonSchema);\n\n if (params.schema && !useJson) {\n throw new LLMError(\n 'schema was provided but jsonMode: false disables JSON parsing, so nothing would validate it. Remove jsonMode: false, set jsonSchema, or remove schema.',\n 'invalid_params',\n );\n }\n\n const responseFormat = this.buildResponseFormat(jsonSchema, useJson);\n\n this.validateHistory(history);\n\n const request = {\n model,\n ...(temperature !== null ? { temperature } : {}),\n max_tokens: maxTokens,\n ...(responseFormat ? { response_format: responseFormat } : {}),\n ...(reasoningEffort ? { reasoning_effort: reasoningEffort } : {}),\n ...(budgetTokens !== undefined && budgetTokens !== null\n ? { budget_tokens: budgetTokens }\n : {}),\n ...(tools ? { tools: toWireTools(tools) } : {}),\n ...(tools ? { tool_choice: this.buildWireToolChoice(toolChoice) } : {}),\n messages: [\n ...(systemPrompt ? [{ role: 'system' as const, content: systemPrompt }] : []),\n ...history.flatMap((turn): WireMessage[] => this.turnToWireMessages(turn)),\n { role: 'user' as const, content: userContent },\n ] satisfies WireMessage[],\n };\n\n return { useJson, model, request };\n }\n\n /**\n * Validates `history` alternates user/assistant turns, since providers\n * like Anthropic/Gemini reject or mishandle consecutive same-role turns.\n */\n private validateHistory(history: ConversationTurn[]): void {\n let previousTurn: ConversationTurn | undefined;\n\n for (const [index, turn] of history.entries()) {\n if (turn.role === 'tool') {\n if (previousTurn?.role !== 'assistant' || !previousTurn.toolCalls?.length) {\n throw new LLMError(\n `history[${index}] is a \"tool\" turn, but must immediately follow an \"assistant\" turn that requested tools`,\n 'invalid_params',\n );\n }\n\n if (!turn.toolResults?.length) {\n throw new LLMError(\n `history[${index}] is a \"tool\" turn but has no toolResults`,\n 'invalid_params',\n );\n }\n\n const requestedIds = new Set(previousTurn.toolCalls.map((tc) => tc.id));\n const resultIds = turn.toolResults.map((tr) => tr.toolCallId);\n\n const unknownIds = resultIds.filter((id) => !requestedIds.has(id));\n\n if (unknownIds.length) {\n throw new LLMError(\n `history[${index}].toolResults references unknown toolCallId(s) [${unknownIds.join(', ')}]`,\n 'invalid_params',\n { code: 'unknown_tool_result_ids', issues: { historyIndex: index, ids: unknownIds } },\n );\n }\n\n // Catches a duplicated toolCallId that would otherwise mask a different call's missing result.\n const seenIds = new Set<string>();\n const duplicateIds = new Set<string>();\n\n for (const id of resultIds) {\n if (seenIds.has(id)) duplicateIds.add(id);\n seenIds.add(id);\n }\n\n if (duplicateIds.size) {\n throw new LLMError(\n `history[${index}].toolResults has duplicate toolCallId(s) [${[...duplicateIds].join(', ')}]`,\n 'invalid_params',\n {\n code: 'duplicate_tool_result_ids',\n issues: { historyIndex: index, ids: [...duplicateIds] },\n },\n );\n }\n\n const missingIds = [...requestedIds].filter((id) => !resultIds.includes(id));\n\n if (missingIds.length) {\n throw new LLMError(\n `history[${index}] is missing toolResults for toolCallId(s) [${missingIds.join(', ')}]`,\n 'invalid_params',\n { code: 'missing_tool_results', issues: { historyIndex: index, ids: missingIds } },\n );\n }\n } else {\n if (turn.role === previousTurn?.role) {\n throw new LLMError(\n `history must alternate user/assistant turns: consecutive \"${turn.role}\" turns at history[${index - 1}] and history[${index}]`,\n 'invalid_params',\n );\n }\n\n if (previousTurn?.role === 'assistant' && previousTurn.toolCalls?.length) {\n throw new LLMError(\n `history[${index}] follows an assistant tool request without tool results`,\n 'invalid_params',\n );\n }\n }\n\n previousTurn = turn;\n }\n\n if (previousTurn?.role === 'assistant' && previousTurn.toolCalls?.length) {\n throw new LLMError(\n 'The last entry in history is an assistant tool request without tool results',\n 'invalid_params',\n );\n }\n\n if (previousTurn?.role === 'user') {\n throw new LLMError(\n 'The last entry in history is a \"user\" turn, which would collide with the current userContent turn.',\n 'invalid_params',\n );\n }\n }\n\n /** Maps VernLLM's app-facing `ToolChoice` onto the OpenAI-shaped wire `tool_choice`. */\n private buildWireToolChoice(toolChoice: CallParams<unknown>['toolChoice']): WireToolChoice {\n if (!toolChoice || toolChoice === 'auto') return 'auto';\n if (toolChoice === 'none' || toolChoice === 'required') return toolChoice;\n\n return { type: 'function', function: { name: toolChoice.name } };\n }\n\n /**\n * Expands one `ConversationTurn` into one or more wire messages. Plain\n * user/assistant turns map 1:1. An assistant turn with `toolCalls` maps\n * to an assistant message carrying wire-shaped `tool_calls`. A `'tool'`\n * turn expands into one wire `tool` message per `toolResult`, since\n * OpenAI-shaped wire format wants one message per tool_call_id.\n */\n private turnToWireMessages(turn: ConversationTurn): WireMessage[] {\n if (turn.role === 'tool') {\n return (turn.toolResults ?? []).map((tr) => ({\n role: 'tool' as const,\n tool_call_id: tr.toolCallId,\n content: typeof tr.content === 'string' ? tr.content : JSON.stringify(tr.content ?? null),\n ...(tr.isError ? { is_error: true } : {}),\n }));\n }\n\n if (turn.role === 'assistant' && turn.toolCalls?.length) {\n return [\n {\n role: 'assistant' as const,\n ...(turn.content !== undefined\n ? { content: serializeAssistantContent(turn.content) }\n : {}),\n tool_calls: toWireToolCalls(turn.toolCalls),\n },\n ];\n }\n\n if (turn.role === 'assistant') {\n return [\n {\n role: 'assistant' as const,\n content: serializeAssistantContent(turn.content === undefined ? '' : turn.content),\n },\n ];\n }\n\n return [{ role: turn.role as 'user', content: turn.content ?? '' }];\n }\n\n /**\n * Chooses the response format: a provider-native `jsonSchema` takes\n * priority when supplied (constrains generation directly), otherwise\n * falls back to the looser `json_object` mode when JSON output is\n * requested, or no format at all for plain text responses.\n */\n private buildResponseFormat(jsonSchema: CallParams<unknown>['jsonSchema'], useJson: boolean) {\n if (jsonSchema) {\n return {\n type: 'json_schema' as const,\n json_schema: {\n name: jsonSchema.name,\n schema: jsonSchema.schema,\n strict: jsonSchema.strict ?? true,\n description: jsonSchema.description,\n },\n };\n }\n\n return useJson ? { type: 'json_object' as const } : undefined;\n }\n}\n","import { normalizeError } from './errors.utils.js';\nimport { withChunkIdleTimeout } from './retry.utils.js';\n\nimport type { Logger } from '../../logger.js';\nimport type { LLMError } from '../../types/errors.js';\nimport type {\n CallWithToolsResult,\n StreamChunk,\n TokenUsage,\n WireStreamChunk,\n WireToolCall,\n} from '../../types/index.js';\n\n/** Everything `buildStreamResult` needs beyond the raw iterator and first chunk. */\nexport interface StreamAccumulatorOptions<T> {\n requestId: string;\n model: string;\n providerName: string;\n /** Whether this attempt ran on a fallback target rather than the primary, mirroring `extractUsage`'s `usedFallback`. */\n isFallback: boolean;\n /** Per-call override, falling back to the instance default, mirroring every other per-call timeout. */\n chunkIdleTimeoutMs: number | undefined;\n streamController: AbortController;\n logger: Logger;\n /** External signal, forwarded to `normalizeError` so a transport error during an already-aborted call is reported as `'aborted'`, not whatever the transport itself threw. */\n signal?: AbortSignal;\n /**\n * Fires once, synchronously, right after the transport-level loop\n * finishes successfully, before `finalize` runs. Lets the caller record\n * circuit-breaker success and release rate-limiter capacity before the\n * (possibly failing) finalization step.\n */\n onStreamSuccess: (usage: TokenUsage | undefined) => void;\n /**\n * Fires once when the transport-level loop itself fails (idle timeout\n * or a transport error), before this stream's `finalResult` rejects.\n * `normalized.type === 'timeout'` is the one mid-stream failure that\n * should trip the breaker: otherwise a provider that hangs after one\n * chunk would always record a success and never open it.\n */\n onStreamFailure: (normalized: LLMError, usage: TokenUsage | undefined) => void;\n /**\n * Produces the final `T | CallWithToolsResult<T>` from the accumulated\n * text and tool-call deltas once the stream completes. Errors thrown\n * here are assumed already normalized and usage-failure-reported by the\n * caller (mirrors `finalizeResponse`'s own contract).\n */\n finalize: (\n textAcc: string,\n wireToolCalls: WireToolCall[] | undefined,\n usage: TokenUsage | undefined,\n ) => T | CallWithToolsResult<T>;\n}\n\n/**\n * The streaming accumulator: wraps the raw `WireStreamChunk` iterator in\n * an async generator that yields translated `StreamChunk`s to the caller\n * live, as they arrive, with no per-chunk timeout and no bound on total\n * duration, and accumulates text/tool-call deltas internally so that\n * `finalize` can produce `finalResult` once the stream completes.\n *\n * Two separate try/catches: the iteration loop's catch handles errors\n * the transport itself throws, which aren't normalized yet, so that\n * happens here, alongside the one `onStreamFailure` call for them. The\n * second catch, around `finalize`, does not re-normalize or re-report,\n * since `finalize`'s caller (`finalizeResponse`) already does both\n * internally.\n */\nexport function buildStreamResult<T>(\n iterator: AsyncIterator<WireStreamChunk>,\n first: IteratorResult<WireStreamChunk>,\n options: StreamAccumulatorOptions<T>,\n): { chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T | CallWithToolsResult<T>> } {\n const {\n requestId,\n model,\n providerName,\n isFallback,\n chunkIdleTimeoutMs,\n streamController,\n logger,\n signal,\n } = options;\n\n let resolveFinal!: (value: T | CallWithToolsResult<T>) => void;\n let rejectFinal!: (error: unknown) => void;\n\n const finalResult = new Promise<T | CallWithToolsResult<T>>((resolve, reject) => {\n resolveFinal = resolve;\n rejectFinal = reject;\n });\n\n // Avoid an unhandled-rejection warning for callers that only read `chunks`.\n finalResult.catch(() => {});\n\n // Push-based, not a pulled generator, so the pump always drives\n // `finalResult` to completion even if `chunks` is never read. Buffer\n // size (not \"has anyone started iterating yet\") is what caps memory,\n // since the pump can outrace the caller starting iteration.\n const MAX_BUFFERED_CHUNKS = 10_000;\n const buffered: StreamChunk[] = [];\n const pending: Array<{\n resolve: (result: IteratorResult<StreamChunk>) => void;\n reject: (error: unknown) => void;\n }> = [];\n let streamDone = false;\n let streamError: unknown;\n let hasLoggedEviction = false;\n\n const push = (chunk: StreamChunk) => {\n const waiter = pending.shift();\n\n if (waiter) {\n waiter.resolve({ done: false, value: chunk });\n return;\n }\n\n buffered.push(chunk);\n\n if (buffered.length > MAX_BUFFERED_CHUNKS * 2) {\n // Nothing else surfaces this: without a log, a caller that never\n // read (or fell behind on) `chunks` has no way to tell eviction,\n // not a provider or transport bug, is why chunks are missing.\n // Logged once per stream, not on every crossing, so an ignored\n // high-volume stream doesn't spam dozens of near-identical lines.\n if (!hasLoggedEviction) {\n hasLoggedEviction = true;\n logger.warn(\n `[VernLLM] stream chunk buffer exceeded cap (${MAX_BUFFERED_CHUNKS}), evicting ` +\n `${buffered.length - MAX_BUFFERED_CHUNKS} oldest chunk(s); buffered=${buffered.length}. ` +\n 'The chunks iterable was never read (or fell far behind) for this stream.',\n );\n }\n\n // Trim back down to the cap in one batch operation instead of\n // `shift()`ing a single element off on every push once the cap is\n // reached. A per-push `shift()` here is O(current length) in the\n // worst case, cheap for a handful of calls, but that cost is\n // paid on *every* push for the remainder of an ignored stream,\n // and its real-world cost isn't a stable, engine-independent\n // property: benchmarking this exact pattern at a similar backing\n // -array size showed multi-second stalls for what should be\n // sub-millisecond work. Letting the array grow to 2x the cap\n // before trimming amortizes the O(n) `splice` across\n // `MAX_BUFFERED_CHUNKS` pushes, so the average cost per push\n // stays O(1) regardless of how far past the cap the array is\n // allowed to grow before trimming.\n buffered.splice(0, buffered.length - MAX_BUFFERED_CHUNKS);\n }\n };\n\n const finish = () => {\n streamDone = true;\n\n for (const waiter of pending.splice(0)) {\n waiter.resolve({ done: true, value: undefined });\n }\n };\n\n const fail = (error: unknown) => {\n streamDone = true;\n streamError = error;\n\n for (const waiter of pending.splice(0)) {\n waiter.reject(error);\n }\n };\n\n const chunks: AsyncIterable<StreamChunk> = {\n [Symbol.asyncIterator]() {\n return {\n next(): Promise<IteratorResult<StreamChunk>> {\n if (buffered.length) {\n return Promise.resolve({ done: false, value: buffered.shift() as StreamChunk });\n }\n\n if (streamDone) {\n return streamError\n ? Promise.reject(streamError)\n : Promise.resolve({ done: true, value: undefined });\n }\n\n return new Promise((resolve, reject) => {\n pending.push({ resolve, reject });\n });\n },\n };\n },\n };\n\n const toolCallAcc = new Map<number, { id?: string; name?: string; args: string }>();\n\n let textAcc = '';\n let usage: TokenUsage | undefined;\n\n // Fires immediately, not lazily, so it always drives finalResult to\n // completion regardless of whether the caller reads chunks.\n void (async () => {\n try {\n let result: IteratorResult<WireStreamChunk> = first;\n\n while (!result.done) {\n const wireChunk = result.value;\n\n if (wireChunk.type === 'ping') {\n // No content to accumulate or push. Just resolving here\n // resets the idle-timeout clock on the next .next() call.\n } else if (wireChunk.type === 'text-delta') {\n textAcc += wireChunk.delta;\n push({ type: 'text-delta', delta: wireChunk.delta });\n } else if (wireChunk.type === 'tool_call_delta') {\n const entry = toolCallAcc.get(wireChunk.index) ?? { args: '' };\n\n entry.id ??= wireChunk.id;\n entry.name ??= wireChunk.name;\n entry.args += wireChunk.argumentsDelta ?? '';\n toolCallAcc.set(wireChunk.index, entry);\n\n push({\n type: 'tool_call_delta',\n index: wireChunk.index,\n id: wireChunk.id,\n name: wireChunk.name,\n argsDelta: wireChunk.argumentsDelta,\n complete: wireChunk.complete,\n });\n } else if (wireChunk.type === 'usage') {\n const reasoningTokens = wireChunk.usage.completion_tokens_details?.reasoning_tokens;\n\n usage = {\n promptTokens: wireChunk.usage.prompt_tokens ?? 0,\n completionTokens: wireChunk.usage.completion_tokens ?? 0,\n totalTokens: wireChunk.usage.total_tokens ?? 0,\n ...(reasoningTokens !== undefined ? { reasoningTokens } : {}),\n requestId,\n model,\n provider: providerName,\n usedFallback: isFallback,\n };\n push({ type: 'usage', usage });\n }\n\n result = await withChunkIdleTimeout(\n () => iterator.next(),\n chunkIdleTimeoutMs,\n () => streamController.abort(),\n logger,\n );\n }\n } catch (error) {\n // Best-effort cleanup for a processing-time throw (as opposed to\n // `iterator.next()` rejecting, which usually means the adapter's\n // own generator already cleaned up). Two independent layers,\n // since neither is guaranteed to reach every SDK on its own:\n //\n // 1. `iterator.return()`: `iterator` is the async generator\n // returned by the adapter's `createStream`, and every\n // adapter's `createStream` body is a `for await...of` over\n // the SDK's raw stream. Calling `.return()` on a generator\n // suspended inside a `for await...of` forwards `.return()` to\n // the iterable being iterated, standard IteratorClose\n // behavior, so this one call closes the whole chain down to\n // the SDK's own stream, as long as the SDK's stream\n // implements `.return()` (true for every adapter here, see\n // the \"propagates .return()\" test in each adapter's stream\n // unit tests).\n // 2. `streamController.abort()`: aborts the same signal every\n // adapter received for this call. SDKs that honor an\n // AbortSignal for the life of the request, arguably the more\n // common pattern than implementing custom `.return()`\n // forwarding, get closed this way even if layer 1 has nothing\n // to forward to.\n try {\n await iterator.return?.();\n } catch {\n // Cleanup failing isn't the error being reported; swallow it.\n }\n streamController.abort();\n\n const normalized = normalizeError(error, signal);\n\n try {\n options.onStreamFailure(normalized, usage);\n } catch {\n // A throwing callback must not stop fail/rejectFinal from settling\n // the promises below; the stream failure itself is still reported.\n }\n\n fail(normalized);\n rejectFinal(normalized);\n\n return;\n }\n\n finish();\n\n try {\n options.onStreamSuccess(usage);\n } catch {\n // A throwing callback must not stop finalize/resolveFinal below from\n // running; the stream itself still completed successfully.\n }\n\n try {\n const wireToolCalls: WireToolCall[] | undefined = toolCallAcc.size\n ? [...toolCallAcc.entries()]\n .sort(([indexA], [indexB]) => indexA - indexB)\n .map(([, entry]) => ({\n id: entry.id ?? '',\n type: 'function' as const,\n function: { name: entry.name ?? '', arguments: entry.args },\n }))\n : undefined;\n\n const finalized = options.finalize(textAcc, wireToolCalls, usage);\n\n resolveFinal(finalized);\n } catch (error) {\n // finalize's caller has already normalized this error and\n // reported the usage failure internally. Just propagate it.\n rejectFinal(error);\n }\n })();\n\n return { chunks, finalResult };\n}\n","import { CircuitBreaker } from '../../circuitBreaker.js';\nimport { LLMError, toRequestSnapshot, type LLMRequestSnapshot } from '../../types/errors.js';\nimport { makeEventReporter } from '../circuitBreaker.utils.js';\nimport { describeError, extractStatus, normalizeError } from './errors.utils.js';\nimport { defaultParseJson } from './parse.utils.js';\nimport { RequestBuilder } from './requestBuilder.js';\nimport { extractRetryAfterMs, getBackoffDelay, waitForRetry, withTimeout } from './retry.utils.js';\nimport { buildStreamResult } from './streamAccumulator.js';\nimport { parseWireToolCalls } from './wire.utils.js';\n\nimport type { Logger } from '../../logger.js';\nimport type { RateLimiter } from '../../rateLimit.js';\nimport type {\n CallParams,\n CallWithToolsResult,\n LLMClient,\n RetryAttempt,\n StreamChunk,\n TokenUsage,\n ToolIssue,\n VernLLMEvent,\n WireToolCall,\n} from '../../types/index.js';\n\n/**\n * `executeCall`/`executeStreamCall` call `onRequest` with a fully built\n * `LLMRequestSnapshot`, right after the outgoing payload is built and\n * before dispatch (rate limiting, `client.chat.completions.create`, etc).\n * Building the complete, cloned snapshot at this point, not later once an\n * attempt has failed, matters for two reasons: `startedAt` should mean\n * \"when the attempt started\", not \"when the failure was handled\", and\n * some adapters mutate the outgoing request object during dispatch itself\n * (e.g. `fromGemini` sets `request.config` in place inside `create()`),\n * so waiting until the catch block to snapshot could capture a payload\n * that had already changed since it was actually sent.\n */\ntype OnRequest = (snapshot: LLMRequestSnapshot) => void;\n\n/**\n * Identity function with its own parameter, used only to sidestep a TS\n * quirk: a `let` reassigned solely inside a nested closure (like\n * `retryWithBackoff`'s `onRequest`) gets narrowed to `undefined` at the\n * point it was last synchronously assigned, which would otherwise make\n * `lastRequestForAttempt` read as `never` at the point it's used below.\n */\nfunction passThroughRequestSnapshot(\n snapshot: LLMRequestSnapshot | undefined,\n): LLMRequestSnapshot | undefined {\n return snapshot;\n}\n\n/** Everything one `CallExecutor` needs beyond the client and model. */\nexport interface CallExecutorOptions {\n maxRetries: number;\n timeoutMs: number;\n chunkIdleTimeoutMs: number;\n baseDelayMs: number;\n defaultMaxTokens: number;\n defaultTemperature: number | null;\n defaultReasoningEffort?: 'minimal' | 'low' | 'medium' | 'high';\n defaultBudgetTokens?: number;\n nonRetryableStatus: number[];\n parseJson?: (content: string) => unknown;\n logger: Logger;\n /** Applied to model output before it reaches the debug logger. See `VernLLMOptions.redact`. */\n redact?: (text: string) => string;\n onUsage?: (usage: TokenUsage) => void;\n onUsageFailure?: (usage: TokenUsage, error: LLMError) => void;\n onEvent?: (event: VernLLMEvent) => void;\n breaker?: CircuitBreaker;\n limiter?: RateLimiter;\n /** True for every target after the primary. Stamped onto reported `TokenUsage`. */\n isFallback?: boolean;\n}\n\n/**\n * Everything one provider target needs to attempt a call: request\n * building, retry with backoff, the per-target breaker, the per-target\n * limiter. Never exported publicly. `VernLLM` holds one per target and\n * owns the fallback loop and caching on top.\n */\nexport class CallExecutor {\n private readonly maxRetries: number;\n private readonly timeoutMs: number;\n private readonly chunkIdleTimeoutMs: number;\n private readonly baseDelayMs: number;\n private readonly nonRetryableStatus: number[];\n private readonly parseJson: (content: string) => unknown;\n private readonly logger: Logger;\n private readonly redact?: (text: string) => string;\n private readonly onUsage?: (usage: TokenUsage) => void;\n private readonly onUsageFailure?: (usage: TokenUsage, error: LLMError) => void;\n private readonly reportEvent: (event: VernLLMEvent) => void;\n private readonly breaker?: CircuitBreaker;\n private readonly limiter?: RateLimiter;\n private readonly isFallback: boolean;\n private readonly requestBuilder: RequestBuilder;\n\n constructor(\n readonly providerName: string,\n private readonly client: LLMClient,\n readonly model: string,\n options: CallExecutorOptions,\n ) {\n this.maxRetries = options.maxRetries;\n this.timeoutMs = options.timeoutMs;\n this.chunkIdleTimeoutMs = options.chunkIdleTimeoutMs;\n this.baseDelayMs = options.baseDelayMs;\n this.nonRetryableStatus = options.nonRetryableStatus;\n this.parseJson = options.parseJson ?? defaultParseJson;\n this.logger = options.logger;\n this.redact = options.redact;\n this.onUsage = options.onUsage;\n this.onUsageFailure = options.onUsageFailure;\n this.reportEvent = makeEventReporter(options.onEvent, this.logger);\n this.breaker = options.breaker;\n this.limiter = options.limiter;\n this.isFallback = options.isFallback ?? false;\n this.requestBuilder = new RequestBuilder({\n model,\n defaultMaxTokens: options.defaultMaxTokens,\n defaultTemperature: options.defaultTemperature,\n defaultReasoningEffort: options.defaultReasoningEffort,\n defaultBudgetTokens: options.defaultBudgetTokens,\n supportsJsonObjectMode: client.supportsJsonObjectMode ?? true,\n });\n }\n\n getCircuitState(model?: string) {\n return this.breaker?.getState(model);\n }\n\n /** Whether this target's breaker tracks failures per model. `false` if no breaker is configured. */\n get isolateByModel(): boolean {\n return this.breaker?.isolateByModel ?? false;\n }\n\n /** Manually opens this target's circuit breaker, if one is configured. No-op otherwise. */\n openCircuit(model?: string): void {\n this.breaker?.open(model);\n }\n\n /** Manually closes this target's circuit breaker, if one is configured. No-op otherwise. */\n closeCircuit(model?: string): void {\n this.breaker?.close(model);\n }\n\n /**\n * Throws if the breaker is open for this target/model, exactly like the\n * check `run`/`runStream` used to make internally. Exposed so `VernLLM`\n * can gate on it before reserving usage, avoiding a reserve-then-refund\n * round trip on a call that was never going to be attempted. `assertClosed`\n * has a stateful side effect (claiming a half-open trial slot), so it must\n * run exactly once per logical call: `run`/`runStream` no longer call it\n * themselves, this is now the only call site.\n */\n assertBreakerClosed(model?: string): void {\n this.breaker?.assertClosed(model ?? this.model);\n }\n\n /**\n * Runs a single logical call against this target: retry with backoff,\n * normalized error on exhaustion. Mirrors the old `VernLLM.call`'s\n * non-streaming branch, minus cache/usage-reservation and the breaker\n * check, which stay one layer up since they aren't per-target concerns\n * (see `assertBreakerClosed`).\n */\n async run<T>(\n params: CallParams<T>,\n requestId: string,\n onAttempt?: () => void,\n ): Promise<T | CallWithToolsResult<T>> {\n const model = params.model ?? this.model;\n const attempts: RetryAttempt[] = [];\n\n try {\n return await this.retryWithBackoff(\n (attempt, onRequest) => this.executeCall(params, requestId, attempt, onRequest),\n requestId,\n model,\n params.signal,\n onAttempt,\n attempts,\n );\n } catch (error) {\n // `attempts` only holds prior attempts that were actually retried\n // past. It's `[]` when nothing was retried, so normalize that to\n // `undefined` per `LLMError.attempts`'s contract.\n const normalized = normalizeError(\n error,\n params.signal,\n attempts.length > 0 ? attempts : undefined,\n );\n\n if (this.countsTowardBreaker(normalized)) {\n this.breaker?.recordFailure(model);\n }\n\n this.logger.debug(`[VernLLM:${requestId}] error:\\n${this.redactText(describeError(error))}`);\n\n throw normalized;\n }\n }\n\n /** Streaming counterpart to `run`. Mirrors the old streaming branch of `VernLLM.call`. */\n async runStream<T>(\n params: CallParams<T>,\n requestId: string,\n onAttempt?: () => void,\n ): Promise<{\n chunks: AsyncIterable<StreamChunk>;\n finalResult: Promise<T | CallWithToolsResult<T>>;\n }> {\n const model = params.model ?? this.model;\n const attempts: RetryAttempt[] = [];\n\n try {\n return await this.retryWithBackoff(\n (attempt, onRequest) => this.executeStreamCall(params, requestId, attempt, onRequest),\n requestId,\n model,\n params.signal,\n onAttempt,\n attempts,\n );\n } catch (error) {\n // See the matching comment in `run`.\n const normalized = normalizeError(\n error,\n params.signal,\n attempts.length > 0 ? attempts : undefined,\n );\n\n if (this.countsTowardBreaker(normalized)) {\n this.breaker?.recordFailure(model);\n }\n\n this.logger.debug(\n `[VernLLM:${requestId}] stream-open error:\\n${this.redactText(describeError(error))}`,\n );\n\n throw normalized;\n }\n }\n\n /**\n * Performs a single attempt: builds the request (translating `tools` to\n * wire shape when present), dispatches it with a timeout, and shapes the\n * response into `T` or a `CallWithToolsResult<T>` when `params.tools` was\n * set. Throws on an empty response (no text and no tool_calls) so the\n * retry loop treats it like any other transient failure.\n */\n private async executeCall<T>(\n params: CallParams<T>,\n requestId: string,\n attempt: number,\n onRequest?: OnRequest,\n ): Promise<T | CallWithToolsResult<T>> {\n const { useJson, model, request } = this.requestBuilder.build(params);\n\n onRequest?.(toRequestSnapshot(this.providerName, model, request, undefined, Date.now()));\n\n // A retry is a real request, so capacity is acquired per attempt\n // (inside the retry loop, via `executeCall` being re-invoked), not\n // once for the whole call.\n let release: ((actualTokens?: number) => void) | undefined;\n\n if (this.limiter) {\n const acquired = await this.limiter.acquire(this.limiter.estimate(request), params.signal);\n release = acquired.release;\n\n if (acquired.waitedMs > 0) {\n this.reportEvent({\n kind: 'rate_limited',\n requestId,\n provider: this.providerName,\n model,\n waitedMs: acquired.waitedMs,\n reason: acquired.reason ?? 'rpm',\n });\n }\n }\n\n try {\n const response = await withTimeout(\n (attemptSignal) => this.client.chat.completions.create(request, { signal: attemptSignal }),\n this.timeoutMs,\n params.signal,\n );\n\n // Extracted right after the response arrives, before anything else\n // touches it, so a post-response failure still gets its usage reported.\n const usage = this.extractUsage(response, requestId, model);\n\n // Reconcile against real usage, then hand off so `finally` below\n // can't release a second time.\n release?.(this.actualTokensFor(usage));\n release = undefined;\n\n // Raw and unvalidated on purpose. Extraction (including `.trim()`,\n // which throws on a non-string `content`) happens inside\n // `finalizeResponse`'s try/catch, so a malformed response still gets\n // normalized and its usage failure reported.\n const rawContent = response.choices?.[0]?.message?.content;\n const wireToolCalls = response.choices?.[0]?.message?.tool_calls;\n\n return this.finalizeResponse(\n rawContent,\n wireToolCalls,\n params,\n useJson,\n model,\n usage,\n requestId,\n attempt,\n );\n } finally {\n release?.();\n }\n }\n\n /** Applies `redact` (if configured); otherwise returns `text` unchanged. */\n private redactText(text: string): string {\n return this.redact ? this.redact(text) : text;\n }\n\n /**\n * Applies `redact` (if configured) to whatever the debug log is about\n * to show: real content when there is any, otherwise the tool-call\n * placeholder, which carries no user data and passes through\n * `redact` unchanged in practice but is included for a caller whose\n * `redact` does something structural (e.g. adding a marker) rather\n * than just scrubbing PII.\n */\n private redactedOutput(\n content: string | undefined,\n wireToolCalls: WireToolCall[] | undefined,\n ): string {\n return this.redactText(content ?? `[${wireToolCalls?.length ?? 0} tool call(s)]`);\n }\n\n /**\n * Shapes a fully-arrived response (content and/or tool_calls, already\n * extracted from the provider's payload) into `T` or a\n * `CallWithToolsResult<T>`. Reused by the streaming path once it has\n * buffered the full text/tool-call deltas, so there's no separate\n * parsing/validation logic for streaming.\n *\n * Normalizes and reports usage failure on error itself, so every caller\n * gets identical error handling without duplicating it.\n */\n private finalizeResponse<T>(\n rawContent: string | null | undefined,\n wireToolCalls: WireToolCall[] | undefined,\n params: CallParams<T>,\n useJson: boolean,\n model: string,\n usage: TokenUsage | undefined,\n requestId: string,\n attempt: number,\n ): T | CallWithToolsResult<T> {\n try {\n // `.trim()` runs inside this try: a malformed response shape\n // (e.g. a non-string `content`) throws here and is normalized and\n // reported like any other post-response failure.\n const content = rawContent?.trim();\n\n if (!content && !wireToolCalls?.length) {\n throw new LLMError('Empty LLM response', 'api', { code: 'empty_response' });\n }\n\n this.logger.debug(\n `[VernLLM:${requestId}] output:\\n${this.redactedOutput(content, wireToolCalls).slice(0, 800)}`,\n );\n\n if (wireToolCalls?.length) {\n if (!params.tools) {\n // Same class of problem as the other tool-contract codes below:\n // a provider contract violation, not an HTTP failure, so this is\n // `type: 'validation'` rather than `'api'`. Byte-for-byte\n // identical on retry, so not retryable.\n throw new LLMError(\n 'Provider returned tool_calls but no `tools` were sent with this call.',\n 'validation',\n { code: 'unexpected_tool_calls' },\n );\n }\n\n if (params.toolChoice === 'none') {\n // `toolChoice: 'none'` is what lets `call()`'s type narrow to\n // `ContentResult<T>` (see `ToolsDisabledCallParams`). A\n // nonconforming provider/adapter returning tool_calls anyway\n // would silently break that guarantee for the caller, so this\n // is treated as a hard API-contract violation rather than\n // passed through as a normal tool_calls result. The request\n // itself is byte-for-byte identical on retry, so this repeats\n // deterministically like the other tool-contract failures\n // below: not retryable, and not the provider being unhealthy.\n throw new LLMError(\n \"Provider returned tool_calls despite toolChoice: 'none'.\",\n 'validation',\n {\n code: 'tool_choice_none_violated',\n },\n );\n }\n\n const toolCalls = parseWireToolCalls(wireToolCalls);\n\n this.validateToolCallArguments(toolCalls, params.tools);\n this.breaker?.recordSuccess(model);\n this.reportUsage(usage);\n\n return { type: 'tool_calls', toolCalls, ...(content ? { content } : {}) };\n }\n\n // No tool_calls here, so content must be present.\n const textContent = content ?? '';\n\n if (!useJson) {\n this.breaker?.recordSuccess(model);\n this.reportUsage(usage);\n\n return params.tools ? { type: 'content', content: textContent as T } : (textContent as T);\n }\n\n const result = this.parseAndValidate<T>(textContent, params.schema);\n this.breaker?.recordSuccess(model);\n this.reportUsage(usage);\n\n return params.tools ? { type: 'content', content: result } : result;\n } catch (error) {\n // Normalized first so onUsageFailure always gets a real LLMError.\n // Also covers aborted signals: normalizeError returns type\n // 'aborted' in that case.\n const normalized = normalizeError(error, params.signal);\n\n if (usage && normalized.type !== 'aborted') {\n this.reportUsageFailure(usage, normalized, attempt);\n }\n\n throw normalized;\n }\n }\n\n /**\n * Opens a stream for a single attempt: builds the request exactly like\n * `executeCall`, then requires `createStream` on the client (a clear\n * `validation` error if the adapter doesn't support it). The timeout\n * wraps stream construction and the first `.next()` together, not just\n * construction: calling an `async function*` returns an iterator\n * synchronously without running its body until `.next()` is first\n * invoked, so timing only construction would time an operation that's\n * always instant, not the actual connection. Both are folded into a\n * single `withTimeout` so the same abort signal reaches whatever the\n * adapter's `createStream` uses internally for its first network\n * round-trip.\n *\n * Circuit-breaker success is recorded once the stream fully completes,\n * not on the first chunk arriving, so a connection that opens but then\n * dies mid-stream isn't masked as a success (see `buildStreamResult`).\n */\n private async executeStreamCall<T>(\n params: CallParams<T>,\n requestId: string,\n attempt: number,\n onRequest?: OnRequest,\n ): Promise<{\n chunks: AsyncIterable<StreamChunk>;\n finalResult: Promise<T | CallWithToolsResult<T>>;\n }> {\n const { useJson, model, request } = this.requestBuilder.build(params);\n\n onRequest?.(toRequestSnapshot(this.providerName, model, request, undefined, Date.now()));\n\n const completions = this.client.chat.completions;\n\n if (!completions.createStream) {\n throw new LLMError(\n 'stream: true requires a client/adapter with createStream',\n 'invalid_params',\n {\n code: 'unsupported_capability',\n issues: { capability: 'createStream' },\n },\n );\n }\n\n const createStream = completions.createStream.bind(completions);\n\n // A stream holds a real connection for its whole life, so its\n // capacity is released on completion (in `buildStreamResult`), not\n // once opening succeeds.\n let release: ((actualTokens?: number) => void) | undefined;\n\n if (this.limiter) {\n const acquired = await this.limiter.acquire(this.limiter.estimate(request), params.signal);\n release = acquired.release;\n\n if (acquired.waitedMs > 0) {\n this.reportEvent({\n kind: 'rate_limited',\n requestId,\n provider: this.providerName,\n model,\n waitedMs: acquired.waitedMs,\n reason: acquired.reason ?? 'rpm',\n });\n }\n }\n\n // One controller for the entire stream, not just opening it. Adapters\n // already thread this signal into their transport for the life of the\n // request (that's how user-initiated cancellation works today), so\n // reusing it for the idle timeout means the same abort() call that\n // fires when the stream goes idle mid-way also tears down the\n // underlying connection, instead of only rejecting VernLLM's own\n // promise while the transport stays open.\n const streamController = new AbortController();\n const combinedExternal = params.signal\n ? AbortSignal.any([params.signal, streamController.signal])\n : streamController.signal;\n\n try {\n const { iterator, first } = await withTimeout(\n async (attemptSignal) => {\n const streamIterator = createStream(request, { signal: attemptSignal })[\n Symbol.asyncIterator\n ]();\n const firstResult = await streamIterator.next();\n\n return { iterator: streamIterator, first: firstResult };\n },\n this.timeoutMs,\n combinedExternal,\n );\n\n // An immediately-exhausted stream (no chunks at all) is the streaming\n // equivalent of `executeCall`'s empty-response check: surface the same\n // `LLMError('Empty LLM response', 'api')` so retry behaves identically\n // whether the empty result came from a non-streaming or streaming\n // attempt.\n if (first.done) {\n throw new LLMError('Empty LLM response', 'api');\n }\n\n // Snapshotted before the closures below are created, since `release`\n // (the outer variable) is reassigned to undefined right after this\n // call to hand ownership off. The callbacks only run later, once the\n // stream completes, so closing over the mutable variable itself\n // would see that later `undefined` instead of the value being\n // handed off.\n const releaseAtOpen = release;\n\n const result = buildStreamResult(iterator, first, {\n requestId,\n model,\n providerName: this.providerName,\n isFallback: this.isFallback,\n chunkIdleTimeoutMs: params.chunkIdleTimeoutMs ?? this.chunkIdleTimeoutMs,\n streamController,\n logger: this.logger,\n signal: params.signal,\n onStreamSuccess: (usage) => {\n this.breaker?.recordSuccess(model);\n releaseAtOpen?.(this.actualTokensFor(usage));\n },\n onStreamFailure: (normalized, usage) => {\n // Idle timeout is the one mid-stream failure that trips the\n // breaker: otherwise a provider that hangs after one chunk\n // would always record a success and never open it.\n if (normalized.type === 'timeout') {\n this.breaker?.recordFailure(model);\n }\n\n if (usage && normalized.type !== 'aborted') {\n this.reportUsageFailure(usage, normalized, attempt, true);\n }\n\n releaseAtOpen?.(this.actualTokensFor(usage));\n },\n finalize: (textAcc, wireToolCalls, usage) =>\n this.finalizeResponse(\n textAcc,\n wireToolCalls,\n params,\n useJson,\n model,\n usage,\n requestId,\n attempt,\n ),\n });\n\n // Ownership of `release` passes to `buildStreamResult` from here.\n release = undefined;\n\n return result;\n } finally {\n // Only reached if opening the stream itself threw; a successful\n // open hands `release` off above and leaves this a no-op.\n release?.();\n }\n }\n\n /**\n * Checks every `ToolCall` against the `tools` that were offered, catching\n * a hallucinated tool name and a duplicate call id before either reaches\n * the application's dispatch table, then runs each tool's\n * `argumentsSchema`, if present.\n *\n * Contract failures (unknown name, duplicate id) are collected across\n * every call and thrown together as one `type: 'validation'` error with\n * `issues: ToolIssue[]`, since retrying a request that already has these\n * errors cannot help (excluded from retry by `type`) and a caller fixing\n * them wants to see every one, not just the first. Schema failures keep\n * the original single-error, `type: 'validation'` shape rather than being\n * folded into the aggregate, since they're a distinct failure kind from\n * the contract failures above.\n */\n private validateToolCallArguments(\n toolCalls: { id: string; name: string; arguments: unknown }[],\n tools: NonNullable<CallParams<unknown>['tools']>,\n ): void {\n const known = new Map(tools.map((t) => [t.name, t]));\n const seenIds = new Set<string>();\n const toolIssues: ToolIssue[] = [];\n\n for (const call of toolCalls) {\n if (seenIds.has(call.id)) {\n toolIssues.push({ name: call.name, toolCallId: call.id, code: 'duplicate_tool_call_id' });\n }\n seenIds.add(call.id);\n\n if (!known.has(call.name)) {\n toolIssues.push({ name: call.name, toolCallId: call.id, code: 'unknown_tool' });\n }\n }\n\n if (toolIssues.length > 0) {\n const unknownTool = toolIssues.find((i) => i.code === 'unknown_tool');\n const primary = unknownTool\n ? `Model requested tool \"${unknownTool.name}\", which was not in the tools offered ([${[...known.keys()].join(', ')}]).`\n : `Duplicate tool call id \"${toolIssues[0]!.toolCallId}\" in the model's response.`;\n\n // Most responses hit exactly one issue. When there's more than one,\n // say so, since toolCalls[0]'s problem alone would otherwise read as\n // the whole story.\n const message =\n toolIssues.length > 1\n ? `${primary} (${toolIssues.length} tool call issues total, see error.issues.)`\n : primary;\n\n throw new LLMError(message, 'validation', {\n code: unknownTool ? 'unknown_tool' : 'duplicate_tool_call_id',\n issues: toolIssues,\n });\n }\n\n for (const call of toolCalls) {\n const definition = known.get(call.name);\n\n if (!definition?.argumentsSchema) continue;\n\n const result = definition.argumentsSchema.safeParse(call.arguments);\n\n if (!result.success) {\n throw new LLMError(\n `Arguments for tool call \"${call.name}\" failed validation`,\n 'validation',\n {\n issues: result.error,\n },\n );\n }\n }\n }\n\n /**\n * Runs `fn`, retrying with backoff according to `shouldRetry`. When\n * `attempts` is given, every failed attempt that is actually followed by\n * a retry is recorded, in order. This mirrors `LLMError.attempts`'s\n * contract: every attempt made before this error was thrown. The\n * terminal failure is never pushed since it isn't a prior attempt, it\n * is the error being thrown. `attempts` stays empty when nothing was\n * retried, so no separate bookkeeping is needed at the call sites.\n * Each failure is recorded as a snapshot (`LLMError.toSnapshot()`),\n * not the live `LLMError`, per `RetryAttempt`'s contract.\n */\n private async retryWithBackoff<T>(\n fn: (attempt: number, onRequest: OnRequest) => Promise<T>,\n requestId: string,\n model: string,\n signal?: AbortSignal,\n onAttempt?: () => void,\n attempts?: RetryAttempt[],\n ): Promise<T> {\n let lastError: unknown;\n let lastRequestForAttempt: LLMRequestSnapshot | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n // Reset before this iteration's own onRequest can run. If this\n // attempt fails before onRequest is ever called (e.g. thrown by\n // recoverDelay or onAttempt, before fn/onRequest runs), the\n // previous attempt's request must not be misattributed to this\n // attempt's index below.\n lastRequestForAttempt = undefined;\n\n try {\n if (attempt > 0) {\n await this.recoverDelay(requestId, model, attempt, lastError, signal);\n }\n\n onAttempt?.();\n return await fn(attempt, (req) => {\n lastRequestForAttempt = req;\n });\n } catch (error) {\n lastError = error;\n\n const willRetry = attempt < this.maxRetries && this.shouldRetry(error, signal);\n if (!willRetry) break;\n\n attempts?.push({\n index: attempt,\n error: normalizeError(error, signal).toSnapshot(),\n request: passThroughRequestSnapshot(lastRequestForAttempt),\n });\n }\n }\n\n throw lastError;\n }\n\n /**\n * Pulls `TokenUsage` out of a raw response, if the provider reported it.\n * Extraction doesn't depend on what happens to the response afterward, so\n * a malformed body can still yield usage if the provider's usage block\n * itself came through intact.\n */\n private extractUsage(\n response: Awaited<ReturnType<LLMClient['chat']['completions']['create']>>,\n requestId: string,\n model: string,\n ): TokenUsage | undefined {\n if (!response.usage) return undefined;\n\n const reasoningTokens = response.usage.completion_tokens_details?.reasoning_tokens;\n\n return {\n promptTokens: response.usage.prompt_tokens ?? 0,\n completionTokens: response.usage.completion_tokens ?? 0,\n totalTokens: response.usage.total_tokens ?? 0,\n ...(reasoningTokens !== undefined ? { reasoningTokens } : {}),\n requestId,\n model,\n provider: this.providerName,\n usedFallback: this.isFallback,\n };\n }\n\n /**\n * The token count to reconcile the rate limiter against for a finished\n * attempt: `totalTokens` when reported, otherwise the sum of prompt and\n * completion tokens, matching `reportUsageFailure`'s own fallback below\n * for a hand-rolled client that reports the parts but omits the total.\n */\n private actualTokensFor(usage: TokenUsage | undefined): number | undefined {\n if (!usage) return undefined;\n return usage.totalTokens || usage.promptTokens + usage.completionTokens;\n }\n\n /** Reports token usage for a successful call, swallowing and logging any error `onUsage` throws. */\n private reportUsage(usage: TokenUsage | undefined): void {\n if (!usage || !this.onUsage) return;\n\n try {\n this.onUsage(usage);\n } catch (error) {\n this.logger.error('[VernLLM] onUsage failed', {\n message: error instanceof Error ? error.message : 'unknown',\n });\n }\n }\n\n /**\n * Reports token usage spent on an attempt that then failed, so it isn't\n * dropped alongside the error. Covers any error thrown after usage\n * extraction, since all of them happen only after a response (real\n * spend) already arrived. Swallows and logs any error `onUsageFailure`\n * itself throws.\n */\n private reportUsageFailure(\n usage: TokenUsage,\n error: LLMError,\n attempt: number,\n terminal = false,\n ): void {\n // Falls back to promptTokens + completionTokens if totalTokens is 0\n // (e.g. a hand-rolled client that omits the total), so the log\n // doesn't understate real spend.\n const displayTokens = usage.totalTokens || usage.promptTokens + usage.completionTokens;\n\n // A mid-stream failure is terminal for that call (no further attempts\n // for this stream), unlike a stream-open failure where attempt N+1 may\n // still follow. Label them differently so the log doesn't imply a\n // retry that isn't coming.\n const attemptText = terminal\n ? 'mid-stream failure (terminal, no further attempts)'\n : `attempt ${attempt + 1}/${this.maxRetries + 1}`;\n\n this.logger.warn(\n `[VernLLM:${usage.requestId}] usage failure, ${attemptText}: ` +\n `type=${error.type} tokens=${displayTokens}`,\n );\n\n if (!this.onUsageFailure) return;\n\n try {\n this.onUsageFailure(usage, error);\n } catch (hookError) {\n this.logger.error('[VernLLM] onUsageFailure failed', {\n message: hookError instanceof Error ? hookError.message : 'unknown',\n });\n }\n }\n\n /** Parses response content as JSON and validates it against `schema` when supplied. */\n private parseAndValidate<T>(content: string, schema?: CallParams<T>['schema']): T {\n let parsed: unknown;\n\n try {\n parsed = this.parseJson(content);\n } catch {\n throw new LLMError('Invalid JSON response', 'parse');\n }\n\n if (parsed === null || parsed === undefined) {\n throw new LLMError('Invalid JSON response', 'parse');\n }\n\n if (!schema) return parsed as T;\n\n const result = schema.safeParse(parsed);\n\n if (!result.success) {\n throw new LLMError('Schema validation failed', 'validation', { issues: result.error });\n }\n\n return result.data;\n }\n\n /**\n * Waits out the backoff delay for a retry attempt, honoring a\n * Retry-After header on the failed attempt's error when present.\n * Both Retry-After and plain exponential backoff are capped at the same\n * max delay (see `DEFAULT_MAX_DELAY_MS` in `retry.utils.ts`).\n */\n private async recoverDelay(\n requestId: string,\n model: string,\n attempt: number,\n error: unknown,\n signal?: AbortSignal,\n ) {\n const retryAfterMs = extractRetryAfterMs(error);\n const delay = retryAfterMs ?? getBackoffDelay(this.baseDelayMs, attempt);\n const retryAfterHonored = retryAfterMs !== undefined;\n\n this.logger.warn(\n `[VernLLM:${requestId}] recovery attempt ${attempt}/${this.maxRetries}, waiting ${Math.ceil(delay)}ms` +\n (retryAfterHonored ? ' (honoring Retry-After)' : ''),\n );\n\n this.reportEvent({\n kind: 'retry',\n requestId,\n provider: this.providerName,\n model,\n attempt,\n maxRetries: this.maxRetries,\n delayMs: delay,\n retryAfterHonored,\n error: normalizeError(error, signal),\n });\n\n await waitForRetry(delay, signal);\n }\n\n /** Decides whether a failed attempt is worth retrying. */\n private shouldRetry(error: unknown, signal?: AbortSignal): boolean {\n if (signal?.aborted) return false;\n\n // `LLMError.retryable` already covers the deterministic cases: parse/\n // validation/invalid_params/aborted types, the tool contract codes,\n // and the local rate-limit codes. Only `nonRetryableStatus`, specific\n // to this call, isn't part of that general-purpose property.\n if (error instanceof LLMError && !error.retryable) return false;\n\n const status = extractStatus(error);\n\n return !(status !== undefined && this.nonRetryableStatus.includes(status));\n }\n\n /**\n * Decides whether a failed attempt should count toward the circuit\n * breaker's failure threshold. A model hallucinating a tool name,\n * reusing a call id, or a provider ignoring `toolChoice: 'none'` isn't\n * the provider being unhealthy, it's a model/provider response defect\n * that will very likely recur regardless of provider health, so it\n * shouldn't push a healthy provider's circuit toward opening. Same for\n * a caller-input bug or a local rate-limit rejection: neither ever\n * reached the provider at all. This is exactly what `LLMError.retryable`\n * already excludes, so this defers to it directly.\n */\n private countsTowardBreaker(error: LLMError): boolean {\n return error.retryable;\n }\n}\n","import type { Logger } from '../logger.js';\n\n/**\n * Wraps a `Logger` so a throwing implementation can never break the call\n * it's trying to describe. `logger` is user-supplied (`VernLLMOptions.logger`),\n * so a custom logger that ships to a file, Datadog, etc. can throw for\n * reasons unrelated to VernLLM. Wrap once at construction so every\n * downstream `this.logger.warn(...)` call stays as-is and is safe by\n * construction, instead of guarding each call site individually.\n */\nexport function createSafeLogger(logger: Logger): Logger {\n return {\n debug: safe(logger, 'debug'),\n warn: safe(logger, 'warn'),\n error: safe(logger, 'error'),\n };\n}\n\nfunction safe<M extends 'debug' | 'warn' | 'error'>(logger: Logger, method: M): Logger[M] {\n const fn = (logger[method] as (...args: Parameters<Logger[M]>) => unknown).bind(logger);\n\n return ((...args: Parameters<Logger[M]>) => {\n try {\n swallowRejection(fn(...args));\n } catch {\n // a broken logger must never break the call it's describing\n }\n }) as Logger[M];\n}\n\nfunction isPromiseLike(value: unknown): value is PromiseLike<unknown> {\n return typeof (value as PromiseLike<unknown>)?.then === 'function';\n}\n\nfunction swallowRejection(result: unknown): void {\n if (isPromiseLike(result)) {\n Promise.resolve(result).catch(() => {\n // a broken logger must never break the call it's describing\n });\n }\n}\n","export interface Logger {\n debug(message: string): void;\n warn(message: string): void;\n error(message: string, meta?: Record<string, unknown>): void;\n}\n\n/**\n * Default logger. `debug` is gated by the `debug` option on VernLLM\n * warn/error always fire since they indicate real problems (retries, cache failures)\n */\nexport class ConsoleLogger implements Logger {\n constructor(private debugEnabled: boolean) {}\n\n debug(message: string): void {\n if (this.debugEnabled) console.debug(message);\n }\n\n warn(message: string): void {\n console.warn(message);\n }\n\n error(message: string, meta?: Record<string, unknown>): void {\n console.error(message, meta ?? '');\n }\n}\n","import { LLMError } from './types/errors.js';\n\nimport type { LLMClient } from './types/client.js';\n\n/** The request shape sent to `LLMClient['chat']['completions']['create']`, used for token estimation. */\nexport type WireRequest = Parameters<LLMClient['chat']['completions']['create']>[0];\n\n/** Which configured bucket is currently blocking a call. */\nexport type RateLimitReason = 'concurrency' | 'rpm' | 'tpm';\n\nexport interface RateLimitOptions {\n /** Max requests per minute. Omit for unlimited. */\n requestsPerMinute?: number;\n /**\n * Max tokens per minute. Enforced against a pre-flight estimate, then\n * reconciled against reported usage once the call completes. Omit for\n * unlimited.\n */\n tokensPerMinute?: number;\n /** Max requests in flight at once. Default 0, meaning unlimited. */\n maxConcurrent?: number;\n /**\n * Max time a call may sit queued waiting for capacity, in ms. Exceeding\n * it throws rather than hanging forever. Default 30000. Pass 0 to wait\n * indefinitely.\n */\n maxQueueMs?: number;\n /** Max queued calls before new ones reject immediately instead of queueing. Default 0, unbounded. */\n maxQueueSize?: number;\n /**\n * Pre-flight token estimate for `tokensPerMinute`. Defaults to a\n * chars/4 heuristic over message content plus `max_tokens`.\n */\n estimateTokens?: (request: WireRequest) => number;\n}\n\nexport interface RateLimitAcquireResult {\n /**\n * Releases the concurrency slot this attempt held and reconciles the\n * token bucket against real usage, when `actualTokens` is supplied.\n * Idempotent: only the first call does anything. Must run in a\n * `finally` block so a slot is never leaked on a failed attempt.\n */\n release: (actualTokens?: number) => void;\n /** How long this attempt waited in queue before capacity was available. */\n waitedMs: number;\n /** Which bucket was blocking this attempt just before it cleared, if any wait happened. */\n reason?: RateLimitReason;\n}\n\n/** Default `estimateTokens`: chars/4 over every message's content, plus the requested `max_tokens`. */\nexport function defaultEstimateTokens(request: WireRequest): number {\n const messagesChars = request.messages.reduce((sum, message) => {\n const content = (message as { content?: unknown }).content;\n\n if (typeof content === 'string') return sum + content.length;\n if (content === undefined || content === null) return sum;\n\n try {\n return sum + JSON.stringify(content).length;\n } catch {\n return sum;\n }\n }, 0);\n\n return Math.ceil(messagesChars / 4) + (request.max_tokens ?? 0);\n}\n\n/**\n * A capacity that refills continuously. Used for requests per minute and\n * tokens per minute, where `refillPerMs` is `capacity / 60000`, and for\n * concurrency, where `refillPerMs` is 0 and every release calls\n * `give(1)` instead of relying on the clock.\n */\nclass TokenBucket {\n private available: number;\n private lastRefill = Date.now();\n\n constructor(\n private readonly capacity: number,\n private readonly refillPerMs: number,\n ) {\n this.available = capacity;\n }\n\n private refill(): void {\n if (this.refillPerMs === 0) return;\n\n const now = Date.now();\n const elapsedMs = now - this.lastRefill;\n\n // A backward clock adjustment (NTP correction, VM migration, etc.)\n // makes `elapsedMs` negative, which would otherwise reduce `available`\n // on the next line, rate-limiting harder than configured for no\n // real-world reason. Treat a negative elapsed time as no time having\n // passed instead: `available` just doesn't grow this tick, rather\n // than shrinking, and `lastRefill` still advances so a subsequent\n // forward-moving `now` measures from here, not from the skewed past.\n this.available = Math.min(\n this.capacity,\n this.available + Math.max(0, elapsedMs) * this.refillPerMs,\n );\n this.lastRefill = now;\n }\n\n /** Refills, then takes `amount` if available. Leaves the bucket untouched if it can't. */\n tryTake(amount: number): boolean {\n this.refill();\n\n if (this.available < amount) return false;\n\n this.available -= amount;\n return true;\n }\n\n /**\n * Refills, then reports how many ms until this bucket could supply\n * `amount`, assuming nothing else takes from it meanwhile. Returns 0 if\n * it already can, `Infinity` if it never will on its own (a\n * concurrency bucket, `refillPerMs === 0`, only frees via `give`).\n */\n msUntilAvailable(amount: number): number {\n this.refill();\n\n if (this.available >= amount) return 0;\n if (this.refillPerMs === 0) return Infinity;\n\n return (amount - this.available) / this.refillPerMs;\n }\n\n /**\n * Gives capacity back. Not floored at 0: a bad token-usage estimate can\n * push `available` negative, and it self-corrects on the next refill\n * rather than being clamped away immediately. Only ceilinged at\n * `capacity`, so a give can never overfill the bucket.\n */\n give(amount: number): void {\n this.available = Math.min(this.capacity, this.available + amount);\n }\n\n /** The bucket's ceiling, e.g. so a request that could never fit can fail fast instead of queueing forever. */\n getCapacity(): number {\n return this.capacity;\n }\n}\n\n/**\n * `setTimeout` silently clamps any delay above this (~24.8 days) instead\n * of erroring, so an uncapped delay derived from a very small\n * `requestsPerMinute`/`tokensPerMinute` could wrap around to firing\n * almost immediately instead of waiting. Mirrors the same guard in\n * `withTimeout`/`withChunkIdleTimeout`.\n */\nconst MAX_WAKE_DELAY_MS = 2_147_483_647;\n\n/** One caller waiting for capacity, queued FIFO. */\ninterface Waiter {\n estimatedTokens: number;\n enqueuedAt: number;\n /** Reason recorded the last time this waiter was checked and found still blocked. */\n lastReason?: RateLimitReason;\n resolve: (result: RateLimitAcquireResult) => void;\n reject: (error: unknown) => void;\n}\n\n/**\n * Per-target rate limiter. Up to three buckets (requests/min, tokens/min,\n * concurrency) behind one FIFO queue, so a large call isn't starved by a\n * stream of small ones. Any bucket omitted from `options` has infinite\n * capacity and never blocks.\n */\nexport class RateLimiter {\n private readonly requests?: TokenBucket;\n private readonly tokens?: TokenBucket;\n private readonly concurrency?: TokenBucket;\n\n private readonly maxQueueMs: number;\n private readonly maxQueueSize: number;\n private readonly estimateTokensFn: (request: WireRequest) => number;\n\n private readonly queue: Waiter[] = [];\n\n /**\n * A single scheduled re-check for the head of the queue when it's\n * blocked on a bucket that refills on its own clock (rpm/tpm), so a\n * queue that nobody calls `acquire`/`release` on again isn't stuck\n * forever waiting for an external trigger to re-drain it. Not needed\n * for a concurrency block, which only clears via `release`.\n */\n private wakeTimer?: ReturnType<typeof setTimeout>;\n\n constructor(options: RateLimitOptions) {\n if (options.requestsPerMinute) {\n this.requests = new TokenBucket(\n options.requestsPerMinute,\n options.requestsPerMinute / 60_000,\n );\n }\n\n if (options.tokensPerMinute) {\n this.tokens = new TokenBucket(options.tokensPerMinute, options.tokensPerMinute / 60_000);\n }\n\n if (options.maxConcurrent) {\n this.concurrency = new TokenBucket(options.maxConcurrent, 0);\n }\n\n this.maxQueueMs = options.maxQueueMs ?? 30_000;\n this.maxQueueSize = options.maxQueueSize ?? 0;\n this.estimateTokensFn = options.estimateTokens ?? defaultEstimateTokens;\n }\n\n /** Pre-flight token estimate for a request, per the configured (or default) heuristic. */\n estimate(request: WireRequest): number {\n return this.estimateTokensFn(request);\n }\n\n /**\n * Waits for capacity in every configured bucket, then takes from each.\n * The returned `release` gives the concurrency slot back and reconciles\n * the token bucket against real usage; it must run in a `finally` block.\n */\n async acquire(estimatedTokens: number, signal?: AbortSignal): Promise<RateLimitAcquireResult> {\n if (signal?.aborted) {\n throw new LLMError('LLM request aborted', 'aborted');\n }\n\n // Guards `estimatedTokens` even on this directly-exported entry point\n // (not just the `VernLLM.executeCall`/`executeStreamCall` call sites):\n // an unchecked NaN or negative value would poison a bucket's\n // `available` permanently, since `NaN < amount` is always false and\n // would make `tryTake` wrongly report success forever after.\n if (!Number.isFinite(estimatedTokens) || estimatedTokens < 0) {\n throw new LLMError(\n `estimatedTokens must be a finite, non-negative number, got ${String(estimatedTokens)}`,\n 'invalid_params',\n );\n }\n\n // A request over the bucket's own ceiling can never be satisfied by\n // any amount of waiting, refill included, so failing fast here also\n // avoids permanently stalling every waiter queued behind it in FIFO.\n if (this.tokens && estimatedTokens > this.tokens.getCapacity()) {\n throw new LLMError(\n `estimatedTokens (${estimatedTokens}) exceeds the configured tokensPerMinute capacity (${this.tokens.getCapacity()}); this call could never acquire capacity.`,\n 'rate_limited',\n { code: 'rate_limit_capacity_exceeded' },\n );\n }\n\n // Fast path: nothing already queued, so try to go straight through\n // rather than paying queue bookkeeping for the common, uncontended case.\n if (this.queue.length === 0) {\n const attempt = this.tryAcquireBuckets(estimatedTokens);\n\n if (attempt.ok) {\n return { release: this.makeRelease(estimatedTokens), waitedMs: 0 };\n }\n\n // No maxQueueSize check needed here: the queue is empty (this\n // branch's own condition), so enqueueing this one waiter can never\n // exceed any maxQueueSize > 0. The check below only becomes\n // reachable once the queue is non-empty.\n return this.enqueue(estimatedTokens, attempt.reason, signal);\n }\n\n if (this.maxQueueSize > 0 && this.queue.length >= this.maxQueueSize) {\n throw this.queueFullError();\n }\n\n return this.enqueue(estimatedTokens, undefined, signal);\n }\n\n private queueFullError(): LLMError {\n return new LLMError('Rate limit queue is full', 'rate_limited', {\n code: 'rate_limit_queue_full',\n });\n }\n\n private enqueue(\n estimatedTokens: number,\n initialReason: RateLimitReason | undefined,\n signal?: AbortSignal,\n ): Promise<RateLimitAcquireResult> {\n return new Promise<RateLimitAcquireResult>((resolvePromise, rejectPromise) => {\n const waiter: Waiter = {\n estimatedTokens,\n enqueuedAt: Date.now(),\n lastReason: initialReason,\n resolve: (result) => {\n cleanup();\n resolvePromise(result);\n },\n reject: (error) => {\n cleanup();\n\n // The removed waiter may have been the head a wakeTimer was\n // scheduled around (or, for a concurrency block, the head with\n // no timer scheduled at all). Either way, re-drain immediately\n // so a successor with different requirements is evaluated now\n // instead of waiting on a stale timer or an unrelated\n // acquire/release call to trigger it.\n if (this.wakeTimer) {\n clearTimeout(this.wakeTimer);\n this.wakeTimer = undefined;\n }\n this.drain();\n\n rejectPromise(error);\n },\n };\n\n let queueTimer: ReturnType<typeof setTimeout> | undefined;\n\n const onAbort = () => {\n waiter.reject(new LLMError('LLM request aborted', 'aborted'));\n };\n\n const cleanup = () => {\n if (queueTimer) clearTimeout(queueTimer);\n signal?.removeEventListener('abort', onAbort);\n\n const index = this.queue.indexOf(waiter);\n if (index !== -1) this.queue.splice(index, 1);\n };\n\n if (this.maxQueueMs > 0) {\n queueTimer = setTimeout(() => {\n waiter.reject(\n new LLMError(\n 'Rate limit queue timed out before capacity was available',\n 'rate_limited',\n {\n code: 'rate_limit_queue_timeout',\n },\n ),\n );\n }, this.maxQueueMs);\n }\n\n signal?.addEventListener('abort', onAbort, { once: true });\n\n this.queue.push(waiter);\n this.drain();\n });\n }\n\n /**\n * Checks and takes from every configured bucket as one atomic unit: if\n * any bucket lacks capacity, whatever was already taken from the\n * earlier ones in this attempt is rolled back before reporting which\n * bucket blocked.\n */\n private tryAcquireBuckets(\n estimatedTokens: number,\n ): { ok: true } | { ok: false; reason: RateLimitReason } {\n const taken: Array<{ bucket: TokenBucket; amount: number }> = [];\n\n const take = (bucket: TokenBucket | undefined, amount: number) => {\n if (!bucket) return true;\n if (!bucket.tryTake(amount)) return false;\n\n taken.push({ bucket, amount });\n return true;\n };\n\n if (!take(this.concurrency, 1)) {\n return { ok: false, reason: 'concurrency' };\n }\n\n if (!take(this.requests, 1)) {\n for (const entry of taken) entry.bucket.give(entry.amount);\n return { ok: false, reason: 'rpm' };\n }\n\n if (!take(this.tokens, estimatedTokens)) {\n for (const entry of taken) entry.bucket.give(entry.amount);\n return { ok: false, reason: 'tpm' };\n }\n\n return { ok: true };\n }\n\n /** Drains the queue head first. Stops at the first waiter that still can't proceed, so no one is starved out of turn. */\n private drain(): void {\n while (this.queue.length > 0) {\n const waiter = this.queue[0] as Waiter;\n const attempt = this.tryAcquireBuckets(waiter.estimatedTokens);\n\n if (!attempt.ok) {\n waiter.lastReason = attempt.reason;\n this.scheduleWake(attempt.reason, waiter.estimatedTokens);\n return;\n }\n\n const waitedMs = Date.now() - waiter.enqueuedAt;\n\n waiter.resolve({\n release: this.makeRelease(waiter.estimatedTokens),\n waitedMs,\n reason: waiter.lastReason,\n });\n }\n }\n\n /**\n * Schedules a one-shot re-check of the queue for whenever the bucket\n * that's currently blocking the head waiter should next have enough\n * capacity. A no-op for a concurrency block (only `release` can clear\n * that) or while a wake is already pending.\n */\n private scheduleWake(reason: RateLimitReason, estimatedTokens: number): void {\n if (this.wakeTimer) return;\n\n const ms =\n reason === 'rpm'\n ? this.requests?.msUntilAvailable(1)\n : reason === 'tpm'\n ? this.tokens?.msUntilAvailable(estimatedTokens)\n : undefined;\n\n if (ms === undefined || !Number.isFinite(ms)) return;\n\n // Capped, not just clamped-by-omission: `drain()` re-derives the\n // real remaining wait from live bucket state on every firing (it\n // doesn't trust the delay that got it there), so a wake that fires\n // early because the true wait exceeded the cap just re-schedules\n // correctly from where the bucket actually is, rather than looping\n // on a delay that never shrinks.\n const delay = Math.min(Math.max(1, Math.ceil(ms)), MAX_WAKE_DELAY_MS);\n\n this.wakeTimer = setTimeout(() => {\n this.wakeTimer = undefined;\n this.drain();\n }, delay);\n }\n\n /**\n * Builds the one-shot release closure for an acquired slot. Only the\n * concurrency bucket is given back on release; the requests-per-minute\n * bucket is a real spend that only recovers via its own refill, and the\n * tokens bucket is reconciled against `actualTokens` rather than fully\n * refunded, since real tokens really were spent.\n */\n private makeRelease(estimatedTokens: number): (actualTokens?: number) => void {\n let released = false;\n\n return (actualTokens?: number) => {\n if (released) return;\n released = true;\n\n this.concurrency?.give(1);\n\n // An invalid `actualTokens` (e.g. NaN from a malformed usage\n // report) must not reach `give`: `Math.min(capacity, available +\n // NaN)` is NaN, and a NaN `available` poisons every future\n // `tryTake` on that bucket (any comparison against NaN is false,\n // so it would look permanently under capacity and rate limiting\n // would silently stop happening). Falling back to no reconciliation\n // at least keeps the estimated debit, the safe direction to err.\n if (this.tokens && actualTokens !== undefined && Number.isFinite(actualTokens)) {\n this.tokens.give(estimatedTokens - actualTokens);\n }\n\n this.drain();\n };\n }\n}\n","import { randomUUID } from 'crypto';\n\nimport { CacheOrchestrator } from './internal/cache/cacheOrchestrator.js';\nimport { buildCircuitBreaker, makeEventReporter } from './internal/circuitBreaker.utils.js';\nimport { CallExecutor } from './internal/execution/callExecutor.js';\nimport { normalizeError } from './internal/execution/errors.utils.js';\nimport { withReservedUsage, withReservedUsageForStream } from './internal/execution/usage.utils.js';\nimport { createSafeLogger } from './internal/logger.utils.js';\nimport { ConsoleLogger, type Logger } from './logger.js';\nimport { RateLimiter } from './rateLimit.js';\nimport {\n InMemoryCacheAdapter,\n LLMError,\n FallbackExhaustedError,\n defaultFallbackOn,\n type CachedCallParams,\n type CachedStreamCallParams,\n type CachedStreamConditionalToolCallParams,\n type CachedStreamToolCallParams,\n type CachedConditionalToolCallParams,\n type CachedToolCallParams,\n type CachedJsonModeDisabledCallParams,\n type CachedJsonModeEnabledCallParams,\n type CallParams,\n type CallWithToolsResult,\n type ConditionalToolCallParams,\n type ContentResult,\n type FallbackAttempt,\n type FallbackOn,\n type FallbackTarget,\n type JsonModeDisabledCallParams,\n type JsonModeEnabledCallParams,\n type JsonValue,\n type StreamCallResult,\n type StreamJsonModeDisabledCallParams,\n type StreamJsonModeEnabledCallParams,\n type CachedStreamJsonModeDisabledCallParams,\n type CachedStreamJsonModeEnabledCallParams,\n type TargetCircuitState,\n type CircuitTarget,\n type StreamEnabledCallParams,\n type ToolEnabledCallParams,\n type ToolsDisabledCallParams,\n type VernLLMEvent,\n type VernLLMOptions,\n} from './types/index.js';\n\nimport type { CircuitState } from './circuitBreaker.js';\nimport type { InternalCacheParams } from './internal/cache/cache.utils.js';\n\n/**\n * A LLM call framework for resilience, observability and control. This is VernLLM!\n *\n * Adds retry with backoff and jitter, per-attempt timeouts, an optional\n * circuit breaker, JSON parsing with optional schema validation, usage\n * tracking, and an optional response cache. All configurable, all opt-in\n * beyond sensible defaults.\n */\nexport class VernLLM {\n private readonly logger: Logger;\n\n /**\n * One `CallExecutor` per provider target: index 0 is the primary,\n * everything after it is a `fallback` target, in the order declared.\n * Each owns its own request building, retry/timeout, circuit breaker,\n * and rate limiter. `call()` walks this array in `runFallbackChain`,\n * moving to the next entry only when `fallbackOn` says to.\n */\n private readonly executors: CallExecutor[];\n\n /** Decides whether a failed target is followed by the next one or the chain stops. See `VernLLMOptions['fallbackOn']`. */\n private readonly fallbackOn: FallbackOn;\n\n /** Reports a `'fallback'` event when the chain moves to the next target. Shared `onEvent` plumbing, same as every executor's. */\n private readonly reportEvent: (event: VernLLMEvent) => void;\n\n /**\n * Owns cache key resolution, cache reads/writes, and in-flight\n * coalescing for `cachedCall()`. Independent of `executor`: it only\n * ever calls back into `this.call()` as an opaque function.\n */\n private readonly cacheOrchestrator: CacheOrchestrator;\n\n /**\n * @param options Client, model, and tunables. Defaults: `maxRetries` 1,\n * `timeoutMs` 25000, `baseDelayMs` 500, `defaultMaxTokens` 1000,\n * `defaultTemperature` 0.2, `cache` an in-memory adapter,\n * `nonRetryableStatus` `[400, 401, 403, 404, 422]`, `debug` false.\n */\n constructor(options: VernLLMOptions) {\n this.logger = createSafeLogger(options.logger ?? new ConsoleLogger(options.debug ?? false));\n\n const providerName = options.name ?? 'primary';\n\n this.cacheOrchestrator = new CacheOrchestrator(\n options.cache ?? new InMemoryCacheAdapter(),\n this.logger,\n );\n\n this.fallbackOn = options.fallbackOn ?? defaultFallbackOn;\n this.reportEvent = makeEventReporter(options.onEvent, this.logger);\n\n // The primary target's shared knobs, resolved once here rather than\n // inline in the retry-tunable default below, since fallback targets\n // that omit a field inherit this resolved value, not the raw\n // (possibly-undefined) option.\n const primaryDefaultTemperature =\n options.defaultTemperature === undefined ? 0.2 : options.defaultTemperature;\n const primaryDefaultReasoningEffort = options.defaultReasoningEffort;\n const primaryDefaultBudgetTokens = options.defaultBudgetTokens;\n\n // The primary, shaped like a `FallbackTarget` so it walks the same\n // build loop as every declared fallback target below. Its own\n // `circuitBreaker`/`rateLimit` are read directly off `options`\n // instead of this list, since only the primary carries them at the\n // top level (a `FallbackTarget`'s copies are genuinely independent,\n // never inherited, see `FallbackTarget`'s docs).\n const primaryTarget: FallbackTarget = {\n client: options.client,\n model: options.model,\n name: providerName,\n maxRetries: options.maxRetries,\n timeoutMs: options.timeoutMs,\n chunkIdleTimeoutMs: options.chunkIdleTimeoutMs,\n baseDelayMs: options.baseDelayMs,\n defaultMaxTokens: options.defaultMaxTokens,\n defaultTemperature: primaryDefaultTemperature,\n defaultReasoningEffort: primaryDefaultReasoningEffort,\n defaultBudgetTokens: primaryDefaultBudgetTokens,\n nonRetryableStatus: options.nonRetryableStatus,\n circuitBreaker: options.circuitBreaker,\n rateLimit: options.rateLimit,\n };\n\n const declaredFallbacks: FallbackTarget[] = Array.isArray(options.fallback)\n ? options.fallback\n : options.fallback\n ? [options.fallback]\n : [];\n\n const targets = [primaryTarget, ...declaredFallbacks];\n\n this.executors = targets.map((target, i) => {\n const isFallback = i > 0;\n // `-1` for the primary, matching `FallbackAttempt.index`.\n const name = target.name ?? (isFallback ? `fallback[${i - 1}]` : providerName);\n\n // Built before the executor: onStateChange fires from inside the\n // breaker itself, which the executor is merely handed a reference to.\n const breaker = buildCircuitBreaker(\n target.circuitBreaker,\n name,\n target.model,\n options.onEvent,\n this.logger,\n );\n\n return new CallExecutor(name, target.client, target.model, {\n maxRetries: target.maxRetries ?? options.maxRetries ?? 1,\n timeoutMs: target.timeoutMs ?? options.timeoutMs ?? 25_000,\n chunkIdleTimeoutMs: target.chunkIdleTimeoutMs ?? options.chunkIdleTimeoutMs ?? 30_000,\n baseDelayMs: target.baseDelayMs ?? options.baseDelayMs ?? 500,\n defaultMaxTokens: target.defaultMaxTokens ?? options.defaultMaxTokens ?? 1000,\n defaultTemperature:\n target.defaultTemperature === undefined\n ? primaryDefaultTemperature\n : target.defaultTemperature,\n defaultReasoningEffort:\n target.defaultReasoningEffort === undefined\n ? primaryDefaultReasoningEffort\n : target.defaultReasoningEffort,\n defaultBudgetTokens:\n target.defaultBudgetTokens === undefined\n ? primaryDefaultBudgetTokens\n : target.defaultBudgetTokens,\n nonRetryableStatus: target.nonRetryableStatus ??\n options.nonRetryableStatus ?? [400, 401, 403, 404, 422],\n parseJson: options.parseJson,\n logger: this.logger,\n redact: options.redact,\n onUsage: options.onUsage,\n onUsageFailure: options.onUsageFailure,\n onEvent: options.onEvent,\n breaker,\n limiter: target.rateLimit ? new RateLimiter(target.rateLimit) : undefined,\n isFallback,\n });\n });\n }\n\n /** Logs a failed refundUsage attempt via the configured logger. */\n private logRefundError(logMessage: string, error: unknown): void {\n this.logger.error(logMessage, {\n message: error instanceof Error ? error.message : 'unknown',\n });\n }\n\n /**\n * Walks `this.executors` in order, running `attempt` against each until\n * one succeeds or every target has failed. `run` on a lone target\n * (no `fallback` configured) throws exactly what it throws today: the\n * loop's single iteration path is unchanged from pre-fallback behavior.\n *\n * For streaming, `attempt` is `executor.runStream`, whose own retries\n * only cover *opening* the stream (see `CallExecutor.runStream`). A\n * mid-stream failure surfaces through `finalResult` after this function\n * has already returned, so it's never seen here and never falls over,\n * per the streaming limitation: splicing a second model's output into a\n * response the consumer has already partially rendered would corrupt\n * it.\n */\n private async runFallbackChain<R>(\n params: Pick<CallParams<unknown>, 'model' | 'signal'>,\n requestId: string,\n attempt: (executor: CallExecutor, onAttempt: () => void) => Promise<R>,\n skipBreakerCheckForFirst = false,\n ): Promise<{ result: R; executor: CallExecutor; index: number; attemptCount: number }> {\n const attempts: FallbackAttempt[] = [];\n\n for (let i = 0; i < this.executors.length; i++) {\n const executor = this.executors[i]!;\n const startedAt = Date.now();\n let attemptCount = 0;\n\n try {\n // Already checked once, before usage was reserved, when this is\n // the sole target (see `call()`). `assertClosed` claims a\n // half-open trial slot as a side effect on a non-throwing call,\n // so it must run exactly once per logical call: checking it\n // again here for the same executor could either falsely see\n // \"trial already in flight\" (from the check that just claimed\n // it) or double-claim a slot no concurrent caller actually has.\n if (!(i === 0 && skipBreakerCheckForFirst)) {\n executor.assertBreakerClosed(params.model);\n }\n\n const result = await attempt(executor, () => {\n attemptCount += 1;\n });\n return { result, executor, index: i, attemptCount };\n } catch (error) {\n const normalized = normalizeError(error, params.signal);\n\n attempts.push({\n index: i - 1,\n provider: executor.providerName,\n model: params.model ?? executor.model,\n // `.toSnapshot()`: this target's own `attempts` (from its own\n // retries, already snapshots per `CallExecutor`) come along\n // for free since `toSnapshot()` copies them as-is.\n error: normalized.toSnapshot(),\n });\n\n const isLast = i === this.executors.length - 1;\n // Always consult fallbackOn, including on the last target, so it\n // sees every failure and callers who log or count from inside it\n // get a complete picture. The chain still stops once the last\n // target fails regardless of what fallbackOn returns: there is no\n // next executor to fall over to.\n const policyDecision = this.fallbackOn(normalized, { isLastTarget: isLast });\n const decision = isLast ? 'stop' : policyDecision;\n\n if (decision === 'stop') {\n // A lone target (or a chain that stopped on its first failure)\n // throws its own error, unchanged from pre-fallback behavior.\n throw attempts.length > 1 ? new FallbackExhaustedError(attempts) : normalized;\n }\n\n const next = this.executors[i + 1]!;\n\n this.reportEvent({\n kind: 'fallback',\n requestId,\n from: executor.providerName,\n to: next.providerName,\n fromIndex: i - 1,\n toIndex: i,\n error: normalized,\n elapsedMs: Date.now() - startedAt,\n });\n }\n }\n\n // Unreachable: the loop above always either returns or throws before\n // running out of targets (the last iteration's `isLast` forces a\n // throw). Kept only to satisfy the return type.\n throw new LLMError('No provider targets configured', 'invalid_params');\n }\n\n /**\n * Makes a single logical LLM call, retrying on failure per the configured\n * policy. Fails fast if the breaker is open or the signal is already\n * aborted. Rejects with a normalized LLMError on exhausted retries.\n *\n * When `tools` is set, returns a `CallWithToolsResult<T>` instead of `T`:\n * `{ type: 'content', content }` or `{ type: 'tool_calls', toolCalls,\n * content? }`. VernLLM never executes tools; run them yourself and\n * continue via `history` (see `ConversationTurn`). Mutually exclusive\n * with `jsonSchema`/`schema`.\n *\n * TypeScript picks the tools-aware overload (`CallWithToolsResult<T>`)\n * when `tools` is a literal array on `params`, and the conditional-tools\n * overload (`T | CallWithToolsResult<T>`, see `ConditionalToolCallParams`)\n * when `tools` is present but statically `ToolDefinition[] | undefined`,\n * e.g. `const tools = condition ? [myTool] : undefined`. Either way, use\n * `isToolCallResult()` to narrow the result once `tools` isn't a literal\n * array: TypeScript's static type can't know from the `ConditionalToolCallParams`\n * shape alone whether tools actually ran on a given call. Only omitting\n * `tools` entirely resolves to the plain `T` overload, since then tools\n * genuinely cannot have run. See the Tool Calling docs for details.\n *\n * The same static-vs-dynamic caveat applies to `stream`: TypeScript only\n * selects the streaming overload (returning `StreamCallResult<...>`) when\n * `stream: true` is statically present on `params`. A `stream` value set\n * conditionally on a plain `CallParams<T>` still resolves to `Promise<T>`\n * (or `Promise<CallWithToolsResult<T>>`) at the type level even though\n * the actual runtime result is the `{ chunks, finalResult }` streaming\n * shape whenever `stream` evaluates to `true`, callers doing this should\n * narrow/cast accordingly rather than relying on the static return type.\n *\n * @param params System/user content plus per-call overrides. See `CallParams`.\n * @returns Without `tools` or `stream`: the parsed response, or raw\n * string if `jsonMode` is false. With `tools`: a `CallWithToolsResult<T>`,\n * narrowed to `ContentResult<T>` when `toolChoice: 'none'` is set, since\n * the model is then structurally barred from returning a `tool_calls`\n * result. With `stream: true` (statically): a `{ chunks, finalResult }`\n * `StreamCallResult`, `finalResult` resolving to whichever of the above\n * shapes applies once the stream completes. See `StreamCallResult`.\n */\n async call<T = unknown>(\n params: StreamEnabledCallParams<T> & ToolsDisabledCallParams<T>,\n ): Promise<StreamCallResult<ContentResult<T>>>;\n\n async call<T = unknown>(\n params: StreamEnabledCallParams<T> & ToolEnabledCallParams<T>,\n ): Promise<StreamCallResult<CallWithToolsResult<T>>>;\n\n async call<T = unknown>(\n params: StreamEnabledCallParams<T> & ConditionalToolCallParams<T>,\n ): Promise<StreamCallResult<T | CallWithToolsResult<T>>>;\n\n async call(params: StreamJsonModeDisabledCallParams): Promise<StreamCallResult<string>>;\n\n async call(params: StreamJsonModeEnabledCallParams): Promise<StreamCallResult<JsonValue>>;\n\n async call<T = unknown>(params: StreamEnabledCallParams<T>): Promise<StreamCallResult<T>>;\n\n async call<T = unknown>(params: ToolsDisabledCallParams<T>): Promise<ContentResult<T>>;\n\n async call<T = unknown>(params: ToolEnabledCallParams<T>): Promise<CallWithToolsResult<T>>;\n\n async call<T = unknown>(\n params: ConditionalToolCallParams<T>,\n ): Promise<T | CallWithToolsResult<T>>;\n\n async call(params: JsonModeDisabledCallParams): Promise<string>;\n\n async call(params: JsonModeEnabledCallParams): Promise<JsonValue>;\n\n async call<T = unknown>(params: CallParams<T>): Promise<T>;\n\n async call<T = unknown>(\n params: CallParams<T>,\n ): Promise<T | CallWithToolsResult<T> | StreamCallResult<T | CallWithToolsResult<T>>> {\n if (params.signal?.aborted) {\n throw new LLMError('LLM request aborted', 'aborted');\n }\n\n const requestId = params.requestId ?? randomUUID();\n\n // A lone target (no `fallback` configured) keeps the exact pre-fallback\n // contract: the breaker is checked once, up front, before usage is\n // reserved, so a call that's definitely blocked never pays a\n // reserve-then-refund round trip. This can only be hoisted out of the\n // chain for the sole-target case: `assertBreakerClosed` claims a\n // half-open trial slot as a side effect, which must happen exactly\n // once per logical call, so with more than one target the check has\n // to stay inside `runFallbackChain`, where an open primary is just\n // another target failure that `fallbackOn` can fall over from.\n const soleTarget = this.executors.length === 1;\n\n if (soleTarget) {\n this.executors[0]!.assertBreakerClosed(params.model);\n }\n\n if (params.stream) {\n // Same breaker/logging treatment as non-streaming, applied around\n // opening the stream; mid-stream failures are handled separately\n // inside the executor and never fall over (see `runFallbackChain`).\n // Usage refund/report is deferred onto finalResult, since call()\n // must return { chunks, finalResult } before the real outcome is\n // known, which is also why `params.meta` isn't populated for\n // streaming calls.\n return withReservedUsageForStream(\n params,\n async () => {\n const { result } = await this.runFallbackChain(\n params,\n requestId,\n (executor, onAttempt) => executor.runStream(params, requestId, onAttempt),\n soleTarget,\n );\n return result;\n },\n params.signal,\n (logMessage, error) => this.logRefundError(logMessage, error),\n );\n }\n\n return withReservedUsage(\n params,\n false,\n async () => {\n const { result, executor, index, attemptCount } = await this.runFallbackChain(\n params,\n requestId,\n (target, onAttempt) => target.run(params, requestId, onAttempt),\n soleTarget,\n );\n\n if (params.meta) {\n params.meta.current = {\n provider: executor.providerName,\n model: params.model ?? executor.model,\n fallbackIndex: index - 1,\n usedFallback: index > 0,\n attempts: attemptCount,\n };\n }\n\n return result;\n },\n params.signal,\n (logMessage, error) => this.logRefundError(logMessage, error),\n );\n }\n\n /**\n * Thin delegator kept private on `VernLLM` (rather than only existing on\n * `CacheOrchestrator`) since it's the one caching primitive exercised\n * directly by white-box tests, independent of the public `cachedCall()`\n * surface.\n */\n private runCached<T>(params: InternalCacheParams<T>) {\n return this.cacheOrchestrator.runCached(params);\n }\n\n /**\n * Removes a cached response by key when the configured cache adapter\n * supports deletion. Cache invalidation is the caller's responsibility;\n * only the application knows when cached data is stale.\n *\n * @param key The raw cache key (resolved through the adapter's\n * `resolveKey`, if any, before deletion).\n */\n async deleteCache(key: string): Promise<void> {\n await this.cacheOrchestrator.deleteCache(key);\n }\n\n /**\n * Cache wrapper composing `call` + caching, so cached LLM calls\n * automatically get retry/timeout/circuit-breaker behavior. `reserveUsage`/\n * `refundUsage` are read from the top-level params only. Concurrent misses\n * for the same `cacheKey` share a single in-flight call, avoiding cache\n * stampedes. Supports `stream: true` and `tools` in any combination.\n *\n * When `call.tools` is set, this caches the whole `CallWithToolsResult`,\n * including `tool_calls` results, not just final answers. Whether\n * that's appropriate depends on the tool: caching \"the model decided to\n * call get_weather\" is usually fine to reuse briefly, but caching a\n * decision made under permissions or account state that can change\n * between calls is not. Use a short `ttl` or a separate `cacheKey` for\n * such tools if this distinction matters.\n *\n * There is no public way to cache an arbitrary non-LLM function through\n * `VernLLM`. This method always composes with `call()`. For\n * general-purpose caching unrelated to an LLM call, use a dedicated\n * caching library at the application level instead.\n *\n * @param params `cacheKey`, `ttl`, and optional\n * `reserveUsage`/`refundUsage`/`signal`, plus `call`, the `CallParams`\n * (optionally with `tools` and/or `stream`) to pass through to\n * `this.call(...)`. The top-level `signal` governs the cached operation\n * and its usage hooks only; to also abort the underlying provider\n * request, set `signal` inside `call`.\n * @returns The cached value on a hit, or the freshly-called result on a miss.\n */\n async cachedCall<T>(\n params: CachedStreamToolCallParams<T>,\n ): Promise<StreamCallResult<CallWithToolsResult<T>>>;\n\n async cachedCall<T>(\n params: CachedStreamConditionalToolCallParams<T>,\n ): Promise<StreamCallResult<T | CallWithToolsResult<T>>>;\n\n async cachedCall(\n params: CachedStreamJsonModeDisabledCallParams,\n ): Promise<StreamCallResult<string>>;\n\n async cachedCall(\n params: CachedStreamJsonModeEnabledCallParams,\n ): Promise<StreamCallResult<JsonValue>>;\n\n async cachedCall<T>(params: CachedStreamCallParams<T>): Promise<StreamCallResult<T>>;\n\n async cachedCall<T>(params: CachedToolCallParams<T>): Promise<CallWithToolsResult<T>>;\n\n async cachedCall<T>(\n params: CachedConditionalToolCallParams<T>,\n ): Promise<T | CallWithToolsResult<T>>;\n\n async cachedCall(params: CachedJsonModeDisabledCallParams): Promise<string>;\n\n async cachedCall(params: CachedJsonModeEnabledCallParams): Promise<JsonValue>;\n\n async cachedCall<T>(params: CachedCallParams<T>): Promise<T>;\n\n async cachedCall<T>(\n params:\n | CachedCallParams<T>\n | CachedToolCallParams<T>\n | CachedConditionalToolCallParams<T>\n | CachedStreamCallParams<T>\n | CachedStreamToolCallParams<T>\n | CachedStreamConditionalToolCallParams<T>\n | CachedJsonModeDisabledCallParams\n | CachedJsonModeEnabledCallParams\n | CachedStreamJsonModeDisabledCallParams\n | CachedStreamJsonModeEnabledCallParams,\n ): Promise<T | CallWithToolsResult<T> | StreamCallResult<T | CallWithToolsResult<T>>> {\n const { call: callParams, ...cacheParams } = params;\n\n // `callParams`'s type no longer includes reserveUsage/refundUsage (see\n // CachedCallParams et al.): a well-typed caller can't reach this branch\n // at all, TypeScript rejects it at the call site instead. This check is\n // a defense-in-depth backstop for callers that bypass the type system\n // (plain JS, or an `as any` cast), and now throws instead of silently\n // ignoring the hooks and continuing: reserveUsage/refundUsage exist as\n // a cost-control safety mechanism, so silently dropping them fails\n // open, not safe, which a warning callers may never see doesn't fix.\n const restCallParams = callParams as CallParams<T>;\n\n if (restCallParams.reserveUsage || restCallParams.refundUsage) {\n throw new LLMError(\n '`reserveUsage`/`refundUsage` were set inside `call`, where cachedCall ignores them. Move them ' +\n 'to the top level of the cachedCall() params, alongside cacheKey/ttl, instead.',\n 'invalid_params',\n );\n }\n\n if (restCallParams.stream) {\n const streamParams = restCallParams as StreamEnabledCallParams<T>;\n\n return this.cacheOrchestrator.runCachedStream(\n {\n ...cacheParams,\n openStream: () => this.call(streamParams),\n },\n Boolean(restCallParams.tools),\n );\n }\n\n return this.runCached({\n ...cacheParams,\n fn: () => this.call(restCallParams),\n });\n }\n\n /**\n * @param target.index Which target to read. Defaults to the primary.\n * @param target.model Which model bucket to read, if the target isolates by model.\n * @returns The breaker state, or `undefined` if that target has no breaker.\n * @throws {RangeError} If `target.index` names no target. Lets a real\n * target with no breaker (`undefined`) stay distinguishable from a\n * target that doesn't exist.\n */\n getCircuitState(target?: CircuitTarget): CircuitState | undefined {\n const executor = this.resolveExecutor(target?.index ?? 0, 'getCircuitState');\n this.warnIfModelUnsupported(executor.isolateByModel, target?.model, 'getCircuitState');\n\n return executor.getCircuitState(target?.model ?? executor.model);\n }\n\n /**\n * @param model Which model bucket to read, for targets that isolate by model.\n * @returns Every target's state, in chain order.\n */\n getCircuitStates(model?: string): TargetCircuitState[] {\n return this.executors.map((executor, index) => ({\n provider: executor.providerName,\n index,\n isFallback: index > 0,\n isolateByModel: executor.isolateByModel,\n state: executor.getCircuitState(model ?? executor.model),\n }));\n }\n\n /**\n * Manually opens a target's breaker, e.g. to pull a provider out of\n * rotation ahead of known maintenance instead of waiting for it to fail.\n *\n * @param target.index Which target to open. Defaults to the primary.\n * @param target.model Which model bucket to open, if the target isolates by model.\n * @throws {RangeError} If `target.index` names no target.\n */\n openCircuit(target?: CircuitTarget): void {\n const executor = this.resolveExecutor(target?.index ?? 0, 'openCircuit');\n this.warnIfModelUnsupported(executor.isolateByModel, target?.model, 'openCircuit');\n executor.openCircuit(target?.model ?? executor.model);\n }\n\n /**\n * Manually closes a target's breaker, e.g. once a provider is confirmed\n * healthy again without waiting out the cooldown.\n *\n * @param target.index Which target to close. Defaults to the primary.\n * @param target.model Which model bucket to close, if the target isolates by model.\n * @throws {RangeError} If `target.index` names no target.\n */\n closeCircuit(target?: CircuitTarget): void {\n const executor = this.resolveExecutor(target?.index ?? 0, 'closeCircuit');\n this.warnIfModelUnsupported(executor.isolateByModel, target?.model, 'closeCircuit');\n executor.closeCircuit(target?.model ?? executor.model);\n }\n\n /** Resolves a target index so every circuit-breaker method agrees on what counts as valid. */\n private resolveExecutor(index: number, caller: string): CallExecutor {\n const executor = this.executors[index];\n\n if (!executor) {\n throw new RangeError(\n `${caller}: no target at index ${index} (chain has ${this.executors.length} target${this.executors.length === 1 ? '' : 's'})`,\n );\n }\n\n return executor;\n }\n\n /** Warns when `model` can't do anything on this target, so it's never silently ignored. */\n private warnIfModelUnsupported(\n isolateByModel: boolean,\n model: string | undefined,\n caller: string,\n ): void {\n if (model !== undefined && !isolateByModel) {\n this.logger.warn(\n `[VernLLM] ${caller}: \\`model: '${model}'\\` has no effect here. This target's circuitBreaker doesn't have isolateByModel on, so it only tracks one shared circuit regardless of \\`model\\`. Omit \\`model\\`, or set \\`circuitBreaker.isolateByModel: true\\` on this target if per-model tracking is what you want.`,\n );\n }\n }\n}\n\n/**\n * Identity function preserving `params`'s own precise type, unlike a `:\n * CallParams<T>` annotation, which would widen `tools` away and break the\n * `ConditionalToolCallParams<T>` overload for `tools: someCondition ?\n * [tool] : undefined`. Use it when you need `call()` params in a named,\n * reusable variable; skip it when you can pass the object inline.\n *\n * ```ts\n * const params = defineCallParams({\n * userContent: 'What is the weather?',\n * tools: someCondition ? [weatherTool] : undefined,\n * });\n * const result = await llm.call(params);\n * // result: unknown | CallWithToolsResult<unknown>, same as inline\n * ```\n *\n * `T` isn't a parameter here; pin it via `llm.call<T>(params)` as usual.\n * `defineCachedCallParams` is the `cachedCall()` counterpart.\n */\nexport function defineCallParams<P extends CallParams<unknown>>(params: P): P {\n return params;\n}\n\n/**\n * The `cachedCall()` counterpart to `defineCallParams`: preserves the\n * whole `{ cacheKey, ttl, call }` object, `call.tools` included, in one\n * named variable.\n *\n * ```ts\n * const params = defineCachedCallParams({\n * cacheKey: 'weather-ny',\n * ttl: 60,\n * call: { userContent: 'What is the weather?', tools: someCondition ? [weatherTool] : undefined },\n * });\n * const result = await llm.cachedCall(params);\n * ```\n */\nexport function defineCachedCallParams<P extends CachedCallParams<unknown>>(params: P): P {\n return params;\n}\n","import { LLMError } from '../../types/errors.js';\n\n/**\n * Parses a Server-Sent-Events byte/text stream into the JSON payload of\n * each `data:` frame, in arrival order. Generic over transport: works with\n * anything that hands back progressively-arriving `Uint8Array` or `string`\n * chunks via async iteration: native `fetch`'s `response.body` (wrapped\n * to be iterable, see `webStreamToAsyncIterable` in `fetch.ts`), axios's\n * Node `Readable` (already async-iterable, no wrapping needed), etc, so\n * this framing layer doesn't care which transport produced the bytes.\n *\n * Follows the SSE spec's frame-delimiting rules closely enough for LLM\n * streaming responses: frames are separated by a blank line, each frame\n * may carry one or more `data:` lines (joined with `\\n` per spec when\n * there's more than one), `:`-prefixed lines are comments and ignored, and\n * other SSE fields (`event:`, `id:`, `retry:`) are ignored since VernLLM\n * only needs the payload. A frame whose data is exactly `[DONE]` (the\n * sentinel several providers, notably OpenAI, send to mark stream end)\n * ends iteration without yielding it.\n *\n * Line endings: `\\r\\n` and bare `\\r` (both legal per the SSE spec, alongside `\\n`) are normalized\n * to `\\n` before frame splitting. A `\\r` at the very end of the currently-buffered text is left\n * alone until either more text arrives (in case it's the first half of a split `\\r\\n` pair) or the\n * stream ends, so a `\\r\\n` pair split across two transport chunks is never misread as two blank\n * lines.\n *\n * Malformed JSON in a frame throws `LLMError('parse')`, consistent with\n * how malformed JSON is handled elsewhere in VernLLM.\n */\nexport async function* parseSseStream(\n source: AsyncIterable<Uint8Array | string>,\n): AsyncGenerator<unknown> {\n // `fatal: true` makes invalid UTF-8 throw instead of silently decoding\n // to U+FFFD replacement characters, which could otherwise land inside a\n // JSON string and either corrupt it unnoticeably or, worse, still parse\n // as syntactically valid JSON with silently-wrong content.\n const decoder = new TextDecoder('utf-8', { fatal: true });\n let buffer = '';\n\n for await (const chunk of source) {\n let text: string;\n\n try {\n text = typeof chunk === 'string' ? chunk : decoder.decode(chunk, { stream: true });\n } catch (cause) {\n throw new LLMError('Invalid UTF-8 in SSE stream', 'parse', { cause });\n }\n\n // Normalized against the whole buffer, not just the newly-arrived\n // chunk: a `\\r\\n` delimiter can straddle a chunk boundary (one chunk\n // ending in `\\r`, the next starting with `\\n`), and normalizing only\n // the new text would miss that split pair. A bare trailing `\\r` (not\n // followed by anything yet) is left as-is for the same reason; it's\n // converted once either more text or end-of-stream resolves whether\n // it was standalone or the start of a split `\\r\\n`.\n buffer = (buffer + text).replace(/\\r\\n/g, '\\n').replace(/\\r(?!$)/g, '\\n');\n\n let boundary = buffer.indexOf('\\n\\n');\n\n while (boundary !== -1) {\n const frame = buffer.slice(0, boundary);\n\n buffer = buffer.slice(boundary + 2);\n\n const event = parseSseFrame(frame);\n\n if (event === DONE) return;\n if (event !== NO_DATA) yield event;\n\n boundary = buffer.indexOf('\\n\\n');\n }\n }\n\n // Flush any bytes TextDecoder held back mid-decode, so a truncated\n // multi-byte char surfaces as a parse error instead of silently\n // vanishing (and possibly leaving behind valid-looking, wrong JSON).\n try {\n buffer += decoder.decode();\n } catch (cause) {\n throw new LLMError('Invalid UTF-8 in SSE stream', 'parse', { cause });\n }\n\n // The stream has ended, so a trailing `\\r` still held back above (it\n // could have been the start of a split `\\r\\n` pair) can only be a bare\n // CR line ending now. Normalize it and re-check for any frame boundary\n // it just completed.\n buffer = buffer.replace(/\\r$/, '\\n');\n\n let boundary = buffer.indexOf('\\n\\n');\n\n while (boundary !== -1) {\n const frame = buffer.slice(0, boundary);\n\n buffer = buffer.slice(boundary + 2);\n\n const event = parseSseFrame(frame);\n\n if (event === DONE) return;\n if (event !== NO_DATA) yield event;\n\n boundary = buffer.indexOf('\\n\\n');\n }\n\n // Flush a final frame that arrived without a trailing blank line: some\n // servers close the connection right after the last `data:` line instead\n // of sending one more `\\n\\n` first.\n const trailing = buffer.trim();\n\n if (trailing) {\n const event = parseSseFrame(trailing);\n\n if (event !== DONE && event !== NO_DATA) yield event;\n }\n}\n\nconst DONE = Symbol('sse-stream-done');\nconst NO_DATA = Symbol('sse-frame-no-data');\n\n/**\n * Sentinel yielded by `parseSseStream` for a comment-only frame (no\n * `data:` payload), the mechanism providers use for SSE keep-alive\n * pings. Exported so a consumer (e.g. `fromFetch`) can react to \"still\n * alive\" separately from a genuinely empty frame (`NO_DATA`, kept internal).\n */\nexport const SSE_PING = Symbol('sse-frame-ping');\n\n/** Extracts and JSON-parses the `data:` payload of one SSE frame (the text between two blank lines). */\nfunction parseSseFrame(frame: string): unknown {\n const dataLines: string[] = [];\n let sawComment = false;\n\n for (const line of frame.split('\\n')) {\n if (line.startsWith(':')) {\n sawComment = true; // comment line, also used as a keep-alive ping\n continue;\n }\n if (!line.startsWith('data:')) continue; // ignore event:/id:/retry:/blank lines\n\n // A single space after the colon is stripped per the SSE spec; further\n // leading whitespace is preserved as part of the payload.\n dataLines.push(line.startsWith('data: ') ? line.slice(6) : line.slice(5));\n }\n\n if (!dataLines.length) return sawComment ? SSE_PING : NO_DATA;\n\n const data = dataLines.join('\\n');\n\n if (data === '[DONE]') return DONE;\n\n try {\n return JSON.parse(data);\n } catch (cause) {\n throw new LLMError(`Invalid JSON in SSE frame: ${data.slice(0, 200)}`, 'parse', {\n cause,\n code: 'stream_frame_invalid',\n });\n }\n}\n","import { LLMError } from '../../types/index.js';\n\n/**\n * MIME types accepted for `ImageBlock.mimeType` across all adapters. This is\n * the intersection of what Anthropic, Gemini, OpenAI-compatible, and Bedrock\n * Converse all natively support, so a `ContentBlock[]` that validates for\n * one provider validates for all of them.\n */\nexport const SUPPORTED_IMAGE_MIME_TYPES = [\n 'image/png',\n 'image/jpeg',\n 'image/gif',\n 'image/webp',\n] as const;\n\nexport type SupportedImageMimeType = (typeof SUPPORTED_IMAGE_MIME_TYPES)[number];\n\n/**\n * Validates an `ImageBlock.mimeType` against the shared supported set.\n * Throws a non-retryable `LLMError('invalid_params')`, since an unsupported\n * mimeType is a bug in the caller's own input, deterministic before any\n * request is built, the same class of failure as every other check in\n * `RequestBuilder`.\n */\nexport function assertSupportedImageMimeType(mimeType: string): SupportedImageMimeType {\n if ((SUPPORTED_IMAGE_MIME_TYPES as readonly string[]).includes(mimeType)) {\n return mimeType as SupportedImageMimeType;\n }\n\n throw new LLMError(\n `Unsupported image mimeType \"${mimeType}\": expected one of ${SUPPORTED_IMAGE_MIME_TYPES.join(', ')}`,\n 'invalid_params',\n );\n}\n","/**\n * A static allow-list or predicate naming which models support native,\n * schema-constrained output as its own request field — Anthropic's\n * `output_config.format`, Bedrock's `outputConfig.textFormat` — separate\n * from `tools`/`tool_choice`, so it can be combined with real,\n * caller-supplied `tools` in the same request.\n *\n * There is no built-in default list here. Which models support this is\n * Anthropic's and Bedrock's call to make, not this package's, and it\n * changes over time; hardcoding a guessed list would risk silently\n * routing a request onto a field a given model doesn't actually support,\n * trading a clear `LLMError('validation')` for a confusing error from the\n * provider instead. So this is opt-in: pass the model IDs you've verified\n * against the provider's own docs (or a predicate). Left unset, no model\n * is treated as native-capable, `jsonSchema` keeps using the older\n * forced-single-tool-call emulation, and `tools` + `jsonSchema` together\n * is rejected, exactly this package's behavior before native support was\n * added.\n */\nexport type ModelCapabilityOverride = string[] | ((model: string) => boolean);\n\n/** Resolves whether `model` is covered by a caller-supplied allow-list/predicate. */\nexport function supportsNativeStructuredOutput(\n model: string,\n override?: ModelCapabilityOverride,\n): boolean {\n if (!override) return false;\n\n return Array.isArray(override) ? override.includes(model) : override(model);\n}\n","import { LLMError } from '../../types/errors.js';\n\nimport type { ModelCapabilityOverride } from './nativeStructuredOutput.js';\n\n/**\n * Shared conversion between the two reasoning controls VernLLM exposes:\n * `reasoningEffort` (a tier string, OpenAI's native shape) and\n * `budgetTokens` (a raw integer, Anthropic's and Gemini's native shape).\n *\n * Every adapter prefers its own native field when the caller set it, and\n * only calls into this table when the caller set the other one instead.\n * The numbers here are a guess, not a provider guarantee, callers who\n * need a precise budget on a specific model should set `budgetTokens`\n * directly rather than relying on this table's `reasoningEffort` mapping.\n *\n * The table itself is overridable per adapter instance, via\n * `reasoningEffortTokens` on each `from*` adapter's options (see\n * `AnthropicAdapterOptions`, `GeminiAdapterOptions`,\n * `OpenAICompatibleAdapterOptions`, `BedrockAdapterOptions`), for callers\n * who want `reasoningEffort` tiers to map onto different token counts\n * than the defaults below, e.g. a model whose useful reasoning range\n * doesn't match these numbers.\n */\n\nexport type EffortTokenTable = Record<'minimal' | 'low' | 'medium' | 'high', number>;\n\nexport const DEFAULT_EFFORT_TOKENS: EffortTokenTable = {\n minimal: 1024,\n low: 4096,\n medium: 16000,\n high: 32000,\n};\n\n/**\n * Merges a caller-supplied partial override over `DEFAULT_EFFORT_TOKENS`.\n * Called once per adapter instance (not per request), so a per-instance\n * override only needs to specify the tiers it actually wants to change.\n *\n * Throws `LLMError('invalid_params')` if the override doesn't keep the\n * tiers in strictly ascending order (`minimal < low < medium < high`).\n * `budgetTokensToEffort` buckets by walking the tiers low to high and\n * returning on the first one a value is `<=`, so an unordered table (e.g.\n * `low` above `medium`) wouldn't just produce a \"wrong\" bucket, it would\n * make some tiers unreachable outright, silently, with no signal to the\n * caller that their override doesn't do what they think it does.\n */\nexport function resolveEffortTokenTable(override?: Partial<EffortTokenTable>): EffortTokenTable {\n if (!override) return DEFAULT_EFFORT_TOKENS;\n\n const table = { ...DEFAULT_EFFORT_TOKENS, ...override };\n\n if (!(table.minimal < table.low && table.low < table.medium && table.medium < table.high)) {\n throw new LLMError(\n `reasoningEffortTokens must keep tiers in strictly ascending order ` +\n `(minimal < low < medium < high), got ${JSON.stringify(table)}. An out-of-order ` +\n `override doesn't just misrank tiers, it can make some of them unreachable.`,\n 'invalid_params',\n );\n }\n\n return table;\n}\n\n/** Converts a `reasoningEffort` tier into the nearest `budgetTokens` value. */\nexport function effortToBudgetTokens(\n effort: 'minimal' | 'low' | 'medium' | 'high',\n table: EffortTokenTable = DEFAULT_EFFORT_TOKENS,\n): number {\n return table[effort];\n}\n\n/**\n * Converts a raw `budgetTokens` value into the nearest `reasoningEffort`\n * tier, for providers that only understand tiers. Buckets by the same\n * `table` `effortToBudgetTokens` produces its values from, so the two\n * functions agree with each other at the boundary values, as long as the\n * same (possibly overridden) table is passed to both. A value strictly\n * between two tiers (e.g. 4097, one above the default `low`) rounds up to\n * the next tier it's still `<=`, i.e. `medium` here, not down to `low`.\n */\nexport function budgetTokensToEffort(\n budgetTokens: number,\n table: EffortTokenTable = DEFAULT_EFFORT_TOKENS,\n): 'minimal' | 'low' | 'medium' | 'high' {\n if (budgetTokens <= table.minimal) return 'minimal';\n if (budgetTokens <= table.low) return 'low';\n if (budgetTokens <= table.medium) return 'medium';\n return 'high';\n}\n\n/**\n * Parses an Opus model id's generation and minor version, e.g.\n * `\"claude-opus-4-7-20260101\"` -> `[4, 7]`, `\"anthropic.claude-opus-5-x\"` ->\n * `[5, 0]`. Not anchored, so it matches equally inside a bare Anthropic id\n * or a Bedrock id carrying a provider prefix. Returns `null` for a\n * non-Opus model id.\n */\n/**\n * Parses an Opus model id's generation and minor version, e.g.\n * `\"claude-opus-4-7-20260101\"` -> `[4, 7]`, `\"anthropic.claude-opus-5-x\"` ->\n * `[5, 0]`. Not anchored, so it matches equally inside a bare Anthropic id\n * or a Bedrock id carrying a provider prefix. Returns `null` for a\n * non-Opus model id.\n *\n * Anthropic model ids sometimes carry a trailing snapshot date instead of\n * (or in addition to) an explicit minor version, e.g. the real, still-\n * supported base `\"claude-opus-4-20250514\"` (no `.7`-style minor at all,\n * just a date suffix directly after the major version). Read naively,\n * `20250514` looks like a minor version far above any real threshold and\n * would misclassify this pre-4.6 model as adaptive-only. Snapshot dates\n * are always 8 digits (`YYYYMMDD`); a real minor version never is, so an\n * 8+ digit second segment is treated as a date, not a minor version.\n */\nfunction parseOpusVersion(model: string): [major: number, minor: number] | null {\n const match = /opus-(\\d+)(?:-(\\d+))?/.exec(model);\n if (!match) return null;\n\n const minorStr = match[2];\n const minor = minorStr === undefined || minorStr.length >= 8 ? 0 : Number(minorStr);\n\n return [Number(match[1]), minor];\n}\n\n/**\n * Default rule for whether `model` only supports adaptive thinking\n * (`thinking: { type: 'adaptive' }`) and returns a 400 for manual,\n * budget-based thinking (`thinking: { type: 'enabled', budget_tokens }`):\n * Claude Opus 4.7 and later (matched as a version threshold, so 4.8, 4.9,\n * 5, and every future Opus point release are covered automatically,\n * without a new list entry per release), and every Claude 5 tier model\n * outside the Opus family (Sonnet 5, Fable 5, Mythos 5, Mythos Preview).\n * `mythos` alone is enough to catch both Mythos names without listing\n * each separately.\n *\n * Necessarily best-effort: a new model family with its own name (not\n * `opus-*`, not `sonnet-5`/`fable-5`/`mythos-*`) still needs a code\n * update here, or a caller-supplied `adaptiveOnlyModels` override (see\n * `isAdaptiveOnlyModel`) covering it in the meantime.\n */\nfunction isDefaultAdaptiveOnly(model: string): boolean {\n const opusVersion = parseOpusVersion(model);\n\n if (opusVersion) {\n const [major, minor] = opusVersion;\n return major > 4 || (major === 4 && minor >= 7);\n }\n\n return ['sonnet-5', 'fable-5', 'mythos'].some((s) => model.includes(s));\n}\n\n/**\n * Whether `model` is adaptive-only, per the built-in rule above, or per a\n * caller-supplied `adaptiveOnlyModels` override. The override is\n * additive, not a replacement: it can mark an *additional* model as\n * adaptive-only (useful for a model family this package doesn't know\n * about yet), but it can't un-mark one the built-in rule already caught,\n * since a caller correcting a false negative is the only direction that\n * needs covering, a false positive here would mean this package is\n * simply wrong and needs its own fix, not a per-caller workaround.\n */\nexport function isAdaptiveOnlyModel(model: string, override?: ModelCapabilityOverride): boolean {\n if (isDefaultAdaptiveOnly(model)) return true;\n if (!override) return false;\n\n return Array.isArray(override) ? override.includes(model) : override(model);\n}\n\n/** Whether `model` is known to support manual, budget-based thinking. */\nexport function supportsManualThinkingBudget(\n model: string,\n override?: ModelCapabilityOverride,\n): boolean {\n return !isAdaptiveOnlyModel(model, override);\n}\n\n/**\n * Anthropic (and Claude models on Bedrock) require `budget_tokens` to be\n * at least 1024 and strictly less than `max_tokens`, since the thinking\n * budget and the reply share the same `max_tokens` ceiling. VernLLM's own\n * default `maxTokens` is 1000 (see `RequestBuilder`'s `defaultMaxTokens`),\n * below the 1024 floor, so the *default* `minimal` tier (1024 tokens) is\n * silently invalid against the *default* `max_tokens` unless a caller\n * happens to raise one or the other. Checked here, once, right before a\n * `thinking` block would be built, rather than left for Anthropic's own\n * 400 to explain after a real network round trip.\n */\nexport function assertValidClaudeBudgetTokens(budgetTokens: number, maxTokens: number): void {\n if (budgetTokens < 1024) {\n throw new LLMError(\n `budgetTokens (${budgetTokens}) is below Anthropic's minimum of 1024. Raise budgetTokens, ` +\n `or use a reasoningEffort tier of 'low' or above with the default conversion table.`,\n 'invalid_params',\n );\n }\n\n if (budgetTokens >= maxTokens) {\n throw new LLMError(\n `budgetTokens (${budgetTokens}) must be less than maxTokens (${maxTokens}); the thinking ` +\n `budget and the reply share the same max_tokens ceiling on Anthropic. Raise maxTokens, ` +\n `or lower budgetTokens/reasoningEffort.`,\n 'invalid_params',\n );\n }\n}\n\n/**\n * Anthropic rejects any form of `thinking` (manual `budget_tokens` or\n * adaptive) combined with a `tool_choice` that forces tool use, a forced\n * single tool or \"must call some tool\", with a 400: `\"Thinking may not be\n * enabled when tool_choice forces tool use.\"` Auto/none (or no tools at\n * all) are unaffected, thinking only conflicts with a choice that removes\n * the model's ability to just reply with text. This is a Claude-model\n * constraint, not specific to the Anthropic API's own wire shape, so it\n * applies identically to Claude models called through Bedrock's Converse\n * API, which forwards `thinking` under `additionalModelRequestFields` but\n * is still talking to the same underlying model.\n *\n * This combination can arise two ways: a caller explicitly sets both\n * `budgetTokens`/`reasoningEffort` and a forced `toolChoice`, or, more\n * subtly (Anthropic adapter only), a caller sets `jsonSchema` on a model\n * without native structured output support, which silently forces a\n * single synthetic tool call to emulate it, with no `tool_choice` of the\n * caller's own in sight. Both end up resolving to a forced tool choice by\n * the time each adapter calls this, so checking the adapter's own\n * already-resolved choice (rather than the caller's raw\n * `params.tool_choice`) catches both, right before a `thinking` block\n * would be built, rather than left for Anthropic's own 400 to explain\n * after a real network round trip.\n *\n * Takes a plain description of the forced choice rather than either\n * adapter's own wire shape (Anthropic SDK's `{ type: 'tool' | 'any', ... }`\n * vs Converse's `{ tool: {...} } | { any: {} }`), so both adapters can\n * share one check without either shape leaking into this file. Pass\n * `undefined` when the resolved choice is `auto`/`none`/unset, forcing\n * nothing.\n */\nexport function assertNoForcedToolChoiceWithThinking(\n forcedChoiceDescription: string | undefined,\n): void {\n if (!forcedChoiceDescription) return;\n\n throw new LLMError(\n `budgetTokens/reasoningEffort was set alongside ${forcedChoiceDescription}. Anthropic ` +\n 'rejects thinking combined with a tool_choice that forces tool use, the model has to be ' +\n \"able to reply with plain text for thinking to run. Use toolChoice: 'auto' (or omit \" +\n 'toolChoice) for this call, or drop budgetTokens/reasoningEffort for it.',\n 'invalid_params',\n );\n}\n\n/**\n * Anthropic's own effort levels for adaptive thinking, `output_config.effort`\n * (or Bedrock's typed `outputConfig.effort`), five tiers: `low`, `medium`,\n * `high`, `xhigh`, `max`. This is a different control than VernLLM's own\n * `reasoningEffort`/`budgetTokens`, not a token count, so it needs its own\n * mapping rather than reusing `EffortTokenTable`.\n */\nexport type ClaudeAdaptiveEffort = 'low' | 'medium' | 'high' | 'xhigh' | 'max';\n\n/**\n * Maps VernLLM's four-tier `reasoningEffort` onto Anthropic's five-tier\n * adaptive effort. `xhigh` and `max` have no VernLLM-side equivalent and\n * are unreachable through this mapping; a caller who wants either has to\n * target Anthropic/Bedrock-specific behavior already, so there's no gap\n * the shared `CallParams` surface needs to cover for a first pass.\n */\nexport function toClaudeAdaptiveEffort(\n effort: 'minimal' | 'low' | 'medium' | 'high',\n): ClaudeAdaptiveEffort {\n return effort === 'minimal' ? 'low' : effort;\n}\n\n/**\n * Gemini's own thinking-level control, `thinkingConfig.thinkingLevel`,\n * used by Gemini 3 series models instead of the numeric `thinkingBudget`\n * every earlier Gemini generation uses. Unlike Anthropic's five-tier\n * adaptive effort, this lines up exactly with VernLLM's own four-tier\n * `reasoningEffort`, so no lossy mapping table is needed, just a literal\n * case change.\n */\nexport type GeminiThinkingLevel = 'MINIMAL' | 'LOW' | 'MEDIUM' | 'HIGH';\n\n/** Converts VernLLM's `reasoningEffort` directly into Gemini's `ThinkingLevel` enum value. */\nexport function toGeminiThinkingLevel(\n effort: 'minimal' | 'low' | 'medium' | 'high',\n model: string,\n): GeminiThinkingLevel {\n return clampGeminiThinkingLevel(model, effort.toUpperCase() as GeminiThinkingLevel);\n}\n\n/**\n * Parses a Gemini model id's minor version, e.g. `\"gemini-3.1-pro\"` -> `1`,\n * `\"gemini-3-pro\"` -> `0` (no explicit minor). Only meaningful alongside\n * `parseGeminiMajorVersion`.\n */\nfunction parseGeminiMinorVersion(model: string): number {\n const match = /gemini-\\d+\\.(\\d+)/.exec(model);\n return match ? Number(match[1]) : 0;\n}\n\n/**\n * Some Gemini 3 \"Pro\" tier models accept a narrower set of `thinkingLevel`\n * values than VernLLM's four tiers map onto, confirmed against real API\n * 400s and Google's own migration guidance, not assumed:\n * - Gemini 3 Pro (major 3, minor 0, e.g. `\"gemini-3-pro-preview\"`): only\n * `LOW` and `HIGH`; `MEDIUM` returns a 400 (\"Thinking level MEDIUM is\n * not supported for this model\").\n * - Gemini 3.1 Pro (major 3, minor >= 1): `LOW`/`MEDIUM`/`HIGH`, no\n * `MINIMAL`, Google's own docs point users toward a Flash-tier model\n * instead for the lowest setting.\n * - Every Flash-tier Gemini 3+ model accepts the full four levels, no\n * clamping needed, matched by this function simply not applying to\n * anything without `\"pro\"` in the model id.\n *\n * Clamped automatically rather than left to error, since `reasoningEffort`\n * is a per-call value, a caller hitting this isn't misconfiguring an\n * instance once, they're getting an intermittent-looking failure on\n * whichever specific call happened to pick an unsupported tier. Necessarily\n * best-effort: a future Pro-tier release could add back a level this rule\n * still clamps, or clamp one this rule doesn't yet know to touch.\n */\nfunction clampGeminiThinkingLevel(model: string, level: GeminiThinkingLevel): GeminiThinkingLevel {\n if (!model.includes('pro')) return level;\n\n const major = parseGeminiMajorVersion(model);\n if (major === null || major < 3) return level;\n\n const minor = parseGeminiMinorVersion(model);\n\n if (minor === 0) {\n // Gemini 3 Pro: only LOW and HIGH are accepted.\n return level === 'HIGH' ? 'HIGH' : 'LOW';\n }\n\n // Gemini 3.1 Pro and later: LOW/MEDIUM/HIGH accepted, no MINIMAL.\n return level === 'MINIMAL' ? 'LOW' : level;\n}\n\n/**\n * Parses a Gemini model id's major generation number, e.g.\n * `\"gemini-3.1-flash-lite\"` -> `3`, `\"gemini-2.5-flash\"` -> `2`. Not\n * anchored, so a Vertex-prefixed or otherwise decorated id still matches.\n * Returns `null` for a non-Gemini model id.\n */\nfunction parseGeminiMajorVersion(model: string): number | null {\n const match = /gemini-(\\d+)/.exec(model);\n return match ? Number(match[1]) : null;\n}\n\n/**\n * Default rule for whether `model` uses `thinkingLevel` instead of\n * `thinkingBudget`: every Gemini 3 series model and later, matched as a\n * version threshold so 3.1, 3.5, 3.6, and every future Gemini 3.x or\n * later release are covered automatically, without a new entry per\n * release, same reasoning as `isDefaultAdaptiveOnly`'s Opus threshold.\n * Gemini 2.5 and earlier still use `thinkingBudget`.\n *\n * `thinkingBudget` is still *accepted* on Gemini 3 for backward\n * compatibility, per Google's own docs, but \"may result in unexpected\n * performance\" there, so this rule switches VernLLM's own default\n * behavior over rather than leaving it on the old field indefinitely.\n */\nfunction isDefaultThinkingLevelModel(model: string): boolean {\n const major = parseGeminiMajorVersion(model);\n return major !== null && major >= 3;\n}\n\n/**\n * Whether `model` uses `thinkingLevel`, per the built-in version\n * threshold above, or per a caller-supplied `thinkingLevelModels`\n * override. Additive, not a replacement, same reasoning as\n * `isAdaptiveOnlyModel`: an override can mark an *additional* model as\n * using `thinkingLevel` (a model family this package doesn't recognize\n * yet), it can't un-mark one the built-in threshold already caught.\n */\nexport function usesGeminiThinkingLevel(\n model: string,\n override?: ModelCapabilityOverride,\n): boolean {\n if (isDefaultThinkingLevelModel(model)) return true;\n if (!override) return false;\n\n return Array.isArray(override) ? override.includes(model) : override(model);\n}\n","import {\n LLMError,\n type ContentBlock,\n type LLMClient,\n type WireStreamChunk,\n type WireToolCall,\n} from '../types/index.js';\nimport {\n assertSupportedImageMimeType,\n type SupportedImageMimeType,\n} from './internal/imageFormat.js';\nimport {\n supportsNativeStructuredOutput,\n type ModelCapabilityOverride,\n} from './internal/nativeStructuredOutput.js';\nimport {\n assertNoForcedToolChoiceWithThinking,\n assertValidClaudeBudgetTokens,\n budgetTokensToEffort,\n effortToBudgetTokens,\n resolveEffortTokenTable,\n supportsManualThinkingBudget,\n toClaudeAdaptiveEffort,\n type ClaudeAdaptiveEffort,\n type EffortTokenTable,\n} from './internal/reasoningBudget.utils.js';\n\n/** Anthropic's native per-block content shape for a message. */\ntype AnthropicContentBlock =\n | { type: 'text'; text: string }\n | {\n type: 'image';\n source: { type: 'base64'; media_type: SupportedImageMimeType; data: string };\n }\n | { type: 'tool_use'; id: string; name: string; input: unknown }\n | { type: 'tool_result'; tool_use_id: string; content: string; is_error?: boolean };\n\n/** Minimal structural type for the Anthropic SDK's `messages.create` */\nexport interface AnthropicClient {\n messages: {\n create(\n params: {\n model: string;\n max_tokens: number;\n temperature?: number;\n system?: string;\n messages: Array<{ role: 'user' | 'assistant'; content: string | AnthropicContentBlock[] }>;\n tools?: Array<{\n name: string;\n description?: string;\n // The real Anthropic SDK's `Tool.input_schema` requires the\n // literal `type: 'object'` (VernLLM's own public `tools` API\n // accepts freeform JSON Schema, so this is narrower than that);\n // see the two call sites below for how a caller's schema is\n // asserted into this shape.\n input_schema: { type: 'object'; [key: string]: unknown };\n strict?: boolean;\n }>;\n tool_choice?:\n | { type: 'auto' }\n | { type: 'any' }\n | { type: 'none' }\n | { type: 'tool'; name: string };\n /**\n * Native, schema-constrained output: a separate request field from\n * `tools`/`tool_choice`, so it can be sent alongside real tool\n * calls. Only built by this adapter for models covered by\n * `nativeStructuredOutputModels` (opt-in, see\n * `AnthropicAdapterOptions`); other models keep getting\n * `jsonSchema` emulated as a forced single tool call, the\n * pre-existing behavior.\n *\n * Matches the real Anthropic API's `output_config.format` shape\n * exactly: just `type` and `schema`, no `name`/`description`/\n * `strict`. Those three exist on VernLLM's own `jsonSchema` API\n * (and are still forwarded on the legacy forced-tool-call path,\n * where they're real `Tool` fields), but the native structured-\n * output endpoint has no equivalent for any of them.\n */\n output_config?: {\n format?: {\n type: 'json_schema';\n schema: Record<string, unknown>;\n };\n /**\n * Effort control for adaptive thinking, on models where manual\n * `budget_tokens` thinking is no longer accepted (see\n * `supportsManualThinkingBudget` in\n * `adapters/internal/reasoningBudget.utils.ts`). Sibling to\n * `format`, either or both may be present independently.\n */\n effort?: 'low' | 'medium' | 'high' | 'xhigh' | 'max';\n };\n /**\n * Native reasoning control. `{ type: 'enabled', budget_tokens }`\n * is built directly from `CallParams.budgetTokens`, or converted\n * from `reasoningEffort`, on models that still accept a manual\n * token budget. `{ type: 'adaptive' }` is sent instead, paired\n * with `output_config.effort`, on models that only support\n * adaptive thinking. See\n * `adapters/internal/reasoningBudget.utils.ts`.\n */\n thinking?: { type: 'enabled'; budget_tokens: number } | { type: 'adaptive' };\n },\n options: { signal: AbortSignal },\n ): Promise<{\n content: Array<{ type: string; text?: string; id?: string; name?: string; input?: unknown }>;\n usage?: {\n input_tokens?: number;\n output_tokens?: number;\n output_tokens_details?: { thinking_tokens?: number } | null;\n };\n }>;\n };\n}\n\n/**\n * Translates a VernLLM `ContentBlock[]` (our provider-agnostic multimodal\n * shape) into Anthropic's native content-block array: text blocks pass\n * through as-is, image blocks become `{ type: 'image', source: { type:\n * 'base64', media_type, data } }`.\n */\nfunction toAnthropicContent(blocks: ContentBlock[]): AnthropicContentBlock[] {\n return blocks.map((block) =>\n block.type === 'image'\n ? {\n type: 'image',\n source: {\n type: 'base64',\n media_type: assertSupportedImageMimeType(block.mimeType),\n data: block.data,\n },\n }\n : { type: 'text', text: block.text },\n );\n}\n\n/**\n * Asserts a caller-supplied JSON Schema is an object schema before it's\n * used as Anthropic's `Tool.input_schema`, which (like every other\n * provider's function-calling API) requires `type: 'object'`. VernLLM's own\n * public `tools`/`jsonSchema` APIs accept freeform `Record<string,\n * unknown>` JSON Schema, so nothing upstream guarantees this at compile\n * time; this is the runtime check that stands in for that, so a schema\n * missing (or mistyping) `type: 'object'` fails loudly and immediately\n * instead of being silently forwarded to Anthropic malformed.\n */\nfunction assertObjectSchema(\n schema: Record<string, unknown>,\n toolName: string,\n): { type: 'object'; [key: string]: unknown } {\n if (schema.type !== 'object') {\n throw new LLMError(\n `Tool \"${toolName}\"'s schema must have \"type\": \"object\" (Anthropic requires object-shaped tool parameters).`,\n 'validation',\n );\n }\n\n return schema as { type: 'object'; [key: string]: unknown };\n}\n\n/**\n * Translates VernLLM's OpenAI-shaped wire `tool_choice` into Anthropic's\n * `{ type: 'auto' | 'any' | 'none' | 'tool', name? }` shape. `'required'`\n * maps to `'any'` (Anthropic's \"must call some tool\" equivalent).\n */\nfunction toAnthropicToolChoice(\n toolChoice: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice'],\n):\n | { type: 'auto' }\n | { type: 'any' }\n | { type: 'none' }\n | { type: 'tool'; name: string }\n | undefined {\n if (!toolChoice || toolChoice === 'auto') return { type: 'auto' };\n if (toolChoice === 'none') return { type: 'none' };\n if (toolChoice === 'required') return { type: 'any' };\n\n return { type: 'tool', name: toolChoice.function.name };\n}\n\n/** One SSE event of an Anthropic `messages.create({ stream: true })` stream. */\ntype AnthropicStreamEvent =\n | { type: 'message_start'; message: { usage?: { input_tokens?: number } } }\n | {\n type: 'content_block_start';\n index: number;\n content_block: { type: string; id?: string; name?: string };\n }\n | {\n type: 'content_block_delta';\n index: number;\n delta:\n | { type: 'text_delta'; text: string }\n | { type: 'input_json_delta'; partial_json: string };\n }\n | { type: 'content_block_stop'; index: number }\n | {\n type: 'message_delta';\n usage?: {\n output_tokens?: number;\n output_tokens_details?: { thinking_tokens?: number } | null;\n };\n }\n | { type: 'message_stop' }\n // Keep-alive event during long streams (e.g. extended thinking). Modeled\n // so the event switch has somewhere to route it. See createStream.\n | { type: 'ping' };\n\ntype AnthropicRequestBody = Parameters<AnthropicClient['messages']['create']>[0];\n\n/**\n * Maps VernLLM's OpenAI-shaped wire `tools`/`tool_choice` into Anthropic's\n * `tools`/`tool_choice` shape. Shared by the two call sites that build real\n * (non-schema-forced) tool definitions: the plain tools-only branch, and\n * the native-structured-output branch, which sends real tools alongside\n * `output_config` rather than instead of it.\n */\nfunction buildAnthropicTools(\n tools: NonNullable<Parameters<LLMClient['chat']['completions']['create']>[0]['tools']>,\n toolChoiceParam: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice'],\n): {\n tools: NonNullable<Parameters<AnthropicClient['messages']['create']>[0]['tools']>;\n toolChoice: Parameters<AnthropicClient['messages']['create']>[0]['tool_choice'];\n} {\n return {\n tools: tools.map((t) => ({\n name: t.function.name,\n description: t.function.description,\n // Tool parameters are always object schemas in practice (every\n // provider's function-calling API requires it).\n input_schema: assertObjectSchema(t.function.parameters, t.function.name),\n })),\n toolChoice: toAnthropicToolChoice(toolChoiceParam),\n };\n}\n\n/**\n * Builds the Anthropic-shaped request body from VernLLM's wire params,\n * shared between `create` and `createStream` so both go through identical\n * translation (system prompt, message shaping, and the jsonSchema →\n * forced-single-tool mapping all happen exactly once, not once per entry\n * point).\n *\n * Returns `toolName` alongside the body: when set, the model was forced to\n * call a single synthetic tool standing in for `jsonSchema` output (the\n * legacy path, for models without native structured-output support), and\n * both `create` and `createStream` need to know this so they can unwrap\n * that tool call back into plain text content instead of treating it like\n * a real tool call. On the native path (model supports `output_config`),\n * `toolName` is `undefined`: the schema-conforming JSON already arrives as\n * ordinary text content, nothing to unwrap, and any real tool calls in\n * `params.tools` are left for the normal, non-forced tool-call handling\n * both `create` and `createStream` already do when `toolName` is unset.\n */\nfunction buildAnthropicRequestBody(\n params: Parameters<LLMClient['chat']['completions']['create']>[0],\n nativeStructuredOutputModels?: ModelCapabilityOverride,\n effortTokenTable?: EffortTokenTable,\n adaptiveOnlyModels?: ModelCapabilityOverride,\n): { body: AnthropicRequestBody; toolName: string | undefined } {\n const systemMessage = params.messages.find((m) => m.role === 'system');\n\n // Keep user, assistant, and tool turns, in order. Anthropic has no\n // separate 'tool' role: tool results travel as a user-role message\n // containing tool_result content blocks, and an assistant's tool\n // requests travel as tool_use content blocks on its own turn.\n const conversationMessages = params.messages.filter(\n (m) => m.role === 'user' || m.role === 'assistant' || m.role === 'tool',\n );\n\n const jsonSchema =\n params.response_format?.type === 'json_schema' ? params.response_format.json_schema : undefined;\n\n const schemaName = jsonSchema?.name.trim();\n\n if (jsonSchema && !schemaName) {\n throw new LLMError('json_schema.name must not be empty.', 'validation');\n }\n\n const isNative =\n Boolean(jsonSchema) &&\n supportsNativeStructuredOutput(params.model, nativeStructuredOutputModels);\n\n if (jsonSchema && params.tools?.length && !isNative) {\n throw new LLMError(\n `Anthropic model \"${params.model}\" is not covered by nativeStructuredOutputModels, so ` +\n '`jsonSchema` is emulated as a forced single tool call there, which collides with the ' +\n '`tools` you also provided. Either drop `tools` or `jsonSchema` for this call, or pass ' +\n \"this model in fromAnthropic's `nativeStructuredOutputModels` option once you've \" +\n \"confirmed it supports Anthropic's `output_config.format`.\",\n 'validation',\n );\n }\n\n if (params.response_format?.type === 'json_object') {\n throw new LLMError(\n 'response_format: \"json_object\" is not supported on Anthropic. Unlike OpenAI, Anthropic ' +\n 'has no API-level field that mechanically guarantees valid JSON output for this mode, so ' +\n 'it used to be emulated by injecting a \"respond with JSON only\" instruction into the ' +\n 'system prompt, a guarantee this adapter can no longer make. Use `jsonSchema` instead, ' +\n \"which maps to a real API-level constraint (Anthropic's native output_config.format on \" +\n 'covered models, or a forced single tool call otherwise).',\n 'validation',\n );\n }\n\n let toolName: string | undefined;\n let outputFormat: NonNullable<AnthropicRequestBody['output_config']>['format'] | undefined;\n let tools: NonNullable<Parameters<AnthropicClient['messages']['create']>[0]['tools']> | undefined;\n let toolChoice: Parameters<AnthropicClient['messages']['create']>[0]['tool_choice'];\n\n if (jsonSchema && isNative) {\n // Native path: the schema goes in its own request field, independent\n // of tools/tool_choice, so real tools (if any) are built exactly like\n // the tools-only branch below and sent alongside it.\n //\n // Only `type` and `schema` are sent: the real Anthropic API's\n // `output_config.format` has no `name`/`description`/`strict` fields,\n // unlike the legacy forced-tool-call path below, where those are real\n // `Tool` fields. `schemaName` is still required and validated above\n // (a caller-facing identifier, useful for logging/debugging on their\n // end), it just never reaches this particular wire request.\n outputFormat = { type: 'json_schema', schema: jsonSchema.schema };\n\n if (params.tools?.length) {\n ({ tools, toolChoice } = buildAnthropicTools(params.tools, params.tool_choice));\n }\n } else if (jsonSchema && schemaName) {\n // Legacy path: jsonSchema alone (or with tools, on a native model — see\n // above), on a model without native support, becomes a forced single\n // tool call, unchanged from before this adapter had a native path.\n const { schema, description, strict } = jsonSchema;\n\n toolName = schemaName;\n // VernLLM's public `jsonSchema` API accepts a freeform JSON Schema\n // object (`Record<string, unknown>`), not necessarily typed with a\n // literal `type: 'object'`, but tool/function parameters are always\n // object schemas in practice (every provider's function-calling API\n // requires it), so this assertion reflects that existing convention\n // rather than changing behavior.\n tools = [\n { name: toolName, description, input_schema: assertObjectSchema(schema, toolName), strict },\n ];\n toolChoice = { type: 'tool', name: toolName };\n }\n\n if (!jsonSchema && params.tools?.length) {\n ({ tools, toolChoice } = buildAnthropicTools(params.tools, params.tool_choice));\n }\n\n // On models that only support adaptive thinking (Claude Opus 4.7 and\n // later, every Claude 5 tier model, see `supportsManualThinkingBudget`'s\n // docs), manual `budget_tokens` thinking returns a 400. Those models\n // still get a real reasoning control, adaptive thinking's own `effort`\n // parameter, converted from whichever of `reasoningEffort`/`budgetTokens`\n // the caller set, rather than either silently building a request that\n // will fail, or dropping the caller's intent to reason at all.\n let thinking: AnthropicRequestBody['thinking'];\n let effort: ClaudeAdaptiveEffort | undefined;\n\n if (params.budget_tokens !== undefined || params.reasoning_effort !== undefined) {\n // Checked once here, right before any thinking block is built, so a\n // caller who set budgetTokens/reasoningEffort alongside a forced\n // toolChoice (or a jsonSchema call that silently forces one to emulate\n // structured output on a non-native model, see toolChoice above) gets\n // a clear local error instead of a 400 after a real network round trip.\n assertNoForcedToolChoiceWithThinking(\n toolChoice?.type === 'tool'\n ? `toolChoice forcing the \"${toolChoice.name}\" tool`\n : toolChoice?.type === 'any'\n ? \"toolChoice: 'required' (Anthropic's \\\"any\\\" tool_choice)\"\n : undefined,\n );\n\n if (supportsManualThinkingBudget(params.model, adaptiveOnlyModels)) {\n const budgetTokens =\n params.budget_tokens ?? effortToBudgetTokens(params.reasoning_effort!, effortTokenTable);\n\n // Anthropic requires `budget_tokens` to be at least 1024 and\n // strictly less than `max_tokens`. Checked here, once, so a bad\n // combination (e.g. VernLLM's own default `maxTokens: 1000`, below\n // the 1024 floor) surfaces as a clear local error instead of a 400\n // after a real network round trip.\n assertValidClaudeBudgetTokens(budgetTokens, params.max_tokens);\n\n thinking = { type: 'enabled', budget_tokens: budgetTokens };\n } else {\n const effortTier =\n params.reasoning_effort ?? budgetTokensToEffort(params.budget_tokens!, effortTokenTable);\n\n thinking = { type: 'adaptive' };\n effort = toClaudeAdaptiveEffort(effortTier);\n }\n }\n\n const system = systemMessage?.content;\n\n // Anthropic rejects a non-default `temperature` (or `top_p`/`top_k`)\n // alongside *any* thinking mode, manual or adaptive, on every model\n // that supports thinking at all, not just the adaptive-only ones above.\n // VernLLM's own instance/call default is 0.2, not \"unset\", so without\n // this a `budgetTokens`/`reasoningEffort` call would silently attach\n // that default and get a 400 from Anthropic. Once `thinking` is going\n // out, `temperature` is dropped entirely so the provider applies its\n // own default, regardless of whether the 0.2 came from VernLLM's own\n // default or a caller-supplied value; Anthropic has no field that lets\n // a caller keep a custom temperature and thinking at the same time.\n const temperature = thinking ? undefined : params.temperature;\n\n const body: AnthropicRequestBody = {\n model: params.model,\n max_tokens: params.max_tokens,\n ...(temperature !== undefined ? { temperature } : {}),\n system: system || undefined,\n messages: mergeConsecutiveToolResults(conversationMessages.map((m) => toAnthropicMessage(m))),\n ...(tools ? { tools, tool_choice: toolChoice } : {}),\n ...(outputFormat || effort\n ? {\n output_config: {\n ...(outputFormat ? { format: outputFormat } : {}),\n ...(effort ? { effort } : {}),\n },\n }\n : {}),\n ...(thinking ? { thinking } : {}),\n };\n\n return { body, toolName };\n}\n\n/** Optional configuration for `fromAnthropic`. */\nexport interface AnthropicAdapterOptions {\n /**\n * Which models support native, schema-constrained output\n * (`output_config.format`), independent of `tools`/`tool_choice`, so it\n * can be combined with real `tools` in one request. Pass a static list\n * of model IDs (verified against Anthropic's own docs) or a predicate.\n *\n * There is no built-in default here (see `supportsNativeStructuredOutput`\n * for why). Left unset, every model uses the older forced-single-tool-\n * call emulation, and `tools` + `jsonSchema` together is rejected,\n * exactly this adapter's behavior before native support was added.\n */\n nativeStructuredOutputModels?: ModelCapabilityOverride;\n /**\n * Overrides the token count `reasoningEffort` tiers map onto when the\n * caller sets `reasoningEffort` but not `budgetTokens` (Claude has no\n * tier concept of its own, see `adapters/internal/reasoningBudget.utils.ts`).\n * Only the tiers listed are changed; any omitted tier keeps the\n * built-in default. Has no effect when `budgetTokens` is set directly.\n */\n reasoningEffortTokens?: Partial<EffortTokenTable>;\n /**\n * Marks additional models as adaptive-only, on top of this package's\n * own built-in rule (Claude Opus 4.7 and later, every Claude 5 tier\n * model, see `isAdaptiveOnlyModel` in\n * `adapters/internal/reasoningBudget.utils.ts`). Additive, not a\n * replacement: it can correct a false negative (a newer model this\n * package doesn't know about yet), it can't un-mark a model the\n * built-in rule already caught. Pass a static list of model IDs or a\n * predicate.\n */\n adaptiveOnlyModels?: ModelCapabilityOverride;\n}\n\n/**\n * Wraps an Anthropic SDK client so it satisfies the same `LLMClient`\n * interface VernLLM uses for OpenAI/Groq.\n *\n * `response_format: json_schema`, on a model covered by\n * `options.nativeStructuredOutputModels`, is sent as `output_config.format`,\n * its own request field, independent of `tools`/`tool_choice`, so it can be\n * combined with real, caller-supplied `tools` in the same request. Only\n * `type` and `schema` are sent on this path, the real Anthropic API's\n * `output_config.format` has no `name`/`description`/`strict` fields.\n *\n * On any other model (the default, since `nativeStructuredOutputModels` is\n * opt-in), `response_format: json_schema` is mapped to Anthropic's forced\n * tool-use instead: a single tool is defined with `input_schema` set to\n * the caller's schema, `description` forwarded when provided, and `strict`\n * forwarded when set, and `tool_choice` forces the model to call it. This\n * legacy path cannot be combined with real `tools` (both would need the\n * same `tools`/`tool_choice` field), and a call that tries throws\n * `LLMError('validation')` before reaching the API. Provider-constrained\n * schema matching applies only when `strict: true` is forwarded and\n * supported.\n *\n * `response_format: json_object` throws `LLMError('validation')`. Anthropic\n * has no API-level field that mechanically guarantees JSON output the way\n * OpenAI's `json_object` mode does; the only way to emulate it was a\n * system-prompt instruction with no actual enforcement behind it, a\n * guarantee this adapter no longer pretends to make. Use `jsonSchema`\n * instead, which maps to a real constraint either way (native\n * `output_config.format` or a forced tool call).\n */\nexport function fromAnthropic(\n anthropicClient: AnthropicClient,\n options?: AnthropicAdapterOptions,\n): LLMClient {\n const nativeStructuredOutputModels = options?.nativeStructuredOutputModels;\n const effortTokenTable = resolveEffortTokenTable(options?.reasoningEffortTokens);\n const adaptiveOnlyModels = options?.adaptiveOnlyModels;\n // The Anthropic SDK's `messages.create`, called with `stream: true`,\n // returns an AsyncIterable of `AnthropicStreamEvent` rather than\n // `AnthropicClient['messages']['create']`'s normal single-message return\n // type, hence `unknown` here and a cast at the call site, same\n // rationale as `fromOpenAICompatible`'s `rawCreate`: the wire contract,\n // not the SDK's own TS types, is what's actually relied on.\n const rawMessagesCreate = anthropicClient.messages.create.bind(\n anthropicClient.messages,\n ) as unknown as (\n params: unknown,\n options: { signal: AbortSignal },\n ) => Promise<unknown> | AsyncIterable<AnthropicStreamEvent>;\n\n return {\n // json_object is not supported: see buildAnthropicRequestBody's throw\n // above, and LLMClient.supportsJsonObjectMode's docs for why this is\n // false rather than the emulated-via-prompt-instruction default. Lets\n // RequestBuilder downgrade a default (unset) jsonMode to plain text\n // instead of requesting a mode this client can't honor.\n supportsJsonObjectMode: false,\n chat: {\n completions: {\n async create(params, options) {\n const { body, toolName } = buildAnthropicRequestBody(\n params,\n nativeStructuredOutputModels,\n effortTokenTable,\n adaptiveOnlyModels,\n );\n\n const response = await anthropicClient.messages.create(body, options);\n\n let text: string;\n let wireToolCalls: WireToolCall[] | undefined;\n if (toolName) {\n const toolUse = response.content.find(\n (block) => block.type === 'tool_use' && block.name === toolName,\n );\n\n if (!toolUse) {\n throw new LLMError(\n `Anthropic did not return the required structured output tool \"${toolName}\".`,\n 'validation',\n );\n }\n\n if (\n !toolUse.input ||\n typeof toolUse.input !== 'object' ||\n Array.isArray(toolUse.input)\n ) {\n throw new LLMError(\n `Anthropic returned invalid structured output for tool \"${toolName}\". Expected an object.`,\n 'validation',\n );\n }\n\n text = JSON.stringify(toolUse.input);\n } else {\n text = response.content\n .filter((block) => block.type === 'text')\n .map((block) => block.text ?? '')\n .join('');\n\n const toolUses = response.content.filter((block) => block.type === 'tool_use');\n\n if (toolUses.length) {\n wireToolCalls = toolUses.map((block) => ({\n id: block.id!,\n type: 'function' as const,\n function: { name: block.name!, arguments: JSON.stringify(block.input ?? {}) },\n }));\n }\n }\n\n return {\n choices: [\n {\n message: { content: text, ...(wireToolCalls ? { tool_calls: wireToolCalls } : {}) },\n },\n ],\n usage: {\n prompt_tokens: response.usage?.input_tokens,\n completion_tokens: response.usage?.output_tokens,\n total_tokens:\n (response.usage?.input_tokens ?? 0) + (response.usage?.output_tokens ?? 0),\n ...(response.usage?.output_tokens_details?.thinking_tokens !== undefined\n ? {\n completion_tokens_details: {\n reasoning_tokens: response.usage.output_tokens_details.thinking_tokens,\n },\n }\n : {}),\n },\n };\n },\n\n async *createStream(params, options) {\n const { body, toolName } = buildAnthropicRequestBody(\n params,\n nativeStructuredOutputModels,\n effortTokenTable,\n adaptiveOnlyModels,\n );\n\n const stream = (await rawMessagesCreate(\n { ...body, stream: true },\n options,\n )) as AsyncIterable<AnthropicStreamEvent>;\n\n // Tracks which content-block index is which kind, since Anthropic\n // interleaves text and tool_use blocks under a shared `index`\n // sequence and later delta events only carry that index, not the\n // kind. `json-tool` is the forced single-tool-call standing in\n // for `jsonSchema` output (see `toolName` above): its\n // input_json_delta fragments are re-emitted as `text-delta`, not\n // `tool_call_delta`, so the accumulated result lands in\n // finalizeResponse's `content` path exactly like the\n // non-streaming `create` branch above unwraps it.\n const blockKinds = new Map<number, 'text' | 'tool_use' | 'json-tool'>();\n let inputTokens = 0;\n let sawJsonTool = false;\n\n for await (const event of stream) {\n if (event.type === 'message_start') {\n inputTokens = event.message.usage?.input_tokens ?? 0;\n } else if (event.type === 'content_block_start') {\n if (event.content_block.type === 'tool_use') {\n const kind = event.content_block.name === toolName ? 'json-tool' : 'tool_use';\n\n blockKinds.set(event.index, kind);\n\n if (kind === 'json-tool') {\n sawJsonTool = true;\n } else if (!toolName) {\n // Only surface tool_use blocks as tool_call_delta chunks\n // when there's no forced structured-output tool in play.\n // When `toolName` is set, any non-matching tool_use block\n // is unexpected (Anthropic forces exactly one tool), and\n // surfacing it would corrupt the caller's expectation of\n // receiving only the forced tool's JSON payload as text.\n yield {\n type: 'tool_call_delta',\n index: event.index,\n id: event.content_block.id,\n name: event.content_block.name,\n };\n }\n } else {\n blockKinds.set(event.index, 'text');\n }\n } else if (event.type === 'content_block_delta') {\n if (event.delta.type === 'text_delta') {\n // Only surfaced as real content when there's no forced\n // json-schema tool in play. When `toolName` is set, the\n // *only* content that should end up in the accumulated\n // text is the forced tool's own JSON payload (its\n // input_json_delta fragments, handled below), exactly\n // what the non-streaming `create` branch above does by\n // discarding every content block except the matching\n // tool_use one. Anthropic can still emit genuine text\n // blocks alongside a forced tool call (a model narrating\n // before calling it, say), and without this guard those\n // would get concatenated into the same buffer as the\n // tool's JSON, corrupting it.\n if (!toolName) {\n yield { type: 'text-delta', delta: event.delta.text };\n }\n } else if (event.delta.type === 'input_json_delta') {\n const kind = blockKinds.get(event.index);\n\n if (kind === 'json-tool') {\n yield { type: 'text-delta', delta: event.delta.partial_json };\n } else if (!toolName) {\n yield {\n type: 'tool_call_delta',\n index: event.index,\n argumentsDelta: event.delta.partial_json,\n };\n }\n }\n } else if (event.type === 'message_delta') {\n const outputTokens = event.usage?.output_tokens ?? 0;\n const thinkingTokens = event.usage?.output_tokens_details?.thinking_tokens;\n\n yield {\n type: 'usage',\n usage: {\n prompt_tokens: inputTokens,\n completion_tokens: outputTokens,\n total_tokens: inputTokens + outputTokens,\n ...(thinkingTokens !== undefined\n ? { completion_tokens_details: { reasoning_tokens: thinkingTokens } }\n : {}),\n },\n } satisfies WireStreamChunk;\n } else if (event.type === 'ping') {\n // Keep-alive with no content. Yielding it resets the\n // idle-timeout clock in VernLLM's stream loop.\n yield { type: 'ping' };\n }\n }\n\n if (toolName && !sawJsonTool) {\n throw new LLMError(\n `Anthropic did not return the required structured output tool \"${toolName}\".`,\n 'validation',\n );\n }\n },\n },\n },\n };\n}\n\n/**\n * Anthropic requires strict role alternation, so the per-wire-message\n * mapping above (one `{role:'user', content:[tool_result]}` per VernLLM\n * wire tool message) needs merging back together when an assistant turn\n * requested more than one tool: multiple consecutive user turns would\n * violate that alternation, and Anthropic's API rejects it outright. This\n * merges any run of tool-result-only user messages into one, with all\n * their tool_result blocks combined, the shape Anthropic expects for \"here\n * are the results of everything you just asked for.\"\n */\nfunction mergeConsecutiveToolResults(\n messages: { role: 'user' | 'assistant'; content: string | AnthropicContentBlock[] }[],\n): { role: 'user' | 'assistant'; content: string | AnthropicContentBlock[] }[] {\n const isToolResultOnly = (\n m: (typeof messages)[number],\n ): m is { role: 'user'; content: AnthropicContentBlock[] } =>\n m.role === 'user' &&\n Array.isArray(m.content) &&\n m.content.length > 0 &&\n m.content.every((b) => b.type === 'tool_result');\n\n const merged: (typeof messages)[number][] = [];\n\n for (const m of messages) {\n const prev = merged.at(-1);\n\n if (isToolResultOnly(m) && prev && isToolResultOnly(prev)) {\n prev.content.push(...m.content);\n } else {\n merged.push(m);\n }\n }\n\n return merged;\n}\n\n/**\n * Translates one VernLLM wire message (OpenAI-shaped: plain user/assistant\n * turns, an assistant turn with `tool_calls`, or a `tool` turn) into\n * Anthropic's `{ role: 'user' | 'assistant', content }` shape.\n */\nfunction toAnthropicMessage(\n m: Extract<\n Parameters<LLMClient['chat']['completions']['create']>[0]['messages'][number],\n { role: 'user' | 'assistant' | 'tool' }\n >,\n): { role: 'user' | 'assistant'; content: string | AnthropicContentBlock[] } {\n if (m.role === 'tool') {\n // Anthropic has no 'tool' role: results travel as a user turn with\n // tool_result blocks.\n return {\n role: 'user',\n content: [\n {\n type: 'tool_result',\n tool_use_id: m.tool_call_id,\n content: m.content,\n ...(m.is_error ? { is_error: true } : {}),\n },\n ],\n };\n }\n\n if (m.role === 'assistant' && m.tool_calls?.length) {\n const blocks: AnthropicContentBlock[] = [];\n\n if (m.content) blocks.push({ type: 'text', text: m.content });\n\n for (const tc of m.tool_calls) {\n let input: unknown;\n\n try {\n input = tc.function.arguments.trim() ? JSON.parse(tc.function.arguments) : {};\n } catch (cause) {\n throw new LLMError(\n `Assistant tool call \"${tc.function.name}\" (${tc.id}) has arguments that are not valid JSON.`,\n 'validation',\n { cause },\n );\n }\n\n if (input === null || Array.isArray(input) || typeof input !== 'object') {\n throw new LLMError(\n `Assistant tool call \"${tc.function.name}\" (${tc.id}) arguments must be a JSON object.`,\n 'validation',\n );\n }\n\n blocks.push({ type: 'tool_use', id: tc.id, name: tc.function.name, input });\n }\n\n return { role: 'assistant', content: blocks };\n }\n\n return {\n role: m.role,\n content: Array.isArray(m.content) ? toAnthropicContent(m.content) : (m.content ?? ''),\n };\n}\n","import {\n LLMError,\n type ContentBlock,\n type LLMClient,\n type WireStreamChunk,\n type WireToolCall,\n} from '../types/index.js';\nimport { assertSupportedImageMimeType } from './internal/imageFormat.js';\nimport {\n budgetTokensToEffort,\n effortToBudgetTokens,\n resolveEffortTokenTable,\n toGeminiThinkingLevel,\n usesGeminiThinkingLevel,\n type EffortTokenTable,\n} from './internal/reasoningBudget.utils.js';\n\nimport type { ModelCapabilityOverride } from './internal/nativeStructuredOutput.js';\n\n/**\n * Gemini's native per-part content shape for a `contents` entry.\n * `functionCall.args` and `functionResponse.response` are typed as\n * `Record<string, unknown>` (not `unknown`) to match the real SDK's\n * `FunctionCall.args` / `FunctionResponse.response`, see the doc comment\n * on {@link GeminiClient}.\n */\ntype GeminiPart =\n | { text: string }\n | { inlineData: { mimeType: string; data: string } }\n | { functionCall: { name: string; args: Record<string, unknown> } }\n | { functionResponse: { name: string; response: Record<string, unknown> } };\n\n/**\n * Structural type matching the real `@google/genai` SDK, in either shape\n * it's commonly held in: the callable model methods directly (`ai.models`),\n * or the complete top-level client (`ai`, via the optional `models` field\n * below). Both work with `fromGemini` directly, with no cast:\n *\n * ```ts\n * import { GoogleGenAI } from '@google/genai';\n * const ai = new GoogleGenAI({ apiKey: '...' });\n * const llm = new VernLLM({ client: fromGemini(ai), model: 'gemini-2.5-flash' });\n * ```\n *\n * `generateContent` is optional so a `{ models: ... }`-shaped value is\n * still a structural `GeminiClient`; `fromGemini` resolves `models` at\n * runtime and throws if nothing callable results.\n *\n * Every field is shaped to be structurally assignable from the real SDK's\n * generated types without importing them, so provider SDKs stay optional:\n * `model` is required (the real SDK requires it), `functionCall.args` /\n * `functionResponse.response` are `Record<string, unknown>` (matching the\n * real SDK, not `unknown`), `toolConfig...mode` is `any` (TypeScript never\n * treats a string-literal union as assignable to the real SDK's string\n * enum), and response-side `functionCall.name` is optional (matching the\n * real SDK).\n */\nexport interface GeminiClient {\n /** Present when this is the whole top-level SDK client, not `ai.models`. `fromGemini` unwraps it at runtime. */\n models?: GeminiClient;\n\n generateContent?(params: {\n model: string;\n contents: Array<{ role: 'user' | 'model'; parts: GeminiPart[] }>;\n config?: {\n systemInstruction?: { parts: Array<{ text: string }> };\n temperature?: number;\n maxOutputTokens?: number;\n responseMimeType?: string;\n responseSchema?: Record<string, unknown>;\n tools?: Array<{\n functionDeclarations: Array<{\n name: string;\n description?: string;\n parameters: Record<string, unknown>;\n }>;\n }>;\n toolConfig?: {\n functionCallingConfig: {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- see class doc comment above\n mode: any;\n allowedFunctionNames?: string[];\n };\n };\n /**\n * Native reasoning control. `thinkingBudget` is built from\n * `CallParams.budgetTokens` directly when set (0 disables thinking,\n * -1 requests automatic budgeting, both passed through unchanged),\n * or converted from `reasoningEffort`, on Gemini 2.5 and earlier\n * models. `thinkingLevel` is used instead on Gemini 3 and later,\n * which use a level-based control rather than a numeric budget.\n * `any`, same reason as `toolConfig...mode` above, see class doc\n * comment. See `usesGeminiThinkingLevel` in\n * `adapters/internal/reasoningBudget.utils.ts`.\n */\n thinkingConfig?: {\n thinkingBudget?: number;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- see class doc comment above\n thinkingLevel?: any;\n };\n abortSignal?: AbortSignal;\n };\n }): Promise<{\n candidates?: Array<{\n content?: {\n parts?: Array<{ text?: string; functionCall?: { name?: string; args?: unknown } }>;\n };\n }>;\n usageMetadata?: {\n promptTokenCount?: number;\n candidatesTokenCount?: number;\n totalTokenCount?: number;\n thoughtsTokenCount?: number;\n };\n }>;\n\n /**\n * Optional. Required only for `stream: true` calls. Takes the same\n * request shape as `generateContent`. Matching the real SDK's own\n * `generateContentStream`, this resolves to an `AsyncIterable` (rather\n * than returning one synchronously) of partial responses, each chunk\n * holding the same `candidates[].content.parts[]` structure as\n * `generateContent`'s response, just incremental.\n */\n generateContentStream?(\n params: Parameters<NonNullable<GeminiClient['generateContent']>>[0],\n ): Promise<\n AsyncIterable<{\n candidates?: Array<{\n content?: {\n parts?: Array<{ text?: string; functionCall?: { name?: string; args?: unknown } }>;\n };\n }>;\n usageMetadata?: {\n promptTokenCount?: number;\n candidatesTokenCount?: number;\n totalTokenCount?: number;\n thoughtsTokenCount?: number;\n };\n }>\n >;\n}\n\n/**\n * Translates a VernLLM `ContentBlock[]` into Gemini's native `parts` array:\n * text blocks become `{ text }`, image blocks become inline data parts\n * (`{ inlineData: { mimeType, data } }`), Gemini's shape for embedding raw\n * base64 image bytes directly in the request.\n */\nfunction toGeminiParts(blocks: ContentBlock[]): GeminiPart[] {\n return blocks.map((block) =>\n block.type === 'image'\n ? { inlineData: { mimeType: assertSupportedImageMimeType(block.mimeType), data: block.data } }\n : { text: block.text },\n );\n}\n\n/** Maps VernLLM's OpenAI-shaped wire `tool_choice` onto Gemini's `functionCallingConfig`. */\nfunction toGeminiToolConfig(\n toolChoice: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice'],\n): NonNullable<\n NonNullable<Parameters<NonNullable<GeminiClient['generateContent']>>[0]['config']>['toolConfig']\n> {\n if (!toolChoice || toolChoice === 'auto') {\n return { functionCallingConfig: { mode: 'AUTO' } };\n }\n if (toolChoice === 'none') {\n return { functionCallingConfig: { mode: 'NONE' } };\n }\n if (toolChoice === 'required') {\n return { functionCallingConfig: { mode: 'ANY' } };\n }\n\n return {\n functionCallingConfig: { mode: 'ANY', allowedFunctionNames: [toolChoice.function.name] },\n };\n}\n\n/**\n * Translates one VernLLM wire message into a Gemini `contents` entry.\n * Gemini has no separate 'tool' role: a prior assistant tool request\n * becomes a `'model'` turn with `functionCall` parts, and its result\n * becomes a `'user'` turn with `functionResponse` parts.\n */\nfunction toGeminiContent(\n m: Extract<\n Parameters<LLMClient['chat']['completions']['create']>[0]['messages'][number],\n { role: 'user' | 'assistant' | 'tool' }\n >,\n): { role: 'user' | 'model'; parts: GeminiPart[] } {\n if (m.role === 'tool') {\n // Gemini's functionResponse identifies the call by function *name*, and\n // the Gemini branch of this adapter sets wire tool_call ids equal to\n // the function name for exactly this reason, so tool_call_id here is\n // already the name Gemini expects.\n return {\n role: 'user',\n parts: [\n {\n functionResponse: {\n name: m.tool_call_id,\n response: parseToolResult(m.content),\n },\n },\n ],\n };\n }\n\n if (m.role === 'assistant' && m.tool_calls?.length) {\n const parts: GeminiPart[] = [];\n\n if (typeof m.content === 'string' && m.content) {\n parts.push({ text: m.content });\n }\n\n parts.push(\n ...m.tool_calls.map((tc) => ({\n functionCall: {\n name: tc.function.name,\n args: parseToolArguments(tc.function.arguments, tc.function.name),\n },\n })),\n );\n\n return {\n role: 'model',\n parts,\n };\n }\n\n return {\n role: m.role === 'assistant' ? 'model' : 'user',\n parts: Array.isArray(m.content) ? toGeminiParts(m.content) : [{ text: m.content ?? '' }],\n };\n}\n\nfunction parseToolArguments(text: string, toolName: string): Record<string, unknown> {\n let parsed: unknown;\n\n try {\n parsed = text.trim() ? JSON.parse(text) : {};\n } catch (cause) {\n throw new LLMError(`Tool call \"${toolName}\" arguments are not valid JSON.`, 'parse', {\n cause,\n code: 'tool_arguments_parse_failed',\n });\n }\n\n if (!parsed || Array.isArray(parsed) || typeof parsed !== 'object') {\n throw new LLMError(`Tool call \"${toolName}\" arguments must be a JSON object.`, 'validation');\n }\n\n return parsed as Record<string, unknown>;\n}\n\n/**\n * Parses a wire tool message's `content` into the object Gemini's\n * `functionResponse.response` expects. Gemini (and the real SDK's\n * `FunctionResponse.response` type) requires an object, so a result that\n * parses to something other than a plain JSON object (a string, number,\n * array, or unparseable text) is wrapped under an `output` key, mirroring\n * Gemini's own documented convention for non-object function results.\n */\nfunction parseToolResult(text: string): Record<string, unknown> {\n let parsed: unknown;\n\n try {\n parsed = text.trim() ? JSON.parse(text) : '';\n } catch {\n parsed = text;\n }\n\n if (parsed && !Array.isArray(parsed) && typeof parsed === 'object') {\n return parsed as Record<string, unknown>;\n }\n\n return { output: parsed };\n}\n\n/**\n * Gemini expects the results of everything the model asked for in one turn\n * to arrive together as multiple `functionResponse` parts on a single\n * `'user'` entry, not as separate consecutive `'user'` entries. The\n * per-wire-message mapping above produces one `'user'` entry per VernLLM\n * wire tool message, so when an assistant turn requested more than one\n * tool, this merges the resulting run of functionResponse-only `'user'`\n * entries back into one.\n */\nfunction mergeConsecutiveFunctionResponses(\n contents: { role: 'user' | 'model'; parts: GeminiPart[] }[],\n): { role: 'user' | 'model'; parts: GeminiPart[] }[] {\n const isFunctionResponseOnly = (\n c: (typeof contents)[number],\n ): c is { role: 'user'; parts: GeminiPart[] } =>\n c.role === 'user' && c.parts.length > 0 && c.parts.every((p) => 'functionResponse' in p);\n\n const merged: (typeof contents)[number][] = [];\n\n for (const c of contents) {\n const prev = merged.at(-1);\n\n if (isFunctionResponseOnly(c) && prev && isFunctionResponseOnly(prev)) {\n prev.parts.push(...c.parts);\n } else {\n merged.push(c);\n }\n }\n\n return merged;\n}\n\ntype GeminiRequest = Parameters<NonNullable<GeminiClient['generateContent']>>[0];\ntype GeminiConfig = NonNullable<GeminiRequest['config']>;\n\n/**\n * Builds the Gemini-shaped request from VernLLM's wire params, shared\n * between `create` and `createStream` so both go through identical\n * translation (contents shaping, `responseSchema`/`responseMimeType`\n * mapping, and tool/toolConfig translation all happen exactly once).\n * `abortSignal` is folded into `config` by the caller (`create`/\n * `createStream`), once the request options are available.\n */\nfunction buildGeminiRequest(\n params: Parameters<LLMClient['chat']['completions']['create']>[0],\n effortTokenTable?: EffortTokenTable,\n thinkingLevelModels?: ModelCapabilityOverride,\n): GeminiRequest {\n const systemMessage = params.messages.find((m) => m.role === 'system');\n // Keep user, assistant, and tool turns, in order.\n const conversationMessages = params.messages.filter(\n (m) => m.role === 'user' || m.role === 'assistant' || m.role === 'tool',\n );\n\n const wantsJson = Boolean(params.response_format);\n const config: GeminiConfig = {\n ...(params.temperature !== undefined ? { temperature: params.temperature } : {}),\n maxOutputTokens: params.max_tokens,\n ...(systemMessage\n ? // System turns are always plain strings; only user turns can carry ContentBlock[]\n { systemInstruction: { parts: [{ text: systemMessage.content as string }] } }\n : {}),\n };\n\n if (wantsJson) {\n config.responseMimeType = 'application/json';\n }\n\n if (params.response_format?.type === 'json_schema') {\n const { schema, description } = params.response_format.json_schema;\n\n config.responseSchema = {\n ...schema,\n ...(description ? { description } : {}),\n };\n }\n\n if (params.tools?.length) {\n config.tools = [\n {\n functionDeclarations: params.tools.map((t) => ({\n name: t.function.name,\n description: t.function.description,\n parameters: t.function.parameters,\n })),\n },\n ];\n config.toolConfig = toGeminiToolConfig(params.tool_choice);\n }\n\n // On Gemini 3 and later, `thinkingConfig.thinkingLevel` is the native\n // reasoning control, not `thinkingBudget`. `reasoning_effort` maps onto\n // it directly (VernLLM's own four tiers line up exactly with Gemini's\n // level enum). When only `budget_tokens` was set, it's converted to\n // the nearest tier first, same table used elsewhere. Sending\n // `thinkingBudget` there instead still works for backward\n // compatibility, per Google's own docs, but \"may result in unexpected\n // performance\", so VernLLM switches over rather than keeping every\n // Gemini generation on the older field indefinitely. Note that 0\n // (disabled) and -1 (automatic) have no `thinkingLevel` equivalent:\n // both collapse to `minimal` through the same conversion table,\n // `MINIMAL` being the closest available approximation of \"off\", which\n // several Gemini 3 models can't be fully disabled on anyway.\n if (usesGeminiThinkingLevel(params.model, thinkingLevelModels)) {\n const effortTier =\n params.reasoning_effort ??\n (params.budget_tokens !== undefined\n ? budgetTokensToEffort(params.budget_tokens, effortTokenTable)\n : undefined);\n\n if (effortTier !== undefined) {\n config.thinkingConfig = { thinkingLevel: toGeminiThinkingLevel(effortTier, params.model) };\n }\n } else {\n // `thinkingBudget` is Gemini's native reasoning control on 2.5 and\n // earlier, 0 disables thinking and -1 requests automatic budgeting,\n // both passed through unchanged rather than run through the effort\n // table below. Used directly when the caller set `budget_tokens`.\n // When only `reasoning_effort` was set, it's converted to the\n // nearest token budget, since these models have no tier string of\n // their own.\n const thinkingBudget =\n params.budget_tokens ??\n (params.reasoning_effort\n ? effortToBudgetTokens(params.reasoning_effort, effortTokenTable)\n : undefined);\n\n if (thinkingBudget !== undefined) {\n config.thinkingConfig = { thinkingBudget };\n }\n }\n\n return {\n model: params.model,\n contents: mergeConsecutiveFunctionResponses(\n conversationMessages.map((m) => toGeminiContent(m)),\n ),\n config,\n };\n}\n\n/**\n * Wraps a Gemini client so it satisfies the `LLMClient` interface VernLLM\n * uses for OpenAI-compatible APIs. Gemini's shape differs on nearly every\n * axis: a `contents` array instead of `messages`, a separate\n * `systemInstruction` field instead of a `system` role message,\n * `generationConfig` instead of top-level `temperature`/`max_tokens`, and\n * native JSON Schema support via `responseMimeType: 'application/json'` +\n * `responseSchema`. `reasoning_effort` has no native Gemini equivalent, so\n * it's converted to a `thinkingConfig.thinkingBudget` token count; `budget_tokens`\n * maps to `thinkingBudget` directly, Gemini's native reasoning control. See\n * `adapters/internal/reasoningBudget.utils.ts`.\n *\n * `tools` maps to Gemini's native `functionDeclarations`/`functionCall`;\n * `tool_choice` maps to `toolConfig.functionCallingConfig`. Gemini accepts\n * `responseSchema` and `tools` in the same request natively, so both are\n * set independently here and no special-casing is needed for the\n * combination, unlike `fromAnthropic`/`fromBedrock`.\n *\n * `createStream` calls `generateContentStream` (optional on `GeminiClient`\n *, required only if the caller sets `stream: true`) and translates each\n * partial response into `WireStreamChunk`s. Unlike OpenAI/Anthropic,\n * Gemini's own function-calling API doesn't stream tool-call arguments\n * incrementally: a `functionCall` part always arrives whole in one chunk,\n * so each one is emitted as a single, complete `tool_call_delta` (a\n * one-shot \"delta\" containing the full arguments) rather than accumulated\n * fragments, that's a real difference in the underlying API, not\n * something this adapter can smooth over. `usageMetadata` is (per Gemini's\n * own behavior) only reliably present on the last chunk, so the `usage`\n * `WireStreamChunk` is emitted once, after the stream completes, from\n * whichever chunk's `usageMetadata` was seen last.\n *\n * Accepts a `GeminiClient` in either shape it structurally covers: the\n * callable model methods directly (`ai.models`), or the complete\n * top-level client (`ai`), unwrapping `.models` internally when present.\n * Both work with no cast: `fromGemini(ai.models)` and `fromGemini(ai)`.\n * Throws `LLMError('invalid_params')` up front if nothing callable\n * results.\n */\nexport interface GeminiAdapterOptions {\n /**\n * Overrides the token count `reasoningEffort` tiers map onto when the\n * caller sets `reasoningEffort` but not `budgetTokens` (Gemini has no\n * tier string of its own, see `adapters/internal/reasoningBudget.utils.ts`).\n * Only the tiers listed are changed; any omitted tier keeps the\n * built-in default. Has no effect when `budgetTokens` is set directly.\n */\n reasoningEffortTokens?: Partial<EffortTokenTable>;\n /**\n * Marks additional models as using `thinkingLevel` instead of\n * `thinkingBudget`, on top of this package's own built-in rule (every\n * Gemini 3 series model and later, see `usesGeminiThinkingLevel` in\n * `adapters/internal/reasoningBudget.utils.ts`). Additive, not a\n * replacement: it can correct a false negative (a newer model this\n * package doesn't know about yet), it can't un-mark a model the\n * built-in rule already caught. Pass a static list of model IDs or a\n * predicate.\n */\n thinkingLevelModels?: ModelCapabilityOverride;\n}\n\nexport function fromGemini(client: GeminiClient, options?: GeminiAdapterOptions): LLMClient {\n const effortTokenTable = resolveEffortTokenTable(options?.reasoningEffortTokens);\n const thinkingLevelModels = options?.thinkingLevelModels;\n const resolved = client.models ?? client;\n\n if (typeof resolved.generateContent !== 'function') {\n throw new LLMError(\n 'fromGemini requires a client with generateContent: pass ai.models, or the whole ai client (fromGemini(ai)).',\n 'invalid_params',\n { code: 'unsupported_capability', issues: { capability: 'generateContent' } },\n );\n }\n\n const generateContent = resolved.generateContent.bind(resolved);\n const generateContentStream =\n typeof resolved.generateContentStream === 'function'\n ? resolved.generateContentStream.bind(resolved)\n : undefined;\n\n return {\n chat: {\n completions: {\n async create(params, options) {\n const request = buildGeminiRequest(params, effortTokenTable, thinkingLevelModels);\n request.config = { ...request.config, abortSignal: options.signal };\n\n const response = await generateContent(request);\n\n const parts = response.candidates?.[0]?.content?.parts ?? [];\n const text = parts.map((p) => p.text ?? '').join('');\n const functionCalls = parts.filter((p) => p.functionCall);\n\n let wireToolCalls: WireToolCall[] | undefined;\n\n if (functionCalls.length) {\n wireToolCalls = functionCalls.map((p) => ({\n // Gemini's functionResponse correlates by function *name*, not\n // a call id (Gemini has no call-id concept at all), so the id\n // here is just the name. This means two calls to the *same*\n // tool within one turn can't be told apart when results come\n // back, a real limitation of Gemini's own function-calling\n // API, not something VernLLM can paper over.\n // INVARIANT: `name` is typed optional (matching the real\n // SDK's own `FunctionCall.name?: string`), but Gemini always\n // populates it on an actual function call part in practice;\n // the `!` here asserts that invariant, same rationale as the\n // `complete: true` invariant on the streaming path below.\n id: p.functionCall!.name!,\n type: 'function' as const,\n function: {\n name: p.functionCall!.name!,\n arguments: JSON.stringify(p.functionCall!.args ?? {}),\n },\n }));\n }\n\n return {\n choices: [\n {\n message: { content: text, ...(wireToolCalls ? { tool_calls: wireToolCalls } : {}) },\n },\n ],\n usage: {\n prompt_tokens: response.usageMetadata?.promptTokenCount,\n completion_tokens: response.usageMetadata?.candidatesTokenCount,\n total_tokens: response.usageMetadata?.totalTokenCount,\n ...(response.usageMetadata?.thoughtsTokenCount !== undefined\n ? {\n completion_tokens_details: {\n reasoning_tokens: response.usageMetadata.thoughtsTokenCount,\n },\n }\n : {}),\n },\n };\n },\n\n async *createStream(params, options) {\n if (!generateContentStream) {\n throw new LLMError(\n 'stream: true requires a Gemini client with generateContentStream',\n 'invalid_params',\n { code: 'unsupported_capability', issues: { capability: 'generateContentStream' } },\n );\n }\n\n const request = buildGeminiRequest(params, effortTokenTable, thinkingLevelModels);\n request.config = { ...request.config, abortSignal: options.signal };\n\n const stream = await generateContentStream(request);\n\n let toolCallIndex = 0;\n let lastUsage:\n | NonNullable<\n Awaited<ReturnType<NonNullable<GeminiClient['generateContent']>>>['usageMetadata']\n >\n | undefined;\n\n for await (const chunk of stream) {\n const parts = chunk.candidates?.[0]?.content?.parts ?? [];\n\n for (const part of parts) {\n if (part.text) {\n yield { type: 'text-delta', delta: part.text };\n }\n\n if (part.functionCall) {\n yield {\n type: 'tool_call_delta',\n index: toolCallIndex,\n id: part.functionCall.name,\n name: part.functionCall.name,\n argumentsDelta: JSON.stringify(part.functionCall.args ?? {}),\n // INVARIANT: assumes Gemini always sends a complete\n // function-call args blob per part, no incremental\n // streaming, per current API behavior. There is no field\n // on this minimal structural type to derive this from.\n // If Gemini ever starts streaming args incrementally,\n // this becomes silently wrong. See the test titled\n // \"INVARIANT: hardcodes complete: true on\n // tool_call_delta\" in gemini.stream.unit.test.ts, which\n // exists specifically to catch that drift.\n complete: true,\n } satisfies WireStreamChunk;\n toolCallIndex++;\n }\n }\n\n if (chunk.usageMetadata) {\n lastUsage = chunk.usageMetadata;\n }\n }\n\n if (lastUsage) {\n yield {\n type: 'usage',\n usage: {\n prompt_tokens: lastUsage.promptTokenCount,\n completion_tokens: lastUsage.candidatesTokenCount,\n total_tokens: lastUsage.totalTokenCount,\n ...(lastUsage.thoughtsTokenCount !== undefined\n ? {\n completion_tokens_details: { reasoning_tokens: lastUsage.thoughtsTokenCount },\n }\n : {}),\n },\n };\n }\n },\n },\n },\n };\n}\n","import {\n LLMError,\n type ContentBlock,\n type LLMClient,\n type WireStreamChunk,\n type WireToolCall,\n} from '../types/index.js';\nimport { assertSupportedImageMimeType } from './internal/imageFormat.js';\nimport {\n supportsNativeStructuredOutput,\n type ModelCapabilityOverride,\n} from './internal/nativeStructuredOutput.js';\nimport {\n assertNoForcedToolChoiceWithThinking,\n assertValidClaudeBudgetTokens,\n budgetTokensToEffort,\n effortToBudgetTokens,\n resolveEffortTokenTable,\n supportsManualThinkingBudget,\n toClaudeAdaptiveEffort,\n type ClaudeAdaptiveEffort,\n type EffortTokenTable,\n} from './internal/reasoningBudget.utils.js';\n\n/**\n * Default heuristic for whether a Bedrock model id is a Claude model,\n * matching AWS's own `anthropic.claude-*`/`us.anthropic.claude-*` naming.\n * Only used to decide whether a reasoning token budget is worth forwarding\n * through `additionalModelRequestFields`, not a general capability check,\n * so a plain substring match is enough, no override hook needed the way\n * `nativeStructuredOutputModels`/`toolUseSupportedModels` have one: a\n * false positive here just sends an inert extra field, not a request that\n * fails outright.\n */\nfunction isClaudeModel(model: string): boolean {\n return model.includes('claude');\n}\n\n/** Bedrock Converse's supported inline image formats. */\ntype BedrockImageFormat = 'png' | 'jpeg' | 'gif' | 'webp';\n\n/** Bedrock Converse's native per-block content shape for a message. */\ntype BedrockContentBlock =\n | { text: string }\n | { image: { format: BedrockImageFormat; source: { bytes: Uint8Array } } }\n | { toolUse: { toolUseId: string; name: string; input: unknown } }\n | {\n toolResult: {\n toolUseId: string;\n content: Array<{ text: string }>;\n status?: 'success' | 'error';\n };\n };\n\n/**\n * Minimal structural type matching AWS Bedrock's Converse API. This is\n * intentionally NOT `BedrockRuntimeClient` itself, the AWS SDK v3 client\n * exposes `.send(command)`, not a direct `.converse()` method, and pulling\n * in `@aws-sdk/client-bedrock-runtime` as a dependency just for its types\n * isn't worth it for a structural adapter. Wrap your client, e.g:\n *\n * ```ts\n * import { BedrockRuntimeClient, ConverseCommand } from '@aws-sdk/client-bedrock-runtime';\n * const client = new BedrockRuntimeClient({ region: 'us-east-1' });\n * const converseClient = {\n * converse: (params, options) =>\n * client.send(new ConverseCommand(params), { abortSignal: options.signal }),\n * };\n * ```\n */\nexport interface BedrockConverseClient {\n converse(\n params: {\n modelId: string;\n messages: Array<{ role: 'user' | 'assistant'; content: BedrockContentBlock[] }>;\n system?: Array<{ text: string }>;\n inferenceConfig?: { temperature?: number; maxTokens?: number };\n toolConfig?: {\n tools: Array<{\n toolSpec: {\n name: string;\n description?: string;\n inputSchema: { json: Record<string, unknown> };\n strict?: boolean;\n };\n }>;\n toolChoice?:\n | { tool: { name: string } }\n | { auto: Record<string, never> }\n | { any: Record<string, never> };\n };\n /**\n * Native, schema-constrained output: a separate request field from\n * `toolConfig`, so it can be sent alongside real tool calls. Only\n * built by this adapter for models covered by\n * `nativeStructuredOutputModels` (opt-in, see\n * `BedrockAdapterOptions`); other models keep getting `jsonSchema`\n * emulated as a forced single tool call via `toolConfig`, the\n * pre-existing behavior.\n *\n * Matches the real Bedrock Converse API's `outputConfig.textFormat`\n * shape exactly: the schema itself is nested one level deeper, under\n * `structure.jsonSchema`, not flat on `textFormat`, and `schema` is\n * a JSON-encoded *string*, not a parsed object, unlike every other\n * schema field this adapter builds (`toolSpec.inputSchema.json`\n * included). There is no `strict` field here, unlike `toolSpec`.\n */\n outputConfig?: {\n textFormat?: {\n type: 'json_schema';\n structure: {\n jsonSchema: {\n schema: string;\n name?: string;\n description?: string;\n };\n };\n };\n /**\n * Effort control for adaptive thinking, on Claude models where\n * manual `budget_tokens` thinking is no longer accepted (see\n * `supportsManualThinkingBudget` in\n * `adapters/internal/reasoningBudget.utils.ts`). Sibling to\n * `textFormat`, either or both may be present independently.\n */\n effort?: 'low' | 'medium' | 'high' | 'xhigh' | 'max';\n };\n /**\n * Model-specific passthrough. Converse has no reasoning-budget field\n * of its own, so a token budget for a Claude model on Bedrock is\n * forwarded here under Anthropic's own key, `{ thinking: { type:\n * 'enabled', budget_tokens } }`. Non-Claude models get nothing here,\n * there is no equivalent field to reach for.\n */\n additionalModelRequestFields?: Record<string, unknown>;\n },\n options: { signal: AbortSignal },\n ): Promise<{\n output?: {\n message?: {\n content?: Array<{\n text?: string;\n toolUse?: { toolUseId?: string; name?: string; input?: unknown };\n }>;\n };\n };\n usage?: { inputTokens?: number; outputTokens?: number; totalTokens?: number };\n }>;\n\n /**\n * Optional. Required only for `stream: true` calls. Takes the same\n * request shape `converse` does, returning `{ stream }`, matching\n * `ConverseStreamCommand`'s real AWS SDK v3 output shape, an\n * `AsyncIterable` of incremental events under a `stream` property,\n * rather than the whole response being the iterable directly.\n */\n converseStream?(\n params: Parameters<BedrockConverseClient['converse']>[0],\n options: { signal: AbortSignal },\n ): Promise<{ stream: AsyncIterable<BedrockConverseStreamEvent> }>;\n}\n\n/**\n * One event of a Bedrock `ConverseStreamCommand` response's `stream`.\n * Content blocks (text or toolUse) are identified by `contentBlockIndex`,\n * Converse's own convention for correlating start/delta/stop events across\n * possibly-interleaved blocks, mirrored directly by VernLLM's\n * `tool_call_delta.index`.\n */\ntype BedrockConverseStreamEvent =\n | { messageStart: { role: 'assistant' } }\n | {\n contentBlockStart: {\n contentBlockIndex: number;\n start?: { toolUse?: { toolUseId?: string; name?: string } };\n };\n }\n | {\n contentBlockDelta: {\n contentBlockIndex: number;\n delta?: { text?: string } | { toolUse?: { input?: string } };\n };\n }\n | { contentBlockStop: { contentBlockIndex: number } }\n | { messageStop: { stopReason?: string } }\n | {\n metadata: {\n usage?: { inputTokens?: number; outputTokens?: number; totalTokens?: number };\n };\n }\n // The above are the happy-path events. Bedrock Converse streams can also\n // emit these as in-band exception events (not promise rejections), so\n // they need to be modeled and handled explicitly below, an unmatched\n // event previously fell through the if/else chain silently, either\n // truncating output or leaving the stream hanging until an unrelated\n // idle timeout fired.\n | { internalServerException: { message?: string } }\n | { modelStreamErrorException: { message?: string; originalStatusCode?: number } }\n | { validationException: { message?: string } }\n | { throttlingException: { message?: string } }\n | { serviceUnavailableException: { message?: string } };\n\n/** Maps a `ContentBlock` image MIME type, already validated, to Converse's `format` enum. */\nfunction toBedrockImageFormat(mimeType: string): BedrockImageFormat {\n switch (assertSupportedImageMimeType(mimeType)) {\n case 'image/png':\n return 'png';\n case 'image/jpeg':\n return 'jpeg';\n case 'image/gif':\n return 'gif';\n case 'image/webp':\n return 'webp';\n }\n}\n\n/**\n * Decodes base64 image data into the raw `Uint8Array` bytes Converse's\n * `image.source.bytes` expects (unlike Anthropic/Gemini/OpenAI, which all\n * take base64 strings directly). Uses `Buffer`, since this adapter, like\n * the rest of the package, targets Node.\n */\nfunction decodeBase64(data: string): Uint8Array {\n return new Uint8Array(Buffer.from(data, 'base64'));\n}\n\n/**\n * Translates a VernLLM `ContentBlock[]` into Converse's native content-block\n * array: text blocks pass through as `{ text }`, image blocks become\n * `{ image: { format, source: { bytes } } }` with the base64 payload decoded\n * to raw bytes, since Converse doesn't accept base64 strings directly.\n */\nfunction toBedrockContent(blocks: ContentBlock[]): BedrockContentBlock[] {\n return blocks.map((block) =>\n block.type === 'image'\n ? {\n image: {\n format: toBedrockImageFormat(block.mimeType),\n source: { bytes: decodeBase64(block.data) },\n },\n }\n : { text: block.text },\n );\n}\n\n/**\n * Optional configuration for `fromBedrock`.\n */\nexport interface BedrockAdapterOptions {\n /**\n * Optional preflight check for tool-use support, needed whenever a\n * `jsonSchema` call ends up sending Converse `toolConfig` — either the\n * legacy forced-single-tool-call emulation, or real `tools` sent\n * alongside native structured output (`outputConfig`). VernLLM never\n * guesses capability from a failed call's error message (AWS's error\n * text isn't a documented, stable contract), so this is opt-in: pass\n * either a static list of tool-use-capable model IDs, or a predicate\n * function, and VernLLM will reject unsupported models with a clear\n * `LLMError('validation')` *before* dispatching the request, instead of\n * on the wire.\n *\n * Left unset (default), no preflight check runs, and a `jsonSchema` call\n * to an unsupported model surfaces Bedrock's raw `converse` error as-is.\n */\n toolUseSupportedModels?: string[] | ((modelId: string) => boolean);\n\n /**\n * Which models support native, schema-constrained output\n * (`outputConfig.textFormat`), independent of `toolConfig`, so it can be\n * combined with real `tools` in one request. Pass a static list of\n * model IDs (verified against Bedrock's own docs) or a predicate.\n *\n * There is no built-in default here (see `supportsNativeStructuredOutput`\n * for why). Left unset, every model uses the older forced-single-tool-\n * call emulation via `toolConfig`, and `tools` + `jsonSchema` together is\n * rejected, exactly this adapter's behavior before native support was\n * added.\n */\n nativeStructuredOutputModels?: ModelCapabilityOverride;\n\n /**\n * Overrides the token count `reasoningEffort` tiers map onto when the\n * caller sets `reasoningEffort` but not `budgetTokens` (Converse has no\n * tier string of its own, see `adapters/internal/reasoningBudget.utils.ts`).\n * Only the tiers listed are changed; any omitted tier keeps the\n * built-in default. Has no effect when `budgetTokens` is set directly,\n * or when the target model isn't a Claude model.\n */\n reasoningEffortTokens?: Partial<EffortTokenTable>;\n /**\n * Marks additional models as adaptive-only, on top of this package's\n * own built-in rule (Claude Opus 4.7 and later, every Claude 5 tier\n * model, see `isAdaptiveOnlyModel` in\n * `adapters/internal/reasoningBudget.utils.ts`). Additive, not a\n * replacement: it can correct a false negative (a newer model this\n * package doesn't know about yet), it can't un-mark a model the\n * built-in rule already caught. Pass a static list of model IDs or a\n * predicate.\n */\n adaptiveOnlyModels?: ModelCapabilityOverride;\n}\n\ntype BedrockRequest = Parameters<BedrockConverseClient['converse']>[0];\n\n/**\n * Maps VernLLM's OpenAI-shaped wire `tools`/`tool_choice` into Converse's\n * `toolConfig` shape. Shared by the two call sites that build real\n * (non-schema-forced) tool definitions: the plain tools-only branch, and\n * the native-structured-output branch, which sends real tools alongside\n * `outputConfig` rather than instead of it.\n */\nfunction buildBedrockToolConfig(\n tools: NonNullable<Parameters<LLMClient['chat']['completions']['create']>[0]['tools']>,\n toolChoiceParam: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice'],\n): NonNullable<BedrockRequest['toolConfig']> {\n return {\n tools: tools.map((t) => ({\n toolSpec: {\n name: t.function.name,\n description: t.function.description,\n inputSchema: { json: t.function.parameters },\n },\n })),\n toolChoice: toBedrockToolChoice(toolChoiceParam),\n };\n}\n\n/**\n * Builds the Converse-shaped request from VernLLM's wire params, shared\n * between `create` and `createStream` so both go through identical\n * translation (system prompt, message shaping, the jsonSchema →\n * forced-single-tool mapping, and the `toolUseSupportedModels` preflight\n * check all happen exactly once).\n *\n * Returns `toolName` alongside the request: when set, the model was forced\n * to call a single synthetic tool standing in for `jsonSchema` output (the\n * legacy path, for models not covered by `nativeStructuredOutputModels`),\n * and both `create` and `createStream` need to know this so they can\n * unwrap that tool call back into plain text content instead of treating\n * it like a real tool call. On the native path (model covered by\n * `nativeStructuredOutputModels`), `toolName` is `undefined`: the\n * schema-conforming JSON already arrives as ordinary text content, nothing\n * to unwrap, and any real tool calls in `params.tools` are left for the\n * normal, non-forced tool-call handling both `create` and `createStream`\n * already do when `toolName` is unset.\n */\nfunction buildBedrockRequest(\n params: Parameters<LLMClient['chat']['completions']['create']>[0],\n toolUseSupportedModels: BedrockAdapterOptions['toolUseSupportedModels'],\n nativeStructuredOutputModels: BedrockAdapterOptions['nativeStructuredOutputModels'],\n effortTokenTable?: EffortTokenTable,\n adaptiveOnlyModels?: ModelCapabilityOverride,\n): { request: BedrockRequest; toolName: string | undefined } {\n const systemMessage = params.messages.find((m) => m.role === 'system');\n\n // Keep user, assistant, and tool turns, in order. Converse has no\n // separate 'tool' role: tool results travel as a user-role message\n // with toolResult content blocks, and an assistant's tool\n // requests travel as toolUse content blocks on its own turn.\n const conversationMessages = params.messages.filter(\n (m) => m.role === 'user' || m.role === 'assistant' || m.role === 'tool',\n );\n\n const jsonSchema =\n params.response_format?.type === 'json_schema' ? params.response_format.json_schema : undefined;\n\n const schemaName = jsonSchema?.name.trim();\n\n if (jsonSchema && !schemaName) {\n throw new LLMError('json_schema.name must not be empty.', 'validation');\n }\n\n const isNative =\n Boolean(jsonSchema) &&\n supportsNativeStructuredOutput(params.model, nativeStructuredOutputModels);\n\n if (jsonSchema && params.tools?.length && !isNative) {\n throw new LLMError(\n `Bedrock model \"${params.model}\" is not covered by nativeStructuredOutputModels, so ` +\n '`jsonSchema` is emulated as a forced single tool call there (via `toolConfig`), which ' +\n 'collides with the `tools` you also provided. Either drop `tools` or `jsonSchema` for this ' +\n \"call, or pass this model in fromBedrock's `nativeStructuredOutputModels` option once \" +\n \"you've confirmed it supports Converse's `outputConfig.textFormat`.\",\n 'validation',\n );\n }\n\n if (params.response_format?.type === 'json_object') {\n throw new LLMError(\n 'response_format: \"json_object\" is not supported on Bedrock. Converse has no field that ' +\n 'mechanically guarantees valid JSON output for this mode, so it used to be emulated by ' +\n 'injecting a \"respond with JSON only\" instruction into the system prompt, a guarantee ' +\n 'this adapter can no longer make. Use `jsonSchema` instead, which maps to a real ' +\n \"constraint (Converse's native outputConfig.textFormat on covered models, or a forced \" +\n 'tool call otherwise).',\n 'validation',\n );\n }\n\n let toolName: string | undefined;\n let toolConfig: NonNullable<BedrockRequest['toolConfig']> | undefined;\n let outputConfig: NonNullable<BedrockRequest['outputConfig']> | undefined;\n\n if (jsonSchema && isNative) {\n // Native path: the schema goes in its own request field, independent\n // of toolConfig, so real tools (if any) are built exactly like the\n // tools-only branch below and sent alongside it.\n //\n // Unlike every other schema this adapter builds, the real Bedrock\n // Converse API requires `schema` here as a JSON-encoded *string*, not\n // a parsed object, nested under `structure.jsonSchema` rather than\n // flat on `textFormat`. There is no `strict` field on this path,\n // unlike `toolSpec`.\n const { schema, description } = jsonSchema;\n\n outputConfig = {\n textFormat: {\n type: 'json_schema',\n structure: {\n jsonSchema: { schema: JSON.stringify(schema), name: schemaName, description },\n },\n },\n };\n } else if (jsonSchema && schemaName) {\n // Legacy path: jsonSchema alone (or with tools, on a native model;\n // see above), on a model without native support, becomes a forced\n // single tool call via toolConfig, unchanged from before this adapter\n // had a native path.\n const { schema, description, strict } = jsonSchema;\n\n toolName = schemaName;\n toolConfig = {\n tools: [{ toolSpec: { name: toolName, description, inputSchema: { json: schema }, strict } }],\n toolChoice: { tool: { name: toolName } },\n };\n }\n\n // Runs after the branch chain, unified across every case that still\n // wants real tools built: the native-with-tools case above (toolConfig\n // still unset there, only outputConfig is), and the no-jsonSchema-at-all\n // case. `toolName` is the one signal that distinguishes them from the\n // legacy forced-single-tool-call branch, which builds its own toolConfig\n // inline and must not be overwritten here.\n if (params.tools?.length && !toolName) {\n toolConfig = buildBedrockToolConfig(params.tools, params.tool_choice);\n }\n\n // Runs whenever a jsonSchema call actually ends up sending toolConfig,\n // whether that's the legacy forced-single-tool-call path, or the native\n // path with real `tools` also present (native structured output doesn't\n // need Converse tool-use support, but real tools alongside it still do).\n if (jsonSchema && toolConfig && toolUseSupportedModels) {\n const isSupported = Array.isArray(toolUseSupportedModels)\n ? toolUseSupportedModels.includes(params.model)\n : toolUseSupportedModels(params.model);\n\n if (!isSupported) {\n throw new LLMError(\n `Bedrock model \"${params.model}\" is not listed in toolUseSupportedModels, but this call ` +\n 'requires Converse tool use (either jsonSchema emulated as a forced tool call, or real ' +\n '`tools` sent alongside native structured output).',\n 'invalid_params',\n { code: 'unsupported_capability', issues: { capability: 'toolUseSupportedModels' } },\n );\n }\n }\n\n // Converse has no reasoning-budget field of its own; both `thinking`\n // shapes below are forwarded through `additionalModelRequestFields`,\n // passed straight through to the underlying model unchanged, and\n // meaningless to any non-Claude model family, hence the `isClaudeModel`\n // gate. Within Claude models, `budget_tokens` (manual thinking) returns\n // a 400 on Claude Opus 4.7 and later and every Claude 5 tier model, see\n // `supportsManualThinkingBudget`'s docs, so those get adaptive thinking\n // plus `outputConfig.effort` instead, same fallback `fromAnthropic`\n // uses. Native `budget_tokens`/`reasoning_effort` are each used\n // directly when the model natively accepts them; the other is\n // converted through the same table the other adapters share.\n let additionalModelRequestFields: BedrockRequest['additionalModelRequestFields'];\n let effort: ClaudeAdaptiveEffort | undefined;\n\n if (\n isClaudeModel(params.model) &&\n (params.budget_tokens !== undefined || params.reasoning_effort !== undefined)\n ) {\n // Checked once here, right before any thinking block is built, so a\n // caller who set budgetTokens/reasoningEffort alongside a forced\n // toolChoice (or a jsonSchema call that silently forces one to emulate\n // structured output on a non-native model, see toolConfig above) gets\n // a clear local error instead of a 400 after a real network round\n // trip. Same underlying Claude-model constraint as the Anthropic\n // adapter's own check, just against Converse's toolChoice shape\n // instead of the Anthropic SDK's.\n const forcedToolChoice = toolConfig?.toolChoice;\n assertNoForcedToolChoiceWithThinking(\n forcedToolChoice && 'tool' in forcedToolChoice\n ? `toolChoice forcing the \"${forcedToolChoice.tool?.name}\" tool`\n : forcedToolChoice && 'any' in forcedToolChoice\n ? \"toolChoice: 'required' (Converse's \\\"any\\\" tool_choice)\"\n : undefined,\n );\n\n if (supportsManualThinkingBudget(params.model, adaptiveOnlyModels)) {\n const budgetTokens =\n params.budget_tokens ?? effortToBudgetTokens(params.reasoning_effort!, effortTokenTable);\n\n // Same constraint as the Claude API itself: `budget_tokens` must be\n // at least 1024 and strictly less than `max_tokens`.\n assertValidClaudeBudgetTokens(budgetTokens, params.max_tokens);\n\n additionalModelRequestFields = { thinking: { type: 'enabled', budget_tokens: budgetTokens } };\n } else {\n const effortTier =\n params.reasoning_effort ?? budgetTokensToEffort(params.budget_tokens!, effortTokenTable);\n\n additionalModelRequestFields = { thinking: { type: 'adaptive' } };\n effort = toClaudeAdaptiveEffort(effortTier);\n }\n }\n\n // Same constraint as the Claude API itself: temperature (and top_p/\n // top_k) must not be sent alongside any thinking mode, manual or\n // adaptive. See the matching comment in `adapters/anthropic.ts`.\n const temperature = additionalModelRequestFields ? undefined : params.temperature;\n\n const request: BedrockRequest = {\n modelId: params.model,\n messages: mergeConsecutiveToolResults(conversationMessages.map((m) => toBedrockMessage(m))),\n system: systemMessage?.content ? [{ text: systemMessage.content }] : undefined,\n inferenceConfig: {\n ...(temperature !== undefined ? { temperature } : {}),\n maxTokens: params.max_tokens,\n },\n ...(toolConfig ? { toolConfig } : {}),\n ...(outputConfig || effort\n ? {\n outputConfig: {\n ...(outputConfig ?? {}),\n ...(effort ? { effort } : {}),\n },\n }\n : {}),\n ...(additionalModelRequestFields ? { additionalModelRequestFields } : {}),\n };\n\n return { request, toolName };\n}\n\n/**\n * Minimal structural shape of an AWS SDK v3 client that exposes `.send()`,\n * matching `BedrockRuntimeClient` (and its abort-signal-aware call\n * convention). Avoids importing `@aws-sdk/client-bedrock-runtime` for the\n * type.\n */\ninterface AwsSendClient {\n send(command: unknown, options?: { abortSignal?: AbortSignal }): Promise<unknown>;\n}\n\n/**\n * Distinguishes a real AWS SDK v3 client (`.send(command)`) from a\n * hand-written `BedrockConverseClient` (`.converse(params)`) purely\n * structurally, so `fromBedrock` can accept either without the caller\n * saying which one they're passing. The two shapes don't overlap: nothing\n * implementing `.converse()` would also need `.send()`.\n */\nfunction isAwsSendClient(client: BedrockConverseClient | AwsSendClient): client is AwsSendClient {\n return typeof (client as AwsSendClient).send === 'function';\n}\n\n/**\n * One raw event off an AWS SDK `ConverseStreamCommand` response's `stream`.\n * Intentionally untyped (`Record<string, unknown>`, not AWS's own generated\n * `ConverseStreamOutput`). Importing that type would mean importing\n * `@aws-sdk/client-bedrock-runtime` statically, which `wrapAwsSendClient`\n * avoids. Narrowing the raw event structurally, via\n * `normalizeBedrockStreamEvent` below, gets the same safety without the\n * static dependency.\n */\ntype RawBedrockStreamEvent = Record<string, unknown>;\n\n/**\n * Narrows one raw AWS stream event down to VernLLM's intentionally minimal\n * `BedrockConverseStreamEvent` union. Returns `undefined` if the event\n * isn't one of the kinds this adapter models.\n *\n * AWS's real `ConverseStreamOutput` type is a strictly larger union than\n * `BedrockConverseStreamEvent`. On top of every member modeled here, it\n * also includes a generated `$unknown` member, AWS's forward-compatibility\n * escape hatch for event kinds added to the service after this SDK version\n * was generated. A blind type assertion from one union to the other would\n * compile, but would let `$unknown` (or any other future member) reach\n * `fromBedrock`'s event-handling loop unnarrowed, as if it were one of the\n * kinds actually handled there.\n *\n * Returning `undefined` for anything unrecognized, filtered out by\n * `normalizeBedrockEventStream` below, keeps two guarantees. AWS SDK\n * generated types never leak into `fromBedrock`'s application code, only\n * this module's own `BedrockConverseStreamEvent` shape does. An event kind\n * this adapter doesn't yet know about is silently skipped, the same\n * forward-compatible behavior AWS's own `$unknown` convention implies,\n * rather than crashing the stream or being misrouted into a handler that\n * doesn't actually match its shape.\n */\nfunction normalizeBedrockStreamEvent(\n raw: RawBedrockStreamEvent,\n): BedrockConverseStreamEvent | undefined {\n if ('messageStart' in raw) return { messageStart: raw.messageStart as { role: 'assistant' } };\n\n if ('contentBlockStart' in raw) {\n return {\n contentBlockStart: raw.contentBlockStart as BedrockConverseStreamEvent extends {\n contentBlockStart: infer T;\n }\n ? T\n : never,\n };\n }\n\n if ('contentBlockDelta' in raw) {\n return {\n contentBlockDelta: raw.contentBlockDelta as BedrockConverseStreamEvent extends {\n contentBlockDelta: infer T;\n }\n ? T\n : never,\n };\n }\n\n if ('contentBlockStop' in raw) {\n return { contentBlockStop: raw.contentBlockStop as { contentBlockIndex: number } };\n }\n\n if ('messageStop' in raw) return { messageStop: raw.messageStop as { stopReason?: string } };\n\n if ('metadata' in raw) {\n return {\n metadata: raw.metadata as {\n usage?: { inputTokens?: number; outputTokens?: number; totalTokens?: number };\n },\n };\n }\n\n if ('internalServerException' in raw) {\n return { internalServerException: raw.internalServerException as { message?: string } };\n }\n\n if ('modelStreamErrorException' in raw) {\n return {\n modelStreamErrorException: raw.modelStreamErrorException as {\n message?: string;\n originalStatusCode?: number;\n },\n };\n }\n\n if ('validationException' in raw) {\n return { validationException: raw.validationException as { message?: string } };\n }\n\n if ('throttlingException' in raw) {\n return { throttlingException: raw.throttlingException as { message?: string } };\n }\n\n if ('serviceUnavailableException' in raw) {\n return { serviceUnavailableException: raw.serviceUnavailableException as { message?: string } };\n }\n\n // Everything else, including AWS's generated `$unknown` member (and any\n // event kind added to the real service after this adapter was written),\n // is intentionally dropped here rather than forwarded.\n return undefined;\n}\n\n/**\n * Wraps a raw AWS event stream, narrowing each event through\n * `normalizeBedrockStreamEvent` and filtering out anything that doesn't\n * map onto `BedrockConverseStreamEvent`. `fromBedrock`'s event loop only\n * ever sees the shapes it actually models.\n */\nasync function* normalizeBedrockEventStream(\n rawStream: AsyncIterable<RawBedrockStreamEvent>,\n): AsyncGenerator<BedrockConverseStreamEvent> {\n for await (const raw of rawStream) {\n const event = normalizeBedrockStreamEvent(raw);\n\n if (event) yield event;\n }\n}\n\n/**\n * Adapts a real AWS SDK v3 client (anything with `.send()`, matching\n * `BedrockRuntimeClient`) into a `BedrockConverseClient`, so `fromBedrock`\n * can accept either without a hand-written `.converse()`/`.converseStream()`\n * wrapper. Internally does what that wrapper would: `client.send(new\n * ConverseCommand(params))`, `client.send(new\n * ConverseStreamCommand(params))`.\n *\n * `@aws-sdk/client-bedrock-runtime` is intentionally not a dependency (not\n * even a peer dependency) of this package. `vern-llm` otherwise has zero\n * runtime dependencies, and every other adapter works the same way:\n * structural typing over whatever client the caller already has. Instead,\n * `ConverseCommand`/`ConverseStreamCommand` are pulled in with a dynamic\n * `import()` the first time either method actually runs, and memoized\n * after that. Nothing is added to `package.json`, static or peer.\n * Bundlers only pull the AWS SDK in for code paths that actually pass a\n * raw AWS client to `fromBedrock`; a hand-written `BedrockConverseClient`\n * stays unaffected. If `@aws-sdk/client-bedrock-runtime` isn't installed,\n * the failure is a clear `LLMError` naming exactly what's missing, at the\n * moment it's needed, rather than a silent peer-dependency warning at\n * install time or a raw \"Cannot find module\" a caller has to trace back\n * themselves.\n *\n * Also closes two structural gaps between AWS's generated types and\n * `BedrockConverseClient`. AWS's `ConverseStreamCommandOutput.stream` is\n * optional, a response may not include it. This throws a clear `LLMError`\n * instead of letting `undefined` reach `fromBedrock`'s `for await` loop.\n * AWS's `ConverseStreamOutput` union is larger than\n * `BedrockConverseStreamEvent`, it includes a generated `$unknown` member.\n * Every event is narrowed through `normalizeBedrockStreamEvent` before it\n * reaches application code, instead of being asserted wholesale from one\n * type to the other.\n */\nfunction wrapAwsSendClient(client: AwsSendClient): BedrockConverseClient {\n type BedrockRuntimeCommands = {\n ConverseCommand: new (input: unknown) => unknown;\n ConverseStreamCommand: new (input: unknown) => unknown;\n };\n\n let commandsPromise: Promise<BedrockRuntimeCommands> | undefined;\n\n function loadCommands(): Promise<BedrockRuntimeCommands> {\n commandsPromise ??= import('@aws-sdk/client-bedrock-runtime').then(\n (mod) => mod as BedrockRuntimeCommands,\n (cause) => {\n commandsPromise = undefined;\n\n throw new LLMError(\n 'fromBedrock requires \"@aws-sdk/client-bedrock-runtime\" to be installed to use a raw AWS ' +\n 'SDK client (it is not a dependency of vern-llm itself). Install it, or pass your own ' +\n 'object with .converse()/.converseStream() methods instead.',\n 'validation',\n { cause },\n );\n },\n );\n\n return commandsPromise;\n }\n\n return {\n converse: async (params, requestOptions) => {\n const { ConverseCommand } = await loadCommands();\n\n return client.send(new ConverseCommand(params), {\n abortSignal: requestOptions.signal,\n }) as ReturnType<BedrockConverseClient['converse']> extends Promise<infer R>\n ? Promise<R>\n : never;\n },\n\n converseStream: async (params, requestOptions) => {\n const { ConverseStreamCommand } = await loadCommands();\n\n const result = (await client.send(new ConverseStreamCommand(params), {\n abortSignal: requestOptions.signal,\n })) as { stream?: AsyncIterable<RawBedrockStreamEvent> };\n\n // AWS marks `stream` optional on `ConverseStreamCommandOutput`\n // because a response may not include it; VernLLM's own\n // `BedrockConverseClient.converseStream` return shape requires it,\n // since a `stream: true` call is meaningless without one. Fail\n // loudly here, at the adapter boundary, instead of letting\n // `undefined` reach `fromBedrock`'s `for await (const event of\n // stream)` loop, where it would throw a much less specific\n // \"stream is not async iterable\" error.\n if (!result.stream) {\n throw new LLMError(\n 'Bedrock ConverseStreamCommand response did not include a stream. This can happen if the ' +\n \"request or the model doesn't actually support Converse streaming.\",\n 'api',\n { code: 'server_error' },\n );\n }\n\n return { stream: normalizeBedrockEventStream(result.stream) };\n },\n };\n}\n\n/**\n * Wraps a Bedrock Converse-API client so it satisfies the `LLMClient`\n * interface VernLLM uses for OpenAI/Groq. The Converse API is unified\n * across Bedrock's model families (Anthropic, Titan, Llama, Mistral, etc.),\n * so unlike raw per-model Bedrock invocation, this one adapter works\n * regardless of which underlying model `modelId` points at, as long as\n * that model supports Converse (most current-generation ones do)\n *\n * `bedrockClient` accepts either a hand-written `BedrockConverseClient`\n * (a `.converse()`/`.converseStream()` wrapper you provide) or a real AWS\n * SDK v3 client (anything with `.send()`, matching `BedrockRuntimeClient`)\n * directly, detected structurally. Passing a raw AWS client skips the\n * hand-written wrapper entirely, internally doing what it would\n * (`send(new ConverseCommand(...))`, `send(new\n * ConverseStreamCommand(...))`). See `wrapAwsSendClient` for how that path\n * is implemented, including why `@aws-sdk/client-bedrock-runtime` stays\n * out of this package's dependencies either way.\n *\n * `response_format: json_schema`, on a model covered by\n * `options.nativeStructuredOutputModels` (opt-in, unset by default), is\n * sent as `outputConfig.textFormat`, its own request field, independent of\n * `toolConfig`, so it can be combined with real, caller-supplied `tools`\n * in the same request. Matches the real Converse API's shape exactly: the\n * schema is nested under `structure.jsonSchema` and JSON-encoded as a\n * string, not the parsed object `toolConfig`'s tool schemas use, and there\n * is no `strict` field on this path.\n *\n * On any other model (the default), `response_format: json_schema` is\n * mapped to Converse's `toolConfig` instead: a single tool is defined from\n * the schema, description, and strictness settings, and `toolChoice`\n * forces the model to call it. This legacy path cannot be combined with\n * real `tools` (both would need the same `toolConfig`), and a call that\n * tries throws `LLMError('validation')` before reaching the API.\n * Provider-constrained schema matching applies only when `strict: true` is\n * forwarded and supported. Native tool support varies by model family;\n * pass `toolUseSupportedModels` to preflight-check it (see\n * `BedrockAdapterOptions`), otherwise a `jsonSchema` call to an\n * unsupported model surfaces Bedrock's raw error unchanged.\n *\n * `response_format: json_object` throws `LLMError('validation')`: Converse\n * has no field that mechanically guarantees JSON output, and the only way\n * to emulate it was an unenforced system-prompt instruction, a guarantee\n * this adapter no longer pretends to make. Use `jsonSchema` instead.\n * `reasoning_effort` (no Converse equivalent) is converted to a token\n * budget and forwarded via `additionalModelRequestFields` for Claude\n * models only; `budget_tokens` is forwarded the same way directly. Both\n * are silently dropped for non-Claude models, which have no equivalent\n * field to reach for. See `adapters/internal/reasoningBudget.utils.ts`.\n *\n * `tools` alone maps to Converse's native `toolConfig`/`toolUse`/\n * `toolResult`; `tool_choice` maps to `toolConfig.toolChoice`.\n *\n * `createStream` calls `converseStream` (optional on `BedrockConverseClient`\n *, required only if the caller sets `stream: true`) and translates its\n * `contentBlockStart`/`contentBlockDelta`/`metadata` events into\n * `WireStreamChunk`s. Content blocks are tracked by `contentBlockIndex`,\n * same as `fromAnthropic`'s block-index tracking (Converse's streaming\n * shape is structurally close to Anthropic's own, both being tool-use-aware\n * content-block streams), including the same `json-tool` unwrapping: a\n * `jsonSchema`-forced tool's `toolUse.input` deltas are re-emitted as\n * `text-delta`, not `tool_call_delta`, so the accumulated result lands in\n * `finalizeResponse`'s `content` path exactly like the non-streaming\n * `create` branch above unwraps it.\n */\nexport function fromBedrock(\n bedrockClient: BedrockConverseClient | AwsSendClient,\n options?: BedrockAdapterOptions,\n): LLMClient {\n const client: BedrockConverseClient = isAwsSendClient(bedrockClient)\n ? wrapAwsSendClient(bedrockClient)\n : bedrockClient;\n\n const toolUseSupportedModels = options?.toolUseSupportedModels;\n const nativeStructuredOutputModels = options?.nativeStructuredOutputModels;\n const effortTokenTable = resolveEffortTokenTable(options?.reasoningEffortTokens);\n const adaptiveOnlyModels = options?.adaptiveOnlyModels;\n\n return {\n // json_object is not supported: see buildBedrockRequest's throw above,\n // and LLMClient.supportsJsonObjectMode's docs.\n supportsJsonObjectMode: false,\n chat: {\n completions: {\n async create(params, requestOptions) {\n const { request, toolName } = buildBedrockRequest(\n params,\n toolUseSupportedModels,\n nativeStructuredOutputModels,\n effortTokenTable,\n adaptiveOnlyModels,\n );\n\n const response = await client.converse(request, requestOptions);\n\n let text: string;\n let wireToolCalls: WireToolCall[] | undefined;\n\n if (toolName) {\n // Forced tool-use: the schema-conforming payload arrives as the\n // toolUse content block's already-parsed `input`, not as text.\n // Re-serialize it to JSON so it flows through the same\n // string-content contract every other adapter uses.\n const toolUseBlock = response.output?.message?.content?.find(\n (block) => block.toolUse?.name === toolName,\n );\n\n text = toolUseBlock?.toolUse ? JSON.stringify(toolUseBlock.toolUse.input) : '';\n } else {\n const blocks = response.output?.message?.content ?? [];\n\n text = blocks.map((c) => c.text ?? '').join('');\n\n const toolUses = blocks.filter(\n (\n block,\n ): block is { toolUse: { toolUseId?: string; name?: string; input?: unknown } } =>\n Boolean(block.toolUse),\n );\n\n if (toolUses.length) {\n wireToolCalls = toolUses.map((block, i) => {\n const toolUse = block.toolUse;\n\n if (!toolUse.name) {\n throw new LLMError(\n `Bedrock returned a toolUse block without a name at index ${i}.`,\n 'validation',\n );\n }\n\n return {\n id: toolUse.toolUseId ?? `${toolUse.name}_${i}`,\n type: 'function' as const,\n function: {\n name: toolUse.name,\n arguments: JSON.stringify(toolUse.input ?? {}),\n },\n };\n });\n }\n }\n\n return {\n choices: [\n {\n message: { content: text, ...(wireToolCalls ? { tool_calls: wireToolCalls } : {}) },\n },\n ],\n usage: {\n prompt_tokens: response.usage?.inputTokens,\n completion_tokens: response.usage?.outputTokens,\n total_tokens: response.usage?.totalTokens,\n },\n };\n },\n\n async *createStream(params, requestOptions) {\n if (!client.converseStream) {\n throw new LLMError(\n 'stream: true requires a Bedrock client with converseStream',\n 'invalid_params',\n { code: 'unsupported_capability', issues: { capability: 'converseStream' } },\n );\n }\n\n const { request, toolName } = buildBedrockRequest(\n params,\n toolUseSupportedModels,\n nativeStructuredOutputModels,\n effortTokenTable,\n adaptiveOnlyModels,\n );\n\n const { stream } = await client.converseStream(request, requestOptions);\n\n const blockKinds = new Map<number, 'text' | 'tool_use' | 'json-tool'>();\n\n for await (const event of stream) {\n if ('contentBlockStart' in event) {\n const { contentBlockIndex, start } = event.contentBlockStart;\n\n if (start?.toolUse) {\n const kind = start.toolUse.name === toolName ? 'json-tool' : 'tool_use';\n\n blockKinds.set(contentBlockIndex, kind);\n\n if (kind === 'tool_use' && !toolName) {\n yield {\n type: 'tool_call_delta',\n index: contentBlockIndex,\n id: start.toolUse.toolUseId,\n name: start.toolUse.name,\n };\n }\n } else {\n blockKinds.set(contentBlockIndex, 'text');\n }\n } else if ('contentBlockDelta' in event) {\n const { contentBlockIndex, delta } = event.contentBlockDelta;\n\n // Only surfaced as real content when there's no forced\n // json-schema tool in play, see the identical guard (and\n // its full rationale) in `fromAnthropic`'s `createStream`.\n // Converse's streaming shape is structurally close enough to\n // Anthropic's own that the same corruption risk applies: a\n // genuine text block alongside a forced tool call would\n // otherwise get concatenated into the same buffer as the\n // tool's JSON payload.\n if (delta && 'text' in delta && delta.text !== undefined && !toolName) {\n yield { type: 'text-delta', delta: delta.text };\n } else if (delta && 'toolUse' in delta && delta.toolUse?.input !== undefined) {\n const kind = blockKinds.get(contentBlockIndex);\n\n if (kind === 'json-tool') {\n yield { type: 'text-delta', delta: delta.toolUse.input };\n } else if (!toolName) {\n yield {\n type: 'tool_call_delta',\n index: contentBlockIndex,\n argumentsDelta: delta.toolUse.input,\n } satisfies WireStreamChunk;\n }\n }\n } else if ('metadata' in event && event.metadata.usage) {\n yield {\n type: 'usage',\n usage: {\n prompt_tokens: event.metadata.usage.inputTokens,\n completion_tokens: event.metadata.usage.outputTokens,\n total_tokens: event.metadata.usage.totalTokens,\n },\n };\n } else if ('throttlingException' in event) {\n throw new LLMError(\n event.throttlingException.message ?? 'Bedrock throttled the request mid-stream',\n 'api',\n { status: 429, code: 'provider_rate_limited' },\n );\n } else if ('validationException' in event) {\n throw new LLMError(\n event.validationException.message ?? 'Bedrock rejected the request mid-stream',\n 'validation',\n );\n } else if (\n 'internalServerException' in event ||\n 'serviceUnavailableException' in event ||\n 'modelStreamErrorException' in event\n ) {\n const detail =\n ('internalServerException' in event && event.internalServerException.message) ||\n ('serviceUnavailableException' in event &&\n event.serviceUnavailableException.message) ||\n ('modelStreamErrorException' in event && event.modelStreamErrorException.message) ||\n 'Bedrock reported a mid-stream error';\n\n const status =\n ('modelStreamErrorException' in event &&\n event.modelStreamErrorException.originalStatusCode) ||\n ('serviceUnavailableException' in event && 503) ||\n 500;\n\n throw new LLMError(detail, 'api', {\n status,\n code: status >= 500 ? 'server_error' : undefined,\n });\n }\n }\n },\n },\n },\n };\n}\n\n/** Maps VernLLM's OpenAI-shaped wire `tool_choice` onto Converse's `toolChoice`. */\nfunction toBedrockToolChoice(\n toolChoice: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice'],\n): NonNullable<Parameters<BedrockConverseClient['converse']>[0]['toolConfig']>['toolChoice'] {\n if (!toolChoice || toolChoice === 'auto') return { auto: {} };\n if (toolChoice === 'required') return { any: {} };\n\n if (toolChoice === 'none') {\n // Converse's toolConfig.toolChoice has no 'none' option. The only way\n // to guarantee no tool use is to omit toolConfig.tools entirely, which\n // isn't an option here since tools were explicitly requested. Silently\n // falling back to 'auto' would let the model call tools despite the\n // caller explicitly asking it not to, so this fails loudly instead.\n throw new LLMError(\n \"'none' is not supported by fromBedrock: Bedrock Converse has no \" +\n '`tool_choice` equivalent to forbidding tool use while tools are still offered. Omit ' +\n '`tools` entirely for this call instead.',\n 'invalid_params',\n { code: 'unsupported_capability', issues: { capability: \"toolChoice: 'none'\" } },\n );\n }\n\n return { tool: { name: toolChoice.function.name } };\n}\n/**\n * Translates one VernLLM wire message into Converse's\n * `{ role: 'user' | 'assistant', content }` shape.\n */\nfunction toBedrockMessage(\n m: Extract<\n Parameters<LLMClient['chat']['completions']['create']>[0]['messages'][number],\n { role: 'user' | 'assistant' | 'tool' }\n >,\n): { role: 'user' | 'assistant'; content: BedrockContentBlock[] } {\n if (m.role === 'tool') {\n return {\n role: 'user',\n content: [\n {\n toolResult: {\n toolUseId: m.tool_call_id,\n content: [{ text: m.content }],\n status: m.is_error ? 'error' : 'success',\n },\n },\n ],\n };\n }\n\n if (m.role === 'assistant' && m.tool_calls?.length) {\n const blocks: BedrockContentBlock[] = [];\n\n if (m.content) blocks.push({ text: m.content });\n\n for (const tc of m.tool_calls) {\n let input: unknown;\n\n if (!tc.function.arguments.trim()) {\n input = {};\n } else {\n try {\n input = JSON.parse(tc.function.arguments);\n } catch (cause) {\n throw new LLMError(\n `Assistant tool call \"${tc.function.name}\" (${tc.id}) has arguments that are not valid JSON.`,\n 'validation',\n { cause },\n );\n }\n }\n\n blocks.push({ toolUse: { toolUseId: tc.id, name: tc.function.name, input } });\n }\n\n return { role: 'assistant', content: blocks };\n }\n\n return {\n role: m.role,\n content: Array.isArray(m.content) ? toBedrockContent(m.content) : [{ text: m.content ?? '' }],\n };\n}\n\n/**\n * Converse expects the results of everything the model asked for in one\n * turn to arrive together as multiple `toolResult` content blocks on a\n * single `'user'` message, not as separate consecutive `'user'` messages.\n * The per-wire-message mapping above produces one `'user'` message per\n * VernLLM wire tool message, so when an assistant turn requested more than\n * one tool, this merges the resulting run of toolResult-only `'user'`\n * messages back into one.\n */\nfunction mergeConsecutiveToolResults(\n messages: { role: 'user' | 'assistant'; content: BedrockContentBlock[] }[],\n): { role: 'user' | 'assistant'; content: BedrockContentBlock[] }[] {\n const isToolResultOnly = (\n m: (typeof messages)[number],\n ): m is { role: 'user'; content: BedrockContentBlock[] } =>\n m.role === 'user' && m.content.length > 0 && m.content.every((b) => 'toolResult' in b);\n\n const merged: (typeof messages)[number][] = [];\n\n for (const m of messages) {\n const prev = merged.at(-1);\n\n if (isToolResultOnly(m) && prev && isToolResultOnly(prev)) {\n prev.content.push(...m.content);\n } else {\n merged.push(m);\n }\n }\n\n return merged;\n}\n","import {\n LLMError,\n type LLMClient,\n type WireStreamChunk,\n type WireToolCall,\n} from '../types/index.js';\nimport { parseSseStream, SSE_PING } from './internal/sse.js';\n\n/** The chat-completion-shaped request VernLLM builds internally */\ntype ChatRequest = Parameters<LLMClient['chat']['completions']['create']>[0];\n\n/**\n * The minimal shape the fetch adapter needs from a response object.\n * Native `fetch`'s `Response` satisfies this, but so do wrappers around\n * `axios`, `node-fetch`, `undici`, etc, which makes `request` swappable\n * without forcing consumers to polyfill the full `Response` interface\n */\nexport interface ResponseLike {\n ok: boolean;\n status: number;\n headers: {\n get(name: string): string | null;\n };\n text(): Promise<string>;\n json(): Promise<unknown>;\n}\n\n/** A fetch-compatible request function; defaults to native `fetch` */\nexport type RequestLike = (\n url: string,\n init: {\n method: string;\n headers: Record<string, string>;\n body?: string;\n signal?: AbortSignal;\n },\n) => Promise<ResponseLike>;\n\n/**\n * A streaming-capable request function. Unlike `RequestLike`, which returns\n * a fully-buffered `ResponseLike`, this resolves to an `AsyncIterable` of\n * progressively-arriving chunks, the common ground across transports:\n * native `fetch`'s `response.body` (wrapped to be iterable; see\n * `webStreamToAsyncIterable` below), axios's Node `Readable` in\n * `responseType: 'stream'` mode (already async-iterable, no wrapping\n * needed), `node-fetch`, `undici`, etc, all satisfy this with little or no\n * glue code. Defaults to native `fetch`.\n */\nexport type StreamRequestLike = (\n url: string,\n init: {\n method: string;\n headers: Record<string, string>;\n body?: string;\n signal?: AbortSignal;\n },\n) => Promise<AsyncIterable<Uint8Array | string>>;\n\nexport interface FetchAdapterConfig {\n /** Endpoint URL, or a function of the request in case it depends on model/params */\n url: string | ((params: ChatRequest) => string);\n /** Static headers, or a function (sync or async) for things like refreshed auth tokens */\n headers?:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>);\n /** HTTP method. Default 'POST' */\n method?: string;\n /**\n * The function used to make the HTTP request. Defaults to native `fetch`.\n * Swap in `axios`, `node-fetch`, or any other transport, as long as it\n * resolves to a `ResponseLike` object\n */\n request?: RequestLike;\n /** Maps VernLLMs internal chat-completion request into the providers raw request body */\n mapRequest: (params: ChatRequest) => unknown;\n /**\n * Maps the providers raw JSON response into `{ content, usage?, toolCalls? }`\n * `content` is the assistants text (JSON string when JSON mode was requested).\n * `content` may be empty/omitted when the model responded with only tool\n * calls and no text.\n *\n * `toolCalls`, when the model requested one or more tools, is the list of\n * calls as flat `{ id, name, arguments }` entries (matching this config's\n * own `toolCalls?: Array<{ id: string; name: string; arguments: string }>`\n * return type below), each entry's `arguments` already JSON-*encoded* as a\n * string (not the parsed object), mirroring the wire format every\n * OpenAI-compatible provider uses. `fromFetch` itself converts these into\n * `WireToolCall`'s `type`/`function`-wrapped shape before returning them\n * from `create`. VernLLM parses (and validates, if `argumentsSchema` was\n * set) the arguments string internally, mapResponse doesn't need to do\n * that itself.\n */\n mapResponse: (json: unknown) => {\n content?: string;\n usage?: { promptTokens?: number; completionTokens?: number; totalTokens?: number };\n toolCalls?: Array<{ id: string; name: string; arguments: string }>;\n };\n\n /**\n * Optional. Required only for `stream: true` calls. The function used to\n * open a streaming HTTP request. Takes the same request shape as\n * `request`, but resolves to an `AsyncIterable` of progressively-arriving\n * `Uint8Array` or `string` chunks instead of a buffered `ResponseLike`.\n * Defaults to native `fetch`.\n */\n requestStream?: StreamRequestLike;\n\n /**\n * Optional. How the raw stream bytes are split into individual event\n * payloads. Defaults to Server-Sent Events framing (`data: ...` blocks\n * separated by a blank line, `[DONE]` sentinel honored, see\n * `parseSseStream`), which covers the large majority of LLM providers'\n * streaming HTTP endpoints. Override this for a provider that frames its\n * stream differently, e.g. newline-delimited JSON (NDJSON) with no SSE\n * envelope.\n */\n parseStreamFrames?: (chunks: AsyncIterable<Uint8Array | string>) => AsyncIterable<unknown>;\n\n /**\n * Optional. Required only for `stream: true` calls. Maps one parsed\n * stream event (already extracted from its frame by `parseStreamFrames`)\n * into zero, one, or more `WireStreamChunk`s, mirrors `mapResponse`'s\n * role for the non-streaming path, just per-event instead of once for\n * the whole body. Return `undefined` to skip an event that carries\n * nothing VernLLM needs (e.g. a provider's keep-alive ping). Configs\n * that don't implement this make `stream: true` throw a clear\n * `LLMError('validation')` rather than a confusing runtime failure or a\n * silently empty stream.\n */\n mapStreamEvent?: (event: unknown) => WireStreamChunk | WireStreamChunk[] | undefined;\n}\n\n/**\n * Wraps a WHATWG `ReadableStream` (what `response.body` is) so it can be\n * consumed with `for await`. Implemented via `getReader()` rather than\n * relying on `ReadableStream` having a native `Symbol.asyncIterator`,\n * that support varies across runtimes/versions, and this works everywhere\n * a `ReadableStream` does.\n */\nasync function* webStreamToAsyncIterable(\n stream: ReadableStream<Uint8Array>,\n): AsyncGenerator<Uint8Array> {\n const reader = stream.getReader();\n\n try {\n for (;;) {\n const { done, value } = await reader.read();\n\n if (done) return;\n if (value) yield value;\n }\n } finally {\n // Cancel before releasing the lock so an early-terminated or\n // downstream-failed consumer still tells the underlying source to\n // stop, instead of leaving it running with nothing left to read it.\n // An already-errored stream rejects cancel(); that rejection isn't\n // useful to the caller here, so it's swallowed.\n try {\n await reader.cancel();\n } catch {\n // Ignore: the stream may already be errored/closed.\n }\n\n reader.releaseLock();\n }\n}\n\n/** Default `requestStream`: native `fetch`, with the same error/`.status` contract non-streaming errors get. */\nasync function defaultRequestStream(\n url: string,\n init: { method: string; headers: Record<string, string>; body?: string; signal?: AbortSignal },\n): Promise<AsyncIterable<Uint8Array | string>> {\n const res = await fetch(url, init);\n\n if (!res.ok) {\n const body = await res.text().catch(() => '');\n const err = new Error(\n `Fetch adapter stream request failed (${res.status}): ${body.slice(0, 500)}`,\n ) as Error & { status?: number; headers?: ResponseLike['headers'] };\n\n err.status = res.status;\n err.headers = res.headers;\n\n throw err;\n }\n\n if (!res.body) {\n throw new Error('Fetch adapter stream request received a response with no body.');\n }\n\n return webStreamToAsyncIterable(res.body);\n}\n\n/** Builds the shared `{ method, headers, body? }` request-init for both `create` and `createStream`. */\nasync function buildRequestInit(\n config: FetchAdapterConfig,\n params: ChatRequest,\n requestBody: unknown,\n): Promise<{ url: string; method: string; headers: Record<string, string>; body?: string }> {\n const url = typeof config.url === 'function' ? config.url(params) : config.url;\n const headers = typeof config.headers === 'function' ? await config.headers() : config.headers;\n const method = config.method ?? 'POST';\n\n // GET/HEAD requests can't carry a body, so skip both the body and\n // the Content-Type header for them rather than sending a body a\n // server may reject\n const supportsBody = !['GET', 'HEAD'].includes(method.toUpperCase());\n\n return {\n url,\n method,\n headers: supportsBody ? { 'Content-Type': 'application/json', ...headers } : { ...headers },\n ...(supportsBody ? { body: JSON.stringify(requestBody) } : {}),\n };\n}\n\n/**\n * A fetch-based escape hatch for providers with no SDK, or where pulling one\n * in isnt worth it. You supply the URL, headers, and two small mapping\n * functions; this handles the HTTP call and slots the result into the same\n * `LLMClient` shape every other adapter produces, so retries, timeouts,\n * the circuit breaker, and JSON/schema handling all still work unmodified\n *\n * Non-2xx responses throw an error with `.status` set to the HTTP status\n * code, so VernLLMs `nonRetryableStatus` handling (e.g. failing fast on\n * 401/403) applies here too\n *\n * Tool calling works the same way as every other adapter: `mapRequest`\n * receives the full `ChatRequest`, including `tools`/`toolChoice`, so it can\n * translate them into whatever shape the provider's wire format expects\n * (typically an OpenAI-`function`-wrapped `tools` array plus a `tool_choice`\n * field). On the way back, `mapResponse` may return a `toolCalls` array\n * (id/name/JSON-encoded-arguments-string per call) alongside or instead of\n * `content`; VernLLM parses and (if `argumentsSchema` was set) validates\n * those arguments the same way it does for every other adapter. For\n * `stream: true`, tool-call deltas go through the existing\n * `mapStreamEvent` seam via `WireStreamChunk`'s `tool_call_delta` variant,\n * no separate config is needed for streaming vs non-streaming tool calls.\n *\n\n * `createStream` requires `mapStreamEvent` (there's no non-streaming\n * response to fall back on, unlike the other three optional streaming\n * seams). It opens the request via `requestStream` (defaults to native\n * `fetch`), splits the raw bytes into individual events via\n * `parseStreamFrames` (defaults to SSE framing, see `parseSseStream`),\n * and translates each event into `WireStreamChunk`(s) via\n * `mapStreamEvent`. Both seams are overridable per-config for providers\n * that don't fit the SSE-over-fetch default. If a custom `request`\n * transport is configured, `requestStream` must be configured too,\n * `requestStream` never silently falls back to `request` (see\n * `createStream`'s own comment for why), so a `stream: true` call with\n * `request` set but no `requestStream` throws a clear\n * `LLMError('validation')` instead of quietly using unrelated native\n * `fetch`.\n */\nexport function fromFetch(config: FetchAdapterConfig): LLMClient {\n return {\n chat: {\n completions: {\n async create(params, options) {\n const { url, method, headers, body } = await buildRequestInit(\n config,\n params,\n config.mapRequest(params),\n );\n const request = config.request ?? fetch;\n\n const res = await request(url, { method, headers, body, signal: options.signal });\n\n if (!res.ok) {\n const responseBody = await res.text().catch(() => '');\n const err = new Error(\n `Fetch adapter request failed (${res.status}): ${responseBody.slice(0, 500)}`,\n ) as Error & { status?: number; headers?: ResponseLike['headers'] };\n err.status = res.status;\n // Attach headers so downstream retry logic (e.g. rate-limit\n // handling) can read things like `Retry-After`\n err.headers = res.headers;\n throw err;\n }\n\n const json = await res.json();\n const { content, usage, toolCalls } = config.mapResponse(json);\n\n // `.length` guard, not just truthiness: an empty array is\n // semantically \"no tool calls\", same as `undefined`. Kept\n // explicit here rather than relying on downstream consumers\n // (e.g. `finalizeResponse`'s `wireToolCalls?.length` check) to\n // treat `[]` as absent, so this stays correct even if that\n // convention ever changes.\n const wireToolCalls: WireToolCall[] | undefined = toolCalls?.length\n ? toolCalls.map((tc) => ({\n id: tc.id,\n type: 'function' as const,\n function: { name: tc.name, arguments: tc.arguments },\n }))\n : undefined;\n\n return {\n choices: [\n {\n message: {\n content,\n ...(wireToolCalls ? { tool_calls: wireToolCalls } : {}),\n },\n },\n ],\n usage: usage\n ? {\n prompt_tokens: usage.promptTokens,\n completion_tokens: usage.completionTokens,\n total_tokens: usage.totalTokens,\n }\n : undefined,\n };\n },\n\n async *createStream(params, options) {\n if (!config.mapStreamEvent) {\n throw new LLMError(\n 'stream: true requires mapStreamEvent to be configured on fromFetch',\n 'invalid_params',\n { code: 'unsupported_capability', issues: { capability: 'mapStreamEvent' } },\n );\n }\n\n // A custom `request` transport (proxying, special auth, test\n // mocking, etc.) is silently irrelevant to streaming unless the\n // caller *also* configures `requestStream`, `requestStream`\n // defaults to plain native `fetch`, not to `config.request`,\n // since `RequestLike`'s buffered `ResponseLike` has no way to\n // expose a byte stream generically. Falling back to native\n // `fetch` anyway would be a surprising, easy-to-miss divergence\n // (bypassing whatever `request` was there for, a proxy, custom\n // auth, or a test's mocked transport, and potentially hitting\n // the real network). Failing loudly here instead of guessing.\n if (config.request && !config.requestStream) {\n throw new LLMError(\n '`stream: true` requires `requestStream` to be configured on fromFetch when a ' +\n 'custom `request` transport is set. `requestStream` does not fall back to ' +\n \"`request` (it needs an async-iterable byte stream, which `RequestLike`'s \" +\n 'buffered `ResponseLike` has no way to provide), without it, `stream: true` ' +\n 'would silently use plain native `fetch` instead of your configured transport. ' +\n 'Add a `requestStream` that opens the same connection your `request` does, or ' +\n 'omit `request` if native `fetch` is fine for both.',\n 'invalid_params',\n { code: 'unsupported_capability', issues: { capability: 'requestStream' } },\n );\n }\n\n const { url, method, headers, body } = await buildRequestInit(\n config,\n params,\n config.mapRequest(params),\n );\n const requestStream = config.requestStream ?? defaultRequestStream;\n const parseFrames = config.parseStreamFrames ?? parseSseStream;\n\n const byteStream = await requestStream(url, {\n method,\n headers,\n body,\n signal: options.signal,\n });\n\n for await (const event of parseFrames(byteStream)) {\n // Only the default parseSseStream produces this sentinel (an\n // SSE comment line used as a keep-alive ping). Handled here,\n // before mapStreamEvent, since provider-specific mapping\n // shouldn't need to know about SSE framing internals.\n if (event === SSE_PING) {\n yield { type: 'ping' };\n continue;\n }\n\n const wireChunks = config.mapStreamEvent(event);\n\n if (!wireChunks) continue;\n\n if (Array.isArray(wireChunks)) {\n yield* wireChunks;\n } else {\n yield wireChunks;\n }\n }\n },\n },\n },\n };\n}\n","import { assertSupportedImageMimeType } from './internal/imageFormat.js';\nimport {\n budgetTokensToEffort,\n resolveEffortTokenTable,\n type EffortTokenTable,\n} from './internal/reasoningBudget.utils.js';\n\nimport type { ContentBlock, LLMClient, WireStreamChunk } from '../types/index.js';\n\n/**\n * OpenAI's wire format only understands `reasoning_effort`, not a raw\n * token budget. When the caller set `reasoningEffort`, it's already on\n * `params` and passed through unchanged, this function does nothing.\n * When only `budgetTokens` was set, it's converted to the nearest tier\n * and `budget_tokens` is dropped, since OpenAI's API would otherwise\n * silently ignore an unrecognized field.\n */\nfunction applyReasoningBudget<\n P extends { reasoning_effort?: 'minimal' | 'low' | 'medium' | 'high'; budget_tokens?: number },\n>(params: P, effortTokenTable?: EffortTokenTable): P {\n if (params.budget_tokens === undefined) return params;\n\n const { budget_tokens, ...rest } = params;\n\n return rest.reasoning_effort !== undefined\n ? (rest as P)\n : ({ ...rest, reasoning_effort: budgetTokensToEffort(budget_tokens, effortTokenTable) } as P);\n}\n\n/** OpenAI's native per-part content shape for a user message. */\ntype OpenAIContentPart =\n | { type: 'text'; text: string }\n | { type: 'image_url'; image_url: { url: string } };\n\n/**\n * Translates a VernLLM `ContentBlock[]` into OpenAI's wire-level content\n * array. Text blocks become `{ type: 'text', text }`; image blocks become\n * `{ type: 'image_url', image_url: { url } }` with the base64 payload\n * inlined as a `data:` URL, since our `ContentBlock` shape (`{ type:\n * 'image', data, mimeType }`) is provider-agnostic and doesn't itself match\n * OpenAI's wire format.\n */\nfunction toOpenAIContent(blocks: ContentBlock[]): OpenAIContentPart[] {\n return blocks.map((block) =>\n block.type === 'image'\n ? {\n type: 'image_url',\n image_url: {\n url: `data:${assertSupportedImageMimeType(block.mimeType)};base64,${block.data}`,\n },\n }\n : { type: 'text', text: block.text },\n );\n}\n\n/** One chunk of an OpenAI-shaped `chat.completions.create({ stream: true })` SSE stream. */\ninterface OpenAIStreamChunk {\n choices?: Array<{\n delta?: {\n content?: string | null;\n tool_calls?: Array<{\n index: number;\n id?: string;\n function?: { name?: string; arguments?: string };\n }>;\n };\n }>;\n usage?: { prompt_tokens?: number; completion_tokens?: number; total_tokens?: number };\n}\n\n/**\n * Translates VernLLM's provider-agnostic `messages` (the one part of a\n * request that isn't a pure passthrough for OpenAI-compatible clients) into\n * OpenAI's native wire shape. Shared between `create` and `createStream` so\n * both go through identical message translation.\n */\nfunction toOpenAIMessages(\n params: Parameters<LLMClient['chat']['completions']['create']>[0],\n): unknown[] {\n return params.messages.map((m) => {\n if (m.role === 'user' && Array.isArray(m.content)) {\n return { ...m, content: toOpenAIContent(m.content) };\n }\n\n if (m.role === 'tool') {\n const { is_error: _isError, ...openAIToolMessage } = m;\n return openAIToolMessage;\n }\n\n return m;\n });\n}\n\n/**\n * Translates one OpenAI-shaped SSE chunk into zero or more `WireStreamChunk`s.\n * A single chunk can carry a text delta, one or more tool-call argument\n * deltas (each keyed by `index`, OpenAI's own convention for streaming\n * parallel tool calls, mirrored directly by VernLLM's `tool_call_delta`\n * shape so accumulation composes without translation), and/or a final\n * usage block (present only when `stream_options.include_usage` is set,\n * which this adapter always sets).\n */\nfunction* toWireStreamChunks(chunk: OpenAIStreamChunk): Generator<WireStreamChunk> {\n const delta = chunk.choices?.[0]?.delta;\n\n if (delta?.content) {\n yield { type: 'text-delta', delta: delta.content };\n }\n\n if (delta?.tool_calls?.length) {\n for (const toolCall of delta.tool_calls) {\n yield {\n type: 'tool_call_delta',\n index: toolCall.index,\n id: toolCall.id,\n name: toolCall.function?.name,\n argumentsDelta: toolCall.function?.arguments,\n };\n }\n }\n\n if (chunk.usage) {\n yield { type: 'usage', usage: chunk.usage };\n }\n}\n\n/**\n * Adapter for any SDK/client whose `chat.completions.create` already\n * matches the OpenAI wire format: this covers most hosted inference\n * providers, since \"OpenAI-compatible\" is a de facto standard for chat\n * completion APIs. Almost everything passes straight through untouched,\n * this exists purely so call sites read clearly (`fromMistral(client)` vs\n * handing a Mistral client to something typed for OpenAI) and so a real\n * transformation could be added later, per-provider, without a breaking\n * change.\n *\n * The one thing that isn't a pure passthrough: a `ContentBlock[]`\n * `userContent` is translated into OpenAI's native `image_url` content-part\n * shape, since VernLLM's `ContentBlock` is intentionally provider-agnostic\n * rather than a copy of any one provider's wire format.\n *\n * Not every SDKs own TypeScript types line up exactly with `LLMClient`\n * (extra fields, stricter unions, etc.), so this takes `unknown` and casts:\n * the actual compatibility contract is the JSON each provider sends and\n * receives over the wire, not the SDKs TS types.\n *\n * `createStream` is implemented by calling the same underlying\n * `chat.completions.create` with `stream: true` (and, for providers that\n * support it, `stream_options: { include_usage: true }`, so a final usage\n * block arrives), the OpenAI SDK, and every OpenAI-compatible client\n * modeled on it, returns an `AsyncIterable` of SSE chunks instead of a\n * single completion object when `stream: true` is set. Each chunk is\n * translated into `WireStreamChunk`(s) via `toWireStreamChunks`.\n *\n * Note on long-running reasoning models: this adapter consumes the\n * underlying SDK's already-parsed stream rather than raw SSE bytes, so\n * unlike `fromFetch`/`fromAnthropic` it cannot see comment-only keep-alive\n * ping frames. Combined with `chunkIdleTimeoutMs`'s 30 second default and\n * `reasoningEffort` (documented to have long silent gaps for o-series and\n * similar models), a long-running reasoning call on this adapter can trip\n * the idle timeout even though the provider is still working. Raise or\n * disable `chunkIdleTimeoutMs` per call for those routes, see `CallParams`.\n */\nexport interface OpenAICompatibleAdapterOptions {\n /**\n * Whether the provider supports `stream_options.include_usage`. Not\n * every \"OpenAI-compatible\" provider is guaranteed to, so this defaults\n * to `true` (matching OpenAI, Groq, Mistral, and most others observed)\n * and should be set to `false` for a provider verified not to support\n * it. When `false`, `stream_options` is omitted entirely and no usage\n * block will arrive on the stream; callers relying on streamed `usage`\n * with such a provider won't get one.\n */\n supportsStreamUsage?: boolean;\n /**\n * Overrides the token count `budgetTokens` buckets into when the caller\n * sets `budgetTokens` but not `reasoningEffort` (OpenAI-compatible\n * clients have no numeric budget field of their own, see\n * `adapters/internal/reasoningBudget.utils.ts`). Only the tiers listed\n * are changed; any omitted tier keeps the built-in default. Has no\n * effect when `reasoningEffort` is set directly.\n */\n reasoningEffortTokens?: Partial<EffortTokenTable>;\n}\n\nexport function fromOpenAICompatible(\n client: unknown,\n options: OpenAICompatibleAdapterOptions = {},\n): LLMClient {\n const raw = client as LLMClient;\n const { supportsStreamUsage = true } = options;\n const effortTokenTable = resolveEffortTokenTable(options.reasoningEffortTokens);\n\n // The underlying client's `create`, called with `stream: true`, returns\n // an AsyncIterable of `OpenAIStreamChunk` rather than\n // `LLMClient['create']`'s normal single-completion return type, hence\n // `unknown` here and a cast at the call site, same rationale as casting\n // the whole client above: the wire contract, not the SDK's own TS types,\n // is what's actually being relied on.\n const rawCreate = raw.chat.completions.create.bind(raw.chat.completions) as unknown as (\n params: unknown,\n options: { signal: AbortSignal },\n ) => Promise<unknown> | AsyncIterable<OpenAIStreamChunk>;\n\n return {\n chat: {\n completions: {\n async create(params, options) {\n const messages = toOpenAIMessages(params);\n\n return raw.chat.completions.create(\n applyReasoningBudget({ ...params, messages }, effortTokenTable) as Parameters<\n LLMClient['chat']['completions']['create']\n >[0],\n options,\n );\n },\n\n async *createStream(params, options) {\n const messages = toOpenAIMessages(params);\n\n const stream = (await rawCreate(\n applyReasoningBudget(\n {\n ...params,\n messages,\n stream: true,\n ...(supportsStreamUsage ? { stream_options: { include_usage: true } } : {}),\n },\n effortTokenTable,\n ),\n options,\n )) as AsyncIterable<OpenAIStreamChunk>;\n\n for await (const chunk of stream) {\n yield* toWireStreamChunks(chunk);\n }\n },\n },\n },\n };\n}\n\n// LLM aliases\n\n/**\n * Named alias for the OpenAI SDK itself. A raw `new OpenAI(...)` instance\n * structurally matches most of `LLMClient`, but newer `openai` SDK major\n * versions have widened `ChatCompletionContentPart` (e.g. adding a `file`\n * variant) in ways that no longer structurally satisfy VernLLM's\n * provider-agnostic `ContentBlock[]` on `userContent`, so passing the SDK\n * instance directly can fail to typecheck depending on the installed\n * `openai` version. Wrapping with `fromOpenAI()` (a plain alias of\n * `fromOpenAICompatible()`) sidesteps that by translating through\n * `unknown` at the boundary, and also picks up multimodal image\n * translation and `createStream` wiring that a raw client doesn't have.\n * See Migration Notes for details.\n */\nexport const fromOpenAI = fromOpenAICompatible;\n\n/** Groqs SDK matches the OpenAI wire format */\nexport const fromGroq = fromOpenAICompatible;\n\n/**\n * Mistrals `chat.completions`-shaped client (or their OpenAI-compat\n * endpoint). Mistral supports `stream_options.include_usage` (added after\n * an earlier period where it returned a 422 for unrecognized fields, per\n * Mistral's changelog and streaming docs), so this is a plain alias like\n * the others, `supportsStreamUsage` defaults to `true`.\n */\nexport const fromMistral = fromOpenAICompatible;\n\n/** DeepSeeks API is OpenAI-compatible */\nexport const fromDeepSeek = fromOpenAICompatible;\n\n/** Cerebras inference API is OpenAI-compatible */\nexport const fromCerebras = fromOpenAICompatible;\n\n/** Together AIs API is OpenAI-compatible */\nexport const fromTogether = fromOpenAICompatible;\n\n/** Fireworks AIs API is OpenAI-compatible */\nexport const fromFireworks = fromOpenAICompatible;\n\n/**\n * Ollama exposes an OpenAI-compatible endpoint at `/v1/chat/completions`\n * (as opposed to its native `/api/chat` format, which differs). Point an\n * OpenAI SDK instances `baseURL` at your Ollama server and pass it here:\n * this does not talk to Ollamas native API directly.\n */\nexport const fromOllama = fromOpenAICompatible;\n\n/** OpenRouter's API is OpenAI-compatible */\nexport const fromOpenRouter = fromOpenAICompatible;\n\n/** Perplexity's API is OpenAI-compatible */\nexport const fromPerplexity = fromOpenAICompatible;\n\n/** DeepInfra's API is OpenAI-compatible */\nexport const fromDeepInfra = fromOpenAICompatible;\n\n/** Novita's API is OpenAI-compatible */\nexport const fromNovita = fromOpenAICompatible;\n\n/** Hyperbolic's API is OpenAI-compatible */\nexport const fromHyperbolic = fromOpenAICompatible;\n\n/** Moonshot's (Kimi) API is OpenAI-compatible */\nexport const fromMoonshot = fromOpenAICompatible;\n\n/** Zhipu's (GLM) API is OpenAI-compatible */\nexport const fromZhipu = fromOpenAICompatible;\n\n/**\n * LM Studio exposes an OpenAI-compatible endpoint at `/v1/chat/completions`.\n * Point an OpenAI SDK instance's `baseURL` at your local LM Studio server.\n */\nexport const fromLMStudio = fromOpenAICompatible;\n\n/**\n * vLLM's OpenAI-compatible server mode exposes `/v1/chat/completions`.\n * Point an OpenAI SDK instance's `baseURL` at your vLLM server.\n */\nexport const fromVLLM = fromOpenAICompatible;\n\n/** xAI's Grok API is OpenAI-compatible */\nexport const fromXAI = fromOpenAICompatible;\n\n/** NVIDIA NIM's hosted and self-hosted endpoints are OpenAI-compatible */\nexport const fromNvidiaNIM = fromOpenAICompatible;\n\n/** Vercel AI Gateway is OpenAI-compatible */\nexport const fromVercelAIGateway = fromOpenAICompatible;\n\n/** Cloudflare Workers AI exposes an OpenAI-compatible endpoint */\nexport const fromCloudflareWorkersAI = fromOpenAICompatible;\n\n/** Nebius AI Studio is OpenAI-compatible */\nexport const fromNebius = fromOpenAICompatible;\n\n/** SambaNova Cloud's API is OpenAI-compatible */\nexport const fromSambaNova = fromOpenAICompatible;\n\n/** Baseten's model hosting exposes an OpenAI-compatible endpoint */\nexport const fromBaseten = fromOpenAICompatible;\n\n/** Featherless AI's API is OpenAI-compatible */\nexport const fromFeatherless = fromOpenAICompatible;\n\n/** Friendli AI's serving endpoint is OpenAI-compatible */\nexport const fromFriendli = fromOpenAICompatible;\n\n/** SiliconFlow's API is OpenAI-compatible */\nexport const fromSiliconFlow = fromOpenAICompatible;\n\n/** Parasail's inference API is OpenAI-compatible */\nexport const fromParasail = fromOpenAICompatible;\n\n/** StepFun's API is OpenAI-compatible */\nexport const fromStepFun = fromOpenAICompatible;\n\n/** MiniMax's API is OpenAI-compatible */\nexport const fromMiniMax = fromOpenAICompatible;\n\n/** Lambda Labs' Inference API is OpenAI-compatible */\nexport const fromLambdaLabs = fromOpenAICompatible;\n\n/** Snowflake Cortex's LLM endpoint is OpenAI-compatible */\nexport const fromSnowflakeCortex = fromOpenAICompatible;\n\n/** Anyscale Endpoints' API is OpenAI-compatible */\nexport const fromAnyscale = fromOpenAICompatible;\n\n/** Lepton AI's inference API is OpenAI-compatible */\nexport const fromLepton = fromOpenAICompatible;\n\n/** Inference.net's API is OpenAI-compatible */\nexport const fromInferenceNet = fromOpenAICompatible;\n\n/** Infermatic's API is OpenAI-compatible */\nexport const fromInfermatic = fromOpenAICompatible;\n\n/** AtlasCloud's inference API is OpenAI-compatible */\nexport const fromAtlasCloud = fromOpenAICompatible;\n\n/** 01.AI's (Yi models) API is OpenAI-compatible */\nexport const from01AI = fromOpenAICompatible;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["NON_RETRYABLE_TOOL_CONTRACT_CODES: ReadonlySet<LLMErrorCode>","LOCAL_RATE_LIMIT_CODES: ReadonlySet<LLMErrorCode>","NON_RETRYABLE_TYPES: ReadonlySet<LLMErrorType>","type: LLMErrorType","code: LLMErrorCode | undefined","issues: unknown","body: unknown","headers: Record<string, string> | undefined","out: Record<string, string>","attempts: RetryAttempt[] | undefined","provider: string","model: string","headers?: Record<string, string>","startedAt: number","message: string","options: LLMErrorOptions","err: unknown","err: LLMError","code: C","key: string","value: T","ttl: number","inner: CacheAdapter<T>","l1: CacheAdapter<T>","l2: CacheAdapter<T>","l1Ttl?: number","tool: ToolDefinition<Name, Args>","result: R","defaultFallbackOn: FallbackOn","attempts: FallbackAttempt[]","err: unknown","params: UsageHooks","coalesced: boolean","signal: AbortSignal | undefined","onRefundError: (logMessage: string, error: unknown) => void","logMessage: string","getResult: () => Promise<T>","result: T","openStream: () => Promise<{ chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> }>","opened: { chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> }","value: unknown","value: T | CallWithToolsResult<T>","hasTools: boolean","items: StreamChunk[]","promise: Promise<T | CallWithToolsResult<T>>","cache: CacheAdapter<unknown>","logger: Logger","key: string","logMessage: string","error: unknown","params: InternalCacheParams<T>","params: InternalCacheStreamParams<T>","hasTools: boolean","resolveInFlight!: (value: T) => void","rejectInFlight!: (error: unknown) => void","trackedResult: Promise<T>","options: CircuitBreakerOptions","model: string | undefined","bucket: CircuitBucket","to: CircuitState","model?: string","onEvent: ((event: VernLLMEvent) => void) | undefined","logger: Logger","circuitBreakerOption: boolean | CircuitBreakerOptions | undefined","providerName: string","defaultModel: string","ms: number | undefined","ms: number","fn: (signal: AbortSignal) => Promise<T>","timeoutMs: number","externalSignal?: AbortSignal","next: () => Promise<IteratorResult<T>>","timeoutMs: number | undefined","onIdle?: () => void","logger?: Pick<Logger, 'debug'>","error: unknown","err: unknown","baseDelayMs: number","attempt: number","delay: number","signal?: AbortSignal","err: unknown","error: unknown","value: unknown","status: number","value: object","signal?: AbortSignal","attempts?: RetryAttempt[]","content: string","tools: ToolDefinition[]","toolCalls: ToolCall[]","wireToolCalls: WireToolCall[]","parsedArgs: unknown","content: AssistantContent","options: RequestBuilderOptions","params: CallParams<T>","history: ConversationTurn[]","previousTurn: ConversationTurn | undefined","toolChoice: CallParams<unknown>['toolChoice']","turn: ConversationTurn","jsonSchema: CallParams<unknown>['jsonSchema']","useJson: boolean","iterator: AsyncIterator<WireStreamChunk>","first: IteratorResult<WireStreamChunk>","options: StreamAccumulatorOptions<T>","resolveFinal!: (value: T | CallWithToolsResult<T>) => void","rejectFinal!: (error: unknown) => void","buffered: StreamChunk[]","pending: Array<{\n resolve: (result: IteratorResult<StreamChunk>) => void;\n reject: (error: unknown) => void;\n }>","streamError: unknown","chunk: StreamChunk","error: unknown","chunks: AsyncIterable<StreamChunk>","usage: TokenUsage | undefined","result: IteratorResult<WireStreamChunk>","wireToolCalls: WireToolCall[] | undefined","snapshot: LLMRequestSnapshot | undefined","providerName: string","client: LLMClient","model: string","options: CallExecutorOptions","model?: string","params: CallParams<T>","requestId: string","onAttempt?: () => void","attempts: RetryAttempt[]","attempt: number","onRequest?: OnRequest","release: ((actualTokens?: number) => void) | undefined","text: string","content: string | undefined","wireToolCalls: WireToolCall[] | undefined","rawContent: string | null | undefined","useJson: boolean","usage: TokenUsage | undefined","toolCalls: { id: string; name: string; arguments: unknown }[]","tools: NonNullable<CallParams<unknown>['tools']>","toolIssues: ToolIssue[]","fn: (attempt: number, onRequest: OnRequest) => Promise<T>","signal?: AbortSignal","attempts?: RetryAttempt[]","lastError: unknown","lastRequestForAttempt: LLMRequestSnapshot | undefined","response: Awaited<ReturnType<LLMClient['chat']['completions']['create']>>","usage: TokenUsage","error: LLMError","content: string","schema?: CallParams<T>['schema']","parsed: unknown","error: unknown","logger: Logger","method: M","value: unknown","result: unknown","debugEnabled: boolean","message: string","meta?: Record<string, unknown>","request: WireRequest","capacity: number","refillPerMs: number","amount: number","options: RateLimitOptions","estimatedTokens: number","signal?: AbortSignal","initialReason: RateLimitReason | undefined","waiter: Waiter","queueTimer: ReturnType<typeof setTimeout> | undefined","taken: Array<{ bucket: TokenBucket; amount: number }>","bucket: TokenBucket | undefined","reason: RateLimitReason","actualTokens?: number","options: VernLLMOptions","primaryTarget: FallbackTarget","declaredFallbacks: FallbackTarget[]","logMessage: string","error: unknown","params: Pick<CallParams<unknown>, 'model' | 'signal'>","requestId: string","attempt: (executor: CallExecutor, onAttempt: () => void) => Promise<R>","attempts: FallbackAttempt[]","params: CallParams<T>","params: InternalCacheParams<T>","key: string","params:\n | CachedCallParams<T>\n | CachedToolCallParams<T>\n | CachedConditionalToolCallParams<T>\n | CachedStreamCallParams<T>\n | CachedStreamToolCallParams<T>\n | CachedStreamConditionalToolCallParams<T>\n | CachedJsonModeDisabledCallParams\n | CachedJsonModeEnabledCallParams\n | CachedStreamJsonModeDisabledCallParams\n | CachedStreamJsonModeEnabledCallParams","target?: CircuitTarget","model?: string","index: number","caller: string","isolateByModel: boolean","model: string | undefined","params: P","source: AsyncIterable<Uint8Array | string>","text: string","boundary","frame: string","dataLines: string[]","mimeType: string","model: string","override?: ModelCapabilityOverride","DEFAULT_EFFORT_TOKENS: EffortTokenTable","override?: Partial<EffortTokenTable>","effort: 'minimal' | 'low' | 'medium' | 'high'","table: EffortTokenTable","budgetTokens: number","model: string","override?: ModelCapabilityOverride","maxTokens: number","forcedChoiceDescription: string | undefined","level: GeminiThinkingLevel","blocks: ContentBlock[]","schema: Record<string, unknown>","toolName: string","toolChoice: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice']","tools: NonNullable<Parameters<LLMClient['chat']['completions']['create']>[0]['tools']>","toolChoiceParam: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice']","params: Parameters<LLMClient['chat']['completions']['create']>[0]","nativeStructuredOutputModels?: ModelCapabilityOverride","effortTokenTable?: EffortTokenTable","adaptiveOnlyModels?: ModelCapabilityOverride","toolName: string | undefined","outputFormat: NonNullable<AnthropicRequestBody['output_config']>['format'] | undefined","tools: NonNullable<Parameters<AnthropicClient['messages']['create']>[0]['tools']> | undefined","toolChoice: Parameters<AnthropicClient['messages']['create']>[0]['tool_choice']","thinking: AnthropicRequestBody['thinking']","effort: ClaudeAdaptiveEffort | undefined","body: AnthropicRequestBody","anthropicClient: AnthropicClient","options?: AnthropicAdapterOptions","options","text: string","wireToolCalls: WireToolCall[] | undefined","mergeConsecutiveToolResults","messages: { role: 'user' | 'assistant'; content: string | AnthropicContentBlock[] }[]","m: (typeof messages)[number]","merged: (typeof messages)[number][]","m: Extract<\n Parameters<LLMClient['chat']['completions']['create']>[0]['messages'][number],\n { role: 'user' | 'assistant' | 'tool' }\n >","blocks: AnthropicContentBlock[]","input: unknown","blocks: ContentBlock[]","name: string","occurrenceIndex: number","toolChoice: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice']","messages: Parameters<LLMClient['chat']['completions']['create']>[0]['messages']","m: Extract<\n Parameters<LLMClient['chat']['completions']['create']>[0]['messages'][number],\n { role: 'user' | 'assistant' | 'tool' }\n >","toolCallNames: Map<string, string>","parts: GeminiPart[]","text: string","toolName: string","parsed: unknown","contents: { role: 'user' | 'model'; parts: GeminiPart[] }[]","c: (typeof contents)[number]","merged: (typeof contents)[number][]","params: Parameters<LLMClient['chat']['completions']['create']>[0]","effortTokenTable?: EffortTokenTable","thinkingLevelModels?: ModelCapabilityOverride","config: GeminiConfig","client: GeminiClient","options?: GeminiAdapterOptions","options","wireToolCalls: WireToolCall[] | undefined","lastUsage:\n | NonNullable<\n Awaited<ReturnType<NonNullable<GeminiClient['generateContent']>>>['usageMetadata']\n >\n | undefined","model: string","mimeType: string","data: string","blocks: ContentBlock[]","tools: NonNullable<Parameters<LLMClient['chat']['completions']['create']>[0]['tools']>","toolChoiceParam: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice']","params: Parameters<LLMClient['chat']['completions']['create']>[0]","toolUseSupportedModels: BedrockAdapterOptions['toolUseSupportedModels']","nativeStructuredOutputModels: BedrockAdapterOptions['nativeStructuredOutputModels']","effortTokenTable?: EffortTokenTable","adaptiveOnlyModels?: ModelCapabilityOverride","toolName: string | undefined","toolConfig: NonNullable<BedrockRequest['toolConfig']> | undefined","outputConfig: NonNullable<BedrockRequest['outputConfig']> | undefined","additionalModelRequestFields: BedrockRequest['additionalModelRequestFields']","effort: ClaudeAdaptiveEffort | undefined","request: BedrockRequest","client: BedrockConverseClient | AwsSendClient","raw: RawBedrockStreamEvent","rawStream: AsyncIterable<RawBedrockStreamEvent>","client: AwsSendClient","commandsPromise: Promise<BedrockRuntimeCommands> | undefined","bedrockClient: BedrockConverseClient | AwsSendClient","options?: BedrockAdapterOptions","client: BedrockConverseClient","text: string","wireToolCalls: WireToolCall[] | undefined","toolChoice: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice']","m: Extract<\n Parameters<LLMClient['chat']['completions']['create']>[0]['messages'][number],\n { role: 'user' | 'assistant' | 'tool' }\n >","blocks: BedrockContentBlock[]","input: unknown","messages: { role: 'user' | 'assistant'; content: BedrockContentBlock[] }[]","m: (typeof messages)[number]","merged: (typeof messages)[number][]","stream: ReadableStream<Uint8Array>","url: string","init: { method: string; headers: Record<string, string>; body?: string; signal?: AbortSignal }","config: FetchAdapterConfig","params: ChatRequest","requestBody: unknown","wireToolCalls: WireToolCall[] | undefined","params: P","effortTokenTable?: EffortTokenTable","blocks: ContentBlock[]","params: Parameters<LLMClient['chat']['completions']['create']>[0]","chunk: OpenAIStreamChunk","client: unknown","options: OpenAICompatibleAdapterOptions","options"],"sources":["../src/types/errors.ts","../src/types/cache.ts","../src/types/tools.ts","../src/types/fallback.ts","../src/internal/execution/usage.utils.ts","../src/internal/cache/replay.utils.ts","../src/internal/cache/cacheOrchestrator.ts","../src/circuitBreaker.ts","../src/internal/circuitBreaker.utils.ts","../src/internal/execution/retry.utils.ts","../src/internal/execution/errors.utils.ts","../src/internal/execution/parse.utils.ts","../src/internal/execution/wire.utils.ts","../src/internal/execution/requestBuilder.ts","../src/internal/execution/streamAccumulator.ts","../src/internal/execution/callExecutor.ts","../src/internal/logger.utils.ts","../src/logger.ts","../src/rateLimit.ts","../src/vernLLM.ts","../src/adapters/internal/sse.ts","../src/adapters/internal/imageFormat.ts","../src/adapters/internal/nativeStructuredOutput.ts","../src/adapters/internal/reasoningBudget.utils.ts","../src/adapters/anthropic.ts","../src/adapters/gemini.ts","../src/adapters/bedrock.ts","../src/adapters/fetch.ts","../src/adapters/openaiCompatible.ts"],"sourcesContent":["export type LLMErrorType =\n | 'timeout'\n | 'api'\n | 'network'\n | 'parse'\n | 'validation'\n | 'invalid_params'\n | 'rate_limited'\n | 'quota_exceeded'\n | 'circuit_open'\n | 'fallback_exhausted'\n | 'aborted'\n | 'unknown';\n\n/**\n * Machine readable discriminator within a `type`, for cases where `type`\n * alone is too coarse to act on. Optional and additive: errors thrown\n * before a given code existed simply omit it. Not owned by a single type;\n * e.g. `authentication`/`authorization` apply the same way regardless of\n * which type wraps them.\n */\nexport type LLMErrorCode =\n // Tool contract (validation)\n | 'unknown_tool'\n | 'duplicate_tool_call_id'\n | 'tool_choice_none_violated'\n | 'unexpected_tool_calls'\n // Caller input (invalid_params)\n | 'unsupported_capability'\n | 'duplicate_tool_names'\n | 'unknown_tool_choice'\n | 'duplicate_tool_result_ids'\n | 'unknown_tool_result_ids'\n | 'missing_tool_results'\n // Rate limiting (rate_limited)\n | 'rate_limit_queue_full'\n | 'rate_limit_queue_timeout'\n | 'rate_limit_capacity_exceeded'\n | 'provider_rate_limited'\n // Timeouts (timeout)\n | 'request_timeout'\n | 'idle_timeout'\n // HTTP status (api)\n | 'authentication'\n | 'authorization'\n | 'not_found'\n | 'payload_too_large'\n | 'server_error'\n | 'empty_response'\n // Connectivity (network)\n | 'connection_failed'\n // Circuit breaker (circuit_open)\n | 'circuit_cooling_down'\n | 'circuit_trial_in_flight'\n // Fallback (fallback_exhausted)\n | 'fallback_exhausted'\n // Parsing (parse)\n | 'tool_arguments_parse_failed'\n | 'stream_frame_invalid';\n\n/**\n * Tool contract codes: a model or provider response defect, not a\n * transient provider fault. Deterministic on the wire request, so\n * retrying can't change the outcome and it shouldn't count toward the\n * circuit breaker either. Shared by `LLMError.retryable` below and by\n * `CallExecutor`'s own retry/breaker accounting, so the two can't drift\n * apart.\n */\nexport const NON_RETRYABLE_TOOL_CONTRACT_CODES: ReadonlySet<LLMErrorCode> = new Set([\n 'unknown_tool',\n 'duplicate_tool_call_id',\n 'tool_choice_none_violated',\n 'unexpected_tool_calls',\n]);\n\n/**\n * Local rate-limit codes: the call never reached the provider, so it says\n * nothing about the provider's health, and retrying either just requeues\n * behind the same limit (the two queue codes) or can never succeed at all\n * (`rate_limit_capacity_exceeded`). Shared for the same reason as\n * {@link NON_RETRYABLE_TOOL_CONTRACT_CODES}.\n */\nexport const LOCAL_RATE_LIMIT_CODES: ReadonlySet<LLMErrorCode> = new Set([\n 'rate_limit_queue_full',\n 'rate_limit_queue_timeout',\n 'rate_limit_capacity_exceeded',\n]);\n\n/**\n * Types that are never worth retrying on their own: deterministic\n * caller-input, model-response, or cancellation failures rather than a\n * transient provider fault.\n */\nconst NON_RETRYABLE_TYPES: ReadonlySet<LLMErrorType> = new Set([\n 'parse',\n 'validation',\n 'invalid_params',\n 'aborted',\n]);\n\n/**\n * Shared retryability rule behind both `LLMError.retryable` and\n * `LLMErrorSnapshot.retryable`. Pulled out so the two can't drift apart:\n * a snapshot is a point-in-time copy of an error's fields, and this is\n * one of them, so it has to be computed the same way in both places.\n */\nfunction computeRetryable(type: LLMErrorType, code: LLMErrorCode | undefined): boolean {\n if (NON_RETRYABLE_TYPES.has(type)) return false;\n if (code && NON_RETRYABLE_TOOL_CONTRACT_CODES.has(code)) return false;\n if (code && LOCAL_RATE_LIMIT_CODES.has(code)) return false;\n return true;\n}\n\n/**\n * Returns `issues` unchanged when it can survive `JSON.stringify`.\n * Most `issues` values are VernLLM's own structured shapes (see\n * `LLMErrorIssuesByCode`) and always safe. The one exception is a\n * schema validation failure, where `issues` is a caller supplied\n * `SchemaLike` validator's own `error: unknown`, not controlled by\n * VernLLM and not guaranteed to be circular free. Rather than silently\n * dropping it in that case, this returns a marker string so a reader\n * of serialized output can tell \"no issues data\" apart from \"issues\n * existed but could not be shown\".\n */\nfunction safeIssues(issues: unknown): unknown {\n if (issues === undefined) return undefined;\n try {\n JSON.stringify(issues);\n return issues;\n } catch {\n return '[Unserializable: issues contained a circular reference]';\n }\n}\n\n/**\n * Returns a JSON safe, independent copy of `body`, or a marker string if\n * `body` can't survive `JSON.stringify` (e.g. a circular reference). A\n * request body built from adapter-transformed messages is normally\n * always plain data, but tool call arguments or a caller supplied\n * `cause`-adjacent value could in principle carry a circular reference,\n * so this guards the same way `safeIssues` does rather than assuming it\n * can't happen. Unlike `safeIssues`, this clones rather than returning\n * the same reference: the object backing a request body can still be\n * mutated by adapter code between when a request is dispatched and when\n * an attempt is later recorded as failed (e.g. `fromGemini` sets\n * `request.config` in place), so returning the same reference here could\n * make a stored snapshot silently reflect a later, different state than\n * what was actually sent.\n */\nfunction safeBody(body: unknown): unknown {\n if (body === undefined) return undefined;\n try {\n return JSON.parse(JSON.stringify(body)) as unknown;\n } catch {\n return '[Unserializable: request body contained a circular reference]';\n }\n}\n\nconst AUTH_HEADER_NAMES = new Set(['authorization', 'x-api-key', 'x-goog-api-key', 'api-key']);\n\n/** Removes auth headers before a request snapshot is built. Case insensitive on header names. */\nfunction stripAuthHeaders(\n headers: Record<string, string> | undefined,\n): Record<string, string> | undefined {\n if (headers === undefined) return undefined;\n const out: Record<string, string> = {};\n for (const [key, value] of Object.entries(headers)) {\n if (!AUTH_HEADER_NAMES.has(key.toLowerCase())) out[key] = value;\n }\n return out;\n}\n\n/**\n * Depth cap for `safeAttempts`, guarding against a pathological,\n * self referential `attempts` array. `attempts` is a public\n * `LLMErrorOptions` field, so a caller can construct one by hand; this\n * keeps that path bounded the same way a circular `issues` value is\n * bounded, rather than assuming well formed input.\n */\nconst MAX_ATTEMPTS_DEPTH = 20;\n\n/**\n * Returns a copy of `attempts` with every nested snapshot's `issues`\n * re-checked through `safeIssues`, recursively through each snapshot's\n * own `attempts`. Needed for two reasons: `safeIssues` returns a safe\n * `issues` value by reference, so a shared object can be mutated into a\n * circular one after the snapshot was created, and `attempts` is a\n * public constructor option, so a caller can hand build a `RetryAttempt`\n * (or a whole `LLMErrorSnapshot`) with a circular `issues` and pass it\n * in directly, never touching `toSnapshot()` at all. The same applies to\n * `request`: its `body` is re-checked through `safeBody`, and its\n * `headers` are re-stripped through `stripAuthHeaders`, so a hand built\n * `RetryAttempt.request` can't smuggle an auth header past `toSnapshot()`\n * either. Extra fields on an attempt (e.g. `FallbackAttempt`'s\n * `provider`/`model`) are preserved.\n */\nfunction safeAttempts(attempts: RetryAttempt[] | undefined, depth = 0): RetryAttempt[] | undefined {\n if (attempts === undefined) return undefined;\n if (depth >= MAX_ATTEMPTS_DEPTH) return [];\n\n return attempts.map((attempt) => ({\n ...attempt,\n error: {\n ...attempt.error,\n issues: safeIssues(attempt.error.issues),\n attempts: safeAttempts(attempt.error.attempts, depth + 1),\n },\n request: attempt.request && {\n ...attempt.request,\n body: safeBody(attempt.request.body),\n headers: stripAuthHeaders(attempt.request.headers),\n },\n }));\n}\n\n/** One tool call's contract failure, used to report every bad call in a response at once. */\nexport interface ToolIssue {\n name: string;\n toolCallId: string;\n code: LLMErrorCode;\n detail?: unknown;\n}\n\n/**\n * The specific values behind a `duplicate_tool_names` failure: the\n * offending call's `tools` array had more than one entry sharing a name.\n */\nexport interface DuplicateToolNamesIssue {\n names: string[];\n}\n\n/**\n * The specific values behind an `unknown_tool_choice` failure: `toolChoice`\n * named a tool that wasn't in the call's own `tools` array.\n */\nexport interface UnknownToolChoiceIssue {\n requested: string;\n available: string[];\n}\n\n/**\n * The specific values behind a `duplicate_tool_result_ids` /\n * `unknown_tool_result_ids` / `missing_tool_results` failure: which\n * `history` turn was affected, and which `toolCallId`s were the problem.\n */\nexport interface HistoryToolResultIssue {\n historyIndex: number;\n ids: string[];\n}\n\n/**\n * The specific values behind an `unsupported_capability` failure: which\n * capability the current adapter/client/model doesn't support.\n */\nexport interface UnsupportedCapabilityIssue {\n capability: string;\n}\n\n/**\n * Maps each `LLMErrorCode` that carries structured `issues` to that\n * payload's exact shape. Not every code appears here: most `invalid_params`\n * failures are a single deterministic fact the `message` already states in\n * full, so adding a typed `issues` entry for them would only duplicate the\n * message into a field, the same near-duplicate-code problem `code` itself\n * avoids. Codes that repeat here are exactly the ones whose `message`\n * already string-joins a list a caller might want to consume directly\n * rather than re-parse out of prose, or that otherwise want a place to\n * report the exact captured values of a failure.\n *\n * Deliberately not a mapped type over the whole `LLMErrorCode` union: a\n * schema-validation failure's `issues` (the caller's own Zod-compatible\n * validator's error object) has no code and no shape VernLLM could know in\n * advance, so it stays untyped on `LLMError.issues` itself rather than\n * forcing every code into this table.\n */\nexport interface LLMErrorIssuesByCode {\n unknown_tool: ToolIssue[];\n duplicate_tool_call_id: ToolIssue[];\n duplicate_tool_names: DuplicateToolNamesIssue;\n unknown_tool_choice: UnknownToolChoiceIssue;\n duplicate_tool_result_ids: HistoryToolResultIssue;\n unknown_tool_result_ids: HistoryToolResultIssue;\n missing_tool_results: HistoryToolResultIssue;\n unsupported_capability: UnsupportedCapabilityIssue;\n}\n\n/**\n * Point-in-time copy of an `LLMError`'s fields, produced by\n * `LLMError.toSnapshot()`. This is what `RetryAttempt.error` holds\n * instead of a live `LLMError`.\n *\n * A past attempt only needs to be describable (message, type, code,\n * whether it was retryable), never thrown again. So it skips `Error`'s\n * behavior, `instanceof` identity, and any live getter. Using the full\n * `LLMError` class here would also make the type self referential\n * through its own `attempts` field.\n *\n * Has no `cause`. `cause` is `unknown` and never validated by VernLLM,\n * and it is meant to be read directly on the live error you just\n * caught, not carried indefinitely inside history. `type`, `code`,\n * `status`, and `issues` are the structured fields a snapshot carries\n * instead.\n *\n * `attempts` is still present, since a recorded attempt can itself be\n * the terminal failure of an inner retry loop with its own history (see\n * `FallbackAttempt`). That's a tree of past data, not a cycle.\n */\nexport interface LLMErrorSnapshot {\n message: string;\n type: LLMErrorType;\n status?: number;\n issues?: unknown;\n retryAfterMs?: number;\n code?: LLMErrorCode;\n /** Computed once, at snapshot time, since a snapshot has no live getter. */\n retryable: boolean;\n /** This attempt's own prior attempts, if it was itself the terminal failure of a retry loop. */\n attempts?: RetryAttempt[];\n}\n\n/**\n * Point-in-time copy of the request an attempt sent, produced by\n * `toRequestSnapshot()`. This is what `RetryAttempt.request` holds.\n * Mirrors `LLMErrorSnapshot`: plain data, never thrown or dispatched\n * again, safe to serialize and store.\n */\nexport interface LLMRequestSnapshot {\n /** Provider id this attempt targeted, e.g. \"openai\". */\n provider: string;\n /** Model id this attempt targeted. */\n model: string;\n /** The payload as actually sent for this attempt, after any transform/repair. Passed through `safeBody`. */\n body: unknown;\n /** Non sensitive request headers. Auth headers are stripped before the snapshot is built, never included. */\n headers?: Record<string, string>;\n /** Wall clock time the attempt started, ms since epoch. */\n startedAt: number;\n}\n\n/**\n * Builds a point-in-time, plain data copy of one attempt's outgoing\n * request. Mirrors `LLMError.toSnapshot()`: never thrown or dispatched\n * again, safe to serialize and store. A plain function rather than a\n * method, since unlike `LLMError` a request has no throwable identity or\n * derived state worth wrapping in a class.\n *\n * `startedAt` is optional so existing call sites (and tests) that don't\n * care about exact timing keep working, but a caller that has a real\n * capture time should always pass it: this function may run well after\n * the request was actually dispatched (e.g. `callExecutor` only builds\n * the snapshot once an attempt has failed), so defaulting to `Date.now()`\n * here would record failure-handling time, not request-start time.\n */\nexport function toRequestSnapshot(\n provider: string,\n model: string,\n body: unknown,\n headers?: Record<string, string>,\n startedAt: number = Date.now(),\n): LLMRequestSnapshot {\n return {\n provider,\n model,\n body: safeBody(body),\n headers: stripAuthHeaders(headers),\n startedAt,\n };\n}\n\n/**\n * One failed attempt on the way to a terminal error: which attempt index\n * it was, and a snapshot of the error it failed with. The base shape\n * every richer attempt record (e.g. `FallbackAttempt`) extends, rather\n * than duplicates.\n */\nexport interface RetryAttempt {\n index: number;\n error: LLMErrorSnapshot;\n /** What was sent for this attempt. Optional: absent for attempts predating this field. */\n request?: LLMRequestSnapshot;\n}\n\n/** Optional fields for constructing an {@link LLMError}. `message` and `type` stay positional since every throw site sets both. */\nexport interface LLMErrorOptions {\n status?: number;\n issues?: unknown;\n cause?: unknown;\n retryAfterMs?: number;\n /** Stable discriminator within `type`. Absent on errors predating it. */\n code?: LLMErrorCode;\n /** Every attempt made before this error was thrown, in order. Absent when nothing was retried. */\n attempts?: RetryAttempt[];\n}\n\nexport class LLMError extends Error {\n public status?: number;\n public issues?: unknown;\n public cause?: unknown;\n public retryAfterMs?: number;\n /** Stable discriminator within `type`. Absent on errors predating it. */\n public code?: LLMErrorCode;\n /** Every attempt made before this error was thrown, in order. Absent when nothing was retried. */\n public attempts?: RetryAttempt[];\n\n constructor(\n message: string,\n public type: LLMErrorType,\n options: LLMErrorOptions = {},\n ) {\n super(message);\n this.name = 'LLMError';\n this.status = options.status;\n this.issues = options.issues;\n this.cause = options.cause;\n this.retryAfterMs = options.retryAfterMs;\n this.code = options.code;\n this.attempts = options.attempts;\n }\n\n /**\n * Computed purely from `type`/`code`, independent of any specific call's\n * `nonRetryableStatus` list. False for `parse`/`validation`/\n * `invalid_params`/`aborted` types (the caller's own input, the model's\n * own response, or intentional cancellation, none of which are the\n * provider being unhealthy), the tool contract codes, and the local\n * rate limit codes. Subclasses (see `FallbackExhaustedError`) may\n * override this when `type` alone carries no retry signal.\n */\n get retryable(): boolean {\n return computeRetryable(this.type, this.code);\n }\n\n /**\n * Copies this error's fields into an {@link LLMErrorSnapshot}, for\n * recording as a `RetryAttempt`/`FallbackAttempt`. `retryable` is\n * captured here since a snapshot has no getter of its own. `cause` is\n * not copied, see `LLMErrorSnapshot`'s own doc. `issues` and every\n * nested `attempts` entry's own `issues` go through `safeAttempts`,\n * since a schema validation failure's `issues` is a caller supplied\n * value, not controlled by VernLLM, and `attempts` is itself a public\n * constructor option a caller can hand build.\n */\n toSnapshot(): LLMErrorSnapshot {\n return {\n message: this.message,\n type: this.type,\n status: this.status,\n issues: safeIssues(this.issues),\n retryAfterMs: this.retryAfterMs,\n code: this.code,\n retryable: this.retryable,\n attempts: safeAttempts(this.attempts),\n };\n }\n\n /**\n * Controls what `JSON.stringify(err)` produces. Omits `cause` for the\n * same reason `toSnapshot()` does: `cause` is `unknown` and never\n * validated by VernLLM, and some SDK errors carry circular structures\n * `JSON.stringify` cannot serialize at all. Read `err.cause` directly\n * instead. `issues`, including every nested `attempts` entry's own\n * `issues`, goes through `safeAttempts` for the same reason: a schema\n * validation failure's `issues` is caller supplied and not guaranteed\n * circular free. Also includes `message` and `retryable`, which a\n * plain property walk would otherwise miss: `message` is\n * non-enumerable on `Error`, and `retryable` is a getter, not an own\n * property.\n */\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n type: this.type,\n status: this.status,\n issues: safeIssues(this.issues),\n retryAfterMs: this.retryAfterMs,\n code: this.code,\n retryable: this.retryable,\n attempts: safeAttempts(this.attempts),\n };\n }\n}\n\nexport function isLLMError(err: unknown): err is LLMError {\n return err instanceof LLMError;\n}\n\n/**\n * Narrows `err.issues` to the exact shape {@link LLMErrorIssuesByCode} maps\n * `code` to, for any code listed there. `code` stays the only discriminator\n * VernLLM uses; this just gives that existing check a typed return instead\n * of requiring a manual cast of `issues`:\n *\n * ```ts\n * if (isLLMError(err) && hasIssues(err, 'duplicate_tool_names')) {\n * console.log(err.issues.names); // string[], no cast needed\n * }\n * ```\n */\nexport function hasIssues<C extends keyof LLMErrorIssuesByCode>(\n err: LLMError,\n code: C,\n): err is LLMError & { code: C; issues: LLMErrorIssuesByCode[C] } {\n return err.code === code && err.issues !== undefined;\n}\n","export interface CacheAdapter<T = unknown> {\n get(key: string): Promise<{ hit: boolean; value: T | null }>;\n set(key: string, value: T, ttl: number): Promise<void>;\n delete?(key: string): Promise<void>;\n resolveKey?(key: string): Promise<string>;\n}\n\n/**\n * Trivial default so the package works out of the box with no external deps\n * Not shared across processes, swap in Redis/Upstash/etc for production\n */\nexport class InMemoryCacheAdapter<T = unknown> implements CacheAdapter<T> {\n private store = new Map<string, { value: T; expiresAt: number }>();\n\n constructor(private readonly maxSize = 1000) {}\n\n async get(key: string): Promise<{ hit: boolean; value: T | null }> {\n const entry = this.store.get(key);\n\n if (!entry) return { hit: false, value: null };\n\n if (Date.now() >= entry.expiresAt) {\n this.store.delete(key);\n return { hit: false, value: null };\n }\n\n return { hit: true, value: entry.value };\n }\n\n async set(key: string, value: T, ttl: number): Promise<void> {\n this.cleanupExpiredEntries();\n\n this.store.set(key, {\n value,\n expiresAt: Date.now() + ttl * 1000,\n });\n\n this.enforceSizeLimit();\n }\n\n async delete(key: string): Promise<void> {\n this.store.delete(key);\n }\n\n private cleanupExpiredEntries(): void {\n const now = Date.now();\n\n for (const [key, entry] of this.store) {\n if (now >= entry.expiresAt) {\n this.store.delete(key);\n }\n }\n }\n\n private enforceSizeLimit(): void {\n while (this.store.size > this.maxSize) {\n const oldestKey = this.store.keys().next().value;\n\n if (oldestKey === undefined) break;\n\n this.store.delete(oldestKey);\n }\n }\n}\n\n/**\n * Normalizes keys before caching to avoid duplicate entries from formatting differences.\n */\nexport class NormalizedCacheAdapter<T = unknown> implements CacheAdapter<T> {\n constructor(private readonly inner: CacheAdapter<T> = new InMemoryCacheAdapter<T>()) {}\n\n private normalize(key: string): string {\n return key\n .toLowerCase()\n .trim()\n .replace(/[^\\p{L}\\p{N}\\s]/gu, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n }\n\n async resolveKey(key: string): Promise<string> {\n return this.normalize(key);\n }\n\n async get(key: string): Promise<{ hit: boolean; value: T | null }> {\n return this.inner.get(this.normalize(key));\n }\n\n async set(key: string, value: T, ttl: number): Promise<void> {\n await this.inner.set(this.normalize(key), value, ttl);\n }\n\n async delete(key: string): Promise<void> {\n await this.inner.delete?.(this.normalize(key));\n }\n}\n\n/**\n * Two-tier cache with fast local L1 and shared L2.\n * L2 hits are promoted back to L1.\n */\nexport class TieredCacheAdapter<T = unknown> implements CacheAdapter<T> {\n constructor(\n private readonly l1: CacheAdapter<T>,\n private readonly l2: CacheAdapter<T>,\n private readonly l1Ttl?: number,\n ) {}\n\n /**\n * Forwards to L1's `resolveKey` if it has one, otherwise L2's. L1 is\n * preferred since `get()` checks L1 first, so its notion of \"the same\n * key\" is the one that determines whether a lookup can skip L2 entirely.\n */\n async resolveKey(key: string): Promise<string> {\n if (this.l1.resolveKey) return this.l1.resolveKey(key);\n if (this.l2.resolveKey) return this.l2.resolveKey(key);\n return key;\n }\n\n async get(key: string): Promise<{ hit: boolean; value: T | null }> {\n const l1Result = await this.l1.get(key);\n if (l1Result.hit) return l1Result;\n\n const l2Result = await this.l2.get(key);\n\n if (l2Result.hit) {\n await this.l1.set(key, l2Result.value as T, this.l1Ttl ?? 60);\n }\n\n return l2Result;\n }\n\n async set(key: string, value: T, ttl: number): Promise<void> {\n await Promise.all([this.l1.set(key, value, this.l1Ttl ?? ttl), this.l2.set(key, value, ttl)]);\n }\n\n async delete(key: string): Promise<void> {\n await Promise.all([this.l1.delete?.(key), this.l2.delete?.(key)]);\n }\n}\n","import type { SchemaLike } from './schema.js';\n\n/**\n * Describes a capability the model may request, not the capability\n * itself. VernLLM transports this to the provider and parses what comes\n * back; it never executes anything.\n */\nexport interface ToolDefinition<Name extends string = string, Args = unknown> {\n name: Name;\n description: string;\n /** JSON Schema for the tool's input. */\n parameters: Record<string, unknown>;\n /**\n * Optional client-side validator run on the parsed `arguments` before\n * they're handed back to the caller, mirroring the `schema: SchemaLike<T>`\n * pattern already used for response validation (see `types/schema.ts`).\n * Reuses that zero-dependency, `safeParse`-compatible shape instead of\n * requiring a JSON Schema validator (e.g. ajv) as a new dependency.\n * Failed validation throws `LLMError('validation')`. If omitted, VernLLM\n * parses arguments as JSON but does not validate them further.\n *\n * When set, `Args` (and therefore `Name`) flow into the `ToolCall`s\n * returned by `call()`/`cachedCall()`, provided the tool was declared\n * with `defineTool()` or otherwise has a literal `name`; see\n * `defineTool()` below for why a plain object literal often doesn't.\n */\n argumentsSchema?: SchemaLike<Args>;\n}\n\n/**\n * Preserves a tool definition's literal `name` (and its `argumentsSchema`'s\n * inferred `Args`) so it can discriminate a `ToolCall` union later.\n *\n * A plain object literal like `{ name: 'get_weather', ... }` widens `name`\n * to `string` unless annotated `as const`, which silently defeats\n * `ToolCall` narrowing the moment a second tool is added to the same\n * `tools: [...]` array (single-tool arrays still narrow fine even without\n * this, since there's nothing to discriminate against — but that stops\n * being true as soon as a second tool shows up). Wrapping the same object\n * in `defineTool()` preserves the literal `name` type without requiring\n * `as const` at every call site.\n */\nexport function defineTool<const Name extends string, Args = unknown>(\n tool: ToolDefinition<Name, Args>,\n): ToolDefinition<Name, Args> {\n return tool;\n}\n\n/** Maps a single `ToolDefinition` to its matching `ToolCall` shape. */\ntype ToolCallFor<T> =\n T extends ToolDefinition<infer N, infer A> ? { id: string; name: N; arguments: A } : never;\n\n/**\n * A single tool invocation requested by the model.\n *\n * When `Tools` is a literal tuple (e.g. inferred from `tools: [getWeather,\n * cancelOrder]` at a `call()`/`cachedCall()` site), this is a discriminated\n * union keyed by `name` — checking `call.name === 'get_weather'` narrows\n * `call.arguments` to that tool's `Args` with no cast needed. Without a\n * literal `Tools` (the default), this collapses back to today's\n * `{ id: string; name: string; arguments: unknown }`.\n */\nexport type ToolCall<Tools extends readonly ToolDefinition[] = ToolDefinition[]> = ToolCallFor<\n Tools[number]\n>;\n\n/** The application's result of executing a `ToolCall`, sent back to the model. */\nexport interface ToolResult {\n toolCallId: string;\n content: unknown;\n /**\n * Signals a failed tool execution back to the model (matches Anthropic's\n * native `is_error` on tool_result blocks). Only `fromAnthropic` honors\n * this today, Gemini and Bedrock have no equivalent wire concept, so\n * other adapters ignore it silently.\n */\n isError?: boolean;\n}\n\n/** `call()` result when `tools` was set and the model produced a normal answer. */\nexport interface ContentResult<T> {\n type: 'content';\n content: T;\n}\n\n/** `call()` result when `tools` was set and the model requested one or more tools. */\nexport interface ToolCallResult<Tools extends readonly ToolDefinition[] = ToolDefinition[]> {\n type: 'tool_calls';\n toolCalls: ToolCall<Tools>[];\n /** Any text the model produced alongside the tool request, if present. */\n content?: string;\n}\n\nexport type CallWithToolsResult<T, Tools extends readonly ToolDefinition[] = ToolDefinition[]> =\n | ContentResult<T>\n | ToolCallResult<Tools>;\n\n/**\n * Pulls `Tools` out of a `result` value's own static type, when that type\n * is already `ContentResult<T> | ToolCallResult<Tools>` (or a superset\n * including it) rather than plain `unknown`. `Extract` isolates just the\n * `ToolCallResult<...>` member(s) of a union before inferring, so this\n * degrades to the default cleanly when `result` doesn't carry a\n * `ToolCallResult` shape at all (e.g. `unknown`, or a `call()` result that\n * TypeScript could only type as plain `T`, see `isToolCallResult`'s docs).\n */\ntype ExtractTools<R> =\n Extract<R, ToolCallResult<ToolDefinition[]>> extends ToolCallResult<infer Tools>\n ? Tools\n : ToolDefinition[];\n\n/**\n * Resolves the `Tools` `isToolCallResult` actually narrows with: the\n * explicit `Tools` type argument if one was given, otherwise whatever\n * `ExtractTools` can infer from `R` (the `result` argument's own type).\n * `Tools` defaults to `never` as an \"unset\" sentinel, not a real tools\n * list, so this can tell \"caller passed nothing\" apart from \"caller\n * genuinely passed `never`\" (which would be an unusual thing to write on\n * purpose, and isn't a meaningful `Tools` value regardless).\n */\ntype ResolvedTools<Tools, R> = [Tools] extends [never] ? ExtractTools<R> : Tools;\n\n/**\n * Runtime-safe check for whether a `call()` result is a `tool_calls`\n * result. Prefer this over relying on TypeScript's static narrowing\n * whenever `params` passed to `call()` wasn't a literal with `tools`\n * inlined (see the \"note on the overload\" in `VernLLM.call`'s docs), in\n * that case TS may have typed the result as plain `T` even though it's\n * actually a `CallWithToolsResult<T>` at runtime, and this check works\n * either way.\n *\n * Generic over `Tools`, same as `ToolCallResult` itself, so narrowing a\n * conditional-tools result (`tools: someCondition ? [myTool] : undefined`)\n * through this check doesn't erase the per-tool `arguments` typing that\n * `ConditionalToolCallParams` already captured. `Tools` is inferred\n * automatically from `result`'s own static type whenever that's already\n * `T | CallWithToolsResult<T, Tools>` (which it is whenever `call()`'s\n * overload resolution succeeded, the common case), no type argument\n * needed:\n *\n * ```ts\n * const tools = someCondition ? [myTool] : undefined;\n * const result = await llm.call({ userContent: '...', tools });\n * if (isToolCallResult(result)) {\n * // result.toolCalls[number].arguments is typed per tool, inferred\n * // automatically, not `unknown`\n * }\n * ```\n *\n * If `result`'s static type is plain `unknown` (or otherwise doesn't\n * carry `Tools`, e.g. a variable annotated `: CallParams<T>` upstream\n * widened it away, see the overload note), there's nothing to infer from\n * and this falls back to the default `ToolCallResult` with `arguments:\n * unknown`, same as before `isToolCallResult` became generic. Pass\n * `Tools` explicitly as the first type argument to override the inferred\n * (or defaulted) type in either case; the second type argument (`R`, the\n * `result` value's own type) is always inferred from the argument itself\n * and should not be set manually:\n *\n * ```ts\n * if (isToolCallResult<typeof tools>(result)) {\n * // arguments typed per tool via the explicit override\n * }\n * ```\n */\nexport function isToolCallResult<\n Tools extends readonly ToolDefinition[] | undefined = never,\n R = unknown,\n>(result: R): result is R & ToolCallResult<NonNullable<ResolvedTools<Tools, R>>> {\n return (\n typeof result === 'object' &&\n result !== null &&\n 'type' in result &&\n (result as { type: unknown }).type === 'tool_calls' &&\n Array.isArray((result as { toolCalls?: unknown }).toolCalls)\n );\n}\n\n/** What the model should do about tools on a given call. */\nexport type ToolChoice = 'auto' | 'none' | 'required' | { name: string };\n","import { LLMError, type RetryAttempt } from './errors.js';\n\nimport type { CircuitBreakerOptions, CircuitState } from '../circuitBreaker.js';\nimport type { RateLimitOptions } from '../rateLimit.js';\nimport type { LLMClient } from './client.js';\n\n/**\n * One provider to try after the primary (or after an earlier fallback\n * target) fails. Order is the policy: VernLLM never reorders, scores, or\n * selects a target, it only walks the list as given.\n *\n * Most per-target overrides fall back to the parent `VernLLM` instance's\n * own option when omitted, so a target only needs to specify what's\n * actually different about it (a different client/model is the common\n * case). `circuitBreaker` and `rateLimit` are the exception: they are\n * never inherited from the parent, since a breaker or limiter tuned for\n * the primary provider's limits is rarely right for a fallback's. Leave\n * them unset on a target to run it without one, even if the parent has\n * one configured.\n */\nexport interface FallbackTarget {\n client: LLMClient;\n model: string;\n /** Label for events, errors, and `TokenUsage.provider`. Default `` `fallback[${index}]` ``. */\n name?: string;\n\n maxRetries?: number;\n timeoutMs?: number;\n chunkIdleTimeoutMs?: number;\n baseDelayMs?: number;\n defaultMaxTokens?: number;\n defaultTemperature?: number | null;\n defaultReasoningEffort?: 'minimal' | 'low' | 'medium' | 'high';\n defaultBudgetTokens?: number;\n nonRetryableStatus?: number[];\n /** This target's own circuit breaker, independent of every other target's. Not inherited from the parent's `circuitBreaker`. */\n circuitBreaker?: boolean | CircuitBreakerOptions;\n /** This target's own rate limiter, independent of every other target's. Not inherited from the parent's `rateLimit`. */\n rateLimit?: RateLimitOptions;\n}\n\n/**\n * Written into `CallParams['meta']` once `call()` resolves, so a caller\n * who wants provider identity on the same line as the result doesn't need\n * to read it back out of `onUsage`.\n */\nexport interface CallMeta {\n provider: string;\n model: string;\n /** `-1` if the primary target answered, otherwise the index into `fallback`. */\n fallbackIndex: number;\n usedFallback: boolean;\n /** Attempts made against the target that ultimately answered, including the successful one. */\n attempts: number;\n}\n\n/** One target's circuit state, as returned by `VernLLM.getCircuitStates()`. */\nexport interface TargetCircuitState {\n provider: string;\n /** Position in the chain: `0` for the primary, `1`+ for fallback targets. */\n index: number;\n isFallback: boolean;\n /** Whether this target tracks failures per model. `false` means `model` on `getCircuitStates` had no effect on this entry. */\n isolateByModel: boolean;\n /** `undefined` if that target has no circuit breaker configured. */\n state: CircuitState | undefined;\n}\n\n/** Which target/model `VernLLM.getCircuitState`, `openCircuit`, and `closeCircuit` act on. */\nexport interface CircuitTarget {\n /** Which target to act on. `0` is the primary, `1`+ are fallbacks. Defaults to `0`. */\n index?: number;\n /** Which model bucket to act on, if the resolved target isolates by model. */\n model?: string;\n}\n\n/**\n * One target's failure, recorded on the way to either the next target or\n * `FallbackExhaustedError`. Extends `RetryAttempt`: `index` is `-1` for\n * the primary target here (rather than a plain retry count), and\n * `provider`/`model` identify which target failed.\n */\nexport interface FallbackAttempt extends RetryAttempt {\n provider: string;\n model: string;\n}\n\n/**\n * Decides what happens after a target's own retries are exhausted or\n * abandoned early. Called once per failed target. `'retry'` is not a\n * valid return here: retrying already happened inside the target, this\n * only decides whether to move on to the next one or stop.\n */\nexport type FallbackOn = (error: LLMError, context: { isLastTarget: boolean }) => 'next' | 'stop';\n\n/**\n * Tool contract failures where retrying elsewhere can't help: `unknown_tool`,\n * `tool_choice_none_violated`, and `unexpected_tool_calls` are the model\n * ignoring the request outright. `duplicate_tool_call_id` is different in\n * kind, once an adapter prefers a real provider-issued id and only\n * synthesizes a collision-free one when none is given, a duplicate means an\n * actual protocol violation (the provider reused an id it shouldn't have),\n * not the model misbehaving, but it's still not something a different\n * provider in the chain would be expected to reproduce or fix.\n */\nconst TOOL_CONTRACT_CODES = new Set([\n 'unknown_tool',\n 'duplicate_tool_call_id',\n 'tool_choice_none_violated',\n 'unexpected_tool_calls',\n]);\n\n/**\n * The default `fallbackOn` policy. Exported so a caller can wrap rather\n * than replace it, e.g. `fallbackOn: (e, ctx) => myCheck(e) ? 'stop' : defaultFallbackOn(e, ctx)`.\n */\nexport const defaultFallbackOn: FallbackOn = (error) => {\n if (error.type === 'parse' || error.type === 'validation' || error.type === 'aborted') {\n return 'stop';\n }\n\n if (error.type === 'quota_exceeded') return 'stop';\n\n if (error.code && TOOL_CONTRACT_CODES.has(error.code)) return 'stop';\n\n return 'next';\n};\n\n/**\n * Thrown when the chain gives up, whether because the last target failed\n * or `fallbackOn` chose to stop early. Carries each attempt in order so\n * an outage across providers stays debuggable without reproducing it.\n * Extends `LLMError` so `isLLMError` and any `instanceof LLMError` check\n * still passes, inheriting the last failure's `type`/`status`/`retryAfterMs`\n * so existing type-based handling, including reading `retryAfterMs` on an\n * `'api'`-typed error, keeps working on a fallback-exhausted error too.\n */\nexport class FallbackExhaustedError extends LLMError {\n constructor(public override readonly attempts: FallbackAttempt[]) {\n const last = attempts[attempts.length - 1]?.error;\n\n // `type` is always `'fallback_exhausted'`, never inherited from the last\n // target's own type: every target failing is a meaningfully different\n // event from any single target's own failure. `status` and\n // `retryAfterMs` still inherit from the last attempt.\n super(\n `${attempts.length} provider${attempts.length === 1 ? '' : 's'} attempted and failed: ${attempts\n .map((a) => `${a.provider}(${a.error.type})`)\n .join(' then ')}`,\n 'fallback_exhausted',\n {\n status: last?.status,\n // `last` is an `LLMErrorSnapshot`, not the live `LLMError` that\n // target actually threw, so `cause` here is the same descriptive\n // data a caller would get from `err.attempts.at(-1)!.error`\n // rather than a distinct object.\n cause: last,\n retryAfterMs: last?.retryAfterMs,\n code: 'fallback_exhausted',\n attempts,\n },\n );\n }\n\n /**\n * `type: 'fallback_exhausted'` by itself says nothing about whether\n * retrying could help; the reason the last target failed does. Defers to\n * that attempt's own `retryable` instead of anything about this class's\n * own type.\n */\n override get retryable(): boolean {\n const last = this.attempts[this.attempts.length - 1]?.error;\n return last ? last.retryable : super.retryable;\n }\n}\n\n/** Narrows `err` to {@link FallbackExhaustedError}, for direct access to its `attempts` (`provider`/`model` per failed target) without a manual `instanceof` check. */\nexport function isFallbackExhaustedError(err: unknown): err is FallbackExhaustedError {\n return err instanceof FallbackExhaustedError;\n}\n","import { LLMError, type StreamChunk, type UsageHooks } from '../../types/index.js';\n\n/**\n * Calls `params.reserveUsage`, if present, mapping any failure to a\n * `quota_exceeded` LLMError (or an aborted error, if the signal fired\n * during reservation). Returns whether a reservation was actually made,\n * so callers know whether a later refund is needed. Shared by\n * `withReservedUsage` and `withReservedUsageForStream`, which differ only\n * in whether `coalesced` is caller-supplied or always `false`.\n */\nasync function reserve(\n params: UsageHooks,\n coalesced: boolean,\n signal: AbortSignal | undefined,\n): Promise<boolean> {\n if (!params.reserveUsage) return false;\n\n try {\n await params.reserveUsage({ coalesced, signal });\n return true;\n } catch (error) {\n if (signal?.aborted) {\n throw new LLMError('LLM request aborted', 'aborted');\n }\n\n throw new LLMError(\n error instanceof Error ? error.message : 'Usage reservation failed',\n 'quota_exceeded',\n { cause: error },\n );\n }\n}\n\n/**\n * Builds a `(logMessage) => Promise<void>` refund function bound to the\n * given hooks/coalesced/signal, reporting (instead of throwing) any error\n * the refund hook itself raises, so a broken refund hook never masks the\n * original error it was called to clean up after.\n */\nfunction makeRefund(\n params: UsageHooks,\n coalesced: boolean,\n signal: AbortSignal | undefined,\n onRefundError: (logMessage: string, error: unknown) => void,\n): (logMessage: string) => Promise<void> {\n return async (logMessage: string) => {\n try {\n await params.refundUsage?.({ coalesced, signal });\n } catch (refundError) {\n onRefundError(logMessage, refundError);\n }\n };\n}\n\n/**\n * Runs `getResult` after reserving usage, if a `reserveUsage` hook was\n * provided. `refundUsage` fires only if a reservation was actually made.\n * `onRefundError` is called (instead of throwing) whenever a refund attempt\n * itself fails, so a broken refund hook never masks the original error.\n */\nexport async function withReservedUsage<T>(\n params: UsageHooks,\n coalesced: boolean,\n getResult: () => Promise<T>,\n signal: AbortSignal | undefined,\n onRefundError: (logMessage: string, error: unknown) => void,\n): Promise<T> {\n if (signal?.aborted) {\n throw new LLMError('LLM request aborted', 'aborted');\n }\n\n const reserved = await reserve(params, coalesced, signal);\n\n const refund = makeRefund(params, coalesced, signal, onRefundError);\n\n if (signal?.aborted) {\n if (reserved) await refund('[VernLLM] refundUsage failed after abort');\n throw new LLMError('LLM request aborted', 'aborted');\n }\n\n let result: T;\n\n try {\n result = await getResult();\n } catch (error) {\n if (reserved) await refund('[VernLLM] refundUsage failed');\n throw error;\n }\n\n if (signal?.aborted) {\n if (reserved) await refund('[VernLLM] refundUsage failed after abort');\n throw new LLMError('LLM request aborted', 'aborted');\n }\n\n return result;\n}\n\n/**\n * Streaming counterpart to `withReservedUsage`. `withReservedUsage` assumes\n * `getResult()` settling *is* the operation's final outcome, awaiting it\n * synchronously before reserve/refund resolve. Streaming can't satisfy that:\n * `call()` must return `{ chunks, finalResult }` as soon as the stream\n * opens, well before the real outcome (validation, schema/tool-call checks)\n * is known.\n *\n * Reserves usage before `openStream` runs, same failure mode as the\n * non-streaming path if `reserveUsage` itself throws (mapped to\n * `quota_exceeded`, nothing opened). If `openStream` itself throws (stream\n * never opened), refunds synchronously and rethrows, exactly like\n * `withReservedUsage` does today. If it succeeds, returns `{ chunks,\n * finalResult }` immediately, refund/report is deferred onto\n * `finalResult`'s continuation, since that's the only point the real\n * outcome is known. This means `onUsageFailure` (and any refund) can fire\n * well after this function itself has returned.\n */\nexport async function withReservedUsageForStream<T>(\n params: UsageHooks,\n openStream: () => Promise<{ chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> }>,\n signal: AbortSignal | undefined,\n onRefundError: (logMessage: string, error: unknown) => void,\n): Promise<{ chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> }> {\n if (signal?.aborted) {\n throw new LLMError('LLM request aborted', 'aborted');\n }\n\n const reserved = await reserve(params, false, signal);\n const refund = makeRefund(params, false, signal, onRefundError);\n\n if (signal?.aborted) {\n if (reserved) await refund('[VernLLM] refundUsage failed after abort');\n throw new LLMError('LLM request aborted', 'aborted');\n }\n\n let opened: { chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> };\n\n try {\n opened = await openStream();\n } catch (error) {\n if (reserved) await refund('[VernLLM] refundUsage failed after stream-open failure');\n throw error;\n }\n\n // Stream opened. The real outcome is only known once finalResult settles,\n // so refund is attached there instead of awaited inline, this is the\n // structural difference from withReservedUsage, not an optional variant.\n const finalResult = opened.finalResult.then(\n (value) => value,\n async (error) => {\n if (reserved) await refund('[VernLLM] refundUsage failed after stream error');\n throw error;\n },\n );\n\n // Same rationale as the no-op catch attached where finalResult is first\n // constructed: mark this derived promise observed too, so a caller that\n // only reads `chunks` doesn't get an unhandled-rejection warning from\n // this wrapper promise either.\n finalResult.catch(() => {});\n\n return { chunks: opened.chunks, finalResult };\n}\n","import type { StreamChunk } from '../../types/stream.js';\nimport type { CallWithToolsResult } from '../../types/tools.js';\n\n/**\n * Converts an already-known cache value back into a plausible \"text\" form\n * for a one-shot replay chunk: passed through unchanged if it's already a\n * string (the `jsonMode: false` case), otherwise `JSON.stringify`'d (the\n * `jsonMode: true` case, where the cached value is the *parsed* result, not\n * the original raw text). This is a reasonable reconstruction, not a\n * byte-identical replay of whatever text the model originally streamed,\n * good enough for `for await (const c of chunks)` call sites that don't\n * branch on hit vs. miss, which is the only thing a cache-hit replay needs\n * to support.\n */\nfunction toReplayText(value: unknown): string {\n return typeof value === 'string' ? value : (JSON.stringify(value) ?? '');\n}\n\n/**\n * Builds a trivially-exhausted one-shot `chunks` iterable from an\n * already-known value, used for a `cachedCall` cache hit, where there's no\n * live generation to relay (see `VernLLM.cachedCall`'s docs). No `usage`\n * chunk is emitted: a cache hit spent no real tokens, so there's nothing to\n * report, matching how non-streaming `cachedCall` never calls `onUsage` on\n * a hit either.\n *\n * `hasTools` must reflect whether the *original* call that produced this\n * cached value had `tools` set, that's what determines whether `value` is\n * `T` directly or a `CallWithToolsResult<T>` wrapper, and it isn't\n * something that can be reliably guessed from the value's shape alone\n * (a `schema`-validated `T` could coincidentally look like a\n * `CallWithToolsResult`).\n */\nexport function buildReplayChunks<T>(\n value: T | CallWithToolsResult<T>,\n hasTools: boolean,\n): AsyncIterable<StreamChunk> {\n const items: StreamChunk[] = [];\n\n if (hasTools) {\n const result = value as CallWithToolsResult<T>;\n\n if (result.type === 'tool_calls') {\n result.toolCalls.forEach((toolCall, index) => {\n items.push({\n type: 'tool_call_delta',\n index,\n id: toolCall.id,\n name: toolCall.name,\n argsDelta: JSON.stringify(toolCall.arguments ?? {}),\n // A replay is always the whole value in one shot, never a\n // fragment, same as Gemini's one-shot tool_call_delta chunks.\n complete: true,\n });\n });\n\n if (result.content) items.push({ type: 'text-delta', delta: result.content });\n } else {\n items.push({ type: 'text-delta', delta: toReplayText(result.content) });\n }\n } else {\n items.push({ type: 'text-delta', delta: toReplayText(value) });\n }\n\n return {\n async *[Symbol.asyncIterator]() {\n for (const item of items) yield item;\n },\n };\n}\n\n/**\n * Streaming counterpart to `buildReplayChunks` for a `cachedCall` that\n * *joined* an already-in-flight call for the same key rather than\n * triggering one itself (see `runCachedStream`'s in-flight-coalescing\n * path): there's no live stream to relay (it isn't this call's stream to\n * relay, see the joiner-path comment in `runCachedStream`), but there's\n * also no value yet, only a pending promise for one. Waits for `promise`,\n * then delegates to `buildReplayChunks`. If `promise` rejects, iterating\n * `chunks` throws that same error, consistent with how a live stream's\n * `chunks` throws on a mid-stream failure.\n */\nexport function buildReplayChunksFromPromise<T>(\n promise: Promise<T | CallWithToolsResult<T>>,\n hasTools: boolean,\n): AsyncIterable<StreamChunk> {\n return {\n async *[Symbol.asyncIterator]() {\n const value = await promise;\n\n yield* buildReplayChunks(value, hasTools);\n },\n };\n}\n","import { withReservedUsage, withReservedUsageForStream } from '../execution/usage.utils.js';\nimport { buildReplayChunks, buildReplayChunksFromPromise } from './replay.utils.js';\n\nimport type { Logger } from '../../logger.js';\nimport type { CacheAdapter, StreamChunk } from '../../types/index.js';\nimport type { InternalCacheParams, InternalCacheStreamParams } from './cache.utils.js';\n\n/**\n * Owns cache key resolution, cache reads/writes, and in-flight coalescing\n * for concurrent misses on the same key. Doesn't know about `CallExecutor`,\n * retries, or providers at all: `fn`/`openStream` are opaque callbacks\n * (`VernLLM.cachedCall` passes `() => this.call(...)`), so this class only\n * needs the cache adapter and a logger. Extracted from `VernLLM` since\n * caching and per-target call mechanics are independent concerns that\n * happened to live on the same class.\n */\nexport class CacheOrchestrator {\n private readonly inFlight = new Map<string, Promise<unknown>>();\n\n constructor(\n private readonly cache: CacheAdapter<unknown>,\n private readonly logger: Logger,\n ) {}\n\n /** Resolves a cache key through the adapter when it supports normalization. */\n async resolveCacheKey(key: string): Promise<string> {\n return this.cache.resolveKey ? await this.cache.resolveKey(key) : key;\n }\n\n /**\n * Removes a cached response by key when the configured cache adapter\n * supports deletion. Cache invalidation is the caller's responsibility;\n * only the application knows when cached data is stale.\n */\n async deleteCache(key: string): Promise<void> {\n if (!this.cache.delete) return;\n\n try {\n await this.cache.delete(await this.resolveCacheKey(key));\n } catch (error) {\n this.logger.warn(\n `[VernLLM] cache delete failed: ${error instanceof Error ? error.message : 'unknown'}`,\n );\n }\n }\n\n /** Logs a failed refundUsage attempt via the configured logger. */\n private logRefundError(logMessage: string, error: unknown): void {\n this.logger.error(logMessage, {\n message: error instanceof Error ? error.message : 'unknown',\n });\n }\n\n /**\n * Reads from the cache, treating a failed adapter read as a miss rather\n * than letting it fail the call. The request still falls through to a\n * real provider call, but that fallback is now logged instead of silent.\n */\n private async getCached(key: string): Promise<{ hit: boolean; value?: unknown }> {\n try {\n return await this.cache.get(key);\n } catch (error) {\n this.logger.warn(\n `[VernLLM] cache read failed: ${error instanceof Error ? error.message : 'unknown'}`,\n );\n\n return { hit: false };\n }\n }\n\n /**\n * Internal cache primitive around caller-supplied logic. Concurrent misses\n * for the same `cacheKey` share a single in-flight call, avoiding cache\n * stampedes.\n *\n * Backs the public `VernLLM.cachedCall()`, which always composes this\n * with `call()` so cached results get the same retry/timeout/\n * circuit-breaker guarantees as any other LLM call.\n *\n * @param params `cacheKey`, `ttl`, `fn` (the work to run on a cache\n * miss, typically `() => this.call(...)`), and optional\n * `reserveUsage`/`refundUsage`/`signal`. See `InternalCacheParams`.\n * @returns The cached value on a hit, or the result of `fn()` on a miss.\n */\n async runCached<T>(params: InternalCacheParams<T>): Promise<T> {\n const resolvedKey = await this.resolveCacheKey(params.cacheKey);\n const resolvedParams =\n resolvedKey === params.cacheKey ? params : { ...params, cacheKey: resolvedKey };\n\n const cached = await this.getCached(resolvedKey);\n\n if (cached.hit) return cached.value as T;\n\n const existing = this.inFlight.get(resolvedKey) as Promise<T> | undefined;\n\n if (existing) {\n return withReservedUsage(\n resolvedParams,\n true,\n () => existing,\n params.signal,\n (logMessage, error) => this.logRefundError(logMessage, error),\n );\n }\n\n return this.registerTrigger(resolvedParams);\n }\n\n /** Starts the shared fn() call for a cache miss and tracks it in the in-flight map until it settles. */\n private registerTrigger<T>(params: InternalCacheParams<T>): Promise<T> {\n const resultPromise = withReservedUsage(\n params,\n false,\n () => this.runAndCache(params),\n params.signal,\n (logMessage, error) => this.logRefundError(logMessage, error),\n );\n\n this.inFlight.set(params.cacheKey, resultPromise);\n\n void resultPromise\n .catch(() => {})\n .finally(() => {\n this.inFlight.delete(params.cacheKey);\n });\n\n return resultPromise;\n }\n\n /** Runs `fn` and writes its result to the cache. */\n private async runAndCache<T>(params: InternalCacheParams<T>): Promise<T> {\n const result = await params.fn();\n\n try {\n await this.cache.set(params.cacheKey, result, params.ttl);\n } catch (error) {\n this.logger.warn(\n `[VernLLM] cache write failed: ${error instanceof Error ? error.message : 'unknown'}`,\n );\n }\n\n return result;\n }\n\n /**\n * Streaming counterpart to `runCached`. Three cases:\n *\n * - Hit: no live generation to relay. Returns immediately with\n * `finalResult` resolved to the cached value and a one-shot `chunks`\n * replay built from it, so `for await (const c of chunks)` call sites\n * work identically on a hit or a miss. No usage hooks fire, since\n * nothing was actually spent.\n * - Miss, nothing else in flight for this key: delegates to\n * `registerStreamTrigger`, which opens the stream and relays its\n * `chunks` live.\n * - Miss, but another call for the same key is already in flight: this\n * call has no live chunks of its own to relay, so it's treated like a\n * delayed hit. `finalResult` shares the trigger's in-flight promise\n * (the same in-flight map non-streaming `runCached` uses, so\n * streaming and non-streaming calls for the same key coalesce\n * against each other too), and `chunks` is a one-shot replay built\n * once that promise resolves.\n */\n async runCachedStream<T>(\n params: InternalCacheStreamParams<T>,\n hasTools: boolean,\n ): Promise<{ chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> }> {\n const resolvedKey = await this.resolveCacheKey(params.cacheKey);\n const resolvedParams =\n resolvedKey === params.cacheKey ? params : { ...params, cacheKey: resolvedKey };\n\n const cached = await this.getCached(resolvedKey);\n\n if (cached.hit) {\n const value = cached.value as T;\n\n return { chunks: buildReplayChunks(value, hasTools), finalResult: Promise.resolve(value) };\n }\n\n const existing = this.inFlight.get(resolvedKey) as Promise<T> | undefined;\n\n if (existing) {\n const finalResult = withReservedUsage(\n resolvedParams,\n true,\n () => existing,\n params.signal,\n (logMessage, error) => this.logRefundError(logMessage, error),\n );\n\n // Mirror the no-op catch in withReservedUsageForStream: buildReplayChunksFromPromise\n // doesn't await this promise until `chunks` is iterated, so a caller that only reads\n // `finalResult` eagerly (or never reads `chunks`) could otherwise trigger an\n // unhandled-rejection warning.\n finalResult.catch(() => {});\n\n return { chunks: buildReplayChunksFromPromise(finalResult, hasTools), finalResult };\n }\n\n return this.registerStreamTrigger(resolvedParams);\n }\n\n /**\n * Opens the shared stream for a cache miss and tracks its settled value\n * in the in-flight map until it resolves or rejects. Writes to the cache\n * on success only, matching `runAndCache`.\n *\n * Registers the in-flight promise synchronously, before anything async\n * runs, so a concurrent `cachedCall` for the same key always sees it in\n * time to join instead of triggering its own stream. Settlement is\n * wired onto the whole `withReservedUsageForStream` call rather than a\n * line inside its callback, so any failure point (reserving usage,\n * opening the stream, or the stream itself) reliably settles the\n * in-flight entry instead of leaving it stuck.\n */\n private registerStreamTrigger<T>(\n params: InternalCacheStreamParams<T>,\n ): Promise<{ chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> }> {\n let resolveInFlight!: (value: T) => void;\n let rejectInFlight!: (error: unknown) => void;\n\n const inFlightResult = new Promise<T>((resolve, reject) => {\n resolveInFlight = resolve;\n rejectInFlight = reject;\n });\n\n this.inFlight.set(params.cacheKey, inFlightResult);\n\n void inFlightResult\n .catch(() => {})\n .finally(() => {\n this.inFlight.delete(params.cacheKey);\n });\n\n const streamPromise = withReservedUsageForStream(\n params,\n async () => {\n const opened = await params.openStream();\n\n const trackedResult: Promise<T> = opened.finalResult.then(\n async (value) => {\n try {\n await this.cache.set(params.cacheKey, value, params.ttl);\n } catch (error) {\n this.logger.warn(\n `[VernLLM] cache write failed: ${error instanceof Error ? error.message : 'unknown'}`,\n );\n }\n\n return value;\n },\n (error: unknown) => {\n // Failed calls aren't cached, matching `runAndCache`, which\n // only calls `cache.set` after `fn()` succeeds. Rethrown\n // unchanged so both the refund logic attached downstream and\n // `inFlightResult` see the real failure.\n throw error;\n },\n );\n\n return { chunks: opened.chunks, finalResult: trackedResult };\n },\n params.signal,\n (logMessage, error) => this.logRefundError(logMessage, error),\n );\n\n // Settles `inFlightResult` (registered above) based on `streamPromise`'s\n // own outcome, not a line inside its callback. See this function's\n // docs for why.\n streamPromise.then(\n (opened) => {\n opened.finalResult.then(resolveInFlight, rejectInFlight);\n },\n (error: unknown) => {\n rejectInFlight(error);\n },\n );\n\n return streamPromise;\n }\n}\n","import { LLMError } from './types/errors.js';\n\nexport interface CircuitBreakerOptions {\n /** Consecutive failures before the circuit opens, default 5 */\n threshold?: number;\n /** How long the circuit stays open before allowing a trial request, in ms. Default 30000 */\n cooldownMs?: number;\n /**\n * Called after every real state change, never for a no-op transition\n * (e.g. open to open). `model` is the resolved model of whichever call\n * triggered this specific transition (the `model` passed to whichever\n * of `assertClosed`/`recordSuccess`/`recordFailure` caused it).\n *\n * With `isolateByModel` off (the default), this is a label only: the\n * breaker still counts failures across every model together, so a\n * threshold crossing can be the sum of several different models'\n * failures even though only the triggering call's `model` is reported\n * here. With `isolateByModel` on, it's exact: each model has its own\n * counter, so the transition really was caused solely by that model.\n */\n onStateChange?: (\n from: CircuitState,\n to: CircuitState,\n consecutiveFailures: number,\n model?: string,\n ) => void;\n /**\n * Track a separate circuit per resolved model instead of one shared\n * circuit for the whole instance. A failure on one model then never\n * opens another model's circuit, at the cost of slower detection for\n * an outage spread across many distinct models (each model's counter\n * must independently cross `threshold`). Default false: one shared\n * circuit, matching every version before this option existed.\n *\n * A call that omits `model` (only possible calling `CircuitBreaker`\n * directly, `VernLLM` always passes one) falls into one shared bucket\n * alongside every other call that also omits it.\n */\n isolateByModel?: boolean;\n}\n\nexport type CircuitState = 'closed' | 'open' | 'half-open';\n\n/** Mutable state for one circuit, either the single shared one or one model's bucket under `isolateByModel`. */\ninterface CircuitBucket {\n state: CircuitState;\n consecutiveFailures: number;\n openedAt: number;\n /**\n * True while a single half-open trial call is in flight. Guards against\n * multiple concurrent callers all treating themselves as \"the\" trial once\n * the cooldown elapses\n */\n trialInFlight: boolean;\n}\n\nfunction newBucket(): CircuitBucket {\n return { state: 'closed', consecutiveFailures: 0, openedAt: 0, trialInFlight: false };\n}\n\n/** Key a bucket lookup falls into when the call omitted `model` under `isolateByModel`. */\nconst UNLABELED_MODEL = '';\n\n/**\n * Per retry VernLLM-instance circuit breaker. Tracks consecutive failures across\n * calls. Once the threshold is hit, short-circuits new calls with an\n * LLMError('circuit_open') instead of hitting the provider, until the\n * cooldown elapses and a single trial call is allowed through\n */\nexport class CircuitBreaker {\n private readonly threshold: number;\n private readonly cooldownMs: number;\n private readonly onStateChange?: CircuitBreakerOptions['onStateChange'];\n /** Whether this breaker tracks failures per model instead of one shared circuit. Read by `CallExecutor`/`VernLLM` to report per-target in `getCircuitStates`. */\n readonly isolateByModel: boolean;\n\n // Exactly one of these is used, chosen once at construction by\n // `isolateByModel`, so every method has a single, unambiguous place to\n // resolve a bucket from instead of branching on the flag repeatedly.\n private readonly sharedBucket: CircuitBucket = newBucket();\n private readonly bucketsByModel = new Map<string, CircuitBucket>();\n\n constructor(options: CircuitBreakerOptions = {}) {\n this.threshold = options.threshold ?? 5;\n this.cooldownMs = options.cooldownMs ?? 30_000;\n this.onStateChange = options.onStateChange;\n this.isolateByModel = options.isolateByModel ?? false;\n }\n\n /** Returns the bucket for a model if one already exists, without allocating. */\n private lookupBucket(model: string | undefined): CircuitBucket | undefined {\n if (!this.isolateByModel) return this.sharedBucket;\n\n const key = model ?? UNLABELED_MODEL;\n return this.bucketsByModel.get(key);\n }\n\n /** Creates and stores a bucket for a model when the first mutation needs one. */\n private ensureBucketFor(model: string | undefined): CircuitBucket {\n if (!this.isolateByModel) return this.sharedBucket;\n\n const key = model ?? UNLABELED_MODEL;\n let bucket = this.bucketsByModel.get(key);\n\n if (!bucket) {\n bucket = newBucket();\n this.bucketsByModel.set(key, bucket);\n }\n\n return bucket;\n }\n\n /** Every state mutation routes through here, so `onStateChange` fires exactly once per real change. */\n private transition(bucket: CircuitBucket, to: CircuitState, model: string | undefined): void {\n if (to === bucket.state) return;\n\n const from = bucket.state;\n bucket.state = to;\n this.onStateChange?.(from, to, bucket.consecutiveFailures, model);\n }\n\n /**\n * Throws if the circuit is open and the cooldown hasn't elapsed, or if\n * the circuit is half-open and a trial call is already in flight.\n * Otherwise, if the circuit just became eligible for a trial (cooldown\n * elapsed, or half-open with no trial currently running), this call\n * becomes that trial\n */\n assertClosed(model?: string): void {\n const bucket = this.ensureBucketFor(model);\n\n if (bucket.state === 'closed') return;\n\n if (bucket.state === 'open') {\n const elapsed = Date.now() - bucket.openedAt;\n if (elapsed < this.cooldownMs) {\n throw new LLMError(\n `Circuit open, provider has failed ${bucket.consecutiveFailures} times in a row. Retry in ${Math.ceil((this.cooldownMs - elapsed) / 1000)}s.`,\n 'circuit_open',\n { code: 'circuit_cooling_down' },\n );\n }\n\n // Set before transition(): a synchronous onStateChange observer\n // that re-enters (e.g. calls assertClosed again) must see this\n // call as already claiming the trial, not still eligible for one.\n bucket.trialInFlight = true;\n this.transition(bucket, 'half-open', model);\n return;\n }\n\n // state === 'half-open'\n if (bucket.trialInFlight) {\n throw new LLMError(\n 'Circuit half-open. A trial request is already in flight. Try again shortly.',\n 'circuit_open',\n { code: 'circuit_trial_in_flight' },\n );\n }\n\n bucket.trialInFlight = true;\n }\n\n recordSuccess(model?: string): void {\n const bucket = this.lookupBucket(model);\n\n if (!bucket) {\n return;\n }\n\n bucket.consecutiveFailures = 0;\n bucket.trialInFlight = false;\n this.transition(bucket, 'closed', model);\n\n if (this.isolateByModel && bucket.state === 'closed' && bucket.consecutiveFailures === 0) {\n this.bucketsByModel.delete(model ?? UNLABELED_MODEL);\n }\n }\n\n recordFailure(model?: string): void {\n const bucket = this.ensureBucketFor(model);\n\n bucket.consecutiveFailures += 1;\n bucket.trialInFlight = false;\n\n if (bucket.state === 'half-open') {\n // Trial call failed: reopen and reset the cooldown window. Set\n // before transition() for the same reason as assertClosed above:\n // a synchronous observer must see the fresh cooldown, not a stale\n // or zeroed one.\n bucket.openedAt = Date.now();\n this.transition(bucket, 'open', model);\n return;\n }\n\n if (bucket.consecutiveFailures >= this.threshold) {\n bucket.openedAt = Date.now();\n this.transition(bucket, 'open', model);\n }\n }\n\n /**\n * With `isolateByModel` off (the default), `model` is ignored and the\n * one shared circuit's state is returned, unchanged from every version\n * before this option existed. With `isolateByModel` on, returns that\n * model's own state, `'closed'` for a model never seen yet, same as a\n * fresh breaker.\n */\n getState(model?: string): CircuitState {\n return this.lookupBucket(model)?.state ?? 'closed';\n }\n\n /**\n * Manually opens the circuit, as if `threshold` consecutive failures had\n * just happened, e.g. to pull a provider out of rotation ahead of known\n * maintenance. Resets the cooldown window from now, same as a real\n * threshold-crossing failure would, and clears any in-flight half-open\n * trial since it no longer applies once the circuit is (re)opened.\n */\n open(model?: string): void {\n const bucket = this.ensureBucketFor(model);\n\n bucket.openedAt = Date.now();\n bucket.trialInFlight = false;\n this.transition(bucket, 'open', model);\n }\n\n /**\n * Manually closes the circuit and resets its failure count, e.g. once a\n * provider is confirmed healthy again without waiting out the cooldown.\n * Mirrors `recordSuccess`'s bookkeeping (including dropping the\n * per-model bucket under `isolateByModel`, once idle) but without\n * requiring an actual successful call first.\n */\n close(model?: string): void {\n const bucket = this.ensureBucketFor(model);\n\n bucket.consecutiveFailures = 0;\n bucket.trialInFlight = false;\n this.transition(bucket, 'closed', model);\n\n // transition() may have synchronously re-entered (e.g. an\n // onStateChange callback that calls open(model) on this same\n // bucket), so re-check state/consecutiveFailures rather than\n // assuming they still hold the values set above, same as\n // recordSuccess does.\n if (this.isolateByModel && bucket.state === 'closed' && bucket.consecutiveFailures === 0) {\n this.bucketsByModel.delete(model ?? UNLABELED_MODEL);\n }\n }\n}\n","import { CircuitBreaker, type CircuitBreakerOptions } from '../circuitBreaker.js';\n\nimport type { Logger } from '../logger.js';\nimport type { VernLLMEvent } from '../types/events.js';\n\n/**\n * Builds a `(event) => void` reporter that no-ops when `onEvent` is unset,\n * and otherwise calls it, swallowing and logging any error the handler\n * throws so a broken `onEvent` can't break the call that triggered it.\n * Shared by `buildCircuitBreaker` (which needs to report before any\n * executor exists) and `CallExecutor.reportEvent`, kept independent of the\n * executor for that reason.\n */\nexport function makeEventReporter(\n onEvent: ((event: VernLLMEvent) => void) | undefined,\n logger: Logger,\n): (event: VernLLMEvent) => void {\n return (event) => {\n if (!onEvent) return;\n\n try {\n onEvent(event);\n } catch (error) {\n logger.error('[VernLLM] onEvent failed', {\n message: error instanceof Error ? error.message : 'unknown',\n });\n }\n };\n}\n\n/**\n * Builds the optional circuit breaker for one provider target, wiring its\n * `onStateChange` to emit a `circuit_state` event and chain any\n * caller-supplied `onStateChange`. Returns `undefined` when\n * `circuitBreakerOption` is falsy, matching the option's own semantics.\n *\n * Lives outside `CallExecutor` (and outside `VernLLM`, once this were\n * inlined) because the breaker has to exist *before* the executor it's\n * passed into, so its construction can't be an executor concern.\n * `onEvent` is called directly rather than through the executor for the\n * same reason: nothing executor-shaped exists yet at this point.\n *\n * Takes the specific fields it needs (rather than a full `VernLLMOptions`)\n * so it works identically for the primary target and for each fallback\n * target, which carry their own `circuitBreaker` override alongside the\n * shared `onEvent`.\n */\nexport function buildCircuitBreaker(\n circuitBreakerOption: boolean | CircuitBreakerOptions | undefined,\n providerName: string,\n defaultModel: string,\n onEvent: ((event: VernLLMEvent) => void) | undefined,\n logger: Logger,\n): CircuitBreaker | undefined {\n if (!circuitBreakerOption) return undefined;\n\n const breakerOptions =\n typeof circuitBreakerOption === 'object' ? circuitBreakerOption : undefined;\n const userOnStateChange = breakerOptions?.onStateChange;\n\n const reportEvent = makeEventReporter(onEvent, logger);\n\n return new CircuitBreaker({\n ...breakerOptions,\n onStateChange: (from, to, consecutiveFailures, model) => {\n reportEvent({\n kind: 'circuit_state',\n provider: providerName,\n model: model ?? defaultModel,\n from,\n to,\n consecutiveFailures,\n });\n\n // A caller-supplied onStateChange would otherwise be silently\n // discarded, since the spread above is overwritten by this\n // property. Chain it instead, same try/catch treatment as every\n // other user-supplied callback so it can't break breaker\n // bookkeeping or the call that triggered it.\n if (!userOnStateChange) return;\n\n try {\n userOnStateChange(from, to, consecutiveFailures, model);\n } catch (error) {\n logger.error('[VernLLM] circuitBreaker.onStateChange failed', {\n message: error instanceof Error ? error.message : 'unknown',\n });\n }\n },\n });\n}\n","import { LLMError } from '../../types/errors.js';\n\nimport type { Logger } from '../../logger.js';\n\n/**\n * Default cap (ms) for both exponential backoff and honored Retry-After\n * values, so a misbehaving/adversarial Retry-After can't stall a caller\n * indefinitely\n */\nexport const DEFAULT_MAX_DELAY_MS = 10_000;\n\n/**\n * `setTimeout` silently clamps any delay above this (~24.8 days) or\n * `Infinity` down to ~1ms instead of erroring, so a caller passing\n * `Infinity` as \"no timeout\" gets the opposite of what they asked for.\n * Both timeout helpers below guard against this explicitly.\n */\nconst MAX_SETTIMEOUT_MS = 2_147_483_647;\n\n/**\n * Resolves a timeout value to the number `setTimeout` should actually use,\n * or `undefined` when the timeout should be treated as disabled (0,\n * negative, or `Infinity`). Returning the resolved value directly, rather\n * than a boolean, lets callers narrow `number | undefined` to `number`\n * without an `as number` cast.\n */\nfunction resolveActiveTimeoutMs(ms: number | undefined): number | undefined {\n return !ms || ms <= 0 || ms === Infinity ? undefined : ms;\n}\n\n/** Caps a timeout at the largest delay `setTimeout` actually honors. */\nfunction clampTimeoutMs(ms: number): number {\n return Math.min(ms, MAX_SETTIMEOUT_MS);\n}\n\n/**\n * Runs an async function and cancels it if it takes longer than the given\n * timeout. Creates an internal abort controller that fires after the\n * timeout elapses, and combines it with any external signal the caller\n * passed in so either one can cancel the underlying call. If the internal\n * timeout triggers and the underlying operation aborts, the error is\n * converted into an LLMError with type \"timeout\". External cancellations\n * continue to propagate as aborted errors. The internal timer is always\n * cleared afterward, whether the function succeeds, fails, or is aborted,\n * so nothing is left running in the background.\n *\n * `timeoutMs` of `Infinity` (or any value beyond what `setTimeout` can\n * represent) disables the timeout rather than firing almost immediately.\n */\nexport async function withTimeout<T>(\n fn: (signal: AbortSignal) => Promise<T>,\n timeoutMs: number,\n externalSignal?: AbortSignal,\n): Promise<T> {\n const controller = new AbortController();\n\n const activeTimeoutMs = resolveActiveTimeoutMs(timeoutMs);\n\n const timer =\n activeTimeoutMs === undefined\n ? undefined\n : setTimeout(() => {\n controller.abort();\n }, clampTimeoutMs(activeTimeoutMs));\n\n const signal = externalSignal\n ? AbortSignal.any([externalSignal, controller.signal])\n : controller.signal;\n\n try {\n return await fn(signal);\n } catch (err) {\n if (\n controller.signal.aborted &&\n !externalSignal?.aborted &&\n err instanceof DOMException &&\n err.name === 'AbortError'\n ) {\n throw new LLMError('Request timed out', 'timeout', { code: 'request_timeout' });\n }\n\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Races one `iterator.next()` call against a per-call idle timer, to\n * bound the gap *between* chunks (unlike `withTimeout`, which only bounds\n * opening the stream and its first chunk). Without this, a connection\n * that streams one chunk then hangs would never fail.\n *\n * `timeoutMs` of 0/undefined/`Infinity` disables the check. Otherwise\n * rejects with `LLMError('timeout')` if `next()` doesn't settle in time.\n * The clock resets on every call, so the window is measured from the most\n * recent chunk, not from stream start.\n *\n * `onIdle`, if given, is called the moment the timer fires (before the\n * rejection), so callers can abort the underlying transport instead of\n * just walking away from an unread promise. `logger`, if given, records a\n * debug line if `next()` still settles *after* the idle timeout already\n * rejected. `resolve`/`reject` on an already-settled promise is otherwise\n * a silent no-op, so without this the late chunk (possibly the final\n * usage chunk) would vanish with no trace.\n */\nexport function withChunkIdleTimeout<T>(\n next: () => Promise<IteratorResult<T>>,\n timeoutMs: number | undefined,\n onIdle?: () => void,\n logger?: Pick<Logger, 'debug'>,\n): Promise<IteratorResult<T>> {\n const activeTimeoutMs = resolveActiveTimeoutMs(timeoutMs);\n\n if (activeTimeoutMs === undefined) {\n return next();\n }\n\n let settled = false;\n\n return new Promise<IteratorResult<T>>((resolve, reject) => {\n const timer = setTimeout(() => {\n settled = true;\n onIdle?.();\n reject(\n new LLMError(\n `No stream chunk received for ${activeTimeoutMs}ms (idle timeout)`,\n 'timeout',\n {\n code: 'idle_timeout',\n },\n ),\n );\n }, clampTimeoutMs(activeTimeoutMs));\n\n next().then(\n (result) => {\n clearTimeout(timer);\n if (settled) {\n logger?.debug('[VernLLM] chunk resolved after idle timeout already fired; discarding');\n return;\n }\n settled = true;\n resolve(result);\n },\n (error: unknown) => {\n clearTimeout(timer);\n if (settled) {\n logger?.debug(\n '[VernLLM] chunk rejection arrived after idle timeout already fired; discarding',\n );\n return;\n }\n settled = true;\n reject(error);\n },\n );\n });\n}\n\n/**\n * Looks inside an unknown error value for a Retry-After header and\n * converts it to milliseconds. Checks `.headers` first (fetch-style,\n * Headers-like with `.get()`), then `.response.headers` (axios-style,\n * plain object) since different client libraries surface headers\n * differently. Supports both the delta-seconds form (\"30\") and the\n * HTTP-date form (\"Wed, 21 Oct 2015 07:28:00 GMT\"). The result is capped\n * at maxDelayMs. Returns undefined when no usable Retry-After is present\n */\nexport function extractRetryAfterMs(\n err: unknown,\n maxDelayMs = DEFAULT_MAX_DELAY_MS,\n): number | undefined {\n if (!err || typeof err !== 'object') return undefined;\n\n const error = err as { headers?: unknown; response?: { headers?: unknown } };\n const headers = error.headers ?? error.response?.headers;\n\n if (!headers || typeof headers !== 'object') return undefined;\n\n const getter = headers as { get?: (name: string) => string | null };\n\n const raw =\n typeof getter.get === 'function'\n ? getter.get('Retry-After')\n : Object.entries(headers as Record<string, string>)\n .find(([name]) => name.toLowerCase() === 'retry-after')\n ?.at(1);\n\n if (typeof raw !== 'string' || raw.trim() === '') return undefined;\n\n const trimmed = raw.trim();\n\n if (/^\\d+$/.test(trimmed)) {\n return Math.max(0, Math.min(Number(trimmed) * 1000, maxDelayMs));\n }\n\n const dateMs = Date.parse(trimmed);\n if (!Number.isNaN(dateMs)) {\n return Math.max(0, Math.min(dateMs - Date.now(), maxDelayMs));\n }\n\n return undefined;\n}\n\n/**\n * Exponential backoff with jitter, capped at maxDelayMs.\n * Jitter avoids thundering-herd retries when many callers back off in lockstep,\n * the cap prevents unbounded delays when maxRetries is high\n */\nexport function getBackoffDelay(\n baseDelayMs: number,\n attempt: number,\n maxDelayMs = DEFAULT_MAX_DELAY_MS,\n): number {\n const exp = Math.min(baseDelayMs * 2 ** attempt, maxDelayMs);\n return exp / 2 + Math.random() * (exp / 2);\n}\n\n/**\n * Pauses execution for the given delay before a retry attempt. If an\n * abort signal is provided and it fires while waiting, the pending\n * timer is cancelled immediately and the wait rejects right away with\n * an aborted error instead of continuing to sit idle until the delay\n * would have finished on its own\n */\nexport async function waitForRetry(delay: number, signal?: AbortSignal): Promise<void> {\n if (signal?.aborted) {\n throw new LLMError('Operation aborted', 'aborted');\n }\n\n await new Promise<void>((resolve, reject) => {\n const onAbort = () => {\n clearTimeout(timer);\n reject(new LLMError('Operation aborted', 'aborted'));\n };\n\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, delay);\n\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n","import { LLMError, type LLMErrorCode, type RetryAttempt } from '../../types/errors.js';\nimport { extractRetryAfterMs } from './retry.utils.js';\n\n/**\n * Looks inside an unknown error value and pulls out an http status code\n * if one is present. Checks the status field first then the status code\n * field since different client libraries use different names for this,\n * falling back to AWS SDK v3's `$metadata.httpStatusCode` (e.g. Bedrock's\n * `ThrottlingException`), which doesn't set either of the other two.\n * Returns undefined when the error is not an object or carries no status\n */\nexport function extractStatus(err: unknown): number | undefined {\n if (!err || typeof err !== 'object') return undefined;\n\n const error = err as {\n status?: unknown;\n statusCode?: unknown;\n $metadata?: { httpStatusCode?: unknown };\n };\n\n if (typeof error.status === 'number') return error.status;\n if (typeof error.statusCode === 'number') return error.statusCode;\n if (typeof error.$metadata?.httpStatusCode === 'number') return error.$metadata.httpStatusCode;\n\n return undefined;\n}\n\n/**\n * POSIX/libuv error codes libuv (and so Node's `fetch`/undici) attaches to\n * genuine transport-level failures: connection refused, DNS lookup\n * failure, connection reset mid-request, a connect that never completed,\n * DNS server unreachable, broken pipe, or host/network unreachable.\n * Deliberately narrow: only codes that can only mean \"the connection\n * itself failed,\" not anything that could also indicate an application\n * error.\n */\nconst NETWORK_ERROR_CODES = new Set([\n 'ECONNREFUSED',\n 'ENOTFOUND',\n 'ECONNRESET',\n 'ETIMEDOUT',\n 'EAI_AGAIN',\n 'EPIPE',\n 'ECONNABORTED',\n 'EHOSTUNREACH',\n 'ENETUNREACH',\n]);\n\n/** `fetch`'s own wording for a transport-level failure, across runtimes/browsers. */\nconst NETWORK_ERROR_MESSAGES = new Set([\n 'fetch failed', // Node/undici\n 'failed to fetch', // Chromium\n 'load failed', // Safari\n 'networkerror when attempting to fetch resource.', // Firefox\n]);\n\n/**\n * Whether `error` is, with reasonable confidence, a transport-level\n * failure (never reached the provider, as opposed to the provider itself\n * responding with an error) rather than some other unexpected exception.\n * Checked via explicit, well-known signals only, so a genuinely unknown\n * error never gets misclassified as a connection failure just because it\n * also lacked an HTTP status.\n */\nfunction isNetworkError(error: unknown): boolean {\n if (!error || typeof error !== 'object') return false;\n\n const err = error as { code?: unknown; message?: unknown; cause?: unknown };\n\n if (typeof err.code === 'string' && NETWORK_ERROR_CODES.has(err.code)) return true;\n\n if (typeof err.message === 'string' && NETWORK_ERROR_MESSAGES.has(err.message.toLowerCase())) {\n return true;\n }\n\n // undici/Node's `fetch` wraps the real libuv error one level down, as\n // TypeError('fetch failed', { cause: <the real error, with .code> }).\n // The message check above already catches that wrapper by itself if\n // the cause is missing or unrecognized, this catches it by the cause's\n // code when the wrapper's own message wasn't matched (e.g. a runtime\n // that phrases the wrapper differently but still sets `cause.code`).\n if (err.cause && typeof err.cause === 'object') {\n const cause = err.cause as { code?: unknown };\n if (typeof cause.code === 'string' && NETWORK_ERROR_CODES.has(cause.code)) return true;\n }\n\n return false;\n}\n\nfunction formatSafely(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2) ?? String(value);\n } catch {\n try {\n return String(value);\n } catch {\n return '[unprintable error]';\n }\n }\n}\n\n/**\n * Looks inside an unknown thrown value and pulls out a human-readable\n * description of it. Checks the `error` field first (the provider's raw\n * rejection body, JSON-stringified if possible) then falls back to the\n * message` field. Always returns a safe string, even when the thrown value\n * has hostile properties or cannot be serialized normally.\n */\nexport function describeError(err: unknown): string {\n if (err && typeof err === 'object') {\n try {\n const error = err as { message?: unknown; error?: unknown };\n\n if (error.error !== undefined) {\n return formatSafely(error.error);\n }\n\n if (typeof error.message === 'string') {\n return error.message;\n }\n } catch {\n // Fall through to safe string.\n }\n }\n\n return formatSafely(err);\n}\n\n/**\n * Maps an HTTP status to its corresponding `LLMErrorCode`, derived purely\n * from the status itself so it applies the same way regardless of which\n * adapter or client raised the error. Used both when building a fresh\n * `LLMError` and when filling in a `code` on an already-normalized one\n * that doesn't have one yet, so the two paths can't drift apart.\n */\nfunction codeForStatus(status: number): LLMErrorCode | undefined {\n switch (status) {\n case 429:\n return 'provider_rate_limited';\n case 401:\n return 'authentication';\n case 403:\n return 'authorization';\n case 404:\n return 'not_found';\n case 413:\n return 'payload_too_large';\n default:\n return status >= 500 ? 'server_error' : undefined;\n }\n}\n\n/**\n * Whether a provider's error response actually contains anything a person\n * could act on. Some providers return a non-2xx status with **no body at\n * all** for certain field-validation failures (Mistral's OpenAI-compatible\n * endpoint does this, for example, when a request includes a field the\n * target model doesn't support). SDKs built on top of `openai` render that\n * specific case as a message like `\"400 status code (no body)\"`.\n *\n * Derived from the object's own `error`/`message` fields directly, rather\n * than from whatever `describeError` rendered, because `describeError`\n * falls back to serializing the *whole* thrown value when neither field is\n * present or meaningful. That fallback is local echo (e.g. just the\n * `status` a caller passed in), not provider diagnostic content, and\n * treating it as \"detail\" defeats the whole point of this check.\n */\nconst NO_BODY_MESSAGE_PATTERN = /\\(no body\\)/i;\n\nfunction isEmptyObject(value: object): boolean {\n return Object.keys(value).length === 0;\n}\n\nfunction hasNoDiagnosticDetail(error: unknown): boolean {\n if (error && typeof error === 'object') {\n const { error: errorField, message } = error as { error?: unknown; message?: unknown };\n\n // A present, non-null, non-empty `.error` is the provider's raw\n // structured error body, genuine diagnostic content whenever it's\n // present, regardless of how describeError ends up phrasing it.\n // `error: null`, `error: ''`, and `error: {}` are all placeholders,\n // not real content, and fall through to the message check below like\n // a missing field would.\n if (errorField !== undefined && errorField !== null) {\n const isEmptyString = typeof errorField === 'string' && errorField.trim().length === 0;\n const isEmptyStruct = typeof errorField === 'object' && isEmptyObject(errorField);\n\n if (!isEmptyString && !isEmptyStruct) {\n return false;\n }\n }\n\n if (typeof message === 'string') {\n const trimmed = message.trim();\n return trimmed.length === 0 || NO_BODY_MESSAGE_PATTERN.test(trimmed);\n }\n\n // Neither a meaningful `.error` nor a `.message` string: describeError\n // has nothing of the provider's own to report and falls back to\n // stringifying the whole object instead.\n return true;\n }\n\n // A non-object thrown value (string, number, etc.) has no `.error`/\n // `.message` fields to check at all.\n return true;\n}\n\n/**\n * Converts any thrown value into a well-typed LLMError. `attempts`, when\n * given, is the accumulated record of every attempt made before `error`\n * was thrown; it's passed straight into the constructed error's options\n * rather than assigned onto the error afterward, so `attempts` is always\n * settled once, through the constructor, like every other field on\n * `LLMError`.\n */\nexport function normalizeError(\n error: unknown,\n signal?: AbortSignal,\n attempts?: RetryAttempt[],\n): LLMError {\n if (signal?.aborted) {\n return new LLMError('LLM request aborted', 'aborted', { attempts });\n }\n\n if (error instanceof LLMError) {\n // A caller or adapter can throw an already-built LLMError directly\n // (bypassing the generic-SDK-error path below), so a status reaching\n // us this way still needs the same `code` a generic error with that\n // status gets, without overwriting a `code` that error already carries.\n if (error.code === undefined && error.status !== undefined) {\n error.code = codeForStatus(error.status);\n }\n\n // Same rule for `attempts`: fill it in if this already-built error\n // doesn't carry one of its own, without overwriting one it does.\n if (error.attempts === undefined && attempts !== undefined) {\n error.attempts = attempts;\n }\n\n return error;\n }\n\n const status = extractStatus(error);\n const retryAfterMs = extractRetryAfterMs(error);\n\n if (status !== undefined) {\n const description = describeError(error);\n\n // The generic \"LLM request failed\" message previously never carried\n // any of the detail describeError() already extracts (that function\n // was only ever used for debug logging, gated behind `debug: true`),\n // so a caught LLMError's own .message told you nothing beyond \"it\n // failed with this status,\" even when the provider's response did\n // include a real, readable description. Folding that description into\n // the thrown message means the detail is there unconditionally, not\n // only when debug logging happens to be on.\n const code = codeForStatus(status);\n\n // The \"probably an unsupported field/value\" guidance is only accurate\n // for statuses that don't already have a more specific, known meaning\n // (auth, rate limiting, not-found, payload-too-large, server errors);\n // for those, a no-body response is just a no-body response and the\n // field-validation explanation would be actively misleading.\n const isRequestValidationStatus = code === undefined;\n\n const message = hasNoDiagnosticDetail(error)\n ? isRequestValidationStatus\n ? `LLM request failed with status ${status} and no error detail from the provider. This usually means a field or value in the request isn't supported by the specific model (for example, a reasoning/thinking parameter the model doesn't accept), rather than a transport or auth problem.`\n : `LLM request failed with status ${status} and no error detail from the provider.`\n : `LLM request failed: ${description}`;\n\n return new LLMError(message, 'api', {\n status,\n cause: error,\n retryAfterMs,\n code,\n attempts,\n });\n }\n\n // No extractable HTTP status: distinguish a genuine transport-level\n // failure (DNS, connection refused, connection reset) from any other\n // unexpected exception via explicit signals only, rather than assuming\n // every status-less error reaching here is a connection failure.\n if (isNetworkError(error)) {\n return new LLMError('LLM request failed', 'network', {\n cause: error,\n retryAfterMs,\n code: 'connection_failed',\n attempts,\n });\n }\n\n return new LLMError('LLM request failed', 'unknown', { cause: error, retryAfterMs, attempts });\n}\n","/** Default `parseJson`: `JSON.parse` wrapped in try/catch, returning `undefined` on failure. */\nexport function defaultParseJson(content: string): unknown {\n try {\n return JSON.parse(content);\n } catch {\n return undefined;\n }\n}\n","import { LLMError } from '../../types/errors.js';\n\nimport type { LLMClient, WireToolCall } from '../../types/client.js';\nimport type { ToolCall, ToolDefinition } from '../../types/tools.js';\n\n/** Translates app-facing `ToolDefinition[]` into the OpenAI-shaped wire tools array. */\nexport function toWireTools(\n tools: ToolDefinition[],\n): NonNullable<Parameters<LLMClient['chat']['completions']['create']>[0]['tools']> {\n return tools.map((tool) => ({\n type: 'function' as const,\n function: {\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters,\n },\n }));\n}\n\n/** Translates app-facing `ToolCall[]` (e.g. from a replayed assistant turn) into wire tool_calls. */\nexport function toWireToolCalls(toolCalls: ToolCall[]): WireToolCall[] {\n return toolCalls.map((tc) => ({\n id: tc.id,\n type: 'function' as const,\n function: {\n name: tc.name,\n arguments: JSON.stringify(tc.arguments ?? {}),\n },\n }));\n}\n\n/**\n * Parses the provider's wire-shaped `tool_calls` back into VernLLM's\n * `ToolCall[]`. Malformed argument JSON is a `'parse'` error, same\n * convention as malformed JSON response bodies elsewhere in VernLLM.\n */\nexport function parseWireToolCalls(wireToolCalls: WireToolCall[]): ToolCall[] {\n return wireToolCalls.map((wc) => {\n let parsedArgs: unknown;\n\n try {\n parsedArgs = wc.function.arguments.trim() ? JSON.parse(wc.function.arguments) : {};\n } catch {\n throw new LLMError(`Invalid JSON arguments for tool call \"${wc.function.name}\"`, 'parse', {\n code: 'tool_arguments_parse_failed',\n });\n }\n\n return { id: wc.id, name: wc.function.name, arguments: parsedArgs };\n });\n}\n","import { LLMError } from '../../types/errors.js';\nimport { toWireTools, toWireToolCalls } from './wire.utils.js';\n\nimport type {\n AssistantContent,\n CallParams,\n ConversationTurn,\n WireMessage,\n WireToolChoice,\n} from '../../types/index.js';\n\n/**\n * Serializes `ConversationTurn` assistant content for the wire. Strings\n * pass through unchanged. Parsed JSON values are `JSON.stringify`'d.\n */\nfunction serializeAssistantContent(content: AssistantContent): string {\n return typeof content === 'string' ? content : JSON.stringify(content);\n}\n\n/** Everything `RequestBuilder` needs beyond a single call's own `CallParams`. */\nexport interface RequestBuilderOptions {\n model: string;\n defaultMaxTokens: number;\n defaultTemperature: number | null;\n defaultReasoningEffort?: 'minimal' | 'low' | 'medium' | 'high';\n defaultBudgetTokens?: number;\n /**\n * Whether the target client honors `response_format: { type: 'json_object' }`\n * as a real constraint (see `LLMClient.supportsJsonObjectMode`'s docs).\n * `true` for every built-in adapter except `fromAnthropic`/`fromBedrock`.\n */\n supportsJsonObjectMode: boolean;\n}\n\n/**\n * Builds the wire request object for one call, applying per-instance\n * defaults (model, max tokens, temperature) and per-call overrides.\n * Owns every check that depends only on the caller's own input shape, not\n * on execution: history alternation, duplicate/empty tool lists,\n * `toolChoice` naming a real tool. All deterministic on the call site's\n * own input and never touch the network, so every throw here is\n * `type: 'invalid_params'`, not `'validation'` (which is reserved for the\n * model/provider's own response failing a contract check). Has no\n * knowledge of retry, timeouts, or the breaker, only\n * the three defaults a `FallbackTarget` can override per-target (see the\n * `defaultMaxTokens`/`defaultTemperature` overrides in the fallback\n * design), which is what keeps it separable from `CallExecutor`.\n */\nexport class RequestBuilder {\n private readonly model: string;\n private readonly defaultMaxTokens: number;\n private readonly defaultTemperature: number | null;\n private readonly defaultReasoningEffort?: 'minimal' | 'low' | 'medium' | 'high';\n private readonly defaultBudgetTokens?: number;\n private readonly supportsJsonObjectMode: boolean;\n\n constructor(options: RequestBuilderOptions) {\n this.model = options.model;\n this.defaultMaxTokens = options.defaultMaxTokens;\n this.defaultTemperature = options.defaultTemperature;\n this.defaultReasoningEffort = options.defaultReasoningEffort;\n this.defaultBudgetTokens = options.defaultBudgetTokens;\n this.supportsJsonObjectMode = options.supportsJsonObjectMode;\n }\n\n /** Applies per-call defaults and shapes params into the client's request object. */\n build<T>(params: CallParams<T>) {\n const {\n systemPrompt,\n userContent,\n history = [],\n maxTokens = this.defaultMaxTokens,\n model = this.model,\n jsonSchema,\n tools,\n toolChoice,\n } = params;\n\n const temperature =\n params.temperature === undefined ? this.defaultTemperature : params.temperature;\n const reasoningEffort =\n params.reasoningEffort === undefined ? this.defaultReasoningEffort : params.reasoningEffort;\n const budgetTokens =\n params.budgetTokens === undefined ? this.defaultBudgetTokens : params.budgetTokens;\n\n if (tools && tools.length === 0) {\n throw new LLMError(\n '`tools` was an empty array. This is almost always a bug (e.g. a filtered tool list ' +\n 'that ended up empty). An empty `tools` array still switches on tool-call mode ' +\n '(response shape, jsonMode default, wire format) with nothing for the model to call. ' +\n 'Omit `tools` entirely for a normal call, or make sure the array is non-empty.',\n 'invalid_params',\n );\n }\n\n if (tools) {\n const seen = new Set<string>();\n const duplicates = new Set<string>();\n\n for (const tool of tools) {\n if (seen.has(tool.name)) duplicates.add(tool.name);\n seen.add(tool.name);\n }\n\n if (duplicates.size) {\n throw new LLMError(\n `\\`tools\\` has duplicate name(s): [${[...duplicates].join(', ')}]. Tool names must be unique.`,\n 'invalid_params',\n { code: 'duplicate_tool_names', issues: { names: [...duplicates] } },\n );\n }\n }\n\n if (toolChoice && !tools) {\n throw new LLMError(\n '`toolChoice` was set without `tools`. There is nothing for it to choose between. ' +\n 'Set `tools`, or remove `toolChoice`.',\n 'invalid_params',\n );\n }\n\n if (tools && typeof toolChoice === 'object' && !tools.some((t) => t.name === toolChoice.name)) {\n throw new LLMError(\n `toolChoice names \"${toolChoice.name}\", which is not in \\`tools\\` ([${tools.map((t) => t.name).join(', ')}]).`,\n 'invalid_params',\n {\n code: 'unknown_tool_choice',\n issues: { requested: toolChoice.name, available: tools.map((t) => t.name) },\n },\n );\n }\n\n // Defaults to false when tools are set and the caller didn't say otherwise,\n // since forcing a JSON response format alongside tool calling is unreliable\n // across providers.\n const jsonModeExplicit = params.jsonMode;\n const jsonMode = jsonModeExplicit ?? (tools ? false : true);\n\n // A client that can't honor `json_object` as a real constraint\n // (`supportsJsonObjectMode: false`, currently `fromAnthropic`/\n // `fromBedrock`) never receives it. An *explicit* `jsonMode: true`\n // still throws here, before the request ever reaches the client: the\n // caller asked for a guarantee this target can't provide, and staying\n // silent about that would be worse than the plain-text fallback below.\n if (!this.supportsJsonObjectMode && !jsonSchema && jsonModeExplicit === true) {\n throw new LLMError(\n 'jsonMode: true was set explicitly, but this client does not support ' +\n '`response_format: \"json_object\"` (see LLMClient.supportsJsonObjectMode). Neither ' +\n 'Anthropic nor Bedrock has a field that mechanically guarantees JSON output for this ' +\n 'mode. Use `jsonSchema` instead, which maps to a real constraint on both.',\n 'invalid_params',\n );\n }\n\n // `schema` needs JSON parsing to run against something, so a *default*\n // (unset) `jsonMode` here is a real, if implicit, request for JSON\n // output, not a caller who's indifferent to it. Downgrading it to\n // plain text the way a schema-less default call is downgraded below\n // would silently skip validation instead of running it, and then blame\n // it on a `jsonMode: false` the caller never actually set (see the\n // `params.schema && !useJson` check further down, whose message\n // assumes the caller chose `jsonMode: false`). Fail loudly instead,\n // before the request is sent, naming the real cause.\n if (\n !this.supportsJsonObjectMode &&\n !jsonSchema &&\n jsonModeExplicit === undefined &&\n params.schema\n ) {\n throw new LLMError(\n '`schema` was provided, which requires JSON output to validate against, but this client ' +\n 'does not support `response_format: \"json_object\"` (see LLMClient.supportsJsonObjectMode) ' +\n 'and no `jsonSchema` was set. Neither Anthropic nor Bedrock has a field that mechanically ' +\n 'guarantees JSON output without one. Use `jsonSchema` instead, which maps to a real ' +\n 'constraint on both and still runs `schema` against its parsed result.',\n 'invalid_params',\n );\n }\n\n // A *default* (unset) `jsonMode` with no `schema` to satisfy, which\n // resolves to `true` on every plain call with no `tools`, is silently\n // downgraded to plain text instead of throwing: this is what keeps\n // `llm.call({ userContent })` working out of the box on\n // Anthropic/Bedrock exactly as it did before `json_object` support was\n // removed from those two adapters, for anyone not relying on JSON\n // output they never actually asked for.\n const jsonModeEffective =\n !this.supportsJsonObjectMode && !jsonSchema && jsonModeExplicit === undefined\n ? false // downgrade: default jsonMode, no jsonSchema, no schema to validate either\n : jsonMode;\n\n const useJson = jsonModeEffective || Boolean(jsonSchema);\n\n if (params.schema && !useJson) {\n throw new LLMError(\n 'schema was provided but jsonMode: false disables JSON parsing, so nothing would validate it. Remove jsonMode: false, set jsonSchema, or remove schema.',\n 'invalid_params',\n );\n }\n\n const responseFormat = this.buildResponseFormat(jsonSchema, useJson);\n\n this.validateHistory(history);\n\n const request = {\n model,\n ...(temperature !== null ? { temperature } : {}),\n max_tokens: maxTokens,\n ...(responseFormat ? { response_format: responseFormat } : {}),\n ...(reasoningEffort ? { reasoning_effort: reasoningEffort } : {}),\n ...(budgetTokens !== undefined && budgetTokens !== null\n ? { budget_tokens: budgetTokens }\n : {}),\n ...(tools ? { tools: toWireTools(tools) } : {}),\n ...(tools ? { tool_choice: this.buildWireToolChoice(toolChoice) } : {}),\n messages: [\n ...(systemPrompt ? [{ role: 'system' as const, content: systemPrompt }] : []),\n ...history.flatMap((turn): WireMessage[] => this.turnToWireMessages(turn)),\n { role: 'user' as const, content: userContent },\n ] satisfies WireMessage[],\n };\n\n return { useJson, model, request };\n }\n\n /**\n * Validates `history` alternates user/assistant turns, since providers\n * like Anthropic/Gemini reject or mishandle consecutive same-role turns.\n */\n private validateHistory(history: ConversationTurn[]): void {\n let previousTurn: ConversationTurn | undefined;\n\n for (const [index, turn] of history.entries()) {\n if (turn.role === 'tool') {\n if (previousTurn?.role !== 'assistant' || !previousTurn.toolCalls?.length) {\n throw new LLMError(\n `history[${index}] is a \"tool\" turn, but must immediately follow an \"assistant\" turn that requested tools`,\n 'invalid_params',\n );\n }\n\n if (!turn.toolResults?.length) {\n throw new LLMError(\n `history[${index}] is a \"tool\" turn but has no toolResults`,\n 'invalid_params',\n );\n }\n\n const requestedIds = new Set(previousTurn.toolCalls.map((tc) => tc.id));\n const resultIds = turn.toolResults.map((tr) => tr.toolCallId);\n\n const unknownIds = resultIds.filter((id) => !requestedIds.has(id));\n\n if (unknownIds.length) {\n throw new LLMError(\n `history[${index}].toolResults references unknown toolCallId(s) [${unknownIds.join(', ')}]`,\n 'invalid_params',\n { code: 'unknown_tool_result_ids', issues: { historyIndex: index, ids: unknownIds } },\n );\n }\n\n // Catches a duplicated toolCallId that would otherwise mask a different call's missing result.\n const seenIds = new Set<string>();\n const duplicateIds = new Set<string>();\n\n for (const id of resultIds) {\n if (seenIds.has(id)) duplicateIds.add(id);\n seenIds.add(id);\n }\n\n if (duplicateIds.size) {\n throw new LLMError(\n `history[${index}].toolResults has duplicate toolCallId(s) [${[...duplicateIds].join(', ')}]`,\n 'invalid_params',\n {\n code: 'duplicate_tool_result_ids',\n issues: { historyIndex: index, ids: [...duplicateIds] },\n },\n );\n }\n\n const missingIds = [...requestedIds].filter((id) => !resultIds.includes(id));\n\n if (missingIds.length) {\n throw new LLMError(\n `history[${index}] is missing toolResults for toolCallId(s) [${missingIds.join(', ')}]`,\n 'invalid_params',\n { code: 'missing_tool_results', issues: { historyIndex: index, ids: missingIds } },\n );\n }\n } else {\n if (turn.role === previousTurn?.role) {\n throw new LLMError(\n `history must alternate user/assistant turns: consecutive \"${turn.role}\" turns at history[${index - 1}] and history[${index}]`,\n 'invalid_params',\n );\n }\n\n if (previousTurn?.role === 'assistant' && previousTurn.toolCalls?.length) {\n throw new LLMError(\n `history[${index}] follows an assistant tool request without tool results`,\n 'invalid_params',\n );\n }\n }\n\n previousTurn = turn;\n }\n\n if (previousTurn?.role === 'assistant' && previousTurn.toolCalls?.length) {\n throw new LLMError(\n 'The last entry in history is an assistant tool request without tool results',\n 'invalid_params',\n );\n }\n\n if (previousTurn?.role === 'user') {\n throw new LLMError(\n 'The last entry in history is a \"user\" turn, which would collide with the current userContent turn.',\n 'invalid_params',\n );\n }\n }\n\n /** Maps VernLLM's app-facing `ToolChoice` onto the OpenAI-shaped wire `tool_choice`. */\n private buildWireToolChoice(toolChoice: CallParams<unknown>['toolChoice']): WireToolChoice {\n if (!toolChoice || toolChoice === 'auto') return 'auto';\n if (toolChoice === 'none' || toolChoice === 'required') return toolChoice;\n\n return { type: 'function', function: { name: toolChoice.name } };\n }\n\n /**\n * Expands one `ConversationTurn` into one or more wire messages. Plain\n * user/assistant turns map 1:1. An assistant turn with `toolCalls` maps\n * to an assistant message carrying wire-shaped `tool_calls`. A `'tool'`\n * turn expands into one wire `tool` message per `toolResult`, since\n * OpenAI-shaped wire format wants one message per tool_call_id.\n */\n private turnToWireMessages(turn: ConversationTurn): WireMessage[] {\n if (turn.role === 'tool') {\n return (turn.toolResults ?? []).map((tr) => ({\n role: 'tool' as const,\n tool_call_id: tr.toolCallId,\n content: typeof tr.content === 'string' ? tr.content : JSON.stringify(tr.content ?? null),\n ...(tr.isError ? { is_error: true } : {}),\n }));\n }\n\n if (turn.role === 'assistant' && turn.toolCalls?.length) {\n return [\n {\n role: 'assistant' as const,\n ...(turn.content !== undefined\n ? { content: serializeAssistantContent(turn.content) }\n : {}),\n tool_calls: toWireToolCalls(turn.toolCalls),\n },\n ];\n }\n\n if (turn.role === 'assistant') {\n return [\n {\n role: 'assistant' as const,\n content: serializeAssistantContent(turn.content === undefined ? '' : turn.content),\n },\n ];\n }\n\n return [{ role: turn.role as 'user', content: turn.content ?? '' }];\n }\n\n /**\n * Chooses the response format: a provider-native `jsonSchema` takes\n * priority when supplied (constrains generation directly), otherwise\n * falls back to the looser `json_object` mode when JSON output is\n * requested, or no format at all for plain text responses.\n */\n private buildResponseFormat(jsonSchema: CallParams<unknown>['jsonSchema'], useJson: boolean) {\n if (jsonSchema) {\n return {\n type: 'json_schema' as const,\n json_schema: {\n name: jsonSchema.name,\n schema: jsonSchema.schema,\n strict: jsonSchema.strict ?? true,\n description: jsonSchema.description,\n },\n };\n }\n\n return useJson ? { type: 'json_object' as const } : undefined;\n }\n}\n","import { LLMError } from '../../types/errors.js';\nimport { normalizeError } from './errors.utils.js';\nimport { withChunkIdleTimeout } from './retry.utils.js';\n\nimport type { Logger } from '../../logger.js';\nimport type {\n CallWithToolsResult,\n StreamChunk,\n TokenUsage,\n WireStreamChunk,\n WireToolCall,\n} from '../../types/index.js';\n\n// Bound provider-controlled tool accumulation independently of the unread\n// chunk buffer: one stream can otherwise create unlimited map entries or\n// append unlimited argument text before finalization runs.\nconst MAX_TOOL_CALLS = 10_000;\nconst MAX_TOOL_ARGUMENTS_LENGTH = 1_000_000;\n\n/** Everything `buildStreamResult` needs beyond the raw iterator and first chunk. */\nexport interface StreamAccumulatorOptions<T> {\n requestId: string;\n model: string;\n providerName: string;\n /** Whether this attempt ran on a fallback target rather than the primary, mirroring `extractUsage`'s `usedFallback`. */\n isFallback: boolean;\n /** Per-call override, falling back to the instance default, mirroring every other per-call timeout. */\n chunkIdleTimeoutMs: number | undefined;\n streamController: AbortController;\n logger: Logger;\n /** External signal, forwarded to `normalizeError` so a transport error during an already-aborted call is reported as `'aborted'`, not whatever the transport itself threw. */\n signal?: AbortSignal;\n /**\n * Fires once, synchronously, right after the transport-level loop\n * finishes successfully, before `finalize` runs. Lets the caller record\n * circuit-breaker success and release rate-limiter capacity before the\n * (possibly failing) finalization step.\n */\n onStreamSuccess: (usage: TokenUsage | undefined) => void;\n /**\n * Fires once when the transport-level loop itself fails (idle timeout\n * or a transport error), before this stream's `finalResult` rejects.\n * `normalized.type === 'timeout'` is the one mid-stream failure that\n * should trip the breaker: otherwise a provider that hangs after one\n * chunk would always record a success and never open it.\n */\n onStreamFailure: (normalized: LLMError, usage: TokenUsage | undefined) => void;\n /**\n * Produces the final `T | CallWithToolsResult<T>` from the accumulated\n * text and tool-call deltas once the stream completes. Errors thrown\n * here are assumed already normalized and usage-failure-reported by the\n * caller (mirrors `finalizeResponse`'s own contract).\n */\n finalize: (\n textAcc: string,\n wireToolCalls: WireToolCall[] | undefined,\n usage: TokenUsage | undefined,\n ) => T | CallWithToolsResult<T>;\n}\n\n/**\n * The streaming accumulator: wraps the raw `WireStreamChunk` iterator in\n * an async generator that yields translated `StreamChunk`s to the caller\n * live, as they arrive, with no per-chunk timeout and no bound on total\n * duration, and accumulates text/tool-call deltas internally so that\n * `finalize` can produce `finalResult` once the stream completes.\n *\n * Two separate try/catches: the iteration loop's catch handles errors\n * the transport itself throws, which aren't normalized yet, so that\n * happens here, alongside the one `onStreamFailure` call for them. The\n * second catch, around `finalize`, does not re-normalize or re-report,\n * since `finalize`'s caller (`finalizeResponse`) already does both\n * internally.\n */\nexport function buildStreamResult<T>(\n iterator: AsyncIterator<WireStreamChunk>,\n first: IteratorResult<WireStreamChunk>,\n options: StreamAccumulatorOptions<T>,\n): { chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T | CallWithToolsResult<T>> } {\n const {\n requestId,\n model,\n providerName,\n isFallback,\n chunkIdleTimeoutMs,\n streamController,\n logger,\n signal,\n } = options;\n\n let resolveFinal!: (value: T | CallWithToolsResult<T>) => void;\n let rejectFinal!: (error: unknown) => void;\n\n const finalResult = new Promise<T | CallWithToolsResult<T>>((resolve, reject) => {\n resolveFinal = resolve;\n rejectFinal = reject;\n });\n\n // Avoid an unhandled-rejection warning for callers that only read `chunks`.\n finalResult.catch(() => {});\n\n // Push-based, not a pulled generator, so the pump always drives\n // `finalResult` to completion even if `chunks` is never read. Buffer\n // size (not \"has anyone started iterating yet\") is what caps memory,\n // since the pump can outrace the caller starting iteration.\n const MAX_BUFFERED_CHUNKS = 10_000;\n const buffered: StreamChunk[] = [];\n const pending: Array<{\n resolve: (result: IteratorResult<StreamChunk>) => void;\n reject: (error: unknown) => void;\n }> = [];\n let streamDone = false;\n let streamError: unknown;\n let hasLoggedEviction = false;\n\n const push = (chunk: StreamChunk) => {\n const waiter = pending.shift();\n\n if (waiter) {\n waiter.resolve({ done: false, value: chunk });\n return;\n }\n\n buffered.push(chunk);\n\n if (buffered.length > MAX_BUFFERED_CHUNKS * 2) {\n // Nothing else surfaces this: without a log, a caller that never\n // read (or fell behind on) `chunks` has no way to tell eviction,\n // not a provider or transport bug, is why chunks are missing.\n // Logged once per stream, not on every crossing, so an ignored\n // high-volume stream doesn't spam dozens of near-identical lines.\n if (!hasLoggedEviction) {\n hasLoggedEviction = true;\n logger.warn(\n `[VernLLM] stream chunk buffer exceeded cap (${MAX_BUFFERED_CHUNKS}), evicting ` +\n `${buffered.length - MAX_BUFFERED_CHUNKS} oldest chunk(s); buffered=${buffered.length}. ` +\n 'The chunks iterable was never read (or fell far behind) for this stream.',\n );\n }\n\n // Trim back down to the cap in one batch operation instead of\n // `shift()`ing a single element off on every push once the cap is\n // reached. A per-push `shift()` here is O(current length) in the\n // worst case, cheap for a handful of calls, but that cost is\n // paid on *every* push for the remainder of an ignored stream,\n // and its real-world cost isn't a stable, engine-independent\n // property: benchmarking this exact pattern at a similar backing\n // -array size showed multi-second stalls for what should be\n // sub-millisecond work. Letting the array grow to 2x the cap\n // before trimming amortizes the O(n) `splice` across\n // `MAX_BUFFERED_CHUNKS` pushes, so the average cost per push\n // stays O(1) regardless of how far past the cap the array is\n // allowed to grow before trimming.\n buffered.splice(0, buffered.length - MAX_BUFFERED_CHUNKS);\n }\n };\n\n const finish = () => {\n streamDone = true;\n\n for (const waiter of pending.splice(0)) {\n waiter.resolve({ done: true, value: undefined });\n }\n };\n\n const fail = (error: unknown) => {\n streamDone = true;\n streamError = error;\n\n for (const waiter of pending.splice(0)) {\n waiter.reject(error);\n }\n };\n\n const chunks: AsyncIterable<StreamChunk> = {\n [Symbol.asyncIterator]() {\n return {\n next(): Promise<IteratorResult<StreamChunk>> {\n if (buffered.length) {\n return Promise.resolve({ done: false, value: buffered.shift() as StreamChunk });\n }\n\n if (streamDone) {\n return streamError\n ? Promise.reject(streamError)\n : Promise.resolve({ done: true, value: undefined });\n }\n\n return new Promise((resolve, reject) => {\n pending.push({ resolve, reject });\n });\n },\n };\n },\n };\n\n const toolCallAcc = new Map<number, { id?: string; name?: string; args: string }>();\n\n let textAcc = '';\n let usage: TokenUsage | undefined;\n\n // Fires immediately, not lazily, so it always drives finalResult to\n // completion regardless of whether the caller reads chunks.\n void (async () => {\n try {\n let result: IteratorResult<WireStreamChunk> = first;\n\n while (!result.done) {\n const wireChunk = result.value;\n\n if (wireChunk.type === 'ping') {\n // No content to accumulate or push. Just resolving here\n // resets the idle-timeout clock on the next .next() call.\n } else if (wireChunk.type === 'text-delta') {\n textAcc += wireChunk.delta;\n push({ type: 'text-delta', delta: wireChunk.delta });\n } else if (wireChunk.type === 'tool_call_delta') {\n let entry = toolCallAcc.get(wireChunk.index);\n\n if (!entry) {\n // Check before creating the entry so an unbounded sequence of\n // provider-supplied indices cannot grow the map.\n if (toolCallAcc.size >= MAX_TOOL_CALLS) {\n throw new LLMError(\n `Stream contained more than ${MAX_TOOL_CALLS} distinct tool calls`,\n 'validation',\n );\n }\n\n entry = { args: '' };\n }\n\n const argumentsDelta = wireChunk.argumentsDelta ?? '';\n // Check before concatenation: string growth is the other unbounded\n // path, including when one delta is already very large.\n if (entry.args.length + argumentsDelta.length > MAX_TOOL_ARGUMENTS_LENGTH) {\n throw new LLMError(\n `Tool call arguments exceeded the ${MAX_TOOL_ARGUMENTS_LENGTH}-character stream limit`,\n 'validation',\n );\n }\n\n entry.id ??= wireChunk.id;\n entry.name ??= wireChunk.name;\n entry.args += argumentsDelta;\n toolCallAcc.set(wireChunk.index, entry);\n\n push({\n type: 'tool_call_delta',\n index: wireChunk.index,\n id: wireChunk.id,\n name: wireChunk.name,\n argsDelta: wireChunk.argumentsDelta,\n complete: wireChunk.complete,\n });\n } else if (wireChunk.type === 'usage') {\n const reasoningTokens = wireChunk.usage.completion_tokens_details?.reasoning_tokens;\n\n usage = {\n promptTokens: wireChunk.usage.prompt_tokens ?? 0,\n completionTokens: wireChunk.usage.completion_tokens ?? 0,\n totalTokens: wireChunk.usage.total_tokens ?? 0,\n ...(reasoningTokens !== undefined ? { reasoningTokens } : {}),\n requestId,\n model,\n provider: providerName,\n usedFallback: isFallback,\n };\n push({ type: 'usage', usage });\n }\n\n result = await withChunkIdleTimeout(\n () => iterator.next(),\n chunkIdleTimeoutMs,\n () => streamController.abort(),\n logger,\n );\n }\n } catch (error) {\n // Best-effort cleanup for a processing-time throw (as opposed to\n // `iterator.next()` rejecting, which usually means the adapter's\n // own generator already cleaned up). Two independent layers,\n // since neither is guaranteed to reach every SDK on its own:\n //\n // 1. `iterator.return()`: `iterator` is the async generator\n // returned by the adapter's `createStream`, and every\n // adapter's `createStream` body is a `for await...of` over\n // the SDK's raw stream. Calling `.return()` on a generator\n // suspended inside a `for await...of` forwards `.return()` to\n // the iterable being iterated, standard IteratorClose\n // behavior, so this one call closes the whole chain down to\n // the SDK's own stream, as long as the SDK's stream\n // implements `.return()` (true for every adapter here, see\n // the \"propagates .return()\" test in each adapter's stream\n // unit tests).\n // 2. `streamController.abort()`: aborts the same signal every\n // adapter received for this call. SDKs that honor an\n // AbortSignal for the life of the request, arguably the more\n // common pattern than implementing custom `.return()`\n // forwarding, get closed this way even if layer 1 has nothing\n // to forward to.\n try {\n await iterator.return?.();\n } catch {\n // Cleanup failing isn't the error being reported; swallow it.\n }\n streamController.abort();\n\n const normalized = normalizeError(error, signal);\n\n try {\n options.onStreamFailure(normalized, usage);\n } catch {\n // A throwing callback must not stop fail/rejectFinal from settling\n // the promises below; the stream failure itself is still reported.\n }\n\n fail(normalized);\n rejectFinal(normalized);\n\n return;\n }\n\n finish();\n\n try {\n options.onStreamSuccess(usage);\n } catch {\n // A throwing callback must not stop finalize/resolveFinal below from\n // running; the stream itself still completed successfully.\n }\n\n try {\n const wireToolCalls: WireToolCall[] | undefined = toolCallAcc.size\n ? [...toolCallAcc.entries()]\n .sort(([indexA], [indexB]) => indexA - indexB)\n .map(([, entry]) => ({\n id: entry.id ?? '',\n type: 'function' as const,\n function: { name: entry.name ?? '', arguments: entry.args },\n }))\n : undefined;\n\n const finalized = options.finalize(textAcc, wireToolCalls, usage);\n\n resolveFinal(finalized);\n } catch (error) {\n // finalize's caller has already normalized this error and\n // reported the usage failure internally. Just propagate it.\n rejectFinal(error);\n }\n })();\n\n return { chunks, finalResult };\n}\n","import { CircuitBreaker } from '../../circuitBreaker.js';\nimport { LLMError, toRequestSnapshot, type LLMRequestSnapshot } from '../../types/errors.js';\nimport { makeEventReporter } from '../circuitBreaker.utils.js';\nimport { describeError, extractStatus, normalizeError } from './errors.utils.js';\nimport { defaultParseJson } from './parse.utils.js';\nimport { RequestBuilder } from './requestBuilder.js';\nimport { extractRetryAfterMs, getBackoffDelay, waitForRetry, withTimeout } from './retry.utils.js';\nimport { buildStreamResult } from './streamAccumulator.js';\nimport { parseWireToolCalls } from './wire.utils.js';\n\nimport type { Logger } from '../../logger.js';\nimport type { RateLimiter } from '../../rateLimit.js';\nimport type {\n CallParams,\n CallWithToolsResult,\n LLMClient,\n RetryAttempt,\n StreamChunk,\n TokenUsage,\n ToolIssue,\n VernLLMEvent,\n WireToolCall,\n} from '../../types/index.js';\n\n/**\n * `executeCall`/`executeStreamCall` call `onRequest` with a fully built\n * `LLMRequestSnapshot`, right after the outgoing payload is built and\n * before dispatch (rate limiting, `client.chat.completions.create`, etc).\n * Building the complete, cloned snapshot at this point, not later once an\n * attempt has failed, matters for two reasons: `startedAt` should mean\n * \"when the attempt started\", not \"when the failure was handled\", and\n * some adapters mutate the outgoing request object during dispatch itself\n * (e.g. `fromGemini` sets `request.config` in place inside `create()`),\n * so waiting until the catch block to snapshot could capture a payload\n * that had already changed since it was actually sent.\n */\ntype OnRequest = (snapshot: LLMRequestSnapshot) => void;\n\n/**\n * Identity function with its own parameter, used only to sidestep a TS\n * quirk: a `let` reassigned solely inside a nested closure (like\n * `retryWithBackoff`'s `onRequest`) gets narrowed to `undefined` at the\n * point it was last synchronously assigned, which would otherwise make\n * `lastRequestForAttempt` read as `never` at the point it's used below.\n */\nfunction passThroughRequestSnapshot(\n snapshot: LLMRequestSnapshot | undefined,\n): LLMRequestSnapshot | undefined {\n return snapshot;\n}\n\n/** Everything one `CallExecutor` needs beyond the client and model. */\nexport interface CallExecutorOptions {\n maxRetries: number;\n timeoutMs: number;\n chunkIdleTimeoutMs: number;\n baseDelayMs: number;\n defaultMaxTokens: number;\n defaultTemperature: number | null;\n defaultReasoningEffort?: 'minimal' | 'low' | 'medium' | 'high';\n defaultBudgetTokens?: number;\n nonRetryableStatus: number[];\n parseJson?: (content: string) => unknown;\n logger: Logger;\n /** Applied to model output before it reaches the debug logger. See `VernLLMOptions.redact`. */\n redact?: (text: string) => string;\n onUsage?: (usage: TokenUsage) => void;\n onUsageFailure?: (usage: TokenUsage, error: LLMError) => void;\n onEvent?: (event: VernLLMEvent) => void;\n breaker?: CircuitBreaker;\n limiter?: RateLimiter;\n /** True for every target after the primary. Stamped onto reported `TokenUsage`. */\n isFallback?: boolean;\n}\n\n/**\n * Everything one provider target needs to attempt a call: request\n * building, retry with backoff, the per-target breaker, the per-target\n * limiter. Never exported publicly. `VernLLM` holds one per target and\n * owns the fallback loop and caching on top.\n */\nexport class CallExecutor {\n private readonly maxRetries: number;\n private readonly timeoutMs: number;\n private readonly chunkIdleTimeoutMs: number;\n private readonly baseDelayMs: number;\n private readonly nonRetryableStatus: number[];\n private readonly parseJson: (content: string) => unknown;\n private readonly logger: Logger;\n private readonly redact?: (text: string) => string;\n private readonly onUsage?: (usage: TokenUsage) => void;\n private readonly onUsageFailure?: (usage: TokenUsage, error: LLMError) => void;\n private readonly reportEvent: (event: VernLLMEvent) => void;\n private readonly breaker?: CircuitBreaker;\n private readonly limiter?: RateLimiter;\n private readonly isFallback: boolean;\n private readonly requestBuilder: RequestBuilder;\n\n constructor(\n readonly providerName: string,\n private readonly client: LLMClient,\n readonly model: string,\n options: CallExecutorOptions,\n ) {\n this.maxRetries = options.maxRetries;\n this.timeoutMs = options.timeoutMs;\n this.chunkIdleTimeoutMs = options.chunkIdleTimeoutMs;\n this.baseDelayMs = options.baseDelayMs;\n this.nonRetryableStatus = options.nonRetryableStatus;\n this.parseJson = options.parseJson ?? defaultParseJson;\n this.logger = options.logger;\n this.redact = options.redact;\n this.onUsage = options.onUsage;\n this.onUsageFailure = options.onUsageFailure;\n this.reportEvent = makeEventReporter(options.onEvent, this.logger);\n this.breaker = options.breaker;\n this.limiter = options.limiter;\n this.isFallback = options.isFallback ?? false;\n this.requestBuilder = new RequestBuilder({\n model,\n defaultMaxTokens: options.defaultMaxTokens,\n defaultTemperature: options.defaultTemperature,\n defaultReasoningEffort: options.defaultReasoningEffort,\n defaultBudgetTokens: options.defaultBudgetTokens,\n supportsJsonObjectMode: client.supportsJsonObjectMode ?? true,\n });\n }\n\n getCircuitState(model?: string) {\n return this.breaker?.getState(model);\n }\n\n /** Whether this target's breaker tracks failures per model. `false` if no breaker is configured. */\n get isolateByModel(): boolean {\n return this.breaker?.isolateByModel ?? false;\n }\n\n /** Manually opens this target's circuit breaker, if one is configured. No-op otherwise. */\n openCircuit(model?: string): void {\n this.breaker?.open(model);\n }\n\n /** Manually closes this target's circuit breaker, if one is configured. No-op otherwise. */\n closeCircuit(model?: string): void {\n this.breaker?.close(model);\n }\n\n /**\n * Throws if the breaker is open for this target/model, exactly like the\n * check `run`/`runStream` used to make internally. Exposed so `VernLLM`\n * can gate on it before reserving usage, avoiding a reserve-then-refund\n * round trip on a call that was never going to be attempted. `assertClosed`\n * has a stateful side effect (claiming a half-open trial slot), so it must\n * run exactly once per logical call: `run`/`runStream` no longer call it\n * themselves, this is now the only call site.\n */\n assertBreakerClosed(model?: string): void {\n this.breaker?.assertClosed(model ?? this.model);\n }\n\n /**\n * Runs a single logical call against this target: retry with backoff,\n * normalized error on exhaustion. Mirrors the old `VernLLM.call`'s\n * non-streaming branch, minus cache/usage-reservation and the breaker\n * check, which stay one layer up since they aren't per-target concerns\n * (see `assertBreakerClosed`).\n */\n async run<T>(\n params: CallParams<T>,\n requestId: string,\n onAttempt?: () => void,\n ): Promise<T | CallWithToolsResult<T>> {\n const model = params.model ?? this.model;\n const attempts: RetryAttempt[] = [];\n\n try {\n return await this.retryWithBackoff(\n (attempt, onRequest) => this.executeCall(params, requestId, attempt, onRequest),\n requestId,\n model,\n params.signal,\n onAttempt,\n attempts,\n );\n } catch (error) {\n // `attempts` only holds prior attempts that were actually retried\n // past. It's `[]` when nothing was retried, so normalize that to\n // `undefined` per `LLMError.attempts`'s contract.\n const normalized = normalizeError(\n error,\n params.signal,\n attempts.length > 0 ? attempts : undefined,\n );\n\n if (this.countsTowardBreaker(normalized)) {\n this.breaker?.recordFailure(model);\n }\n\n this.logger.debug(`[VernLLM:${requestId}] error:\\n${this.redactText(describeError(error))}`);\n\n throw normalized;\n }\n }\n\n /** Streaming counterpart to `run`. Mirrors the old streaming branch of `VernLLM.call`. */\n async runStream<T>(\n params: CallParams<T>,\n requestId: string,\n onAttempt?: () => void,\n ): Promise<{\n chunks: AsyncIterable<StreamChunk>;\n finalResult: Promise<T | CallWithToolsResult<T>>;\n }> {\n const model = params.model ?? this.model;\n const attempts: RetryAttempt[] = [];\n\n try {\n return await this.retryWithBackoff(\n (attempt, onRequest) => this.executeStreamCall(params, requestId, attempt, onRequest),\n requestId,\n model,\n params.signal,\n onAttempt,\n attempts,\n );\n } catch (error) {\n // See the matching comment in `run`.\n const normalized = normalizeError(\n error,\n params.signal,\n attempts.length > 0 ? attempts : undefined,\n );\n\n if (this.countsTowardBreaker(normalized)) {\n this.breaker?.recordFailure(model);\n }\n\n this.logger.debug(\n `[VernLLM:${requestId}] stream-open error:\\n${this.redactText(describeError(error))}`,\n );\n\n throw normalized;\n }\n }\n\n /**\n * Performs a single attempt: builds the request (translating `tools` to\n * wire shape when present), dispatches it with a timeout, and shapes the\n * response into `T` or a `CallWithToolsResult<T>` when `params.tools` was\n * set. Throws on an empty response (no text and no tool_calls) so the\n * retry loop treats it like any other transient failure.\n */\n private async executeCall<T>(\n params: CallParams<T>,\n requestId: string,\n attempt: number,\n onRequest?: OnRequest,\n ): Promise<T | CallWithToolsResult<T>> {\n const { useJson, model, request } = this.requestBuilder.build(params);\n\n onRequest?.(toRequestSnapshot(this.providerName, model, request, undefined, Date.now()));\n\n // A retry is a real request, so capacity is acquired per attempt\n // (inside the retry loop, via `executeCall` being re-invoked), not\n // once for the whole call.\n let release: ((actualTokens?: number) => void) | undefined;\n\n if (this.limiter) {\n const acquired = await this.limiter.acquire(this.limiter.estimate(request), params.signal);\n release = acquired.release;\n\n if (acquired.waitedMs > 0) {\n this.reportEvent({\n kind: 'rate_limited',\n requestId,\n provider: this.providerName,\n model,\n waitedMs: acquired.waitedMs,\n reason: acquired.reason ?? 'rpm',\n });\n }\n }\n\n try {\n const response = await withTimeout(\n (attemptSignal) => this.client.chat.completions.create(request, { signal: attemptSignal }),\n this.timeoutMs,\n params.signal,\n );\n\n // Extracted right after the response arrives, before anything else\n // touches it, so a post-response failure still gets its usage reported.\n const usage = this.extractUsage(response, requestId, model);\n\n // Reconcile against real usage, then hand off so `finally` below\n // can't release a second time.\n release?.(this.actualTokensFor(usage));\n release = undefined;\n\n // Raw and unvalidated on purpose. Extraction (including `.trim()`,\n // which throws on a non-string `content`) happens inside\n // `finalizeResponse`'s try/catch, so a malformed response still gets\n // normalized and its usage failure reported.\n const rawContent = response.choices?.[0]?.message?.content;\n const wireToolCalls = response.choices?.[0]?.message?.tool_calls;\n\n return this.finalizeResponse(\n rawContent,\n wireToolCalls,\n params,\n useJson,\n model,\n usage,\n requestId,\n attempt,\n );\n } finally {\n release?.();\n }\n }\n\n /** Applies `redact` (if configured); otherwise returns `text` unchanged. */\n private redactText(text: string): string {\n return this.redact ? this.redact(text) : text;\n }\n\n /**\n * Applies `redact` (if configured) to whatever the debug log is about\n * to show: real content when there is any, otherwise the tool-call\n * placeholder, which carries no user data and passes through\n * `redact` unchanged in practice but is included for a caller whose\n * `redact` does something structural (e.g. adding a marker) rather\n * than just scrubbing PII.\n */\n private redactedOutput(\n content: string | undefined,\n wireToolCalls: WireToolCall[] | undefined,\n ): string {\n return this.redactText(content ?? `[${wireToolCalls?.length ?? 0} tool call(s)]`);\n }\n\n /**\n * Shapes a fully-arrived response (content and/or tool_calls, already\n * extracted from the provider's payload) into `T` or a\n * `CallWithToolsResult<T>`. Reused by the streaming path once it has\n * buffered the full text/tool-call deltas, so there's no separate\n * parsing/validation logic for streaming.\n *\n * Normalizes and reports usage failure on error itself, so every caller\n * gets identical error handling without duplicating it.\n */\n private finalizeResponse<T>(\n rawContent: string | null | undefined,\n wireToolCalls: WireToolCall[] | undefined,\n params: CallParams<T>,\n useJson: boolean,\n model: string,\n usage: TokenUsage | undefined,\n requestId: string,\n attempt: number,\n ): T | CallWithToolsResult<T> {\n try {\n // `.trim()` runs inside this try: a malformed response shape\n // (e.g. a non-string `content`) throws here and is normalized and\n // reported like any other post-response failure.\n const content = rawContent?.trim();\n\n if (!content && !wireToolCalls?.length) {\n throw new LLMError('Empty LLM response', 'api', { code: 'empty_response' });\n }\n\n this.logger.debug(\n `[VernLLM:${requestId}] output:\\n${this.redactedOutput(content, wireToolCalls).slice(0, 800)}`,\n );\n\n if (wireToolCalls?.length) {\n if (!params.tools) {\n // Same class of problem as the other tool-contract codes below:\n // a provider contract violation, not an HTTP failure, so this is\n // `type: 'validation'` rather than `'api'`. Byte-for-byte\n // identical on retry, so not retryable.\n throw new LLMError(\n 'Provider returned tool_calls but no `tools` were sent with this call.',\n 'validation',\n { code: 'unexpected_tool_calls' },\n );\n }\n\n if (params.toolChoice === 'none') {\n // `toolChoice: 'none'` is what lets `call()`'s type narrow to\n // `ContentResult<T>` (see `ToolsDisabledCallParams`). A\n // nonconforming provider/adapter returning tool_calls anyway\n // would silently break that guarantee for the caller, so this\n // is treated as a hard API-contract violation rather than\n // passed through as a normal tool_calls result. The request\n // itself is byte-for-byte identical on retry, so this repeats\n // deterministically like the other tool-contract failures\n // below: not retryable, and not the provider being unhealthy.\n throw new LLMError(\n \"Provider returned tool_calls despite toolChoice: 'none'.\",\n 'validation',\n {\n code: 'tool_choice_none_violated',\n },\n );\n }\n\n const toolCalls = parseWireToolCalls(wireToolCalls);\n\n this.validateToolCallArguments(toolCalls, params.tools);\n this.breaker?.recordSuccess(model);\n this.reportUsage(usage);\n\n return { type: 'tool_calls', toolCalls, ...(content ? { content } : {}) };\n }\n\n // No tool_calls here, so content must be present.\n const textContent = content ?? '';\n\n if (!useJson) {\n this.breaker?.recordSuccess(model);\n this.reportUsage(usage);\n\n return params.tools ? { type: 'content', content: textContent as T } : (textContent as T);\n }\n\n const result = this.parseAndValidate<T>(textContent, params.schema);\n this.breaker?.recordSuccess(model);\n this.reportUsage(usage);\n\n return params.tools ? { type: 'content', content: result } : result;\n } catch (error) {\n // Normalized first so onUsageFailure always gets a real LLMError.\n // Also covers aborted signals: normalizeError returns type\n // 'aborted' in that case.\n const normalized = normalizeError(error, params.signal);\n\n if (usage && normalized.type !== 'aborted') {\n this.reportUsageFailure(usage, normalized, attempt);\n }\n\n throw normalized;\n }\n }\n\n /**\n * Opens a stream for a single attempt: builds the request exactly like\n * `executeCall`, then requires `createStream` on the client (a clear\n * `validation` error if the adapter doesn't support it). The timeout\n * wraps stream construction and the first `.next()` together, not just\n * construction: calling an `async function*` returns an iterator\n * synchronously without running its body until `.next()` is first\n * invoked, so timing only construction would time an operation that's\n * always instant, not the actual connection. Both are folded into a\n * single `withTimeout` so the same abort signal reaches whatever the\n * adapter's `createStream` uses internally for its first network\n * round-trip.\n *\n * Circuit-breaker success is recorded once the stream fully completes,\n * not on the first chunk arriving, so a connection that opens but then\n * dies mid-stream isn't masked as a success (see `buildStreamResult`).\n */\n private async executeStreamCall<T>(\n params: CallParams<T>,\n requestId: string,\n attempt: number,\n onRequest?: OnRequest,\n ): Promise<{\n chunks: AsyncIterable<StreamChunk>;\n finalResult: Promise<T | CallWithToolsResult<T>>;\n }> {\n const { useJson, model, request } = this.requestBuilder.build(params);\n\n onRequest?.(toRequestSnapshot(this.providerName, model, request, undefined, Date.now()));\n\n const completions = this.client.chat.completions;\n\n if (!completions.createStream) {\n throw new LLMError(\n 'stream: true requires a client/adapter with createStream',\n 'invalid_params',\n {\n code: 'unsupported_capability',\n issues: { capability: 'createStream' },\n },\n );\n }\n\n const createStream = completions.createStream.bind(completions);\n\n // A stream holds a real connection for its whole life, so its\n // capacity is released on completion (in `buildStreamResult`), not\n // once opening succeeds.\n let release: ((actualTokens?: number) => void) | undefined;\n\n if (this.limiter) {\n const acquired = await this.limiter.acquire(this.limiter.estimate(request), params.signal);\n release = acquired.release;\n\n if (acquired.waitedMs > 0) {\n this.reportEvent({\n kind: 'rate_limited',\n requestId,\n provider: this.providerName,\n model,\n waitedMs: acquired.waitedMs,\n reason: acquired.reason ?? 'rpm',\n });\n }\n }\n\n // One controller for the entire stream, not just opening it. Adapters\n // already thread this signal into their transport for the life of the\n // request (that's how user-initiated cancellation works today), so\n // reusing it for the idle timeout means the same abort() call that\n // fires when the stream goes idle mid-way also tears down the\n // underlying connection, instead of only rejecting VernLLM's own\n // promise while the transport stays open.\n const streamController = new AbortController();\n const combinedExternal = params.signal\n ? AbortSignal.any([params.signal, streamController.signal])\n : streamController.signal;\n\n try {\n const { iterator, first } = await withTimeout(\n async (attemptSignal) => {\n const streamIterator = createStream(request, { signal: attemptSignal })[\n Symbol.asyncIterator\n ]();\n const firstResult = await streamIterator.next();\n\n return { iterator: streamIterator, first: firstResult };\n },\n this.timeoutMs,\n combinedExternal,\n );\n\n // An immediately-exhausted stream (no chunks at all) is the streaming\n // equivalent of `executeCall`'s empty-response check: surface the same\n // `LLMError('Empty LLM response', 'api')` so retry behaves identically\n // whether the empty result came from a non-streaming or streaming\n // attempt.\n if (first.done) {\n throw new LLMError('Empty LLM response', 'api');\n }\n\n // Snapshotted before the closures below are created, since `release`\n // (the outer variable) is reassigned to undefined right after this\n // call to hand ownership off. The callbacks only run later, once the\n // stream completes, so closing over the mutable variable itself\n // would see that later `undefined` instead of the value being\n // handed off.\n const releaseAtOpen = release;\n\n const result = buildStreamResult(iterator, first, {\n requestId,\n model,\n providerName: this.providerName,\n isFallback: this.isFallback,\n chunkIdleTimeoutMs: params.chunkIdleTimeoutMs ?? this.chunkIdleTimeoutMs,\n streamController,\n logger: this.logger,\n signal: params.signal,\n onStreamSuccess: (usage) => {\n this.breaker?.recordSuccess(model);\n releaseAtOpen?.(this.actualTokensFor(usage));\n },\n onStreamFailure: (normalized, usage) => {\n // Idle timeout is the one mid-stream failure that trips the\n // breaker: otherwise a provider that hangs after one chunk\n // would always record a success and never open it.\n if (normalized.type === 'timeout') {\n this.breaker?.recordFailure(model);\n }\n\n if (usage && normalized.type !== 'aborted') {\n this.reportUsageFailure(usage, normalized, attempt, true);\n }\n\n releaseAtOpen?.(this.actualTokensFor(usage));\n },\n finalize: (textAcc, wireToolCalls, usage) =>\n this.finalizeResponse(\n textAcc,\n wireToolCalls,\n params,\n useJson,\n model,\n usage,\n requestId,\n attempt,\n ),\n });\n\n // Ownership of `release` passes to `buildStreamResult` from here.\n release = undefined;\n\n return result;\n } finally {\n // Only reached if opening the stream itself threw; a successful\n // open hands `release` off above and leaves this a no-op.\n release?.();\n }\n }\n\n /**\n * Checks every `ToolCall` against the `tools` that were offered, catching\n * a hallucinated tool name and a duplicate call id before either reaches\n * the application's dispatch table, then runs each tool's\n * `argumentsSchema`, if present.\n *\n * Contract failures (unknown name, duplicate id) are collected across\n * every call and thrown together as one `type: 'validation'` error with\n * `issues: ToolIssue[]`, since retrying a request that already has these\n * errors cannot help (excluded from retry by `type`) and a caller fixing\n * them wants to see every one, not just the first. Schema failures keep\n * the original single-error, `type: 'validation'` shape rather than being\n * folded into the aggregate, since they're a distinct failure kind from\n * the contract failures above.\n */\n private validateToolCallArguments(\n toolCalls: { id: string; name: string; arguments: unknown }[],\n tools: NonNullable<CallParams<unknown>['tools']>,\n ): void {\n const known = new Map(tools.map((t) => [t.name, t]));\n const seenIds = new Set<string>();\n const toolIssues: ToolIssue[] = [];\n\n for (const call of toolCalls) {\n if (seenIds.has(call.id)) {\n toolIssues.push({ name: call.name, toolCallId: call.id, code: 'duplicate_tool_call_id' });\n }\n seenIds.add(call.id);\n\n if (!known.has(call.name)) {\n toolIssues.push({ name: call.name, toolCallId: call.id, code: 'unknown_tool' });\n }\n }\n\n if (toolIssues.length > 0) {\n const unknownTool = toolIssues.find((i) => i.code === 'unknown_tool');\n const primary = unknownTool\n ? `Model requested tool \"${unknownTool.name}\", which was not in the tools offered ([${[...known.keys()].join(', ')}]).`\n : `Duplicate tool call id \"${toolIssues[0]!.toolCallId}\" in the model's response.`;\n\n // Most responses hit exactly one issue. When there's more than one,\n // say so, since toolCalls[0]'s problem alone would otherwise read as\n // the whole story.\n const message =\n toolIssues.length > 1\n ? `${primary} (${toolIssues.length} tool call issues total, see error.issues.)`\n : primary;\n\n throw new LLMError(message, 'validation', {\n code: unknownTool ? 'unknown_tool' : 'duplicate_tool_call_id',\n issues: toolIssues,\n });\n }\n\n for (const call of toolCalls) {\n const definition = known.get(call.name);\n\n if (!definition?.argumentsSchema) continue;\n\n const result = definition.argumentsSchema.safeParse(call.arguments);\n\n if (!result.success) {\n throw new LLMError(\n `Arguments for tool call \"${call.name}\" failed validation`,\n 'validation',\n {\n issues: result.error,\n },\n );\n }\n }\n }\n\n /**\n * Runs `fn`, retrying with backoff according to `shouldRetry`. When\n * `attempts` is given, every failed attempt that is actually followed by\n * a retry is recorded, in order. This mirrors `LLMError.attempts`'s\n * contract: every attempt made before this error was thrown. The\n * terminal failure is never pushed since it isn't a prior attempt, it\n * is the error being thrown. `attempts` stays empty when nothing was\n * retried, so no separate bookkeeping is needed at the call sites.\n * Each failure is recorded as a snapshot (`LLMError.toSnapshot()`),\n * not the live `LLMError`, per `RetryAttempt`'s contract.\n */\n private async retryWithBackoff<T>(\n fn: (attempt: number, onRequest: OnRequest) => Promise<T>,\n requestId: string,\n model: string,\n signal?: AbortSignal,\n onAttempt?: () => void,\n attempts?: RetryAttempt[],\n ): Promise<T> {\n let lastError: unknown;\n let lastRequestForAttempt: LLMRequestSnapshot | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n // Reset before this iteration's own onRequest can run. If this\n // attempt fails before onRequest is ever called (e.g. thrown by\n // recoverDelay or onAttempt, before fn/onRequest runs), the\n // previous attempt's request must not be misattributed to this\n // attempt's index below.\n lastRequestForAttempt = undefined;\n\n try {\n if (attempt > 0) {\n await this.recoverDelay(requestId, model, attempt, lastError, signal);\n }\n\n onAttempt?.();\n return await fn(attempt, (req) => {\n lastRequestForAttempt = req;\n });\n } catch (error) {\n lastError = error;\n\n const willRetry = attempt < this.maxRetries && this.shouldRetry(error, signal);\n if (!willRetry) break;\n\n attempts?.push({\n index: attempt,\n error: normalizeError(error, signal).toSnapshot(),\n request: passThroughRequestSnapshot(lastRequestForAttempt),\n });\n }\n }\n\n throw lastError;\n }\n\n /**\n * Pulls `TokenUsage` out of a raw response, if the provider reported it.\n * Extraction doesn't depend on what happens to the response afterward, so\n * a malformed body can still yield usage if the provider's usage block\n * itself came through intact.\n */\n private extractUsage(\n response: Awaited<ReturnType<LLMClient['chat']['completions']['create']>>,\n requestId: string,\n model: string,\n ): TokenUsage | undefined {\n if (!response.usage) return undefined;\n\n const reasoningTokens = response.usage.completion_tokens_details?.reasoning_tokens;\n\n return {\n promptTokens: response.usage.prompt_tokens ?? 0,\n completionTokens: response.usage.completion_tokens ?? 0,\n totalTokens: response.usage.total_tokens ?? 0,\n ...(reasoningTokens !== undefined ? { reasoningTokens } : {}),\n requestId,\n model,\n provider: this.providerName,\n usedFallback: this.isFallback,\n };\n }\n\n /**\n * The token count to reconcile the rate limiter against for a finished\n * attempt: `totalTokens` when reported, otherwise the sum of prompt and\n * completion tokens, matching `reportUsageFailure`'s own fallback below\n * for a hand-rolled client that reports the parts but omits the total.\n */\n private actualTokensFor(usage: TokenUsage | undefined): number | undefined {\n if (!usage) return undefined;\n return usage.totalTokens || usage.promptTokens + usage.completionTokens;\n }\n\n /** Reports token usage for a successful call, swallowing and logging any error `onUsage` throws. */\n private reportUsage(usage: TokenUsage | undefined): void {\n if (!usage || !this.onUsage) return;\n\n try {\n this.onUsage(usage);\n } catch (error) {\n this.logger.error('[VernLLM] onUsage failed', {\n message: error instanceof Error ? error.message : 'unknown',\n });\n }\n }\n\n /**\n * Reports token usage spent on an attempt that then failed, so it isn't\n * dropped alongside the error. Covers any error thrown after usage\n * extraction, since all of them happen only after a response (real\n * spend) already arrived. Swallows and logs any error `onUsageFailure`\n * itself throws.\n */\n private reportUsageFailure(\n usage: TokenUsage,\n error: LLMError,\n attempt: number,\n terminal = false,\n ): void {\n // Falls back to promptTokens + completionTokens if totalTokens is 0\n // (e.g. a hand-rolled client that omits the total), so the log\n // doesn't understate real spend.\n const displayTokens = usage.totalTokens || usage.promptTokens + usage.completionTokens;\n\n // A mid-stream failure is terminal for that call (no further attempts\n // for this stream), unlike a stream-open failure where attempt N+1 may\n // still follow. Label them differently so the log doesn't imply a\n // retry that isn't coming.\n const attemptText = terminal\n ? 'mid-stream failure (terminal, no further attempts)'\n : `attempt ${attempt + 1}/${this.maxRetries + 1}`;\n\n this.logger.warn(\n `[VernLLM:${usage.requestId}] usage failure, ${attemptText}: ` +\n `type=${error.type} tokens=${displayTokens}`,\n );\n\n if (!this.onUsageFailure) return;\n\n try {\n this.onUsageFailure(usage, error);\n } catch (hookError) {\n this.logger.error('[VernLLM] onUsageFailure failed', {\n message: hookError instanceof Error ? hookError.message : 'unknown',\n });\n }\n }\n\n /** Parses response content as JSON and validates it against `schema` when supplied. */\n private parseAndValidate<T>(content: string, schema?: CallParams<T>['schema']): T {\n let parsed: unknown;\n\n try {\n parsed = this.parseJson(content);\n } catch {\n throw new LLMError('Invalid JSON response', 'parse');\n }\n\n if (parsed === null || parsed === undefined) {\n throw new LLMError('Invalid JSON response', 'parse');\n }\n\n if (!schema) return parsed as T;\n\n const result = schema.safeParse(parsed);\n\n if (!result.success) {\n throw new LLMError('Schema validation failed', 'validation', { issues: result.error });\n }\n\n return result.data;\n }\n\n /**\n * Waits out the backoff delay for a retry attempt, honoring a\n * Retry-After header on the failed attempt's error when present.\n * Both Retry-After and plain exponential backoff are capped at the same\n * max delay (see `DEFAULT_MAX_DELAY_MS` in `retry.utils.ts`).\n */\n private async recoverDelay(\n requestId: string,\n model: string,\n attempt: number,\n error: unknown,\n signal?: AbortSignal,\n ) {\n const retryAfterMs = extractRetryAfterMs(error);\n const delay = retryAfterMs ?? getBackoffDelay(this.baseDelayMs, attempt);\n const retryAfterHonored = retryAfterMs !== undefined;\n\n this.logger.warn(\n `[VernLLM:${requestId}] recovery attempt ${attempt}/${this.maxRetries}, waiting ${Math.ceil(delay)}ms` +\n (retryAfterHonored ? ' (honoring Retry-After)' : ''),\n );\n\n this.reportEvent({\n kind: 'retry',\n requestId,\n provider: this.providerName,\n model,\n attempt,\n maxRetries: this.maxRetries,\n delayMs: delay,\n retryAfterHonored,\n error: normalizeError(error, signal),\n });\n\n await waitForRetry(delay, signal);\n }\n\n /** Decides whether a failed attempt is worth retrying. */\n private shouldRetry(error: unknown, signal?: AbortSignal): boolean {\n if (signal?.aborted) return false;\n\n // `LLMError.retryable` already covers the deterministic cases: parse/\n // validation/invalid_params/aborted types, the tool contract codes,\n // and the local rate-limit codes. Only `nonRetryableStatus`, specific\n // to this call, isn't part of that general-purpose property.\n if (error instanceof LLMError && !error.retryable) return false;\n\n const status = extractStatus(error);\n\n return !(status !== undefined && this.nonRetryableStatus.includes(status));\n }\n\n /**\n * Decides whether a failed attempt should count toward the circuit\n * breaker's failure threshold. A model hallucinating a tool name,\n * reusing a call id, or a provider ignoring `toolChoice: 'none'` isn't\n * the provider being unhealthy, it's a model/provider response defect\n * that will very likely recur regardless of provider health, so it\n * shouldn't push a healthy provider's circuit toward opening. Same for\n * a caller-input bug or a local rate-limit rejection: neither ever\n * reached the provider at all. This is exactly what `LLMError.retryable`\n * already excludes, so this defers to it directly.\n */\n private countsTowardBreaker(error: LLMError): boolean {\n return error.retryable;\n }\n}\n","import type { Logger } from '../logger.js';\n\n/**\n * Wraps a `Logger` so a throwing implementation can never break the call\n * it's trying to describe. `logger` is user-supplied (`VernLLMOptions.logger`),\n * so a custom logger that ships to a file, Datadog, etc. can throw for\n * reasons unrelated to VernLLM. Wrap once at construction so every\n * downstream `this.logger.warn(...)` call stays as-is and is safe by\n * construction, instead of guarding each call site individually.\n */\nexport function createSafeLogger(logger: Logger): Logger {\n return {\n debug: safe(logger, 'debug'),\n warn: safe(logger, 'warn'),\n error: safe(logger, 'error'),\n };\n}\n\nfunction safe<M extends 'debug' | 'warn' | 'error'>(logger: Logger, method: M): Logger[M] {\n const fn = (logger[method] as (...args: Parameters<Logger[M]>) => unknown).bind(logger);\n\n return ((...args: Parameters<Logger[M]>) => {\n try {\n swallowRejection(fn(...args));\n } catch {\n // a broken logger must never break the call it's describing\n }\n }) as Logger[M];\n}\n\nfunction isPromiseLike(value: unknown): value is PromiseLike<unknown> {\n return typeof (value as PromiseLike<unknown>)?.then === 'function';\n}\n\nfunction swallowRejection(result: unknown): void {\n if (isPromiseLike(result)) {\n Promise.resolve(result).catch(() => {\n // a broken logger must never break the call it's describing\n });\n }\n}\n","export interface Logger {\n debug(message: string): void;\n warn(message: string): void;\n error(message: string, meta?: Record<string, unknown>): void;\n}\n\n/**\n * Default logger. `debug` is gated by the `debug` option on VernLLM\n * warn/error always fire since they indicate real problems (retries, cache failures)\n */\nexport class ConsoleLogger implements Logger {\n constructor(private debugEnabled: boolean) {}\n\n debug(message: string): void {\n if (this.debugEnabled) console.debug(message);\n }\n\n warn(message: string): void {\n console.warn(message);\n }\n\n error(message: string, meta?: Record<string, unknown>): void {\n console.error(message, meta ?? '');\n }\n}\n","import { LLMError } from './types/errors.js';\n\nimport type { LLMClient } from './types/client.js';\n\n/** The request shape sent to `LLMClient['chat']['completions']['create']`, used for token estimation. */\nexport type WireRequest = Parameters<LLMClient['chat']['completions']['create']>[0];\n\n/** Which configured bucket is currently blocking a call. */\nexport type RateLimitReason = 'concurrency' | 'rpm' | 'tpm';\n\nexport interface RateLimitOptions {\n /** Max requests per minute. Omit for unlimited. */\n requestsPerMinute?: number;\n /**\n * Max tokens per minute. Enforced against a pre-flight estimate, then\n * reconciled against reported usage once the call completes. Omit for\n * unlimited.\n */\n tokensPerMinute?: number;\n /** Max requests in flight at once. Default 0, meaning unlimited. */\n maxConcurrent?: number;\n /**\n * Max time a call may sit queued waiting for capacity, in ms. Exceeding\n * it throws rather than hanging forever. Default 30000. Pass 0 to wait\n * indefinitely.\n */\n maxQueueMs?: number;\n /** Max queued calls before new ones reject immediately instead of queueing. Default 0, unbounded. */\n maxQueueSize?: number;\n /**\n * Pre-flight token estimate for `tokensPerMinute`. Defaults to a\n * chars/4 heuristic over message content plus `max_tokens`.\n */\n estimateTokens?: (request: WireRequest) => number;\n}\n\nexport interface RateLimitAcquireResult {\n /**\n * Releases the concurrency slot this attempt held and reconciles the\n * token bucket against real usage, when `actualTokens` is supplied.\n * Idempotent: only the first call does anything. Must run in a\n * `finally` block so a slot is never leaked on a failed attempt.\n */\n release: (actualTokens?: number) => void;\n /** How long this attempt waited in queue before capacity was available. */\n waitedMs: number;\n /** Which bucket was blocking this attempt just before it cleared, if any wait happened. */\n reason?: RateLimitReason;\n}\n\n/** Default `estimateTokens`: chars/4 over every message's content, plus the requested `max_tokens`. */\nexport function defaultEstimateTokens(request: WireRequest): number {\n const messagesChars = request.messages.reduce((sum, message) => {\n const content = (message as { content?: unknown }).content;\n\n if (typeof content === 'string') return sum + content.length;\n if (content === undefined || content === null) return sum;\n\n try {\n return sum + JSON.stringify(content).length;\n } catch {\n return sum;\n }\n }, 0);\n\n return Math.ceil(messagesChars / 4) + (request.max_tokens ?? 0);\n}\n\n/**\n * A capacity that refills continuously. Used for requests per minute and\n * tokens per minute, where `refillPerMs` is `capacity / 60000`, and for\n * concurrency, where `refillPerMs` is 0 and every release calls\n * `give(1)` instead of relying on the clock.\n */\nclass TokenBucket {\n private available: number;\n private lastRefill = Date.now();\n\n constructor(\n private readonly capacity: number,\n private readonly refillPerMs: number,\n ) {\n this.available = capacity;\n }\n\n private refill(): void {\n if (this.refillPerMs === 0) return;\n\n const now = Date.now();\n const elapsedMs = now - this.lastRefill;\n\n // A backward clock adjustment (NTP correction, VM migration, etc.)\n // makes `elapsedMs` negative, which would otherwise reduce `available`\n // on the next line, rate-limiting harder than configured for no\n // real-world reason. Treat a negative elapsed time as no time having\n // passed instead: `available` just doesn't grow this tick, rather\n // than shrinking, and `lastRefill` still advances so a subsequent\n // forward-moving `now` measures from here, not from the skewed past.\n this.available = Math.min(\n this.capacity,\n this.available + Math.max(0, elapsedMs) * this.refillPerMs,\n );\n this.lastRefill = now;\n }\n\n /** Refills, then takes `amount` if available. Leaves the bucket untouched if it can't. */\n tryTake(amount: number): boolean {\n this.refill();\n\n if (this.available < amount) return false;\n\n this.available -= amount;\n return true;\n }\n\n /**\n * Refills, then reports how many ms until this bucket could supply\n * `amount`, assuming nothing else takes from it meanwhile. Returns 0 if\n * it already can, `Infinity` if it never will on its own (a\n * concurrency bucket, `refillPerMs === 0`, only frees via `give`).\n */\n msUntilAvailable(amount: number): number {\n this.refill();\n\n if (this.available >= amount) return 0;\n if (this.refillPerMs === 0) return Infinity;\n\n return (amount - this.available) / this.refillPerMs;\n }\n\n /**\n * Gives capacity back. Not floored at 0: a bad token-usage estimate can\n * push `available` negative, and it self-corrects on the next refill\n * rather than being clamped away immediately. Only ceilinged at\n * `capacity`, so a give can never overfill the bucket.\n */\n give(amount: number): void {\n this.available = Math.min(this.capacity, this.available + amount);\n }\n\n /** The bucket's ceiling, e.g. so a request that could never fit can fail fast instead of queueing forever. */\n getCapacity(): number {\n return this.capacity;\n }\n}\n\n/**\n * `setTimeout` silently clamps any delay above this (~24.8 days) instead\n * of erroring, so an uncapped delay derived from a very small\n * `requestsPerMinute`/`tokensPerMinute` could wrap around to firing\n * almost immediately instead of waiting. Mirrors the same guard in\n * `withTimeout`/`withChunkIdleTimeout`.\n */\nconst MAX_WAKE_DELAY_MS = 2_147_483_647;\n\n/** One caller waiting for capacity, queued FIFO. */\ninterface Waiter {\n estimatedTokens: number;\n enqueuedAt: number;\n /** Reason recorded the last time this waiter was checked and found still blocked. */\n lastReason?: RateLimitReason;\n resolve: (result: RateLimitAcquireResult) => void;\n reject: (error: unknown) => void;\n}\n\n/**\n * Per-target rate limiter. Up to three buckets (requests/min, tokens/min,\n * concurrency) behind one FIFO queue, so a large call isn't starved by a\n * stream of small ones. Any bucket omitted from `options` has infinite\n * capacity and never blocks.\n */\nexport class RateLimiter {\n private readonly requests?: TokenBucket;\n private readonly tokens?: TokenBucket;\n private readonly concurrency?: TokenBucket;\n\n private readonly maxQueueMs: number;\n private readonly maxQueueSize: number;\n private readonly estimateTokensFn: (request: WireRequest) => number;\n\n private readonly queue: Waiter[] = [];\n\n /**\n * A single scheduled re-check for the head of the queue when it's\n * blocked on a bucket that refills on its own clock (rpm/tpm), so a\n * queue that nobody calls `acquire`/`release` on again isn't stuck\n * forever waiting for an external trigger to re-drain it. Not needed\n * for a concurrency block, which only clears via `release`.\n */\n private wakeTimer?: ReturnType<typeof setTimeout>;\n\n constructor(options: RateLimitOptions) {\n if (options.requestsPerMinute) {\n this.requests = new TokenBucket(\n options.requestsPerMinute,\n options.requestsPerMinute / 60_000,\n );\n }\n\n if (options.tokensPerMinute) {\n this.tokens = new TokenBucket(options.tokensPerMinute, options.tokensPerMinute / 60_000);\n }\n\n if (options.maxConcurrent) {\n this.concurrency = new TokenBucket(options.maxConcurrent, 0);\n }\n\n this.maxQueueMs = options.maxQueueMs ?? 30_000;\n this.maxQueueSize = options.maxQueueSize ?? 0;\n this.estimateTokensFn = options.estimateTokens ?? defaultEstimateTokens;\n }\n\n /** Pre-flight token estimate for a request, per the configured (or default) heuristic. */\n estimate(request: WireRequest): number {\n return this.estimateTokensFn(request);\n }\n\n /**\n * Waits for capacity in every configured bucket, then takes from each.\n * The returned `release` gives the concurrency slot back and reconciles\n * the token bucket against real usage; it must run in a `finally` block.\n */\n async acquire(estimatedTokens: number, signal?: AbortSignal): Promise<RateLimitAcquireResult> {\n if (signal?.aborted) {\n throw new LLMError('LLM request aborted', 'aborted');\n }\n\n // Guards `estimatedTokens` even on this directly-exported entry point\n // (not just the `VernLLM.executeCall`/`executeStreamCall` call sites):\n // an unchecked NaN or negative value would poison a bucket's\n // `available` permanently, since `NaN < amount` is always false and\n // would make `tryTake` wrongly report success forever after.\n if (!Number.isFinite(estimatedTokens) || estimatedTokens < 0) {\n throw new LLMError(\n `estimatedTokens must be a finite, non-negative number, got ${String(estimatedTokens)}`,\n 'invalid_params',\n );\n }\n\n // A request over the bucket's own ceiling can never be satisfied by\n // any amount of waiting, refill included, so failing fast here also\n // avoids permanently stalling every waiter queued behind it in FIFO.\n if (this.tokens && estimatedTokens > this.tokens.getCapacity()) {\n throw new LLMError(\n `estimatedTokens (${estimatedTokens}) exceeds the configured tokensPerMinute capacity (${this.tokens.getCapacity()}); this call could never acquire capacity.`,\n 'rate_limited',\n { code: 'rate_limit_capacity_exceeded' },\n );\n }\n\n // Fast path: nothing already queued, so try to go straight through\n // rather than paying queue bookkeeping for the common, uncontended case.\n if (this.queue.length === 0) {\n const attempt = this.tryAcquireBuckets(estimatedTokens);\n\n if (attempt.ok) {\n return { release: this.makeRelease(estimatedTokens), waitedMs: 0 };\n }\n\n // No maxQueueSize check needed here: the queue is empty (this\n // branch's own condition), so enqueueing this one waiter can never\n // exceed any maxQueueSize > 0. The check below only becomes\n // reachable once the queue is non-empty.\n return this.enqueue(estimatedTokens, attempt.reason, signal);\n }\n\n if (this.maxQueueSize > 0 && this.queue.length >= this.maxQueueSize) {\n throw this.queueFullError();\n }\n\n return this.enqueue(estimatedTokens, undefined, signal);\n }\n\n private queueFullError(): LLMError {\n return new LLMError('Rate limit queue is full', 'rate_limited', {\n code: 'rate_limit_queue_full',\n });\n }\n\n private enqueue(\n estimatedTokens: number,\n initialReason: RateLimitReason | undefined,\n signal?: AbortSignal,\n ): Promise<RateLimitAcquireResult> {\n return new Promise<RateLimitAcquireResult>((resolvePromise, rejectPromise) => {\n const waiter: Waiter = {\n estimatedTokens,\n enqueuedAt: Date.now(),\n lastReason: initialReason,\n resolve: (result) => {\n cleanup();\n resolvePromise(result);\n },\n reject: (error) => {\n cleanup();\n\n // The removed waiter may have been the head a wakeTimer was\n // scheduled around (or, for a concurrency block, the head with\n // no timer scheduled at all). Either way, re-drain immediately\n // so a successor with different requirements is evaluated now\n // instead of waiting on a stale timer or an unrelated\n // acquire/release call to trigger it.\n if (this.wakeTimer) {\n clearTimeout(this.wakeTimer);\n this.wakeTimer = undefined;\n }\n this.drain();\n\n rejectPromise(error);\n },\n };\n\n let queueTimer: ReturnType<typeof setTimeout> | undefined;\n\n const onAbort = () => {\n waiter.reject(new LLMError('LLM request aborted', 'aborted'));\n };\n\n const cleanup = () => {\n if (queueTimer) clearTimeout(queueTimer);\n signal?.removeEventListener('abort', onAbort);\n\n const index = this.queue.indexOf(waiter);\n if (index !== -1) this.queue.splice(index, 1);\n };\n\n if (this.maxQueueMs > 0) {\n queueTimer = setTimeout(() => {\n waiter.reject(\n new LLMError(\n 'Rate limit queue timed out before capacity was available',\n 'rate_limited',\n {\n code: 'rate_limit_queue_timeout',\n },\n ),\n );\n }, this.maxQueueMs);\n }\n\n signal?.addEventListener('abort', onAbort, { once: true });\n\n this.queue.push(waiter);\n this.drain();\n });\n }\n\n /**\n * Checks and takes from every configured bucket as one atomic unit: if\n * any bucket lacks capacity, whatever was already taken from the\n * earlier ones in this attempt is rolled back before reporting which\n * bucket blocked.\n */\n private tryAcquireBuckets(\n estimatedTokens: number,\n ): { ok: true } | { ok: false; reason: RateLimitReason } {\n const taken: Array<{ bucket: TokenBucket; amount: number }> = [];\n\n const take = (bucket: TokenBucket | undefined, amount: number) => {\n if (!bucket) return true;\n if (!bucket.tryTake(amount)) return false;\n\n taken.push({ bucket, amount });\n return true;\n };\n\n if (!take(this.concurrency, 1)) {\n return { ok: false, reason: 'concurrency' };\n }\n\n if (!take(this.requests, 1)) {\n for (const entry of taken) entry.bucket.give(entry.amount);\n return { ok: false, reason: 'rpm' };\n }\n\n if (!take(this.tokens, estimatedTokens)) {\n for (const entry of taken) entry.bucket.give(entry.amount);\n return { ok: false, reason: 'tpm' };\n }\n\n return { ok: true };\n }\n\n /** Drains the queue head first. Stops at the first waiter that still can't proceed, so no one is starved out of turn. */\n private drain(): void {\n while (this.queue.length > 0) {\n const waiter = this.queue[0] as Waiter;\n const attempt = this.tryAcquireBuckets(waiter.estimatedTokens);\n\n if (!attempt.ok) {\n waiter.lastReason = attempt.reason;\n this.scheduleWake(attempt.reason, waiter.estimatedTokens);\n return;\n }\n\n const waitedMs = Date.now() - waiter.enqueuedAt;\n\n waiter.resolve({\n release: this.makeRelease(waiter.estimatedTokens),\n waitedMs,\n reason: waiter.lastReason,\n });\n }\n }\n\n /**\n * Schedules a one-shot re-check of the queue for whenever the bucket\n * that's currently blocking the head waiter should next have enough\n * capacity. A no-op for a concurrency block (only `release` can clear\n * that) or while a wake is already pending.\n */\n private scheduleWake(reason: RateLimitReason, estimatedTokens: number): void {\n if (this.wakeTimer) return;\n\n const ms =\n reason === 'rpm'\n ? this.requests?.msUntilAvailable(1)\n : reason === 'tpm'\n ? this.tokens?.msUntilAvailable(estimatedTokens)\n : undefined;\n\n if (ms === undefined || !Number.isFinite(ms)) return;\n\n // Capped, not just clamped-by-omission: `drain()` re-derives the\n // real remaining wait from live bucket state on every firing (it\n // doesn't trust the delay that got it there), so a wake that fires\n // early because the true wait exceeded the cap just re-schedules\n // correctly from where the bucket actually is, rather than looping\n // on a delay that never shrinks.\n const delay = Math.min(Math.max(1, Math.ceil(ms)), MAX_WAKE_DELAY_MS);\n\n this.wakeTimer = setTimeout(() => {\n this.wakeTimer = undefined;\n this.drain();\n }, delay);\n }\n\n /**\n * Builds the one-shot release closure for an acquired slot. Only the\n * concurrency bucket is given back on release; the requests-per-minute\n * bucket is a real spend that only recovers via its own refill, and the\n * tokens bucket is reconciled against `actualTokens` rather than fully\n * refunded, since real tokens really were spent.\n */\n private makeRelease(estimatedTokens: number): (actualTokens?: number) => void {\n let released = false;\n\n return (actualTokens?: number) => {\n if (released) return;\n released = true;\n\n this.concurrency?.give(1);\n\n // An invalid `actualTokens` (e.g. NaN from a malformed usage\n // report) must not reach `give`: `Math.min(capacity, available +\n // NaN)` is NaN, and a NaN `available` poisons every future\n // `tryTake` on that bucket (any comparison against NaN is false,\n // so it would look permanently under capacity and rate limiting\n // would silently stop happening). Falling back to no reconciliation\n // at least keeps the estimated debit, the safe direction to err.\n if (this.tokens && actualTokens !== undefined && Number.isFinite(actualTokens)) {\n this.tokens.give(estimatedTokens - actualTokens);\n }\n\n this.drain();\n };\n }\n}\n","import { randomUUID } from 'crypto';\n\nimport { CacheOrchestrator } from './internal/cache/cacheOrchestrator.js';\nimport { buildCircuitBreaker, makeEventReporter } from './internal/circuitBreaker.utils.js';\nimport { CallExecutor } from './internal/execution/callExecutor.js';\nimport { normalizeError } from './internal/execution/errors.utils.js';\nimport { withReservedUsage, withReservedUsageForStream } from './internal/execution/usage.utils.js';\nimport { createSafeLogger } from './internal/logger.utils.js';\nimport { ConsoleLogger, type Logger } from './logger.js';\nimport { RateLimiter } from './rateLimit.js';\nimport {\n InMemoryCacheAdapter,\n LLMError,\n FallbackExhaustedError,\n defaultFallbackOn,\n type CachedCallParams,\n type CachedStreamCallParams,\n type CachedStreamConditionalToolCallParams,\n type CachedStreamConditionalStringToolCallParams,\n type CachedStreamToolCallParams,\n type CachedConditionalToolCallParams,\n type CachedConditionalStringToolCallParams,\n type CachedToolCallParams,\n type CachedJsonModeDisabledCallParams,\n type CachedJsonModeEnabledCallParams,\n type CallParams,\n type CallWithToolsResult,\n type ConditionalToolCallParams,\n type ConditionalStringToolCallParams,\n type ContentResult,\n type FallbackAttempt,\n type FallbackOn,\n type FallbackTarget,\n type JsonModeDisabledCallParams,\n type JsonModeEnabledCallParams,\n type JsonValue,\n type StreamCallResult,\n type StreamConditionalStringToolCallParams,\n type StreamJsonModeDisabledCallParams,\n type StreamJsonModeEnabledCallParams,\n type CachedStreamJsonModeDisabledCallParams,\n type CachedStreamJsonModeEnabledCallParams,\n type TargetCircuitState,\n type CircuitTarget,\n type StreamEnabledCallParams,\n type ToolDefinition,\n type ToolEnabledCallParams,\n type ToolsDisabledCallParams,\n type VernLLMEvent,\n type VernLLMOptions,\n} from './types/index.js';\n\nimport type { CircuitState } from './circuitBreaker.js';\nimport type { InternalCacheParams } from './internal/cache/cache.utils.js';\n\n/**\n * A LLM call framework for resilience, observability and control. This is VernLLM!\n *\n * Adds retry with backoff and jitter, per-attempt timeouts, an optional\n * circuit breaker, JSON parsing with optional schema validation, usage\n * tracking, and an optional response cache. All configurable, all opt-in\n * beyond sensible defaults.\n */\nexport class VernLLM {\n private readonly logger: Logger;\n\n /**\n * One `CallExecutor` per provider target: index 0 is the primary,\n * everything after it is a `fallback` target, in the order declared.\n * Each owns its own request building, retry/timeout, circuit breaker,\n * and rate limiter. `call()` walks this array in `runFallbackChain`,\n * moving to the next entry only when `fallbackOn` says to.\n */\n private readonly executors: CallExecutor[];\n\n /** Decides whether a failed target is followed by the next one or the chain stops. See `VernLLMOptions['fallbackOn']`. */\n private readonly fallbackOn: FallbackOn;\n\n /** Reports a `'fallback'` event when the chain moves to the next target. Shared `onEvent` plumbing, same as every executor's. */\n private readonly reportEvent: (event: VernLLMEvent) => void;\n\n /**\n * Owns cache key resolution, cache reads/writes, and in-flight\n * coalescing for `cachedCall()`. Independent of `executor`: it only\n * ever calls back into `this.call()` as an opaque function.\n */\n private readonly cacheOrchestrator: CacheOrchestrator;\n\n /**\n * @param options Client, model, and tunables. Defaults: `maxRetries` 1,\n * `timeoutMs` 25000, `baseDelayMs` 500, `defaultMaxTokens` 1000,\n * `defaultTemperature` 0.2, `cache` an in-memory adapter,\n * `nonRetryableStatus` `[400, 401, 403, 404, 422]`, `debug` false.\n */\n constructor(options: VernLLMOptions) {\n this.logger = createSafeLogger(options.logger ?? new ConsoleLogger(options.debug ?? false));\n\n const providerName = options.name ?? 'primary';\n\n this.cacheOrchestrator = new CacheOrchestrator(\n options.cache ?? new InMemoryCacheAdapter(),\n this.logger,\n );\n\n this.fallbackOn = options.fallbackOn ?? defaultFallbackOn;\n this.reportEvent = makeEventReporter(options.onEvent, this.logger);\n\n // The primary target's shared knobs, resolved once here rather than\n // inline in the retry-tunable default below, since fallback targets\n // that omit a field inherit this resolved value, not the raw\n // (possibly-undefined) option.\n const primaryDefaultTemperature =\n options.defaultTemperature === undefined ? 0.2 : options.defaultTemperature;\n const primaryDefaultReasoningEffort = options.defaultReasoningEffort;\n const primaryDefaultBudgetTokens = options.defaultBudgetTokens;\n\n // The primary, shaped like a `FallbackTarget` so it walks the same\n // build loop as every declared fallback target below. Its own\n // `circuitBreaker`/`rateLimit` are read directly off `options`\n // instead of this list, since only the primary carries them at the\n // top level (a `FallbackTarget`'s copies are genuinely independent,\n // never inherited, see `FallbackTarget`'s docs).\n const primaryTarget: FallbackTarget = {\n client: options.client,\n model: options.model,\n name: providerName,\n maxRetries: options.maxRetries,\n timeoutMs: options.timeoutMs,\n chunkIdleTimeoutMs: options.chunkIdleTimeoutMs,\n baseDelayMs: options.baseDelayMs,\n defaultMaxTokens: options.defaultMaxTokens,\n defaultTemperature: primaryDefaultTemperature,\n defaultReasoningEffort: primaryDefaultReasoningEffort,\n defaultBudgetTokens: primaryDefaultBudgetTokens,\n nonRetryableStatus: options.nonRetryableStatus,\n circuitBreaker: options.circuitBreaker,\n rateLimit: options.rateLimit,\n };\n\n const declaredFallbacks: FallbackTarget[] = Array.isArray(options.fallback)\n ? options.fallback\n : options.fallback\n ? [options.fallback]\n : [];\n\n const targets = [primaryTarget, ...declaredFallbacks];\n\n this.executors = targets.map((target, i) => {\n const isFallback = i > 0;\n // `-1` for the primary, matching `FallbackAttempt.index`.\n const name = target.name ?? (isFallback ? `fallback[${i - 1}]` : providerName);\n\n // Built before the executor: onStateChange fires from inside the\n // breaker itself, which the executor is merely handed a reference to.\n const breaker = buildCircuitBreaker(\n target.circuitBreaker,\n name,\n target.model,\n options.onEvent,\n this.logger,\n );\n\n return new CallExecutor(name, target.client, target.model, {\n maxRetries: target.maxRetries ?? options.maxRetries ?? 1,\n timeoutMs: target.timeoutMs ?? options.timeoutMs ?? 25_000,\n chunkIdleTimeoutMs: target.chunkIdleTimeoutMs ?? options.chunkIdleTimeoutMs ?? 30_000,\n baseDelayMs: target.baseDelayMs ?? options.baseDelayMs ?? 500,\n defaultMaxTokens: target.defaultMaxTokens ?? options.defaultMaxTokens ?? 1000,\n defaultTemperature:\n target.defaultTemperature === undefined\n ? primaryDefaultTemperature\n : target.defaultTemperature,\n defaultReasoningEffort:\n target.defaultReasoningEffort === undefined\n ? primaryDefaultReasoningEffort\n : target.defaultReasoningEffort,\n defaultBudgetTokens:\n target.defaultBudgetTokens === undefined\n ? primaryDefaultBudgetTokens\n : target.defaultBudgetTokens,\n nonRetryableStatus: target.nonRetryableStatus ??\n options.nonRetryableStatus ?? [400, 401, 403, 404, 422],\n parseJson: options.parseJson,\n logger: this.logger,\n redact: options.redact,\n onUsage: options.onUsage,\n onUsageFailure: options.onUsageFailure,\n onEvent: options.onEvent,\n breaker,\n limiter: target.rateLimit ? new RateLimiter(target.rateLimit) : undefined,\n isFallback,\n });\n });\n }\n\n /** Logs a failed refundUsage attempt via the configured logger. */\n private logRefundError(logMessage: string, error: unknown): void {\n this.logger.error(logMessage, {\n message: error instanceof Error ? error.message : 'unknown',\n });\n }\n\n /**\n * Walks `this.executors` in order, running `attempt` against each until\n * one succeeds or every target has failed. `run` on a lone target\n * (no `fallback` configured) throws exactly what it throws today: the\n * loop's single iteration path is unchanged from pre-fallback behavior.\n *\n * For streaming, `attempt` is `executor.runStream`, whose own retries\n * only cover *opening* the stream (see `CallExecutor.runStream`). A\n * mid-stream failure surfaces through `finalResult` after this function\n * has already returned, so it's never seen here and never falls over,\n * per the streaming limitation: splicing a second model's output into a\n * response the consumer has already partially rendered would corrupt\n * it.\n */\n private async runFallbackChain<R>(\n params: Pick<CallParams<unknown>, 'model' | 'signal'>,\n requestId: string,\n attempt: (executor: CallExecutor, onAttempt: () => void) => Promise<R>,\n skipBreakerCheckForFirst = false,\n ): Promise<{ result: R; executor: CallExecutor; index: number; attemptCount: number }> {\n const attempts: FallbackAttempt[] = [];\n\n for (let i = 0; i < this.executors.length; i++) {\n const executor = this.executors[i]!;\n const startedAt = Date.now();\n let attemptCount = 0;\n\n try {\n // Already checked once, before usage was reserved, when this is\n // the sole target (see `call()`). `assertClosed` claims a\n // half-open trial slot as a side effect on a non-throwing call,\n // so it must run exactly once per logical call: checking it\n // again here for the same executor could either falsely see\n // \"trial already in flight\" (from the check that just claimed\n // it) or double-claim a slot no concurrent caller actually has.\n if (!(i === 0 && skipBreakerCheckForFirst)) {\n executor.assertBreakerClosed(params.model);\n }\n\n const result = await attempt(executor, () => {\n attemptCount += 1;\n });\n return { result, executor, index: i, attemptCount };\n } catch (error) {\n const normalized = normalizeError(error, params.signal);\n\n attempts.push({\n index: i - 1,\n provider: executor.providerName,\n model: params.model ?? executor.model,\n // `.toSnapshot()`: this target's own `attempts` (from its own\n // retries, already snapshots per `CallExecutor`) come along\n // for free since `toSnapshot()` copies them as-is.\n error: normalized.toSnapshot(),\n });\n\n const isLast = i === this.executors.length - 1;\n // Always consult fallbackOn, including on the last target, so it\n // sees every failure and callers who log or count from inside it\n // get a complete picture. The chain still stops once the last\n // target fails regardless of what fallbackOn returns: there is no\n // next executor to fall over to.\n const policyDecision = this.fallbackOn(normalized, { isLastTarget: isLast });\n const decision = isLast ? 'stop' : policyDecision;\n\n if (decision === 'stop') {\n // A lone target (or a chain that stopped on its first failure)\n // throws its own error, unchanged from pre-fallback behavior.\n throw attempts.length > 1 ? new FallbackExhaustedError(attempts) : normalized;\n }\n\n const next = this.executors[i + 1]!;\n\n this.reportEvent({\n kind: 'fallback',\n requestId,\n from: executor.providerName,\n to: next.providerName,\n fromIndex: i - 1,\n toIndex: i,\n error: normalized,\n elapsedMs: Date.now() - startedAt,\n });\n }\n }\n\n // Unreachable: the loop above always either returns or throws before\n // running out of targets (the last iteration's `isLast` forces a\n // throw). Kept only to satisfy the return type.\n throw new LLMError('No provider targets configured', 'invalid_params');\n }\n\n /**\n * Makes a single logical LLM call, retrying on failure per the configured\n * policy. Fails fast if the breaker is open or the signal is already\n * aborted. Rejects with a normalized LLMError on exhausted retries.\n *\n * When `tools` is set, returns a `CallWithToolsResult<T>` instead of `T`:\n * `{ type: 'content', content }` or `{ type: 'tool_calls', toolCalls,\n * content? }`. VernLLM never executes tools; run them yourself and\n * continue via `history` (see `ConversationTurn`). Mutually exclusive\n * with `jsonSchema`/`schema`.\n *\n * TypeScript picks the tools-aware overload (`CallWithToolsResult<T>`)\n * when `tools` is a literal array on `params`, and the conditional-tools\n * overload (`T | CallWithToolsResult<T>`, see `ConditionalToolCallParams`)\n * when `tools` is present but statically `ToolDefinition[] | undefined`,\n * e.g. `const tools = condition ? [myTool] : undefined`. Either way, use\n * `isToolCallResult()` to narrow the result once `tools` isn't a literal\n * array: TypeScript's static type can't know from the `ConditionalToolCallParams`\n * shape alone whether tools actually ran on a given call. Only omitting\n * `tools` entirely resolves to the plain `T` overload, since then tools\n * genuinely cannot have run. See the Tool Calling docs for details.\n *\n * The same static-vs-dynamic caveat applies to `stream`: TypeScript only\n * selects the streaming overload (returning `StreamCallResult<...>`) when\n * `stream: true` is statically present on `params`. A `stream` value set\n * conditionally on a plain `CallParams<T>` still resolves to `Promise<T>`\n * (or `Promise<CallWithToolsResult<T>>`) at the type level even though\n * the actual runtime result is the `{ chunks, finalResult }` streaming\n * shape whenever `stream` evaluates to `true`, callers doing this should\n * narrow/cast accordingly rather than relying on the static return type.\n *\n * Pinning `T` explicitly (`call<string>(...)`) alongside a literal\n * `tools` array loses per-tool `arguments` typing: TypeScript's own\n * generic inference rules mean providing *any* explicit type argument\n * suppresses inference for every subsequent type parameter in that call,\n * `Tools` included, regardless of its `const` modifier or default. This\n * isn't specific to this overload, it's true of all TypeScript generic\n * calls with a partial explicit type argument list. Pass `Tools`\n * explicitly too when pinning `T` this way, e.g. `call<string, typeof\n * myTools>(...)`, or prefer inferring `T` from `schema`/`jsonSchema`\n * instead (which doesn't touch the type argument list, so `Tools` still\n * infers normally).\n *\n * @param params System/user content plus per-call overrides. See `CallParams`.\n * @returns Without `tools` or `stream`: the parsed response, or raw\n * string if `jsonMode` is false. With `tools`: a `CallWithToolsResult<T>`,\n * narrowed to `ContentResult<T>` when `toolChoice: 'none'` is set, since\n * the model is then structurally barred from returning a `tool_calls`\n * result. With `stream: true` (statically): a `{ chunks, finalResult }`\n * `StreamCallResult`, `finalResult` resolving to whichever of the above\n * shapes applies once the stream completes. See `StreamCallResult`.\n */\n async call<T = unknown>(\n params: StreamEnabledCallParams<T> & ToolsDisabledCallParams<T>,\n ): Promise<StreamCallResult<ContentResult<T>>>;\n\n async call<T = unknown, const Tools extends readonly ToolDefinition[] = ToolDefinition[]>(\n params: StreamEnabledCallParams<T, Tools> & ToolEnabledCallParams<T, Tools>,\n ): Promise<StreamCallResult<CallWithToolsResult<T, Tools>>>;\n\n async call<const Tools extends readonly ToolDefinition[] = ToolDefinition[]>(\n params: StreamConditionalStringToolCallParams<Tools>,\n ): Promise<StreamCallResult<string | CallWithToolsResult<string, Tools>>>;\n\n async call<T = unknown, const Tools extends readonly ToolDefinition[] = ToolDefinition[]>(\n params: StreamEnabledCallParams<T, Tools> & ConditionalToolCallParams<T, Tools>,\n ): Promise<StreamCallResult<T | CallWithToolsResult<T, Tools>>>;\n\n async call(params: StreamJsonModeDisabledCallParams): Promise<StreamCallResult<string>>;\n\n async call(params: StreamJsonModeEnabledCallParams): Promise<StreamCallResult<JsonValue>>;\n\n async call<T = unknown>(params: StreamEnabledCallParams<T>): Promise<StreamCallResult<T>>;\n\n async call<T = unknown>(params: ToolsDisabledCallParams<T>): Promise<ContentResult<T>>;\n\n async call<T = unknown, const Tools extends readonly ToolDefinition[] = ToolDefinition[]>(\n params: ToolEnabledCallParams<T, Tools>,\n ): Promise<CallWithToolsResult<T, Tools>>;\n\n async call<const Tools extends readonly ToolDefinition[] = ToolDefinition[]>(\n params: ConditionalStringToolCallParams<Tools>,\n ): Promise<string | CallWithToolsResult<string, Tools>>;\n\n async call<T = unknown, const Tools extends readonly ToolDefinition[] = ToolDefinition[]>(\n params: ConditionalToolCallParams<T, Tools>,\n ): Promise<T | CallWithToolsResult<T, Tools>>;\n\n async call(params: JsonModeDisabledCallParams): Promise<string>;\n\n async call(params: JsonModeEnabledCallParams): Promise<JsonValue>;\n\n async call<T = unknown>(params: CallParams<T>): Promise<T>;\n\n async call<T = unknown>(\n params: CallParams<T>,\n ): Promise<T | CallWithToolsResult<T> | StreamCallResult<T | CallWithToolsResult<T>>> {\n if (params.signal?.aborted) {\n throw new LLMError('LLM request aborted', 'aborted');\n }\n\n const requestId = params.requestId ?? randomUUID();\n\n // A lone target (no `fallback` configured) keeps the exact pre-fallback\n // contract: the breaker is checked once, up front, before usage is\n // reserved, so a call that's definitely blocked never pays a\n // reserve-then-refund round trip. This can only be hoisted out of the\n // chain for the sole-target case: `assertBreakerClosed` claims a\n // half-open trial slot as a side effect, which must happen exactly\n // once per logical call, so with more than one target the check has\n // to stay inside `runFallbackChain`, where an open primary is just\n // another target failure that `fallbackOn` can fall over from.\n const soleTarget = this.executors.length === 1;\n\n if (soleTarget) {\n this.executors[0]!.assertBreakerClosed(params.model);\n }\n\n if (params.stream) {\n // Same breaker/logging treatment as non-streaming, applied around\n // opening the stream; mid-stream failures are handled separately\n // inside the executor and never fall over (see `runFallbackChain`).\n // Usage refund/report is deferred onto finalResult, since call()\n // must return { chunks, finalResult } before the real outcome is\n // known, which is also why `params.meta` isn't populated for\n // streaming calls.\n return withReservedUsageForStream(\n params,\n async () => {\n const { result } = await this.runFallbackChain(\n params,\n requestId,\n (executor, onAttempt) => executor.runStream(params, requestId, onAttempt),\n soleTarget,\n );\n return result;\n },\n params.signal,\n (logMessage, error) => this.logRefundError(logMessage, error),\n );\n }\n\n return withReservedUsage(\n params,\n false,\n async () => {\n const { result, executor, index, attemptCount } = await this.runFallbackChain(\n params,\n requestId,\n (target, onAttempt) => target.run(params, requestId, onAttempt),\n soleTarget,\n );\n\n if (params.meta) {\n params.meta.current = {\n provider: executor.providerName,\n model: params.model ?? executor.model,\n fallbackIndex: index - 1,\n usedFallback: index > 0,\n attempts: attemptCount,\n };\n }\n\n return result;\n },\n params.signal,\n (logMessage, error) => this.logRefundError(logMessage, error),\n );\n }\n\n /**\n * Thin delegator kept private on `VernLLM` (rather than only existing on\n * `CacheOrchestrator`) since it's the one caching primitive exercised\n * directly by white-box tests, independent of the public `cachedCall()`\n * surface.\n */\n private runCached<T>(params: InternalCacheParams<T>) {\n return this.cacheOrchestrator.runCached(params);\n }\n\n /**\n * Removes a cached response by key when the configured cache adapter\n * supports deletion. Cache invalidation is the caller's responsibility;\n * only the application knows when cached data is stale.\n *\n * @param key The raw cache key (resolved through the adapter's\n * `resolveKey`, if any, before deletion).\n */\n async deleteCache(key: string): Promise<void> {\n await this.cacheOrchestrator.deleteCache(key);\n }\n\n /**\n * Cache wrapper composing `call` + caching, so cached LLM calls\n * automatically get retry/timeout/circuit-breaker behavior. `reserveUsage`/\n * `refundUsage` are read from the top-level params only. Concurrent misses\n * for the same `cacheKey` share a single in-flight call, avoiding cache\n * stampedes. Supports `stream: true` and `tools` in any combination.\n *\n * When `call.tools` is set, this caches the whole `CallWithToolsResult`,\n * including `tool_calls` results, not just final answers. Whether\n * that's appropriate depends on the tool: caching \"the model decided to\n * call get_weather\" is usually fine to reuse briefly, but caching a\n * decision made under permissions or account state that can change\n * between calls is not. Use a short `ttl` or a separate `cacheKey` for\n * such tools if this distinction matters.\n *\n * There is no public way to cache an arbitrary non-LLM function through\n * `VernLLM`. This method always composes with `call()`. For\n * general-purpose caching unrelated to an LLM call, use a dedicated\n * caching library at the application level instead.\n *\n * The same `T`-vs-`Tools` inference caveat documented on `call()` applies\n * here too: pinning `T` explicitly (`cachedCall<string>(...)`) alongside\n * a literal `call.tools` array loses per-tool `arguments` typing, pass\n * `Tools` explicitly too in that case.\n *\n * @param params `cacheKey`, `ttl`, and optional\n * `reserveUsage`/`refundUsage`/`signal`, plus `call`, the `CallParams`\n * (optionally with `tools` and/or `stream`) to pass through to\n * `this.call(...)`. The top-level `signal` governs the cached operation\n * and its usage hooks only; to also abort the underlying provider\n * request, set `signal` inside `call`.\n * @returns The cached value on a hit, or the freshly-called result on a miss.\n */\n async cachedCall<T, const Tools extends readonly ToolDefinition[] = ToolDefinition[]>(\n params: CachedStreamToolCallParams<T, Tools>,\n ): Promise<StreamCallResult<CallWithToolsResult<T, Tools>>>;\n\n async cachedCall<const Tools extends readonly ToolDefinition[] = ToolDefinition[]>(\n params: CachedStreamConditionalStringToolCallParams<Tools>,\n ): Promise<StreamCallResult<string | CallWithToolsResult<string, Tools>>>;\n\n async cachedCall<T, const Tools extends readonly ToolDefinition[] = ToolDefinition[]>(\n params: CachedStreamConditionalToolCallParams<T, Tools>,\n ): Promise<StreamCallResult<T | CallWithToolsResult<T, Tools>>>;\n\n async cachedCall(\n params: CachedStreamJsonModeDisabledCallParams,\n ): Promise<StreamCallResult<string>>;\n\n async cachedCall(\n params: CachedStreamJsonModeEnabledCallParams,\n ): Promise<StreamCallResult<JsonValue>>;\n\n async cachedCall<T>(params: CachedStreamCallParams<T>): Promise<StreamCallResult<T>>;\n\n async cachedCall<T, const Tools extends readonly ToolDefinition[] = ToolDefinition[]>(\n params: CachedToolCallParams<T, Tools>,\n ): Promise<CallWithToolsResult<T, Tools>>;\n\n async cachedCall<const Tools extends readonly ToolDefinition[] = ToolDefinition[]>(\n params: CachedConditionalStringToolCallParams<Tools>,\n ): Promise<string | CallWithToolsResult<string, Tools>>;\n\n async cachedCall<T, const Tools extends readonly ToolDefinition[] = ToolDefinition[]>(\n params: CachedConditionalToolCallParams<T, Tools>,\n ): Promise<T | CallWithToolsResult<T, Tools>>;\n\n async cachedCall(params: CachedJsonModeDisabledCallParams): Promise<string>;\n\n async cachedCall(params: CachedJsonModeEnabledCallParams): Promise<JsonValue>;\n\n async cachedCall<T>(params: CachedCallParams<T>): Promise<T>;\n\n async cachedCall<T>(\n params:\n | CachedCallParams<T>\n | CachedToolCallParams<T>\n | CachedConditionalToolCallParams<T>\n | CachedStreamCallParams<T>\n | CachedStreamToolCallParams<T>\n | CachedStreamConditionalToolCallParams<T>\n | CachedJsonModeDisabledCallParams\n | CachedJsonModeEnabledCallParams\n | CachedStreamJsonModeDisabledCallParams\n | CachedStreamJsonModeEnabledCallParams,\n ): Promise<T | CallWithToolsResult<T> | StreamCallResult<T | CallWithToolsResult<T>>> {\n const { call: callParams, ...cacheParams } = params;\n\n // `callParams`'s type no longer includes reserveUsage/refundUsage (see\n // CachedCallParams et al.): a well-typed caller can't reach this branch\n // at all, TypeScript rejects it at the call site instead. This check is\n // a defense-in-depth backstop for callers that bypass the type system\n // (plain JS, or an `as any` cast), and now throws instead of silently\n // ignoring the hooks and continuing: reserveUsage/refundUsage exist as\n // a cost-control safety mechanism, so silently dropping them fails\n // open, not safe, which a warning callers may never see doesn't fix.\n const restCallParams = callParams as CallParams<T>;\n\n if (restCallParams.reserveUsage || restCallParams.refundUsage) {\n throw new LLMError(\n '`reserveUsage`/`refundUsage` were set inside `call`, where cachedCall ignores them. Move them ' +\n 'to the top level of the cachedCall() params, alongside cacheKey/ttl, instead.',\n 'invalid_params',\n );\n }\n\n if (restCallParams.stream) {\n const streamParams = restCallParams as StreamEnabledCallParams<T>;\n\n return this.cacheOrchestrator.runCachedStream(\n {\n ...cacheParams,\n openStream: () => this.call(streamParams),\n },\n Boolean(restCallParams.tools),\n );\n }\n\n return this.runCached({\n ...cacheParams,\n fn: () => this.call(restCallParams),\n });\n }\n\n /**\n * @param target.index Which target to read. Defaults to the primary.\n * @param target.model Which model bucket to read, if the target isolates by model.\n * @returns The breaker state, or `undefined` if that target has no breaker.\n * @throws {RangeError} If `target.index` names no target. Lets a real\n * target with no breaker (`undefined`) stay distinguishable from a\n * target that doesn't exist.\n */\n getCircuitState(target?: CircuitTarget): CircuitState | undefined {\n const executor = this.resolveExecutor(target?.index ?? 0, 'getCircuitState');\n this.warnIfModelUnsupported(executor.isolateByModel, target?.model, 'getCircuitState');\n\n return executor.getCircuitState(target?.model ?? executor.model);\n }\n\n /**\n * @param model Which model bucket to read, for targets that isolate by model.\n * @returns Every target's state, in chain order.\n */\n getCircuitStates(model?: string): TargetCircuitState[] {\n return this.executors.map((executor, index) => ({\n provider: executor.providerName,\n index,\n isFallback: index > 0,\n isolateByModel: executor.isolateByModel,\n state: executor.getCircuitState(model ?? executor.model),\n }));\n }\n\n /**\n * Manually opens a target's breaker, e.g. to pull a provider out of\n * rotation ahead of known maintenance instead of waiting for it to fail.\n *\n * @param target.index Which target to open. Defaults to the primary.\n * @param target.model Which model bucket to open, if the target isolates by model.\n * @throws {RangeError} If `target.index` names no target.\n */\n openCircuit(target?: CircuitTarget): void {\n const executor = this.resolveExecutor(target?.index ?? 0, 'openCircuit');\n this.warnIfModelUnsupported(executor.isolateByModel, target?.model, 'openCircuit');\n executor.openCircuit(target?.model ?? executor.model);\n }\n\n /**\n * Manually closes a target's breaker, e.g. once a provider is confirmed\n * healthy again without waiting out the cooldown.\n *\n * @param target.index Which target to close. Defaults to the primary.\n * @param target.model Which model bucket to close, if the target isolates by model.\n * @throws {RangeError} If `target.index` names no target.\n */\n closeCircuit(target?: CircuitTarget): void {\n const executor = this.resolveExecutor(target?.index ?? 0, 'closeCircuit');\n this.warnIfModelUnsupported(executor.isolateByModel, target?.model, 'closeCircuit');\n executor.closeCircuit(target?.model ?? executor.model);\n }\n\n /** Resolves a target index so every circuit-breaker method agrees on what counts as valid. */\n private resolveExecutor(index: number, caller: string): CallExecutor {\n const executor = this.executors[index];\n\n if (!executor) {\n throw new RangeError(\n `${caller}: no target at index ${index} (chain has ${this.executors.length} target${this.executors.length === 1 ? '' : 's'})`,\n );\n }\n\n return executor;\n }\n\n /** Warns when `model` can't do anything on this target, so it's never silently ignored. */\n private warnIfModelUnsupported(\n isolateByModel: boolean,\n model: string | undefined,\n caller: string,\n ): void {\n if (model !== undefined && !isolateByModel) {\n this.logger.warn(\n `[VernLLM] ${caller}: \\`model: '${model}'\\` has no effect here. This target's circuitBreaker doesn't have isolateByModel on, so it only tracks one shared circuit regardless of \\`model\\`. Omit \\`model\\`, or set \\`circuitBreaker.isolateByModel: true\\` on this target if per-model tracking is what you want.`,\n );\n }\n }\n}\n\n/**\n * Identity function preserving `params`'s own precise type, unlike a `:\n * CallParams<T>` annotation, which would widen `tools` away and break the\n * `ConditionalToolCallParams<T>` overload for `tools: someCondition ?\n * [tool] : undefined`. Use it when you need `call()` params in a named,\n * reusable variable; skip it when you can pass the object inline.\n *\n * ```ts\n * const params = defineCallParams({\n * userContent: 'What is the weather?',\n * tools: someCondition ? [weatherTool] : undefined,\n * });\n * const result = await llm.call(params);\n * // result: unknown | CallWithToolsResult<unknown>, same as inline\n * ```\n *\n * `T` isn't a parameter here; pin it via `llm.call<T>(params)` as usual.\n * `defineCachedCallParams` is the `cachedCall()` counterpart.\n */\nexport function defineCallParams<P extends CallParams<unknown>>(params: P): P {\n return params;\n}\n\n/**\n * The `cachedCall()` counterpart to `defineCallParams`: preserves the\n * whole `{ cacheKey, ttl, call }` object, `call.tools` included, in one\n * named variable.\n *\n * ```ts\n * const params = defineCachedCallParams({\n * cacheKey: 'weather-ny',\n * ttl: 60,\n * call: { userContent: 'What is the weather?', tools: someCondition ? [weatherTool] : undefined },\n * });\n * const result = await llm.cachedCall(params);\n * ```\n */\nexport function defineCachedCallParams<P extends CachedCallParams<unknown>>(params: P): P {\n return params;\n}\n","import { LLMError } from '../../types/errors.js';\n\n/**\n * Parses a Server-Sent-Events byte/text stream into the JSON payload of\n * each `data:` frame, in arrival order. Generic over transport: works with\n * anything that hands back progressively-arriving `Uint8Array` or `string`\n * chunks via async iteration: native `fetch`'s `response.body` (wrapped\n * to be iterable, see `webStreamToAsyncIterable` in `fetch.ts`), axios's\n * Node `Readable` (already async-iterable, no wrapping needed), etc, so\n * this framing layer doesn't care which transport produced the bytes.\n *\n * Follows the SSE spec's frame-delimiting rules closely enough for LLM\n * streaming responses: frames are separated by a blank line, each frame\n * may carry one or more `data:` lines (joined with `\\n` per spec when\n * there's more than one), `:`-prefixed lines are comments and ignored, and\n * other SSE fields (`event:`, `id:`, `retry:`) are ignored since VernLLM\n * only needs the payload. A frame whose data is exactly `[DONE]` (the\n * sentinel several providers, notably OpenAI, send to mark stream end)\n * ends iteration without yielding it.\n *\n * Line endings: `\\r\\n` and bare `\\r` (both legal per the SSE spec, alongside `\\n`) are normalized\n * to `\\n` before frame splitting. A `\\r` at the very end of the currently-buffered text is left\n * alone until either more text arrives (in case it's the first half of a split `\\r\\n` pair) or the\n * stream ends, so a `\\r\\n` pair split across two transport chunks is never misread as two blank\n * lines.\n *\n * Malformed JSON in a frame throws `LLMError('parse')`, consistent with\n * how malformed JSON is handled elsewhere in VernLLM.\n */\nexport async function* parseSseStream(\n source: AsyncIterable<Uint8Array | string>,\n): AsyncGenerator<unknown> {\n // `fatal: true` makes invalid UTF-8 throw instead of silently decoding\n // to U+FFFD replacement characters, which could otherwise land inside a\n // JSON string and either corrupt it unnoticeably or, worse, still parse\n // as syntactically valid JSON with silently-wrong content.\n const decoder = new TextDecoder('utf-8', { fatal: true });\n let buffer = '';\n\n for await (const chunk of source) {\n let text: string;\n\n try {\n text = typeof chunk === 'string' ? chunk : decoder.decode(chunk, { stream: true });\n } catch (cause) {\n throw new LLMError('Invalid UTF-8 in SSE stream', 'parse', { cause });\n }\n\n // Normalized against the whole buffer, not just the newly-arrived\n // chunk: a `\\r\\n` delimiter can straddle a chunk boundary (one chunk\n // ending in `\\r`, the next starting with `\\n`), and normalizing only\n // the new text would miss that split pair. A bare trailing `\\r` (not\n // followed by anything yet) is left as-is for the same reason; it's\n // converted once either more text or end-of-stream resolves whether\n // it was standalone or the start of a split `\\r\\n`.\n buffer = (buffer + text).replace(/\\r\\n/g, '\\n').replace(/\\r(?!$)/g, '\\n');\n\n let boundary = buffer.indexOf('\\n\\n');\n\n while (boundary !== -1) {\n const frame = buffer.slice(0, boundary);\n\n buffer = buffer.slice(boundary + 2);\n\n const event = parseSseFrame(frame);\n\n if (event === DONE) return;\n if (event !== NO_DATA) yield event;\n\n boundary = buffer.indexOf('\\n\\n');\n }\n }\n\n // Flush any bytes TextDecoder held back mid-decode, so a truncated\n // multi-byte char surfaces as a parse error instead of silently\n // vanishing (and possibly leaving behind valid-looking, wrong JSON).\n try {\n buffer += decoder.decode();\n } catch (cause) {\n throw new LLMError('Invalid UTF-8 in SSE stream', 'parse', { cause });\n }\n\n // The stream has ended, so a trailing `\\r` still held back above (it\n // could have been the start of a split `\\r\\n` pair) can only be a bare\n // CR line ending now. Normalize it and re-check for any frame boundary\n // it just completed.\n buffer = buffer.replace(/\\r$/, '\\n');\n\n let boundary = buffer.indexOf('\\n\\n');\n\n while (boundary !== -1) {\n const frame = buffer.slice(0, boundary);\n\n buffer = buffer.slice(boundary + 2);\n\n const event = parseSseFrame(frame);\n\n if (event === DONE) return;\n if (event !== NO_DATA) yield event;\n\n boundary = buffer.indexOf('\\n\\n');\n }\n\n // Flush a final frame that arrived without a trailing blank line: some\n // servers close the connection right after the last `data:` line instead\n // of sending one more `\\n\\n` first.\n const trailing = buffer.trim();\n\n if (trailing) {\n const event = parseSseFrame(trailing);\n\n if (event !== DONE && event !== NO_DATA) yield event;\n }\n}\n\nconst DONE = Symbol('sse-stream-done');\nconst NO_DATA = Symbol('sse-frame-no-data');\n\n/**\n * Sentinel yielded by `parseSseStream` for a comment-only frame (no\n * `data:` payload), the mechanism providers use for SSE keep-alive\n * pings. Exported so a consumer (e.g. `fromFetch`) can react to \"still\n * alive\" separately from a genuinely empty frame (`NO_DATA`, kept internal).\n */\nexport const SSE_PING = Symbol('sse-frame-ping');\n\n/** Extracts and JSON-parses the `data:` payload of one SSE frame (the text between two blank lines). */\nfunction parseSseFrame(frame: string): unknown {\n const dataLines: string[] = [];\n let sawComment = false;\n\n for (const line of frame.split('\\n')) {\n if (line.startsWith(':')) {\n sawComment = true; // comment line, also used as a keep-alive ping\n continue;\n }\n if (!line.startsWith('data:')) continue; // ignore event:/id:/retry:/blank lines\n\n // A single space after the colon is stripped per the SSE spec; further\n // leading whitespace is preserved as part of the payload.\n dataLines.push(line.startsWith('data: ') ? line.slice(6) : line.slice(5));\n }\n\n if (!dataLines.length) return sawComment ? SSE_PING : NO_DATA;\n\n const data = dataLines.join('\\n');\n\n if (data === '[DONE]') return DONE;\n\n try {\n return JSON.parse(data);\n } catch (cause) {\n throw new LLMError(`Invalid JSON in SSE frame: ${data.slice(0, 200)}`, 'parse', {\n cause,\n code: 'stream_frame_invalid',\n });\n }\n}\n","import { LLMError } from '../../types/index.js';\n\n/**\n * MIME types accepted for `ImageBlock.mimeType` across all adapters. This is\n * the intersection of what Anthropic, Gemini, OpenAI-compatible, and Bedrock\n * Converse all natively support, so a `ContentBlock[]` that validates for\n * one provider validates for all of them.\n */\nexport const SUPPORTED_IMAGE_MIME_TYPES = [\n 'image/png',\n 'image/jpeg',\n 'image/gif',\n 'image/webp',\n] as const;\n\nexport type SupportedImageMimeType = (typeof SUPPORTED_IMAGE_MIME_TYPES)[number];\n\n/**\n * Validates an `ImageBlock.mimeType` against the shared supported set.\n * Throws a non-retryable `LLMError('invalid_params')`, since an unsupported\n * mimeType is a bug in the caller's own input, deterministic before any\n * request is built, the same class of failure as every other check in\n * `RequestBuilder`.\n */\nexport function assertSupportedImageMimeType(mimeType: string): SupportedImageMimeType {\n if ((SUPPORTED_IMAGE_MIME_TYPES as readonly string[]).includes(mimeType)) {\n return mimeType as SupportedImageMimeType;\n }\n\n throw new LLMError(\n `Unsupported image mimeType \"${mimeType}\": expected one of ${SUPPORTED_IMAGE_MIME_TYPES.join(', ')}`,\n 'invalid_params',\n );\n}\n","/**\n * A static allow-list or predicate naming which models support native,\n * schema-constrained output as its own request field — Anthropic's\n * `output_config.format`, Bedrock's `outputConfig.textFormat` — separate\n * from `tools`/`tool_choice`, so it can be combined with real,\n * caller-supplied `tools` in the same request.\n *\n * There is no built-in default list here. Which models support this is\n * Anthropic's and Bedrock's call to make, not this package's, and it\n * changes over time; hardcoding a guessed list would risk silently\n * routing a request onto a field a given model doesn't actually support,\n * trading a clear `LLMError('invalid_params')` with\n * `code: 'unsupported_capability'` for a confusing error from the provider\n * instead. So this is opt-in: pass the model IDs you've verified against the\n * provider's own docs (or a predicate). Left unset, no model is treated as\n * native-capable, `jsonSchema` keeps using the older forced-single-tool-call\n * emulation, and combining it with `tools` throws the coded capability error,\n * exactly this package's behavior before native support was added.\n */\nexport type ModelCapabilityOverride = string[] | ((model: string) => boolean);\n\n/** Resolves whether `model` is covered by a caller-supplied allow-list/predicate. */\nexport function supportsNativeStructuredOutput(\n model: string,\n override?: ModelCapabilityOverride,\n): boolean {\n if (!override) return false;\n\n return Array.isArray(override) ? override.includes(model) : override(model);\n}\n","import { LLMError } from '../../types/errors.js';\n\nimport type { ModelCapabilityOverride } from './nativeStructuredOutput.js';\n\n/**\n * Shared conversion between the two reasoning controls VernLLM exposes:\n * `reasoningEffort` (a tier string, OpenAI's native shape) and\n * `budgetTokens` (a raw integer, Anthropic's and Gemini's native shape).\n *\n * Every adapter prefers its own native field when the caller set it, and\n * only calls into this table when the caller set the other one instead.\n * The numbers here are a guess, not a provider guarantee, callers who\n * need a precise budget on a specific model should set `budgetTokens`\n * directly rather than relying on this table's `reasoningEffort` mapping.\n *\n * The table itself is overridable per adapter instance, via\n * `reasoningEffortTokens` on each `from*` adapter's options (see\n * `AnthropicAdapterOptions`, `GeminiAdapterOptions`,\n * `OpenAICompatibleAdapterOptions`, `BedrockAdapterOptions`), for callers\n * who want `reasoningEffort` tiers to map onto different token counts\n * than the defaults below, e.g. a model whose useful reasoning range\n * doesn't match these numbers.\n */\n\nexport type EffortTokenTable = Record<'minimal' | 'low' | 'medium' | 'high', number>;\n\nexport const DEFAULT_EFFORT_TOKENS: EffortTokenTable = {\n minimal: 1024,\n low: 4096,\n medium: 16000,\n high: 32000,\n};\n\n/**\n * Merges a caller-supplied partial override over `DEFAULT_EFFORT_TOKENS`.\n * Called once per adapter instance (not per request), so a per-instance\n * override only needs to specify the tiers it actually wants to change.\n *\n * Throws `LLMError('invalid_params')` if the override doesn't keep the\n * tiers in strictly ascending order (`minimal < low < medium < high`).\n * `budgetTokensToEffort` buckets by walking the tiers low to high and\n * returning on the first one a value is `<=`, so an unordered table (e.g.\n * `low` above `medium`) wouldn't just produce a \"wrong\" bucket, it would\n * make some tiers unreachable outright, silently, with no signal to the\n * caller that their override doesn't do what they think it does.\n */\nexport function resolveEffortTokenTable(override?: Partial<EffortTokenTable>): EffortTokenTable {\n if (!override) return DEFAULT_EFFORT_TOKENS;\n\n const table = { ...DEFAULT_EFFORT_TOKENS, ...override };\n\n if (!(table.minimal < table.low && table.low < table.medium && table.medium < table.high)) {\n throw new LLMError(\n `reasoningEffortTokens must keep tiers in strictly ascending order ` +\n `(minimal < low < medium < high), got ${JSON.stringify(table)}. An out-of-order ` +\n `override doesn't just misrank tiers, it can make some of them unreachable.`,\n 'invalid_params',\n );\n }\n\n return table;\n}\n\n/** Converts a `reasoningEffort` tier into the nearest `budgetTokens` value. */\nexport function effortToBudgetTokens(\n effort: 'minimal' | 'low' | 'medium' | 'high',\n table: EffortTokenTable = DEFAULT_EFFORT_TOKENS,\n): number {\n return table[effort];\n}\n\n/**\n * Converts a raw `budgetTokens` value into the nearest `reasoningEffort`\n * tier, for providers that only understand tiers. Buckets by the same\n * `table` `effortToBudgetTokens` produces its values from, so the two\n * functions agree with each other at the boundary values, as long as the\n * same (possibly overridden) table is passed to both. A value strictly\n * between two tiers (e.g. 4097, one above the default `low`) rounds up to\n * the next tier it's still `<=`, i.e. `medium` here, not down to `low`.\n */\nexport function budgetTokensToEffort(\n budgetTokens: number,\n table: EffortTokenTable = DEFAULT_EFFORT_TOKENS,\n): 'minimal' | 'low' | 'medium' | 'high' {\n if (budgetTokens <= table.minimal) return 'minimal';\n if (budgetTokens <= table.low) return 'low';\n if (budgetTokens <= table.medium) return 'medium';\n return 'high';\n}\n\n/**\n * Parses an Opus model id's generation and minor version, e.g.\n * `\"claude-opus-4-7-20260101\"` -> `[4, 7]`, `\"anthropic.claude-opus-5-x\"` ->\n * `[5, 0]`. Not anchored, so it matches equally inside a bare Anthropic id\n * or a Bedrock id carrying a provider prefix. Returns `null` for a\n * non-Opus model id.\n */\n/**\n * Parses an Opus model id's generation and minor version, e.g.\n * `\"claude-opus-4-7-20260101\"` -> `[4, 7]`, `\"anthropic.claude-opus-5-x\"` ->\n * `[5, 0]`. Not anchored, so it matches equally inside a bare Anthropic id\n * or a Bedrock id carrying a provider prefix. Returns `null` for a\n * non-Opus model id.\n *\n * Anthropic model ids sometimes carry a trailing snapshot date instead of\n * (or in addition to) an explicit minor version, e.g. the real, still-\n * supported base `\"claude-opus-4-20250514\"` (no `.7`-style minor at all,\n * just a date suffix directly after the major version). Read naively,\n * `20250514` looks like a minor version far above any real threshold and\n * would misclassify this pre-4.6 model as adaptive-only. Snapshot dates\n * are always 8 digits (`YYYYMMDD`); a real minor version never is, so an\n * 8+ digit second segment is treated as a date, not a minor version.\n */\nfunction parseOpusVersion(model: string): [major: number, minor: number] | null {\n const match = /opus-(\\d+)(?:-(\\d+))?/.exec(model);\n if (!match) return null;\n\n const minorStr = match[2];\n const minor = minorStr === undefined || minorStr.length >= 8 ? 0 : Number(minorStr);\n\n return [Number(match[1]), minor];\n}\n\n/**\n * Default rule for whether `model` only supports adaptive thinking\n * (`thinking: { type: 'adaptive' }`) and returns a 400 for manual,\n * budget-based thinking (`thinking: { type: 'enabled', budget_tokens }`):\n * Claude Opus 4.7 and later (matched as a version threshold, so 4.8, 4.9,\n * 5, and every future Opus point release are covered automatically,\n * without a new list entry per release), and every Claude 5 tier model\n * outside the Opus family (Sonnet 5, Fable 5, Mythos 5, Mythos Preview).\n * `mythos` alone is enough to catch both Mythos names without listing\n * each separately.\n *\n * Necessarily best-effort: a new model family with its own name (not\n * `opus-*`, not `sonnet-5`/`fable-5`/`mythos-*`) still needs a code\n * update here, or a caller-supplied `adaptiveOnlyModels` override (see\n * `isAdaptiveOnlyModel`) covering it in the meantime.\n */\nfunction isDefaultAdaptiveOnly(model: string): boolean {\n const opusVersion = parseOpusVersion(model);\n\n if (opusVersion) {\n const [major, minor] = opusVersion;\n return major > 4 || (major === 4 && minor >= 7);\n }\n\n return ['sonnet-5', 'fable-5', 'mythos'].some((s) => model.includes(s));\n}\n\n/**\n * Whether `model` is adaptive-only, per the built-in rule above, or per a\n * caller-supplied `adaptiveOnlyModels` override. The override is\n * additive, not a replacement: it can mark an *additional* model as\n * adaptive-only (useful for a model family this package doesn't know\n * about yet), but it can't un-mark one the built-in rule already caught,\n * since a caller correcting a false negative is the only direction that\n * needs covering, a false positive here would mean this package is\n * simply wrong and needs its own fix, not a per-caller workaround.\n */\nexport function isAdaptiveOnlyModel(model: string, override?: ModelCapabilityOverride): boolean {\n if (isDefaultAdaptiveOnly(model)) return true;\n if (!override) return false;\n\n return Array.isArray(override) ? override.includes(model) : override(model);\n}\n\n/** Whether `model` is known to support manual, budget-based thinking. */\nexport function supportsManualThinkingBudget(\n model: string,\n override?: ModelCapabilityOverride,\n): boolean {\n return !isAdaptiveOnlyModel(model, override);\n}\n\n/**\n * Anthropic (and Claude models on Bedrock) require `budget_tokens` to be\n * at least 1024 and strictly less than `max_tokens`, since the thinking\n * budget and the reply share the same `max_tokens` ceiling. VernLLM's own\n * default `maxTokens` is 1000 (see `RequestBuilder`'s `defaultMaxTokens`),\n * below the 1024 floor, so the *default* `minimal` tier (1024 tokens) is\n * silently invalid against the *default* `max_tokens` unless a caller\n * happens to raise one or the other. Checked here, once, right before a\n * `thinking` block would be built, rather than left for Anthropic's own\n * 400 to explain after a real network round trip.\n */\nexport function assertValidClaudeBudgetTokens(budgetTokens: number, maxTokens: number): void {\n if (budgetTokens < 1024) {\n throw new LLMError(\n `budgetTokens (${budgetTokens}) is below Anthropic's minimum of 1024. Raise budgetTokens, ` +\n `or use a reasoningEffort tier of 'low' or above with the default conversion table.`,\n 'invalid_params',\n );\n }\n\n if (budgetTokens >= maxTokens) {\n throw new LLMError(\n `budgetTokens (${budgetTokens}) must be less than maxTokens (${maxTokens}); the thinking ` +\n `budget and the reply share the same max_tokens ceiling on Anthropic. Raise maxTokens, ` +\n `or lower budgetTokens/reasoningEffort.`,\n 'invalid_params',\n );\n }\n}\n\n/**\n * Anthropic rejects any form of `thinking` (manual `budget_tokens` or\n * adaptive) combined with a `tool_choice` that forces tool use, a forced\n * single tool or \"must call some tool\", with a 400: `\"Thinking may not be\n * enabled when tool_choice forces tool use.\"` Auto/none (or no tools at\n * all) are unaffected, thinking only conflicts with a choice that removes\n * the model's ability to just reply with text. This is a Claude-model\n * constraint, not specific to the Anthropic API's own wire shape, so it\n * applies identically to Claude models called through Bedrock's Converse\n * API, which forwards `thinking` under `additionalModelRequestFields` but\n * is still talking to the same underlying model.\n *\n * This combination can arise two ways: a caller explicitly sets both\n * `budgetTokens`/`reasoningEffort` and a forced `toolChoice`, or, more\n * subtly (Anthropic adapter only), a caller sets `jsonSchema` on a model\n * without native structured output support, which silently forces a\n * single synthetic tool call to emulate it, with no `tool_choice` of the\n * caller's own in sight. Both end up resolving to a forced tool choice by\n * the time each adapter calls this, so checking the adapter's own\n * already-resolved choice (rather than the caller's raw\n * `params.tool_choice`) catches both, right before a `thinking` block\n * would be built, rather than left for Anthropic's own 400 to explain\n * after a real network round trip.\n *\n * Takes a plain description of the forced choice rather than either\n * adapter's own wire shape (Anthropic SDK's `{ type: 'tool' | 'any', ... }`\n * vs Converse's `{ tool: {...} } | { any: {} }`), so both adapters can\n * share one check without either shape leaking into this file. Pass\n * `undefined` when the resolved choice is `auto`/`none`/unset, forcing\n * nothing.\n */\nexport function assertNoForcedToolChoiceWithThinking(\n forcedChoiceDescription: string | undefined,\n): void {\n if (!forcedChoiceDescription) return;\n\n throw new LLMError(\n `budgetTokens/reasoningEffort was set alongside ${forcedChoiceDescription}. Anthropic ` +\n 'rejects thinking combined with a tool_choice that forces tool use, the model has to be ' +\n \"able to reply with plain text for thinking to run. Use toolChoice: 'auto' (or omit \" +\n 'toolChoice) for this call, or drop budgetTokens/reasoningEffort for it.',\n 'invalid_params',\n );\n}\n\n/**\n * Anthropic's own effort levels for adaptive thinking, `output_config.effort`\n * (or Bedrock's typed `outputConfig.effort`), five tiers: `low`, `medium`,\n * `high`, `xhigh`, `max`. This is a different control than VernLLM's own\n * `reasoningEffort`/`budgetTokens`, not a token count, so it needs its own\n * mapping rather than reusing `EffortTokenTable`.\n */\nexport type ClaudeAdaptiveEffort = 'low' | 'medium' | 'high' | 'xhigh' | 'max';\n\n/**\n * Maps VernLLM's four-tier `reasoningEffort` onto Anthropic's five-tier\n * adaptive effort. `xhigh` and `max` have no VernLLM-side equivalent and\n * are unreachable through this mapping; a caller who wants either has to\n * target Anthropic/Bedrock-specific behavior already, so there's no gap\n * the shared `CallParams` surface needs to cover for a first pass.\n */\nexport function toClaudeAdaptiveEffort(\n effort: 'minimal' | 'low' | 'medium' | 'high',\n): ClaudeAdaptiveEffort {\n return effort === 'minimal' ? 'low' : effort;\n}\n\n/**\n * Gemini's own thinking-level control, `thinkingConfig.thinkingLevel`,\n * used by Gemini 3 series models instead of the numeric `thinkingBudget`\n * every earlier Gemini generation uses. Unlike Anthropic's five-tier\n * adaptive effort, this lines up exactly with VernLLM's own four-tier\n * `reasoningEffort`, so no lossy mapping table is needed, just a literal\n * case change.\n */\nexport type GeminiThinkingLevel = 'MINIMAL' | 'LOW' | 'MEDIUM' | 'HIGH';\n\n/** Converts VernLLM's `reasoningEffort` directly into Gemini's `ThinkingLevel` enum value. */\nexport function toGeminiThinkingLevel(\n effort: 'minimal' | 'low' | 'medium' | 'high',\n model: string,\n): GeminiThinkingLevel {\n return clampGeminiThinkingLevel(model, effort.toUpperCase() as GeminiThinkingLevel);\n}\n\n/**\n * Parses a Gemini model id's minor version, e.g. `\"gemini-3.1-pro\"` -> `1`,\n * `\"gemini-3-pro\"` -> `0` (no explicit minor). Only meaningful alongside\n * `parseGeminiMajorVersion`.\n */\nfunction parseGeminiMinorVersion(model: string): number {\n const match = /gemini-\\d+\\.(\\d+)/.exec(model);\n return match ? Number(match[1]) : 0;\n}\n\n/**\n * Some Gemini 3 \"Pro\" tier models accept a narrower set of `thinkingLevel`\n * values than VernLLM's four tiers map onto, confirmed against real API\n * 400s and Google's own migration guidance, not assumed:\n * - Gemini 3 Pro (major 3, minor 0, e.g. `\"gemini-3-pro-preview\"`): only\n * `LOW` and `HIGH`; `MEDIUM` returns a 400 (\"Thinking level MEDIUM is\n * not supported for this model\").\n * - Gemini 3.1 Pro (major 3, minor >= 1): `LOW`/`MEDIUM`/`HIGH`, no\n * `MINIMAL`, Google's own docs point users toward a Flash-tier model\n * instead for the lowest setting.\n * - Every Flash-tier Gemini 3+ model accepts the full four levels, no\n * clamping needed, matched by this function simply not applying to\n * anything without `\"pro\"` in the model id.\n *\n * Clamped automatically rather than left to error, since `reasoningEffort`\n * is a per-call value, a caller hitting this isn't misconfiguring an\n * instance once, they're getting an intermittent-looking failure on\n * whichever specific call happened to pick an unsupported tier. Necessarily\n * best-effort: a future Pro-tier release could add back a level this rule\n * still clamps, or clamp one this rule doesn't yet know to touch.\n */\nfunction clampGeminiThinkingLevel(model: string, level: GeminiThinkingLevel): GeminiThinkingLevel {\n if (!model.includes('pro')) return level;\n\n const major = parseGeminiMajorVersion(model);\n if (major === null || major < 3) return level;\n\n const minor = parseGeminiMinorVersion(model);\n\n if (minor === 0) {\n // Gemini 3 Pro: only LOW and HIGH are accepted.\n return level === 'HIGH' ? 'HIGH' : 'LOW';\n }\n\n // Gemini 3.1 Pro and later: LOW/MEDIUM/HIGH accepted, no MINIMAL.\n return level === 'MINIMAL' ? 'LOW' : level;\n}\n\n/**\n * Parses a Gemini model id's major generation number, e.g.\n * `\"gemini-3.1-flash-lite\"` -> `3`, `\"gemini-2.5-flash\"` -> `2`. Not\n * anchored, so a Vertex-prefixed or otherwise decorated id still matches.\n * Returns `null` for a non-Gemini model id.\n */\nfunction parseGeminiMajorVersion(model: string): number | null {\n const match = /gemini-(\\d+)/.exec(model);\n return match ? Number(match[1]) : null;\n}\n\n/**\n * Default rule for whether `model` uses `thinkingLevel` instead of\n * `thinkingBudget`: every Gemini 3 series model and later, matched as a\n * version threshold so 3.1, 3.5, 3.6, and every future Gemini 3.x or\n * later release are covered automatically, without a new entry per\n * release, same reasoning as `isDefaultAdaptiveOnly`'s Opus threshold.\n * Gemini 2.5 and earlier still use `thinkingBudget`.\n *\n * `thinkingBudget` is still *accepted* on Gemini 3 for backward\n * compatibility, per Google's own docs, but \"may result in unexpected\n * performance\" there, so this rule switches VernLLM's own default\n * behavior over rather than leaving it on the old field indefinitely.\n */\nfunction isDefaultThinkingLevelModel(model: string): boolean {\n const major = parseGeminiMajorVersion(model);\n return major !== null && major >= 3;\n}\n\n/**\n * Whether `model` uses `thinkingLevel`, per the built-in version\n * threshold above, or per a caller-supplied `thinkingLevelModels`\n * override. Additive, not a replacement, same reasoning as\n * `isAdaptiveOnlyModel`: an override can mark an *additional* model as\n * using `thinkingLevel` (a model family this package doesn't recognize\n * yet), it can't un-mark one the built-in threshold already caught.\n */\nexport function usesGeminiThinkingLevel(\n model: string,\n override?: ModelCapabilityOverride,\n): boolean {\n if (isDefaultThinkingLevelModel(model)) return true;\n if (!override) return false;\n\n return Array.isArray(override) ? override.includes(model) : override(model);\n}\n","import {\n LLMError,\n type ContentBlock,\n type LLMClient,\n type WireStreamChunk,\n type WireToolCall,\n} from '../types/index.js';\nimport {\n assertSupportedImageMimeType,\n type SupportedImageMimeType,\n} from './internal/imageFormat.js';\nimport {\n supportsNativeStructuredOutput,\n type ModelCapabilityOverride,\n} from './internal/nativeStructuredOutput.js';\nimport {\n assertNoForcedToolChoiceWithThinking,\n assertValidClaudeBudgetTokens,\n budgetTokensToEffort,\n effortToBudgetTokens,\n resolveEffortTokenTable,\n supportsManualThinkingBudget,\n toClaudeAdaptiveEffort,\n type ClaudeAdaptiveEffort,\n type EffortTokenTable,\n} from './internal/reasoningBudget.utils.js';\n\n/** Anthropic's native per-block content shape for a message. */\ntype AnthropicContentBlock =\n | { type: 'text'; text: string }\n | {\n type: 'image';\n source: { type: 'base64'; media_type: SupportedImageMimeType; data: string };\n }\n | { type: 'tool_use'; id: string; name: string; input: unknown }\n | { type: 'tool_result'; tool_use_id: string; content: string; is_error?: boolean };\n\n/** Minimal structural type for the Anthropic SDK's `messages.create` */\nexport interface AnthropicClient {\n messages: {\n create(\n params: {\n model: string;\n max_tokens: number;\n temperature?: number;\n system?: string;\n messages: Array<{ role: 'user' | 'assistant'; content: string | AnthropicContentBlock[] }>;\n tools?: Array<{\n name: string;\n description?: string;\n // The real Anthropic SDK's `Tool.input_schema` requires the\n // literal `type: 'object'` (VernLLM's own public `tools` API\n // accepts freeform JSON Schema, so this is narrower than that);\n // see the two call sites below for how a caller's schema is\n // asserted into this shape.\n input_schema: { type: 'object'; [key: string]: unknown };\n strict?: boolean;\n }>;\n tool_choice?:\n | { type: 'auto' }\n | { type: 'any' }\n | { type: 'none' }\n | { type: 'tool'; name: string };\n /**\n * Native, schema-constrained output: a separate request field from\n * `tools`/`tool_choice`, so it can be sent alongside real tool\n * calls. Only built by this adapter for models covered by\n * `nativeStructuredOutputModels` (opt-in, see\n * `AnthropicAdapterOptions`); other models keep getting\n * `jsonSchema` emulated as a forced single tool call, the\n * pre-existing behavior.\n *\n * Matches the real Anthropic API's `output_config.format` shape\n * exactly: just `type` and `schema`, no `name`/`description`/\n * `strict`. Those three exist on VernLLM's own `jsonSchema` API\n * (and are still forwarded on the legacy forced-tool-call path,\n * where they're real `Tool` fields), but the native structured-\n * output endpoint has no equivalent for any of them.\n */\n output_config?: {\n format?: {\n type: 'json_schema';\n schema: Record<string, unknown>;\n };\n /**\n * Effort control for adaptive thinking, on models where manual\n * `budget_tokens` thinking is no longer accepted (see\n * `supportsManualThinkingBudget` in\n * `adapters/internal/reasoningBudget.utils.ts`). Sibling to\n * `format`, either or both may be present independently.\n */\n effort?: 'low' | 'medium' | 'high' | 'xhigh' | 'max';\n };\n /**\n * Native reasoning control. `{ type: 'enabled', budget_tokens }`\n * is built directly from `CallParams.budgetTokens`, or converted\n * from `reasoningEffort`, on models that still accept a manual\n * token budget. `{ type: 'adaptive' }` is sent instead, paired\n * with `output_config.effort`, on models that only support\n * adaptive thinking. See\n * `adapters/internal/reasoningBudget.utils.ts`.\n */\n thinking?: { type: 'enabled'; budget_tokens: number } | { type: 'adaptive' };\n },\n options: { signal: AbortSignal },\n ): Promise<{\n content: Array<{ type: string; text?: string; id?: string; name?: string; input?: unknown }>;\n usage?: {\n input_tokens?: number;\n output_tokens?: number;\n output_tokens_details?: { thinking_tokens?: number } | null;\n };\n }>;\n };\n}\n\n/**\n * Translates a VernLLM `ContentBlock[]` (our provider-agnostic multimodal\n * shape) into Anthropic's native content-block array: text blocks pass\n * through as-is, image blocks become `{ type: 'image', source: { type:\n * 'base64', media_type, data } }`.\n */\nfunction toAnthropicContent(blocks: ContentBlock[]): AnthropicContentBlock[] {\n return blocks.map((block) =>\n block.type === 'image'\n ? {\n type: 'image',\n source: {\n type: 'base64',\n media_type: assertSupportedImageMimeType(block.mimeType),\n data: block.data,\n },\n }\n : { type: 'text', text: block.text },\n );\n}\n\n/**\n * Asserts a caller-supplied JSON Schema is an object schema before it's\n * used as Anthropic's `Tool.input_schema`, which (like every other\n * provider's function-calling API) requires `type: 'object'`. VernLLM's own\n * public `tools`/`jsonSchema` APIs accept freeform `Record<string,\n * unknown>` JSON Schema, so nothing upstream guarantees this at compile\n * time; this is the runtime check that stands in for that, so a schema\n * missing (or mistyping) `type: 'object'` fails loudly and immediately\n * instead of being silently forwarded to Anthropic malformed.\n */\nfunction assertObjectSchema(\n schema: Record<string, unknown>,\n toolName: string,\n): { type: 'object'; [key: string]: unknown } {\n if (schema.type !== 'object') {\n throw new LLMError(\n `Tool \"${toolName}\"'s schema must have \"type\": \"object\" (Anthropic requires object-shaped tool parameters).`,\n 'validation',\n );\n }\n\n return schema as { type: 'object'; [key: string]: unknown };\n}\n\n/**\n * Translates VernLLM's OpenAI-shaped wire `tool_choice` into Anthropic's\n * `{ type: 'auto' | 'any' | 'none' | 'tool', name? }` shape. `'required'`\n * maps to `'any'` (Anthropic's \"must call some tool\" equivalent).\n */\nfunction toAnthropicToolChoice(\n toolChoice: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice'],\n):\n | { type: 'auto' }\n | { type: 'any' }\n | { type: 'none' }\n | { type: 'tool'; name: string }\n | undefined {\n if (!toolChoice || toolChoice === 'auto') return { type: 'auto' };\n if (toolChoice === 'none') return { type: 'none' };\n if (toolChoice === 'required') return { type: 'any' };\n\n return { type: 'tool', name: toolChoice.function.name };\n}\n\n/** One SSE event of an Anthropic `messages.create({ stream: true })` stream. */\ntype AnthropicStreamEvent =\n | { type: 'message_start'; message: { usage?: { input_tokens?: number } } }\n | {\n type: 'content_block_start';\n index: number;\n content_block: { type: string; id?: string; name?: string };\n }\n | {\n type: 'content_block_delta';\n index: number;\n delta:\n | { type: 'text_delta'; text: string }\n | { type: 'input_json_delta'; partial_json: string };\n }\n | { type: 'content_block_stop'; index: number }\n | {\n type: 'message_delta';\n usage?: {\n output_tokens?: number;\n output_tokens_details?: { thinking_tokens?: number } | null;\n };\n }\n | { type: 'message_stop' }\n // Keep-alive event during long streams (e.g. extended thinking). Modeled\n // so the event switch has somewhere to route it. See createStream.\n | { type: 'ping' };\n\ntype AnthropicRequestBody = Parameters<AnthropicClient['messages']['create']>[0];\n\n/**\n * Maps VernLLM's OpenAI-shaped wire `tools`/`tool_choice` into Anthropic's\n * `tools`/`tool_choice` shape. Shared by the two call sites that build real\n * (non-schema-forced) tool definitions: the plain tools-only branch, and\n * the native-structured-output branch, which sends real tools alongside\n * `output_config` rather than instead of it.\n */\nfunction buildAnthropicTools(\n tools: NonNullable<Parameters<LLMClient['chat']['completions']['create']>[0]['tools']>,\n toolChoiceParam: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice'],\n): {\n tools: NonNullable<Parameters<AnthropicClient['messages']['create']>[0]['tools']>;\n toolChoice: Parameters<AnthropicClient['messages']['create']>[0]['tool_choice'];\n} {\n return {\n tools: tools.map((t) => ({\n name: t.function.name,\n description: t.function.description,\n // Tool parameters are always object schemas in practice (every\n // provider's function-calling API requires it).\n input_schema: assertObjectSchema(t.function.parameters, t.function.name),\n })),\n toolChoice: toAnthropicToolChoice(toolChoiceParam),\n };\n}\n\n/**\n * Builds the Anthropic-shaped request body from VernLLM's wire params,\n * shared between `create` and `createStream` so both go through identical\n * translation (system prompt, message shaping, and the jsonSchema →\n * forced-single-tool mapping all happen exactly once, not once per entry\n * point).\n *\n * Returns `toolName` alongside the body: when set, the model was forced to\n * call a single synthetic tool standing in for `jsonSchema` output (the\n * legacy path, for models without native structured-output support), and\n * both `create` and `createStream` need to know this so they can unwrap\n * that tool call back into plain text content instead of treating it like\n * a real tool call. On the native path (model supports `output_config`),\n * `toolName` is `undefined`: the schema-conforming JSON already arrives as\n * ordinary text content, nothing to unwrap, and any real tool calls in\n * `params.tools` are left for the normal, non-forced tool-call handling\n * both `create` and `createStream` already do when `toolName` is unset.\n */\nfunction buildAnthropicRequestBody(\n params: Parameters<LLMClient['chat']['completions']['create']>[0],\n nativeStructuredOutputModels?: ModelCapabilityOverride,\n effortTokenTable?: EffortTokenTable,\n adaptiveOnlyModels?: ModelCapabilityOverride,\n): { body: AnthropicRequestBody; toolName: string | undefined } {\n const systemMessage = params.messages.find((m) => m.role === 'system');\n\n // Keep user, assistant, and tool turns, in order. Anthropic has no\n // separate 'tool' role: tool results travel as a user-role message\n // containing tool_result content blocks, and an assistant's tool\n // requests travel as tool_use content blocks on its own turn.\n const conversationMessages = params.messages.filter(\n (m) => m.role === 'user' || m.role === 'assistant' || m.role === 'tool',\n );\n\n const jsonSchema =\n params.response_format?.type === 'json_schema' ? params.response_format.json_schema : undefined;\n\n const schemaName = jsonSchema?.name.trim();\n\n if (jsonSchema && !schemaName) {\n throw new LLMError('json_schema.name must not be empty.', 'validation');\n }\n\n const isNative =\n Boolean(jsonSchema) &&\n supportsNativeStructuredOutput(params.model, nativeStructuredOutputModels);\n\n if (jsonSchema && params.tools?.length && !isNative) {\n throw new LLMError(\n `Anthropic model \"${params.model}\" is not covered by nativeStructuredOutputModels, so ` +\n '`jsonSchema` is emulated as a forced single tool call there, which collides with the ' +\n '`tools` you also provided. Either drop `tools` or `jsonSchema` for this call, or pass ' +\n \"this model in fromAnthropic's `nativeStructuredOutputModels` option once you've \" +\n \"confirmed it supports Anthropic's `output_config.format`.\",\n 'invalid_params',\n { code: 'unsupported_capability', issues: { capability: 'tools_with_json_schema' } },\n );\n }\n\n if (params.response_format?.type === 'json_object') {\n throw new LLMError(\n 'response_format: \"json_object\" is not supported on Anthropic. Unlike OpenAI, Anthropic ' +\n 'has no API-level field that mechanically guarantees valid JSON output for this mode, so ' +\n 'it used to be emulated by injecting a \"respond with JSON only\" instruction into the ' +\n 'system prompt, a guarantee this adapter can no longer make. Use `jsonSchema` instead, ' +\n \"which maps to a real API-level constraint (Anthropic's native output_config.format on \" +\n 'covered models, or a forced single tool call otherwise).',\n 'validation',\n );\n }\n\n let toolName: string | undefined;\n let outputFormat: NonNullable<AnthropicRequestBody['output_config']>['format'] | undefined;\n let tools: NonNullable<Parameters<AnthropicClient['messages']['create']>[0]['tools']> | undefined;\n let toolChoice: Parameters<AnthropicClient['messages']['create']>[0]['tool_choice'];\n\n if (jsonSchema && isNative) {\n // Native path: the schema goes in its own request field, independent\n // of tools/tool_choice, so real tools (if any) are built exactly like\n // the tools-only branch below and sent alongside it.\n //\n // Only `type` and `schema` are sent: the real Anthropic API's\n // `output_config.format` has no `name`/`description`/`strict` fields,\n // unlike the legacy forced-tool-call path below, where those are real\n // `Tool` fields. `schemaName` is still required and validated above\n // (a caller-facing identifier, useful for logging/debugging on their\n // end), it just never reaches this particular wire request.\n outputFormat = { type: 'json_schema', schema: jsonSchema.schema };\n\n if (params.tools?.length) {\n ({ tools, toolChoice } = buildAnthropicTools(params.tools, params.tool_choice));\n }\n } else if (jsonSchema && schemaName) {\n // Legacy path: jsonSchema alone (or with tools, on a native model — see\n // above), on a model without native support, becomes a forced single\n // tool call, unchanged from before this adapter had a native path.\n const { schema, description, strict } = jsonSchema;\n\n toolName = schemaName;\n // VernLLM's public `jsonSchema` API accepts a freeform JSON Schema\n // object (`Record<string, unknown>`), not necessarily typed with a\n // literal `type: 'object'`, but tool/function parameters are always\n // object schemas in practice (every provider's function-calling API\n // requires it), so this assertion reflects that existing convention\n // rather than changing behavior.\n tools = [\n { name: toolName, description, input_schema: assertObjectSchema(schema, toolName), strict },\n ];\n toolChoice = { type: 'tool', name: toolName };\n }\n\n if (!jsonSchema && params.tools?.length) {\n ({ tools, toolChoice } = buildAnthropicTools(params.tools, params.tool_choice));\n }\n\n // On models that only support adaptive thinking (Claude Opus 4.7 and\n // later, every Claude 5 tier model, see `supportsManualThinkingBudget`'s\n // docs), manual `budget_tokens` thinking returns a 400. Those models\n // still get a real reasoning control, adaptive thinking's own `effort`\n // parameter, converted from whichever of `reasoningEffort`/`budgetTokens`\n // the caller set, rather than either silently building a request that\n // will fail, or dropping the caller's intent to reason at all.\n let thinking: AnthropicRequestBody['thinking'];\n let effort: ClaudeAdaptiveEffort | undefined;\n\n if (params.budget_tokens !== undefined || params.reasoning_effort !== undefined) {\n // Checked once here, right before any thinking block is built, so a\n // caller who set budgetTokens/reasoningEffort alongside a forced\n // toolChoice (or a jsonSchema call that silently forces one to emulate\n // structured output on a non-native model, see toolChoice above) gets\n // a clear local error instead of a 400 after a real network round trip.\n assertNoForcedToolChoiceWithThinking(\n toolChoice?.type === 'tool'\n ? `toolChoice forcing the \"${toolChoice.name}\" tool`\n : toolChoice?.type === 'any'\n ? \"toolChoice: 'required' (Anthropic's \\\"any\\\" tool_choice)\"\n : undefined,\n );\n\n if (supportsManualThinkingBudget(params.model, adaptiveOnlyModels)) {\n const budgetTokens =\n params.budget_tokens ?? effortToBudgetTokens(params.reasoning_effort!, effortTokenTable);\n\n // Anthropic requires `budget_tokens` to be at least 1024 and\n // strictly less than `max_tokens`. Checked here, once, so a bad\n // combination (e.g. VernLLM's own default `maxTokens: 1000`, below\n // the 1024 floor) surfaces as a clear local error instead of a 400\n // after a real network round trip.\n assertValidClaudeBudgetTokens(budgetTokens, params.max_tokens);\n\n thinking = { type: 'enabled', budget_tokens: budgetTokens };\n } else {\n const effortTier =\n params.reasoning_effort ?? budgetTokensToEffort(params.budget_tokens!, effortTokenTable);\n\n thinking = { type: 'adaptive' };\n effort = toClaudeAdaptiveEffort(effortTier);\n }\n }\n\n const system = systemMessage?.content;\n\n // Anthropic rejects a non-default `temperature` (or `top_p`/`top_k`)\n // alongside *any* thinking mode, manual or adaptive, on every model\n // that supports thinking at all, not just the adaptive-only ones above.\n // VernLLM's own instance/call default is 0.2, not \"unset\", so without\n // this a `budgetTokens`/`reasoningEffort` call would silently attach\n // that default and get a 400 from Anthropic. Once `thinking` is going\n // out, `temperature` is dropped entirely so the provider applies its\n // own default, regardless of whether the 0.2 came from VernLLM's own\n // default or a caller-supplied value; Anthropic has no field that lets\n // a caller keep a custom temperature and thinking at the same time.\n const temperature = thinking ? undefined : params.temperature;\n\n const body: AnthropicRequestBody = {\n model: params.model,\n max_tokens: params.max_tokens,\n ...(temperature !== undefined ? { temperature } : {}),\n system: system || undefined,\n messages: mergeConsecutiveToolResults(conversationMessages.map((m) => toAnthropicMessage(m))),\n ...(tools ? { tools, tool_choice: toolChoice } : {}),\n ...(outputFormat || effort\n ? {\n output_config: {\n ...(outputFormat ? { format: outputFormat } : {}),\n ...(effort ? { effort } : {}),\n },\n }\n : {}),\n ...(thinking ? { thinking } : {}),\n };\n\n return { body, toolName };\n}\n\n/** Optional configuration for `fromAnthropic`. */\nexport interface AnthropicAdapterOptions {\n /**\n * Which models support native, schema-constrained output\n * (`output_config.format`), independent of `tools`/`tool_choice`, so it\n * can be combined with real `tools` in one request. Pass a static list\n * of model IDs (verified against Anthropic's own docs) or a predicate.\n *\n * There is no built-in default here (see `supportsNativeStructuredOutput`\n * for why). Left unset, every model uses the older forced-single-tool-\n * call emulation, and `tools` + `jsonSchema` together is rejected,\n * exactly this adapter's behavior before native support was added.\n */\n nativeStructuredOutputModels?: ModelCapabilityOverride;\n /**\n * Overrides the token count `reasoningEffort` tiers map onto when the\n * caller sets `reasoningEffort` but not `budgetTokens` (Claude has no\n * tier concept of its own, see `adapters/internal/reasoningBudget.utils.ts`).\n * Only the tiers listed are changed; any omitted tier keeps the\n * built-in default. Has no effect when `budgetTokens` is set directly.\n */\n reasoningEffortTokens?: Partial<EffortTokenTable>;\n /**\n * Marks additional models as adaptive-only, on top of this package's\n * own built-in rule (Claude Opus 4.7 and later, every Claude 5 tier\n * model, see `isAdaptiveOnlyModel` in\n * `adapters/internal/reasoningBudget.utils.ts`). Additive, not a\n * replacement: it can correct a false negative (a newer model this\n * package doesn't know about yet), it can't un-mark a model the\n * built-in rule already caught. Pass a static list of model IDs or a\n * predicate.\n */\n adaptiveOnlyModels?: ModelCapabilityOverride;\n}\n\n/**\n * Wraps an Anthropic SDK client so it satisfies the same `LLMClient`\n * interface VernLLM uses for OpenAI/Groq.\n *\n * `response_format: json_schema`, on a model covered by\n * `options.nativeStructuredOutputModels`, is sent as `output_config.format`,\n * its own request field, independent of `tools`/`tool_choice`, so it can be\n * combined with real, caller-supplied `tools` in the same request. Only\n * `type` and `schema` are sent on this path, the real Anthropic API's\n * `output_config.format` has no `name`/`description`/`strict` fields.\n *\n * On any other model (the default, since `nativeStructuredOutputModels` is\n * opt-in), `response_format: json_schema` is mapped to Anthropic's forced\n * tool-use instead: a single tool is defined with `input_schema` set to\n * the caller's schema, `description` forwarded when provided, and `strict`\n * forwarded when set, and `tool_choice` forces the model to call it. This\n * legacy path cannot be combined with real `tools` (both would need the\n * same `tools`/`tool_choice` field), and a call that tries throws\n * `LLMError('invalid_params')` with `code: 'unsupported_capability'` and\n * `issues: { capability: 'tools_with_json_schema' }` before reaching the API. Provider-constrained\n * schema matching applies only when `strict: true` is forwarded and\n * supported.\n *\n * `response_format: json_object` throws `LLMError('validation')`. Anthropic\n * has no API-level field that mechanically guarantees JSON output the way\n * OpenAI's `json_object` mode does; the only way to emulate it was a\n * system-prompt instruction with no actual enforcement behind it, a\n * guarantee this adapter no longer pretends to make. Use `jsonSchema`\n * instead, which maps to a real constraint either way (native\n * `output_config.format` or a forced tool call).\n */\nexport function fromAnthropic(\n anthropicClient: AnthropicClient,\n options?: AnthropicAdapterOptions,\n): LLMClient {\n const nativeStructuredOutputModels = options?.nativeStructuredOutputModels;\n const effortTokenTable = resolveEffortTokenTable(options?.reasoningEffortTokens);\n const adaptiveOnlyModels = options?.adaptiveOnlyModels;\n // The Anthropic SDK's `messages.create`, called with `stream: true`,\n // returns an AsyncIterable of `AnthropicStreamEvent` rather than\n // `AnthropicClient['messages']['create']`'s normal single-message return\n // type, hence `unknown` here and a cast at the call site, same\n // rationale as `fromOpenAICompatible`'s `rawCreate`: the wire contract,\n // not the SDK's own TS types, is what's actually relied on.\n const rawMessagesCreate = anthropicClient.messages.create.bind(\n anthropicClient.messages,\n ) as unknown as (\n params: unknown,\n options: { signal: AbortSignal },\n ) => Promise<unknown> | AsyncIterable<AnthropicStreamEvent>;\n\n return {\n // json_object is not supported: see buildAnthropicRequestBody's throw\n // above, and LLMClient.supportsJsonObjectMode's docs for why this is\n // false rather than the emulated-via-prompt-instruction default. Lets\n // RequestBuilder downgrade a default (unset) jsonMode to plain text\n // instead of requesting a mode this client can't honor.\n supportsJsonObjectMode: false,\n chat: {\n completions: {\n async create(params, options) {\n const { body, toolName } = buildAnthropicRequestBody(\n params,\n nativeStructuredOutputModels,\n effortTokenTable,\n adaptiveOnlyModels,\n );\n\n const response = await anthropicClient.messages.create(body, options);\n\n let text: string;\n let wireToolCalls: WireToolCall[] | undefined;\n if (toolName) {\n const toolUse = response.content.find(\n (block) => block.type === 'tool_use' && block.name === toolName,\n );\n\n if (!toolUse) {\n throw new LLMError(\n `Anthropic did not return the required structured output tool \"${toolName}\".`,\n 'validation',\n );\n }\n\n if (\n !toolUse.input ||\n typeof toolUse.input !== 'object' ||\n Array.isArray(toolUse.input)\n ) {\n throw new LLMError(\n `Anthropic returned invalid structured output for tool \"${toolName}\". Expected an object.`,\n 'validation',\n );\n }\n\n text = JSON.stringify(toolUse.input);\n } else {\n text = response.content\n .filter((block) => block.type === 'text')\n .map((block) => block.text ?? '')\n .join('');\n\n const toolUses = response.content.filter((block) => block.type === 'tool_use');\n\n if (toolUses.length) {\n wireToolCalls = toolUses.map((block) => ({\n id: block.id!,\n type: 'function' as const,\n function: { name: block.name!, arguments: JSON.stringify(block.input ?? {}) },\n }));\n }\n }\n\n return {\n choices: [\n {\n message: { content: text, ...(wireToolCalls ? { tool_calls: wireToolCalls } : {}) },\n },\n ],\n usage: {\n prompt_tokens: response.usage?.input_tokens,\n completion_tokens: response.usage?.output_tokens,\n total_tokens:\n (response.usage?.input_tokens ?? 0) + (response.usage?.output_tokens ?? 0),\n ...(response.usage?.output_tokens_details?.thinking_tokens !== undefined\n ? {\n completion_tokens_details: {\n reasoning_tokens: response.usage.output_tokens_details.thinking_tokens,\n },\n }\n : {}),\n },\n };\n },\n\n async *createStream(params, options) {\n const { body, toolName } = buildAnthropicRequestBody(\n params,\n nativeStructuredOutputModels,\n effortTokenTable,\n adaptiveOnlyModels,\n );\n\n const stream = (await rawMessagesCreate(\n { ...body, stream: true },\n options,\n )) as AsyncIterable<AnthropicStreamEvent>;\n\n // Tracks which content-block index is which kind, since Anthropic\n // interleaves text and tool_use blocks under a shared `index`\n // sequence and later delta events only carry that index, not the\n // kind. `json-tool` is the forced single-tool-call standing in\n // for `jsonSchema` output (see `toolName` above): its\n // input_json_delta fragments are re-emitted as `text-delta`, not\n // `tool_call_delta`, so the accumulated result lands in\n // finalizeResponse's `content` path exactly like the\n // non-streaming `create` branch above unwraps it.\n const blockKinds = new Map<number, 'text' | 'tool_use' | 'json-tool'>();\n let inputTokens = 0;\n let sawJsonTool = false;\n\n for await (const event of stream) {\n if (event.type === 'message_start') {\n inputTokens = event.message.usage?.input_tokens ?? 0;\n } else if (event.type === 'content_block_start') {\n if (event.content_block.type === 'tool_use') {\n const kind = event.content_block.name === toolName ? 'json-tool' : 'tool_use';\n\n blockKinds.set(event.index, kind);\n\n if (kind === 'json-tool') {\n sawJsonTool = true;\n } else if (!toolName) {\n // Only surface tool_use blocks as tool_call_delta chunks\n // when there's no forced structured-output tool in play.\n // When `toolName` is set, any non-matching tool_use block\n // is unexpected (Anthropic forces exactly one tool), and\n // surfacing it would corrupt the caller's expectation of\n // receiving only the forced tool's JSON payload as text.\n yield {\n type: 'tool_call_delta',\n index: event.index,\n id: event.content_block.id,\n name: event.content_block.name,\n };\n }\n } else {\n blockKinds.set(event.index, 'text');\n }\n } else if (event.type === 'content_block_delta') {\n if (event.delta.type === 'text_delta') {\n // Only surfaced as real content when there's no forced\n // json-schema tool in play. When `toolName` is set, the\n // *only* content that should end up in the accumulated\n // text is the forced tool's own JSON payload (its\n // input_json_delta fragments, handled below), exactly\n // what the non-streaming `create` branch above does by\n // discarding every content block except the matching\n // tool_use one. Anthropic can still emit genuine text\n // blocks alongside a forced tool call (a model narrating\n // before calling it, say), and without this guard those\n // would get concatenated into the same buffer as the\n // tool's JSON, corrupting it.\n if (!toolName) {\n yield { type: 'text-delta', delta: event.delta.text };\n }\n } else if (event.delta.type === 'input_json_delta') {\n const kind = blockKinds.get(event.index);\n\n if (kind === 'json-tool') {\n yield { type: 'text-delta', delta: event.delta.partial_json };\n } else if (!toolName) {\n yield {\n type: 'tool_call_delta',\n index: event.index,\n argumentsDelta: event.delta.partial_json,\n };\n }\n }\n } else if (event.type === 'message_delta') {\n const outputTokens = event.usage?.output_tokens ?? 0;\n const thinkingTokens = event.usage?.output_tokens_details?.thinking_tokens;\n\n yield {\n type: 'usage',\n usage: {\n prompt_tokens: inputTokens,\n completion_tokens: outputTokens,\n total_tokens: inputTokens + outputTokens,\n ...(thinkingTokens !== undefined\n ? { completion_tokens_details: { reasoning_tokens: thinkingTokens } }\n : {}),\n },\n } satisfies WireStreamChunk;\n } else if (event.type === 'ping') {\n // Keep-alive with no content. Yielding it resets the\n // idle-timeout clock in VernLLM's stream loop.\n yield { type: 'ping' };\n }\n }\n\n if (toolName && !sawJsonTool) {\n throw new LLMError(\n `Anthropic did not return the required structured output tool \"${toolName}\".`,\n 'validation',\n );\n }\n },\n },\n },\n };\n}\n\n/**\n * Anthropic requires strict role alternation, so the per-wire-message\n * mapping above (one `{role:'user', content:[tool_result]}` per VernLLM\n * wire tool message) needs merging back together when an assistant turn\n * requested more than one tool: multiple consecutive user turns would\n * violate that alternation, and Anthropic's API rejects it outright. This\n * merges any run of tool-result-only user messages into one, with all\n * their tool_result blocks combined, the shape Anthropic expects for \"here\n * are the results of everything you just asked for.\"\n */\nfunction mergeConsecutiveToolResults(\n messages: { role: 'user' | 'assistant'; content: string | AnthropicContentBlock[] }[],\n): { role: 'user' | 'assistant'; content: string | AnthropicContentBlock[] }[] {\n const isToolResultOnly = (\n m: (typeof messages)[number],\n ): m is { role: 'user'; content: AnthropicContentBlock[] } =>\n m.role === 'user' &&\n Array.isArray(m.content) &&\n m.content.length > 0 &&\n m.content.every((b) => b.type === 'tool_result');\n\n const merged: (typeof messages)[number][] = [];\n\n for (const m of messages) {\n const prev = merged.at(-1);\n\n if (isToolResultOnly(m) && prev && isToolResultOnly(prev)) {\n prev.content.push(...m.content);\n } else {\n merged.push(m);\n }\n }\n\n return merged;\n}\n\n/**\n * Translates one VernLLM wire message (OpenAI-shaped: plain user/assistant\n * turns, an assistant turn with `tool_calls`, or a `tool` turn) into\n * Anthropic's `{ role: 'user' | 'assistant', content }` shape.\n */\nfunction toAnthropicMessage(\n m: Extract<\n Parameters<LLMClient['chat']['completions']['create']>[0]['messages'][number],\n { role: 'user' | 'assistant' | 'tool' }\n >,\n): { role: 'user' | 'assistant'; content: string | AnthropicContentBlock[] } {\n if (m.role === 'tool') {\n // Anthropic has no 'tool' role: results travel as a user turn with\n // tool_result blocks.\n return {\n role: 'user',\n content: [\n {\n type: 'tool_result',\n tool_use_id: m.tool_call_id,\n content: m.content,\n ...(m.is_error ? { is_error: true } : {}),\n },\n ],\n };\n }\n\n if (m.role === 'assistant' && m.tool_calls?.length) {\n const blocks: AnthropicContentBlock[] = [];\n\n if (m.content) blocks.push({ type: 'text', text: m.content });\n\n for (const tc of m.tool_calls) {\n let input: unknown;\n\n try {\n input = tc.function.arguments.trim() ? JSON.parse(tc.function.arguments) : {};\n } catch (cause) {\n throw new LLMError(\n `Assistant tool call \"${tc.function.name}\" (${tc.id}) has arguments that are not valid JSON.`,\n 'validation',\n { cause },\n );\n }\n\n if (input === null || Array.isArray(input) || typeof input !== 'object') {\n throw new LLMError(\n `Assistant tool call \"${tc.function.name}\" (${tc.id}) arguments must be a JSON object.`,\n 'validation',\n );\n }\n\n blocks.push({ type: 'tool_use', id: tc.id, name: tc.function.name, input });\n }\n\n return { role: 'assistant', content: blocks };\n }\n\n return {\n role: m.role,\n content: Array.isArray(m.content) ? toAnthropicContent(m.content) : (m.content ?? ''),\n };\n}\n","import {\n LLMError,\n type ContentBlock,\n type LLMClient,\n type WireStreamChunk,\n type WireToolCall,\n} from '../types/index.js';\nimport { assertSupportedImageMimeType } from './internal/imageFormat.js';\nimport {\n budgetTokensToEffort,\n effortToBudgetTokens,\n resolveEffortTokenTable,\n toGeminiThinkingLevel,\n usesGeminiThinkingLevel,\n type EffortTokenTable,\n} from './internal/reasoningBudget.utils.js';\n\nimport type { ModelCapabilityOverride } from './internal/nativeStructuredOutput.js';\n\n/**\n * Gemini's native per-part content shape for a `contents` entry.\n * `functionCall.args` and `functionResponse.response` are typed as\n * `Record<string, unknown>` (not `unknown`) to match the real SDK's\n * `FunctionCall.args` / `FunctionResponse.response`, see the doc comment\n * on {@link GeminiClient}.\n */\ntype GeminiPart =\n | { text: string }\n | { inlineData: { mimeType: string; data: string } }\n | { functionCall: { id?: string; name: string; args: Record<string, unknown> } }\n | { functionResponse: { id?: string; name: string; response: Record<string, unknown> } };\n\n/**\n * Structural type matching the real `@google/genai` SDK, in either shape\n * it's commonly held in: the callable model methods directly (`ai.models`),\n * or the complete top-level client (`ai`, via the optional `models` field\n * below). Both work with `fromGemini` directly, with no cast:\n *\n * ```ts\n * import { GoogleGenAI } from '@google/genai';\n * const ai = new GoogleGenAI({ apiKey: '...' });\n * const llm = new VernLLM({ client: fromGemini(ai), model: 'gemini-2.5-flash' });\n * ```\n *\n * `generateContent` is optional so a `{ models: ... }`-shaped value is\n * still a structural `GeminiClient`; `fromGemini` resolves `models` at\n * runtime and throws if nothing callable results.\n *\n * Every field is shaped to be structurally assignable from the real SDK's\n * generated types without importing them, so provider SDKs stay optional:\n * `model` is required (the real SDK requires it), `functionCall.args` /\n * `functionResponse.response` are `Record<string, unknown>` (matching the\n * real SDK, not `unknown`), `toolConfig...mode` is `any` (TypeScript never\n * treats a string-literal union as assignable to the real SDK's string\n * enum), and response-side `functionCall.name` is optional (matching the\n * real SDK).\n */\nexport interface GeminiClient {\n /** Present when this is the whole top-level SDK client, not `ai.models`. `fromGemini` unwraps it at runtime. */\n models?: GeminiClient;\n\n generateContent?(params: {\n model: string;\n contents: Array<{ role: 'user' | 'model'; parts: GeminiPart[] }>;\n config?: {\n systemInstruction?: { parts: Array<{ text: string }> };\n temperature?: number;\n maxOutputTokens?: number;\n responseMimeType?: string;\n responseSchema?: Record<string, unknown>;\n tools?: Array<{\n functionDeclarations: Array<{\n name: string;\n description?: string;\n parameters: Record<string, unknown>;\n }>;\n }>;\n toolConfig?: {\n functionCallingConfig: {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- see class doc comment above\n mode: any;\n allowedFunctionNames?: string[];\n };\n };\n /**\n * Native reasoning control. `thinkingBudget` is built from\n * `CallParams.budgetTokens` directly when set (0 disables thinking,\n * -1 requests automatic budgeting, both passed through unchanged),\n * or converted from `reasoningEffort`, on Gemini 2.5 and earlier\n * models. `thinkingLevel` is used instead on Gemini 3 and later,\n * which use a level-based control rather than a numeric budget.\n * `any`, same reason as `toolConfig...mode` above, see class doc\n * comment. See `usesGeminiThinkingLevel` in\n * `adapters/internal/reasoningBudget.utils.ts`.\n */\n thinkingConfig?: {\n thinkingBudget?: number;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- see class doc comment above\n thinkingLevel?: any;\n };\n abortSignal?: AbortSignal;\n };\n }): Promise<{\n candidates?: Array<{\n content?: {\n parts?: Array<{\n text?: string;\n functionCall?: { id?: string; name?: string; args?: unknown };\n }>;\n };\n }>;\n usageMetadata?: {\n promptTokenCount?: number;\n candidatesTokenCount?: number;\n totalTokenCount?: number;\n thoughtsTokenCount?: number;\n };\n }>;\n\n /**\n * Optional. Required only for `stream: true` calls. Takes the same\n * request shape as `generateContent`. Matching the real SDK's own\n * `generateContentStream`, this resolves to an `AsyncIterable` (rather\n * than returning one synchronously) of partial responses, each chunk\n * holding the same `candidates[].content.parts[]` structure as\n * `generateContent`'s response, just incremental.\n */\n generateContentStream?(\n params: Parameters<NonNullable<GeminiClient['generateContent']>>[0],\n ): Promise<\n AsyncIterable<{\n candidates?: Array<{\n content?: {\n parts?: Array<{\n text?: string;\n functionCall?: { id?: string; name?: string; args?: unknown };\n }>;\n };\n }>;\n usageMetadata?: {\n promptTokenCount?: number;\n candidatesTokenCount?: number;\n totalTokenCount?: number;\n thoughtsTokenCount?: number;\n };\n }>\n >;\n}\n\n/**\n * Translates a VernLLM `ContentBlock[]` into Gemini's native `parts` array:\n * text blocks become `{ text }`, image blocks become inline data parts\n * (`{ inlineData: { mimeType, data } }`), Gemini's shape for embedding raw\n * base64 image bytes directly in the request.\n */\nfunction toGeminiParts(blocks: ContentBlock[]): GeminiPart[] {\n return blocks.map((block) =>\n block.type === 'image'\n ? { inlineData: { mimeType: assertSupportedImageMimeType(block.mimeType), data: block.data } }\n : { text: block.text },\n );\n}\n\n/**\n * Builds a wire tool_call id for a functionCall that Gemini did not assign\n * a native id to (models before Gemini 3). `occurrenceIndex` is how many\n * times this function name has already appeared earlier in the same\n * response, so repeated calls to the same tool in one turn get distinct\n * ids instead of colliding.\n */\nfunction synthesizeToolCallId(name: string, occurrenceIndex: number): string {\n return `${name}#${occurrenceIndex}`;\n}\n\n/** Maps VernLLM's OpenAI-shaped wire `tool_choice` onto Gemini's `functionCallingConfig`. */\nfunction toGeminiToolConfig(\n toolChoice: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice'],\n): NonNullable<\n NonNullable<Parameters<NonNullable<GeminiClient['generateContent']>>[0]['config']>['toolConfig']\n> {\n if (!toolChoice || toolChoice === 'auto') {\n return { functionCallingConfig: { mode: 'AUTO' } };\n }\n if (toolChoice === 'none') {\n return { functionCallingConfig: { mode: 'NONE' } };\n }\n if (toolChoice === 'required') {\n return { functionCallingConfig: { mode: 'ANY' } };\n }\n\n return {\n functionCallingConfig: { mode: 'ANY', allowedFunctionNames: [toolChoice.function.name] },\n };\n}\n\n/**\n * Builds a lookup of wire tool_call_id to function name, from every\n * assistant tool_calls entry in the conversation. The id itself carries no\n * meaning: it may be a real Gemini-issued id or one synthesized locally\n * when Gemini omitted one, and nothing here needs to tell those apart.\n * The name is always resolved from the assistant turn that made the call,\n * never derived from the id string.\n */\nfunction buildToolCallNameMap(\n messages: Parameters<LLMClient['chat']['completions']['create']>[0]['messages'],\n): Map<string, string> {\n const map = new Map<string, string>();\n\n for (const m of messages) {\n if (m.role === 'assistant') {\n for (const tc of m.tool_calls ?? []) {\n map.set(tc.id, tc.function.name);\n }\n }\n }\n\n return map;\n}\n\n/**\n * Translates one VernLLM wire message into a Gemini `contents` entry.\n * Gemini has no separate 'tool' role: a prior assistant tool request\n * becomes a `'model'` turn with `functionCall` parts, and its result\n * becomes a `'user'` turn with `functionResponse` parts.\n */\nfunction toGeminiContent(\n m: Extract<\n Parameters<LLMClient['chat']['completions']['create']>[0]['messages'][number],\n { role: 'user' | 'assistant' | 'tool' }\n >,\n toolCallNames: Map<string, string>,\n): { role: 'user' | 'model'; parts: GeminiPart[] } {\n if (m.role === 'tool') {\n // The name is resolved from the assistant turn that made this call,\n // never from the id's shape, so this is correct whether the id is a\n // real Gemini-issued id or one synthesized locally. The id itself is\n // passed through unchanged; Gemini 3 and later use it to correlate\n // this response with the original call.\n return {\n role: 'user',\n parts: [\n {\n functionResponse: {\n id: m.tool_call_id,\n name: toolCallNames.get(m.tool_call_id) ?? m.tool_call_id,\n response: parseToolResult(m.content),\n },\n },\n ],\n };\n }\n\n if (m.role === 'assistant' && m.tool_calls?.length) {\n const parts: GeminiPart[] = [];\n\n if (typeof m.content === 'string' && m.content) {\n parts.push({ text: m.content });\n }\n\n parts.push(\n ...m.tool_calls.map((tc) => ({\n functionCall: {\n id: tc.id,\n name: tc.function.name,\n args: parseToolArguments(tc.function.arguments, tc.function.name),\n },\n })),\n );\n\n return {\n role: 'model',\n parts,\n };\n }\n\n return {\n role: m.role === 'assistant' ? 'model' : 'user',\n parts: Array.isArray(m.content) ? toGeminiParts(m.content) : [{ text: m.content ?? '' }],\n };\n}\n\nfunction parseToolArguments(text: string, toolName: string): Record<string, unknown> {\n let parsed: unknown;\n\n try {\n parsed = text.trim() ? JSON.parse(text) : {};\n } catch (cause) {\n throw new LLMError(`Tool call \"${toolName}\" arguments are not valid JSON.`, 'parse', {\n cause,\n code: 'tool_arguments_parse_failed',\n });\n }\n\n if (!parsed || Array.isArray(parsed) || typeof parsed !== 'object') {\n throw new LLMError(`Tool call \"${toolName}\" arguments must be a JSON object.`, 'validation');\n }\n\n return parsed as Record<string, unknown>;\n}\n\n/**\n * Parses a wire tool message's `content` into the object Gemini's\n * `functionResponse.response` expects. Gemini (and the real SDK's\n * `FunctionResponse.response` type) requires an object, so a result that\n * parses to something other than a plain JSON object (a string, number,\n * array, or unparseable text) is wrapped under an `output` key, mirroring\n * Gemini's own documented convention for non-object function results.\n */\nfunction parseToolResult(text: string): Record<string, unknown> {\n let parsed: unknown;\n\n try {\n parsed = text.trim() ? JSON.parse(text) : '';\n } catch {\n parsed = text;\n }\n\n if (parsed && !Array.isArray(parsed) && typeof parsed === 'object') {\n return parsed as Record<string, unknown>;\n }\n\n return { output: parsed };\n}\n\n/**\n * Gemini expects the results of everything the model asked for in one turn\n * to arrive together as multiple `functionResponse` parts on a single\n * `'user'` entry, not as separate consecutive `'user'` entries. The\n * per-wire-message mapping above produces one `'user'` entry per VernLLM\n * wire tool message, so when an assistant turn requested more than one\n * tool, this merges the resulting run of functionResponse-only `'user'`\n * entries back into one.\n */\nfunction mergeConsecutiveFunctionResponses(\n contents: { role: 'user' | 'model'; parts: GeminiPart[] }[],\n): { role: 'user' | 'model'; parts: GeminiPart[] }[] {\n const isFunctionResponseOnly = (\n c: (typeof contents)[number],\n ): c is { role: 'user'; parts: GeminiPart[] } =>\n c.role === 'user' && c.parts.length > 0 && c.parts.every((p) => 'functionResponse' in p);\n\n const merged: (typeof contents)[number][] = [];\n\n for (const c of contents) {\n const prev = merged.at(-1);\n\n if (isFunctionResponseOnly(c) && prev && isFunctionResponseOnly(prev)) {\n prev.parts.push(...c.parts);\n } else {\n merged.push(c);\n }\n }\n\n return merged;\n}\n\ntype GeminiRequest = Parameters<NonNullable<GeminiClient['generateContent']>>[0];\ntype GeminiConfig = NonNullable<GeminiRequest['config']>;\n\n/**\n * Builds the Gemini-shaped request from VernLLM's wire params, shared\n * between `create` and `createStream` so both go through identical\n * translation (contents shaping, `responseSchema`/`responseMimeType`\n * mapping, and tool/toolConfig translation all happen exactly once).\n * `abortSignal` is folded into `config` by the caller (`create`/\n * `createStream`), once the request options are available.\n */\nfunction buildGeminiRequest(\n params: Parameters<LLMClient['chat']['completions']['create']>[0],\n effortTokenTable?: EffortTokenTable,\n thinkingLevelModels?: ModelCapabilityOverride,\n): GeminiRequest {\n const systemMessage = params.messages.find((m) => m.role === 'system');\n // Keep user, assistant, and tool turns, in order.\n const conversationMessages = params.messages.filter(\n (m) => m.role === 'user' || m.role === 'assistant' || m.role === 'tool',\n );\n\n const wantsJson = Boolean(params.response_format);\n const config: GeminiConfig = {\n ...(params.temperature !== undefined ? { temperature: params.temperature } : {}),\n maxOutputTokens: params.max_tokens,\n ...(systemMessage\n ? // System turns are always plain strings; only user turns can carry ContentBlock[]\n { systemInstruction: { parts: [{ text: systemMessage.content as string }] } }\n : {}),\n };\n\n if (wantsJson) {\n config.responseMimeType = 'application/json';\n }\n\n if (params.response_format?.type === 'json_schema') {\n const { schema, description } = params.response_format.json_schema;\n\n config.responseSchema = {\n ...schema,\n ...(description ? { description } : {}),\n };\n }\n\n if (params.tools?.length) {\n config.tools = [\n {\n functionDeclarations: params.tools.map((t) => ({\n name: t.function.name,\n description: t.function.description,\n parameters: t.function.parameters,\n })),\n },\n ];\n config.toolConfig = toGeminiToolConfig(params.tool_choice);\n }\n\n // On Gemini 3 and later, `thinkingConfig.thinkingLevel` is the native\n // reasoning control, not `thinkingBudget`. `reasoning_effort` maps onto\n // it directly (VernLLM's own four tiers line up exactly with Gemini's\n // level enum). When only `budget_tokens` was set, it's converted to\n // the nearest tier first, same table used elsewhere. Sending\n // `thinkingBudget` there instead still works for backward\n // compatibility, per Google's own docs, but \"may result in unexpected\n // performance\", so VernLLM switches over rather than keeping every\n // Gemini generation on the older field indefinitely. Note that 0\n // (disabled) and -1 (automatic) have no `thinkingLevel` equivalent:\n // both collapse to `minimal` through the same conversion table,\n // `MINIMAL` being the closest available approximation of \"off\", which\n // several Gemini 3 models can't be fully disabled on anyway.\n if (usesGeminiThinkingLevel(params.model, thinkingLevelModels)) {\n const effortTier =\n params.reasoning_effort ??\n (params.budget_tokens !== undefined\n ? budgetTokensToEffort(params.budget_tokens, effortTokenTable)\n : undefined);\n\n if (effortTier !== undefined) {\n config.thinkingConfig = { thinkingLevel: toGeminiThinkingLevel(effortTier, params.model) };\n }\n } else {\n // `thinkingBudget` is Gemini's native reasoning control on 2.5 and\n // earlier, 0 disables thinking and -1 requests automatic budgeting,\n // both passed through unchanged rather than run through the effort\n // table below. Used directly when the caller set `budget_tokens`.\n // When only `reasoning_effort` was set, it's converted to the\n // nearest token budget, since these models have no tier string of\n // their own.\n const thinkingBudget =\n params.budget_tokens ??\n (params.reasoning_effort\n ? effortToBudgetTokens(params.reasoning_effort, effortTokenTable)\n : undefined);\n\n if (thinkingBudget !== undefined) {\n config.thinkingConfig = { thinkingBudget };\n }\n }\n\n const toolCallNames = buildToolCallNameMap(conversationMessages);\n\n return {\n model: params.model,\n contents: mergeConsecutiveFunctionResponses(\n conversationMessages.map((m) => toGeminiContent(m, toolCallNames)),\n ),\n config,\n };\n}\n\n/**\n * Wraps a Gemini client so it satisfies the `LLMClient` interface VernLLM\n * uses for OpenAI-compatible APIs. Gemini's shape differs on nearly every\n * axis: a `contents` array instead of `messages`, a separate\n * `systemInstruction` field instead of a `system` role message,\n * `generationConfig` instead of top-level `temperature`/`max_tokens`, and\n * native JSON Schema support via `responseMimeType: 'application/json'` +\n * `responseSchema`. `reasoning_effort` has no native Gemini equivalent, so\n * it's converted to a `thinkingConfig.thinkingBudget` token count; `budget_tokens`\n * maps to `thinkingBudget` directly, Gemini's native reasoning control. See\n * `adapters/internal/reasoningBudget.utils.ts`.\n *\n * `tools` maps to Gemini's native `functionDeclarations`/`functionCall`;\n * `tool_choice` maps to `toolConfig.functionCallingConfig`. Gemini accepts\n * `responseSchema` and `tools` in the same request natively, so both are\n * set independently here and no special-casing is needed for the\n * combination, unlike `fromAnthropic`/`fromBedrock`.\n *\n * `createStream` calls `generateContentStream` (optional on `GeminiClient`\n *, required only if the caller sets `stream: true`) and translates each\n * partial response into `WireStreamChunk`s. Unlike OpenAI/Anthropic,\n * Gemini's own function-calling API doesn't stream tool-call arguments\n * incrementally: a `functionCall` part always arrives whole in one chunk,\n * so each one is emitted as a single, complete `tool_call_delta` (a\n * one-shot \"delta\" containing the full arguments) rather than accumulated\n * fragments, that's a real difference in the underlying API, not\n * something this adapter can smooth over. `usageMetadata` is (per Gemini's\n * own behavior) only reliably present on the last chunk, so the `usage`\n * `WireStreamChunk` is emitted once, after the stream completes, from\n * whichever chunk's `usageMetadata` was seen last.\n *\n * Accepts a `GeminiClient` in either shape it structurally covers: the\n * callable model methods directly (`ai.models`), or the complete\n * top-level client (`ai`), unwrapping `.models` internally when present.\n * Both work with no cast: `fromGemini(ai.models)` and `fromGemini(ai)`.\n * Throws `LLMError('invalid_params')` up front if nothing callable\n * results.\n */\nexport interface GeminiAdapterOptions {\n /**\n * Overrides the token count `reasoningEffort` tiers map onto when the\n * caller sets `reasoningEffort` but not `budgetTokens` (Gemini has no\n * tier string of its own, see `adapters/internal/reasoningBudget.utils.ts`).\n * Only the tiers listed are changed; any omitted tier keeps the\n * built-in default. Has no effect when `budgetTokens` is set directly.\n */\n reasoningEffortTokens?: Partial<EffortTokenTable>;\n /**\n * Marks additional models as using `thinkingLevel` instead of\n * `thinkingBudget`, on top of this package's own built-in rule (every\n * Gemini 3 series model and later, see `usesGeminiThinkingLevel` in\n * `adapters/internal/reasoningBudget.utils.ts`). Additive, not a\n * replacement: it can correct a false negative (a newer model this\n * package doesn't know about yet), it can't un-mark a model the\n * built-in rule already caught. Pass a static list of model IDs or a\n * predicate.\n */\n thinkingLevelModels?: ModelCapabilityOverride;\n}\n\nexport function fromGemini(client: GeminiClient, options?: GeminiAdapterOptions): LLMClient {\n const effortTokenTable = resolveEffortTokenTable(options?.reasoningEffortTokens);\n const thinkingLevelModels = options?.thinkingLevelModels;\n const resolved = client.models ?? client;\n\n if (typeof resolved.generateContent !== 'function') {\n throw new LLMError(\n 'fromGemini requires a client with generateContent: pass ai.models, or the whole ai client (fromGemini(ai)).',\n 'invalid_params',\n { code: 'unsupported_capability', issues: { capability: 'generateContent' } },\n );\n }\n\n const generateContent = resolved.generateContent.bind(resolved);\n const generateContentStream =\n typeof resolved.generateContentStream === 'function'\n ? resolved.generateContentStream.bind(resolved)\n : undefined;\n\n return {\n chat: {\n completions: {\n async create(params, options) {\n const request = buildGeminiRequest(params, effortTokenTable, thinkingLevelModels);\n request.config = { ...request.config, abortSignal: options.signal };\n\n const response = await generateContent(request);\n\n const parts = response.candidates?.[0]?.content?.parts ?? [];\n const text = parts.map((p) => p.text ?? '').join('');\n const functionCalls = parts.filter((p) => p.functionCall);\n\n let wireToolCalls: WireToolCall[] | undefined;\n\n if (functionCalls.length) {\n const nameOccurrence = new Map<string, number>();\n\n wireToolCalls = functionCalls.map((p) => {\n // INVARIANT: `name` is typed optional (matching the real\n // SDK's own `FunctionCall.name?: string`), but Gemini always\n // populates it on an actual function call part in practice;\n // the `!` here asserts that invariant, same rationale as the\n // `complete: true` invariant on the streaming path below.\n const name = p.functionCall!.name!;\n const nativeId = p.functionCall!.id;\n const occurrenceIndex = nameOccurrence.get(name) ?? 0;\n nameOccurrence.set(name, occurrenceIndex + 1);\n\n return {\n // Gemini 3 and later always populate a native, unique `id`\n // on every functionCall, meant to be echoed back on the\n // matching functionResponse for correlation. Models before\n // Gemini 3 never populate it, in which case an id is\n // synthesized from the name plus how many times that name\n // has already appeared in this response, so two calls to\n // the same tool in one turn still get distinct ids. Either\n // way, this id is opaque from here on: nothing downstream\n // inspects its shape to decide whether it's native or\n // synthesized.\n id: nativeId ?? synthesizeToolCallId(name, occurrenceIndex),\n type: 'function' as const,\n function: {\n name,\n arguments: JSON.stringify(p.functionCall!.args ?? {}),\n },\n };\n });\n }\n\n return {\n choices: [\n {\n message: { content: text, ...(wireToolCalls ? { tool_calls: wireToolCalls } : {}) },\n },\n ],\n usage: {\n prompt_tokens: response.usageMetadata?.promptTokenCount,\n completion_tokens: response.usageMetadata?.candidatesTokenCount,\n total_tokens: response.usageMetadata?.totalTokenCount,\n ...(response.usageMetadata?.thoughtsTokenCount !== undefined\n ? {\n completion_tokens_details: {\n reasoning_tokens: response.usageMetadata.thoughtsTokenCount,\n },\n }\n : {}),\n },\n };\n },\n\n async *createStream(params, options) {\n if (!generateContentStream) {\n throw new LLMError(\n 'stream: true requires a Gemini client with generateContentStream',\n 'invalid_params',\n { code: 'unsupported_capability', issues: { capability: 'generateContentStream' } },\n );\n }\n\n const request = buildGeminiRequest(params, effortTokenTable, thinkingLevelModels);\n request.config = { ...request.config, abortSignal: options.signal };\n\n const stream = await generateContentStream(request);\n\n let toolCallIndex = 0;\n const nameOccurrence = new Map<string, number>();\n let lastUsage:\n | NonNullable<\n Awaited<ReturnType<NonNullable<GeminiClient['generateContent']>>>['usageMetadata']\n >\n | undefined;\n\n for await (const chunk of stream) {\n const parts = chunk.candidates?.[0]?.content?.parts ?? [];\n\n for (const part of parts) {\n if (part.text) {\n yield { type: 'text-delta', delta: part.text };\n }\n\n if (part.functionCall) {\n const name = part.functionCall.name;\n const nativeId = part.functionCall.id;\n const occurrenceIndex = name ? (nameOccurrence.get(name) ?? 0) : 0;\n if (name) nameOccurrence.set(name, occurrenceIndex + 1);\n\n yield {\n type: 'tool_call_delta',\n index: toolCallIndex,\n id: nativeId ?? (name ? synthesizeToolCallId(name, occurrenceIndex) : undefined),\n name: part.functionCall.name,\n argumentsDelta: JSON.stringify(part.functionCall.args ?? {}),\n // INVARIANT: assumes Gemini always sends a complete\n // function-call args blob per part, no incremental\n // streaming, per current API behavior. There is no field\n // on this minimal structural type to derive this from.\n // If Gemini ever starts streaming args incrementally,\n // this becomes silently wrong. See the test titled\n // \"INVARIANT: hardcodes complete: true on\n // tool_call_delta\" in gemini.stream.unit.test.ts, which\n // exists specifically to catch that drift.\n complete: true,\n } satisfies WireStreamChunk;\n toolCallIndex++;\n }\n }\n\n if (chunk.usageMetadata) {\n lastUsage = chunk.usageMetadata;\n }\n }\n\n if (lastUsage) {\n yield {\n type: 'usage',\n usage: {\n prompt_tokens: lastUsage.promptTokenCount,\n completion_tokens: lastUsage.candidatesTokenCount,\n total_tokens: lastUsage.totalTokenCount,\n ...(lastUsage.thoughtsTokenCount !== undefined\n ? {\n completion_tokens_details: { reasoning_tokens: lastUsage.thoughtsTokenCount },\n }\n : {}),\n },\n };\n }\n },\n },\n },\n };\n}\n","import {\n LLMError,\n type ContentBlock,\n type LLMClient,\n type WireStreamChunk,\n type WireToolCall,\n} from '../types/index.js';\nimport { assertSupportedImageMimeType } from './internal/imageFormat.js';\nimport {\n supportsNativeStructuredOutput,\n type ModelCapabilityOverride,\n} from './internal/nativeStructuredOutput.js';\nimport {\n assertNoForcedToolChoiceWithThinking,\n assertValidClaudeBudgetTokens,\n budgetTokensToEffort,\n effortToBudgetTokens,\n resolveEffortTokenTable,\n supportsManualThinkingBudget,\n toClaudeAdaptiveEffort,\n type ClaudeAdaptiveEffort,\n type EffortTokenTable,\n} from './internal/reasoningBudget.utils.js';\n\n/**\n * Default heuristic for whether a Bedrock model id is a Claude model,\n * matching AWS's own `anthropic.claude-*`/`us.anthropic.claude-*` naming.\n * Only used to decide whether a reasoning token budget is worth forwarding\n * through `additionalModelRequestFields`, not a general capability check,\n * so a plain substring match is enough, no override hook needed the way\n * `nativeStructuredOutputModels`/`toolUseSupportedModels` have one: a\n * false positive here just sends an inert extra field, not a request that\n * fails outright.\n */\nfunction isClaudeModel(model: string): boolean {\n return model.includes('claude');\n}\n\n/** Bedrock Converse's supported inline image formats. */\ntype BedrockImageFormat = 'png' | 'jpeg' | 'gif' | 'webp';\n\n/** Bedrock Converse's native per-block content shape for a message. */\ntype BedrockContentBlock =\n | { text: string }\n | { image: { format: BedrockImageFormat; source: { bytes: Uint8Array } } }\n | { toolUse: { toolUseId: string; name: string; input: unknown } }\n | {\n toolResult: {\n toolUseId: string;\n content: Array<{ text: string }>;\n status?: 'success' | 'error';\n };\n };\n\n/**\n * Minimal structural type matching AWS Bedrock's Converse API. This is\n * intentionally NOT `BedrockRuntimeClient` itself, the AWS SDK v3 client\n * exposes `.send(command)`, not a direct `.converse()` method, and pulling\n * in `@aws-sdk/client-bedrock-runtime` as a dependency just for its types\n * isn't worth it for a structural adapter. Wrap your client, e.g:\n *\n * ```ts\n * import { BedrockRuntimeClient, ConverseCommand } from '@aws-sdk/client-bedrock-runtime';\n * const client = new BedrockRuntimeClient({ region: 'us-east-1' });\n * const converseClient = {\n * converse: (params, options) =>\n * client.send(new ConverseCommand(params), { abortSignal: options.signal }),\n * };\n * ```\n */\nexport interface BedrockConverseClient {\n converse(\n params: {\n modelId: string;\n messages: Array<{ role: 'user' | 'assistant'; content: BedrockContentBlock[] }>;\n system?: Array<{ text: string }>;\n inferenceConfig?: { temperature?: number; maxTokens?: number };\n toolConfig?: {\n tools: Array<{\n toolSpec: {\n name: string;\n description?: string;\n inputSchema: { json: Record<string, unknown> };\n strict?: boolean;\n };\n }>;\n toolChoice?:\n | { tool: { name: string } }\n | { auto: Record<string, never> }\n | { any: Record<string, never> };\n };\n /**\n * Native, schema-constrained output: a separate request field from\n * `toolConfig`, so it can be sent alongside real tool calls. Only\n * built by this adapter for models covered by\n * `nativeStructuredOutputModels` (opt-in, see\n * `BedrockAdapterOptions`); other models keep getting `jsonSchema`\n * emulated as a forced single tool call via `toolConfig`, the\n * pre-existing behavior.\n *\n * Matches the real Bedrock Converse API's `outputConfig.textFormat`\n * shape exactly: the schema itself is nested one level deeper, under\n * `structure.jsonSchema`, not flat on `textFormat`, and `schema` is\n * a JSON-encoded *string*, not a parsed object, unlike every other\n * schema field this adapter builds (`toolSpec.inputSchema.json`\n * included). There is no `strict` field here, unlike `toolSpec`.\n */\n outputConfig?: {\n textFormat?: {\n type: 'json_schema';\n structure: {\n jsonSchema: {\n schema: string;\n name?: string;\n description?: string;\n };\n };\n };\n /**\n * Effort control for adaptive thinking, on Claude models where\n * manual `budget_tokens` thinking is no longer accepted (see\n * `supportsManualThinkingBudget` in\n * `adapters/internal/reasoningBudget.utils.ts`). Sibling to\n * `textFormat`, either or both may be present independently.\n */\n effort?: 'low' | 'medium' | 'high' | 'xhigh' | 'max';\n };\n /**\n * Model-specific passthrough. Converse has no reasoning-budget field\n * of its own, so a token budget for a Claude model on Bedrock is\n * forwarded here under Anthropic's own key, `{ thinking: { type:\n * 'enabled', budget_tokens } }`. Non-Claude models get nothing here,\n * there is no equivalent field to reach for.\n */\n additionalModelRequestFields?: Record<string, unknown>;\n },\n options: { signal: AbortSignal },\n ): Promise<{\n output?: {\n message?: {\n content?: Array<{\n text?: string;\n toolUse?: { toolUseId?: string; name?: string; input?: unknown };\n }>;\n };\n };\n usage?: { inputTokens?: number; outputTokens?: number; totalTokens?: number };\n }>;\n\n /**\n * Optional. Required only for `stream: true` calls. Takes the same\n * request shape `converse` does, returning `{ stream }`, matching\n * `ConverseStreamCommand`'s real AWS SDK v3 output shape, an\n * `AsyncIterable` of incremental events under a `stream` property,\n * rather than the whole response being the iterable directly.\n */\n converseStream?(\n params: Parameters<BedrockConverseClient['converse']>[0],\n options: { signal: AbortSignal },\n ): Promise<{ stream: AsyncIterable<BedrockConverseStreamEvent> }>;\n}\n\n/**\n * One event of a Bedrock `ConverseStreamCommand` response's `stream`.\n * Content blocks (text or toolUse) are identified by `contentBlockIndex`,\n * Converse's own convention for correlating start/delta/stop events across\n * possibly-interleaved blocks, mirrored directly by VernLLM's\n * `tool_call_delta.index`.\n */\ntype BedrockConverseStreamEvent =\n | { messageStart: { role: 'assistant' } }\n | {\n contentBlockStart: {\n contentBlockIndex: number;\n start?: { toolUse?: { toolUseId?: string; name?: string } };\n };\n }\n | {\n contentBlockDelta: {\n contentBlockIndex: number;\n delta?: { text?: string } | { toolUse?: { input?: string } };\n };\n }\n | { contentBlockStop: { contentBlockIndex: number } }\n | { messageStop: { stopReason?: string } }\n | {\n metadata: {\n usage?: { inputTokens?: number; outputTokens?: number; totalTokens?: number };\n };\n }\n // The above are the happy-path events. Bedrock Converse streams can also\n // emit these as in-band exception events (not promise rejections), so\n // they need to be modeled and handled explicitly below, an unmatched\n // event previously fell through the if/else chain silently, either\n // truncating output or leaving the stream hanging until an unrelated\n // idle timeout fired.\n | { internalServerException: { message?: string } }\n | { modelStreamErrorException: { message?: string; originalStatusCode?: number } }\n | { validationException: { message?: string } }\n | { throttlingException: { message?: string } }\n | { serviceUnavailableException: { message?: string } };\n\n/** Maps a `ContentBlock` image MIME type, already validated, to Converse's `format` enum. */\nfunction toBedrockImageFormat(mimeType: string): BedrockImageFormat {\n switch (assertSupportedImageMimeType(mimeType)) {\n case 'image/png':\n return 'png';\n case 'image/jpeg':\n return 'jpeg';\n case 'image/gif':\n return 'gif';\n case 'image/webp':\n return 'webp';\n }\n}\n\n/**\n * Decodes base64 image data into the raw `Uint8Array` bytes Converse's\n * `image.source.bytes` expects (unlike Anthropic/Gemini/OpenAI, which all\n * take base64 strings directly). Uses `Buffer`, since this adapter, like\n * the rest of the package, targets Node.\n */\nfunction decodeBase64(data: string): Uint8Array {\n return new Uint8Array(Buffer.from(data, 'base64'));\n}\n\n/**\n * Translates a VernLLM `ContentBlock[]` into Converse's native content-block\n * array: text blocks pass through as `{ text }`, image blocks become\n * `{ image: { format, source: { bytes } } }` with the base64 payload decoded\n * to raw bytes, since Converse doesn't accept base64 strings directly.\n */\nfunction toBedrockContent(blocks: ContentBlock[]): BedrockContentBlock[] {\n return blocks.map((block) =>\n block.type === 'image'\n ? {\n image: {\n format: toBedrockImageFormat(block.mimeType),\n source: { bytes: decodeBase64(block.data) },\n },\n }\n : { text: block.text },\n );\n}\n\n/**\n * Optional configuration for `fromBedrock`.\n */\nexport interface BedrockAdapterOptions {\n /**\n * Optional preflight check for tool-use support, needed whenever a\n * `jsonSchema` call ends up sending Converse `toolConfig` — either the\n * legacy forced-single-tool-call emulation, or real `tools` sent\n * alongside native structured output (`outputConfig`). VernLLM never\n * guesses capability from a failed call's error message (AWS's error\n * text isn't a documented, stable contract), so this is opt-in: pass\n * either a static list of tool-use-capable model IDs, or a predicate\n * function, and VernLLM will reject unsupported models with a clear\n * `LLMError('validation')` *before* dispatching the request, instead of\n * on the wire.\n *\n * Left unset (default), no preflight check runs, and a `jsonSchema` call\n * to an unsupported model surfaces Bedrock's raw `converse` error as-is.\n */\n toolUseSupportedModels?: string[] | ((modelId: string) => boolean);\n\n /**\n * Which models support native, schema-constrained output\n * (`outputConfig.textFormat`), independent of `toolConfig`, so it can be\n * combined with real `tools` in one request. Pass a static list of\n * model IDs (verified against Bedrock's own docs) or a predicate.\n *\n * There is no built-in default here (see `supportsNativeStructuredOutput`\n * for why). Left unset, every model uses the older forced-single-tool-\n * call emulation via `toolConfig`, and `tools` + `jsonSchema` together is\n * rejected, exactly this adapter's behavior before native support was\n * added.\n */\n nativeStructuredOutputModels?: ModelCapabilityOverride;\n\n /**\n * Overrides the token count `reasoningEffort` tiers map onto when the\n * caller sets `reasoningEffort` but not `budgetTokens` (Converse has no\n * tier string of its own, see `adapters/internal/reasoningBudget.utils.ts`).\n * Only the tiers listed are changed; any omitted tier keeps the\n * built-in default. Has no effect when `budgetTokens` is set directly,\n * or when the target model isn't a Claude model.\n */\n reasoningEffortTokens?: Partial<EffortTokenTable>;\n /**\n * Marks additional models as adaptive-only, on top of this package's\n * own built-in rule (Claude Opus 4.7 and later, every Claude 5 tier\n * model, see `isAdaptiveOnlyModel` in\n * `adapters/internal/reasoningBudget.utils.ts`). Additive, not a\n * replacement: it can correct a false negative (a newer model this\n * package doesn't know about yet), it can't un-mark a model the\n * built-in rule already caught. Pass a static list of model IDs or a\n * predicate.\n */\n adaptiveOnlyModels?: ModelCapabilityOverride;\n}\n\ntype BedrockRequest = Parameters<BedrockConverseClient['converse']>[0];\n\n/**\n * Maps VernLLM's OpenAI-shaped wire `tools`/`tool_choice` into Converse's\n * `toolConfig` shape. Shared by the two call sites that build real\n * (non-schema-forced) tool definitions: the plain tools-only branch, and\n * the native-structured-output branch, which sends real tools alongside\n * `outputConfig` rather than instead of it.\n */\nfunction buildBedrockToolConfig(\n tools: NonNullable<Parameters<LLMClient['chat']['completions']['create']>[0]['tools']>,\n toolChoiceParam: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice'],\n): NonNullable<BedrockRequest['toolConfig']> {\n return {\n tools: tools.map((t) => ({\n toolSpec: {\n name: t.function.name,\n description: t.function.description,\n inputSchema: { json: t.function.parameters },\n },\n })),\n toolChoice: toBedrockToolChoice(toolChoiceParam),\n };\n}\n\n/**\n * Builds the Converse-shaped request from VernLLM's wire params, shared\n * between `create` and `createStream` so both go through identical\n * translation (system prompt, message shaping, the jsonSchema →\n * forced-single-tool mapping, and the `toolUseSupportedModels` preflight\n * check all happen exactly once).\n *\n * Returns `toolName` alongside the request: when set, the model was forced\n * to call a single synthetic tool standing in for `jsonSchema` output (the\n * legacy path, for models not covered by `nativeStructuredOutputModels`),\n * and both `create` and `createStream` need to know this so they can\n * unwrap that tool call back into plain text content instead of treating\n * it like a real tool call. On the native path (model covered by\n * `nativeStructuredOutputModels`), `toolName` is `undefined`: the\n * schema-conforming JSON already arrives as ordinary text content, nothing\n * to unwrap, and any real tool calls in `params.tools` are left for the\n * normal, non-forced tool-call handling both `create` and `createStream`\n * already do when `toolName` is unset.\n */\nfunction buildBedrockRequest(\n params: Parameters<LLMClient['chat']['completions']['create']>[0],\n toolUseSupportedModels: BedrockAdapterOptions['toolUseSupportedModels'],\n nativeStructuredOutputModels: BedrockAdapterOptions['nativeStructuredOutputModels'],\n effortTokenTable?: EffortTokenTable,\n adaptiveOnlyModels?: ModelCapabilityOverride,\n): { request: BedrockRequest; toolName: string | undefined } {\n const systemMessage = params.messages.find((m) => m.role === 'system');\n\n // Keep user, assistant, and tool turns, in order. Converse has no\n // separate 'tool' role: tool results travel as a user-role message\n // with toolResult content blocks, and an assistant's tool\n // requests travel as toolUse content blocks on its own turn.\n const conversationMessages = params.messages.filter(\n (m) => m.role === 'user' || m.role === 'assistant' || m.role === 'tool',\n );\n\n const jsonSchema =\n params.response_format?.type === 'json_schema' ? params.response_format.json_schema : undefined;\n\n const schemaName = jsonSchema?.name.trim();\n\n if (jsonSchema && !schemaName) {\n throw new LLMError('json_schema.name must not be empty.', 'validation');\n }\n\n const isNative =\n Boolean(jsonSchema) &&\n supportsNativeStructuredOutput(params.model, nativeStructuredOutputModels);\n\n if (jsonSchema && params.tools?.length && !isNative) {\n throw new LLMError(\n `Bedrock model \"${params.model}\" is not covered by nativeStructuredOutputModels, so ` +\n '`jsonSchema` is emulated as a forced single tool call there (via `toolConfig`), which ' +\n 'collides with the `tools` you also provided. Either drop `tools` or `jsonSchema` for this ' +\n \"call, or pass this model in fromBedrock's `nativeStructuredOutputModels` option once \" +\n \"you've confirmed it supports Converse's `outputConfig.textFormat`.\",\n 'invalid_params',\n { code: 'unsupported_capability', issues: { capability: 'tools_with_json_schema' } },\n );\n }\n\n if (params.response_format?.type === 'json_object') {\n throw new LLMError(\n 'response_format: \"json_object\" is not supported on Bedrock. Converse has no field that ' +\n 'mechanically guarantees valid JSON output for this mode, so it used to be emulated by ' +\n 'injecting a \"respond with JSON only\" instruction into the system prompt, a guarantee ' +\n 'this adapter can no longer make. Use `jsonSchema` instead, which maps to a real ' +\n \"constraint (Converse's native outputConfig.textFormat on covered models, or a forced \" +\n 'tool call otherwise).',\n 'validation',\n );\n }\n\n let toolName: string | undefined;\n let toolConfig: NonNullable<BedrockRequest['toolConfig']> | undefined;\n let outputConfig: NonNullable<BedrockRequest['outputConfig']> | undefined;\n\n if (jsonSchema && isNative) {\n // Native path: the schema goes in its own request field, independent\n // of toolConfig, so real tools (if any) are built exactly like the\n // tools-only branch below and sent alongside it.\n //\n // Unlike every other schema this adapter builds, the real Bedrock\n // Converse API requires `schema` here as a JSON-encoded *string*, not\n // a parsed object, nested under `structure.jsonSchema` rather than\n // flat on `textFormat`. There is no `strict` field on this path,\n // unlike `toolSpec`.\n const { schema, description } = jsonSchema;\n\n outputConfig = {\n textFormat: {\n type: 'json_schema',\n structure: {\n jsonSchema: { schema: JSON.stringify(schema), name: schemaName, description },\n },\n },\n };\n } else if (jsonSchema && schemaName) {\n // Legacy path: jsonSchema alone (or with tools, on a native model;\n // see above), on a model without native support, becomes a forced\n // single tool call via toolConfig, unchanged from before this adapter\n // had a native path.\n const { schema, description, strict } = jsonSchema;\n\n toolName = schemaName;\n toolConfig = {\n tools: [{ toolSpec: { name: toolName, description, inputSchema: { json: schema }, strict } }],\n toolChoice: { tool: { name: toolName } },\n };\n }\n\n // Runs after the branch chain, unified across every case that still\n // wants real tools built: the native-with-tools case above (toolConfig\n // still unset there, only outputConfig is), and the no-jsonSchema-at-all\n // case. `toolName` is the one signal that distinguishes them from the\n // legacy forced-single-tool-call branch, which builds its own toolConfig\n // inline and must not be overwritten here.\n if (params.tools?.length && !toolName) {\n toolConfig = buildBedrockToolConfig(params.tools, params.tool_choice);\n }\n\n // Runs whenever a jsonSchema call actually ends up sending toolConfig,\n // whether that's the legacy forced-single-tool-call path, or the native\n // path with real `tools` also present (native structured output doesn't\n // need Converse tool-use support, but real tools alongside it still do).\n if (jsonSchema && toolConfig && toolUseSupportedModels) {\n const isSupported = Array.isArray(toolUseSupportedModels)\n ? toolUseSupportedModels.includes(params.model)\n : toolUseSupportedModels(params.model);\n\n if (!isSupported) {\n throw new LLMError(\n `Bedrock model \"${params.model}\" is not listed in toolUseSupportedModels, but this call ` +\n 'requires Converse tool use (either jsonSchema emulated as a forced tool call, or real ' +\n '`tools` sent alongside native structured output).',\n 'invalid_params',\n { code: 'unsupported_capability', issues: { capability: 'toolUseSupportedModels' } },\n );\n }\n }\n\n // Converse has no reasoning-budget field of its own; both `thinking`\n // shapes below are forwarded through `additionalModelRequestFields`,\n // passed straight through to the underlying model unchanged, and\n // meaningless to any non-Claude model family, hence the `isClaudeModel`\n // gate. Within Claude models, `budget_tokens` (manual thinking) returns\n // a 400 on Claude Opus 4.7 and later and every Claude 5 tier model, see\n // `supportsManualThinkingBudget`'s docs, so those get adaptive thinking\n // plus `outputConfig.effort` instead, same fallback `fromAnthropic`\n // uses. Native `budget_tokens`/`reasoning_effort` are each used\n // directly when the model natively accepts them; the other is\n // converted through the same table the other adapters share.\n let additionalModelRequestFields: BedrockRequest['additionalModelRequestFields'];\n let effort: ClaudeAdaptiveEffort | undefined;\n\n if (\n isClaudeModel(params.model) &&\n (params.budget_tokens !== undefined || params.reasoning_effort !== undefined)\n ) {\n // Checked once here, right before any thinking block is built, so a\n // caller who set budgetTokens/reasoningEffort alongside a forced\n // toolChoice (or a jsonSchema call that silently forces one to emulate\n // structured output on a non-native model, see toolConfig above) gets\n // a clear local error instead of a 400 after a real network round\n // trip. Same underlying Claude-model constraint as the Anthropic\n // adapter's own check, just against Converse's toolChoice shape\n // instead of the Anthropic SDK's.\n const forcedToolChoice = toolConfig?.toolChoice;\n assertNoForcedToolChoiceWithThinking(\n forcedToolChoice && 'tool' in forcedToolChoice\n ? `toolChoice forcing the \"${forcedToolChoice.tool?.name}\" tool`\n : forcedToolChoice && 'any' in forcedToolChoice\n ? \"toolChoice: 'required' (Converse's \\\"any\\\" tool_choice)\"\n : undefined,\n );\n\n if (supportsManualThinkingBudget(params.model, adaptiveOnlyModels)) {\n const budgetTokens =\n params.budget_tokens ?? effortToBudgetTokens(params.reasoning_effort!, effortTokenTable);\n\n // Same constraint as the Claude API itself: `budget_tokens` must be\n // at least 1024 and strictly less than `max_tokens`.\n assertValidClaudeBudgetTokens(budgetTokens, params.max_tokens);\n\n additionalModelRequestFields = { thinking: { type: 'enabled', budget_tokens: budgetTokens } };\n } else {\n const effortTier =\n params.reasoning_effort ?? budgetTokensToEffort(params.budget_tokens!, effortTokenTable);\n\n additionalModelRequestFields = { thinking: { type: 'adaptive' } };\n effort = toClaudeAdaptiveEffort(effortTier);\n }\n }\n\n // Same constraint as the Claude API itself: temperature (and top_p/\n // top_k) must not be sent alongside any thinking mode, manual or\n // adaptive. See the matching comment in `adapters/anthropic.ts`.\n const temperature = additionalModelRequestFields ? undefined : params.temperature;\n\n const request: BedrockRequest = {\n modelId: params.model,\n messages: mergeConsecutiveToolResults(conversationMessages.map((m) => toBedrockMessage(m))),\n system: systemMessage?.content ? [{ text: systemMessage.content }] : undefined,\n inferenceConfig: {\n ...(temperature !== undefined ? { temperature } : {}),\n maxTokens: params.max_tokens,\n },\n ...(toolConfig ? { toolConfig } : {}),\n ...(outputConfig || effort\n ? {\n outputConfig: {\n ...(outputConfig ?? {}),\n ...(effort ? { effort } : {}),\n },\n }\n : {}),\n ...(additionalModelRequestFields ? { additionalModelRequestFields } : {}),\n };\n\n return { request, toolName };\n}\n\n/**\n * Minimal structural shape of an AWS SDK v3 client that exposes `.send()`,\n * matching `BedrockRuntimeClient` (and its abort-signal-aware call\n * convention). Avoids importing `@aws-sdk/client-bedrock-runtime` for the\n * type.\n */\ninterface AwsSendClient {\n send(command: unknown, options?: { abortSignal?: AbortSignal }): Promise<unknown>;\n}\n\n/**\n * Distinguishes a real AWS SDK v3 client (`.send(command)`) from a\n * hand-written `BedrockConverseClient` (`.converse(params)`) purely\n * structurally, so `fromBedrock` can accept either without the caller\n * saying which one they're passing. The two shapes don't overlap: nothing\n * implementing `.converse()` would also need `.send()`.\n */\nfunction isAwsSendClient(client: BedrockConverseClient | AwsSendClient): client is AwsSendClient {\n return typeof (client as AwsSendClient).send === 'function';\n}\n\n/**\n * One raw event off an AWS SDK `ConverseStreamCommand` response's `stream`.\n * Intentionally untyped (`Record<string, unknown>`, not AWS's own generated\n * `ConverseStreamOutput`). Importing that type would mean importing\n * `@aws-sdk/client-bedrock-runtime` statically, which `wrapAwsSendClient`\n * avoids. Narrowing the raw event structurally, via\n * `normalizeBedrockStreamEvent` below, gets the same safety without the\n * static dependency.\n */\ntype RawBedrockStreamEvent = Record<string, unknown>;\n\n/**\n * Narrows one raw AWS stream event down to VernLLM's intentionally minimal\n * `BedrockConverseStreamEvent` union. Returns `undefined` if the event\n * isn't one of the kinds this adapter models.\n *\n * AWS's real `ConverseStreamOutput` type is a strictly larger union than\n * `BedrockConverseStreamEvent`. On top of every member modeled here, it\n * also includes a generated `$unknown` member, AWS's forward-compatibility\n * escape hatch for event kinds added to the service after this SDK version\n * was generated. A blind type assertion from one union to the other would\n * compile, but would let `$unknown` (or any other future member) reach\n * `fromBedrock`'s event-handling loop unnarrowed, as if it were one of the\n * kinds actually handled there.\n *\n * Returning `undefined` for anything unrecognized, filtered out by\n * `normalizeBedrockEventStream` below, keeps two guarantees. AWS SDK\n * generated types never leak into `fromBedrock`'s application code, only\n * this module's own `BedrockConverseStreamEvent` shape does. An event kind\n * this adapter doesn't yet know about is silently skipped, the same\n * forward-compatible behavior AWS's own `$unknown` convention implies,\n * rather than crashing the stream or being misrouted into a handler that\n * doesn't actually match its shape.\n */\nfunction normalizeBedrockStreamEvent(\n raw: RawBedrockStreamEvent,\n): BedrockConverseStreamEvent | undefined {\n if ('messageStart' in raw) return { messageStart: raw.messageStart as { role: 'assistant' } };\n\n if ('contentBlockStart' in raw) {\n return {\n contentBlockStart: raw.contentBlockStart as BedrockConverseStreamEvent extends {\n contentBlockStart: infer T;\n }\n ? T\n : never,\n };\n }\n\n if ('contentBlockDelta' in raw) {\n return {\n contentBlockDelta: raw.contentBlockDelta as BedrockConverseStreamEvent extends {\n contentBlockDelta: infer T;\n }\n ? T\n : never,\n };\n }\n\n if ('contentBlockStop' in raw) {\n return { contentBlockStop: raw.contentBlockStop as { contentBlockIndex: number } };\n }\n\n if ('messageStop' in raw) return { messageStop: raw.messageStop as { stopReason?: string } };\n\n if ('metadata' in raw) {\n return {\n metadata: raw.metadata as {\n usage?: { inputTokens?: number; outputTokens?: number; totalTokens?: number };\n },\n };\n }\n\n if ('internalServerException' in raw) {\n return { internalServerException: raw.internalServerException as { message?: string } };\n }\n\n if ('modelStreamErrorException' in raw) {\n return {\n modelStreamErrorException: raw.modelStreamErrorException as {\n message?: string;\n originalStatusCode?: number;\n },\n };\n }\n\n if ('validationException' in raw) {\n return { validationException: raw.validationException as { message?: string } };\n }\n\n if ('throttlingException' in raw) {\n return { throttlingException: raw.throttlingException as { message?: string } };\n }\n\n if ('serviceUnavailableException' in raw) {\n return { serviceUnavailableException: raw.serviceUnavailableException as { message?: string } };\n }\n\n // Everything else, including AWS's generated `$unknown` member (and any\n // event kind added to the real service after this adapter was written),\n // is intentionally dropped here rather than forwarded.\n return undefined;\n}\n\n/**\n * Wraps a raw AWS event stream, narrowing each event through\n * `normalizeBedrockStreamEvent` and filtering out anything that doesn't\n * map onto `BedrockConverseStreamEvent`. `fromBedrock`'s event loop only\n * ever sees the shapes it actually models.\n */\nasync function* normalizeBedrockEventStream(\n rawStream: AsyncIterable<RawBedrockStreamEvent>,\n): AsyncGenerator<BedrockConverseStreamEvent> {\n for await (const raw of rawStream) {\n const event = normalizeBedrockStreamEvent(raw);\n\n if (event) yield event;\n }\n}\n\n/**\n * Adapts a real AWS SDK v3 client (anything with `.send()`, matching\n * `BedrockRuntimeClient`) into a `BedrockConverseClient`, so `fromBedrock`\n * can accept either without a hand-written `.converse()`/`.converseStream()`\n * wrapper. Internally does what that wrapper would: `client.send(new\n * ConverseCommand(params))`, `client.send(new\n * ConverseStreamCommand(params))`.\n *\n * `@aws-sdk/client-bedrock-runtime` is intentionally not a dependency (not\n * even a peer dependency) of this package. `vern-llm` otherwise has zero\n * runtime dependencies, and every other adapter works the same way:\n * structural typing over whatever client the caller already has. Instead,\n * `ConverseCommand`/`ConverseStreamCommand` are pulled in with a dynamic\n * `import()` the first time either method actually runs, and memoized\n * after that. Nothing is added to `package.json`, static or peer.\n * Bundlers only pull the AWS SDK in for code paths that actually pass a\n * raw AWS client to `fromBedrock`; a hand-written `BedrockConverseClient`\n * stays unaffected. If `@aws-sdk/client-bedrock-runtime` isn't installed,\n * the failure is a clear `LLMError` naming exactly what's missing, at the\n * moment it's needed, rather than a silent peer-dependency warning at\n * install time or a raw \"Cannot find module\" a caller has to trace back\n * themselves.\n *\n * Also closes two structural gaps between AWS's generated types and\n * `BedrockConverseClient`. AWS's `ConverseStreamCommandOutput.stream` is\n * optional, a response may not include it. This throws a clear `LLMError`\n * instead of letting `undefined` reach `fromBedrock`'s `for await` loop.\n * AWS's `ConverseStreamOutput` union is larger than\n * `BedrockConverseStreamEvent`, it includes a generated `$unknown` member.\n * Every event is narrowed through `normalizeBedrockStreamEvent` before it\n * reaches application code, instead of being asserted wholesale from one\n * type to the other.\n */\nfunction wrapAwsSendClient(client: AwsSendClient): BedrockConverseClient {\n type BedrockRuntimeCommands = {\n ConverseCommand: new (input: unknown) => unknown;\n ConverseStreamCommand: new (input: unknown) => unknown;\n };\n\n let commandsPromise: Promise<BedrockRuntimeCommands> | undefined;\n\n function loadCommands(): Promise<BedrockRuntimeCommands> {\n commandsPromise ??= import('@aws-sdk/client-bedrock-runtime').then(\n (mod) => mod as BedrockRuntimeCommands,\n (cause) => {\n commandsPromise = undefined;\n\n throw new LLMError(\n 'fromBedrock requires \"@aws-sdk/client-bedrock-runtime\" to be installed to use a raw AWS ' +\n 'SDK client (it is not a dependency of vern-llm itself). Install it, or pass your own ' +\n 'object with .converse()/.converseStream() methods instead.',\n 'validation',\n { cause },\n );\n },\n );\n\n return commandsPromise;\n }\n\n return {\n converse: async (params, requestOptions) => {\n const { ConverseCommand } = await loadCommands();\n\n return client.send(new ConverseCommand(params), {\n abortSignal: requestOptions.signal,\n }) as ReturnType<BedrockConverseClient['converse']> extends Promise<infer R>\n ? Promise<R>\n : never;\n },\n\n converseStream: async (params, requestOptions) => {\n const { ConverseStreamCommand } = await loadCommands();\n\n const result = (await client.send(new ConverseStreamCommand(params), {\n abortSignal: requestOptions.signal,\n })) as { stream?: AsyncIterable<RawBedrockStreamEvent> };\n\n // AWS marks `stream` optional on `ConverseStreamCommandOutput`\n // because a response may not include it; VernLLM's own\n // `BedrockConverseClient.converseStream` return shape requires it,\n // since a `stream: true` call is meaningless without one. Fail\n // loudly here, at the adapter boundary, instead of letting\n // `undefined` reach `fromBedrock`'s `for await (const event of\n // stream)` loop, where it would throw a much less specific\n // \"stream is not async iterable\" error.\n if (!result.stream) {\n throw new LLMError(\n 'Bedrock ConverseStreamCommand response did not include a stream. This can happen if the ' +\n \"request or the model doesn't actually support Converse streaming.\",\n 'api',\n { code: 'server_error' },\n );\n }\n\n return { stream: normalizeBedrockEventStream(result.stream) };\n },\n };\n}\n\n/**\n * Wraps a Bedrock Converse-API client so it satisfies the `LLMClient`\n * interface VernLLM uses for OpenAI/Groq. The Converse API is unified\n * across Bedrock's model families (Anthropic, Titan, Llama, Mistral, etc.),\n * so unlike raw per-model Bedrock invocation, this one adapter works\n * regardless of which underlying model `modelId` points at, as long as\n * that model supports Converse (most current-generation ones do)\n *\n * `bedrockClient` accepts either a hand-written `BedrockConverseClient`\n * (a `.converse()`/`.converseStream()` wrapper you provide) or a real AWS\n * SDK v3 client (anything with `.send()`, matching `BedrockRuntimeClient`)\n * directly, detected structurally. Passing a raw AWS client skips the\n * hand-written wrapper entirely, internally doing what it would\n * (`send(new ConverseCommand(...))`, `send(new\n * ConverseStreamCommand(...))`). See `wrapAwsSendClient` for how that path\n * is implemented, including why `@aws-sdk/client-bedrock-runtime` stays\n * out of this package's dependencies either way.\n *\n * `response_format: json_schema`, on a model covered by\n * `options.nativeStructuredOutputModels` (opt-in, unset by default), is\n * sent as `outputConfig.textFormat`, its own request field, independent of\n * `toolConfig`, so it can be combined with real, caller-supplied `tools`\n * in the same request. Matches the real Converse API's shape exactly: the\n * schema is nested under `structure.jsonSchema` and JSON-encoded as a\n * string, not the parsed object `toolConfig`'s tool schemas use, and there\n * is no `strict` field on this path.\n *\n * On any other model (the default), `response_format: json_schema` is\n * mapped to Converse's `toolConfig` instead: a single tool is defined from\n * the schema, description, and strictness settings, and `toolChoice`\n * forces the model to call it. This legacy path cannot be combined with\n * real `tools` (both would need the same `toolConfig`), and a call that\n * tries throws `LLMError('invalid_params')` with `code: 'unsupported_capability'`\n * and `issues: { capability: 'tools_with_json_schema' }` before reaching the API.\n * Provider-constrained schema matching applies only when `strict: true` is\n * forwarded and supported. Native tool support varies by model family;\n * pass `toolUseSupportedModels` to preflight-check it (see\n * `BedrockAdapterOptions`), otherwise a `jsonSchema` call to an\n * unsupported model surfaces Bedrock's raw error unchanged.\n *\n * `response_format: json_object` throws `LLMError('validation')`: Converse\n * has no field that mechanically guarantees JSON output, and the only way\n * to emulate it was an unenforced system-prompt instruction, a guarantee\n * this adapter no longer pretends to make. Use `jsonSchema` instead.\n * `reasoning_effort` (no Converse equivalent) is converted to a token\n * budget and forwarded via `additionalModelRequestFields` for Claude\n * models only; `budget_tokens` is forwarded the same way directly. Both\n * are silently dropped for non-Claude models, which have no equivalent\n * field to reach for. See `adapters/internal/reasoningBudget.utils.ts`.\n *\n * `tools` alone maps to Converse's native `toolConfig`/`toolUse`/\n * `toolResult`; `tool_choice` maps to `toolConfig.toolChoice`.\n *\n * `createStream` calls `converseStream` (optional on `BedrockConverseClient`\n *, required only if the caller sets `stream: true`) and translates its\n * `contentBlockStart`/`contentBlockDelta`/`metadata` events into\n * `WireStreamChunk`s. Content blocks are tracked by `contentBlockIndex`,\n * same as `fromAnthropic`'s block-index tracking (Converse's streaming\n * shape is structurally close to Anthropic's own, both being tool-use-aware\n * content-block streams), including the same `json-tool` unwrapping: a\n * `jsonSchema`-forced tool's `toolUse.input` deltas are re-emitted as\n * `text-delta`, not `tool_call_delta`, so the accumulated result lands in\n * `finalizeResponse`'s `content` path exactly like the non-streaming\n * `create` branch above unwraps it.\n */\nexport function fromBedrock(\n bedrockClient: BedrockConverseClient | AwsSendClient,\n options?: BedrockAdapterOptions,\n): LLMClient {\n const client: BedrockConverseClient = isAwsSendClient(bedrockClient)\n ? wrapAwsSendClient(bedrockClient)\n : bedrockClient;\n\n const toolUseSupportedModels = options?.toolUseSupportedModels;\n const nativeStructuredOutputModels = options?.nativeStructuredOutputModels;\n const effortTokenTable = resolveEffortTokenTable(options?.reasoningEffortTokens);\n const adaptiveOnlyModels = options?.adaptiveOnlyModels;\n\n return {\n // json_object is not supported: see buildBedrockRequest's throw above,\n // and LLMClient.supportsJsonObjectMode's docs.\n supportsJsonObjectMode: false,\n chat: {\n completions: {\n async create(params, requestOptions) {\n const { request, toolName } = buildBedrockRequest(\n params,\n toolUseSupportedModels,\n nativeStructuredOutputModels,\n effortTokenTable,\n adaptiveOnlyModels,\n );\n\n const response = await client.converse(request, requestOptions);\n\n let text: string;\n let wireToolCalls: WireToolCall[] | undefined;\n\n if (toolName) {\n // Forced tool-use: the schema-conforming payload arrives as the\n // toolUse content block's already-parsed `input`, not as text.\n // Re-serialize it to JSON so it flows through the same\n // string-content contract every other adapter uses.\n const toolUseBlock = response.output?.message?.content?.find(\n (block) => block.toolUse?.name === toolName,\n );\n\n text = toolUseBlock?.toolUse ? JSON.stringify(toolUseBlock.toolUse.input) : '';\n } else {\n const blocks = response.output?.message?.content ?? [];\n\n text = blocks.map((c) => c.text ?? '').join('');\n\n const toolUses = blocks.filter(\n (\n block,\n ): block is { toolUse: { toolUseId?: string; name?: string; input?: unknown } } =>\n Boolean(block.toolUse),\n );\n\n if (toolUses.length) {\n wireToolCalls = toolUses.map((block, i) => {\n const toolUse = block.toolUse;\n\n if (!toolUse.name) {\n throw new LLMError(\n `Bedrock returned a toolUse block without a name at index ${i}.`,\n 'validation',\n );\n }\n\n return {\n id: toolUse.toolUseId ?? `${toolUse.name}_${i}`,\n type: 'function' as const,\n function: {\n name: toolUse.name,\n arguments: JSON.stringify(toolUse.input ?? {}),\n },\n };\n });\n }\n }\n\n return {\n choices: [\n {\n message: { content: text, ...(wireToolCalls ? { tool_calls: wireToolCalls } : {}) },\n },\n ],\n usage: {\n prompt_tokens: response.usage?.inputTokens,\n completion_tokens: response.usage?.outputTokens,\n total_tokens: response.usage?.totalTokens,\n },\n };\n },\n\n async *createStream(params, requestOptions) {\n if (!client.converseStream) {\n throw new LLMError(\n 'stream: true requires a Bedrock client with converseStream',\n 'invalid_params',\n { code: 'unsupported_capability', issues: { capability: 'converseStream' } },\n );\n }\n\n const { request, toolName } = buildBedrockRequest(\n params,\n toolUseSupportedModels,\n nativeStructuredOutputModels,\n effortTokenTable,\n adaptiveOnlyModels,\n );\n\n const { stream } = await client.converseStream(request, requestOptions);\n\n const blockKinds = new Map<number, 'text' | 'tool_use' | 'json-tool'>();\n\n for await (const event of stream) {\n if ('contentBlockStart' in event) {\n const { contentBlockIndex, start } = event.contentBlockStart;\n\n if (start?.toolUse) {\n const kind = start.toolUse.name === toolName ? 'json-tool' : 'tool_use';\n\n blockKinds.set(contentBlockIndex, kind);\n\n if (kind === 'tool_use' && !toolName) {\n yield {\n type: 'tool_call_delta',\n index: contentBlockIndex,\n id: start.toolUse.toolUseId,\n name: start.toolUse.name,\n };\n }\n } else {\n blockKinds.set(contentBlockIndex, 'text');\n }\n } else if ('contentBlockDelta' in event) {\n const { contentBlockIndex, delta } = event.contentBlockDelta;\n\n // Only surfaced as real content when there's no forced\n // json-schema tool in play, see the identical guard (and\n // its full rationale) in `fromAnthropic`'s `createStream`.\n // Converse's streaming shape is structurally close enough to\n // Anthropic's own that the same corruption risk applies: a\n // genuine text block alongside a forced tool call would\n // otherwise get concatenated into the same buffer as the\n // tool's JSON payload.\n if (delta && 'text' in delta && delta.text !== undefined && !toolName) {\n yield { type: 'text-delta', delta: delta.text };\n } else if (delta && 'toolUse' in delta && delta.toolUse?.input !== undefined) {\n const kind = blockKinds.get(contentBlockIndex);\n\n if (kind === 'json-tool') {\n yield { type: 'text-delta', delta: delta.toolUse.input };\n } else if (!toolName) {\n yield {\n type: 'tool_call_delta',\n index: contentBlockIndex,\n argumentsDelta: delta.toolUse.input,\n } satisfies WireStreamChunk;\n }\n }\n } else if ('metadata' in event && event.metadata.usage) {\n yield {\n type: 'usage',\n usage: {\n prompt_tokens: event.metadata.usage.inputTokens,\n completion_tokens: event.metadata.usage.outputTokens,\n total_tokens: event.metadata.usage.totalTokens,\n },\n };\n } else if ('throttlingException' in event) {\n throw new LLMError(\n event.throttlingException.message ?? 'Bedrock throttled the request mid-stream',\n 'api',\n { status: 429, code: 'provider_rate_limited' },\n );\n } else if ('validationException' in event) {\n throw new LLMError(\n event.validationException.message ?? 'Bedrock rejected the request mid-stream',\n 'validation',\n );\n } else if (\n 'internalServerException' in event ||\n 'serviceUnavailableException' in event ||\n 'modelStreamErrorException' in event\n ) {\n const detail =\n ('internalServerException' in event && event.internalServerException.message) ||\n ('serviceUnavailableException' in event &&\n event.serviceUnavailableException.message) ||\n ('modelStreamErrorException' in event && event.modelStreamErrorException.message) ||\n 'Bedrock reported a mid-stream error';\n\n const status =\n ('modelStreamErrorException' in event &&\n event.modelStreamErrorException.originalStatusCode) ||\n ('serviceUnavailableException' in event && 503) ||\n 500;\n\n throw new LLMError(detail, 'api', {\n status,\n code: status >= 500 ? 'server_error' : undefined,\n });\n }\n }\n },\n },\n },\n };\n}\n\n/** Maps VernLLM's OpenAI-shaped wire `tool_choice` onto Converse's `toolChoice`. */\nfunction toBedrockToolChoice(\n toolChoice: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice'],\n): NonNullable<Parameters<BedrockConverseClient['converse']>[0]['toolConfig']>['toolChoice'] {\n if (!toolChoice || toolChoice === 'auto') return { auto: {} };\n if (toolChoice === 'required') return { any: {} };\n\n if (toolChoice === 'none') {\n // Converse's toolConfig.toolChoice has no 'none' option. The only way\n // to guarantee no tool use is to omit toolConfig.tools entirely, which\n // isn't an option here since tools were explicitly requested. Silently\n // falling back to 'auto' would let the model call tools despite the\n // caller explicitly asking it not to, so this fails loudly instead.\n throw new LLMError(\n \"'none' is not supported by fromBedrock: Bedrock Converse has no \" +\n '`tool_choice` equivalent to forbidding tool use while tools are still offered. Omit ' +\n '`tools` entirely for this call instead.',\n 'invalid_params',\n { code: 'unsupported_capability', issues: { capability: \"toolChoice: 'none'\" } },\n );\n }\n\n return { tool: { name: toolChoice.function.name } };\n}\n/**\n * Translates one VernLLM wire message into Converse's\n * `{ role: 'user' | 'assistant', content }` shape.\n */\nfunction toBedrockMessage(\n m: Extract<\n Parameters<LLMClient['chat']['completions']['create']>[0]['messages'][number],\n { role: 'user' | 'assistant' | 'tool' }\n >,\n): { role: 'user' | 'assistant'; content: BedrockContentBlock[] } {\n if (m.role === 'tool') {\n return {\n role: 'user',\n content: [\n {\n toolResult: {\n toolUseId: m.tool_call_id,\n content: [{ text: m.content }],\n status: m.is_error ? 'error' : 'success',\n },\n },\n ],\n };\n }\n\n if (m.role === 'assistant' && m.tool_calls?.length) {\n const blocks: BedrockContentBlock[] = [];\n\n if (m.content) blocks.push({ text: m.content });\n\n for (const tc of m.tool_calls) {\n let input: unknown;\n\n if (!tc.function.arguments.trim()) {\n input = {};\n } else {\n try {\n input = JSON.parse(tc.function.arguments);\n } catch (cause) {\n throw new LLMError(\n `Assistant tool call \"${tc.function.name}\" (${tc.id}) has arguments that are not valid JSON.`,\n 'validation',\n { cause },\n );\n }\n }\n\n blocks.push({ toolUse: { toolUseId: tc.id, name: tc.function.name, input } });\n }\n\n return { role: 'assistant', content: blocks };\n }\n\n return {\n role: m.role,\n content: Array.isArray(m.content) ? toBedrockContent(m.content) : [{ text: m.content ?? '' }],\n };\n}\n\n/**\n * Converse expects the results of everything the model asked for in one\n * turn to arrive together as multiple `toolResult` content blocks on a\n * single `'user'` message, not as separate consecutive `'user'` messages.\n * The per-wire-message mapping above produces one `'user'` message per\n * VernLLM wire tool message, so when an assistant turn requested more than\n * one tool, this merges the resulting run of toolResult-only `'user'`\n * messages back into one.\n */\nfunction mergeConsecutiveToolResults(\n messages: { role: 'user' | 'assistant'; content: BedrockContentBlock[] }[],\n): { role: 'user' | 'assistant'; content: BedrockContentBlock[] }[] {\n const isToolResultOnly = (\n m: (typeof messages)[number],\n ): m is { role: 'user'; content: BedrockContentBlock[] } =>\n m.role === 'user' && m.content.length > 0 && m.content.every((b) => 'toolResult' in b);\n\n const merged: (typeof messages)[number][] = [];\n\n for (const m of messages) {\n const prev = merged.at(-1);\n\n if (isToolResultOnly(m) && prev && isToolResultOnly(prev)) {\n prev.content.push(...m.content);\n } else {\n merged.push(m);\n }\n }\n\n return merged;\n}\n","import {\n LLMError,\n type LLMClient,\n type WireStreamChunk,\n type WireToolCall,\n} from '../types/index.js';\nimport { parseSseStream, SSE_PING } from './internal/sse.js';\n\n/** The chat-completion-shaped request VernLLM builds internally */\ntype ChatRequest = Parameters<LLMClient['chat']['completions']['create']>[0];\n\n/**\n * The minimal shape the fetch adapter needs from a response object.\n * Native `fetch`'s `Response` satisfies this, but so do wrappers around\n * `axios`, `node-fetch`, `undici`, etc, which makes `request` swappable\n * without forcing consumers to polyfill the full `Response` interface\n */\nexport interface ResponseLike {\n ok: boolean;\n status: number;\n headers: {\n get(name: string): string | null;\n };\n text(): Promise<string>;\n json(): Promise<unknown>;\n}\n\n/** A fetch-compatible request function; defaults to native `fetch` */\nexport type RequestLike = (\n url: string,\n init: {\n method: string;\n headers: Record<string, string>;\n body?: string;\n signal?: AbortSignal;\n },\n) => Promise<ResponseLike>;\n\n/**\n * A streaming-capable request function. Unlike `RequestLike`, which returns\n * a fully-buffered `ResponseLike`, this resolves to an `AsyncIterable` of\n * progressively-arriving chunks, the common ground across transports:\n * native `fetch`'s `response.body` (wrapped to be iterable; see\n * `webStreamToAsyncIterable` below), axios's Node `Readable` in\n * `responseType: 'stream'` mode (already async-iterable, no wrapping\n * needed), `node-fetch`, `undici`, etc, all satisfy this with little or no\n * glue code. Defaults to native `fetch`.\n */\nexport type StreamRequestLike = (\n url: string,\n init: {\n method: string;\n headers: Record<string, string>;\n body?: string;\n signal?: AbortSignal;\n },\n) => Promise<AsyncIterable<Uint8Array | string>>;\n\nexport interface FetchAdapterConfig {\n /** Endpoint URL, or a function of the request in case it depends on model/params */\n url: string | ((params: ChatRequest) => string);\n /** Static headers, or a function (sync or async) for things like refreshed auth tokens */\n headers?:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>);\n /** HTTP method. Default 'POST' */\n method?: string;\n /**\n * The function used to make the HTTP request. Defaults to native `fetch`.\n * Swap in `axios`, `node-fetch`, or any other transport, as long as it\n * resolves to a `ResponseLike` object\n */\n request?: RequestLike;\n /** Maps VernLLMs internal chat-completion request into the providers raw request body */\n mapRequest: (params: ChatRequest) => unknown;\n /**\n * Maps the providers raw JSON response into `{ content, usage?, toolCalls? }`\n * `content` is the assistants text (JSON string when JSON mode was requested).\n * `content` may be empty/omitted when the model responded with only tool\n * calls and no text.\n *\n * `toolCalls`, when the model requested one or more tools, is the list of\n * calls as flat `{ id, name, arguments }` entries (matching this config's\n * own `toolCalls?: Array<{ id: string; name: string; arguments: string }>`\n * return type below), each entry's `arguments` already JSON-*encoded* as a\n * string (not the parsed object), mirroring the wire format every\n * OpenAI-compatible provider uses. `fromFetch` itself converts these into\n * `WireToolCall`'s `type`/`function`-wrapped shape before returning them\n * from `create`. VernLLM parses (and validates, if `argumentsSchema` was\n * set) the arguments string internally, mapResponse doesn't need to do\n * that itself.\n */\n mapResponse: (json: unknown) => {\n content?: string;\n usage?: { promptTokens?: number; completionTokens?: number; totalTokens?: number };\n toolCalls?: Array<{ id: string; name: string; arguments: string }>;\n };\n\n /**\n * Optional. Required only for `stream: true` calls. The function used to\n * open a streaming HTTP request. Takes the same request shape as\n * `request`, but resolves to an `AsyncIterable` of progressively-arriving\n * `Uint8Array` or `string` chunks instead of a buffered `ResponseLike`.\n * Defaults to native `fetch`.\n */\n requestStream?: StreamRequestLike;\n\n /**\n * Optional. How the raw stream bytes are split into individual event\n * payloads. Defaults to Server-Sent Events framing (`data: ...` blocks\n * separated by a blank line, `[DONE]` sentinel honored, see\n * `parseSseStream`), which covers the large majority of LLM providers'\n * streaming HTTP endpoints. Override this for a provider that frames its\n * stream differently, e.g. newline-delimited JSON (NDJSON) with no SSE\n * envelope.\n */\n parseStreamFrames?: (chunks: AsyncIterable<Uint8Array | string>) => AsyncIterable<unknown>;\n\n /**\n * Optional. Required only for `stream: true` calls. Maps one parsed\n * stream event (already extracted from its frame by `parseStreamFrames`)\n * into zero, one, or more `WireStreamChunk`s, mirrors `mapResponse`'s\n * role for the non-streaming path, just per-event instead of once for\n * the whole body. Return `undefined` to skip an event that carries\n * nothing VernLLM needs (e.g. a provider's keep-alive ping). Configs\n * that don't implement this make `stream: true` throw a clear\n * `LLMError('validation')` rather than a confusing runtime failure or a\n * silently empty stream.\n */\n mapStreamEvent?: (event: unknown) => WireStreamChunk | WireStreamChunk[] | undefined;\n}\n\n/**\n * Wraps a WHATWG `ReadableStream` (what `response.body` is) so it can be\n * consumed with `for await`. Implemented via `getReader()` rather than\n * relying on `ReadableStream` having a native `Symbol.asyncIterator`,\n * that support varies across runtimes/versions, and this works everywhere\n * a `ReadableStream` does.\n */\nasync function* webStreamToAsyncIterable(\n stream: ReadableStream<Uint8Array>,\n): AsyncGenerator<Uint8Array> {\n const reader = stream.getReader();\n\n try {\n for (;;) {\n const { done, value } = await reader.read();\n\n if (done) return;\n if (value) yield value;\n }\n } finally {\n // Cancel before releasing the lock so an early-terminated or\n // downstream-failed consumer still tells the underlying source to\n // stop, instead of leaving it running with nothing left to read it.\n // An already-errored stream rejects cancel(); that rejection isn't\n // useful to the caller here, so it's swallowed.\n try {\n await reader.cancel();\n } catch {\n // Ignore: the stream may already be errored/closed.\n }\n\n reader.releaseLock();\n }\n}\n\n/** Default `requestStream`: native `fetch`, with the same error/`.status` contract non-streaming errors get. */\nasync function defaultRequestStream(\n url: string,\n init: { method: string; headers: Record<string, string>; body?: string; signal?: AbortSignal },\n): Promise<AsyncIterable<Uint8Array | string>> {\n const res = await fetch(url, init);\n\n if (!res.ok) {\n const body = await res.text().catch(() => '');\n const err = new Error(\n `Fetch adapter stream request failed (${res.status}): ${body.slice(0, 500)}`,\n ) as Error & { status?: number; headers?: ResponseLike['headers'] };\n\n err.status = res.status;\n err.headers = res.headers;\n\n throw err;\n }\n\n if (!res.body) {\n throw new Error('Fetch adapter stream request received a response with no body.');\n }\n\n return webStreamToAsyncIterable(res.body);\n}\n\n/** Builds the shared `{ method, headers, body? }` request-init for both `create` and `createStream`. */\nasync function buildRequestInit(\n config: FetchAdapterConfig,\n params: ChatRequest,\n requestBody: unknown,\n): Promise<{ url: string; method: string; headers: Record<string, string>; body?: string }> {\n const url = typeof config.url === 'function' ? config.url(params) : config.url;\n const headers = typeof config.headers === 'function' ? await config.headers() : config.headers;\n const method = config.method ?? 'POST';\n\n // GET/HEAD requests can't carry a body, so skip both the body and\n // the Content-Type header for them rather than sending a body a\n // server may reject\n const supportsBody = !['GET', 'HEAD'].includes(method.toUpperCase());\n\n return {\n url,\n method,\n headers: supportsBody ? { 'Content-Type': 'application/json', ...headers } : { ...headers },\n ...(supportsBody ? { body: JSON.stringify(requestBody) } : {}),\n };\n}\n\n/**\n * A fetch-based escape hatch for providers with no SDK, or where pulling one\n * in isnt worth it. You supply the URL, headers, and two small mapping\n * functions; this handles the HTTP call and slots the result into the same\n * `LLMClient` shape every other adapter produces, so retries, timeouts,\n * the circuit breaker, and JSON/schema handling all still work unmodified\n *\n * Non-2xx responses throw an error with `.status` set to the HTTP status\n * code, so VernLLMs `nonRetryableStatus` handling (e.g. failing fast on\n * 401/403) applies here too\n *\n * Tool calling works the same way as every other adapter: `mapRequest`\n * receives the full `ChatRequest`, including `tools`/`toolChoice`, so it can\n * translate them into whatever shape the provider's wire format expects\n * (typically an OpenAI-`function`-wrapped `tools` array plus a `tool_choice`\n * field). On the way back, `mapResponse` may return a `toolCalls` array\n * (id/name/JSON-encoded-arguments-string per call) alongside or instead of\n * `content`; VernLLM parses and (if `argumentsSchema` was set) validates\n * those arguments the same way it does for every other adapter. For\n * `stream: true`, tool-call deltas go through the existing\n * `mapStreamEvent` seam via `WireStreamChunk`'s `tool_call_delta` variant,\n * no separate config is needed for streaming vs non-streaming tool calls.\n *\n\n * `createStream` requires `mapStreamEvent` (there's no non-streaming\n * response to fall back on, unlike the other three optional streaming\n * seams). It opens the request via `requestStream` (defaults to native\n * `fetch`), splits the raw bytes into individual events via\n * `parseStreamFrames` (defaults to SSE framing, see `parseSseStream`),\n * and translates each event into `WireStreamChunk`(s) via\n * `mapStreamEvent`. Both seams are overridable per-config for providers\n * that don't fit the SSE-over-fetch default. If a custom `request`\n * transport is configured, `requestStream` must be configured too,\n * `requestStream` never silently falls back to `request` (see\n * `createStream`'s own comment for why), so a `stream: true` call with\n * `request` set but no `requestStream` throws a clear\n * `LLMError('validation')` instead of quietly using unrelated native\n * `fetch`.\n */\nexport function fromFetch(config: FetchAdapterConfig): LLMClient {\n return {\n chat: {\n completions: {\n async create(params, options) {\n const { url, method, headers, body } = await buildRequestInit(\n config,\n params,\n config.mapRequest(params),\n );\n const request = config.request ?? fetch;\n\n const res = await request(url, { method, headers, body, signal: options.signal });\n\n if (!res.ok) {\n const responseBody = await res.text().catch(() => '');\n const err = new Error(\n `Fetch adapter request failed (${res.status}): ${responseBody.slice(0, 500)}`,\n ) as Error & { status?: number; headers?: ResponseLike['headers'] };\n err.status = res.status;\n // Attach headers so downstream retry logic (e.g. rate-limit\n // handling) can read things like `Retry-After`\n err.headers = res.headers;\n throw err;\n }\n\n const json = await res.json();\n const { content, usage, toolCalls } = config.mapResponse(json);\n\n // `.length` guard, not just truthiness: an empty array is\n // semantically \"no tool calls\", same as `undefined`. Kept\n // explicit here rather than relying on downstream consumers\n // (e.g. `finalizeResponse`'s `wireToolCalls?.length` check) to\n // treat `[]` as absent, so this stays correct even if that\n // convention ever changes.\n const wireToolCalls: WireToolCall[] | undefined = toolCalls?.length\n ? toolCalls.map((tc) => ({\n id: tc.id,\n type: 'function' as const,\n function: { name: tc.name, arguments: tc.arguments },\n }))\n : undefined;\n\n return {\n choices: [\n {\n message: {\n content,\n ...(wireToolCalls ? { tool_calls: wireToolCalls } : {}),\n },\n },\n ],\n usage: usage\n ? {\n prompt_tokens: usage.promptTokens,\n completion_tokens: usage.completionTokens,\n total_tokens: usage.totalTokens,\n }\n : undefined,\n };\n },\n\n async *createStream(params, options) {\n if (!config.mapStreamEvent) {\n throw new LLMError(\n 'stream: true requires mapStreamEvent to be configured on fromFetch',\n 'invalid_params',\n { code: 'unsupported_capability', issues: { capability: 'mapStreamEvent' } },\n );\n }\n\n // A custom `request` transport (proxying, special auth, test\n // mocking, etc.) is silently irrelevant to streaming unless the\n // caller *also* configures `requestStream`, `requestStream`\n // defaults to plain native `fetch`, not to `config.request`,\n // since `RequestLike`'s buffered `ResponseLike` has no way to\n // expose a byte stream generically. Falling back to native\n // `fetch` anyway would be a surprising, easy-to-miss divergence\n // (bypassing whatever `request` was there for, a proxy, custom\n // auth, or a test's mocked transport, and potentially hitting\n // the real network). Failing loudly here instead of guessing.\n if (config.request && !config.requestStream) {\n throw new LLMError(\n '`stream: true` requires `requestStream` to be configured on fromFetch when a ' +\n 'custom `request` transport is set. `requestStream` does not fall back to ' +\n \"`request` (it needs an async-iterable byte stream, which `RequestLike`'s \" +\n 'buffered `ResponseLike` has no way to provide), without it, `stream: true` ' +\n 'would silently use plain native `fetch` instead of your configured transport. ' +\n 'Add a `requestStream` that opens the same connection your `request` does, or ' +\n 'omit `request` if native `fetch` is fine for both.',\n 'invalid_params',\n { code: 'unsupported_capability', issues: { capability: 'requestStream' } },\n );\n }\n\n const { url, method, headers, body } = await buildRequestInit(\n config,\n params,\n config.mapRequest(params),\n );\n const requestStream = config.requestStream ?? defaultRequestStream;\n const parseFrames = config.parseStreamFrames ?? parseSseStream;\n\n const byteStream = await requestStream(url, {\n method,\n headers,\n body,\n signal: options.signal,\n });\n\n for await (const event of parseFrames(byteStream)) {\n // Only the default parseSseStream produces this sentinel (an\n // SSE comment line used as a keep-alive ping). Handled here,\n // before mapStreamEvent, since provider-specific mapping\n // shouldn't need to know about SSE framing internals.\n if (event === SSE_PING) {\n yield { type: 'ping' };\n continue;\n }\n\n const wireChunks = config.mapStreamEvent(event);\n\n if (!wireChunks) continue;\n\n if (Array.isArray(wireChunks)) {\n yield* wireChunks;\n } else {\n yield wireChunks;\n }\n }\n },\n },\n },\n };\n}\n","import { assertSupportedImageMimeType } from './internal/imageFormat.js';\nimport {\n budgetTokensToEffort,\n resolveEffortTokenTable,\n type EffortTokenTable,\n} from './internal/reasoningBudget.utils.js';\n\nimport type { ContentBlock, LLMClient, WireStreamChunk } from '../types/index.js';\n\n/**\n * OpenAI's wire format only understands `reasoning_effort`, not a raw\n * token budget. When the caller set `reasoningEffort`, it's already on\n * `params` and passed through unchanged, this function does nothing.\n * When only `budgetTokens` was set, it's converted to the nearest tier\n * and `budget_tokens` is dropped, since OpenAI's API would otherwise\n * silently ignore an unrecognized field.\n */\nfunction applyReasoningBudget<\n P extends { reasoning_effort?: 'minimal' | 'low' | 'medium' | 'high'; budget_tokens?: number },\n>(params: P, effortTokenTable?: EffortTokenTable): P {\n if (params.budget_tokens === undefined) return params;\n\n const { budget_tokens, ...rest } = params;\n\n return rest.reasoning_effort !== undefined\n ? (rest as P)\n : ({ ...rest, reasoning_effort: budgetTokensToEffort(budget_tokens, effortTokenTable) } as P);\n}\n\n/** OpenAI's native per-part content shape for a user message. */\ntype OpenAIContentPart =\n | { type: 'text'; text: string }\n | { type: 'image_url'; image_url: { url: string } };\n\n/**\n * Translates a VernLLM `ContentBlock[]` into OpenAI's wire-level content\n * array. Text blocks become `{ type: 'text', text }`; image blocks become\n * `{ type: 'image_url', image_url: { url } }` with the base64 payload\n * inlined as a `data:` URL, since our `ContentBlock` shape (`{ type:\n * 'image', data, mimeType }`) is provider-agnostic and doesn't itself match\n * OpenAI's wire format.\n */\nfunction toOpenAIContent(blocks: ContentBlock[]): OpenAIContentPart[] {\n return blocks.map((block) =>\n block.type === 'image'\n ? {\n type: 'image_url',\n image_url: {\n url: `data:${assertSupportedImageMimeType(block.mimeType)};base64,${block.data}`,\n },\n }\n : { type: 'text', text: block.text },\n );\n}\n\n/** One chunk of an OpenAI-shaped `chat.completions.create({ stream: true })` SSE stream. */\ninterface OpenAIStreamChunk {\n choices?: Array<{\n delta?: {\n content?: string | null;\n tool_calls?: Array<{\n index: number;\n id?: string;\n function?: { name?: string; arguments?: string };\n }>;\n };\n }>;\n usage?: { prompt_tokens?: number; completion_tokens?: number; total_tokens?: number };\n}\n\n/**\n * Translates VernLLM's provider-agnostic `messages` (the one part of a\n * request that isn't a pure passthrough for OpenAI-compatible clients) into\n * OpenAI's native wire shape. Shared between `create` and `createStream` so\n * both go through identical message translation.\n */\nfunction toOpenAIMessages(\n params: Parameters<LLMClient['chat']['completions']['create']>[0],\n): unknown[] {\n return params.messages.map((m) => {\n if (m.role === 'user' && Array.isArray(m.content)) {\n return { ...m, content: toOpenAIContent(m.content) };\n }\n\n if (m.role === 'tool') {\n const { is_error: _isError, ...openAIToolMessage } = m;\n return openAIToolMessage;\n }\n\n return m;\n });\n}\n\n/**\n * Translates one OpenAI-shaped SSE chunk into zero or more `WireStreamChunk`s.\n * A single chunk can carry a text delta, one or more tool-call argument\n * deltas (each keyed by `index`, OpenAI's own convention for streaming\n * parallel tool calls, mirrored directly by VernLLM's `tool_call_delta`\n * shape so accumulation composes without translation), and/or a final\n * usage block (present only when `stream_options.include_usage` is set,\n * which this adapter always sets).\n */\nfunction* toWireStreamChunks(chunk: OpenAIStreamChunk): Generator<WireStreamChunk> {\n const delta = chunk.choices?.[0]?.delta;\n\n if (delta?.content) {\n yield { type: 'text-delta', delta: delta.content };\n }\n\n if (delta?.tool_calls?.length) {\n for (const toolCall of delta.tool_calls) {\n yield {\n type: 'tool_call_delta',\n index: toolCall.index,\n id: toolCall.id,\n name: toolCall.function?.name,\n argumentsDelta: toolCall.function?.arguments,\n };\n }\n }\n\n if (chunk.usage) {\n yield { type: 'usage', usage: chunk.usage };\n }\n}\n\n/**\n * Adapter for any SDK/client whose `chat.completions.create` already\n * matches the OpenAI wire format: this covers most hosted inference\n * providers, since \"OpenAI-compatible\" is a de facto standard for chat\n * completion APIs. Almost everything passes straight through untouched,\n * this exists purely so call sites read clearly (`fromMistral(client)` vs\n * handing a Mistral client to something typed for OpenAI) and so a real\n * transformation could be added later, per-provider, without a breaking\n * change.\n *\n * The one thing that isn't a pure passthrough: a `ContentBlock[]`\n * `userContent` is translated into OpenAI's native `image_url` content-part\n * shape, since VernLLM's `ContentBlock` is intentionally provider-agnostic\n * rather than a copy of any one provider's wire format.\n *\n * Not every SDKs own TypeScript types line up exactly with `LLMClient`\n * (extra fields, stricter unions, etc.), so this takes `unknown` and casts:\n * the actual compatibility contract is the JSON each provider sends and\n * receives over the wire, not the SDKs TS types.\n *\n * `createStream` is implemented by calling the same underlying\n * `chat.completions.create` with `stream: true` (and, for providers that\n * support it, `stream_options: { include_usage: true }`, so a final usage\n * block arrives), the OpenAI SDK, and every OpenAI-compatible client\n * modeled on it, returns an `AsyncIterable` of SSE chunks instead of a\n * single completion object when `stream: true` is set. Each chunk is\n * translated into `WireStreamChunk`(s) via `toWireStreamChunks`.\n *\n * Note on long-running reasoning models: this adapter consumes the\n * underlying SDK's already-parsed stream rather than raw SSE bytes, so\n * unlike `fromFetch`/`fromAnthropic` it cannot see comment-only keep-alive\n * ping frames. Combined with `chunkIdleTimeoutMs`'s 30 second default and\n * `reasoningEffort` (documented to have long silent gaps for o-series and\n * similar models), a long-running reasoning call on this adapter can trip\n * the idle timeout even though the provider is still working. Raise or\n * disable `chunkIdleTimeoutMs` per call for those routes, see `CallParams`.\n */\nexport interface OpenAICompatibleAdapterOptions {\n /**\n * Whether the provider supports `stream_options.include_usage`. Not\n * every \"OpenAI-compatible\" provider is guaranteed to, so this defaults\n * to `true` (matching OpenAI, Groq, Mistral, and most others observed)\n * and should be set to `false` for a provider verified not to support\n * it. When `false`, `stream_options` is omitted entirely and no usage\n * block will arrive on the stream; callers relying on streamed `usage`\n * with such a provider won't get one.\n */\n supportsStreamUsage?: boolean;\n /**\n * Overrides the token count `budgetTokens` buckets into when the caller\n * sets `budgetTokens` but not `reasoningEffort` (OpenAI-compatible\n * clients have no numeric budget field of their own, see\n * `adapters/internal/reasoningBudget.utils.ts`). Only the tiers listed\n * are changed; any omitted tier keeps the built-in default. Has no\n * effect when `reasoningEffort` is set directly.\n */\n reasoningEffortTokens?: Partial<EffortTokenTable>;\n}\n\nexport function fromOpenAICompatible(\n client: unknown,\n options: OpenAICompatibleAdapterOptions = {},\n): LLMClient {\n const raw = client as LLMClient;\n const { supportsStreamUsage = true } = options;\n const effortTokenTable = resolveEffortTokenTable(options.reasoningEffortTokens);\n\n // The underlying client's `create`, called with `stream: true`, returns\n // an AsyncIterable of `OpenAIStreamChunk` rather than\n // `LLMClient['create']`'s normal single-completion return type, hence\n // `unknown` here and a cast at the call site, same rationale as casting\n // the whole client above: the wire contract, not the SDK's own TS types,\n // is what's actually being relied on.\n const rawCreate = raw.chat.completions.create.bind(raw.chat.completions) as unknown as (\n params: unknown,\n options: { signal: AbortSignal },\n ) => Promise<unknown> | AsyncIterable<OpenAIStreamChunk>;\n\n return {\n chat: {\n completions: {\n async create(params, options) {\n const messages = toOpenAIMessages(params);\n\n return raw.chat.completions.create(\n applyReasoningBudget({ ...params, messages }, effortTokenTable) as Parameters<\n LLMClient['chat']['completions']['create']\n >[0],\n options,\n );\n },\n\n async *createStream(params, options) {\n const messages = toOpenAIMessages(params);\n\n const stream = (await rawCreate(\n applyReasoningBudget(\n {\n ...params,\n messages,\n stream: true,\n ...(supportsStreamUsage ? { stream_options: { include_usage: true } } : {}),\n },\n effortTokenTable,\n ),\n options,\n )) as AsyncIterable<OpenAIStreamChunk>;\n\n for await (const chunk of stream) {\n yield* toWireStreamChunks(chunk);\n }\n },\n },\n },\n };\n}\n\n// LLM aliases\n\n/**\n * Named alias for the OpenAI SDK itself. A raw `new OpenAI(...)` instance\n * structurally matches most of `LLMClient`, but newer `openai` SDK major\n * versions have widened `ChatCompletionContentPart` (e.g. adding a `file`\n * variant) in ways that no longer structurally satisfy VernLLM's\n * provider-agnostic `ContentBlock[]` on `userContent`, so passing the SDK\n * instance directly can fail to typecheck depending on the installed\n * `openai` version. Wrapping with `fromOpenAI()` (a plain alias of\n * `fromOpenAICompatible()`) sidesteps that by translating through\n * `unknown` at the boundary, and also picks up multimodal image\n * translation and `createStream` wiring that a raw client doesn't have.\n * See Migration Notes for details.\n */\nexport const fromOpenAI = fromOpenAICompatible;\n\n/** Groqs SDK matches the OpenAI wire format */\nexport const fromGroq = fromOpenAICompatible;\n\n/**\n * Mistrals `chat.completions`-shaped client (or their OpenAI-compat\n * endpoint). Mistral supports `stream_options.include_usage` (added after\n * an earlier period where it returned a 422 for unrecognized fields, per\n * Mistral's changelog and streaming docs), so this is a plain alias like\n * the others, `supportsStreamUsage` defaults to `true`.\n */\nexport const fromMistral = fromOpenAICompatible;\n\n/** DeepSeeks API is OpenAI-compatible */\nexport const fromDeepSeek = fromOpenAICompatible;\n\n/** Cerebras inference API is OpenAI-compatible */\nexport const fromCerebras = fromOpenAICompatible;\n\n/** Together AIs API is OpenAI-compatible */\nexport const fromTogether = fromOpenAICompatible;\n\n/** Fireworks AIs API is OpenAI-compatible */\nexport const fromFireworks = fromOpenAICompatible;\n\n/**\n * Ollama exposes an OpenAI-compatible endpoint at `/v1/chat/completions`\n * (as opposed to its native `/api/chat` format, which differs). Point an\n * OpenAI SDK instances `baseURL` at your Ollama server and pass it here:\n * this does not talk to Ollamas native API directly.\n */\nexport const fromOllama = fromOpenAICompatible;\n\n/** OpenRouter's API is OpenAI-compatible */\nexport const fromOpenRouter = fromOpenAICompatible;\n\n/** Perplexity's API is OpenAI-compatible */\nexport const fromPerplexity = fromOpenAICompatible;\n\n/** DeepInfra's API is OpenAI-compatible */\nexport const fromDeepInfra = fromOpenAICompatible;\n\n/** Novita's API is OpenAI-compatible */\nexport const fromNovita = fromOpenAICompatible;\n\n/** Hyperbolic's API is OpenAI-compatible */\nexport const fromHyperbolic = fromOpenAICompatible;\n\n/** Moonshot's (Kimi) API is OpenAI-compatible */\nexport const fromMoonshot = fromOpenAICompatible;\n\n/** Zhipu's (GLM) API is OpenAI-compatible */\nexport const fromZhipu = fromOpenAICompatible;\n\n/**\n * LM Studio exposes an OpenAI-compatible endpoint at `/v1/chat/completions`.\n * Point an OpenAI SDK instance's `baseURL` at your local LM Studio server.\n */\nexport const fromLMStudio = fromOpenAICompatible;\n\n/**\n * vLLM's OpenAI-compatible server mode exposes `/v1/chat/completions`.\n * Point an OpenAI SDK instance's `baseURL` at your vLLM server.\n */\nexport const fromVLLM = fromOpenAICompatible;\n\n/** xAI's Grok API is OpenAI-compatible */\nexport const fromXAI = fromOpenAICompatible;\n\n/** NVIDIA NIM's hosted and self-hosted endpoints are OpenAI-compatible */\nexport const fromNvidiaNIM = fromOpenAICompatible;\n\n/** Vercel AI Gateway is OpenAI-compatible */\nexport const fromVercelAIGateway = fromOpenAICompatible;\n\n/** Cloudflare Workers AI exposes an OpenAI-compatible endpoint */\nexport const fromCloudflareWorkersAI = fromOpenAICompatible;\n\n/** Nebius AI Studio is OpenAI-compatible */\nexport const fromNebius = fromOpenAICompatible;\n\n/** SambaNova Cloud's API is OpenAI-compatible */\nexport const fromSambaNova = fromOpenAICompatible;\n\n/** Baseten's model hosting exposes an OpenAI-compatible endpoint */\nexport const fromBaseten = fromOpenAICompatible;\n\n/** Featherless AI's API is OpenAI-compatible */\nexport const fromFeatherless = fromOpenAICompatible;\n\n/** Friendli AI's serving endpoint is OpenAI-compatible */\nexport const fromFriendli = fromOpenAICompatible;\n\n/** SiliconFlow's API is OpenAI-compatible */\nexport const fromSiliconFlow = fromOpenAICompatible;\n\n/** Parasail's inference API is OpenAI-compatible */\nexport const fromParasail = fromOpenAICompatible;\n\n/** StepFun's API is OpenAI-compatible */\nexport const fromStepFun = fromOpenAICompatible;\n\n/** MiniMax's API is OpenAI-compatible */\nexport const fromMiniMax = fromOpenAICompatible;\n\n/** Lambda Labs' Inference API is OpenAI-compatible */\nexport const fromLambdaLabs = fromOpenAICompatible;\n\n/** Snowflake Cortex's LLM endpoint is OpenAI-compatible */\nexport const fromSnowflakeCortex = fromOpenAICompatible;\n\n/** Anyscale Endpoints' API is OpenAI-compatible */\nexport const fromAnyscale = fromOpenAICompatible;\n\n/** Lepton AI's inference API is OpenAI-compatible */\nexport const fromLepton = fromOpenAICompatible;\n\n/** Inference.net's API is OpenAI-compatible */\nexport const fromInferenceNet = fromOpenAICompatible;\n\n/** Infermatic's API is OpenAI-compatible */\nexport const fromInfermatic = fromOpenAICompatible;\n\n/** AtlasCloud's inference API is OpenAI-compatible */\nexport const fromAtlasCloud = fromOpenAICompatible;\n\n/** 01.AI's (Yi models) API is OpenAI-compatible */\nexport const from01AI = fromOpenAICompatible;\n"],"mappings":"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"}
|