vern-llm 3.0.0 → 3.1.0

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["isPromiseLike","OPTIONAL_FUNCTION_MEMBER_NAMES","invalidOptionalMembers"],"sources":["../src/types/cache.ts","../src/types/tools.ts","../src/types/stream.ts","../src/types/fallback.ts","../src/types/middleware.ts","../src/types/createMiddleware.ts","../src/internal/execution/utils/response/usage.utils.ts","../src/internal/execution/utils/stream/earlyExit.utils.ts","../src/internal/utils/deferred.utils.ts","../src/internal/utils/logger.utils.ts","../src/internal/cache/utils/inFlightRegistry.utils.ts","../src/internal/cache/utils/replay.utils.ts","../src/internal/cache/utils/sharedAbort.utils.ts","../src/internal/cache/cacheOrchestrator.ts","../src/internal/cache/utils/metaHolder.utils.ts","../src/internal/rollingRatio.ts","../src/internal/utils/validate.utils.ts","../src/internal/retryBudget.ts","../src/internal/utils/adapterInfo.utils.ts","../src/internal/utils/circuit-breaker/circuitBreaker.utils.ts","../src/internal/utils/circuit-breaker/prepareBreaker.utils.ts","../src/internal/utils/callScope.utils.ts","../src/internal/utils/middlewareLabels.utils.ts","../src/internal/execution/utils/retry/retryAfter.utils.ts","../src/internal/execution/utils/deadline.utils.ts","../src/internal/execution/utils/retry/timeout.utils.ts","../src/internal/execution/utils/retry/retry.utils.ts","../src/internal/execution/utils/errors.utils.ts","../src/internal/execution/utils/once.utils.ts","../src/internal/execution/utils/middleware/transformPatch.utils.ts","../src/internal/execution/utils/middleware/middleware.utils.ts","../src/internal/execution/utils/dispatch/rateLimitDispatch.utils.ts","../src/internal/execution/utils/dispatch/attemptDispatch.utils.ts","../src/internal/execution/attempt/attemptEnvironment.ts","../src/internal/execution/utils/wire.utils.ts","../src/internal/execution/utils/response/responseShape.utils.ts","../src/internal/execution/responseFinalizer.ts","../src/internal/execution/attempt/providerDispatch.ts","../src/internal/execution/attempt/nonStreamAttempt.ts","../src/internal/execution/utils/stream/chunkBuffer.utils.ts","../src/internal/execution/utils/stream/toolCallAccumulator.utils.ts","../src/internal/execution/utils/stream/streamAccumulation.utils.ts","../src/internal/execution/streamAccumulator.ts","../src/internal/execution/attempt/streamAttempt.ts","../src/internal/execution/utils/request/requestShape.utils.ts","../src/internal/execution/requestBuilder.ts","../src/internal/execution/usageReporter.ts","../src/internal/execution/circuitBreakerContext.ts","../src/internal/execution/utils/dispatch/attemptLoop.utils.ts","../src/internal/execution/utils/parse.utils.ts","../src/internal/execution/callExecutor.ts","../src/internal/execution/targetOrder.ts","../src/internal/execution/logicalCall.ts","../src/internal/execution/reservedLogicalCall.ts","../src/internal/execution/runOperation.ts","../src/internal/execution/utils/callSignal.utils.ts","../src/internal/execution/utils/middleware/customEvent.utils.ts","../src/internal/utils/circuit-breaker/circuitBucket.utils.ts","../src/circuitBreaker.ts","../src/internal/utils/circuit-breaker/circuitBreakerAdapter.utils.ts","../src/internal/tokenBucket.ts","../src/internal/utils/rate-limit/rateLimitOptions.utils.ts","../src/internal/utils/rate-limit/tokenEstimate.utils.ts","../src/rateLimit.ts","../src/internal/utils/rate-limit/rateLimitAdapter.utils.ts","../src/internal/utils/targetNames.utils.ts","../src/internal/executorFactory.ts","../src/internal/resolveMiddlewareOrder.ts","../src/internal/utils/cache/cacheAdapter.utils.ts","../src/logger.ts","../src/vernLLM.ts","../src/paramsHelpers.ts"],"sourcesContent":["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 * Which entry `InMemoryCacheAdapter` evicts once `maxSize` is exceeded.\n * `'fifo'` (default) drops the oldest inserted entry. `'lru'` drops the\n * least recently read or written entry.\n */\nexport type EvictionOption = 'fifo' | 'lru';\n\n/** Not exported. `onAccess`/`onInsert` mark recency, `getEvictee` picks the next victim. */\ninterface Eviction {\n onAccess(store: Map<string, unknown>, key: string): void;\n onInsert(store: Map<string, unknown>, key: string): void;\n getEvictee(store: Map<string, unknown>): string | undefined;\n}\n\nconst FIFO: Eviction = {\n onAccess() {},\n onInsert() {},\n getEvictee: (store) => store.keys().next().value,\n};\n\n/** Moves `key` to the end of `store`'s iteration order. No-op if `key` isn't present. */\nfunction touch(store: Map<string, unknown>, key: string): void {\n // Defensive: both call sites (onAccess in get(), onInsert in set())\n // only invoke this after confirming the key is already in the store,\n // so this guard never actually trips today. Kept in case a future\n // eviction policy calls touch() from a context that can't make the\n // same guarantee.\n /* v8 ignore next */\n if (!store.has(key)) return;\n\n const value = store.get(key);\n store.delete(key);\n store.set(key, value);\n}\n\nconst LRU: Eviction = {\n onAccess: touch,\n onInsert: touch,\n getEvictee: (store) => store.keys().next().value,\n};\n\n/** Not exported. Resolves the shorthand into the shared `Eviction` instance. */\nfunction buildEviction(option: EvictionOption): Eviction {\n return option === 'lru' ? LRU : FIFO;\n}\n\n/**\n * True for a ttl that can actually expire an entry. `undefined` and NaN\n * would otherwise produce a NaN expiry that never compares as due, and a\n * zero or negative ttl is already expired on arrival.\n */\nfunction isLiveTtl(ttl: number): boolean {\n return typeof ttl === 'number' && ttl > 0;\n}\n\n/**\n * Whether `structuredClone` copies `value` faithfully all the way down. A class instance would lose\n * its methods, and functions or symbols can't be cloned.\n */\nfunction isFaithfullyCloneable(value: unknown, seen = new Set<object>()): boolean {\n if (value === null) return true;\n\n const type = typeof value;\n if (type === 'function' || type === 'symbol') return false;\n if (type !== 'object') return true;\n\n const object = value as object;\n if (seen.has(object)) return true;\n seen.add(object);\n\n if (\n object instanceof Date ||\n object instanceof RegExp ||\n object instanceof ArrayBuffer ||\n ArrayBuffer.isView(object)\n ) {\n return true;\n }\n\n if (object instanceof Map) {\n for (const [key, item] of object) {\n if (!isFaithfullyCloneable(key, seen) || !isFaithfullyCloneable(item, seen)) return false;\n }\n return true;\n }\n\n if (object instanceof Set) {\n for (const item of object) {\n if (!isFaithfullyCloneable(item, seen)) return false;\n }\n return true;\n }\n\n const prototype = Object.getPrototypeOf(object);\n if (!Array.isArray(object) && prototype !== Object.prototype && prototype !== null) return false;\n\n // Symbol keys and accessors are dropped or flattened by structuredClone.\n if (Object.getOwnPropertySymbols(object).length > 0) return false;\n\n for (const descriptor of Object.values(Object.getOwnPropertyDescriptors(object))) {\n if (!('value' in descriptor)) return false;\n if (!isFaithfullyCloneable(descriptor.value, seen)) return false;\n }\n\n return true;\n}\n\n/**\n * The default in-process cache. Not shared across processes; use a shared backend in production.\n * Values are copied on `set` and `get`, so mutating a result never changes the next hit. A value\n * that can't be copied faithfully, or a missing, NaN, zero or negative `ttl`, is not stored and\n * drops any existing entry.\n */\nexport class InMemoryCacheAdapter<T = unknown> implements CacheAdapter<T> {\n private store = new Map<string, { value: T; expiresAt: number }>();\n private readonly eviction: Eviction;\n\n constructor(\n private readonly maxSize = 1000,\n eviction: EvictionOption = 'fifo',\n ) {\n this.eviction = buildEviction(eviction);\n }\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 this.eviction.onAccess(this.store, key);\n // Only faithfully cloneable values are ever stored, see `set`.\n return { hit: true, value: structuredClone(entry.value) };\n }\n\n async set(key: string, value: T, ttl: number): Promise<void> {\n this.cleanupExpiredEntries();\n\n if (!isLiveTtl(ttl) || !isFaithfullyCloneable(value)) {\n // The caller asked to replace this key, so an older value must not survive.\n this.store.delete(key);\n return;\n }\n\n this.store.set(key, {\n value: structuredClone(value),\n expiresAt: Date.now() + ttl * 1000,\n });\n this.eviction.onInsert(this.store, key);\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 victim = this.eviction.getEvictee(this.store);\n\n if (victim === undefined) break;\n\n this.store.delete(victim);\n }\n }\n}\n\n/**\n * Normalizes keys to avoid duplicates from formatting that can't change a prompt's meaning: Unicode\n * composition, line endings and outer whitespace. Case, punctuation and inner whitespace are kept,\n * since `\"2+2\"` and `\"2-2\"` must never share an answer.\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.normalize('NFC').replace(/\\r\\n?/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/** Upper bound on tracked L2 expiries, so a long running process can't grow the map forever. */\nconst MAX_TRACKED_EXPIRIES = 10_000;\n\n/**\n * Two tier cache: fast local L1, shared L2, with L2 hits promoted to L1. An L1 entry never outlives\n * an L2 entry this adapter wrote. A promoted entry another process wrote keeps `l1Ttl`, since L2\n * doesn't report remaining ttl.\n */\nexport class TieredCacheAdapter<T = unknown> implements CacheAdapter<T> {\n /** L2 expiry (epoch ms) per key this adapter wrote, oldest write first. */\n private readonly l2ExpiresAt = new Map<string, number>();\n\n /**\n * Expiries as a min heap, so a write only visits expired records. Stale heap entries are skipped\n * unless the map still holds that exact expiry.\n */\n private expiryHeap: Array<{ key: string; expiresAt: number }> = [];\n\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.promotionTtl(key));\n }\n\n return l2Result;\n }\n\n async set(key: string, value: T, ttl: number): Promise<void> {\n this.trackExpiry(key, ttl);\n\n // An L1 ttl above the L2 ttl would keep serving the value after L2 dropped it.\n const l1Ttl = this.l1Ttl === undefined ? ttl : Math.min(this.l1Ttl, ttl);\n\n await Promise.all([this.l1.set(key, value, l1Ttl), this.l2.set(key, value, ttl)]);\n }\n\n async delete(key: string): Promise<void> {\n this.l2ExpiresAt.delete(key);\n await Promise.all([this.l1.delete?.(key), this.l2.delete?.(key)]);\n }\n\n /** L1 ttl for a promoted entry, capped at the seconds L2 has left when that is known. */\n private promotionTtl(key: string): number {\n const fallback = this.l1Ttl ?? 60;\n const expiresAt = this.l2ExpiresAt.get(key);\n\n if (expiresAt === undefined) return fallback;\n\n // L2 still served a key whose tracked write has expired, so another\n // process rewrote it since. The record describes an entry that no\n // longer exists; treat the hit like any other external entry.\n if (expiresAt <= Date.now()) {\n this.l2ExpiresAt.delete(key);\n return fallback;\n }\n\n return Math.min(fallback, (expiresAt - Date.now()) / 1000);\n }\n\n private trackExpiry(key: string, ttl: number): void {\n const now = Date.now();\n\n this.pruneExpired(now);\n\n // Reinserted so the map's order stays oldest write first for the cap below.\n this.l2ExpiresAt.delete(key);\n\n // A ttl that isn't a number stays untracked, so promotion falls back to l1Ttl.\n if (typeof ttl !== 'number' || Number.isNaN(ttl)) return;\n\n const expiresAt = now + ttl * 1000;\n this.l2ExpiresAt.set(key, expiresAt);\n heapPush(this.expiryHeap, { key, expiresAt });\n\n while (this.l2ExpiresAt.size > MAX_TRACKED_EXPIRIES) {\n const oldest = this.l2ExpiresAt.keys().next().value;\n /* v8 ignore next */\n if (oldest === undefined) break;\n this.l2ExpiresAt.delete(oldest);\n }\n\n // Stale heap entries (rewrites, deletes, capped keys) would otherwise\n // pile up for keys that never expire soon. Rebuilding from the map is\n // O(n) and only runs once the heap holds twice what it needs.\n if (this.expiryHeap.length > 2 * this.l2ExpiresAt.size + 64) {\n this.expiryHeap = [];\n for (const [trackedKey, trackedExpiry] of this.l2ExpiresAt) {\n heapPush(this.expiryHeap, { key: trackedKey, expiresAt: trackedExpiry });\n }\n }\n }\n\n /** Drops every tracked record that has expired, visiting only those. */\n private pruneExpired(now: number): void {\n while (this.expiryHeap.length > 0 && this.expiryHeap[0]!.expiresAt <= now) {\n const { key, expiresAt } = heapPop(this.expiryHeap)!;\n if (this.l2ExpiresAt.get(key) === expiresAt) this.l2ExpiresAt.delete(key);\n }\n }\n}\n\ntype ExpiryRecord = { key: string; expiresAt: number };\n\n/** Adds `record` to a min-heap ordered by `expiresAt`. */\nfunction heapPush(heap: ExpiryRecord[], record: ExpiryRecord): void {\n heap.push(record);\n let index = heap.length - 1;\n\n while (index > 0) {\n const parent = (index - 1) >> 1;\n if (heap[parent]!.expiresAt <= heap[index]!.expiresAt) break;\n [heap[parent], heap[index]] = [heap[index]!, heap[parent]!];\n index = parent;\n }\n}\n\n/** Removes and returns the soonest record of a min-heap ordered by `expiresAt`. */\nfunction heapPop(heap: ExpiryRecord[]): ExpiryRecord | undefined {\n const top = heap[0];\n const last = heap.pop();\n if (top === undefined || last === undefined || heap.length === 0) return top;\n\n heap[0] = last;\n let index = 0;\n\n for (;;) {\n const left = 2 * index + 1;\n const right = left + 1;\n let smallest = index;\n\n if (left < heap.length && heap[left]!.expiresAt < heap[smallest]!.expiresAt) smallest = left;\n if (right < heap.length && heap[right]!.expiresAt < heap[smallest]!.expiresAt) smallest = right;\n if (smallest === index) return top;\n\n [heap[smallest], heap[index]] = [heap[index]!, heap[smallest]!];\n index = smallest;\n }\n}\n","import type { ThinkingBlock } from './call.js';\nimport 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 * Validates the parsed `arguments`, using the same `safeParse` shape as `schema`. Failure throws\n * `LLMError('validation')`; on success `ToolCall.arguments` is the schema's output, defaults and\n * transforms applied. Without it, arguments are parsed as JSON only. Types flow into `ToolCall`\n * when the tool's `name` is literal, see `defineTool()`.\n */\n argumentsSchema?: SchemaLike<Args>;\n}\n\n/**\n * Keeps a tool's literal `name` and inferred `Args`, so `ToolCall` narrows by name. A plain object\n * literal widens `name` to `string` without `as const`, which breaks narrowing once a second tool\n * is added.\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 * One tool call from the model. With a literal `Tools` tuple this is a union keyed by `name`, so\n * checking `name` narrows `arguments`. Otherwise `arguments` is `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 * Marks a failed tool execution. Sent as Anthropic's `is_error` and Bedrock's error status;\n * OpenAI-compatible adapters prefix the content with `Error: `; Gemini has no equivalent and\n * ignores it.\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 * Claude's reasoning blocks before this tool request, when thinking is\n * on (`fromAnthropic` and `fromBedrock`). Put them on the assistant\n * history turn with `toolCalls` so the tool loop can continue.\n */\n thinking?: ThinkingBlock[];\n}\n\nexport type CallWithToolsResult<T, Tools extends readonly ToolDefinition[] = ToolDefinition[]> =\n | ContentResult<T>\n | ToolCallResult<Tools>;\n\n/** Recovers `Tools` from a `result` already typed `ContentResult<T> | ToolCallResult<Tools>`. Falls back to `ToolDefinition[]`. */\ntype ExtractTools<R> =\n Extract<R, ToolCallResult<ToolDefinition[]>> extends ToolCallResult<infer Tools>\n ? Tools\n : ToolDefinition[];\n\n/** Explicit `Tools` type argument if given, otherwise inferred via `ExtractTools`. `never` marks \"unset\". */\ntype ResolvedTools<Tools, R> = [Tools] extends [never] ? ExtractTools<R> : Tools;\n\n/**\n * Whether a `call()` result is a tool calls result. Use it whenever `tools` was set conditionally.\n * `toolCalls[number].arguments` is typed per tool; pass `Tools` explicitly to override inference,\n * e.g. `isToolCallResult<typeof tools>(result)`.\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 if (typeof result !== 'object' || result === null) return false;\n\n const candidate = result as Partial<ToolCallResult>;\n return candidate.type === 'tool_calls' && Array.isArray(candidate.toolCalls);\n}\n\n/** What the model should do about tools on a given call. */\nexport type ToolChoice = 'auto' | 'none' | 'required' | { name: string };\n","import type { ProviderRateLimitHint } from '../internal/utils/rate-limit/rateLimitHint.utils.js';\nimport type {\n CachedCallInput,\n CallParams,\n ConditionalStringToolCallParams,\n JsonValue,\n LLMRequestShape,\n ThinkingBlock,\n} from './call.js';\nimport type { ToolDefinition } from './tools.js';\nimport type { TokenUsage } from './usage.js';\n\n/** One incremental unit of a streaming response, as delivered to the caller. */\nexport type StreamChunk =\n | { type: 'text-delta'; delta: string }\n | {\n type: 'tool_call_delta';\n index: number;\n id?: string;\n name?: string;\n argsDelta?: string;\n /**\n * True when `argsDelta` holds the whole arguments rather than a fragment, as with Gemini and\n * cache replays.\n */\n complete?: boolean;\n }\n | { type: 'usage'; usage: TokenUsage };\n\n/**\n * What `call()` returns with `stream: true`. `finalResult` resolves to the same shape a\n * non-streaming call returns. `chunks` is single use; see the streaming docs.\n */\nexport interface StreamCallResult<R> {\n chunks: AsyncIterable<StreamChunk>;\n finalResult: Promise<R>;\n}\n\n/** `CallParams` with `stream: true`, selecting the overload that returns `StreamCallResult`. */\nexport type StreamEnabledCallParams<\n T,\n Tools extends readonly ToolDefinition[] = ToolDefinition[],\n> = CallParams<T, Tools> & { stream: true };\n\n/** Streaming conditional tool-call parameters whose non-tool result is text. */\nexport type StreamConditionalStringToolCallParams<\n Tools extends readonly ToolDefinition[] = ToolDefinition[],\n> = StreamEnabledCallParams<string, Tools> & ConditionalStringToolCallParams<Tools>;\n\n/** Recovers `T` from a `result` already typed `T | StreamCallResult<T>`. Falls back to `unknown`. */\ntype ExtractStreamValue<R> =\n Extract<R, StreamCallResult<unknown>> extends StreamCallResult<infer V> ? V : unknown;\n\n/** Minimal duck-typed `PromiseLike` check: anything with a callable `.then`. */\nfunction isPromiseLike(value: unknown): value is PromiseLike<unknown> {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as { then?: unknown }).then === 'function'\n );\n}\n\n/** Minimal duck-typed `AsyncIterable` check: anything with a callable `Symbol.asyncIterator`. */\nfunction isAsyncIterable(value: unknown): value is AsyncIterable<unknown> {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as { [Symbol.asyncIterator]?: unknown })[Symbol.asyncIterator] === 'function'\n );\n}\n\n/**\n * Whether a `call()` result is a `StreamCallResult`. Useful when `stream` was set conditionally,\n * since the overloads only pick the streaming shape for a literal `stream: true`.\n */\nexport function isStreamResult<R = unknown>(\n result: R,\n): result is R & StreamCallResult<ExtractStreamValue<R>> {\n if (typeof result !== 'object' || result === null) return false;\n\n const candidate = result as Partial<StreamCallResult<unknown>>;\n return isAsyncIterable(candidate.chunks) && isPromiseLike(candidate.finalResult);\n}\n\n/**\n * Streaming `jsonMode: false`, with `finalResult` as a `string`. `jsonSchema` is `never`, as in\n * `JsonModeDisabledCallParams`.\n */\nexport type StreamJsonModeDisabledCallParams = Omit<\n StreamEnabledCallParams<unknown>,\n 'jsonSchema'\n> & {\n jsonMode: false;\n jsonSchema?: never;\n};\n\n/**\n * Streaming `jsonMode: true` without `schema`, with `finalResult` as `JsonValue`. `schema` is\n * `never`, as in `JsonModeEnabledCallParams`.\n */\nexport type StreamJsonModeEnabledCallParams = Omit<StreamEnabledCallParams<JsonValue>, 'schema'> & {\n jsonMode: true;\n schema?: never;\n};\n\n/**\n * The adapter-facing, pre-normalization shape a `createStream` client\n * implementation emits, analogous to how `WireMessage`/`WireToolCall`\n * already sit between `CallParams` and each provider's own wire format.\n */\nexport type WireStreamChunk =\n | { type: 'text-delta'; delta: string }\n | {\n type: 'tool_call_delta';\n index: number;\n id?: string;\n name?: string;\n argumentsDelta?: string;\n /** Same meaning as `StreamChunk`'s `tool_call_delta.complete`. */\n complete?: boolean;\n }\n | {\n type: 'usage';\n usage: {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n completion_tokens_details?: { reasoning_tokens?: number };\n /** Cache split of `prompt_tokens`. Follows OpenAI and OpenRouter naming. */\n prompt_tokens_details?: {\n cached_tokens?: number;\n cache_write_tokens?: number;\n /** Writes by TTL label, e.g. `{ '5m': 1200, '1h': 800 }`. */\n cache_write_tokens_by_ttl?: Record<string, number>;\n };\n };\n }\n | {\n /** A provider keep-alive with no content. Resets the idle timeout; never reaches callers. */\n type: 'ping';\n }\n | {\n /**\n * A rate limit hint from the stream's response headers, yielded as early as possible for\n * AIMD. The streaming counterpart of `attachRateLimitHint`. Never reaches callers.\n */\n type: 'rate_limit_hint';\n hint: ProviderRateLimitHint;\n }\n | {\n /**\n * One complete reasoning block, yielded once it has fully arrived.\n * Collected onto `ToolCallResult.thinking`, never surfaced to\n * callers as a `StreamChunk`.\n */\n type: 'thinking_block';\n block: ThinkingBlock;\n };\n\n/**\n * A cached streaming call without tools. A miss relays live chunks; a hit replays the cached value\n * as chunks. `reserveUsage` and `refundUsage` go at the top level.\n */\nexport type CachedStreamCallParams<T> = CachedCallInput & {\n call: LLMRequestShape<T> & { stream: true };\n};\n\n/** A cached streaming call with tools, caching the full `CallWithToolsResult<T>`. */\nexport type CachedStreamToolCallParams<\n T,\n Tools extends readonly ToolDefinition[] = ToolDefinition[],\n> = CachedCallInput & {\n call: LLMRequestShape<T, Tools> & {\n stream: true;\n tools: NonNullable<LLMRequestShape<T, Tools>['tools']>;\n };\n};\n\n/**\n * A cached streaming call with `call.tools` set conditionally, resolving to `T |\n * CallWithToolsResult<T>`.\n */\nexport type CachedStreamConditionalToolCallParams<\n T,\n Tools extends readonly ToolDefinition[] = ToolDefinition[],\n> = CachedCallInput & {\n call: LLMRequestShape<T, Tools> & { stream: true; tools: Tools | undefined };\n};\n\n/** Cached streaming conditional tool-call parameters whose non-tool result is text. */\nexport type CachedStreamConditionalStringToolCallParams<\n Tools extends readonly ToolDefinition[] = ToolDefinition[],\n> = CachedStreamConditionalToolCallParams<string, Tools> & {\n call: { jsonMode: false };\n};\n\n/**\n * Parameters for a cached, streaming LLM call with `jsonMode: false`.\n * Selects the `cachedCall()` overload whose `finalResult` (on a miss) or\n * cached value (on a hit) is a plain `string`.\n */\nexport type CachedStreamJsonModeDisabledCallParams = CachedCallInput & {\n call: Omit<LLMRequestShape<unknown>, 'jsonSchema'> & {\n stream: true;\n jsonMode: false;\n jsonSchema?: never;\n };\n};\n\n/**\n * Parameters for a cached, streaming LLM call with `jsonMode: true` and no\n * `schema`. Selects the `cachedCall()` overload whose `finalResult` (on a\n * miss) or cached value (on a hit) is a `JsonValue`.\n */\nexport type CachedStreamJsonModeEnabledCallParams = CachedCallInput & {\n call: Omit<LLMRequestShape<JsonValue>, 'schema'> & {\n stream: true;\n jsonMode: true;\n schema?: never;\n };\n};\n","import { LLMError, type RetryAttempt } from './errors.js';\n\nimport type { CircuitState } from '../circuitBreaker.js';\nimport type { RetryBudgetOptions } from '../internal/retryBudget.js';\nimport type { CircuitBreakerOption } from '../internal/utils/circuit-breaker/circuitBreakerAdapter.utils.js';\nimport type { RateLimitOption } from '../internal/utils/rate-limit/rateLimitAdapter.utils.js';\nimport type { DetectSoftFailure } from './call.js';\nimport type { AdapterInfo, LLMClient } from './client.js';\n\n/**\n * A provider tried after the primary fails, in the order given. Omitted overrides fall back to the\n * instance's options, except `circuitBreaker`, `rateLimit` and `retryBudget`, which are never\n * inherited since limits tuned for the primary rarely fit a fallback.\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 readerStallTimeoutMs?: number;\n baseDelayMs?: number;\n maxRetryAfterMs?: 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 breaker, or a shared `CircuitBreakerAdapter`. Not inherited from the parent's `circuitBreaker`. */\n circuitBreaker?: CircuitBreakerOption;\n /** This target's own rate limiter, independent of every other target's. Not inherited from the parent's `rateLimit`. */\n rateLimit?: RateLimitOption;\n /** This target's own retry budget, independent of every other target's. Not inherited from the parent's `retryBudget`. */\n retryBudget?: RetryBudgetOptions;\n /**\n * Reclassifies a successful result from this target as a failure. Inherits the instance's\n * `detectSoftFailure` when omitted.\n */\n detectSoftFailure?: DetectSoftFailure;\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 /** Position of the answering target in the order tried, 0 based. */\n position: number;\n}\n\n/** One configured target, as a middleware sees it in `ctx.targets`. */\nexport interface TargetInfo {\n /** The name `targets` selects by. */\n name: string;\n /** Declared position: 0 is the primary. */\n index: number;\n model: string;\n adapter: AdapterInfo;\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. `index` is `-1` for the primary; `provider` and `model` name the target.\n */\nexport interface FallbackAttempt extends RetryAttempt {\n provider: string;\n model: string;\n}\n\n/** What `fallbackOn` is told about the failed target and what would come after it. */\nexport interface FallbackOnContext {\n /** Whether no target is left in the order tried. The chain stops after the last one whatever `fallbackOn` returns. */\n isLastTarget: boolean;\n /** The target that just failed. `model` is what it ran, so the per call `model` shows on the primary only. */\n failed: TargetInfo;\n /** The target that would be tried next. `undefined` on the last target. */\n next?: TargetInfo;\n}\n\n/**\n * Whether to try the next target (`'next'`) or give up (`'stop'`) after a target's own retries.\n * Called once per failed target.\n */\nexport type FallbackOn = (error: LLMError, context: FallbackOnContext) => 'next' | 'stop';\n\n/**\n * Tool contract failures another provider can't fix. Most are the model ignoring the request;\n * `duplicate_tool_call_id` is a provider protocol violation, but equally not something a fallback\n * would change.\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: (\n error: LLMError,\n context: Pick<FallbackOnContext, 'isLastTarget'>,\n) => 'next' | 'stop' = (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 // Caller input is rejected locally before any provider sees it, so every\n // target would reject it the same way. `unsupported_capability` is the\n // exception: it's one adapter's limit, and another target may support it.\n if (error.type === 'invalid_params' && error.code !== 'unsupported_capability') return 'stop';\n\n return 'next';\n};\n\n/**\n * Thrown when the chain gives up, carrying every attempt in order. Extends `LLMError` and takes the\n * last failure's `type`, `status` and `retryAfterMs`, so existing handling keeps working.\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 * Defers to the last attempt's `retryable`, since `fallback_exhausted` alone says nothing about\n * it.\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\n/**\n * An empty holder for `CallParams['meta']`, so `call()`'s `CallMeta` can be read without declaring\n * one by hand.\n *\n * @example\n * const meta = metaRef();\n * const result = await vern.call({ userContent: '...', meta });\n * meta.current?.provider;\n */\nexport function metaRef(): { current?: CallMeta } {\n return {};\n}\n","import type { CallContext, JsonValue } from './call.js';\nimport type { AdapterInfo, WireMessage, WireToolChoice } from './client.js';\nimport type { VernLLMEvent } from './events.js';\nimport type { CallMeta, TargetInfo } from './fallback.js';\n\n/** Capabilities of the target a middleware hook is currently looking at. */\nexport interface MiddlewareCapabilities {\n /**\n * Whether this target honors `response_format: { type: 'json_object' }`\n * as a real constraint. Mirrors `LLMClient.supportsJsonObjectMode`.\n * `false` for `fromAnthropic` and `fromBedrock`.\n */\n supportsJsonObjectMode: boolean;\n}\n\n/**\n * The `{ debugName }` shape shared by state keys and middleware refs, before each adds its own\n * brand.\n */\nfunction createIdentityToken(debugName: string): { debugName: string } {\n return { debugName };\n}\n\n/**\n * Brands `MiddlewareStateKey` so a ref, or a hand written `{ debugName }`, can't pass as a state\n * key. Only `createStateKey` can produce one.\n */\ndeclare const stateKeyBrand: unique symbol;\n\n/**\n * A typed reference to one slot in `ctx.state`. Create it with `createStateKey` and import it\n * wherever the value is shared, so a typo is a compile error instead of a new property.\n */\nexport interface MiddlewareStateKey<T> {\n readonly debugName: string;\n readonly [stateKeyBrand]: true;\n\n /**\n * Never set. Makes keys of different `T` distinct types, so `get` and `set` infer the value type.\n */\n readonly __phantom?: T;\n}\n\n/** Creates a new, distinct `MiddlewareStateKey`. `debugName` is used only in log lines and the `'middleware'` event; it never affects equality. */\nexport function createStateKey<T>(debugName: string): MiddlewareStateKey<T> {\n return createIdentityToken(debugName) as MiddlewareStateKey<T>;\n}\n\n/** Not exported. See `stateKeyBrand`; same reasoning, distinct symbol, so the two token types can't be cross-assigned either. */\ndeclare const middlewareRefBrand: unique symbol;\n\n/**\n * A typed reference to a middleware, used only as a `runsAfter` or `runsBefore` target, never as a\n * label. Create it with `createMiddlewareRef` and export it, so a typo is a compile error.\n */\nexport interface MiddlewareRef {\n readonly debugName: string;\n readonly [middlewareRefBrand]: true;\n}\n\n/** Creates a new, distinct `MiddlewareRef`. `debugName` is used only in error messages when a reference doesn't resolve; it never affects equality, so two refs with the same `debugName` never collide. */\nexport function createMiddlewareRef(debugName: string): MiddlewareRef {\n return createIdentityToken(debugName) as MiddlewareRef;\n}\n\n/**\n * A `runsAfter` or `runsBefore` entry, made with `requireRef`, that throws at construction when the\n * target isn't registered. A bare ref is optional and only warns.\n */\nexport interface RequiredMiddlewareRef {\n readonly ref: MiddlewareRef;\n}\n\n/** Wraps `ref` so `runsAfter`/`runsBefore` throws at `VernLLM` construction time if it doesn't resolve, instead of warning and continuing. */\nexport function requireRef(ref: MiddlewareRef): RequiredMiddlewareRef {\n return { ref };\n}\n\n/**\n * Typed per call storage that middleware share values through. VernLLM never reads or writes it.\n */\nexport interface MiddlewareStateBag {\n get<T>(key: MiddlewareStateKey<T>): T | undefined;\n set<T>(key: MiddlewareStateKey<T>, value: T): void;\n}\n\n/**\n * One `[key, value]` pair for a call's `state`. A tuple can't tie each value to its own key's type,\n * so `stateEntry` carries that check. Raw pairs are not type checked.\n */\nexport type MiddlewareStateEntry = readonly [MiddlewareStateKey<unknown>, unknown];\n\n/** Builds a type checked `state` entry: `value` must match the key's type. */\nexport function stateEntry<T>(key: MiddlewareStateKey<T>, value: T): MiddlewareStateEntry {\n return [key, value];\n}\n\n/** A plain, `Map`-backed `MiddlewareStateBag`, optionally seeded with `entries`. Later entries win. */\nexport function createMiddlewareStateBag(\n entries?: readonly MiddlewareStateEntry[],\n): MiddlewareStateBag {\n const store = new Map<MiddlewareStateKey<unknown>, unknown>(entries);\n\n return {\n get<T>(key: MiddlewareStateKey<T>): T | undefined {\n return store.get(key) as T | undefined;\n },\n set<T>(key: MiddlewareStateKey<T>, value: T): void {\n store.set(key, value);\n },\n };\n}\n\n/** Fields every `MiddlewareContext` variant carries, regardless of `stage`. */\nexport interface MiddlewareContextBase {\n requestId: string;\n\n /** Capabilities of the target this stage's identity fields describe. */\n capabilities: MiddlewareCapabilities;\n\n signal?: AbortSignal;\n\n /** Shared, collision-proof state for two middleware to deliberately coordinate through. See `MiddlewareStateBag`. */\n state: MiddlewareStateBag;\n\n /** Simple, string-keyed scratch space, pre-namespaced to this one middleware so two middleware can never collide here even by accident. */\n own: Record<string, unknown>;\n\n /**\n * Every registered middleware's label, in `transform` order, e.g. to skip work another known\n * middleware already does.\n */\n registeredMiddlewareNames: readonly string[];\n\n /**\n * The labels from `registeredMiddlewareNames` whose entry defines a\n * `transform`, in the same order, frozen. Lets a middleware tell\n * whether any entry after it can still change the request.\n */\n transformMiddlewareNames: readonly string[];\n\n /** Reports a `custom` event to `onEvent` and every middleware. Never throws. */\n emit(name: string, data?: JsonValue): void;\n\n /** The call's `context`, frozen. `undefined` when none was given. */\n context: CallContext | undefined;\n}\n\n/**\n * The `ctx` for `transform` and every attempt scoped event. Built once a target is selected, so\n * every field describes the real target.\n */\nexport interface AttemptContext extends MiddlewareContextBase {\n stage: 'attempt';\n\n /** The target this attempt is actually dispatched to. */\n requestedProvider: string;\n /** The adapter behind this target. `{ name: 'custom' }` when its client doesn't identify one. */\n adapter: AdapterInfo;\n requestedModel: string;\n isFallbackAttempt: boolean;\n\n /**\n * The current attempt number. A `'circuit_state'` event from the check before any attempt reports\n * 1.\n */\n attempt: number;\n}\n\n/**\n * The `ctx` for `wrap` and `onError`. Built before any target is chosen, so it only describes the\n * primary. Read `next()`'s `CallResult.meta` for what happened.\n */\nexport interface PreDispatchContext extends MiddlewareContextBase {\n stage: 'pre-dispatch';\n\n /** The primary target only, not necessarily who ends up answering. */\n primaryProvider: string;\n /** The adapter behind the primary target. `{ name: 'custom' }` when its client doesn't identify one. */\n primaryAdapter: AdapterInfo;\n primaryModel: string;\n\n /** The order so far: what this `wrap` may try, after every outer `wrap` narrowed it. */\n targets: readonly TargetInfo[];\n}\n\n/**\n * What `enabled` and `onEvent` receive, since they run in both stages. Narrow on `ctx.stage` before\n * reading stage specific fields.\n */\nexport type MiddlewareContext = AttemptContext | PreDispatchContext;\n\n/** The `response_format` shape `RequestBuilder` can put on the wire. */\nexport type WireResponseFormat =\n | { type: 'json_object' }\n | {\n type: 'json_schema';\n json_schema: {\n name: string;\n schema: Record<string, unknown>;\n strict?: boolean;\n description?: string;\n };\n };\n\n/** A tool as it appears on the wire, OpenAI's `function`-wrapped shape. */\nexport interface WireTool {\n type: 'function';\n function: {\n name: string;\n description: string;\n parameters: Record<string, unknown>;\n };\n}\n\n/**\n * The wire-shaped request `RequestBuilder.build()` produces for one call\n * attempt, before dispatch. Read only inside `transform`; return a patch\n * of the fields you want to change instead of the whole object.\n */\nexport interface WireCallRequest {\n model: string;\n temperature?: number;\n max_tokens: number;\n response_format?: WireResponseFormat;\n reasoning_effort?: 'minimal' | 'low' | 'medium' | 'high';\n budget_tokens?: number;\n tools?: WireTool[];\n tool_choice?: WireToolChoice;\n messages: WireMessage[];\n}\n\n/**\n * A patch `transform` returns, merged onto the built request. `model` and `response_format` can't\n * be patched, since targets are attributed by the values already resolved. `add*` fields append, so\n * two middleware can add without overwriting each other.\n */\nexport interface WireCallRequestPatch {\n temperature?: number;\n max_tokens?: number;\n reasoning_effort?: 'minimal' | 'low' | 'medium' | 'high';\n budget_tokens?: number;\n tool_choice?: WireToolChoice;\n\n /** Replaces the whole message list. Prefer `addMessages` unless a full replace is genuinely the intent. */\n messages?: WireMessage[];\n /** Appended after whatever earlier middleware already added. Never clobbers a prior addition. */\n addMessages?: WireMessage[];\n\n /** Replaces the whole tool list. Prefer `addTools`, same reasoning as `messages`/`addMessages`. */\n tools?: WireTool[];\n /** Appended after whatever earlier middleware already added. Never clobbers a prior addition. */\n addTools?: WireTool[];\n}\n\n/**\n * The settled outcome of one logical call, from `wrap`'s `next()`. `meta` is `undefined` only on a\n * cache hit.\n */\nexport interface CallResult<T = unknown> {\n value: T;\n meta?: CallMeta;\n}\n\n/**\n * One entry in `VernLLMOptions.middleware`. Every hook is optional. See the middleware docs for how\n * hooks compose.\n */\nexport interface VernLLMMiddleware {\n /** Used in log lines and the `'middleware'` event. Defaults to this entry's array position when omitted. */\n name?: string;\n\n /**\n * This entry's identity for other entries' `runsAfter` and `runsBefore`. Unrelated to `name`,\n * which is only a label.\n */\n ref?: MiddlewareRef;\n\n /** Sort key for composition order, ascending, ties broken by array order. See the middleware docs for what \"lower runs first\" means for `wrap`. */\n priority?: number;\n\n /**\n * Middleware this entry runs after. An unresolved bare ref is dropped; wrap it with `requireRef`\n * to throw at construction instead. A cycle always throws.\n */\n runsAfter?: (MiddlewareRef | RequiredMiddlewareRef)[];\n\n /**\n * Other middleware this entry must run before. See `runsAfter`; a\n * bare reference is dropped if unresolved, a `requireRef`-wrapped one\n * throws.\n */\n runsBefore?: (MiddlewareRef | RequiredMiddlewareRef)[];\n\n /**\n * Pins this entry in `wrap` nesting only. `'outermost'` sees the net result of every retry and\n * fallback; `'innermost'` sits next to dispatch. A number works like `priority` for `wrap` only.\n */\n position?: 'outermost' | 'innermost' | number;\n\n /**\n * Boolean for a static on/off switch, or a predicate evaluated per\n * call. A throwing, rejecting, or timed-out predicate is logged and\n * treated as `false` for that call.\n */\n enabled?: boolean | ((ctx: MiddlewareContext) => boolean | Promise<boolean>);\n\n /** Per-middleware override of the instance-level `middlewareTimeoutMs`, applied to this entry's `transform` and function `enabled`. `<= 0` means unbounded (no timer at all). */\n timeoutMs?: number;\n\n /** Transforms the outgoing wire request for one attempt. Runs once per attempt, including retries. `ctx` is always accurate to the real target for this attempt. */\n transform?: (\n request: Readonly<WireCallRequest>,\n ctx: AttemptContext,\n ) => WireCallRequestPatch | Promise<WireCallRequestPatch>;\n\n /**\n * Wraps one whole logical call once, however many retries or targets ran. `ctx` describes the\n * primary and the order so far (`ctx.targets`); read `next()`'s `CallResult.meta` for what\n * happened. `next({ targets })` reorders or drops targets by name, never adds one.\n */\n wrap?: (\n request: Readonly<WireCallRequest>,\n next: (options?: { targets?: readonly string[] }) => Promise<CallResult>,\n ctx: PreDispatchContext,\n ) => Promise<CallResult>;\n\n /**\n * Wraps one attempt's provider request, after the limiter and every `transform`. `request` is\n * exactly what the adapter gets. Runs per attempt, nested in `wrap` order.\n *\n * `next()` resolves when the response arrives, or at a stream's first content chunk; pings don't\n * count. It rejects with the attempt's `LLMError`. A hook can observe but not change the outcome:\n * returning or throwing without calling `next()` fails the attempt with code `middleware_threw`,\n * and a throw after it is only logged.\n */\n dispatch?: (\n request: Readonly<WireCallRequest>,\n next: () => Promise<void>,\n ctx: AttemptContext,\n ) => Promise<void>;\n\n /** Observes the same events reported on `VernLLMOptions.onEvent`, filtered by this middleware's own `enabled`. Called from both stages; narrow on `ctx.stage` before reading stage-specific fields. */\n onEvent?: (event: VernLLMEvent, ctx: MiddlewareContext) => void;\n}\n","import type { LLMError } from './errors.js';\nimport type { PreDispatchContext, VernLLMMiddleware } from './middleware.js';\n\n/**\n * `VernLLMMiddleware` plus `onError`, for middleware that only cares about failures. `wrap` can't\n * be set alongside it, since `onError` builds its own.\n */\nexport type CreateMiddlewareOptions = Omit<VernLLMMiddleware, 'wrap'> & {\n wrap?: undefined;\n /**\n * Called with the call's terminal error. Not called on success or when another `wrap` swallowed\n * the failure. Only observes: the error is always rethrown and a throwing `onError` is discarded.\n * `ctx` is `wrap`'s pre-dispatch context.\n */\n onError?: (error: LLMError, ctx: PreDispatchContext) => void | Promise<void>;\n};\n\n/**\n * Builds a middleware entry. With `onError`, adds a `wrap` that reports rejections and always\n * rethrows, so the call's outcome never changes.\n */\nexport function createMiddleware(options: CreateMiddlewareOptions): VernLLMMiddleware {\n const { onError, ...rest } = options;\n\n if (!onError) return rest;\n\n return {\n ...rest,\n wrap: async (_request, next, ctx) => {\n try {\n return await next();\n } catch (error) {\n try {\n await onError(error as LLMError, ctx);\n } catch {\n // onError is fire-and-forget, matching onUsage/onEvent: a\n // throwing observer never masks (or replaces) the real error\n // below.\n }\n throw error;\n }\n },\n };\n}\n","import {\n LLMError,\n type StreamChunk,\n type TokenUsage,\n type UsageHooks,\n} from '../../../../types/index.js';\n\n/** Usage shape shared by a non-streaming response and a stream's `usage` chunk. Both wire types agree field for field. */\nexport interface WireUsage {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n completion_tokens_details?: { reasoning_tokens?: number };\n /** Cache split of `prompt_tokens`. Follows OpenAI and OpenRouter naming. */\n prompt_tokens_details?: {\n cached_tokens?: number;\n cache_write_tokens?: number;\n /** Writes by TTL label, e.g. `{ '5m': 1200, '1h': 800 }`. */\n cache_write_tokens_by_ttl?: Record<string, number>;\n };\n}\n\n/** Call-level fields stamped onto every `TokenUsage`, not carried by the wire usage itself. */\nexport interface TokenUsageMeta {\n requestId: string;\n model: string;\n providerName: string;\n isFallback: boolean;\n}\n\n/**\n * Maps a provider's wire usage block to `TokenUsage`. Shared by\n * `usageReporter.extract` (non-streaming) and `buildStreamResult` (the\n * `usage` stream chunk), since both wire shapes are identical.\n */\nexport function toTokenUsage(wireUsage: WireUsage, meta: TokenUsageMeta): TokenUsage {\n const reasoningTokens = wireUsage.completion_tokens_details?.reasoning_tokens;\n const details = wireUsage.prompt_tokens_details;\n\n return {\n promptTokens: wireUsage.prompt_tokens ?? 0,\n completionTokens: wireUsage.completion_tokens ?? 0,\n totalTokens: wireUsage.total_tokens ?? 0,\n ...(reasoningTokens !== undefined ? { reasoningTokens } : {}),\n ...(details?.cached_tokens !== undefined ? { cacheReadTokens: details.cached_tokens } : {}),\n ...(details?.cache_write_tokens !== undefined\n ? { cacheWriteTokens: details.cache_write_tokens }\n : {}),\n ...(details?.cache_write_tokens_by_ttl\n ? { cacheWriteTokensByTtl: { ...details.cache_write_tokens_by_ttl } }\n : {}),\n requestId: meta.requestId,\n model: meta.model,\n provider: meta.providerName,\n usedFallback: meta.isFallback,\n };\n}\n\n/**\n * Calls `reserveUsage` if set, mapping a failure to `quota_exceeded`, or `aborted` if the signal\n * fired. Returns whether a reservation was made, so callers know to refund.\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 * A refund function that logs a failing refund hook instead of throwing, so it never masks the\n * original error.\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` inside a usage reservation, refunding on failure or abort when a reservation was\n * made.\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`. Reserves before opening and refunds at once if\n * opening fails. Once open it returns straight away and defers the refund to `finalResult`, since\n * the outcome is only known then, well after this returns.\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","/**\n * Wraps `chunks` so that stopping before the end calls `onExit` once the\n * last active reader has left: a `break` out of `for await`, an exception\n * thrown in the loop body, or a direct `return()`. A reader is active from\n * its first pull until it reaches the end, its pull rejects, or it\n * returns. An early exit while another reader is still active doesn't\n * fire, since that reader still needs the stream. Reaching the end, or a\n * pull rejecting because the stream itself failed, never fires. The inner\n * iterator is closed either way.\n */\nexport function onEarlyExit<T>(chunks: AsyncIterable<T>, onExit: () => void): AsyncIterable<T> {\n let activeReaders = 0;\n\n return {\n [Symbol.asyncIterator]() {\n const iterator = chunks[Symbol.asyncIterator]();\n let active = false;\n let ended = false;\n\n // Runs once per reader, whichever way it ends.\n const end = (): void => {\n ended = true;\n if (active) {\n active = false;\n activeReaders--;\n }\n };\n\n return {\n async next(): Promise<IteratorResult<T>> {\n if (!active && !ended) {\n active = true;\n activeReaders++;\n }\n\n try {\n const result = await iterator.next();\n if (result.done) end();\n return result;\n } catch (error) {\n end();\n throw error;\n }\n },\n async return(): Promise<IteratorResult<T>> {\n if (!ended) {\n end();\n if (activeReaders === 0) onExit();\n }\n\n await iterator.return?.();\n return { done: true, value: undefined };\n },\n };\n },\n };\n}\n\n/**\n * Aborts `controller` when the last active reader of `chunks` stops early.\n * A no-op without a controller (`cachedCall()`'s inner call).\n */\nexport function cancelOnBreak<T, R>(\n stream: { chunks: AsyncIterable<T>; finalResult: Promise<R> },\n controller: AbortController | undefined,\n): { chunks: AsyncIterable<T>; finalResult: Promise<R> } {\n if (!controller) return stream;\n\n // Once settled there is nothing to cancel, and aborting would only flip\n // the signal middleware still holds.\n let settled = false;\n const markSettled = () => {\n settled = true;\n };\n void stream.finalResult.then(markSettled, markSettled);\n\n return {\n chunks: onEarlyExit(stream.chunks, () => {\n if (!settled) controller.abort();\n }),\n finalResult: stream.finalResult,\n };\n}\n","/** A promise with its settle functions exposed, for results settled from elsewhere. */\nexport interface Deferred<T> {\n promise: Promise<T>;\n resolve: (value: T) => void;\n reject: (error: unknown) => void;\n}\n\nexport function createDeferred<T>(): Deferred<T> {\n let resolve!: (value: T) => void;\n let reject!: (error: unknown) => void;\n const promise = new Promise<T>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n\n return { promise, resolve, reject };\n}\n","import type { Logger } from '../../logger.js';\n\n/** Logs a user hook that threw, as `[VernLLM] <hookName> failed` with message and stack. */\nexport function logHookError(logger: Logger, hookName: string, error: unknown): void {\n logError(logger, `[VernLLM] ${hookName} failed`, error);\n}\n\n/** An error's message, or `'unknown'` for a non-Error throw. */\nexport function errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : 'unknown';\n}\n\n/** Logs `message` at error level with the error's message and stack kept. */\nexport function logError(logger: Logger, message: string, error: unknown): void {\n logger.error(message, {\n message: errorMessage(error),\n stack: error instanceof Error ? error.stack : undefined,\n });\n}\n\n/**\n * Calls a synchronous, user-supplied hook and swallows/logs anything it\n * throws via `logHookError`, so a broken hook can never break the call\n * that triggered it.\n */\nexport function callHookSafely(logger: Logger, hookName: string, fn: () => void): void {\n try {\n fn();\n } catch (error) {\n logHookError(logger, hookName, error);\n }\n}\n\n/**\n * Wraps a user supplied `Logger` so a throwing one can never break the call it describes. Wrapped\n * once, so call sites need no guard.\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\n/** Discards every call. Used for `logger: 'silent'`. */\nexport class NoopLogger implements Logger {\n debug(_message: string): void {}\n warn(_message: string): void {}\n error(_message: string, _meta?: Record<string, unknown>): void {}\n}\n","/** A keyed registry of in-flight promises, returned by `createInFlightRegistry`. */\nexport interface InFlightRegistry<T> {\n /** The promise currently tracked under `key`, if any. */\n get(key: string): Promise<T> | undefined;\n /**\n * Registers `promise` under `key` synchronously and removes it once it settles. Returns `promise`\n * unchanged.\n */\n track(key: string, promise: Promise<T>): Promise<T>;\n}\n\n/** At most one in-flight promise per key, removed once it settles. */\nexport function createInFlightRegistry<T>(): InFlightRegistry<T> {\n const inFlight = new Map<string, Promise<T>>();\n\n function get(key: string): Promise<T> | undefined {\n return inFlight.get(key);\n }\n\n function track(key: string, promise: Promise<T>): Promise<T> {\n inFlight.set(key, promise);\n\n // The promise returned below is untouched, so its own rejection\n // still propagates normally to anyone who does await it. This\n // separate handle only exists so cleanup doesn't itself surface an\n // unhandled rejection for a promise nobody else observes.\n void promise\n .catch(() => {})\n .finally(() => {\n // Only remove this entry if it's still the one registered under\n // `key`: a newer `track()` call for the same key may have\n // already replaced it, and that replacement must survive this\n // (older) promise settling later.\n if (inFlight.get(key) === promise) {\n inFlight.delete(key);\n }\n });\n\n return promise;\n }\n\n return { get, track };\n}\n","import type { StreamChunk } from '../../../types/stream.js';\nimport type { CallWithToolsResult } from '../../../types/tools.js';\n\n/**\n * A cached value as replay text: strings as is, anything else stringified. Not the original\n * streamed text, but enough for loops that don't care whether they got a hit.\n */\nfunction toReplayText(value: unknown): string {\n return typeof value === 'string' ? value : (JSON.stringify(value) ?? '');\n}\n\n/**\n * A one-shot `chunks` replay of a cached value. No `usage` chunk, since a hit spends nothing.\n * `hasTools` must reflect the original call, since the value's shape alone can't tell a\n * `CallWithToolsResult` from a `T`.\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 * Replay for a joiner: waits for the in-flight value, then replays it. A rejection makes iterating\n * `chunks` throw, as a live stream would.\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 { LLMError } from '../../../types/errors.js';\n\nimport type { StreamChunk } from '../../../types/stream.js';\n\n/**\n * A signal owned by every caller coalesced onto one operation. It fires only once the last one has\n * left, so one caller's abort never cancels work others still wait on.\n */\nexport interface SharedAbort {\n /** Passed to the shared operation. Fires only when no participant remains. */\n readonly signal: AbortSignal;\n /** Number of callers still waiting on the shared operation. */\n readonly participants: number;\n /** Registers a participant. Returns an idempotent release function. */\n join(): () => void;\n /** Marks the shared operation settled, so a later release never aborts it. */\n settle(): void;\n}\n\nexport function createSharedAbort(): SharedAbort {\n const controller = new AbortController();\n let participants = 0;\n let settled = false;\n\n return {\n signal: controller.signal,\n get participants() {\n return participants;\n },\n join() {\n participants++;\n let released = false;\n\n return () => {\n if (released) return;\n released = true;\n participants--;\n\n if (participants === 0 && !settled && !controller.signal.aborted) {\n controller.abort(new LLMError('LLM request aborted', 'aborted'));\n }\n };\n },\n settle() {\n settled = true;\n },\n };\n}\n\nfunction abortedError(): LLMError {\n return new LLMError('LLM request aborted', 'aborted');\n}\n\n/**\n * Settles with `promise`, or rejects with an `aborted` LLMError as soon as\n * `signal` fires, whichever comes first. `promise` itself keeps running;\n * only this caller stops waiting on it.\n */\nexport function raceAbort<T>(promise: Promise<T>, signal: AbortSignal | undefined): Promise<T> {\n if (!signal) return promise;\n\n if (signal.aborted) {\n // Observed so an unawaited rejection of the shared promise stays quiet.\n promise.catch(() => {});\n return Promise.reject(abortedError());\n }\n\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => reject(abortedError());\n signal.addEventListener('abort', onAbort, { once: true });\n\n promise.then(\n (value) => {\n signal.removeEventListener('abort', onAbort);\n resolve(value);\n },\n (error: unknown) => {\n signal.removeEventListener('abort', onAbort);\n reject(error);\n },\n );\n });\n}\n\n/**\n * Relays `chunks` until `signal` fires, then throws `aborted` for this caller only. Leaving early\n * detaches this reader and leaves the shared stream running for the others.\n */\nexport function abortableChunks(\n chunks: AsyncIterable<StreamChunk>,\n signal: AbortSignal | undefined,\n): AsyncIterable<StreamChunk> {\n return {\n async *[Symbol.asyncIterator]() {\n const iterator = chunks[Symbol.asyncIterator]();\n\n try {\n while (true) {\n const next = await raceAbort(iterator.next(), signal);\n if (next.done) return;\n yield next.value;\n }\n } finally {\n // An async generator's own early exit doesn't close the iterator it\n // reads from, so close it here. On a stream channel that detaches\n // this reader instead of cancelling the stream.\n void Promise.resolve(iterator.return?.()).catch(() => {});\n }\n },\n };\n}\n","import {\n withReservedUsage,\n withReservedUsageForStream,\n} from '../execution/utils/response/usage.utils.js';\nimport { onEarlyExit } from '../execution/utils/stream/earlyExit.utils.js';\nimport { createDeferred } from '../utils/deferred.utils.js';\nimport { errorMessage, logError } from '../utils/logger.utils.js';\nimport { createInFlightRegistry } from './utils/inFlightRegistry.utils.js';\nimport { buildReplayChunks, buildReplayChunksFromPromise } from './utils/replay.utils.js';\nimport {\n abortableChunks,\n createSharedAbort,\n raceAbort,\n type SharedAbort,\n} from './utils/sharedAbort.utils.js';\n\nimport type { Logger } from '../../logger.js';\nimport type { LLMError } from '../../types/errors.js';\nimport type { CacheAdapter, StreamChunk, UsageHooks } from '../../types/index.js';\nimport type { InternalCacheParams, InternalCacheStreamParams } from './utils/cache.utils.js';\n\n/**\n * Cache key resolution, reads, writes and coalescing of concurrent misses. Knows nothing about\n * providers: the work is an opaque callback from `cachedCall`.\n */\nexport class CacheOrchestrator {\n private readonly inFlight = createInFlightRegistry<unknown>();\n /** The shared abort owned by each in-flight promise's participants. */\n private readonly sharedAborts = new WeakMap<Promise<unknown>, SharedAbort>();\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(`[VernLLM] cache delete failed: ${errorMessage(error)}`);\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(`[VernLLM] cache read failed: ${errorMessage(error)}`);\n\n return { hit: false };\n }\n }\n\n /**\n * Resolves `params.cacheKey` and reads the cache under that key in one\n * step. Shared by `runCached` and `runCachedStream`, which otherwise\n * duplicated this exact prefix.\n */\n private async resolveKeyAndReadCache<P extends { cacheKey: string }>(\n params: P,\n ): Promise<{ resolvedParams: P; cached: { hit: boolean; value?: unknown } }> {\n const resolvedKey = await this.resolveCacheKey(params.cacheKey);\n const resolvedParams: P =\n resolvedKey === params.cacheKey ? params : { ...params, cacheKey: resolvedKey };\n\n return { resolvedParams, cached: await this.getCached(resolvedKey) };\n }\n\n /** The shared in-flight promise for `key`, if any, so callers can wait for it to settle. */\n inFlightFor(key: string): Promise<unknown> | undefined {\n return this.inFlight.get(key);\n }\n\n /**\n * Returns the in-flight entry for `key` a new caller can still join, or\n * `undefined`. An entry whose shared signal already fired is doomed, so\n * it's skipped and the caller starts fresh work instead.\n */\n private joinable<T>(key: string): { promise: Promise<T>; shared: SharedAbort } | undefined {\n const promise = this.inFlight.get(key) as Promise<T> | undefined;\n if (!promise) return undefined;\n\n const shared = this.sharedAborts.get(promise);\n if (!shared || shared.signal.aborted) return undefined;\n\n return { promise, shared };\n }\n\n /**\n * Joins another caller's in-flight work, reserving usage as a coalesced spend. This caller's\n * signal only ends its own wait.\n */\n private joinInFlight<T, P extends UsageHooks & { signal?: AbortSignal }>(\n params: P,\n existing: Promise<T>,\n shared: SharedAbort,\n ): Promise<T> {\n const release = shared.join();\n\n const result = withReservedUsage(\n params,\n true,\n () => raceAbort(existing, params.signal),\n params.signal,\n (logMessage, error) => logError(this.logger, logMessage, error),\n );\n\n void result.then(release, release);\n\n return result;\n }\n\n /**\n * The caching core behind `cachedCall()`. Concurrent misses for one key share a single in-flight\n * call, aborted only once every waiting caller has left.\n *\n * @param params Cache settings plus `fn`, the work to run on a miss. See `InternalCacheParams`.\n * @returns The cached value on a hit, or `fn()`'s result on a miss.\n */\n async runCached<T>(params: InternalCacheParams<T>): Promise<T> {\n const { resolvedParams, cached } = await this.resolveKeyAndReadCache(params);\n\n if (cached.hit) return cached.value as T;\n\n const existing = this.joinable<T>(resolvedParams.cacheKey);\n\n if (existing) {\n return this.joinInFlight(resolvedParams, existing.promise, existing.shared);\n }\n\n return this.registerTrigger(resolvedParams);\n }\n\n /**\n * Creates and registers the shared work synchronously, so a concurrent caller always sees it in\n * time to join. `start` runs it at most once.\n */\n private createShared<V>(key: string, run: (signal: AbortSignal) => Promise<V>) {\n const shared = createSharedAbort();\n const { promise, resolve: resolveShared, reject: rejectShared } = createDeferred<V>();\n\n void promise.then(shared.settle, shared.settle);\n this.sharedAborts.set(promise, shared);\n this.inFlight.track(key, promise);\n\n let started = false;\n\n // Called exactly once: by the trigger, or by `onTriggerFailed` when\n // the trigger failed before calling it.\n const start = (): Promise<V> => {\n started = true;\n const running = run(shared.signal);\n running.then(resolveShared, rejectShared);\n return running;\n };\n\n /**\n * Called when the trigger failed. If it never started the work, the\n * work starts anyway for any participant still waiting on an abort,\n * otherwise the shared promise fails with the trigger's error.\n */\n const onTriggerFailed = (error: unknown) => {\n if (started) return;\n\n // Before `start`, the trigger can only fail in usage reservation or\n // an abort check, and both throw an LLMError.\n if ((error as LLMError).type === 'aborted' && shared.participants > 0) {\n // `start` already routes a rejection into the shared promise.\n void start();\n return;\n }\n\n rejectShared(error);\n };\n\n return { shared, promise, start, onTriggerFailed };\n }\n\n /** Starts the shared fn() call for a cache miss and tracks it in the in-flight registry until it settles. */\n private registerTrigger<T>(params: InternalCacheParams<T>): Promise<T> {\n const { shared, promise, start, onTriggerFailed } = this.createShared<T>(\n params.cacheKey,\n (signal) => this.runAndCache(params, signal),\n );\n const release = shared.join();\n\n const resultPromise = withReservedUsage(\n params,\n false,\n () => raceAbort(start(), params.signal),\n params.signal,\n (logMessage, error) => logError(this.logger, logMessage, error),\n );\n\n void resultPromise.then(release, (error: unknown) => {\n release();\n onTriggerFailed(error);\n });\n\n // Observed so a shared rejection nobody else awaits stays quiet.\n promise.catch(() => {});\n\n return resultPromise;\n }\n\n /** Runs `fn` and writes its result to the cache. */\n private async runAndCache<T>(params: InternalCacheParams<T>, signal: AbortSignal): Promise<T> {\n const result = await params.fn(signal);\n await this.writeCache(params.cacheKey, result, params.ttl);\n return result;\n }\n\n /** Writes to the cache, logging instead of throwing on adapter failure. */\n private async writeCache(key: string, value: unknown, ttl: number): Promise<void> {\n // Never handed to the adapter: a custom one could turn a NaN expiry into\n // an entry that is never evicted. The warning is the only sign the\n // caller gets that nothing is being cached.\n if (typeof ttl !== 'number' || Number.isNaN(ttl)) {\n this.logger.warn(\n `[VernLLM] cachedCall ttl must be a number of seconds, got ${String(ttl)}. Nothing is cached.`,\n );\n return;\n }\n\n try {\n await this.cache.set(key, value, ttl);\n } catch (error) {\n this.logger.warn(`[VernLLM] cache write failed: ${errorMessage(error)}`);\n }\n }\n\n /**\n * Streaming counterpart to `runCached`. A hit returns the cached value with a one-shot replay of\n * `chunks`, and no usage hooks fire. A miss with nothing in flight opens the stream and relays it\n * live. A miss that finds work in flight replays once it resolves; streaming and plain calls for\n * a key coalesce with each other.\n */\n async runCachedStream<T>(\n params: InternalCacheStreamParams<T>,\n hasTools: boolean,\n ): Promise<{ chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> }> {\n const { resolvedParams, cached } = await this.resolveKeyAndReadCache(params);\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.joinable<T>(resolvedParams.cacheKey);\n\n if (existing) {\n const finalResult = this.joinInFlight(resolvedParams, existing.promise, existing.shared);\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 miss and tracks it until it settles, caching on success only. The\n * stream runs under the shared signal, so joiners keep it after the trigger leaves; the trigger's\n * own `chunks` and `finalResult` stop at its signal.\n */\n private registerStreamTrigger<T>(\n params: InternalCacheStreamParams<T>,\n ): Promise<{ chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> }> {\n type Opened = { chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> };\n\n let openedStream: Promise<Opened> | undefined;\n\n const openShared = (signal: AbortSignal): Promise<Opened> => {\n openedStream ??= params.openStream(signal).then((opened) => ({\n chunks: opened.chunks,\n finalResult: opened.finalResult.then(async (value) => {\n // Failed calls aren't cached, matching `runAndCache`.\n await this.writeCache(params.cacheKey, value, params.ttl);\n return value;\n }),\n }));\n\n return openedStream;\n };\n\n const { shared, promise, start, onTriggerFailed } = this.createShared<T>(\n params.cacheKey,\n async (signal) => (await openShared(signal)).finalResult,\n );\n const release = shared.join();\n\n promise.catch(() => {});\n\n // Stopping `chunks` early leaves the shared stream the same way an\n // abort does: this trigger's `finalResult` rejects as aborted, and the\n // stream is cancelled only once no joiner is left waiting on it.\n const left = new AbortController();\n const triggerSignal = params.signal\n ? AbortSignal.any([params.signal, left.signal])\n : left.signal;\n\n const streamPromise = withReservedUsageForStream(\n params,\n async () => {\n void start().catch(() => {});\n const opened = await raceAbort(openShared(shared.signal), params.signal);\n const finalResult = raceAbort(opened.finalResult, triggerSignal);\n finalResult.catch(() => {});\n\n return {\n chunks: onEarlyExit(abortableChunks(opened.chunks, params.signal), () => left.abort()),\n finalResult,\n };\n },\n params.signal,\n (logMessage, error) => logError(this.logger, logMessage, error),\n );\n\n const onFailed = (error: unknown) => {\n release();\n onTriggerFailed(error);\n };\n\n streamPromise.then((opened) => {\n opened.finalResult.then(release, onFailed);\n }, onFailed);\n\n return streamPromise;\n }\n}\n","import type { CallMeta } from '../../../types/index.js';\n\nexport type MetaHolder = { current?: CallMeta };\n\n/**\n * Returns the `CallMeta` holder shared by every `cachedCall()` in flight for\n * `key`, so a joiner reports the trigger's metadata. A hit never creates one,\n * so it still reports none.\n *\n * `release` is a no-op for joiners. For the creator it deletes the holder once\n * the key's in-flight work settles, looked up at release time.\n */\nexport function claimMetaHolder(\n holders: Map<string, MetaHolder>,\n key: string,\n inFlightFor: (key: string) => Promise<unknown> | undefined,\n): { holder: MetaHolder; release: () => void } {\n const existing = holders.get(key);\n if (existing) return { holder: existing, release: () => {} };\n\n const holder: MetaHolder = {};\n holders.set(key, holder);\n\n const release = () => {\n const deleteHolder = () => holders.delete(key);\n const shared = inFlightFor(key);\n\n if (shared) void shared.then(deleteHolder, deleteHolder);\n else deleteHolder();\n };\n\n return { holder, release };\n}\n","/**\n * A fixed number of coarse time buckets rather than one entry per call, keeping memory bounded.\n * Rotated lazily on access, with no timer.\n */\nconst BUCKET_COUNT = 10;\n\n/**\n * A failure ratio over a trailing window with bounded memory. Shared by `RollingTripping` and\n * `RetryBudget`.\n */\nexport class RollingRatio {\n private buckets: { total: number; failures: number }[];\n private bucketStartMs = Date.now();\n private readonly bucketWidthMs: number;\n\n constructor(windowMs: number) {\n if (!Number.isFinite(windowMs) || windowMs <= 0) {\n throw new RangeError(`RollingRatio: windowMs must be a finite number > 0, got ${windowMs}`);\n }\n\n this.bucketWidthMs = windowMs / BUCKET_COUNT;\n this.buckets = Array.from({ length: BUCKET_COUNT }, () => ({ total: 0, failures: 0 }));\n }\n\n /** Drops buckets that have aged out of the window, replacing them with fresh, empty ones. */\n private rotate(): void {\n const elapsed = Date.now() - this.bucketStartMs;\n const drop = Math.floor(elapsed / this.bucketWidthMs);\n const shiftCount = Math.min(BUCKET_COUNT, drop);\n\n for (let i = 0; i < shiftCount; i++) {\n this.buckets.shift();\n this.buckets.push({ total: 0, failures: 0 });\n }\n\n if (drop > 0) this.bucketStartMs += drop * this.bucketWidthMs;\n }\n\n /** Records one call outcome into the current bucket. */\n record(failed: boolean): void {\n this.rotate();\n const head = this.buckets[BUCKET_COUNT - 1]!;\n head.total += 1;\n if (failed) head.failures += 1;\n }\n\n /** Fraction of recorded calls that failed within the window. 0 if nothing has been recorded yet. */\n getRatio(): number {\n this.rotate();\n const t = this.buckets.reduce((a, b) => a + b.total, 0);\n const f = this.buckets.reduce((a, b) => a + b.failures, 0);\n return t === 0 ? 0 : f / t;\n }\n\n /** Total calls recorded within the window. */\n getCount(): number {\n this.rotate();\n return this.buckets.reduce((a, b) => a + b.total, 0);\n }\n\n /** Clears every bucket and restarts the window from now. */\n reset(): void {\n this.buckets = Array.from({ length: BUCKET_COUNT }, () => ({ total: 0, failures: 0 }));\n this.bucketStartMs = Date.now();\n }\n}\n","/**\n * Throws `RangeError` unless `value` is a non-negative integer: the calls needed in the window\n * before a ratio is judged. `0` applies the check at once.\n */\nexport function validateMinCalls(value: number, label = 'minCalls'): void {\n if (!Number.isInteger(value) || value < 0) {\n throw new RangeError(`${label} must be a non-negative integer, got ${value}`);\n }\n}\n\n/**\n * Throws `RangeError` unless `value` is a finite fraction in `[0, 1]`. Anything else would always\n * or never trip.\n */\nexport function validateRatio(value: number, label: string): void {\n if (!Number.isFinite(value) || value < 0 || value > 1) {\n throw new RangeError(`${label} must be a finite number between 0 and 1, got ${value}`);\n }\n}\n","import { LLMError } from '../types/errors.js';\nimport { RollingRatio } from './rollingRatio.js';\nimport { validateMinCalls, validateRatio } from './utils/validate.utils.js';\n\n/**\n * `windowMs` and `minCalls` work as in `RollingTripping`: `minCalls` keeps a cold start from\n * tripping. `retryRatio` is the largest share of calls in the window that may be retries. Invalid\n * values throw `RangeError` at construction.\n */\nexport interface RetryBudgetOptions {\n windowMs: number;\n minCalls: number;\n retryRatio: number;\n}\n\n/**\n * Caps the share of a target's recent traffic that may be retries. The breaker asks whether the\n * provider is healthy; this asks whether retrying is still worth the capacity it costs.\n */\nexport class RetryBudget {\n private readonly ratio: RollingRatio;\n\n constructor(private readonly options: RetryBudgetOptions) {\n this.ratio = new RollingRatio(options.windowMs);\n validateMinCalls(options.minCalls);\n validateRatio(options.retryRatio, 'retryRatio');\n }\n\n /**\n * Throws `LLMError('retry_budget_exhausted')` once at least `minCalls`\n * calls have landed in the trailing `windowMs` and the retry ratio\n * among them has reached `retryRatio`. A no-op otherwise.\n */\n assertAvailable(): void {\n if (\n this.ratio.getCount() >= this.options.minCalls &&\n this.ratio.getRatio() >= this.options.retryRatio\n ) {\n throw new LLMError('Retry budget exhausted', 'rate_limited', {\n code: 'retry_budget_exhausted',\n });\n }\n }\n\n /** Records one attempt. `isRetry` is false for a call's first attempt, true for every attempt after it. */\n recordAttempt(isRetry: boolean): void {\n this.ratio.record(isRetry);\n }\n\n /** Current traffic and retry ratio in the trailing window. */\n getSnapshot(): { attempts: number; retryRatio: number } {\n return { attempts: this.ratio.getCount(), retryRatio: this.ratio.getRatio() };\n }\n}\n","import type { AdapterInfo, LLMClient } from '../../types/client.js';\n\n/** What middleware see for a client that doesn't identify its adapter. */\nexport const CUSTOM_ADAPTER: AdapterInfo = Object.freeze({ name: 'custom' });\n\n/**\n * `client.adapter`, copied and frozen so one middleware can't change what\n * the next one reads, or `CUSTOM_ADAPTER` when the client sets none. A\n * blank `name` counts as none, since it can't tell adapters apart.\n */\nexport function resolveAdapterInfo(client: LLMClient): AdapterInfo {\n const info = client.adapter;\n\n if (!info || typeof info.name !== 'string' || info.name.trim() === '') return CUSTOM_ADAPTER;\n\n return Object.freeze(\n typeof info.provider === 'string' && info.provider.trim() !== ''\n ? { name: info.name, provider: info.provider }\n : { name: info.name },\n );\n}\n","import { LLMError } from '../../../types/errors.js';\nimport { callHookSafely } from '../logger.utils.js';\n\nimport type { Logger } from '../../../logger.js';\nimport type { VernLLMEvent } from '../../../types/events.js';\nimport type { TokenUsage } from '../../../types/index.js';\nimport type { CallExecutor } from '../../execution/callExecutor.js';\n\n/** `onUsage`/`onUsageFailure` from `VernLLMOptions`, plumbed alongside `onEvent` so `makeEventReporter` can drive both off the one dispatch point. */\nexport interface UsageReporterHooks {\n onUsage?: (usage: TokenUsage) => void;\n onUsageFailure?: (usage: TokenUsage, error: LLMError) => void;\n}\n\n/**\n * An event reporter that logs, rather than throws, a failing `onEvent`. Kept free of the executor\n * since breakers report before one exists. Also drives `onUsage` and `onUsageFailure` from the\n * usage events, each called independently of `onEvent`.\n */\nexport function makeEventReporter(\n onEvent: ((event: VernLLMEvent) => void) | undefined,\n logger: Logger,\n usageHooks: UsageReporterHooks = {},\n): (event: VernLLMEvent) => void {\n return (event) => {\n if (onEvent) callHookSafely(logger, 'onEvent', () => onEvent(event));\n\n if (event.kind === 'usage' && usageHooks.onUsage) {\n callHookSafely(logger, 'onUsage', () => usageHooks.onUsage!(event.usage));\n }\n\n if (event.kind === 'usage_failure' && usageHooks.onUsageFailure) {\n callHookSafely(logger, 'onUsageFailure', () =>\n usageHooks.onUsageFailure!(event.usage, event.error),\n );\n }\n };\n}\n\n/** Resolves a target index so every circuit-breaker method agrees on what counts as valid. */\nexport function resolveExecutor(\n executors: CallExecutor[],\n index: number,\n caller: string,\n): CallExecutor {\n const executor = executors[index];\n\n if (!executor) {\n throw new RangeError(\n `${caller}: no target at index ${index} (chain has ${executors.length} target${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. */\nexport function warnIfModelUnsupported(\n isolateByModel: boolean,\n model: string | undefined,\n caller: string,\n logger: Logger,\n): void {\n if (model !== undefined && !isolateByModel) {\n 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 * A `void` adapter method with remote state may still return a promise nobody awaits, and an\n * unhandled rejection can end the Node process after the call succeeded. Logs the rejection\n * instead, so adapters don't each have to handle it.\n */\nexport function reportRejection(logger: Logger, message: string, result: unknown): void {\n void Promise.resolve(result).catch((error: unknown) => {\n try {\n logger.error(message, { message: error instanceof Error ? error.message : String(error) });\n } catch {\n // Reporting must never become a second, unhandled rejection: even\n // turning the reason into a string can throw.\n }\n });\n}\n","import { LLMError } from '../../../types/errors.js';\n\nimport type { CircuitBreakerAdapter, CircuitBreakerCallContext } from '../../../circuitBreaker.js';\nimport type { Logger } from '../../../logger.js';\n\n/** How long `VernLLM` waits for a breaker's `prepare` when the adapter declares no `prepareTimeoutMs`, in ms. */\nexport const DEFAULT_PREPARE_TIMEOUT_MS = 1000;\n\n/** A breaker known to have `prepare`, so it can be called on the adapter itself and keep its `this`. */\nexport type PreparableBreaker = CircuitBreakerAdapter &\n Required<Pick<CircuitBreakerAdapter, 'prepare'>>;\n\ntype PrepareOutcome = 'ready' | 'timeout' | 'aborted' | { failed: unknown };\n\n/**\n * Awaits `breaker.prepare` so `assertClosed` decides on fresh data, without letting a slow or\n * broken `prepare` block or fail the call. A rejection, throw or timeout is logged and the call\n * goes on with local state; only the call's own abort rejects, as `aborted`. A late rejection is\n * still handled.\n */\nexport async function runPrepare(\n breaker: PreparableBreaker,\n model: string,\n context: CircuitBreakerCallContext | undefined,\n logger: Logger,\n): Promise<void> {\n const signal = context?.signal;\n if (signal?.aborted) throw new LLMError('Circuit breaker check aborted', 'aborted');\n\n const timeoutMs = breaker.prepareTimeoutMs ?? DEFAULT_PREPARE_TIMEOUT_MS;\n\n let pending: Promise<void>;\n try {\n pending = Promise.resolve(breaker.prepare(model, context));\n } catch (error) {\n warnFailed(logger, error);\n return;\n }\n\n let timer: ReturnType<typeof setTimeout> | undefined;\n let onAbort: (() => void) | undefined;\n\n const outcome = await Promise.race<PrepareOutcome>([\n // Handles a rejection here, so a late one from a `prepare` that lost\n // the race below is never left unhandled.\n pending.then(\n () => 'ready' as const,\n (failed: unknown) => ({ failed }),\n ),\n new Promise<'timeout'>((resolve) => {\n timer = setTimeout(() => resolve('timeout'), timeoutMs);\n }),\n new Promise<'aborted'>((resolve) => {\n if (!signal) return;\n onAbort = () => resolve('aborted');\n signal.addEventListener('abort', onAbort, { once: true });\n // `prepare` may have aborted the signal synchronously, before the listener existed.\n if (signal.aborted) onAbort();\n }),\n ]).finally(() => {\n clearTimeout(timer);\n if (signal && onAbort) signal.removeEventListener('abort', onAbort);\n });\n\n if (outcome === 'aborted') throw new LLMError('Circuit breaker check aborted', 'aborted');\n\n if (outcome === 'timeout') {\n logger.warn(\n `[VernLLM] circuitBreaker.prepare took longer than ${timeoutMs}ms, continuing with the adapter's local state`,\n );\n } else if (outcome !== 'ready') {\n warnFailed(logger, outcome.failed);\n }\n}\n\nfunction warnFailed(logger: Logger, error: unknown): void {\n logger.warn(\n `[VernLLM] circuitBreaker.prepare failed, continuing with the adapter's local state: ${error instanceof Error ? error.message : String(error)}`,\n );\n}\n","import { LLMError } from '../../types/errors.js';\n\nimport type { CallContext, JsonValue } from '../../types/call.js';\nimport type {\n MiddlewareContext,\n MiddlewareContextBase,\n MiddlewareStateBag,\n MiddlewareStateEntry,\n} from '../../types/middleware.js';\n\n/**\n * Per call machinery a middleware reaches through `ctx` but must not be able to read or replace,\n * so it is kept off the state bag, the same way `ownStores` is in `middleware.utils.ts`.\n */\nexport interface CallScope {\n /** The call's validated, frozen `context`. `undefined` when none was given. */\n context: CallContext | undefined;\n\n /** Reports a `custom` event. Never throws. See `createCallScope`. */\n emitCustom: (\n name: string,\n data: JsonValue | undefined,\n source: string,\n ctx: MiddlewareContext,\n ) => void;\n}\n\n/** One scope per logical call, keyed by that call's state bag. */\nconst scopes = new WeakMap<MiddlewareStateBag, CallScope>();\n\n/**\n * Attaches `scope` to a call's state bag. A second registration is ignored, since the inner call\n * of `cachedCall` reuses the bag the outer one already registered.\n */\nexport function registerCallScope(state: MiddlewareStateBag, scope: CallScope): void {\n if (!scopes.has(state)) scopes.set(state, scope);\n}\n\n/** The call's scope, or `undefined` for a bag made outside a call, like a manual `openCircuit()`. */\nexport function callScopeFor(state: MiddlewareStateBag): CallScope | undefined {\n return scopes.get(state);\n}\n\n/** The `emit` a freshly built context carries until `withOwn` binds it to a middleware. */\nexport const noopEmit: MiddlewareContextBase['emit'] = () => {};\n\n/** A plain `{}` or `Object.create(null)` object, not a class instance, `Date`, `Map` and so on. */\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== 'object' || value === null) return false;\n\n const prototype = Object.getPrototypeOf(value) as unknown;\n\n return prototype === Object.prototype || prototype === null;\n}\n\n/**\n * Whether `value` is plain JSON: plain objects, arrays, strings, finite numbers, booleans and\n * `null`. `undefined`, functions, symbols, `NaN`, `Infinity` and class instances are rejected.\n *\n * `ancestors` holds only the objects on the current path, so a cycle is rejected while a value\n * shared by two branches is not.\n */\nexport function isJson(value: unknown, ancestors: Set<object> = new Set()): value is JsonValue {\n if (value === null || typeof value === 'string' || typeof value === 'boolean') return true;\n if (typeof value === 'number') return Number.isFinite(value);\n\n // `Array.from` visits the holes of a sparse array as `undefined`, which are then rejected.\n const items = Array.isArray(value)\n ? Array.from(value as unknown[])\n : isPlainObject(value)\n ? Object.values(value)\n : undefined;\n\n if (items === undefined || ancestors.has(value as object)) return false;\n\n ancestors.add(value as object);\n\n const valid = items.every((item) => isJson(item, ancestors));\n\n ancestors.delete(value as object);\n\n return valid;\n}\n\n/** Freezes `value` and everything inside it. Only ever handed plain JSON, so it always ends. */\nfunction deepFreeze<T>(value: T): T {\n if (typeof value === 'object' && value !== null) {\n Object.values(value).forEach(deepFreeze);\n Object.freeze(value);\n }\n\n return value;\n}\n\n/**\n * Validates, clones and deep freezes a call's `context`. The clone means a caller mutating its\n * own object mid call can't change what middleware read. Throws `invalid_params` for anything\n * that isn't a plain JSON object.\n */\nexport function prepareCallContext(value: unknown): CallContext | undefined {\n if (value === undefined) return undefined;\n\n // Data nested deep enough to overflow the stack is as invalid as a cycle.\n let valid = false;\n\n try {\n valid = isPlainObject(value) && isJson(value);\n } catch {\n valid = false;\n }\n\n if (!valid) {\n throw new LLMError('`context` must be a plain JSON object', 'invalid_params', {\n code: 'invalid_context',\n });\n }\n\n return deepFreeze(structuredClone(value as CallContext));\n}\n\n/**\n * A `[key, value]` pair whose key looks like one made by `createStateKey`. `MiddlewareStateKey` is\n * a type level brand, so the only runtime trace of one is its string `debugName`.\n */\nfunction isStateEntry(entry: unknown): entry is MiddlewareStateEntry {\n if (!Array.isArray(entry) || entry.length !== 2) return false;\n\n const key: unknown = entry[0];\n\n return (\n typeof key === 'object' &&\n key !== null &&\n typeof (key as { debugName?: unknown }).debugName === 'string'\n );\n}\n\n/**\n * Checks that `state` is an array of `[key, value]` pairs, so a malformed entry fails here instead\n * of seeding a key nothing can read. Throws a plain `invalid_params`, with no `code`, since it\n * only happens when a caller bypasses the types.\n */\nexport function validateStateEntries(state: unknown): readonly MiddlewareStateEntry[] | undefined {\n if (state === undefined) return undefined;\n\n if (!Array.isArray(state) || !state.every(isStateEntry)) {\n throw new LLMError(\n '`state` must be an array of [key, value] pairs, with keys made by createStateKey',\n 'invalid_params',\n );\n }\n\n return state;\n}\n","import type { VernLLMMiddleware } from '../../types/middleware.js';\n\n/**\n * A middleware's label everywhere a caller can see one: logs, the\n * `'middleware'` event, and `registeredMiddlewareNames`. `name`, or the\n * bracketed `transformOrder` position when unnamed. The brackets keep an\n * unnamed entry from ever reading like one named `\"0\"`.\n */\nexport function middlewareLabel(middleware: VernLLMMiddleware, index: number): string {\n return middleware.name ?? `[${index}]`;\n}\n\n/** `middlewareLabel` for every entry of an already ordered array. */\nexport function middlewareLabels(ordered: readonly VernLLMMiddleware[]): readonly string[] {\n return Object.freeze(ordered.map((entry, index) => middlewareLabel(entry, index)));\n}\n\n/** The two label lists every middleware context carries. */\nexport interface MiddlewareContextNames {\n registeredMiddlewareNames: readonly string[];\n transformMiddlewareNames: readonly string[];\n}\n\n/**\n * Keyed by array identity: every call site passes the same\n * `transformOrder` array, so the labels are built once per instance\n * instead of once per event or attempt.\n */\nconst contextNamesCache = new WeakMap<readonly VernLLMMiddleware[], MiddlewareContextNames>();\n\n/** `registeredMiddlewareNames` and `transformMiddlewareNames` for an already ordered array. */\nexport function middlewareContextNames(\n ordered: readonly VernLLMMiddleware[],\n): MiddlewareContextNames {\n let names = contextNamesCache.get(ordered);\n\n if (!names) {\n const labels = middlewareLabels(ordered);\n names = {\n registeredMiddlewareNames: labels,\n transformMiddlewareNames: Object.freeze(\n labels.filter((_, index) => ordered[index]!.transform !== undefined),\n ),\n };\n contextNamesCache.set(ordered, names);\n }\n\n return names;\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\ntype HeaderKind = 'ms' | 'seconds' | 'date';\n\n/**\n * Headers checked in order. The millisecond forms come first for finer timing; Retry-After is read\n * as seconds and as an HTTP date.\n */\nconst RETRY_AFTER_CANDIDATES: { name: string; kind: HeaderKind }[] = [\n { name: 'Retry-After-Ms', kind: 'ms' },\n { name: 'X-Retry-After-Ms', kind: 'ms' },\n { name: 'Retry-After', kind: 'seconds' },\n { name: 'Retry-After', kind: 'date' },\n];\n\n/** Reads a header from a `Headers` object or a plain object, case insensitively. */\nfunction readHeader(headers: object, name: string): string | undefined {\n const getter = headers as { get?: (n: string) => string | null };\n\n if (typeof getter.get === 'function') {\n return getter.get(name) ?? undefined;\n }\n\n const match = Object.entries(headers as Record<string, unknown>).find(\n ([key]) => key.toLowerCase() === name.toLowerCase(),\n )?.[1];\n\n return typeof match === 'string' ? match : undefined;\n}\n\n/**\n * A negative value (a malformed delta or a past date) gave no usable timing, so it counts as absent\n * rather than a 0ms retry.\n */\nfunction clampOrUndefined(rawMs: number, maxDelayMs: number): number | undefined {\n return rawMs < 0 ? undefined : Math.min(rawMs, maxDelayMs);\n}\n\n/**\n * Provider retry timing in ms from an unknown error: known millisecond headers first, then\n * Retry-After as seconds or an HTTP date. Reads `.headers`, then `.response.headers`. Capped at\n * `maxDelayMs`; `undefined` when nothing usable is present.\n */\nexport function extractRetryAfterMs(\n err: unknown,\n maxDelayMs: number = 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 for (const { name, kind } of RETRY_AFTER_CANDIDATES) {\n const raw = readHeader(headers, name)?.trim();\n if (!raw) continue;\n\n if (kind === 'ms' && /^\\d+$/.test(raw)) {\n return clampOrUndefined(Number(raw), maxDelayMs);\n }\n\n if (kind === 'seconds' && /^\\d+(\\.\\d+)?$/.test(raw)) {\n return clampOrUndefined(Number(raw) * 1000, maxDelayMs);\n }\n\n if (kind === 'date') {\n const dateMs = Date.parse(raw);\n if (!Number.isNaN(dateMs)) return clampOrUndefined(dateMs - Date.now(), maxDelayMs);\n }\n }\n\n return undefined;\n}\n\n/**\n * Returns the cap unchanged or throws. `0` (retry at once) and `Infinity` (no cap) are valid;\n * negative or NaN throws at construction.\n */\nexport function validateMaxRetryAfterMs(maxRetryAfterMs: number, providerName: string): number {\n if (typeof maxRetryAfterMs !== 'number' || Number.isNaN(maxRetryAfterMs) || maxRetryAfterMs < 0) {\n throw new RangeError(\n `${providerName}: maxRetryAfterMs must be 0 or more (Infinity for no cap), got ${String(maxRetryAfterMs)}`,\n );\n }\n\n return maxRetryAfterMs;\n}\n","import { LLMError } from '../../../types/errors.js';\n\n/**\n * Identity, not a message: never read for its text, only compared by\n * reference in `stampDeadlineCode`, so it can't collide with a reason a\n * caller's own `AbortController` happens to use.\n */\nexport const DEADLINE_REASON = Symbol('deadlineExceeded');\n\n/** Largest delay `setTimeout` honors (2^31 - 1 ms, about 24.8 days). */\nexport const MAX_TIMER_DELAY_MS = 2_147_483_647;\n\n/** The signal `call()` should actually use, and the timer to clear when done. */\nexport interface DeadlineSetup {\n signal: AbortSignal | undefined;\n timer: ReturnType<typeof setTimeout> | undefined;\n}\n\n/**\n * Joins `deadlineMs` into one signal the rest of `call()` treats like the caller's own. Without a\n * deadline the caller's signal passes through and no timer is created.\n */\nexport function setupDeadline(\n deadlineMs: number | undefined,\n callerSignal: AbortSignal | undefined,\n): DeadlineSetup {\n // setTimeout clamps anything above MAX_TIMER_DELAY_MS (and NaN) to about\n // 1ms, so an unbounded or out of range deadline would abort almost\n // immediately. Infinity and anything past the timer range mean no\n // deadline; NaN is treated the same as omitting it.\n if (deadlineMs === undefined || Number.isNaN(deadlineMs) || deadlineMs > MAX_TIMER_DELAY_MS) {\n return { signal: callerSignal, timer: undefined };\n }\n\n const controller = new AbortController();\n\n // A deadline of 0 (or negative) means the budget is already spent. A\n // `setTimeout(fn, 0)` still queues a macrotask, so it wouldn't reliably\n // beat dispatch, the abort has to happen synchronously here instead, the\n // same way an already-aborted caller signal is treated as a fail-fast\n // case rather than raced.\n if (deadlineMs <= 0) {\n controller.abort(DEADLINE_REASON);\n const signal = callerSignal\n ? AbortSignal.any([callerSignal, controller.signal])\n : controller.signal;\n return { signal, timer: undefined };\n }\n\n const timer = setTimeout(() => controller.abort(DEADLINE_REASON), deadlineMs);\n const signal = callerSignal\n ? AbortSignal.any([callerSignal, controller.signal])\n : controller.signal;\n\n return { signal, timer };\n}\n\n/**\n * Sets `code: 'deadline_exceeded'` on an aborted error without a code, only when the deadline\n * caused the abort rather than the caller's signal.\n */\nexport function stampDeadlineCode(error: unknown, signal: AbortSignal | undefined): unknown {\n if (\n error instanceof LLMError &&\n error.type === 'aborted' &&\n error.code === undefined &&\n signal?.reason === DEADLINE_REASON\n ) {\n error.code = 'deadline_exceeded';\n }\n\n return error;\n}\n","import { LLMError } from '../../../../types/errors.js';\nimport { MAX_TIMER_DELAY_MS } from '../deadline.utils.js';\n\nimport type { Logger } from '../../../../logger.js';\n\n// `setTimeout` clamps anything above MAX_TIMER_DELAY_MS, or Infinity, to about 1ms,\n// so the helpers below treat those as no timeout rather than an instant one.\n\n/**\n * The delay `setTimeout` should use, or `undefined` when the timeout is off (0, negative or\n * `Infinity`).\n */\nexport function 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. */\nexport function clampTimeoutMs(ms: number): number {\n return Math.min(ms, MAX_TIMER_DELAY_MS);\n}\n\n/**\n * Runs `fn` with a timeout, joined with any external signal. The call is raced against the timer,\n * so a client that ignores the signal still times out. After the timer fires any error becomes\n * `LLMError('timeout')`; an external abort stays `aborted`. `Infinity`, or any value past the timer\n * range, disables the timeout.\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 signal = externalSignal\n ? AbortSignal.any([externalSignal, controller.signal])\n : controller.signal;\n\n const timeoutError = () =>\n new LLMError('Request timed out', 'timeout', { code: 'request_timeout' });\n\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n // Raced against `fn`, so a client that ignores the signal still times out.\n const timeoutPromise = new Promise<never>((_, reject) => {\n if (activeTimeoutMs === undefined) return;\n\n timer = setTimeout(() => {\n controller.abort();\n reject(timeoutError());\n }, clampTimeoutMs(activeTimeoutMs));\n });\n\n try {\n return await Promise.race([fn(signal), timeoutPromise]);\n } catch (err) {\n // Any error raised after the internal timer fired counts as a timeout,\n // whatever abort error type the client threw. External aborts propagate.\n if (controller.signal.aborted && !externalSignal?.aborted) {\n throw err instanceof LLMError && err.type === 'timeout' ? err : timeoutError();\n }\n\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Races one `iterator.next()` against an idle timer, bounding the gap between chunks, measured from\n * the latest chunk. Rejects with `LLMError('timeout')`; 0, undefined or `Infinity` disable it.\n * `onIdle` fires first so the transport can be aborted. `logger` records a `next()` that settles\n * after the timeout, since that late chunk, possibly usage, would otherwise vanish.\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","import { LLMError, type LLMRequestSnapshot, type RetryAttempt } from '../../../../types/errors.js';\nimport { DEFAULT_MAX_DELAY_MS, extractRetryAfterMs } from './retryAfter.utils.js';\nimport { clampTimeoutMs } from './timeout.utils.js';\n\nimport type { Logger } from '../../../../logger.js';\nimport type {\n AttemptContext,\n MiddlewareStateBag,\n VernLLMEvent,\n VernLLMMiddleware,\n} from '../../../../types/index.js';\n\nexport {\n DEFAULT_MAX_DELAY_MS,\n extractRetryAfterMs,\n validateMaxRetryAfterMs,\n} from './retryAfter.utils.js';\nexport {\n clampTimeoutMs,\n resolveActiveTimeoutMs,\n withChunkIdleTimeout,\n withTimeout,\n} from './timeout.utils.js';\n\n/**\n * Full jitter: uniform over `[0, exp]`. Shared by retry backoff and the breaker's cooldown backoff.\n */\nexport function fullJitter(exp: number): number {\n return Math.random() * exp;\n}\n\n/**\n * Exponential backoff with full jitter, capped at `maxDelayMs`. Without a Retry-After, a 429 backs\n * off hardest and a 5xx more than the default curve; `rateLimited` wins when both are set.\n */\nexport function getBackoffDelay(\n baseDelayMs: number,\n attempt: number,\n maxDelayMs = DEFAULT_MAX_DELAY_MS,\n rateLimited = false,\n serverError = false,\n): number {\n const multiplier = rateLimited ? 2 : serverError ? 1.5 : 1;\n const exp = Math.min(baseDelayMs * multiplier * 2 ** attempt, maxDelayMs);\n return fullJitter(exp);\n}\n\n/** Waits `delay` ms before a retry. Rejects as aborted at once when `signal` fires. */\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 // A Retry-After cap of Infinity can hand over a delay setTimeout would\n // wrap to ~1ms, the opposite of the wait the provider asked for.\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, clampTimeoutMs(delay));\n\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n\n/**\n * Whether a failed attempt is worth retrying, per `LLMError.retryable`\n * and `nonRetryableStatus`. Takes `extractStatus` as a param instead of\n * importing it, since `errors.utils.ts` already imports from this file.\n */\nexport function shouldRetry(\n error: unknown,\n nonRetryableStatus: number[],\n extractStatus: (err: unknown) => number | undefined,\n signal?: AbortSignal,\n): boolean {\n if (signal?.aborted) return false;\n\n if (error instanceof LLMError && !error.retryable) return false;\n\n const status = extractStatus(error);\n\n return !(status !== undefined && nonRetryableStatus.includes(status));\n}\n\n/**\n * Everything `recoverDelay` needs. `extractStatus`, `normalizeError`, and\n * `emitEvent` are injected instead of imported, since `errors.utils.ts`\n * already imports from this file.\n */\nexport interface RecoverDelayParams {\n requestId: string;\n model: string;\n attempt: number;\n error: unknown;\n state: MiddlewareStateBag;\n signal: AbortSignal | undefined;\n providerName: string;\n maxRetries: number;\n baseDelayMs: number;\n /** See `VernLLMOptions.maxRetryAfterMs`. Omitted means the 10s default. */\n maxRetryAfterMs?: number;\n middleware: VernLLMMiddleware[];\n middlewareTimeoutMs: number;\n logger: Logger;\n reportEvent: (event: VernLLMEvent) => void;\n buildEventContext: (\n requestId: string,\n model: string,\n attempt: number,\n signal: AbortSignal | undefined,\n state: MiddlewareStateBag,\n ) => AttemptContext;\n extractStatus: (err: unknown) => number | undefined;\n normalizeError: (err: unknown, signal?: AbortSignal) => LLMError;\n emitEvent: (\n event: VernLLMEvent,\n ctx: AttemptContext,\n reportEvent: (event: VernLLMEvent) => void,\n middleware: VernLLMMiddleware[],\n middlewareTimeoutMs: number,\n logger: Logger,\n ) => void;\n}\n\n/**\n * Waits before a retry, honoring the failed attempt's Retry-After when present, otherwise the\n * backoff curve for its status. Both are capped at the same max delay.\n */\nexport async function recoverDelay(params: RecoverDelayParams): Promise<void> {\n const {\n requestId,\n model,\n attempt,\n error,\n state,\n signal,\n providerName,\n maxRetries,\n baseDelayMs,\n maxRetryAfterMs,\n middleware,\n middlewareTimeoutMs,\n logger,\n reportEvent,\n buildEventContext,\n extractStatus,\n normalizeError,\n emitEvent,\n } = params;\n\n const retryAfterMs = extractRetryAfterMs(error, maxRetryAfterMs);\n const status = extractStatus(error);\n const delay =\n retryAfterMs ??\n getBackoffDelay(\n baseDelayMs,\n attempt,\n undefined,\n status === 429,\n status !== undefined && status >= 500 && status <= 599,\n );\n const retryAfterHonored = retryAfterMs !== undefined;\n\n logger.warn(\n `[VernLLM:${requestId}] recovery attempt ${attempt}/${maxRetries}, waiting ${Math.ceil(delay)}ms` +\n (retryAfterHonored ? ' (honoring Retry-After)' : ''),\n );\n\n emitEvent(\n {\n kind: 'retry',\n requestId,\n provider: providerName,\n model,\n attempt,\n maxRetries,\n delayMs: delay,\n retryAfterHonored,\n error: normalizeError(error, signal),\n },\n buildEventContext(requestId, model, attempt, signal, state),\n reportEvent,\n middleware,\n middlewareTimeoutMs,\n logger,\n );\n\n await waitForRetry(delay, signal);\n}\n\n/**\n * Runs `fn` with retries. Each retried failure is recorded in `attempts` as a snapshot; the final\n * failure is the thrown error itself.\n */\nexport interface RetryWithBackoffParams<T> {\n fn: (\n attempt: number,\n onRequest: (snapshot: LLMRequestSnapshot | undefined) => void,\n ) => Promise<T>;\n maxRetries: number;\n signal?: AbortSignal;\n onAttempt?: () => void;\n attempts?: RetryAttempt[];\n shouldRetryAttempt: (error: unknown, signal?: AbortSignal) => boolean;\n recoverDelayForAttempt: (attempt: number, error: unknown) => Promise<void>;\n /** Injected for the same reason as on `RecoverDelayParams`. */\n normalizeError: (err: unknown, signal?: AbortSignal) => LLMError;\n}\n\n/**\n * A usable retry count. NaN, negative or non-number values would skip the loop and make no call, so\n * they mean one attempt. Fractions round down; `Infinity` stays.\n */\nexport function normalizeMaxRetries(maxRetries: number): number {\n if (typeof maxRetries !== 'number' || Number.isNaN(maxRetries) || maxRetries < 0) return 0;\n return Math.floor(maxRetries);\n}\n\nexport async function retryWithBackoff<T>(params: RetryWithBackoffParams<T>): Promise<T> {\n const {\n fn,\n signal,\n onAttempt,\n attempts,\n shouldRetryAttempt,\n recoverDelayForAttempt,\n normalizeError,\n } = params;\n const maxRetries = normalizeMaxRetries(params.maxRetries);\n\n let lastError: unknown;\n let lastRequestForAttempt: LLMRequestSnapshot | undefined;\n\n for (let attempt = 0; attempt <= 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 // recoverDelayForAttempt 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 recoverDelayForAttempt(attempt, lastError);\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 < maxRetries && shouldRetryAttempt(error, signal);\n if (!willRetry) break;\n\n attempts?.push({\n index: attempt,\n error: normalizeError(error, signal).toSnapshot(),\n request: lastRequestForAttempt,\n });\n }\n }\n\n throw lastError;\n}\n","import { LLMError, type LLMErrorCode, type RetryAttempt } from '../../../types/errors.js';\nimport { extractRetryAfterMs } from './retry/retry.utils.js';\n\n/**\n * The HTTP status on an unknown error: `status`, then `statusCode`, then the AWS SDK's\n * `$metadata.httpStatusCode`. `undefined` when none is present.\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/** Error codes that can only mean the connection itself failed, never an application error. */\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 a transport failure that never reached the provider. Only well known signals\n * count, so an unknown error isn't misread as a connection failure.\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 // Node's `fetch` wraps the real error in `TypeError('fetch failed', { cause })`. This catches it\n // by the cause's code when the wrapper message differs.\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 * A readable description of a thrown value: its `error` field (the provider body), else `message`.\n * Always a safe string.\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 * The `LLMErrorCode` for an HTTP status, shared by new and already normalized errors so they can't\n * drift.\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 * Some providers answer a non-2xx with no body, which SDKs render as `\"400 status code (no body)\"`.\n * Detail is read from the `error` and `message` fields directly, since `describeError` falls back\n * to echoing the whole value.\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 // Defensive: this function's only call site (below, in normalizeError)\n // reaches it via a status extracted by extractStatus, which itself\n // only returns a status for an object input, so `error` is always an\n // object here in practice. Kept for callers this function doesn't\n // control yet, and as a safe fallback if that invariant ever changes.\n /* v8 ignore next */\n if (error && typeof error === 'object') {\n const { error: errorField, message } = error as { error?: unknown; message?: unknown };\n\n // A non-empty `error` is the provider's body and counts as detail. `null`, `''` and `{}` are\n // placeholders and fall through.\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. Also unreachable in practice for\n // the same reason as the guard above (extractStatus already filters\n // non-object errors before this function is ever called).\n /* v8 ignore next */\n return true;\n}\n\n/**\n * Converts any thrown value into an `LLMError`. `attempts` goes through the constructor like every\n * other field.\n */\nexport function normalizeError(\n error: unknown,\n signal?: AbortSignal,\n attempts?: RetryAttempt[],\n maxRetryAfterMs?: number,\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 // Same cap a header parsed below gets, so a thrown LLMError can't\n // outwait the target's maxRetryAfterMs. `!== undefined` keeps a 0 cap.\n if (maxRetryAfterMs !== undefined && error.retryAfterMs !== undefined) {\n error.retryAfterMs = Math.min(error.retryAfterMs, maxRetryAfterMs);\n }\n\n return error;\n }\n\n const status = extractStatus(error);\n const retryAfterMs = extractRetryAfterMs(error, maxRetryAfterMs);\n\n if (status !== undefined) {\n const description = describeError(error);\n\n // The provider's description goes into the message itself, so it is there without debug\n // logging.\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","/** A memoized async call, returned by `createOnceAsync`. */\nexport interface OnceAsync<T> {\n /**\n * Calls the wrapped function on the first invocation; every later call\n * returns that same promise, whether it has settled yet or not.\n */\n call(): Promise<T>;\n /** Whether `call()` has been invoked yet. */\n wasCalled(): boolean;\n /**\n * The value `call()`'s promise resolved to, once it has. Stays\n * `undefined` before that settles, and if it rejects instead.\n */\n resolvedValue(): T | undefined;\n}\n\n/**\n * Runs `fn` at most once, reusing the first promise, and marks it handled so a discarded result\n * never becomes an unhandled rejection. A `wrap` may call `next()` more than once or not await it.\n */\nexport function createOnceAsync<T>(fn: () => Promise<T>): OnceAsync<T> {\n let called = false;\n let resolved: T | undefined;\n let promise: Promise<T> | undefined;\n\n function call(): Promise<T> {\n if (promise) return promise;\n\n called = true;\n\n // Not `async`: assigning `promise` here, synchronously, before any\n // `await`, is what makes two `call()`s issued back to back with no\n // `await` between them (e.g. `Promise.all([call(), call()])`) still\n // see the first call's promise already in place.\n promise = fn().then((value) => {\n resolved = value;\n return value;\n });\n\n // The promise returned below is untouched, so its own rejection\n // still propagates normally to anyone who does await it. This\n // separate handle only exists to swallow a rejection nobody else\n // ever observes.\n promise.catch(() => {});\n\n return promise;\n }\n\n return {\n call,\n wasCalled: () => called,\n resolvedValue: () => resolved,\n };\n}\n","import {\n LLMError,\n type WireCallRequest,\n type WireCallRequestPatch,\n} from '../../../../types/index.js';\n\nconst PATCH_FIELDS: (keyof WireCallRequestPatch)[] = [\n 'temperature',\n 'max_tokens',\n 'reasoning_effort',\n 'budget_tokens',\n 'tool_choice',\n 'messages',\n 'addMessages',\n 'tools',\n 'addTools',\n];\n\n/**\n * Merges one `transform` patch onto the request. `addMessages` and `addTools` append; everything\n * else overwrites. Returns the request and which fields changed, for the `'middleware'` event.\n */\nexport function mergePatch(\n request: WireCallRequest,\n patch: WireCallRequestPatch,\n): { request: WireCallRequest; patchedFields: string[] } {\n // `model` and `response_format` aren't on the patch type, but untyped code can still set them.\n // Copied through so the unchanged check can catch them.\n const rawPatch = patch as WireCallRequestPatch & {\n model?: unknown;\n response_format?: unknown;\n };\n\n const patchedFields: string[] = PATCH_FIELDS.filter((field) => patch[field] !== undefined);\n if (rawPatch.model !== undefined) patchedFields.push('model');\n if (rawPatch.response_format !== undefined) patchedFields.push('response_format');\n\n if (patchedFields.length === 0) {\n return { request, patchedFields: [] };\n }\n\n const next: WireCallRequest = { ...request };\n\n if (rawPatch.model !== undefined) next.model = rawPatch.model as string;\n if (rawPatch.response_format !== undefined) {\n next.response_format = rawPatch.response_format as WireCallRequest['response_format'];\n }\n\n if (patch.temperature !== undefined) next.temperature = patch.temperature;\n if (patch.max_tokens !== undefined) next.max_tokens = patch.max_tokens;\n if (patch.reasoning_effort !== undefined) next.reasoning_effort = patch.reasoning_effort;\n if (patch.budget_tokens !== undefined) next.budget_tokens = patch.budget_tokens;\n if (patch.tool_choice !== undefined) next.tool_choice = patch.tool_choice;\n\n if (patch.messages !== undefined) {\n next.messages = patch.messages;\n }\n if (patch.addMessages !== undefined && patch.addMessages.length > 0) {\n next.messages = [...next.messages, ...patch.addMessages];\n }\n\n if (patch.tools !== undefined) {\n next.tools = patch.tools;\n }\n if (patch.addTools !== undefined && patch.addTools.length > 0) {\n next.tools = [...(next.tools ?? []), ...patch.addTools];\n }\n\n return { request: next, patchedFields };\n}\n\n/** Throws `LLMError('invalid_params')` naming `label` if `merged.tools` has a duplicate name, run right after the addTools merge that could have introduced one. */\nexport function assertNoDuplicateTools(request: WireCallRequest, label: string): void {\n if (!request.tools) return;\n\n const seen = new Set<string>();\n const duplicates = new Set<string>();\n\n for (const tool of request.tools) {\n if (seen.has(tool.function.name)) duplicates.add(tool.function.name);\n seen.add(tool.function.name);\n }\n\n if (duplicates.size > 0) {\n throw new LLMError(\n `middleware \"${label}\" added tool(s) with 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/** Backstop for callers who bypass the type system: `transform` can't express a change to `model`/`response_format` in TypeScript, this catches it at runtime for `any`/plain-JS callers. */\nexport function assertModelAndResponseFormatUnchanged(\n before: WireCallRequest,\n after: WireCallRequest,\n label: string,\n): void {\n if (after.model !== before.model) {\n throw new LLMError(\n `middleware \"${label}\" changed \\`model\\` via transform, which isn't supported. Configure the target's model instead.`,\n 'invalid_params',\n );\n }\n\n if (JSON.stringify(after.response_format) !== JSON.stringify(before.response_format)) {\n throw new LLMError(\n `middleware \"${label}\" changed \\`response_format\\` via transform, which isn't supported.`,\n 'invalid_params',\n );\n }\n}\n","import {\n LLMError,\n type AttemptContext,\n type MiddlewareContext,\n type MiddlewareStateBag,\n type VernLLMEvent,\n type VernLLMMiddleware,\n type WireCallRequest,\n type WireCallRequestPatch,\n} from '../../../../types/index.js';\nimport { callScopeFor } from '../../../utils/callScope.utils.js';\nimport { logError, logHookError } from '../../../utils/logger.utils.js';\nimport { middlewareLabel } from '../../../utils/middlewareLabels.utils.js';\nimport { normalizeError } from '../errors.utils.js';\nimport { createOnceAsync } from '../once.utils.js';\nimport {\n assertModelAndResponseFormatUnchanged,\n assertNoDuplicateTools,\n mergePatch,\n} from './transformPatch.utils.js';\n\nimport type { Logger } from '../../../../logger.js';\n\n/** Default `middlewareTimeoutMs`, used both as `VernLLMOptions`'s own default and as the instance-level bound `CallExecutor` falls back to when none is passed in. Bounds `transform` and a function `enabled`; `wrap` itself is never bounded by this. */\nexport const DEFAULT_MIDDLEWARE_TIMEOUT_MS = 5000;\n\nexport {\n assertModelAndResponseFormatUnchanged,\n assertNoDuplicateTools,\n mergePatch,\n} from './transformPatch.utils.js';\n\n/** `middleware.name`, or its array position if unnamed. Used in log lines and the `'middleware'` event. */\nexport { middlewareLabel };\n\n/** Each middleware's `ctx.own`, per logical call (keyed by that call's state bag). */\nconst ownStores = new WeakMap<\n MiddlewareStateBag,\n Map<VernLLMMiddleware, Record<string, unknown>>\n>();\n\n/**\n * `ctx` with `own` set to this middleware's scratch object for the call, and `emit` bound to its\n * `label` so a custom event says who reported it. The same `own` object is returned for every\n * hook, so a value set in `wrap` is there in `transform`. Collected with the call's state bag.\n */\nexport function withOwn<C extends MiddlewareContext>(\n ctx: C,\n entry: VernLLMMiddleware,\n label: string,\n): C {\n let store = ownStores.get(ctx.state);\n\n if (!store) {\n store = new Map();\n ownStores.set(ctx.state, store);\n }\n\n let own = store.get(entry);\n\n if (!own) {\n own = {};\n store.set(entry, own);\n }\n\n return {\n ...ctx,\n own,\n // A bag made outside a call, like a manual `openCircuit()`'s, has no scope to report to.\n emit: (name, data) => callScopeFor(ctx.state)?.emitCustom(name, data, label, ctx),\n };\n}\n\n/**\n * Bounds `transform` and a function `enabled`, which take no signal, with a plain race. A hung\n * middleware keeps running but is no longer awaited. The rejection names `label` and uses code\n * `middleware_timeout`, which is never retried. `timeoutMs <= 0` means unbounded.\n */\nfunction raceTimeout<T>(fn: () => Promise<T>, timeoutMs: number, label: string): Promise<T> {\n if (timeoutMs <= 0) return fn();\n\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(\n new LLMError(`middleware \"${label}\" timed out after ${timeoutMs}ms`, 'timeout', {\n code: 'middleware_timeout',\n }),\n );\n }, timeoutMs);\n\n fn().then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (error) => {\n clearTimeout(timer);\n reject(error);\n },\n );\n });\n}\n\n/**\n * Resolves `enabled` for one call. A throwing or timed out predicate is logged and treated as\n * `false`.\n */\nexport async function resolveEnabled(\n middleware: VernLLMMiddleware,\n ctx: MiddlewareContext,\n label: string,\n middlewareTimeoutMs: number,\n logger: Logger,\n): Promise<boolean> {\n const { enabled } = middleware;\n\n if (enabled === undefined) return true;\n if (typeof enabled === 'boolean') return enabled;\n\n const timeoutMs = middleware.timeoutMs ?? middlewareTimeoutMs;\n\n try {\n return await raceTimeout(\n async () => enabled(withOwn(ctx, middleware, label)),\n timeoutMs,\n label,\n );\n } catch (error) {\n logError(\n logger,\n `[VernLLM] middleware \"${label}\".enabled threw or timed out, treating as disabled`,\n error,\n );\n return false;\n }\n}\n\n/** Everything `applyMiddlewareTransforms` needs beyond the request itself. */\nexport interface ApplyMiddlewareTransformsParams {\n request: WireCallRequest;\n requestId: string;\n attempt: number;\n signal: AbortSignal | undefined;\n state: MiddlewareStateBag;\n /** Already in `transform`/`onEvent` order. Order is decided once, at `VernLLM` construction time, by `buildMiddlewarePipeline`/`resolveMiddlewareOrder` (`resolveMiddlewareOrder.ts`); this function trusts the order it's handed and never re-sorts it. */\n middleware: VernLLMMiddleware[];\n middlewareTimeoutMs: number;\n logger: Logger;\n reportEvent: (event: VernLLMEvent) => void;\n buildContext: (\n attempt: number,\n signal: AbortSignal | undefined,\n state: MiddlewareStateBag,\n ) => AttemptContext;\n /**\n * Filled with every entry whose `enabled` resolved true for this\n * attempt, so `dispatch` reuses the same decision instead of asking a\n * predicate twice and possibly getting a different answer.\n */\n enabledEntries?: Set<VernLLMMiddleware>;\n}\n\n/**\n * Runs each applicable `transform` in order, merging each patch at once so later ones see it.\n * Reports a `'middleware'` event for each change and each skip.\n */\nexport async function applyMiddlewareTransforms(\n params: ApplyMiddlewareTransformsParams,\n): Promise<WireCallRequest> {\n const {\n request,\n requestId,\n attempt,\n signal,\n state,\n middleware,\n middlewareTimeoutMs,\n logger,\n reportEvent,\n buildContext,\n enabledEntries,\n } = params;\n\n if (middleware.length === 0) return request;\n\n const before = request;\n let current = request;\n\n for (const [index, middlewareEntry] of middleware.entries()) {\n const label = middlewareLabel(middlewareEntry, index);\n\n const ctx = buildContext(attempt, signal, state);\n\n const isEnabled = await resolveEnabled(\n middlewareEntry,\n ctx,\n label,\n middlewareTimeoutMs,\n logger,\n );\n\n if (!isEnabled) {\n if (middlewareEntry.enabled !== undefined) {\n emitEvent(\n { kind: 'middleware', requestId, middleware: label, hook: 'enabled_skip' },\n ctx,\n reportEvent,\n middleware,\n middlewareTimeoutMs,\n logger,\n );\n }\n continue;\n }\n\n enabledEntries?.add(middlewareEntry);\n\n if (!middlewareEntry.transform) continue;\n\n const patch = await runTransform(\n middlewareEntry,\n structuredClone(current),\n ctx,\n label,\n middlewareTimeoutMs,\n );\n const { request: merged, patchedFields } = mergePatch(current, patch);\n\n if (patchedFields.length > 0) {\n if (patch.tools !== undefined || patch.addTools?.length) {\n assertNoDuplicateTools(merged, label);\n }\n emitEvent(\n { kind: 'middleware', requestId, middleware: label, hook: 'transform', patchedFields },\n ctx,\n reportEvent,\n middleware,\n middlewareTimeoutMs,\n logger,\n );\n }\n\n current = merged;\n }\n\n assertModelAndResponseFormatUnchanged(before, current, 'chain');\n\n return current;\n}\n\n/**\n * Runs one `transform` within its timeout. A throw is normalized, and only an unrecognizable one\n * becomes `invalid_params` naming the middleware.\n */\nexport async function runTransform(\n middleware: VernLLMMiddleware,\n request: Readonly<WireCallRequest>,\n ctx: AttemptContext,\n label: string,\n middlewareTimeoutMs: number,\n): Promise<WireCallRequestPatch> {\n if (!middleware.transform) return {};\n\n const timeoutMs = middleware.timeoutMs ?? middlewareTimeoutMs;\n\n try {\n return await raceTimeout(\n async () => middleware.transform!(request, withOwn(ctx, middleware, label)),\n timeoutMs,\n label,\n );\n } catch (error) {\n throw reclassifyMiddlewareThrow(error, label, ctx.signal);\n }\n}\n\n/** One `dispatch` hook to run, with the label logs and errors use for it. */\nexport interface DispatchHook {\n entry: VernLLMMiddleware & { dispatch: NonNullable<VernLLMMiddleware['dispatch']> };\n label: string;\n}\n\n/** Everything `runDispatch` needs. */\nexport interface RunDispatchParams {\n /** The final request, after every `transform`. Each hook gets its own copy. */\n request: WireCallRequest;\n /** Outermost first. Already filtered to entries enabled for this attempt. */\n hooks: readonly DispatchHook[];\n ctx: AttemptContext;\n /** Sends the provider request. Rejects with an `LLMError`. */\n send: () => Promise<void>;\n logger: Logger;\n}\n\n/**\n * Runs `send` inside every `dispatch` hook, outermost first, settling with `send`'s outcome. Once\n * `next()` was called a hook throw is only logged; a hook that never called it fails the attempt.\n */\nexport async function runDispatch(params: RunDispatchParams): Promise<void> {\n const { request, hooks, ctx, send, logger } = params;\n\n if (hooks.length === 0) return send();\n\n const provider = createOnceAsync(send);\n\n const runLayer = async (index: number): Promise<void> => {\n if (index === hooks.length) return provider.call();\n\n const { entry, label } = hooks[index]!;\n const inner = createOnceAsync(() => runLayer(index + 1));\n let hookFailure: { error: unknown } | undefined;\n\n try {\n await entry.dispatch(structuredClone(request), inner.call, withOwn(ctx, entry, label));\n } catch (error) {\n hookFailure = { error };\n }\n\n if (!inner.wasCalled()) {\n if (hookFailure) throw reclassifyMiddlewareThrow(hookFailure.error, label, ctx.signal);\n\n throw new LLMError(\n `middleware \"${label}\".dispatch returned without calling next(), so no request was sent`,\n 'invalid_params',\n { code: 'middleware_threw' },\n );\n }\n\n try {\n await inner.call();\n } catch (error) {\n // A hook rethrowing the provider's own error is the normal path, not a hook bug.\n if (hookFailure && hookFailure.error !== error) {\n logHookError(logger, `middleware \"${label}\".dispatch`, hookFailure.error);\n }\n throw error;\n }\n\n if (hookFailure) logHookError(logger, `middleware \"${label}\".dispatch`, hookFailure.error);\n };\n\n return runLayer(0);\n}\n\n/**\n * A middleware throw keeps any classification `normalizeError` recognizes. Only an unrecognizable\n * one becomes `invalid_params`.\n */\nexport function reclassifyMiddlewareThrow(\n error: unknown,\n label: string,\n signal?: AbortSignal,\n): LLMError {\n const normalized = normalizeError(error, signal);\n\n if (normalized.type !== 'unknown') {\n return normalized;\n }\n\n return new LLMError(`middleware \"${label}\" threw: ${normalized.message}`, 'invalid_params', {\n code: 'middleware_threw',\n cause: error,\n });\n}\n\n/**\n * Reports `event` through the instance-level reporter, then fans it out to every applicable\n * middleware's own `onEvent`. Never throws or rejects.\n *\n * Handlers of entries with a static (or absent) `enabled` run synchronously, in registration\n * order, before this returns. Emit sites sit on the call path, so a token attribute or a span\n * ended off a `usage` event is visible before the code after `next()` resumes.\n */\nexport function emitEvent(\n event: VernLLMEvent,\n ctx: MiddlewareContext,\n reportEventInstance: (event: VernLLMEvent) => void,\n middleware: VernLLMMiddleware[],\n middlewareTimeoutMs: number,\n logger: Logger,\n): void {\n const stamped = withCallContext(event, ctx);\n\n reportEventInstance(stamped);\n\n if (middleware.length === 0) return;\n\n dispatchEventToMiddleware(middleware, stamped, ctx, middlewareTimeoutMs, logger);\n}\n\n/**\n * `event` with the call's `context` on it, and on its `usage` too, so `onUsage` and a cost\n * middleware see which tenant spent the tokens. Stamped here, the one place every event passes\n * through. An event with no call behind it, like a manual `openCircuit()`'s, carries none.\n */\nfunction withCallContext(event: VernLLMEvent, ctx: MiddlewareContext): VernLLMEvent {\n const { context } = ctx;\n\n if (context === undefined) return event;\n\n if (event.kind === 'usage' || event.kind === 'usage_failure') {\n return { ...event, context, usage: { ...event.usage, context } };\n }\n\n return { ...event, context };\n}\n\n/** Calls `onEvent`, logging a sync throw or a rejection instead of propagating either. */\nfunction invokeOnEvent(\n entry: VernLLMMiddleware,\n label: string,\n event: VernLLMEvent,\n ctx: MiddlewareContext,\n logger: Logger,\n): void {\n try {\n void Promise.resolve(entry.onEvent!(event, withOwn(ctx, entry, label))).catch(\n (error: unknown) => {\n logHookError(logger, `middleware \"${label}\".onEvent`, error);\n },\n );\n } catch (error) {\n logHookError(logger, `middleware \"${label}\".onEvent`, error);\n }\n}\n\n/**\n * Calls `onEvent` on every enabled middleware. A function `enabled` resolves per entry, so it never\n * holds back the others.\n */\nfunction dispatchEventToMiddleware(\n middleware: VernLLMMiddleware[],\n event: VernLLMEvent,\n ctx: MiddlewareContext,\n middlewareTimeoutMs: number,\n logger: Logger,\n): void {\n for (let index = 0; index < middleware.length; index++) {\n const entry = middleware[index]!;\n if (!entry.onEvent) continue;\n\n const label = middlewareLabel(entry, index);\n const { enabled } = entry;\n\n if (enabled === undefined || enabled === true) {\n invokeOnEvent(entry, label, event, ctx, logger);\n } else if (enabled === false) {\n continue;\n } else {\n void resolveEnabled(entry, ctx, label, middlewareTimeoutMs, logger).then((isEnabled) => {\n if (isEnabled) invokeOnEvent(entry, label, event, ctx, logger);\n });\n }\n }\n}\n\n/**\n * Every entry with a `dispatch`, in `order` (outermost first), labeled by its\n * `transformOrder` position so an unnamed entry reads the same as in\n * `registeredMiddlewareNames` whatever `position` it pins.\n */\nexport function buildDispatchHooks(\n transformOrder: VernLLMMiddleware[],\n order: VernLLMMiddleware[] = transformOrder,\n): readonly DispatchHook[] {\n const indexByEntry = new Map(transformOrder.map((entry, index) => [entry, index]));\n\n return order.flatMap((entry) =>\n entry.dispatch\n ? [\n {\n entry: entry as DispatchHook['entry'],\n label: middlewareLabel(entry, indexByEntry.get(entry)!),\n },\n ]\n : [],\n );\n}\n","import { normalizeError } from '../errors.utils.js';\n\nimport type { RateLimiterAdapter, RateLimitReason, WireRequest } from '../../../../rateLimit.js';\nimport type { LLMError } from '../../../../types/errors.js';\n\n/**\n * Errors thrown while acquiring limiter capacity. Tracked by identity\n * rather than a new error code, so the error's own `type`, `code`, and\n * retry behaviour stay exactly what the limiter produced.\n */\nconst limiterFailures = new WeakSet<LLMError>();\n\n/**\n * Whether `error` came from the limiter. Never counts toward the breaker, since no request was\n * made; a shared limiter losing its store would otherwise open a healthy provider's circuit.\n */\nexport function isLimiterFailure(error: LLMError): boolean {\n return limiterFailures.has(error);\n}\n\n/** Reports the `'rate_limited'` trace event; called only when `acquireRateLimit` actually waited. */\nexport type RateLimitedEventReporter = (waitedMs: number, reason: RateLimitReason) => void;\n\n/**\n * Acquires capacity for one attempt, reporting `'rate_limited'` when it had to wait. Returns `{}`\n * without a limiter. Run `release` in a `finally`. A limiter failure is normalized and marked so it\n * never counts toward the breaker.\n */\nexport async function acquireRateLimit(\n limiter: RateLimiterAdapter | undefined,\n request: WireRequest,\n signal: AbortSignal | undefined,\n onRateLimited: RateLimitedEventReporter,\n): Promise<{ release?: (actualTokens?: number, success?: boolean) => void }> {\n if (!limiter) return {};\n\n let acquired;\n\n try {\n acquired = await limiter.acquire(limiter.estimate(request), signal);\n } catch (error) {\n const normalized = normalizeError(error, signal);\n limiterFailures.add(normalized);\n throw normalized;\n }\n\n if (acquired.waitedMs > 0) {\n onRateLimited(acquired.waitedMs, acquired.reason ?? 'rpm');\n }\n\n return { release: acquired.release };\n}\n","import { toRequestSnapshot, type LLMRequestSnapshot } from '../../../../types/errors.js';\nimport { createMiddlewareStateBag } from '../../../../types/middleware.js';\nimport {\n applyMiddlewareTransforms,\n emitEvent,\n runDispatch,\n type DispatchHook,\n} from '../middleware/middleware.utils.js';\nimport { acquireRateLimit } from './rateLimitDispatch.utils.js';\n\nimport type { Logger } from '../../../../logger.js';\nimport type { RateLimiterAdapter } from '../../../../rateLimit.js';\nimport type {\n CallParams,\n MiddlewareStateBag,\n VernLLMEvent,\n VernLLMMiddleware,\n WireCallRequest,\n} from '../../../../types/index.js';\nimport type { BreakerGateway } from '../../circuitBreakerContext.js';\nimport type { RequestBuilder } from '../../requestBuilder.js';\n\n/** Receives a snapshot of the built request, just before dispatch. */\nexport type OnRequest = (snapshot: LLMRequestSnapshot) => void;\n\n/** Everything `prepareAttempt` needs beyond the per-attempt request params. */\nexport interface PrepareAttemptParams<T> {\n params: CallParams<T>;\n requestId: string;\n attempt: number;\n onRequest: OnRequest | undefined;\n middlewareState: MiddlewareStateBag | undefined;\n gateway: BreakerGateway;\n requestBuilder: RequestBuilder;\n providerName: string;\n limiter: RateLimiterAdapter | undefined;\n middleware: VernLLMMiddleware[];\n /** Every entry with a `dispatch`, outermost first. Filtered per attempt by `enabled`. */\n dispatchHooks: readonly DispatchHook[];\n middlewareTimeoutMs: number;\n logger: Logger;\n reportEvent: (event: VernLLMEvent) => void;\n}\n\n/** Everything one dispatched attempt needs before it proceeds, shared by the non-streaming and streaming paths. */\nexport interface PreparedAttempt {\n request: WireCallRequest;\n model: string;\n useJson: boolean;\n state: MiddlewareStateBag;\n /**\n * Present unless no `limiter` was configured. Must run in a `finally`\n * block so a slot is never leaked on a failed attempt (see `acquireRateLimit`).\n */\n release?: (actualTokens?: number, success?: boolean) => void;\n /**\n * Runs `send`, the provider request, inside this attempt's enabled\n * `dispatch` hooks. Settles with `send`'s own outcome, see `runDispatch`.\n */\n dispatch: (send: () => Promise<void>) => Promise<void>;\n}\n\n/**\n * Shared start of both attempt paths: build the request, run `transform`s, snapshot it through\n * `onRequest`, and acquire rate limit capacity.\n */\nexport async function prepareAttempt<T>(p: PrepareAttemptParams<T>): Promise<PreparedAttempt> {\n const {\n params,\n requestId,\n attempt,\n onRequest,\n middlewareState,\n gateway,\n requestBuilder,\n providerName,\n limiter,\n middleware,\n dispatchHooks,\n middlewareTimeoutMs,\n logger,\n reportEvent,\n } = p;\n\n const state = middlewareState ?? createMiddlewareStateBag();\n const built = requestBuilder.build(params);\n const { useJson, model } = built;\n const enabledEntries = new Set<VernLLMMiddleware>();\n\n const request = await applyMiddlewareTransforms({\n request: built.request,\n requestId,\n attempt,\n signal: params.signal,\n state,\n middleware,\n middlewareTimeoutMs,\n logger,\n reportEvent,\n buildContext: (attempt, signal, state) => gateway.buildAttemptContext(attempt, signal, state),\n enabledEntries,\n });\n\n onRequest?.(toRequestSnapshot(providerName, model, request, undefined, Date.now()));\n\n const { release } = await acquireRateLimit(\n limiter,\n request,\n params.signal,\n (waitedMs, reason) => {\n emitEvent(\n {\n kind: 'rate_limited',\n requestId,\n provider: providerName,\n model,\n waitedMs,\n reason,\n },\n gateway.buildAttemptContext(attempt, params.signal, state),\n reportEvent,\n middleware,\n middlewareTimeoutMs,\n logger,\n );\n },\n );\n\n const hooks = dispatchHooks.filter((hook) => enabledEntries.has(hook.entry));\n\n const dispatch = (send: () => Promise<void>): Promise<void> =>\n runDispatch({\n request,\n hooks,\n ctx: gateway.buildAttemptContext(attempt, params.signal, state),\n send,\n logger,\n });\n\n return { request, model, useJson, state, release, dispatch };\n}\n","import { prepareAttempt, type OnRequest } from '../utils/dispatch/attemptDispatch.utils.js';\nimport { isLimiterFailure } from '../utils/dispatch/rateLimitDispatch.utils.js';\n\nimport type { Logger } from '../../../logger.js';\nimport type { RateLimiterAdapter } from '../../../rateLimit.js';\nimport type { LLMError } from '../../../types/errors.js';\nimport type {\n CallParams,\n DetectSoftFailure,\n LLMClient,\n MiddlewareStateBag,\n VernLLMEvent,\n VernLLMMiddleware,\n} from '../../../types/index.js';\nimport type { BreakerGateway } from '../circuitBreakerContext.js';\nimport type { RequestBuilder } from '../requestBuilder.js';\nimport type { FinalizeResponseDeps } from '../responseFinalizer.js';\nimport type { UsageReporter } from '../usageReporter.js';\nimport type { DispatchHook } from '../utils/middleware/middleware.utils.js';\n\n/** One target's fixed settings for a single attempt, built once per `CallExecutor`. */\nexport interface AttemptEnvironment {\n client: LLMClient;\n providerName: string;\n isFallback: boolean;\n timeoutMs: number;\n chunkIdleTimeoutMs: number;\n readerStallTimeoutMs?: number;\n maxRetryAfterMs: number;\n parseJson: (content: string) => unknown;\n logger: Logger;\n redact?: (text: string) => string;\n usageReporter: UsageReporter;\n reportEvent: (event: VernLLMEvent) => void;\n limiter?: RateLimiterAdapter;\n requestBuilder: RequestBuilder;\n middleware: VernLLMMiddleware[];\n dispatchHooks: readonly DispatchHook[];\n middlewareTimeoutMs: number;\n detectSoftFailure?: DetectSoftFailure;\n}\n\n/** What changes from one attempt to the next. */\nexport interface AttemptArgs<T> {\n params: CallParams<T>;\n requestId: string;\n attempt: number;\n onRequest: OnRequest | undefined;\n middlewareState: MiddlewareStateBag | undefined;\n gateway: BreakerGateway;\n}\n\nexport function prepareTargetAttempt<T>(env: AttemptEnvironment, args: AttemptArgs<T>) {\n return prepareAttempt({\n ...args,\n requestBuilder: env.requestBuilder,\n providerName: env.providerName,\n limiter: env.limiter,\n middleware: env.middleware,\n dispatchHooks: env.dispatchHooks,\n middlewareTimeoutMs: env.middlewareTimeoutMs,\n logger: env.logger,\n reportEvent: env.reportEvent,\n });\n}\n\nexport function redactText(env: AttemptEnvironment, text: string): string {\n return env.redact ? env.redact(text) : text;\n}\n\nexport function finalizeDependencies(\n env: AttemptEnvironment,\n gateway: BreakerGateway,\n model: string,\n): FinalizeResponseDeps {\n return {\n gateway,\n usageReporter: env.usageReporter,\n logger: env.logger,\n redactText: (text) => redactText(env, text),\n parseJson: env.parseJson,\n detectSoftFailure: env.detectSoftFailure,\n providerName: env.providerName,\n isFallback: env.isFallback,\n model,\n };\n}\n\n/**\n * Whether a failed attempt counts toward the breaker. Response defects, caller\n * mistakes, quota rejections and anything the limiter threw say nothing about\n * provider health, so they are excluded.\n */\nexport function countsTowardBreaker(error: LLMError): boolean {\n return error.countsTowardBreaker && !isLimiterFailure(error);\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 { parseWireToolCalls } from '../wire.utils.js';\n\nimport type { Logger } from '../../../../logger.js';\nimport type {\n CallParams,\n CallWithToolsResult,\n ToolIssue,\n WireToolCall,\n} from '../../../../types/index.js';\n\n/** Parses response content as JSON and validates it against `schema` when supplied. */\nexport function parseAndValidate<T>(\n content: string,\n schema: CallParams<T>['schema'] | undefined,\n parseJson: (content: string) => unknown,\n): T {\n let parsed: unknown;\n\n try {\n parsed = 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 * Checks each `ToolCall` against the offered tools, then runs each `argumentsSchema`. Unknown names\n * and duplicate ids are collected into one `validation` error with every issue, since retrying\n * can't fix them. A schema failure keeps its own single error. Returns the calls with `arguments`\n * replaced by the schema output; the input is left untouched.\n */\nexport function validateToolCallArguments<\n Call extends { id: string; name: string; arguments: unknown },\n>(toolCalls: Call[], tools: NonNullable<CallParams<unknown>['tools']>): Call[] {\n const known = new Map(tools.map((tool) => [tool.name, tool]));\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((issue) => issue.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 return toolCalls.map((call) => {\n const definition = known.get(call.name);\n\n if (!definition?.argumentsSchema) return call;\n\n const result = definition.argumentsSchema.safeParse(call.arguments);\n\n if (!result.success) {\n throw new LLMError(`Arguments for tool call \"${call.name}\" failed validation`, 'validation', {\n issues: result.error,\n });\n }\n\n return { ...call, arguments: result.data };\n });\n}\n\n/** Everything `shapeResponse` needs beyond the raw response itself. */\nexport interface ShapeResponseParams<T> {\n rawContent: string | null | undefined;\n wireToolCalls: WireToolCall[] | undefined;\n params: CallParams<T>;\n useJson: boolean;\n parseJson: (content: string) => unknown;\n requestId: string;\n logger: Pick<Logger, 'debug'>;\n redactText: (text: string) => string;\n}\n\n/**\n * Shapes a complete response into `T` or a `CallWithToolsResult<T>`, for streaming too once the\n * stream is buffered. Throws on an empty response, a tool contract violation, or a JSON or schema\n * failure. Reporting happens a layer up.\n */\nexport function shapeResponse<T>(params: ShapeResponseParams<T>): T | CallWithToolsResult<T> {\n const {\n rawContent,\n wireToolCalls,\n params: callParams,\n useJson,\n parseJson,\n requestId,\n logger,\n redactText,\n } = params;\n\n // `.trim()` runs unguarded: a malformed response shape (e.g. a\n // non-string `content`) throws here, same as every other post-response\n // failure, and is normalized by the caller.\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 // wireToolCalls is guaranteed to have at least one entry whenever content\n // is falsy: the throw above only lets us reach this line when content ||\n // wireToolCalls?.length is true (De Morgan's law on that guard), so if\n // content is falsy, wireToolCalls?.length must be truthy.\n const debugOutput = redactText(content ?? `[${wireToolCalls!.length} tool call(s)]`);\n const truncated = debugOutput.length > 800;\n\n logger.debug(\n `[VernLLM:${requestId}] output:\\n` +\n debugOutput.slice(0, 800) +\n (truncated ? `... (truncated, ${debugOutput.length} chars total)` : ''),\n );\n\n if (wireToolCalls?.length) {\n if (!callParams.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 (callParams.toolChoice === 'none') {\n // Returning tool calls under `toolChoice: 'none'` would break the `ContentResult<T>` type\n // guarantee. The same request repeats it, so it is a non-retryable contract violation.\n throw new LLMError(\"Provider returned tool_calls despite toolChoice: 'none'.\", 'validation', {\n code: 'tool_choice_none_violated',\n });\n }\n\n const toolCalls = validateToolCallArguments(\n parseWireToolCalls(wireToolCalls),\n callParams.tools,\n );\n\n return { type: 'tool_calls', toolCalls, ...(content ? { content } : {}) };\n }\n\n // No tool_calls here, so content must be present: the empty-response\n // guard above throws unless content is truthy when wireToolCalls is\n // empty, so the `?? ''` fallback here is defensive only.\n /* v8 ignore next */\n const textContent = content ?? '';\n\n if (!useJson) {\n return callParams.tools ? { type: 'content', content: textContent as T } : (textContent as T);\n }\n\n const result = parseAndValidate<T>(textContent, callParams.schema, parseJson);\n\n return callParams.tools ? { type: 'content', content: result } : result;\n}\n","import { LLMError } from '../../types/errors.js';\nimport { isToolCallResult } from '../../types/tools.js';\nimport { normalizeError } from './utils/errors.utils.js';\nimport { shapeResponse } from './utils/response/responseShape.utils.js';\n\nimport type { Logger } from '../../logger.js';\nimport type {\n CallParams,\n CallWithToolsResult,\n DetectSoftFailure,\n MiddlewareStateBag,\n ThinkingBlock,\n TokenUsage,\n WireToolCall,\n} from '../../types/index.js';\nimport type { BreakerGateway } from './circuitBreakerContext.js';\nimport type { UsageReporter } from './usageReporter.js';\n\n/** Everything `finalizeResponse` needs beyond the raw response and outcome trackers. */\nexport interface FinalizeResponseDeps {\n gateway: BreakerGateway;\n usageReporter: UsageReporter;\n logger: Pick<Logger, 'debug' | 'warn'>;\n redactText: (text: string) => string;\n parseJson: (content: string) => unknown;\n /** See `VernLLMOptions.detectSoftFailure`. Absent when no hook was configured. */\n detectSoftFailure?: DetectSoftFailure;\n providerName: string;\n isFallback: boolean;\n /** The resolved model this attempt actually targeted. */\n model: string;\n}\n\n/**\n * Shapes a complete response and reports the outcome: breaker and usage success when clean, a usage\n * failure otherwise. Breaker failures are decided a layer up, once retries run out.\n * `detectSoftFailure` runs inside the same `try`, so a soft failure takes the normal failure path.\n * With `truncated` set, a parse failure becomes the retryable `response_truncated`. `thinking` is\n * kept only on a tool call result, the one place it must go back.\n */\nexport function finalizeResponse<T>(\n rawContent: string | null | undefined,\n wireToolCalls: WireToolCall[] | undefined,\n params: CallParams<T>,\n useJson: boolean,\n usage: TokenUsage | undefined,\n requestId: string,\n attempt: number,\n state: MiddlewareStateBag,\n deps: FinalizeResponseDeps,\n truncated = false,\n thinking?: ThinkingBlock[],\n): T | CallWithToolsResult<T> {\n const { gateway, usageReporter, logger, redactText, parseJson, detectSoftFailure } = deps;\n\n try {\n const result = withThinking(\n shapeResponse<T>({\n rawContent,\n wireToolCalls,\n params,\n useJson,\n parseJson,\n requestId,\n logger,\n redactText,\n }),\n thinking,\n );\n\n const softFailureCode = detectSoftFailureSafely(\n detectSoftFailure,\n result,\n {\n requestId,\n model: deps.model,\n providerName: deps.providerName,\n isFallback: deps.isFallback,\n attempt: attempt + 1,\n usage,\n },\n logger,\n );\n\n if (softFailureCode !== undefined) {\n // `'api'`, not `'validation'`, which is never retried whatever the code. The returned code\n // alone decides retry and breaker counting.\n throw new LLMError('Soft failure detected', 'api', { code: softFailureCode });\n }\n\n gateway.recordSuccess(attempt, params.signal, state);\n usageReporter.reportSuccess(usage, gateway.buildAttemptContext(attempt, params.signal, state));\n\n return result;\n } catch (error) {\n // Normalized first so `onUsageFailure` gets an `LLMError`, including for aborts. A soft failure\n // is already one and is reported once, here.\n const normalized = asTruncationError(normalizeError(error, params.signal), truncated);\n\n if (usage && normalized.type !== 'aborted') {\n usageReporter.reportFailure(\n usage,\n normalized,\n attempt,\n gateway.buildAttemptContext(attempt, params.signal, state),\n );\n }\n\n throw normalized;\n }\n}\n\n/** Adds `thinking` to a tool call result. Any other result is returned as is. */\nfunction withThinking<T>(\n result: T | CallWithToolsResult<T>,\n thinking: ThinkingBlock[] | undefined,\n): T | CallWithToolsResult<T> {\n if (!thinking?.length || !isToolCallResult(result)) return result;\n\n return { ...result, thinking };\n}\n\n/**\n * Replaces a parse failure on output that was cut off at `max_tokens`\n * with a `response_truncated` error, keeping the original as `cause`.\n * Anything else, or a response that wasn't cut off, passes through.\n */\nfunction asTruncationError(error: LLMError, truncated: boolean): LLMError {\n if (!truncated || error.type !== 'parse') return error;\n\n return new LLMError(\n `Response was cut off at max_tokens before it could be parsed: ${error.message}`,\n 'parse',\n { code: 'response_truncated', cause: error },\n );\n}\n\n/**\n * Runs `detectSoftFailure` and returns its code. A throwing hook is logged and ignored, so it can't\n * fail every call.\n */\nfunction detectSoftFailureSafely<T>(\n detectSoftFailure: DetectSoftFailure | undefined,\n result: T | CallWithToolsResult<T>,\n meta: Parameters<DetectSoftFailure>[1],\n logger: Pick<Logger, 'warn'>,\n) {\n if (!detectSoftFailure) return undefined;\n\n try {\n return detectSoftFailure(result, meta);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const stack = error instanceof Error && error.stack ? `\\n${error.stack}` : '';\n logger.warn(\n `[VernLLM] detectSoftFailure threw and was ignored, treated as no soft failure: ${message}${stack}`,\n );\n return undefined;\n }\n}\n","import { redactResponseBody } from '../../utils/errors/responseBody.utils.js';\nimport { extractStatus, normalizeError } from '../utils/errors.utils.js';\n\nimport type { RateLimiterAdapter } from '../../../rateLimit.js';\nimport type { AttemptEnvironment } from './attemptEnvironment.js';\n\n/** Tells the limiter about a provider 429 so AIMD can shrink. */\nexport function reactToRateLimitError(\n limiter: RateLimiterAdapter | undefined,\n error: unknown,\n): void {\n if (!limiter) return;\n if (extractStatus(error) !== 429) return;\n limiter.signalRateLimit();\n}\n\n/**\n * Runs `send` inside the attempt's `dispatch` hooks. A provider failure is\n * redacted and reported to the limiter, and hooks see it normalized. The raw\n * error is rethrown afterwards, not the `LLMError` hooks saw, since retry\n * timing reads `Retry-After` off it. Anything else, such as a hook that never\n * sent the request, is thrown as is.\n */\nexport async function dispatchToProvider(\n env: AttemptEnvironment,\n dispatch: (send: () => Promise<void>) => Promise<void>,\n signal: AbortSignal | undefined,\n send: () => Promise<void>,\n): Promise<void> {\n let providerFailure: { error: unknown } | undefined;\n\n try {\n await dispatch(async () => {\n try {\n await send();\n } catch (error) {\n if (env.redact) redactResponseBody(error, env.redact);\n reactToRateLimitError(env.limiter, error);\n providerFailure = { error };\n throw normalizeError(error, signal, undefined, env.maxRetryAfterMs);\n }\n });\n } catch (error) {\n throw providerFailure ? providerFailure.error : error;\n }\n}\n","import { readRateLimitHint } from '../../utils/rate-limit/rateLimitHint.utils.js';\nimport { finalizeResponse } from '../responseFinalizer.js';\nimport { withTimeout } from '../utils/retry/retry.utils.js';\nimport {\n finalizeDependencies,\n prepareTargetAttempt,\n type AttemptArgs,\n type AttemptEnvironment,\n} from './attemptEnvironment.js';\nimport { dispatchToProvider } from './providerDispatch.js';\n\nimport type { CallWithToolsResult, LLMClient } from '../../../types/index.js';\n\n/**\n * One non-streaming attempt: acquire, dispatch with a timeout, then shape the\n * response. Capacity is acquired per attempt, since a retry is a real request.\n */\nexport async function executeCall<T>(\n env: AttemptEnvironment,\n args: AttemptArgs<T>,\n): Promise<T | CallWithToolsResult<T>> {\n const { params, requestId, attempt, gateway } = args;\n const {\n request,\n model,\n useJson,\n state,\n release: acquiredRelease,\n dispatch,\n } = await prepareTargetAttempt(env, args);\n let release = acquiredRelease;\n\n try {\n let response!: Awaited<ReturnType<LLMClient['chat']['completions']['create']>>;\n\n await dispatchToProvider(env, dispatch, params.signal, async () => {\n response = await withTimeout(\n (attemptSignal) => env.client.chat.completions.create(request, { signal: attemptSignal }),\n env.timeoutMs,\n params.signal,\n );\n });\n\n // AIMD's proactive path.\n env.limiter?.reactToRateLimitHint(readRateLimitHint(response));\n\n // Taken before anything else touches the response, so a later failure\n // still reports usage.\n const usage = env.usageReporter.extract(response, requestId, model);\n const actualTokens = env.usageReporter.actualTokensFor(usage);\n\n // Raw on purpose: extraction happens inside `finalizeResponse`'s\n // try/catch, so a malformed response is still normalized.\n const choice = response.choices?.[0];\n const rawContent = choice?.message?.content;\n const wireToolCalls = choice?.message?.tool_calls;\n const truncated = choice?.finish_reason === 'length';\n const thinking = choice?.message?.thinking;\n\n let finalized: T | CallWithToolsResult<T>;\n\n try {\n finalized = finalizeResponse(\n rawContent,\n wireToolCalls,\n params,\n useJson,\n usage,\n requestId,\n attempt,\n state,\n finalizeDependencies(env, gateway, model),\n truncated,\n thinking,\n );\n } catch (error) {\n // Reconcile usage and free the slot, but never grow AIMD for a\n // response VernLLM itself rejected.\n release?.(actualTokens);\n release = undefined;\n throw error;\n }\n\n release?.(actualTokens, true);\n release = undefined;\n\n return finalized;\n } finally {\n // Only reached with a live release when dispatch itself threw.\n release?.();\n }\n}\n","import { clampTimeoutMs, resolveActiveTimeoutMs } from '../retry/retry.utils.js';\n\nimport type { Logger } from '../../../../logger.js';\n\n/** Everything `createBackpressureChannel` needs. Generic over the item type: no knowledge of `StreamChunk`. */\nexport interface BackpressureChannelOptions {\n /**\n * Cap on buffered items while nothing is pulling. The buffer grows to twice this before trimming\n * in one batch, keeping eviction cheap per push.\n */\n capacity: number;\n logger: Pick<Logger, 'warn'>;\n /**\n * Folded into the eviction warning so different channels are\n * distinguishable in logs, e.g. `'stream chunk'`.\n */\n label: string;\n /**\n * How long a reader may hold the producer back on a full buffer before\n * it is detached. `0`, negative, NaN, or `Infinity` waits forever.\n */\n stallTimeoutMs?: number;\n /** What a detached reader's next pull rejects with. Required for `stallTimeoutMs` to apply. */\n stallError?: () => unknown;\n}\n\n/** A push/pull async channel with a bounded buffer, returned by `createBackpressureChannel`. */\nexport interface BackpressureChannel<T> {\n /**\n * Delivers `value` to a waiting puller, or buffers it. Returns a promise\n * when a consumer is reading and the buffer is full; the producer should\n * await it before pushing more. Returns `undefined` otherwise.\n */\n push(value: T): Promise<void> | undefined;\n /** Marks the channel done. Every future pull resolves `{ done: true }`. */\n finish(): void;\n /** Marks the channel failed. Every future pull rejects with `error`. */\n fail(error: unknown): void;\n /** Consumed by callers to pull values as they arrive. */\n iterable: AsyncIterable<T>;\n}\n\n/**\n * A bounded push channel whose producer runs whether or not anyone reads. Buffer size caps memory,\n * since the producer can outrace the first read. Once a reader starts, a full buffer holds the\n * producer back instead of evicting, so a slow reader never loses items; eviction only applies\n * while no reader is active.\n */\nexport function createBackpressureChannel<T>(\n options: BackpressureChannelOptions,\n): BackpressureChannel<T> {\n const { capacity, logger, label, stallError } = options;\n const stallTimeoutMs = stallError ? resolveActiveTimeoutMs(options.stallTimeoutMs) : undefined;\n\n const buffered: T[] = [];\n // `owner` ties a pull to the iterator that made it, so one reader's\n // `return()` only settles its own pull.\n const pending: Array<{\n owner: object;\n resolve: (result: IteratorResult<T>) => void;\n reject: (error: unknown) => void;\n }> = [];\n let done = false;\n let failed = false;\n let failure: unknown;\n let hasLoggedEviction = false;\n // Iterators that have pulled and not returned. A full buffer only holds\n // the producer back while there is one; otherwise the eviction path\n // below applies, so a reader that left can't stall the producer.\n let activeReaders = 0;\n let spaceWaiters: Array<() => void> = [];\n // Set once a reader held the producer back past `stallTimeoutMs`. From\n // then on every pull rejects with it and nothing is buffered, so the\n // producer runs to the end on its own instead of waiting forever.\n let stall: { error: unknown } | undefined;\n let stallTimer: ReturnType<typeof setTimeout> | undefined;\n\n function detachStalledReaders(): void {\n stallTimer = undefined;\n stall = { error: stallError!() };\n logger.warn(\n `[VernLLM] ${label} reader held a full buffer for ${stallTimeoutMs}ms; detaching it so the stream can finish.`,\n );\n buffered.length = 0;\n releaseProducer();\n }\n\n function releaseProducer(): void {\n clearTimeout(stallTimer);\n stallTimer = undefined;\n\n const waiters = spaceWaiters;\n\n spaceWaiters = [];\n for (const resolve of waiters) resolve();\n }\n\n function push(value: T): Promise<void> | undefined {\n if (stall) return undefined;\n\n const waiter = pending.shift();\n\n if (waiter) {\n waiter.resolve({ done: false, value });\n return undefined;\n }\n\n buffered.push(value);\n\n if (activeReaders > 0) {\n if (buffered.length < capacity) return undefined;\n\n if (stallTimeoutMs !== undefined && stallTimer === undefined) {\n stallTimer = setTimeout(detachStalledReaders, clampTimeoutMs(stallTimeoutMs));\n }\n\n return new Promise((resolve) => {\n spaceWaiters.push(resolve);\n });\n }\n\n if (buffered.length > capacity * 2) {\n // Nothing else surfaces this: without a log, a caller that never\n // read (or fell behind on) `iterable` has no way to tell eviction,\n // not a producer bug, is why items are missing. Logged once, not\n // on every crossing, so an ignored high-volume channel doesn't\n // spam dozens of near-identical lines.\n if (!hasLoggedEviction) {\n hasLoggedEviction = true;\n logger.warn(\n `[VernLLM] ${label} buffer exceeded cap (${capacity}), evicting ` +\n `${buffered.length - capacity} oldest item(s); buffered=${buffered.length}. ` +\n 'The iterable was never read (or fell far behind) for this channel.',\n );\n }\n\n // Trimmed in one batch once the buffer reaches twice the cap. A `shift()` per push is O(n)\n // every time and stalled for seconds in benchmarks; one `splice` per `capacity` pushes keeps\n // the cost O(1) on average.\n buffered.splice(0, buffered.length - capacity);\n }\n }\n\n function finish(): void {\n done = true;\n releaseProducer();\n\n for (const waiter of pending.splice(0)) {\n waiter.resolve({ done: true, value: undefined });\n }\n }\n\n function fail(error: unknown): void {\n done = true;\n failed = true;\n failure = error;\n releaseProducer();\n\n for (const waiter of pending.splice(0)) {\n waiter.reject(error);\n }\n }\n\n const iterable: AsyncIterable<T> = {\n [Symbol.asyncIterator]() {\n const owner = {};\n let active = false;\n\n return {\n next(): Promise<IteratorResult<T>> {\n if (!active) {\n active = true;\n activeReaders++;\n }\n\n if (stall) return Promise.reject(stall.error);\n\n if (buffered.length) {\n const value = buffered.shift() as T;\n\n if (buffered.length < capacity) releaseProducer();\n\n return Promise.resolve({ done: false, value });\n }\n\n if (done) {\n return failed\n ? Promise.reject(failure)\n : Promise.resolve({ done: true, value: undefined });\n }\n\n return new Promise((resolve, reject) => {\n pending.push({ owner, resolve, reject });\n });\n },\n // Detaches this reader without stopping the producer. Cancelling\n // on a `break` happens a layer up (see `onEarlyExit`), since only\n // the caller knows whether anyone else still needs the stream.\n return(): Promise<IteratorResult<T>> {\n if (active) {\n active = false;\n activeReaders--;\n }\n\n for (let i = pending.length - 1; i >= 0; i--) {\n if (pending[i]!.owner !== owner) continue;\n pending.splice(i, 1)[0]!.resolve({ done: true, value: undefined });\n }\n\n if (activeReaders === 0) releaseProducer();\n\n return Promise.resolve({ done: true, value: undefined });\n },\n };\n },\n };\n\n return { push, finish, fail, iterable };\n}\n","import { LLMError } from '../../../../types/errors.js';\n\nimport type { StreamChunk, WireToolCall } 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/** One incoming tool call delta, matching `WireStreamChunk`'s `tool_call_delta` variant. */\nexport interface ToolCallDelta {\n index: number;\n id?: string;\n name?: string;\n argumentsDelta?: string;\n complete?: boolean;\n}\n\n/** Accumulates streamed tool call deltas, returned by `createToolCallAccumulator`. */\nexport interface ToolCallAccumulator {\n /**\n * Folds one delta in and returns the matching `StreamChunk` to push\n * onward. Throws `LLMError('validation')` if the delta would push the\n * accumulator past its call count or argument length limit.\n */\n apply(delta: ToolCallDelta): StreamChunk;\n /** Shapes everything accumulated so far into wire tool calls, sorted by index. Undefined if nothing arrived. */\n toWireToolCalls(): WireToolCall[] | undefined;\n}\n\n/**\n * Tracks tool call deltas by index as they stream in, merging each\n * delta's `id`/`name`/`argumentsDelta` into a running entry. Pulled out\n * of `buildStreamResult` since it's self contained state with no\n * dependency on the iterator, the chunk buffer, or the final result\n * promise.\n */\nexport function createToolCallAccumulator(): ToolCallAccumulator {\n const entries = new Map<number, { id?: string; name?: string; args: string }>();\n\n function apply(delta: ToolCallDelta): StreamChunk {\n let entry = entries.get(delta.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 (entries.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 = delta.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 ??= delta.id;\n entry.name ??= delta.name;\n entry.args += argumentsDelta;\n entries.set(delta.index, entry);\n\n return {\n type: 'tool_call_delta',\n index: delta.index,\n id: delta.id,\n name: delta.name,\n argsDelta: delta.argumentsDelta,\n complete: delta.complete,\n };\n }\n\n function toWireToolCalls(): WireToolCall[] | undefined {\n if (!entries.size) return undefined;\n\n return [...entries.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 }\n\n return { apply, toWireToolCalls };\n}\n","import { toTokenUsage, type TokenUsageMeta } from '../response/usage.utils.js';\nimport { createToolCallAccumulator } from './toolCallAccumulator.utils.js';\n\nimport type {\n StreamChunk,\n ThinkingBlock,\n TokenUsage,\n WireStreamChunk,\n WireToolCall,\n} from '../../../../types/index.js';\nimport type { ProviderRateLimitHint } from '../../../utils/rate-limit/rateLimitHint.utils.js';\n\nexport interface StreamAccumulation {\n /** Folds one wire chunk in. Returns the push's space promise when a chunk reached the caller. */\n apply: (chunk: WireStreamChunk) => Promise<void> | undefined;\n readonly usage: TokenUsage | undefined;\n /** What `finalize` receives once the stream ends. */\n result: () => {\n text: string;\n wireToolCalls: WireToolCall[] | undefined;\n usage: TokenUsage | undefined;\n thinking: ThinkingBlock[] | undefined;\n };\n}\n\n/**\n * Collects text, tool calls, usage and thinking from wire chunks and forwards\n * caller visible chunks through `push`. Pings and hints push nothing, and\n * thinking stays in the result only.\n */\nexport function createStreamAccumulation(\n usageMeta: TokenUsageMeta,\n push: (chunk: StreamChunk) => Promise<void> | undefined,\n onRateLimitHint?: (hint: ProviderRateLimitHint) => void,\n): StreamAccumulation {\n const toolCalls = createToolCallAccumulator();\n const thinking: ThinkingBlock[] = [];\n let text = '';\n let usage: TokenUsage | undefined;\n\n return {\n apply(chunk) {\n switch (chunk.type) {\n case 'rate_limit_hint':\n // Fired right away, not deferred to the end.\n onRateLimitHint?.(chunk.hint);\n return undefined;\n case 'text-delta':\n text += chunk.delta;\n return push({ type: 'text-delta', delta: chunk.delta });\n case 'tool_call_delta':\n return push(toolCalls.apply(chunk));\n case 'thinking_block':\n thinking.push(chunk.block);\n return undefined;\n case 'usage':\n usage = toTokenUsage(chunk.usage, usageMeta);\n return push({ type: 'usage', usage });\n default:\n // A ping only resets the idle clock on the next read.\n return undefined;\n }\n },\n get usage() {\n return usage;\n },\n result: () => ({\n text,\n wireToolCalls: toolCalls.toWireToolCalls(),\n usage,\n thinking: thinking.length ? thinking : undefined,\n }),\n };\n}\n","import { LLMError } from '../../types/errors.js';\nimport { createDeferred } from '../utils/deferred.utils.js';\nimport { normalizeError } from './utils/errors.utils.js';\nimport { withChunkIdleTimeout } from './utils/retry/retry.utils.js';\nimport { createBackpressureChannel } from './utils/stream/chunkBuffer.utils.js';\nimport { createStreamAccumulation } from './utils/stream/streamAccumulation.utils.js';\n\nimport type { Logger } from '../../logger.js';\nimport type {\n CallWithToolsResult,\n StreamChunk,\n ThinkingBlock,\n TokenUsage,\n WireStreamChunk,\n WireToolCall,\n} from '../../types/index.js';\nimport type { ProviderRateLimitHint } from '../utils/rate-limit/rateLimitHint.utils.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 /** See `VernLLMOptions.readerStallTimeoutMs`. Off when omitted. */\n readerStallTimeoutMs?: number;\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 /** The target's `maxRetryAfterMs`, forwarded to `normalizeError` so a mid-stream failure gets the same retry cap. */\n maxRetryAfterMs?: number;\n /**\n * Fires once when the transport loop ends cleanly, before `finalize`. Success itself is decided\n * by `finalize`, which can still reject the response.\n */\n onStreamSuccess: (usage: TokenUsage | undefined) => void;\n /** Fires once when the transport loop fails, before `finalResult` rejects. */\n onStreamFailure: (normalized: LLMError, usage: TokenUsage | undefined) => void;\n /**\n * Fires as soon as a `rate_limit_hint` arrives. Reacting to a hint is safe whatever the attempt's\n * outcome, unlike growing the ceiling.\n */\n onRateLimitHint?: (hint: ProviderRateLimitHint) => void;\n /**\n * Builds the final result once the stream completes. Its throws are already normalized and\n * reported, as with `finalizeResponse`.\n */\n finalize: (\n textAcc: string,\n wireToolCalls: WireToolCall[] | undefined,\n usage: TokenUsage | undefined,\n thinking: ThinkingBlock[] | undefined,\n ) => T | CallWithToolsResult<T>;\n}\n\n/**\n * Cleanup after a throw while processing. Both layers run, since SDKs differ: `return()` closes a\n * stream that supports it, and `abort()` closes one that follows the signal. A cleanup failure is\n * swallowed.\n */\nasync function closeIterator(\n iterator: AsyncIterator<WireStreamChunk>,\n streamController: AbortController,\n): Promise<void> {\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\n/** Resolves once `space` does or any of `signals` aborts, whichever comes first. */\nfunction untilSpaceOrAbort(\n space: Promise<void>,\n signals: Array<AbortSignal | undefined>,\n): Promise<void> {\n const active = signals.filter((s): s is AbortSignal => s !== undefined);\n\n if (active.some((s) => s.aborted)) return Promise.resolve();\n\n return new Promise((resolve) => {\n const done = () => {\n for (const s of active) s.removeEventListener('abort', done);\n resolve();\n };\n\n for (const s of active) s.addEventListener('abort', done, { once: true });\n void space.then(done);\n });\n}\n\n/**\n * Pumps wire chunks to the caller as they arrive, with no total duration bound, and builds\n * `finalResult` when the stream ends. Transport errors are normalized and reported here; `finalize`\n * errors already were.\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 readerStallTimeoutMs,\n streamController,\n logger,\n signal,\n maxRetryAfterMs,\n onRateLimitHint,\n } = options;\n\n const {\n promise: finalResult,\n resolve: resolveFinal,\n reject: rejectFinal,\n } = createDeferred<T | CallWithToolsResult<T>>();\n\n // Avoid an unhandled-rejection warning for callers that only read `chunks`.\n finalResult.catch(() => {});\n\n // A push channel rather than a pulled generator, so the pump drives `finalResult` to completion\n // even if `chunks` is never read. The buffer size caps memory before a reader starts; once\n // reading, a full buffer pauses the pump. A reader that leaves early is detached and `call()`\n // aborts the stream.\n const MAX_BUFFERED_CHUNKS = 10_000;\n const channel = createBackpressureChannel<StreamChunk>({\n capacity: MAX_BUFFERED_CHUNKS,\n logger,\n label: 'stream chunk',\n stallTimeoutMs: readerStallTimeoutMs,\n stallError: () =>\n new LLMError(\n `The chunks reader stopped pulling for ${readerStallTimeoutMs}ms with a full buffer, so it was detached. finalResult still settles.`,\n 'timeout',\n { code: 'reader_stall_timeout' },\n ),\n });\n const { push, finish, fail } = channel;\n const chunks = channel.iterable;\n\n const accumulation = createStreamAccumulation(\n { requestId, model, providerName, isFallback },\n push,\n onRateLimitHint,\n );\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 space = accumulation.apply(result.value);\n\n // Waiting here, not inside `withChunkIdleTimeout`, so a slow reader\n // never counts as the provider going idle. An abort ends the wait, so\n // the `next()` below surfaces it even if nobody reads again.\n if (space) await untilSpaceOrAbort(space, [streamController.signal, signal]);\n\n // An adapter that ignores the signal would keep yielding, and the\n // call would still resolve after the caller cancelled it.\n if (signal?.aborted) throw new LLMError('LLM request aborted', 'aborted');\n\n result = await withChunkIdleTimeout(\n () => iterator.next(),\n chunkIdleTimeoutMs,\n () => streamController.abort(),\n logger,\n );\n }\n } catch (error) {\n await closeIterator(iterator, streamController);\n\n const normalized = normalizeError(error, signal, undefined, maxRetryAfterMs);\n\n try {\n options.onStreamFailure(normalized, accumulation.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(accumulation.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 { text, wireToolCalls, usage, thinking } = accumulation.result();\n const finalized = options.finalize(text, wireToolCalls, usage, thinking);\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 { LLMError } from '../../../types/errors.js';\nimport { finalizeResponse } from '../responseFinalizer.js';\nimport { buildStreamResult } from '../streamAccumulator.js';\nimport { normalizeError } from '../utils/errors.utils.js';\nimport { toTokenUsage } from '../utils/response/usage.utils.js';\nimport { withChunkIdleTimeout, withTimeout } from '../utils/retry/retry.utils.js';\nimport {\n countsTowardBreaker,\n finalizeDependencies,\n prepareTargetAttempt,\n type AttemptArgs,\n type AttemptEnvironment,\n} from './attemptEnvironment.js';\nimport { dispatchToProvider, reactToRateLimitError } from './providerDispatch.js';\n\nimport type { Logger } from '../../../logger.js';\nimport type { RateLimiterAdapter } from '../../../rateLimit.js';\nimport type { CallWithToolsResult, StreamChunk, WireStreamChunk } from '../../../types/index.js';\n\ntype WireUsageChunk = Extract<WireStreamChunk, { type: 'usage' }>['usage'];\n\n/**\n * Opens a stream for one attempt. The timeout covers `createStream` and the\n * first `next()` together, since a generator does no work until pulled.\n *\n * The attempt succeeds once the first content chunk arrives, so a failure\n * before that is retried and can fall back. A stream holds its connection for\n * its whole life, so capacity is released on completion, not on open.\n */\nexport async function executeStreamCall<T>(\n env: AttemptEnvironment,\n args: AttemptArgs<T>,\n onOpened?: () => void,\n): Promise<{\n chunks: AsyncIterable<StreamChunk>;\n finalResult: Promise<T | CallWithToolsResult<T>>;\n}> {\n const { params, requestId, attempt, gateway } = args;\n const completions = env.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 const {\n request,\n model,\n useJson,\n state,\n release: acquiredRelease,\n dispatch,\n } = await prepareTargetAttempt(env, args);\n let release = acquiredRelease;\n\n // One controller for the whole stream, threaded into the transport, so an\n // idle timeout mid-way also tears the connection down.\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 chunkIdleTimeoutMs = params.chunkIdleTimeoutMs ?? env.chunkIdleTimeoutMs;\n let opened!: {\n head: IteratorResult<WireStreamChunk>;\n rest: AsyncIterator<WireStreamChunk>;\n };\n\n await dispatchToProvider(env, dispatch, params.signal, async () => {\n const { iterator, first } = await withTimeout(\n async (attemptSignal) => {\n const streamIterator = createStream(request, { signal: attemptSignal })[\n Symbol.asyncIterator\n ]();\n let firstResult = await streamIterator.next();\n\n // A hint comes from headers, before any body. Counting it as the\n // open would skip retries and fallback on a failed first chunk.\n while (!firstResult.done && firstResult.value.type === 'rate_limit_hint') {\n env.limiter?.reactToRateLimitHint(firstResult.value.hint);\n firstResult = await streamIterator.next();\n }\n\n return { iterator: streamIterator, first: firstResult };\n },\n env.timeoutMs,\n combinedExternal,\n );\n\n // A ping counts as open, so a thinking phase longer than `timeoutMs`\n // only needs pings to stay open.\n if (!first.done) onOpened?.();\n\n // Until content arrives nothing has reached the caller, so a failure is\n // still an ordinary attempt failure. The idle timeout bounds the wait.\n // Read inside `dispatch`, so its hooks see the attempt settle where it\n // succeeds or fails, not at a keep-alive ping.\n opened = await readUntilContent(\n iterator,\n first,\n chunkIdleTimeoutMs,\n streamController,\n env.limiter,\n env.logger,\n (wireUsage, error) => {\n const usage = toTokenUsage(wireUsage, {\n requestId,\n model,\n providerName: env.providerName,\n isFallback: env.isFallback,\n });\n const normalized = normalizeError(error, params.signal, undefined, env.maxRetryAfterMs);\n\n if (normalized.type !== 'aborted') {\n env.usageReporter.reportFailure(\n usage,\n normalized,\n attempt,\n gateway.buildAttemptContext(attempt, params.signal, state),\n true,\n );\n }\n\n release?.(env.usageReporter.actualTokensFor(usage));\n release = undefined;\n },\n );\n });\n\n const { head, rest } = opened;\n\n // Same error as an empty non-streaming response, so retry treats both alike.\n if (head.done) {\n throw new LLMError('Empty LLM response', 'api');\n }\n\n // Snapshot: `release` is cleared below once ownership passes to the stream.\n const releaseAtOpen = release;\n\n const result = buildStreamResult(rest, head, {\n requestId,\n model,\n providerName: env.providerName,\n isFallback: env.isFallback,\n chunkIdleTimeoutMs,\n readerStallTimeoutMs: env.readerStallTimeoutMs,\n streamController,\n logger: env.logger,\n signal: params.signal,\n maxRetryAfterMs: env.maxRetryAfterMs,\n onRateLimitHint: (hint) => {\n env.limiter?.reactToRateLimitHint(hint);\n },\n onStreamSuccess: (_usage) => {\n // Nothing here: `finalize` decides success, since its shaping or\n // soft failure check can still reject the response.\n },\n onStreamFailure: (normalized, usage) => {\n // A 429 can also arrive after the stream opened.\n reactToRateLimitError(env.limiter, normalized);\n\n // Only an idle timeout trips the breaker mid-stream, or a provider\n // that hangs after one chunk would never open it.\n if (normalized.type === 'timeout') {\n gateway.recordFailure(attempt, params.signal, state, normalized.code);\n } else {\n gateway.releaseTrial(attempt, params.signal, state);\n }\n\n if (usage && normalized.type !== 'aborted') {\n env.usageReporter.reportFailure(\n usage,\n normalized,\n attempt,\n gateway.buildAttemptContext(attempt, params.signal, state),\n true,\n );\n }\n\n releaseAtOpen?.(env.usageReporter.actualTokensFor(usage));\n },\n finalize: (textAcc, wireToolCalls, usage, thinking) => {\n const actualTokens = env.usageReporter.actualTokensFor(usage);\n\n try {\n const finalized = finalizeResponse(\n textAcc,\n wireToolCalls,\n params,\n useJson,\n usage,\n requestId,\n attempt,\n state,\n finalizeDependencies(env, gateway, model),\n false,\n thinking,\n );\n\n releaseAtOpen?.(actualTokens, true);\n\n return finalized;\n } catch (error) {\n // Free the slot without growing AIMD for a rejected response.\n releaseAtOpen?.(actualTokens);\n\n // The retry loop already saw this attempt succeed when the stream\n // opened, so the breaker outcome is recorded here.\n if (error instanceof LLMError && countsTowardBreaker(error)) {\n gateway.recordFailure(attempt, params.signal, state, error.code);\n } else {\n gateway.releaseTrial(attempt, params.signal, state);\n }\n\n throw error;\n }\n },\n });\n\n release = undefined;\n\n return result;\n } finally {\n // Only reached with a live release when opening the stream threw.\n release?.();\n }\n}\n\n/**\n * Reads past pings and rate limit hints until the first content chunk or the\n * end. A usage chunk seen on the way is replayed ahead of that content. On\n * failure the stream is closed and any usage seen goes to `onFailedUsage`.\n * Runs inside `dispatchToProvider`, which feeds the error to AIMD.\n */\nasync function readUntilContent(\n iterator: AsyncIterator<WireStreamChunk>,\n first: IteratorResult<WireStreamChunk>,\n chunkIdleTimeoutMs: number | undefined,\n streamController: AbortController,\n limiter: RateLimiterAdapter | undefined,\n logger: Logger,\n onFailedUsage: (usage: WireUsageChunk, error: unknown) => void,\n): Promise<{ head: IteratorResult<WireStreamChunk>; rest: AsyncIterator<WireStreamChunk> }> {\n const held: WireStreamChunk[] = [];\n let current = first;\n\n try {\n while (!current.done && !isContentChunk(current.value)) {\n const chunk = current.value;\n\n if (chunk.type === 'rate_limit_hint') {\n limiter?.reactToRateLimitHint(chunk.hint);\n } else if (chunk.type !== 'ping') {\n held.push(chunk);\n }\n\n current = await withChunkIdleTimeout(\n () => iterator.next(),\n chunkIdleTimeoutMs,\n () => streamController.abort(),\n logger,\n );\n }\n } catch (error) {\n // Not awaited: after an idle timeout the generator can still be stuck in\n // its own await, and `return()` would wait for it. The abort is what\n // tears the transport down.\n streamController.abort();\n void Promise.resolve()\n .then(() => iterator.return?.())\n .catch(() => {});\n\n const lastUsage = [...held].reverse().find((chunk) => chunk.type === 'usage');\n if (lastUsage?.type === 'usage') onFailedUsage(lastUsage.usage, error);\n\n throw error;\n }\n\n if (current.done || held.length === 0) return { head: current, rest: iterator };\n\n // Replays the held chunks, then the content chunk, then the live stream.\n const queue: WireStreamChunk[] = [...held.slice(1), current.value];\n const rest: AsyncIterator<WireStreamChunk> = {\n next: () => {\n const queued = queue.shift();\n return queued ? Promise.resolve({ done: false, value: queued }) : iterator.next();\n },\n return: async () => iterator.return?.() ?? { done: true, value: undefined },\n };\n\n return { head: { done: false, value: held[0]! }, rest };\n}\n\n/** Text or a tool call delta: the first chunk that reaches the caller as content. */\nfunction isContentChunk(chunk: WireStreamChunk): boolean {\n return chunk.type === 'text-delta' || chunk.type === 'tool_call_delta';\n}\n","import { LLMError } from '../../../../types/errors.js';\nimport { 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 */\nexport function serializeAssistantContent(content: AssistantContent): string {\n return typeof content === 'string' ? content : JSON.stringify(content);\n}\n\n/**\n * Rejects an empty `tools`, duplicate names, `toolChoice` without `tools`, and a `toolChoice`\n * naming an unknown tool, all as `invalid_params`.\n */\nexport function validateTools(\n tools: CallParams<unknown>['tools'],\n toolChoice: CallParams<unknown>['toolChoice'],\n): void {\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\n/** Everything `resolveJsonMode` needs to decide `useJson` for one call. */\nexport interface ResolveJsonModeParams {\n /** `params.jsonMode` as the caller set it, `undefined` if they didn't. */\n jsonModeExplicit: boolean | undefined;\n /** Whether `tools` was set, since the default `jsonMode` depends on it. */\n hasTools: boolean;\n jsonSchema: CallParams<unknown>['jsonSchema'];\n /** Whether `schema` was set. */\n hasSchema: boolean;\n supportsJsonObjectMode: boolean;\n}\n\n/**\n * Whether to request and parse JSON. `jsonMode` defaults to off with `tools`, since forcing JSON\n * alongside tool calls is unreliable, and on otherwise. Clients without real `json_object` support\n * throw on an explicit `jsonMode: true` or a `schema` without `jsonSchema`, but quietly fall back\n * to text for the default. Throws `invalid_params` when `schema` is set but no JSON is requested.\n */\nexport function resolveJsonMode(params: ResolveJsonModeParams): boolean {\n const { jsonModeExplicit, hasTools, jsonSchema, hasSchema, supportsJsonObjectMode } = params;\n\n const jsonMode = jsonModeExplicit ?? !hasTools;\n\n if (!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 if (!supportsJsonObjectMode && !jsonSchema && jsonModeExplicit === undefined && hasSchema) {\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 // The default `jsonMode` falls back to text on clients without `json_object`, so `llm.call({\n // userContent })` works everywhere.\n const jsonModeEffective =\n !supportsJsonObjectMode && !jsonSchema && jsonModeExplicit === undefined ? false : jsonMode;\n\n const useJson = jsonModeEffective || Boolean(jsonSchema);\n\n if (hasSchema && !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 return useJson;\n}\n\n/** A native `jsonSchema` when given, else `json_object` when JSON is wanted, else no format. */\nexport function buildResponseFormat(\n jsonSchema: CallParams<unknown>['jsonSchema'],\n useJson: boolean,\n) {\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/** Maps VernLLM's app-facing `ToolChoice` onto the OpenAI-shaped wire `tool_choice`. */\nexport function 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 * One turn as wire messages. A tool turn expands to one `tool` message per result, since the wire\n * format wants one per `tool_call_id`.\n */\nexport function 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 ? { content: serializeAssistantContent(turn.content) } : {}),\n tool_calls: toWireToolCalls(turn.toolCalls),\n ...(turn.thinking?.length ? { thinking: turn.thinking } : {}),\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 ...(turn.thinking?.length ? { thinking: turn.thinking } : {}),\n },\n ];\n }\n\n return [{ role: turn.role as 'user', content: turn.content ?? '' }];\n}\n\n/**\n * Throws `LLMError('invalid_params')` unless `thinking` is an array of\n * well formed blocks. Checked locally since a malformed block would only\n * come back as a provider 400 after a round trip.\n */\nfunction assertValidThinking(thinking: unknown, index: number): void {\n if (!Array.isArray(thinking)) {\n throw new LLMError(`history[${index}].thinking must be an array`, 'invalid_params');\n }\n\n for (const [blockIndex, block] of thinking.entries()) {\n const candidate = block as Partial<Record<string, unknown>> | null;\n const valid =\n typeof candidate === 'object' &&\n candidate !== null &&\n ((candidate.type === 'thinking' &&\n typeof candidate.thinking === 'string' &&\n typeof candidate.signature === 'string') ||\n (candidate.type === 'redacted_thinking' && typeof candidate.data === 'string'));\n\n if (!valid) {\n throw new LLMError(\n `history[${index}].thinking[${blockIndex}] must be { type: 'thinking', thinking, signature } or { type: 'redacted_thinking', data }, as returned on ToolCallResult.thinking`,\n 'invalid_params',\n );\n }\n }\n}\n\n/**\n * Validates `history` alternates user/assistant turns, since providers\n * like Anthropic/Gemini reject or mishandle consecutive same-role turns.\n */\nexport function validateHistory(history: ConversationTurn[]): void {\n let previousTurn: ConversationTurn | undefined;\n\n for (const [index, turn] of history.entries()) {\n if (turn.role === 'assistant' && turn.thinking !== undefined) {\n assertValidThinking(turn.thinking, index);\n }\n\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","import {\n buildResponseFormat,\n buildWireToolChoice,\n resolveJsonMode,\n turnToWireMessages,\n validateHistory,\n validateTools,\n} from './utils/request/requestShape.utils.js';\nimport { toWireTools } from './utils/wire.utils.js';\n\nimport type { CallParams, WireMessage } from '../../types/index.js';\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 for one call from the target's defaults and the call's overrides. Owns\n * every check on the caller's own input, so every throw is `invalid_params`; `validation` is kept\n * for provider responses. The checks themselves live in `requestShape.utils.ts`.\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 validateTools(tools, toolChoice);\n\n const useJson = resolveJsonMode({\n jsonModeExplicit: params.jsonMode,\n hasTools: Boolean(tools),\n jsonSchema,\n hasSchema: Boolean(params.schema),\n supportsJsonObjectMode: this.supportsJsonObjectMode,\n });\n\n const responseFormat = buildResponseFormat(jsonSchema, useJson);\n\n 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: buildWireToolChoice(toolChoice) } : {}),\n messages: [\n ...(systemPrompt ? [{ role: 'system' as const, content: systemPrompt }] : []),\n ...history.flatMap((turn): WireMessage[] => turnToWireMessages(turn)),\n { role: 'user' as const, content: userContent },\n ] satisfies WireMessage[],\n };\n\n return { useJson, model, request };\n }\n}\n","import { toTokenUsage } from './utils/response/usage.utils.js';\n\nimport type { Logger } from '../../logger.js';\nimport type { LLMError } from '../../types/errors.js';\nimport type { VernLLMEvent } from '../../types/events.js';\nimport type { AttemptContext, LLMClient, TokenUsage } from '../../types/index.js';\n\n/** Everything one target's `UsageReporter` needs beyond the response/error being reported on. */\nexport interface UsageReporterOptions {\n providerName: string;\n /** True for every target after the primary. Stamped onto every reported `TokenUsage`. */\n isFallback: boolean;\n maxRetries: number;\n /** Whether cache reads count toward the provider's token rate limit. Default `true`. */\n cacheReadsCountTowardRateLimit?: boolean;\n /**\n * Reports `'usage'` and `'usage_failure'` events through the shared event path. `onUsage` and\n * `onUsageFailure` are driven from those events, so usage has one reporting route.\n */\n emitEvent: (event: VernLLMEvent, ctx: AttemptContext) => void;\n logger: Logger;\n}\n\nexport interface UsageReporter {\n /**\n * `TokenUsage` from a raw response, if reported. Independent of the rest of the body, so a\n * malformed response can still yield usage.\n */\n extract(\n response: Awaited<ReturnType<LLMClient['chat']['completions']['create']>>,\n requestId: string,\n model: string,\n ): TokenUsage | undefined;\n /**\n * The token count to reconcile the limiter with: `totalTokens`, else prompt plus completion,\n * less cache reads when the provider's limit skips them. `undefined` when missing or nothing is\n * left, so the limiter keeps its estimate.\n */\n actualTokensFor(usage: TokenUsage | undefined): number | undefined;\n /** Reports token usage for a successful call as a `'usage'` event. `ctx` is this attempt's `AttemptContext`, used to fan the event out to middleware and to `onEvent`/`onUsage`. */\n reportSuccess(usage: TokenUsage | undefined, ctx: AttemptContext): void;\n /**\n * Reports usage spent on an attempt that then failed, as `'usage_failure'`, so it isn't lost with\n * the error.\n */\n reportFailure(\n usage: TokenUsage,\n error: LLMError,\n attempt: number,\n ctx: AttemptContext,\n terminal?: boolean,\n ): void;\n}\n\nexport function createUsageReporter(options: UsageReporterOptions): UsageReporter {\n const { providerName, isFallback, maxRetries, emitEvent, logger } = options;\n const cacheReadsCount = options.cacheReadsCountTowardRateLimit ?? true;\n\n function extract(\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 return toTokenUsage(response.usage, { requestId, model, providerName, isFallback });\n }\n\n function actualTokensFor(usage: TokenUsage | undefined): number | undefined {\n if (!usage) return undefined;\n\n const total = usage.totalTokens || usage.promptTokens + usage.completionTokens;\n\n // A real request always spends prompt tokens, so an all zero report\n // means the provider sent no usage. Reconciling against it would\n // refund the whole estimate for tokens that were actually spent.\n if (cacheReadsCount) return total === 0 ? undefined : total;\n\n // Anthropic's limit skips cache reads; counting them would throttle cached traffic harder\n // than the provider does. Nothing left means the report carried no countable usage.\n const counted = total - (usage.cacheReadTokens ?? 0);\n\n return counted > 0 ? counted : undefined;\n }\n\n function reportSuccess(usage: TokenUsage | undefined, ctx: AttemptContext): void {\n if (!usage) return;\n\n emitEvent({ kind: 'usage', requestId: usage.requestId, usage }, ctx);\n }\n\n function reportFailure(\n usage: TokenUsage,\n error: LLMError,\n attempt: number,\n ctx: AttemptContext,\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}/${maxRetries + 1}`;\n\n logger.warn(\n `[VernLLM:${usage.requestId}] usage failure, ${attemptText}: ` +\n `type=${error.type} tokens=${displayTokens}`,\n );\n\n emitEvent({ kind: 'usage_failure', requestId: usage.requestId, usage, error }, ctx);\n }\n\n return { extract, actualTokensFor, reportSuccess, reportFailure };\n}\n","import { callScopeFor, noopEmit } from '../utils/callScope.utils.js';\nimport { reportRejection } from '../utils/circuit-breaker/circuitBreaker.utils.js';\n\nimport type { CircuitBreakerAdapter, CircuitBreakerCallContext } from '../../circuitBreaker.js';\nimport type { Logger } from '../../logger.js';\nimport type {\n AdapterInfo,\n AttemptContext,\n LLMErrorCode,\n MiddlewareStateBag,\n} from '../../types/index.js';\nimport type { MiddlewareContextNames } from '../utils/middlewareLabels.utils.js';\n\n/** Everything one logical call needs to build attempt context and talk to its breaker. */\nexport interface BreakerGatewayOptions {\n breaker?: CircuitBreakerAdapter;\n /** Where a breaker adapter's rejected background promise is reported, see `settleQuietly`. */\n logger: Logger;\n requestId: string;\n model: string;\n providerName: string;\n isFallback: boolean;\n supportsJsonObjectMode: boolean;\n /** Threaded through for `AttemptContext.registeredMiddlewareNames` and `transformMiddlewareNames`. */\n middlewareNames: MiddlewareContextNames;\n /** Threaded through for `AttemptContext.adapter`. */\n adapter: AdapterInfo;\n}\n\n/**\n * Builds `AttemptContext`/`CircuitBreakerCallContext` for one logical\n * call's attempts, and records success/failure against `breaker`.\n * `attempt` stays 0-based at every call site; the 1-based conversion\n * happens once, inside `buildCallContext`/`buildAttemptContext`.\n */\nexport interface BreakerGateway {\n buildAttemptContext(\n attempt: number,\n signal: AbortSignal | undefined,\n state: MiddlewareStateBag,\n ): AttemptContext;\n buildCallContext(\n attempt: number,\n signal: AbortSignal | undefined,\n state: MiddlewareStateBag,\n ): CircuitBreakerCallContext;\n /** No-op if no breaker was configured. */\n recordSuccess(attempt: number, signal: AbortSignal | undefined, state: MiddlewareStateBag): void;\n /** No-op if no breaker was configured or it has no `releaseTrial`. Gives back a half-open trial when the call ended without recording an outcome. */\n releaseTrial(attempt: number, signal: AbortSignal | undefined, state: MiddlewareStateBag): void;\n /** No-op if no breaker was configured. `code`, when present, is forwarded to the breaker for future attribution use. */\n recordFailure(\n attempt: number,\n signal: AbortSignal | undefined,\n state: MiddlewareStateBag,\n code?: LLMErrorCode,\n ): void;\n}\n\nexport function createBreakerGateway(options: BreakerGatewayOptions): BreakerGateway {\n const {\n breaker,\n logger,\n requestId,\n model,\n providerName,\n isFallback,\n supportsJsonObjectMode,\n middlewareNames,\n adapter,\n } = options;\n\n function buildAttemptContext(\n attempt: number,\n signal: AbortSignal | undefined,\n state: MiddlewareStateBag,\n ): AttemptContext {\n return {\n stage: 'attempt',\n requestId,\n requestedProvider: providerName,\n adapter,\n requestedModel: model,\n isFallbackAttempt: isFallback,\n attempt: attempt + 1,\n capabilities: { supportsJsonObjectMode },\n signal,\n state,\n own: {},\n emit: noopEmit,\n context: callScopeFor(state)?.context,\n ...middlewareNames,\n };\n }\n\n function buildCallContext(\n attempt: number,\n signal: AbortSignal | undefined,\n state: MiddlewareStateBag,\n ): CircuitBreakerCallContext {\n return { requestId, state, signal, attempt: attempt + 1 };\n }\n\n function settleQuietly(operation: string, result: unknown): void {\n reportRejection(logger, `[VernLLM:${requestId}] circuitBreaker.${operation} rejected`, result);\n }\n\n return {\n buildAttemptContext,\n buildCallContext,\n recordSuccess(attempt, signal, state) {\n settleQuietly(\n 'recordSuccess',\n breaker?.recordSuccess(model, buildCallContext(attempt, signal, state)),\n );\n },\n recordFailure(attempt, signal, state, code) {\n settleQuietly(\n 'recordFailure',\n breaker?.recordFailure(model, buildCallContext(attempt, signal, state), code),\n );\n },\n releaseTrial(attempt, signal, state) {\n settleQuietly(\n 'releaseTrial',\n breaker?.releaseTrial?.(model, buildCallContext(attempt, signal, state)),\n );\n },\n };\n}\n","import { LLMError, type LLMRequestSnapshot, type RetryAttempt } from '../../../../types/errors.js';\nimport { createMiddlewareStateBag } from '../../../../types/middleware.js';\nimport { middlewareContextNames } from '../../../utils/middlewareLabels.utils.js';\nimport { createBreakerGateway, type BreakerGateway } from '../../circuitBreakerContext.js';\nimport { describeError, extractStatus, normalizeError } from '../errors.utils.js';\nimport { emitEvent } from '../middleware/middleware.utils.js';\nimport { recoverDelay, retryWithBackoff, shouldRetry } from '../retry/retry.utils.js';\n\nimport type { CircuitBreakerAdapter } from '../../../../circuitBreaker.js';\nimport type { Logger } from '../../../../logger.js';\nimport type {\n AdapterInfo,\n MiddlewareStateBag,\n VernLLMEvent,\n VernLLMMiddleware,\n} from '../../../../types/index.js';\nimport type { RetryBudget } from '../../../retryBudget.js';\n\n/** Everything `runAttemptLoop` needs besides the per attempt `fn`. */\nexport interface RunAttemptLoopParams<T> {\n fn: (\n attempt: number,\n onRequest: (snapshot: LLMRequestSnapshot | undefined) => void,\n state: MiddlewareStateBag,\n gateway: BreakerGateway,\n ) => Promise<T>;\n requestId: string;\n model: string;\n providerName: string;\n isFallback: boolean;\n supportsJsonObjectMode: boolean;\n /** See `AttemptContext.adapter`. */\n adapter: AdapterInfo;\n breaker?: CircuitBreakerAdapter;\n /**\n * Caps how much of this target's recent traffic is allowed to be\n * retries, independent of `breaker`. See `RetryBudget`. Undefined\n * means no budget, exactly today's behavior.\n */\n budget?: RetryBudget;\n maxRetries: number;\n baseDelayMs: number;\n /** See `VernLLMOptions.maxRetryAfterMs`. Omitted means the 10s default. */\n maxRetryAfterMs?: number;\n nonRetryableStatus: number[];\n signal?: AbortSignal;\n onAttempt?: () => void;\n state?: MiddlewareStateBag;\n middleware: VernLLMMiddleware[];\n middlewareTimeoutMs: number;\n logger: Logger;\n reportEvent: (event: VernLLMEvent) => void;\n /**\n * Label folded into the debug log line on terminal failure, e.g.\n * `'error'` for `run`, `'stream-open error'` for `runStream`, so the\n * two calls stay distinguishable in logs despite sharing this loop.\n */\n logLabel: string;\n /** Applied to the logged error description. See `VernLLMOptions.redact`. */\n redactText: (text: string) => string;\n /**\n * Decides whether the terminal failure counts toward the breaker's\n * failure threshold. See `CallExecutor`'s own `countsTowardBreaker`,\n * which this is injected from.\n */\n countsTowardBreaker: (error: LLMError) => boolean;\n}\n\n/**\n * Retries `fn` with backoff through one shared `BreakerGateway`. On final failure it normalizes,\n * records against the breaker when `countsTowardBreaker` allows, logs under `logLabel`, and\n * rethrows.\n */\nexport async function runAttemptLoop<T>(params: RunAttemptLoopParams<T>): Promise<T> {\n const {\n fn,\n requestId,\n model,\n providerName,\n isFallback,\n supportsJsonObjectMode,\n adapter,\n breaker,\n budget,\n maxRetries,\n baseDelayMs,\n maxRetryAfterMs,\n nonRetryableStatus,\n signal,\n onAttempt,\n middleware,\n middlewareTimeoutMs,\n logger,\n reportEvent,\n logLabel,\n redactText,\n countsTowardBreaker,\n } = params;\n\n const resolvedState = params.state ?? createMiddlewareStateBag();\n // Every error this loop builds reports `retryAfterMs` under the same cap\n // the wait itself honors, so the two never disagree.\n const normalize = (error: unknown, signal?: AbortSignal, attempts?: RetryAttempt[]) =>\n normalizeError(error, signal, attempts, maxRetryAfterMs);\n const attempts: RetryAttempt[] = [];\n const gateway = createBreakerGateway({\n breaker,\n logger,\n requestId,\n model,\n providerName,\n isFallback,\n supportsJsonObjectMode,\n middlewareNames: middlewareContextNames(middleware),\n adapter,\n });\n\n // Set only when `budget.assertAvailable()` is what actually stopped a\n // retry, so the terminal error below can report *that*, not whichever\n // failure happened to be current when the budget ran out.\n let budgetExhaustedError: LLMError | undefined;\n\n try {\n return await retryWithBackoff({\n fn: (attempt, onRequest) => {\n budget?.recordAttempt(attempt > 0);\n return fn(attempt, onRequest, resolvedState, gateway);\n },\n maxRetries,\n signal,\n onAttempt,\n attempts,\n shouldRetryAttempt: (error, signal) => {\n if (!shouldRetry(error, nonRetryableStatus, extractStatus, signal)) return false;\n if (budget) {\n try {\n budget.assertAvailable();\n } catch (err) {\n budgetExhaustedError = err as LLMError;\n return false;\n }\n }\n return true;\n },\n recoverDelayForAttempt: (attempt, error) =>\n recoverDelay({\n requestId,\n model,\n attempt,\n error,\n state: resolvedState,\n signal,\n providerName,\n maxRetries,\n baseDelayMs,\n maxRetryAfterMs,\n middleware,\n middlewareTimeoutMs,\n logger,\n reportEvent,\n buildEventContext: (_requestId, _model, attempt, signal, state) =>\n gateway.buildAttemptContext(attempt, signal, state),\n extractStatus,\n normalizeError: normalize,\n emitEvent,\n }),\n normalizeError: normalize,\n });\n } catch (error) {\n // An empty `attempts` becomes `undefined`, per `LLMError.attempts`. The budget error goes\n // through `normalizeError` too, which adds the history without changing its type or code.\n const normalized = normalize(\n budgetExhaustedError ?? error,\n signal,\n attempts.length > 0 ? attempts : undefined,\n );\n\n if (countsTowardBreaker(normalized)) {\n // `attempts` only holds prior attempts that were retried past (see\n // above), so the attempt that actually exhausted the retries/broke\n // the loop is one past that. `recordFailure` converts to 1-based\n // itself.\n gateway.recordFailure(attempts.length, signal, resolvedState, normalized.code);\n } else {\n // Nothing was recorded, so a half-open trial this call claimed would\n // otherwise stay held forever. Idempotent, a no-op when it holds none.\n gateway.releaseTrial(attempts.length, signal, resolvedState);\n }\n\n logger.debug(`[VernLLM:${requestId}] ${logLabel}:\\n${redactText(describeError(error))}`);\n\n throw normalized;\n }\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 { type RetryBudget } from '../retryBudget.js';\nimport { resolveAdapterInfo } from '../utils/adapterInfo.utils.js';\nimport {\n makeEventReporter,\n reportRejection,\n} from '../utils/circuit-breaker/circuitBreaker.utils.js';\nimport {\n runPrepare,\n type PreparableBreaker,\n} from '../utils/circuit-breaker/prepareBreaker.utils.js';\nimport { callHookSafely } from '../utils/logger.utils.js';\nimport {\n countsTowardBreaker,\n redactText,\n type AttemptEnvironment,\n} from './attempt/attemptEnvironment.js';\nimport { executeCall } from './attempt/nonStreamAttempt.js';\nimport { executeStreamCall } from './attempt/streamAttempt.js';\nimport { RequestBuilder } from './requestBuilder.js';\nimport { createUsageReporter } from './usageReporter.js';\nimport { type OnRequest } from './utils/dispatch/attemptDispatch.utils.js';\nimport { runAttemptLoop, type RunAttemptLoopParams } from './utils/dispatch/attemptLoop.utils.js';\nimport {\n DEFAULT_MIDDLEWARE_TIMEOUT_MS,\n buildDispatchHooks,\n emitEvent,\n} from './utils/middleware/middleware.utils.js';\nimport { defaultParseJson } from './utils/parse.utils.js';\nimport { normalizeMaxRetries, validateMaxRetryAfterMs } from './utils/retry/retry.utils.js';\n\nimport type { CircuitBreakerAdapter, CircuitBreakerCallContext } from '../../circuitBreaker.js';\nimport type { Logger } from '../../logger.js';\nimport type { RateLimiterAdapter } from '../../rateLimit.js';\nimport type { LLMError } from '../../types/errors.js';\nimport type {\n AdapterInfo,\n CallParams,\n CallWithToolsResult,\n DetectSoftFailure,\n LLMClient,\n MiddlewareStateBag,\n StreamChunk,\n TokenUsage,\n VernLLMEvent,\n VernLLMMiddleware,\n WireCallRequest,\n} from '../../types/index.js';\n\nexport type { OnRequest };\n\n/** Everything one `CallExecutor` needs beyond the client and model. */\nexport interface CallExecutorOptions {\n maxRetries: number;\n timeoutMs: number;\n chunkIdleTimeoutMs: number;\n /** See `VernLLMOptions.readerStallTimeoutMs`. Off when omitted. */\n readerStallTimeoutMs?: number;\n baseDelayMs: number;\n /** See `VernLLMOptions.maxRetryAfterMs`. */\n maxRetryAfterMs: 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?: CircuitBreakerAdapter;\n /** Caps retries against this target independent of `breaker`. See `VernLLMOptions.retryBudget`. */\n budget?: RetryBudget;\n limiter?: RateLimiterAdapter;\n /** True for every target after the primary. Stamped onto reported `TokenUsage`. */\n isFallback?: boolean;\n /** See `VernLLMOptions.middleware`. */\n middleware?: VernLLMMiddleware[];\n /**\n * `wrap` nesting order (`position` applied), which `dispatch` hooks nest\n * in too. Defaults to `middleware`'s order.\n */\n dispatchOrder?: VernLLMMiddleware[];\n /** See `VernLLMOptions.middlewareTimeoutMs`. */\n middlewareTimeoutMs?: number;\n /** See `VernLLMOptions.detectSoftFailure`. */\n detectSoftFailure?: DetectSoftFailure;\n}\n\n/**\n * One provider target: request building, retries, and its own breaker and limiter. `VernLLM` holds\n * one per target and adds fallback and caching on top.\n */\nexport class CallExecutor {\n private readonly maxRetries: number;\n private readonly baseDelayMs: number;\n private readonly nonRetryableStatus: number[];\n private readonly logger: Logger;\n private readonly breaker?: CircuitBreakerAdapter;\n private readonly budget?: RetryBudget;\n private readonly limiter?: RateLimiterAdapter;\n private readonly isFallback: boolean;\n private readonly supportsJsonObjectMode: boolean;\n /** Everything a single attempt reads. Shared by both attempt paths. */\n private readonly env: AttemptEnvironment;\n /** See `AttemptContext.adapter`. */\n readonly adapter: AdapterInfo;\n\n constructor(\n readonly providerName: string,\n client: LLMClient,\n readonly model: string,\n options: CallExecutorOptions,\n ) {\n this.maxRetries = normalizeMaxRetries(options.maxRetries);\n this.baseDelayMs = options.baseDelayMs;\n const maxRetryAfterMs = validateMaxRetryAfterMs(options.maxRetryAfterMs, providerName);\n this.nonRetryableStatus = options.nonRetryableStatus;\n this.logger = options.logger;\n\n if (this.maxRetries !== options.maxRetries) {\n this.logger.warn(\n `[VernLLM] ${providerName}: maxRetries must be a non-negative whole number, got ${String(options.maxRetries)}. Using ${this.maxRetries}.`,\n );\n }\n\n const reportEvent = makeEventReporter(options.onEvent, this.logger, {\n onUsage: options.onUsage,\n onUsageFailure: options.onUsageFailure,\n });\n\n this.breaker = options.breaker;\n this.budget = options.budget;\n this.limiter = options.limiter;\n this.isFallback = options.isFallback ?? false;\n const middleware = options.middleware ?? [];\n const dispatchHooks = buildDispatchHooks(middleware, options.dispatchOrder);\n this.adapter = resolveAdapterInfo(client);\n callHookSafely(this.logger, 'client.setLogger', () => client.setLogger?.(this.logger));\n const middlewareTimeoutMs = options.middlewareTimeoutMs ?? DEFAULT_MIDDLEWARE_TIMEOUT_MS;\n this.supportsJsonObjectMode = client.supportsJsonObjectMode ?? true;\n\n const usageReporter = createUsageReporter({\n providerName,\n isFallback: this.isFallback,\n maxRetries: this.maxRetries,\n cacheReadsCountTowardRateLimit: client.cacheReadsCountTowardRateLimit,\n emitEvent: (event, ctx) =>\n emitEvent(event, ctx, reportEvent, middleware, middlewareTimeoutMs, this.logger),\n logger: this.logger,\n });\n\n const requestBuilder = new RequestBuilder({\n model,\n defaultMaxTokens: options.defaultMaxTokens,\n defaultTemperature: options.defaultTemperature,\n defaultReasoningEffort: options.defaultReasoningEffort,\n defaultBudgetTokens: options.defaultBudgetTokens,\n supportsJsonObjectMode: this.supportsJsonObjectMode,\n });\n\n this.env = {\n client,\n providerName,\n isFallback: this.isFallback,\n timeoutMs: options.timeoutMs,\n chunkIdleTimeoutMs: options.chunkIdleTimeoutMs,\n readerStallTimeoutMs: options.readerStallTimeoutMs,\n maxRetryAfterMs,\n parseJson: options.parseJson ?? defaultParseJson,\n logger: this.logger,\n redact: options.redact,\n usageReporter,\n reportEvent,\n limiter: this.limiter,\n requestBuilder,\n middleware,\n dispatchHooks,\n middlewareTimeoutMs,\n detectSoftFailure: options.detectSoftFailure,\n };\n }\n\n /**\n * This target's wire request for `params`, without dispatch or `transform`.\n * Gives `wrap` a representative request before the real one exists.\n */\n previewRequest<T>(params: CallParams<T>): { model: string; request: WireCallRequest } {\n const { model, request } = this.env.requestBuilder.build(params);\n return { model, request };\n }\n\n /** Whether the client supports `response_format: 'json_object'`. */\n get jsonObjectModeSupported(): boolean {\n return this.supportsJsonObjectMode;\n }\n\n getCircuitState(model?: string) {\n return this.breaker?.getState?.(model);\n }\n\n /** The breaker's `readState` if it has one, otherwise `getState`. */\n async readCircuitState(model?: string) {\n return this.breaker?.readState\n ? this.breaker.readState(model)\n : this.breaker?.getState?.(model);\n }\n\n getFailureBreakdown(model?: string) {\n return this.breaker?.getFailureBreakdown?.(model);\n }\n\n getRetryBudgetState() {\n return this.budget?.getSnapshot();\n }\n\n getRateLimitState() {\n return this.limiter?.getState?.();\n }\n\n /** The limiter's `readState` if it has one, otherwise `getState`. */\n async readRateLimitState() {\n return this.limiter?.readState ? this.limiter.readState() : this.limiter?.getState?.();\n }\n\n /** `false` without a breaker, or when the breaker doesn't report it. */\n get isolateByModel(): boolean {\n return this.breaker?.isolateByModel ?? false;\n }\n\n openCircuit(model?: string, context?: CircuitBreakerCallContext): void {\n this.breaker?.open?.(model, context);\n }\n\n closeCircuit(model?: string, context?: CircuitBreakerCallContext): void {\n this.breaker?.close?.(model, context);\n }\n\n /**\n * Throws if the breaker is open. May claim a half-open trial, so it runs\n * once per logical call, from `VernLLM` or the fallback chain, never from\n * `run`. Returns a promise only when the breaker has a `prepare`, so a plain\n * breaker adds no tick.\n */\n assertBreakerClosed(model?: string, context?: CircuitBreakerCallContext): void | Promise<void> {\n const breaker = this.breaker;\n const resolvedModel = model ?? this.model;\n\n if (!breaker?.prepare) {\n breaker?.assertClosed(resolvedModel, context);\n return;\n }\n\n return runPrepare(breaker as PreparableBreaker, resolvedModel, context, this.logger).then(() =>\n breaker.assertClosed(resolvedModel, context),\n );\n }\n\n /** Gives back a trial `assertBreakerClosed` may have claimed. Idempotent. */\n releaseBreakerTrial(model?: string, context?: CircuitBreakerCallContext): void {\n // Declared `void`, but a remote adapter may return a promise anyway.\n reportRejection(\n this.logger,\n '[VernLLM] circuitBreaker.releaseTrial rejected',\n this.breaker?.releaseTrial?.(model ?? this.model, context),\n );\n }\n\n /** One logical call against this target, with retries. The breaker check stays with the caller. */\n async run<T>(\n params: CallParams<T>,\n requestId: string,\n onAttempt?: () => void,\n state?: MiddlewareStateBag,\n ): Promise<T | CallWithToolsResult<T>> {\n return runAttemptLoop(\n this.attemptLoopParams(\n params,\n requestId,\n onAttempt,\n state,\n 'error',\n (attempt, onRequest, middlewareState, gateway) =>\n executeCall(this.env, {\n params,\n requestId,\n attempt,\n onRequest,\n middlewareState,\n gateway,\n }),\n ),\n );\n }\n\n /**\n * Streaming counterpart to `run`. `onOpened` fires when any attempt's stream\n * opens, a ping included. See `executeLogicalStreamCall`.\n */\n async runStream<T>(\n params: CallParams<T>,\n requestId: string,\n onAttempt?: () => void,\n state?: MiddlewareStateBag,\n onOpened?: () => void,\n ): Promise<{\n chunks: AsyncIterable<StreamChunk>;\n finalResult: Promise<T | CallWithToolsResult<T>>;\n }> {\n return runAttemptLoop(\n this.attemptLoopParams(\n params,\n requestId,\n onAttempt,\n state,\n 'stream-open error',\n (attempt, onRequest, middlewareState, gateway) =>\n executeStreamCall(\n this.env,\n { params, requestId, attempt, onRequest, middlewareState, gateway },\n onOpened,\n ),\n ),\n );\n }\n\n private attemptLoopParams<R>(\n params: CallParams<unknown>,\n requestId: string,\n onAttempt: (() => void) | undefined,\n state: MiddlewareStateBag | undefined,\n logLabel: RunAttemptLoopParams<R>['logLabel'],\n fn: RunAttemptLoopParams<R>['fn'],\n ): RunAttemptLoopParams<R> {\n return {\n fn,\n requestId,\n model: params.model ?? this.model,\n providerName: this.providerName,\n isFallback: this.isFallback,\n supportsJsonObjectMode: this.supportsJsonObjectMode,\n adapter: this.adapter,\n breaker: this.breaker,\n budget: this.budget,\n maxRetries: this.maxRetries,\n baseDelayMs: this.baseDelayMs,\n maxRetryAfterMs: this.env.maxRetryAfterMs,\n nonRetryableStatus: this.nonRetryableStatus,\n signal: params.signal,\n onAttempt,\n state,\n middleware: this.env.middleware,\n middlewareTimeoutMs: this.env.middlewareTimeoutMs,\n logger: this.logger,\n reportEvent: this.env.reportEvent,\n logLabel,\n redactText: (text) => redactText(this.env, text),\n countsTowardBreaker,\n };\n }\n}\n","import { LLMError } from '../../types/errors.js';\n\nimport type { TargetInfo } from '../../types/fallback.js';\nimport type { CallExecutor } from './callExecutor.js';\n\n/** One configured target, with the declared position that stays its identity in events and meta. */\nexport interface ResolvedTarget {\n executor: CallExecutor;\n /** Declared index: 0 is the primary. Unchanged by any reordering. */\n index: number;\n}\n\n/** Every target in declared order. */\nexport function declaredTargets(executors: readonly CallExecutor[]): ResolvedTarget[] {\n return executors.map((executor, index) => ({ executor, index }));\n}\n\n/**\n * The targets as `ctx.targets` shows them. `model` is what the target would run, so the per call\n * `model` override shows on the primary only.\n */\nexport function describeTargets(\n targets: readonly ResolvedTarget[],\n modelFor: (index: number) => string | undefined,\n): TargetInfo[] {\n return targets.map(({ executor, index }) => ({\n name: executor.providerName,\n index,\n model: modelFor(index) ?? executor.model,\n adapter: executor.adapter,\n }));\n}\n\nfunction noEligibleTargets(message: string): LLMError {\n return new LLMError(message, 'invalid_params', { code: 'no_eligible_targets' });\n}\n\n/**\n * Applies `requested` on top of `current`, both by target name. Names in `all` but outside\n * `current` were removed by an outer layer, so they are dropped and reported through `onDropped`\n * rather than added back. `onDropped` is optional since, when `current` is `all`, nothing can have\n * been removed. Throws `invalid_params` before any provider is contacted:\n * `unknown_target` for a name in no target, `no_eligible_targets` for an empty or repeating list\n * or one that ends up empty.\n */\nexport function narrowTargets(\n all: readonly ResolvedTarget[],\n current: readonly ResolvedTarget[],\n requested: readonly string[] | undefined,\n onDropped?: (name: string) => void,\n): ResolvedTarget[] {\n if (requested === undefined) return [...current];\n\n // Only a caller bypassing the types gets here, so this carries no `code`.\n if (!Array.isArray(requested) || requested.some((name) => typeof name !== 'string')) {\n throw new LLMError('`targets` must be an array of target names', 'invalid_params');\n }\n\n if (requested.length === 0 || new Set(requested).size !== requested.length) {\n throw noEligibleTargets('`targets` must name at least one target, each at most once');\n }\n\n const narrowed: ResolvedTarget[] = [];\n\n for (const name of requested) {\n if (!all.some((target) => target.executor.providerName === name)) {\n const valid = all.map((target) => `\"${target.executor.providerName}\"`).join(', ');\n throw new LLMError(`Unknown target \"${name}\". Valid targets: ${valid}`, 'invalid_params', {\n code: 'unknown_target',\n });\n }\n\n const allowed = current.find((target) => target.executor.providerName === name);\n\n if (allowed) narrowed.push(allowed);\n else onDropped?.(name);\n }\n\n if (narrowed.length === 0) {\n throw noEligibleTargets(\n 'No target is left: every requested target was removed by an outer layer',\n );\n }\n\n return narrowed;\n}\n","import { LLMError } from '../../types/errors.js';\nimport { FallbackExhaustedError } from '../../types/fallback.js';\nimport { callScopeFor, noopEmit } from '../utils/callScope.utils.js';\nimport { createDeferred } from '../utils/deferred.utils.js';\nimport { middlewareContextNames } from '../utils/middlewareLabels.utils.js';\nimport { describeTargets, type ResolvedTarget } from './targetOrder.js';\nimport { normalizeError } from './utils/errors.utils.js';\nimport { emitEvent } from './utils/middleware/middleware.utils.js';\n\nimport type { Logger } from '../../logger.js';\nimport type {\n AttemptContext,\n CallParams,\n CallMeta,\n CallResult,\n CallWithToolsResult,\n FallbackAttempt,\n FallbackOn,\n MiddlewareStateBag,\n StreamChunk,\n TargetInfo,\n VernLLMEvent,\n VernLLMMiddleware,\n} from '../../types/index.js';\nimport type { CallExecutor } from './callExecutor.js';\n\n/** What the logical call functions need from `VernLLM`, so they can live outside the class. */\nexport interface LogicalCallDependencies {\n /**\n * The targets this call may try, in the order to try them. Every target as declared, unless the\n * call's `targets` or a `wrap` narrowed or reordered it. Set per call.\n */\n targets: readonly ResolvedTarget[];\n /** Decides whether a failed target is followed by the next one or the chain stops. See `VernLLMOptions['fallbackOn']`. */\n fallbackOn: FallbackOn;\n /** Reports a `'fallback'` event when the chain moves to the next target. */\n reportEvent: (event: VernLLMEvent) => void;\n /** See `VernLLMOptions.middleware`. Already in `transform`/`onEvent` order: `priority`, with `runsAfter`/`runsBefore` resolved first. */\n middleware: VernLLMMiddleware[];\n /** See `VernLLMOptions.middlewareTimeoutMs`. */\n middlewareTimeoutMs: number;\n logger: Logger;\n}\n\n/**\n * The chain's outcome: the winning result, which target answered, its declared index and its\n * position in the order tried, and how many attempts that target made.\n */\nexport interface FallbackChainOutcome<TResult> {\n result: TResult;\n executor: CallExecutor;\n /** Declared index, see `ResolvedTarget`. */\n index: number;\n /** Position in the order tried, 0 based. */\n position: number;\n attemptCount: number;\n /** The model the winning target actually ran, see `modelForTarget`. */\n model: string;\n}\n\n/**\n * The per call `model` override for this target, or `undefined` to use its own. The override names\n * a model on the primary's provider, so a fallback on another provider can only fail with it.\n */\nexport function modelForTarget(\n params: Pick<CallParams<unknown>, 'model'>,\n targetIndex: number,\n): string | undefined {\n return targetIndex === 0 ? params.model : undefined;\n}\n\n/** `params` as the target at `targetIndex` should see it, see `modelForTarget`. */\nexport function paramsForTarget<P extends Pick<CallParams<unknown>, 'model'>>(\n params: P,\n targetIndex: number,\n): P {\n if (targetIndex === 0 || params.model === undefined) return params;\n return { ...params, model: undefined };\n}\n\n/**\n * Tries each of `dependencies.targets` in order until one succeeds. `skipBreakerCheckForFirst` is\n * set when `call()` already checked the sole target, since checking again would see its own\n * claimed trial. Throws the lone failure when one target was tried, else `FallbackExhaustedError`\n * with every attempt. Events and attempts keep declared indices, whatever the order.\n */\nexport async function runFallbackChain<R>(\n dependencies: LogicalCallDependencies,\n params: Pick<CallParams<unknown>, 'model' | 'signal'>,\n requestId: string,\n middlewareState: MiddlewareStateBag,\n attempt: (\n executor: CallExecutor,\n onAttempt: () => void,\n targetIndex: number,\n position: number,\n ) => Promise<R>,\n skipBreakerCheckForFirst = false,\n): Promise<FallbackChainOutcome<R>> {\n const fallbackAttempts: FallbackAttempt[] = [];\n\n const { targets } = dependencies;\n\n for (let position = 0; position < targets.length; position++) {\n const { executor, index: targetIndex } = targets[position]!;\n const targetModel = modelForTarget(params, targetIndex);\n const startedAt = Date.now();\n let attemptCount = 0;\n\n try {\n // Claiming a half-open trial is a side effect, so a target already checked by `call()` isn't\n // checked twice.\n if (!(position === 0 && skipBreakerCheckForFirst)) {\n const checking = executor.assertBreakerClosed(targetModel, {\n requestId,\n state: middlewareState,\n signal: params.signal,\n });\n // Only a breaker with a `prepare` hands back something to wait for.\n if (checking) await checking;\n }\n\n const result = await attempt(\n executor,\n () => {\n attemptCount += 1;\n },\n targetIndex,\n position,\n );\n return {\n result,\n executor,\n index: targetIndex,\n position,\n attemptCount,\n model: targetModel ?? executor.model,\n };\n } catch (error) {\n const normalizedError = normalizeError(error, params.signal);\n\n // Whatever ended this target, a half-open trial it claimed and never\n // settled must not stay held. Idempotent, so this is also safe when\n // the failure was already recorded against the breaker.\n executor.releaseBreakerTrial(targetModel, {\n requestId,\n state: middlewareState,\n signal: params.signal,\n });\n\n fallbackAttempts.push({\n index: targetIndex - 1,\n provider: executor.providerName,\n model: targetModel ?? 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: normalizedError.toSnapshot(),\n });\n\n const isLastTarget = position === targets.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\n // no next executor to fall over to.\n const [failed, next] = describeTargets(targets.slice(position, position + 2), (index) =>\n modelForTarget(params, index),\n ) as [TargetInfo, TargetInfo | undefined];\n const policyDecision = dependencies.fallbackOn(normalizedError, {\n isLastTarget,\n failed,\n ...(next ? { next } : {}),\n });\n const decision = isLastTarget ? '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 fallbackAttempts.length > 1\n ? new FallbackExhaustedError(fallbackAttempts)\n : normalizedError;\n }\n\n reportFallback(dependencies, {\n requestId,\n failed: targets[position]!,\n next: targets[position + 1]!,\n failedModel: targetModel ?? executor.model,\n attempt: attemptCount,\n error: normalizedError,\n elapsedMs: Date.now() - startedAt,\n signal: params.signal,\n middlewareState,\n });\n }\n }\n\n // Unreachable: the loop above always either returns or throws before\n // running out of targets (the last iteration's `isLastTarget` forces\n // a throw). Kept only to satisfy the return type.\n throw new LLMError('No provider targets configured', 'invalid_params');\n}\n\n/**\n * Emits the `'fallback'` event for the `failed` target, moving on to `next`. The context describes\n * the failed target, not the next one. Indices are the declared ones.\n */\nfunction reportFallback(\n dependencies: LogicalCallDependencies,\n failure: {\n requestId: string;\n failed: ResolvedTarget;\n next: ResolvedTarget;\n failedModel: string;\n attempt: number;\n error: LLMError;\n elapsedMs: number;\n signal: AbortSignal | undefined;\n middlewareState: MiddlewareStateBag;\n },\n): void {\n const { requestId, signal } = failure;\n const { executor, index: targetIndex } = failure.failed;\n const nextExecutor = failure.next.executor;\n\n const ctx: AttemptContext = {\n stage: 'attempt',\n requestId,\n requestedProvider: executor.providerName,\n adapter: executor.adapter,\n requestedModel: failure.failedModel,\n isFallbackAttempt: targetIndex > 0,\n // Stays 0 when the breaker check threw before any attempt; the field is 1-based.\n attempt: failure.attempt || 1,\n capabilities: { supportsJsonObjectMode: executor.jsonObjectModeSupported },\n signal,\n state: failure.middlewareState,\n own: {},\n emit: noopEmit,\n context: callScopeFor(failure.middlewareState)?.context,\n ...middlewareContextNames(dependencies.middleware),\n };\n\n emitEvent(\n {\n kind: 'fallback',\n requestId,\n from: executor.providerName,\n to: nextExecutor.providerName,\n fromIndex: targetIndex - 1,\n toIndex: failure.next.index - 1,\n error: failure.error,\n elapsedMs: failure.elapsedMs,\n },\n ctx,\n dependencies.reportEvent,\n dependencies.middleware,\n dependencies.middlewareTimeoutMs,\n dependencies.logger,\n );\n}\n\n/** The `CallResult.meta` fields for whichever target answered. */\nfunction metaFor(\n executor: CallExecutor,\n index: number,\n position: number,\n attemptCount: number,\n model: string,\n): CallMeta {\n return {\n provider: executor.providerName,\n model,\n // Declared, so they keep meaning \"a declared fallback answered\" in any order.\n fallbackIndex: index - 1,\n usedFallback: index > 0,\n attempts: attemptCount,\n position,\n };\n}\n\n/**\n * Builds `CallResult.meta` from the chain's outcome and writes it to `params.meta.current` when\n * given.\n */\nfunction buildCallResult<R>(\n outcome: FallbackChainOutcome<R>,\n params: Pick<CallParams<unknown>, 'meta'>,\n): CallResult<R> {\n const meta = metaFor(\n outcome.executor,\n outcome.index,\n outcome.position,\n outcome.attemptCount,\n outcome.model,\n );\n\n // `params` here is the same object `VernLLM.call()` received from the\n // caller, not a clone, so this write is visible on the caller's own\n // `meta` out-parameter too.\n if (params.meta) {\n params.meta.current = meta;\n }\n\n return { value: outcome.result, meta };\n}\n\n/**\n * The fallback chain and retries of one non-streaming call, without `wrap`. Each caller wraps it\n * once, so no value passes through `wrap` twice.\n */\nexport async function executeLogicalCall<T>(\n dependencies: LogicalCallDependencies,\n params: CallParams<T>,\n requestId: string,\n soleTarget: boolean,\n middlewareState: MiddlewareStateBag,\n): Promise<CallResult<T | CallWithToolsResult<T>>> {\n const fallbackChainOutcome = await runFallbackChain(\n dependencies,\n params,\n requestId,\n middlewareState,\n (executor, onAttempt, targetIndex) =>\n executor.run(paramsForTarget(params, targetIndex), requestId, onAttempt, middlewareState),\n soleTarget,\n );\n\n return buildCallResult(fallbackChainOutcome, params);\n}\n\n/**\n * Streaming counterpart to `executeLogicalCall`. Resolves when the first stream opens, a ping\n * included, while the chain keeps running behind it until content arrives: a failure before content\n * still retries and falls back, and `chunks` and `finalResult` follow whichever attempt answers.\n * `meta` is updated in place once that target is known.\n */\nexport async function executeLogicalStreamCall<T>(\n dependencies: LogicalCallDependencies,\n params: CallParams<T>,\n requestId: string,\n soleTarget: boolean,\n middlewareState: MiddlewareStateBag,\n): Promise<\n CallResult<{\n chunks: AsyncIterable<StreamChunk>;\n finalResult: Promise<T | CallWithToolsResult<T>>;\n }>\n> {\n type Opened = { executor: CallExecutor; index: number; position: number; attempts: number };\n\n const { promise: opened, resolve: resolveOpened } = createDeferred<Opened>();\n\n const chain = runFallbackChain(\n dependencies,\n params,\n requestId,\n middlewareState,\n (executor, onAttempt, targetIndex, position) => {\n let attempts = 0;\n return executor.runStream(\n paramsForTarget(params, targetIndex),\n requestId,\n () => {\n attempts += 1;\n onAttempt();\n },\n middlewareState,\n () => resolveOpened({ executor, index: targetIndex, position, attempts }),\n );\n },\n soleTarget,\n );\n\n // Handled through `finalResult` and `chunks` once the stream has opened.\n chain.catch(() => {});\n\n const first = await Promise.race([\n opened.then((value) => ({ kind: 'opened' as const, value })),\n chain.then((value) => ({ kind: 'settled' as const, value })),\n ]);\n\n if (first.kind === 'settled') return buildCallResult(first.value, params);\n\n const { executor, index, position, attempts } = first.value;\n const meta = metaFor(\n executor,\n index,\n position,\n attempts,\n modelForTarget(params, index) ?? executor.model,\n );\n if (params.meta) params.meta.current = meta;\n\n const finalResult = chain.then((outcome) => {\n // Same object the caller already holds, so a reopened stream shows up in it.\n Object.assign(\n meta,\n metaFor(\n outcome.executor,\n outcome.index,\n outcome.position,\n outcome.attemptCount,\n outcome.model,\n ),\n );\n return outcome.result.finalResult;\n });\n\n // Avoid an unhandled rejection for a caller that only reads `chunks`.\n finalResult.catch(() => {});\n\n const chunks: AsyncIterable<StreamChunk> = {\n async *[Symbol.asyncIterator]() {\n const outcome = await chain;\n yield* outcome.result.chunks;\n },\n };\n\n return { value: { chunks, finalResult }, meta };\n}\n","import { LLMError } from '../../types/errors.js';\nimport {\n executeLogicalCall,\n executeLogicalStreamCall,\n modelForTarget,\n type LogicalCallDependencies,\n} from './logicalCall.js';\nimport { withReservedUsage, withReservedUsageForStream } from './utils/response/usage.utils.js';\nimport { cancelOnBreak } from './utils/stream/earlyExit.utils.js';\n\nimport type { CallMeta, CallParams, CallResult } from '../../types/index.js';\nimport type { MiddlewareStateBag } from '../../types/middleware.js';\n\nexport interface ReservedLogicalCallOptions {\n requestId: string;\n middlewareState: MiddlewareStateBag;\n /** Aborted when the caller leaves `chunks` early. See `setupCallSignal`. */\n breakController: AbortController | undefined;\n onRefundError: (logMessage: string, error: unknown) => void;\n}\n\n/**\n * The part of `call()` inside `wrap`: the sole target breaker check, usage\n * reservation, then the logical call over `dependencies.targets`.\n *\n * With one target the breaker is checked here, before usage is reserved, so a\n * blocked call never pays a reserve and refund round trip. That also covers a\n * call narrowed to one target. With more, the check stays inside\n * `runFallbackChain`, since claiming a half-open trial must happen once per\n * call and an open first target is just another target failure there.\n */\nexport async function runReservedLogicalCall<T>(\n dependencies: LogicalCallDependencies,\n params: CallParams<T>,\n { requestId, middlewareState, breakController, onRefundError }: ReservedLogicalCallOptions,\n): Promise<CallResult> {\n const soleTarget = dependencies.targets.length === 1;\n // The per call `model` override belongs to the primary only, so a sole fallback runs its own.\n const soleModel = modelForTarget(params, dependencies.targets[0]!.index);\n const breakerContext = () => ({ requestId, state: middlewareState, signal: params.signal });\n\n if (soleTarget) {\n // An abort during `wrap` must not claim the trial: the call would then fail\n // before any outcome is recorded and leave the breaker stuck mid-trial.\n if (params.signal?.aborted) {\n throw new LLMError('LLM request aborted', 'aborted');\n }\n\n const checking = dependencies.targets[0]!.executor.assertBreakerClosed(\n soleModel,\n breakerContext(),\n );\n // Only a breaker with `prepare` hands back something to wait for.\n if (checking) await checking;\n }\n\n try {\n let meta: CallMeta | undefined;\n const captureMeta = async <V>(result: Promise<{ value: V; meta?: CallMeta }>) => {\n const settled = await result;\n meta = settled.meta;\n return settled.value;\n };\n\n if (params.stream) {\n // Refund and reporting wait on `finalResult`, since the outcome is only\n // known after `call()` has returned the stream.\n const value = await withReservedUsageForStream(\n params,\n () =>\n captureMeta(\n executeLogicalStreamCall(dependencies, params, requestId, soleTarget, middlewareState),\n ),\n params.signal,\n onRefundError,\n );\n\n // Wrapped inside `wrap`, so middleware hands back the same cancelling `chunks`.\n return { value: cancelOnBreak(value, breakController), meta };\n }\n\n const value = await withReservedUsage(\n params,\n false,\n () =>\n captureMeta(\n executeLogicalCall(dependencies, params, requestId, soleTarget, middlewareState),\n ),\n params.signal,\n onRefundError,\n );\n\n return { value, meta };\n } catch (error) {\n // A trial may have been claimed above; releasing is idempotent if the\n // fallback chain already did.\n if (soleTarget) {\n dependencies.targets[0]!.executor.releaseBreakerTrial(soleModel, breakerContext());\n }\n throw error;\n }\n}\n","import { callScopeFor, noopEmit } from '../utils/callScope.utils.js';\nimport { logError } from '../utils/logger.utils.js';\nimport { modelForTarget } from './logicalCall.js';\nimport { describeTargets, narrowTargets, type ResolvedTarget } from './targetOrder.js';\nimport {\n emitEvent,\n reclassifyMiddlewareThrow,\n middlewareLabel,\n resolveEnabled,\n withOwn,\n} from './utils/middleware/middleware.utils.js';\nimport { createOnceAsync } from './utils/once.utils.js';\n\nimport type { Logger } from '../../logger.js';\nimport type {\n CallParams,\n CallResult,\n MiddlewareStateBag,\n PreDispatchContext,\n VernLLMEvent,\n} from '../../types/index.js';\nimport type { MiddlewarePipeline } from '../resolveMiddlewareOrder.js';\nimport type { CallExecutor } from './callExecutor.js';\n\n/**\n * Everything `runOperation` needs from `VernLLM` itself, gathered into\n * one small object so it can live outside the class as a plain,\n * independently testable function instead of a private method.\n */\nexport interface RunOperationDependencies {\n /**\n * Middleware order, built once at construction. `wrap` nests by `wrapOrder`; labels and events\n * use `transformOrder`.\n */\n pipeline: MiddlewarePipeline;\n /** The primary target, used to build the `previewRequest` handed to every `wrap` (and the `primaryProvider`/`primaryModel` its `ctx` carries). */\n primaryExecutor: CallExecutor;\n /** Every configured target in declared order, the pool a `wrap`'s `next({ targets })` picks from. */\n targets: readonly ResolvedTarget[];\n /** See `VernLLMOptions.middlewareTimeoutMs`. Bounds `transform` and a function `enabled`; `wrap` itself is never bounded by this. */\n middlewareTimeoutMs: number;\n logger: Logger;\n /** Reports the `'middleware'` trace event for an `enabled_skip` or `wrap_short_circuit`. */\n reportEvent: (event: VernLLMEvent) => void;\n}\n\n/**\n * Wraps one whole logical call in every applicable `wrap`, lower priority outermost. `ctx` is a\n * `PreDispatchContext` with a preview request from the primary, since no attempt has started yet.\n * A `wrap` that never calls `next()` skips everything inside it.\n *\n * `targets` is the order the call starts with. Each `wrap` sees it as `ctx.targets` and may\n * reorder or drop through `next({ targets })`, never widen it, and `coreOperation` runs the order\n * that is left.\n */\nexport async function runOperation(\n dependencies: RunOperationDependencies,\n params: CallParams<unknown>,\n requestId: string,\n state: MiddlewareStateBag,\n targets: readonly ResolvedTarget[],\n coreOperation: (targets: readonly ResolvedTarget[]) => Promise<CallResult>,\n /**\n * True when `cachedCall()` already wraps this call, so `wrap` runs once per logical call. Keyed\n * by the params object, not `requestId`, since concurrent `cachedCall()`s can share one.\n */\n skipWrap = false,\n): Promise<CallResult> {\n const { wrapOrder, transformOrder, names, transformNames } = dependencies.pipeline;\n\n if (wrapOrder.length === 0 || skipWrap) {\n return coreOperation(targets);\n }\n\n const primary = dependencies.primaryExecutor;\n const { model, request } = primary.previewRequest(params);\n\n // `position` can reorder `wrapOrder`, so labels come from each entry's `transformOrder` index to\n // match `registeredMiddlewareNames`.\n const transformIndexByEntry = new Map(transformOrder.map((entry, index) => [entry, index]));\n\n // Each level takes the order left by the levels outside it.\n let next: (current: readonly ResolvedTarget[]) => Promise<CallResult> = coreOperation;\n\n for (let middlewareIndex = wrapOrder.length - 1; middlewareIndex >= 0; middlewareIndex--) {\n const middleware = wrapOrder[middlewareIndex]!;\n const label = middlewareLabel(middleware, transformIndexByEntry.get(middleware)!);\n const inner = next;\n\n next = async (current): Promise<CallResult> => {\n const ctx: PreDispatchContext = {\n stage: 'pre-dispatch',\n requestId,\n primaryProvider: primary.providerName,\n primaryAdapter: primary.adapter,\n primaryModel: model,\n targets: describeTargets(current, (index) => modelForTarget(params, index)),\n capabilities: { supportsJsonObjectMode: primary.jsonObjectModeSupported },\n signal: params.signal,\n state,\n own: {},\n emit: noopEmit,\n context: callScopeFor(state)?.context,\n registeredMiddlewareNames: names,\n transformMiddlewareNames: transformNames,\n };\n\n const isEnabled = await resolveEnabled(\n middleware,\n ctx,\n label,\n dependencies.middlewareTimeoutMs,\n dependencies.logger,\n );\n\n if (!isEnabled) {\n if (middleware.enabled !== undefined) {\n emitEvent(\n { kind: 'middleware', requestId, middleware: label, hook: 'enabled_skip' },\n ctx,\n dependencies.reportEvent,\n transformOrder,\n dependencies.middlewareTimeoutMs,\n dependencies.logger,\n );\n }\n return inner(current);\n }\n\n if (!middleware.wrap) return inner(current);\n\n // The first `next()` call runs `inner` and reads this synchronously, so a later call's\n // options change nothing, like its result.\n let requested: readonly string[] | undefined;\n const onceNext = createOnceAsync(async () =>\n inner(\n narrowTargets(dependencies.targets, current, requested, (name) =>\n dependencies.logger.warn(\n `[VernLLM:${requestId}] middleware \"${label}\" asked for target \"${name}\", which an outer layer removed; ignoring it`,\n ),\n ),\n ),\n );\n const wrapNext = (options?: { targets?: readonly string[] }): Promise<CallResult> => {\n requested = options?.targets;\n return onceNext.call();\n };\n\n try {\n const result = await middleware.wrap(request, wrapNext, withOwn(ctx, middleware, label));\n\n if (!onceNext.wasCalled()) {\n emitEvent(\n { kind: 'middleware', requestId, middleware: label, hook: 'wrap_short_circuit' },\n ctx,\n dependencies.reportEvent,\n transformOrder,\n dependencies.middlewareTimeoutMs,\n dependencies.logger,\n );\n }\n\n return result;\n } catch (error) {\n const resolvedResult = onceNext.resolvedValue();\n\n if (resolvedResult !== undefined) {\n // Rule 3: thrown strictly after next() already resolved\n // successfully. A bug in post-processing can never turn a\n // successful, already-billed call into a false failure.\n logError(\n dependencies.logger,\n `[VernLLM] middleware \"${label}\".wrap threw after next() resolved; keeping the original result`,\n error,\n );\n return resolvedResult;\n }\n\n // Rules 1/2: thrown before next() was called, or before it\n // resolved. Passed through normalizeError first so a\n // recognizable status/network error, or an already-built\n // LLMError, keeps its own classification.\n throw reclassifyMiddlewareThrow(error, label, ctx.signal);\n }\n };\n }\n\n return next(targets);\n}\n","import { setupDeadline } from './deadline.utils.js';\n\n/** One signal that aborts when any given signal does, or `undefined` when none is given. */\nexport function combineSignals(\n signals: readonly (AbortSignal | undefined)[],\n): AbortSignal | undefined {\n const present = signals.filter((signal): signal is AbortSignal => signal !== undefined);\n return present.length > 1 ? AbortSignal.any(present) : present[0];\n}\n\nexport interface CallSignalSetup<P> {\n /** `params` with the effective signal, or `params` itself when nothing was added. */\n params: P;\n signal: AbortSignal | undefined;\n /** Aborted when the caller stops reading `chunks` early. Only set for a cancellable stream. */\n breakController: AbortController | undefined;\n dispose: () => void;\n}\n\n/**\n * Joins the caller signal, a break controller for streams, and `deadlineMs` into the\n * one signal the rest of the call reads. `cancellable` is false for `cachedCall()`'s\n * inner call, whose stream is shared and left by the cache instead.\n */\nexport function setupCallSignal<\n P extends { signal?: AbortSignal; deadlineMs?: number; stream?: boolean },\n>(params: P, cancellable: boolean): CallSignalSetup<P> {\n const breakController = params.stream && cancellable ? new AbortController() : undefined;\n const { signal, timer } = setupDeadline(\n params.deadlineMs,\n combineSignals([params.signal, breakController?.signal]),\n );\n\n return {\n params: signal === params.signal ? params : { ...params, signal },\n signal,\n breakController,\n dispose: () => clearTimeout(timer),\n };\n}\n","import { isJson, type CallScope } from '../../../utils/callScope.utils.js';\nimport { emitEvent } from './middleware.utils.js';\n\nimport type { Logger } from '../../../../logger.js';\nimport type { CallContext, VernLLMEvent, VernLLMMiddleware } from '../../../../types/index.js';\n\n/** The most `custom` events one call delivers. Anything past it is dropped, with one warning. */\nexport const MAX_CUSTOM_EVENTS_PER_CALL = 100;\n\n/** What `createCallScope` needs to deliver an event, all of it fixed for the instance. */\nexport interface CallScopeDependencies {\n reportEvent: (event: VernLLMEvent) => void;\n /** Already in `onEvent` order. */\n middleware: VernLLMMiddleware[];\n middlewareTimeoutMs: number;\n logger: Logger;\n}\n\ntype DropReason = 'invalid' | 'reentrant' | 'limit';\n\n/**\n * The scope for one logical call, holding its `context`. `emitCustom` validates the event and delivers it through the\n * same `emitEvent` every other event uses, so it reaches `onEvent` and every enabled\n * middleware's `onEvent`, the emitter included.\n *\n * A handler can emit from inside `onEvent`, so two guards keep that from looping: an emit made\n * synchronously while a custom event is being delivered is dropped, and a call delivers at most\n * `MAX_CUSTOM_EVENTS_PER_CALL`. The second also covers a loop through an async `enabled`, whose\n * delivery is deferred and so escapes the first. Each drop is warned once per call.\n */\nexport function createCallScope(\n dependencies: CallScopeDependencies,\n context: CallContext | undefined,\n): CallScope {\n const { reportEvent, middleware, middlewareTimeoutMs, logger } = dependencies;\n\n let delivered = 0;\n let delivering = false;\n const warned = new Set<DropReason>();\n\n return {\n context,\n emitCustom(name, data, source, ctx) {\n const drop = (reason: DropReason, message: string): void => {\n if (warned.has(reason)) return;\n\n warned.add(reason);\n logger.warn(`[VernLLM:${ctx.requestId}] middleware \"${source}\" ${message}`);\n };\n\n if (!isValidCustomEvent(name, data)) {\n drop(\n 'invalid',\n 'called ctx.emit with an empty name or data that is not plain JSON, dropping the event',\n );\n return;\n }\n\n if (delivering) {\n drop(\n 'reentrant',\n `emitted \"${name}\" while a custom event was being delivered, dropping it`,\n );\n return;\n }\n\n if (delivered >= MAX_CUSTOM_EVENTS_PER_CALL) {\n drop(\n 'limit',\n `emitted more than ${MAX_CUSTOM_EVENTS_PER_CALL} custom events in one call, dropping the rest`,\n );\n return;\n }\n\n delivered++;\n delivering = true;\n\n try {\n emitEvent(\n {\n kind: 'custom',\n requestId: ctx.requestId,\n name,\n source,\n ...(data === undefined ? {} : { data }),\n },\n ctx,\n reportEvent,\n middleware,\n middlewareTimeoutMs,\n logger,\n );\n } finally {\n delivering = false;\n }\n },\n };\n}\n\n/** `data` may be absent. A throw, from data nested deep enough to overflow the stack, is invalid. */\nfunction isValidCustomEvent(name: unknown, data: unknown): boolean {\n if (typeof name !== 'string' || name === '') return false;\n\n try {\n return data === undefined || isJson(data);\n } catch {\n return false;\n }\n}\n","import { fullJitter } from '../../execution/utils/retry/retry.utils.js';\n\nimport type {\n CircuitBreakerCallContext,\n CircuitState,\n CooldownBackoff,\n ExponentialBackoffOptions,\n} from '../../../circuitBreaker.js';\nimport type { LLMErrorCode } from '../../../types/errors.js';\n\n/**\n * Jitters only the growth above `baseCooldownMs`, so several\n * instances don't reopen in lockstep but none ever cools down for less\n * than the configured base.\n */\nexport function buildCooldownBackoff(\n option: ExponentialBackoffOptions | CooldownBackoff | undefined,\n): CooldownBackoff | undefined {\n if (option === undefined) return undefined;\n if (typeof option === 'function') return option;\n\n const { multiplier, maxMs = Infinity } = option;\n return (reopenCount, baseCooldownMs) => {\n const exp = Math.min(baseCooldownMs * multiplier ** reopenCount, maxMs);\n // Only an explicit `maxMs` below the base may lower the floor; a\n // shrinking `multiplier` must not. The ternary also maps a NaN `exp` to the floor.\n const floor = Math.min(baseCooldownMs, maxMs);\n const upper = exp > floor ? exp : floor;\n return floor + fullJitter(upper - floor);\n };\n}\n\n/** Mutable state for one circuit, either the single shared one or one model's bucket under `isolateByModel`. */\nexport interface CircuitBucket {\n state: CircuitState;\n /** True consecutive failures since the last success. Reporting only, independent of `tripping`. */\n consecutiveFailures: number;\n openedAt: number;\n /** Non null only while `state` is half-open. */\n trial: { slotsRemaining: number; successes: number; failures: number } | null;\n /** Times this bucket has reopened after a failed trial. Feeds `cooldownBackoff`. */\n reopenCount: number;\n /** Failure counts by `LLMErrorCode`, `'unknown'` for a missing code. Attribution only. */\n failuresByReason: Map<LLMErrorCode | 'unknown', number>;\n /** Cooldown for this open period, sampled once so a jittered value doesn't change mid-cooldown. */\n cooldownMsForOpen: number;\n /** Breaker-wide generation this bucket last opened in, 0 if never opened. */\n openedInGeneration: number;\n}\n\nexport function newBucket(): CircuitBucket {\n return {\n state: 'closed',\n consecutiveFailures: 0,\n openedAt: 0,\n trial: null,\n reopenCount: 0,\n failuresByReason: new Map(),\n cooldownMsForOpen: 0,\n openedInGeneration: 0,\n };\n}\n\n/** Key a bucket lookup falls into when the call omitted `model` under `isolateByModel`. Also the `tripping` key for the single shared bucket when `isolateByModel` is off. */\nexport const UNLABELED_MODEL = '';\n\n/** Resolves the map key for a model, collapsing an omitted `model` to `UNLABELED_MODEL`. */\nexport function keyFor(model: string | undefined): string {\n return model ?? UNLABELED_MODEL;\n}\n\n/** Maps a call's `state` to the trial object it claimed a slot in, so a stale permit can be told apart from a current one. */\nexport const trialPermits = new WeakMap<object, object>();\n\n/** True if this outcome's call claimed a permit for `bucket`'s current trial. No `context` always counts, matching pre-permit-tracking behavior. */\nexport function claimsCurrentTrial(\n bucket: CircuitBucket,\n context: CircuitBreakerCallContext | undefined,\n): boolean {\n if (!context) return true;\n return trialPermits.get(context.state) === bucket.trial;\n}\n\n/** Records `code` (or `'unknown'` if omitted) against `bucket.failuresByReason`. */\nexport function attributeFailure(bucket: CircuitBucket, code: LLMErrorCode | undefined): void {\n const key = code ?? 'unknown';\n bucket.failuresByReason.set(key, (bucket.failuresByReason.get(key) ?? 0) + 1);\n}\n\n/** Clears a bucket's failure history, as every return to closed does. */\nexport function resetBucket(bucket: CircuitBucket): void {\n bucket.consecutiveFailures = 0;\n bucket.trial = null;\n bucket.reopenCount = 0;\n bucket.failuresByReason.clear();\n}\n","import { RollingRatio } from './internal/rollingRatio.js';\nimport {\n attributeFailure,\n buildCooldownBackoff,\n claimsCurrentTrial,\n keyFor,\n newBucket,\n resetBucket,\n trialPermits,\n UNLABELED_MODEL,\n type CircuitBucket,\n} from './internal/utils/circuit-breaker/circuitBucket.utils.js';\nimport { validateMinCalls, validateRatio } from './internal/utils/validate.utils.js';\nimport { LLMError, type LLMErrorCode } from './types/errors.js';\n\nimport type { Logger } from './logger.js';\nimport type { MiddlewareStateBag } from './types/middleware.js';\n\n/** The call this mutation happened as part of, forwarded to `onStateChange` untouched. */\nexport interface CircuitBreakerCallContext {\n requestId: string;\n state: MiddlewareStateBag;\n signal?: AbortSignal;\n /** Omitted for calls before any attempt exists, like `assertClosed`'s pre-dispatch check. */\n attempt?: number;\n}\n\n/**\n * Fires after every real state change. `model` is the triggering call's resolved model. Shared by\n * the options and the adapter interface, so custom adapters report changes the same way.\n */\nexport type CircuitBreakerStateChangeHandler = (\n from: CircuitState,\n to: CircuitState,\n consecutiveFailures: number,\n model?: string,\n context?: CircuitBreakerCallContext,\n) => void;\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 onStateChange?: CircuitBreakerStateChangeHandler;\n /**\n * Track a separate circuit per resolved model instead of one shared\n * circuit. Default false. A call that omits `model` falls into one\n * shared bucket alongside every other call that also omits it.\n */\n isolateByModel?: boolean;\n /** Trial calls allowed through per half-open cycle. Default 1, clamped to at least 1. */\n halfOpenProbes?: number;\n /** Fraction of `halfOpenProbes` that must succeed to close the circuit. Default 1, clamped to `[0, 1]`. */\n halfOpenSuccessRatio?: number;\n /**\n * Grows `cooldownMs` on each repeat open instead of a fixed wait.\n * `{ multiplier, maxMs }` covers exponential growth; a `CooldownBackoff`\n * function covers anything else. Omitted means `cooldownMs` stays fixed.\n */\n cooldownBackoff?: ExponentialBackoffOptions | CooldownBackoff;\n /**\n * When failures open the circuit. `{ kind: 'consecutive', threshold }` (default) opens after that\n * many in a row; `{ kind: 'rolling', windowMs, minCalls, failureRatio }` opens once `minCalls`\n * calls in the window reach `failureRatio`. Invalid values throw `RangeError` at construction. A\n * custom `TrippingPolicy` is shared across models, keyed per model.\n */\n tripping?: TrippingOption;\n}\n\n/** Computes the cooldown for a bucket's `reopenCount`-th repeat open. */\nexport type CooldownBackoff = (reopenCount: number, baseCooldownMs: number) => number;\n\nexport interface ExponentialBackoffOptions {\n /** Growth factor applied per repeat open, e.g. 2 doubles each time. */\n multiplier: number;\n /** Upper bound on the computed cooldown, in ms. Default `Infinity`. */\n maxMs?: number;\n}\n\n/**\n * Decides when failures open the circuit. Keyed by model (or one shared key), so one instance\n * serves every bucket.\n */\nexport interface TrippingPolicy {\n onSuccess(key: string): void;\n /** Returns true if this failure should open the circuit for `key`. */\n onFailure(key: string): boolean;\n reset(key: string): void;\n /**\n * Called when `key`'s circuit is reset closed, so a keyed policy can drop that key's state. Not\n * called on an ordinary success, whose state a rolling window still needs.\n */\n forget?(key: string): void;\n}\n\nexport class ConsecutiveTripping implements TrippingPolicy {\n private failuresByKey = new Map<string, number>();\n\n constructor(private readonly threshold: number) {}\n\n onSuccess(key: string): void {\n // Delete rather than store 0: same count, and an idle key holds no memory.\n this.failuresByKey.delete(key);\n }\n\n onFailure(key: string): boolean {\n const next = (this.failuresByKey.get(key) ?? 0) + 1;\n this.failuresByKey.set(key, next);\n return next >= this.threshold;\n }\n\n reset(key: string): void {\n this.failuresByKey.set(key, 0);\n }\n\n forget(key: string): void {\n this.failuresByKey.delete(key);\n }\n}\n\nexport class RollingTripping implements TrippingPolicy {\n private ratiosByKey = new Map<string, RollingRatio>();\n\n constructor(\n private readonly windowMs: number,\n private readonly minCalls: number,\n private readonly failureRatio: number,\n ) {\n // Fail at construction rather than on the first recorded outcome.\n new RollingRatio(windowMs);\n validateMinCalls(minCalls);\n validateRatio(failureRatio, 'failureRatio');\n }\n\n private ratioFor(key: string): RollingRatio {\n let ratio = this.ratiosByKey.get(key);\n if (!ratio) {\n ratio = new RollingRatio(this.windowMs);\n this.ratiosByKey.set(key, ratio);\n }\n return ratio;\n }\n\n onSuccess(key: string): void {\n this.ratioFor(key).record(false);\n }\n\n onFailure(key: string): boolean {\n const ratio = this.ratioFor(key);\n ratio.record(true);\n return ratio.getCount() >= this.minCalls && ratio.getRatio() >= this.failureRatio;\n }\n\n reset(key: string): void {\n this.ratiosByKey.delete(key);\n }\n\n forget(key: string): void {\n this.ratiosByKey.delete(key);\n }\n}\n\n/** Not exported. Internal shorthand union for `CircuitBreakerOptions.tripping`. */\ntype TrippingOption =\n | { kind: 'consecutive'; threshold: number }\n | { kind: 'rolling'; windowMs: number; minCalls: number; failureRatio: number }\n | TrippingPolicy;\n\n/** Resolves the shorthand into a real `TrippingPolicy`. One instance total, shared safely across every bucket since it's keyed. */\nfunction buildTripping(option: TrippingOption): TrippingPolicy {\n if ('onFailure' in option) return option;\n\n return option.kind === 'consecutive'\n ? new ConsecutiveTripping(option.threshold)\n : new RollingTripping(option.windowMs, option.minCalls, option.failureRatio);\n}\n\nexport type CircuitState = 'closed' | 'open' | 'half-open';\n\n/**\n * What VernLLM needs from a breaker. Pass your own for cross-process coordination. `onStateChange`\n * is required so `circuit_state` events can't go missing; `() => {}` is fine. Omitting an optional\n * member makes that call a no-op, as with no breaker. `open` and `close` are optional, since a\n * distributed adapter may not allow forced transitions.\n */\nexport interface CircuitBreakerAdapter {\n /** Throws when the circuit is open (or half open with no trial slot free) for `model`. */\n assertClosed(model?: string, context?: CircuitBreakerCallContext): void;\n recordSuccess(model?: string, context?: CircuitBreakerCallContext): void;\n /** `code`, when present, is the failing call's `LLMErrorCode`. */\n recordFailure(model?: string, context?: CircuitBreakerCallContext, code?: LLMErrorCode): void;\n getState?(model?: string): CircuitState;\n /** Failure counts by `LLMErrorCode` for `model`'s bucket, `'unknown'` for one that carried no code. */\n getFailureBreakdown?(model?: string): Partial<Record<LLMErrorCode | 'unknown', number>>;\n /** Whether this adapter tracks failures per model, mirroring `CircuitBreakerOptions.isolateByModel`. Read by `warnIfModelUnsupported`'s diagnostic warning and by `VernLLM.getCircuitStates()`'s public output; omit if the notion doesn't apply to your adapter, `false` is assumed. */\n isolateByModel?: boolean;\n /** Manually opens the circuit, as if enough consecutive failures had just happened. Optional: an adapter that doesn't want external callers forcing a transition can omit it. */\n open?(model?: string, context?: CircuitBreakerCallContext): void;\n /** Manually closes the circuit, without requiring a real success first. Same opt-in reasoning as `open`. */\n close?(model?: string, context?: CircuitBreakerCallContext): void;\n /** Gives back a half-open trial slot when a call ends without `recordSuccess` or `recordFailure`. Idempotent, and a no-op for a call that holds no slot. */\n releaseTrial?(model?: string, context?: CircuitBreakerCallContext): void;\n /** Awaited right before `assertClosed` to refresh local state. Never blocks or fails a call: a rejection or `prepareTimeoutMs` is logged and the call carries on. */\n prepare?(model?: string, context?: CircuitBreakerCallContext): Promise<void>;\n /** How long to wait for `prepare`, in ms. Default 1000. */\n prepareTimeoutMs?: number;\n /** Live counterpart of `getState`, read by `VernLLM.readCircuitStates()`. */\n readState?(model?: string): Promise<CircuitState>;\n /** Receives the instance's `Logger` once, when `VernLLM` wires this adapter in. */\n setLogger?(logger: Logger): void;\n /**\n * Called after every real state change, after VernLLM reports its `circuit_state` event. A throw\n * here is caught and logged.\n */\n onStateChange: CircuitBreakerStateChangeHandler;\n}\n\n/**\n * Per retry VernLLM-instance circuit breaker. Tracks consecutive failures\n * across calls. Once the threshold is hit, short-circuits new calls with\n * LLMError('circuit_open') until the cooldown elapses and a trial succeeds.\n */\nexport class CircuitBreaker implements CircuitBreakerAdapter {\n private readonly cooldownMs: number;\n /** Satisfies `CircuitBreakerAdapter.onStateChange`, required there. Defaults to a no-op when `options.onStateChange` is omitted. */\n readonly onStateChange: CircuitBreakerStateChangeHandler;\n /** Whether this breaker tracks failures per model instead of one shared circuit. */\n readonly isolateByModel: boolean;\n private readonly halfOpenProbes: number;\n private readonly halfOpenSuccessRatio: number;\n private readonly cooldownBackoff?: CooldownBackoff;\n /** One instance, keyed per model internally. See `TrippingPolicy`. */\n private readonly tripping: TrippingPolicy;\n\n // Exactly one of these is used, chosen once at construction by `isolateByModel`.\n private readonly sharedBucket: CircuitBucket = newBucket();\n private readonly bucketsByModel = new Map<string, CircuitBucket>();\n\n /**\n * Breaker-wide rather than per bucket, since an evicted bucket is\n * recreated with no history and a per bucket generation would restart.\n */\n private generation = 0;\n /** Each call's generation at admission, keyed by its `state`, so its outcome can be told apart from a later generation's. */\n private readonly admittedInGeneration = new WeakMap<object, number>();\n\n constructor(options: CircuitBreakerOptions = {}) {\n const threshold = options.threshold ?? 5;\n this.cooldownMs = options.cooldownMs ?? 30_000;\n this.onStateChange = options.onStateChange ?? (() => {});\n this.isolateByModel = options.isolateByModel ?? false;\n // Clamped rather than thrown, same as `TokenBucket.give`.\n const rawProbes = options.halfOpenProbes;\n this.halfOpenProbes = Number.isFinite(rawProbes) ? Math.max(1, Math.floor(rawProbes!)) : 1;\n\n const rawRatio = options.halfOpenSuccessRatio;\n this.halfOpenSuccessRatio = Number.isFinite(rawRatio) ? Math.min(1, Math.max(0, rawRatio!)) : 1;\n\n this.cooldownBackoff = buildCooldownBackoff(options.cooldownBackoff);\n this.tripping = buildTripping(options.tripping ?? { kind: 'consecutive', threshold });\n }\n\n /**\n * Throws if the circuit is open and the cooldown hasn't elapsed, or if\n * half-open with every trial slot claimed. Otherwise claims a trial slot.\n */\n assertClosed(model?: string, context?: CircuitBreakerCallContext): void {\n const bucket = this.ensureBucketFor(model);\n\n if (bucket.state === 'closed') {\n this.markAdmitted(context);\n return;\n }\n\n if (bucket.state === 'open') {\n const elapsed = Date.now() - bucket.openedAt;\n const cooldown = bucket.cooldownMsForOpen;\n if (elapsed < cooldown) {\n throw new LLMError(\n `Circuit open, provider has failed ${bucket.consecutiveFailures} times in a row. Retry in ${Math.ceil((cooldown - elapsed) / 1000)}s.`,\n 'circuit_open',\n { code: 'circuit_cooling_down' },\n );\n }\n\n // Set before transition() so a synchronous re-entrant caller sees the slot as already claimed.\n bucket.trial = { slotsRemaining: this.halfOpenProbes - 1, successes: 0, failures: 0 };\n if (context) trialPermits.set(context.state, bucket.trial);\n this.markAdmitted(context);\n this.transition(bucket, 'half-open', model, context);\n return;\n }\n\n // state === 'half-open'\n if (!bucket.trial || bucket.trial.slotsRemaining <= 0) {\n throw new LLMError(\n 'Circuit half-open. Every trial slot is already in flight. Try again shortly.',\n 'circuit_open',\n { code: 'circuit_trial_in_flight' },\n );\n }\n\n bucket.trial.slotsRemaining -= 1;\n if (context) trialPermits.set(context.state, bucket.trial);\n this.markAdmitted(context);\n }\n\n recordSuccess(model?: string, context?: CircuitBreakerCallContext): void {\n const bucket = this.lookupBucket(model);\n\n if (!bucket) {\n return;\n }\n\n if (this.isFromEarlierGeneration(bucket, context)) return;\n\n if (bucket.state === 'half-open' && bucket.trial && claimsCurrentTrial(bucket, context)) {\n // Outcome recorded, so this call's permit is spent: a later\n // `releaseTrial` for the same call must not hand its slot back.\n if (context) trialPermits.delete(context.state);\n bucket.trial.successes += 1;\n this.settleTrialIfComplete(bucket, model, context);\n return;\n }\n\n // Stale trial permit: ignore, don't settle a trial it wasn't part of.\n if (bucket.state === 'half-open') return;\n\n // A call admitted before the circuit opened can finish after it. Only\n // a half-open trial may close an open circuit, never a late straggler.\n if (bucket.state === 'open') return;\n\n resetBucket(bucket);\n this.tripping.onSuccess(this.trippingKeyFor(model));\n this.transition(bucket, 'closed', model, context);\n\n // Drop only the idle bucket. The tripping state stays, since a rolling\n // window must keep this success and earlier failures to ever trip.\n if (this.isolateByModel && bucket.state === 'closed' && bucket.consecutiveFailures === 0) {\n this.dropBucket(model);\n }\n }\n\n /** `code`, when present, is the failing `LLMError`'s `code`. Missing attributes to `'unknown'`. */\n recordFailure(model?: string, context?: CircuitBreakerCallContext, code?: LLMErrorCode): void {\n const bucket = this.ensureBucketFor(model);\n\n if (this.isFromEarlierGeneration(bucket, context)) return;\n\n if (bucket.state === 'half-open' && bucket.trial && claimsCurrentTrial(bucket, context)) {\n if (context) trialPermits.delete(context.state);\n bucket.trial.failures += 1;\n attributeFailure(bucket, code);\n this.settleTrialIfComplete(bucket, model, context);\n return;\n }\n\n // Stale trial permit: ignore, don't fall through to the closed-state counter below.\n if (bucket.state === 'half-open') return;\n\n // A late failure from a call admitted before the circuit opened would\n // otherwise re-trip it, restamping `openedAt` and extending the cooldown.\n if (bucket.state === 'open') return;\n\n bucket.consecutiveFailures += 1;\n attributeFailure(bucket, code);\n\n if (this.tripping.onFailure(this.trippingKeyFor(model))) {\n this.openBucket(bucket, model, context);\n }\n }\n\n /**\n * Gives back the trial slot `context`'s call claimed when it ended without an outcome. Safe to\n * call on any failure path: a no-op without a live permit.\n */\n releaseTrial(model?: string, context?: CircuitBreakerCallContext): void {\n if (!context) return;\n\n const bucket = this.lookupBucket(model);\n if (!bucket || bucket.state !== 'half-open' || !bucket.trial) return;\n if (!claimsCurrentTrial(bucket, context)) return;\n\n trialPermits.delete(context.state);\n bucket.trial.slotsRemaining += 1;\n }\n\n /**\n * The current state. Ignores `model` unless isolated by model. An open circuit past its cooldown\n * reports `'half-open'`, though the real transition waits for the next call.\n */\n getState(model?: string): CircuitState {\n const bucket = this.lookupBucket(model);\n if (!bucket) return 'closed';\n if (bucket.state === 'open' && Date.now() - bucket.openedAt >= bucket.cooldownMsForOpen) {\n return 'half-open';\n }\n return bucket.state;\n }\n\n /** Failure counts by `LLMErrorCode` for `model`'s bucket. Returned as a plain object copy. */\n getFailureBreakdown(model?: string): Partial<Record<LLMErrorCode | 'unknown', number>> {\n const bucket = this.lookupBucket(model);\n return bucket ? Object.fromEntries(bucket.failuresByReason) : {};\n }\n\n /** Manually opens the circuit, as if `threshold` consecutive failures had just happened. */\n open(model?: string, context?: CircuitBreakerCallContext): void {\n const bucket = this.ensureBucketFor(model);\n bucket.trial = null;\n this.openBucket(bucket, model, context);\n }\n\n /** Manually closes the circuit and resets its failure count, without requiring a real success first. */\n close(model?: string, context?: CircuitBreakerCallContext): void {\n const bucket = this.ensureBucketFor(model);\n\n resetBucket(bucket);\n this.tripping.reset(this.trippingKeyFor(model));\n this.transition(bucket, 'closed', model, context);\n\n // transition() may have synchronously re-entered, so re-check state rather than assuming it still holds.\n if (this.isolateByModel && bucket.state === 'closed' && bucket.consecutiveFailures === 0) {\n this.forgetModel(model);\n }\n }\n\n /**\n * Stamps the open time and cooldown, then transitions to open. Callers have already cleared\n * `trial`.\n */\n private openBucket(\n bucket: CircuitBucket,\n model: string | undefined,\n context: CircuitBreakerCallContext | undefined,\n ): void {\n bucket.openedAt = Date.now();\n bucket.cooldownMsForOpen = this.computeCooldown(bucket);\n bucket.openedInGeneration = ++this.generation;\n this.transition(bucket, 'open', model, context);\n }\n\n /** Computes and clamps the cooldown for `bucket`'s current `reopenCount`. Called once, on open. */\n private computeCooldown(bucket: CircuitBucket): number {\n if (!this.cooldownBackoff) return this.cooldownMs;\n\n const computed = this.cooldownBackoff(bucket.reopenCount, this.cooldownMs);\n if (Number.isNaN(computed)) return 0;\n return Math.max(0, computed);\n }\n\n private markAdmitted(context: CircuitBreakerCallContext | undefined): void {\n if (context) this.admittedInGeneration.set(context.state, this.generation);\n }\n\n /**\n * True if this call was admitted before `bucket` last opened, so its outcome belongs to an ended\n * generation. A call without context always counts.\n */\n private isFromEarlierGeneration(\n bucket: CircuitBucket,\n context: CircuitBreakerCallContext | undefined,\n ): boolean {\n if (!context) return false;\n const admitted = this.admittedInGeneration.get(context.state);\n return admitted !== undefined && admitted < bucket.openedInGeneration;\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 return this.bucketsByModel.get(keyFor(model));\n }\n\n /**\n * The key for `tripping`: per model when isolated by model, otherwise one shared key, matching\n * which bucket a call lands in.\n */\n private trippingKeyFor(model: string | undefined): string {\n return this.isolateByModel ? keyFor(model) : UNLABELED_MODEL;\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 = keyFor(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 /** Drops an idle model's bucket, keeping its tripping state. */\n private dropBucket(model: string | undefined): void {\n this.bucketsByModel.delete(keyFor(model));\n }\n\n /** Drops a reset model's bucket and lets `tripping` release that key's state too. */\n private forgetModel(model: string | undefined): void {\n this.dropBucket(model);\n this.tripping.forget?.(this.trippingKeyFor(model));\n }\n\n /** Every state mutation routes through here, so `onStateChange` fires exactly once per real change. */\n private transition(\n bucket: CircuitBucket,\n to: CircuitState,\n model: string | undefined,\n context: CircuitBreakerCallContext | undefined,\n ): 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, context);\n }\n\n /** Once every admitted trial has reported in, closes or reopens based on `halfOpenSuccessRatio`. */\n private settleTrialIfComplete(\n bucket: CircuitBucket,\n model: string | undefined,\n context: CircuitBreakerCallContext | undefined,\n ): void {\n const trial = bucket.trial;\n if (!trial || trial.successes + trial.failures < this.halfOpenProbes) return;\n\n const ratio = trial.successes / this.halfOpenProbes;\n bucket.trial = null;\n\n if (ratio >= this.halfOpenSuccessRatio) {\n resetBucket(bucket);\n // Reset rather than record a success, so failures from before the\n // circuit opened can't push a rolling window straight back over\n // its threshold. Same as the manual `close()`.\n this.tripping.reset(this.trippingKeyFor(model));\n this.transition(bucket, 'closed', model, context);\n\n if (this.isolateByModel && bucket.state === 'closed') {\n this.forgetModel(model);\n }\n return;\n }\n\n // Trial failed: reopen, reset the cooldown window, count the repeat.\n bucket.reopenCount += 1;\n this.openBucket(bucket, model, context);\n }\n}\n","import {\n CircuitBreaker,\n type CircuitBreakerAdapter,\n type CircuitBreakerOptions,\n type CircuitBreakerStateChangeHandler,\n} from '../../../circuitBreaker.js';\nimport { LLMError } from '../../../types/errors.js';\nimport { createMiddlewareStateBag } from '../../../types/middleware.js';\nimport { emitEvent } from '../../execution/utils/middleware/middleware.utils.js';\nimport { CUSTOM_ADAPTER } from '../adapterInfo.utils.js';\nimport { callScopeFor, noopEmit } from '../callScope.utils.js';\nimport { middlewareContextNames } from '../middlewareLabels.utils.js';\nimport { callHookSafely } from './../logger.utils.js';\nimport { makeEventReporter, reportRejection } from './circuitBreaker.utils.js';\n\nimport type { Logger } from '../../../logger.js';\nimport type { VernLLMEvent } from '../../../types/events.js';\nimport type { AdapterInfo, AttemptContext, VernLLMMiddleware } from '../../../types/index.js';\n\n/** The `circuitBreaker` option union, shared by `VernLLMOptions` and `buildCircuitBreaker`. */\nexport type CircuitBreakerOption = boolean | CircuitBreakerOptions | CircuitBreakerAdapter;\n\nconst REQUIRED_ADAPTER_METHOD_NAMES = [\n 'assertClosed',\n 'recordSuccess',\n 'recordFailure',\n 'onStateChange',\n] as const;\n\n/** Members only an adapter has. `onStateChange` is left out since plain options have it too. */\nconst ADAPTER_ONLY_METHOD_NAMES = ['assertClosed', 'recordSuccess', 'recordFailure'] as const;\n\n/**\n * Optional adapter members that must be functions. `isolateByModel` is left out since plain options\n * have it as a boolean.\n */\nconst OPTIONAL_FUNCTION_MEMBER_NAMES = [\n 'getState',\n 'getFailureBreakdown',\n 'open',\n 'close',\n 'releaseTrial',\n 'setLogger',\n 'prepare',\n 'readState',\n] as const;\n\n/** Any of `OPTIONAL_FUNCTION_MEMBER_NAMES` present but not callable, the same mistake `rateLimitAdapter.utils.ts` guards against for `getState`. */\nfunction invalidOptionalMembers(\n option: CircuitBreakerOptions | CircuitBreakerAdapter,\n): (typeof OPTIONAL_FUNCTION_MEMBER_NAMES)[number][] {\n const candidate = option as Partial<CircuitBreakerAdapter>;\n return OPTIONAL_FUNCTION_MEMBER_NAMES.filter(\n (name) => candidate[name] !== undefined && typeof candidate[name] !== 'function',\n );\n}\n\n/** `prepareTimeoutMs` present but not a finite number greater than 0. Only meaningful on an adapter, plain `CircuitBreakerOptions` has no such field. */\nfunction hasInvalidPrepareTimeout(option: CircuitBreakerOptions | CircuitBreakerAdapter): boolean {\n const { prepareTimeoutMs } = option as Partial<CircuitBreakerAdapter>;\n return (\n prepareTimeoutMs !== undefined && (!Number.isFinite(prepareTimeoutMs) || prepareTimeoutMs <= 0)\n );\n}\n\n/**\n * Classifies the option in one pass: plain options, a complete adapter, an incomplete adapter, or\n * options with an invalid optional member.\n */\nfunction classifyCircuitBreakerOption(option: CircuitBreakerOptions | CircuitBreakerAdapter): {\n /** At least one of the three adapter-only methods is present, so this is clearly an attempted adapter, not plain options. */\n attemptsAdapter: boolean;\n /** Required members not present as functions. Only meaningful when `attemptsAdapter` is true. */\n missing: (typeof REQUIRED_ADAPTER_METHOD_NAMES)[number][];\n /** Present-but-non-function optional members, checked regardless of `attemptsAdapter`, see `OPTIONAL_FUNCTION_MEMBER_NAMES`. */\n invalid: (typeof OPTIONAL_FUNCTION_MEMBER_NAMES)[number][];\n} {\n const candidate = option as Partial<CircuitBreakerAdapter>;\n return {\n attemptsAdapter: ADAPTER_ONLY_METHOD_NAMES.some(\n (name) => typeof candidate[name] === 'function',\n ),\n missing: REQUIRED_ADAPTER_METHOD_NAMES.filter((name) => typeof candidate[name] !== 'function'),\n invalid: invalidOptionalMembers(option),\n };\n}\n\n/**\n * Wraps a caller's `onStateChange` so every real change first reports a `circuit_state` event, then\n * calls the handler safely. Shared by the built in breaker and custom adapters.\n */\nfunction wrapOnStateChange(\n userOnStateChange: CircuitBreakerStateChangeHandler | undefined,\n providerName: string,\n defaultModel: string,\n reportEvent: (event: VernLLMEvent) => void,\n logger: Logger,\n middleware: VernLLMMiddleware[],\n middlewareTimeoutMs: number,\n isFallback: boolean,\n supportsJsonObjectMode: boolean,\n adapter: AdapterInfo,\n): CircuitBreakerStateChangeHandler {\n return (from, to, consecutiveFailures, model, context) => {\n const event: VernLLMEvent = {\n kind: 'circuit_state',\n provider: providerName,\n model: model ?? defaultModel,\n from,\n to,\n consecutiveFailures,\n };\n\n // `context` is absent when the breaker changes state outside any call:\n // called directly, or (for a shared adapter) a change another process\n // made. Middleware still need to see it, so it gets a fresh call\n // identity of its own, like a manual `openCircuit()`.\n const callContext = context ?? {\n requestId: globalThis.crypto.randomUUID(),\n state: createMiddlewareStateBag(),\n };\n\n const ctx: AttemptContext = {\n stage: 'attempt',\n requestId: callContext.requestId,\n requestedProvider: providerName,\n adapter,\n requestedModel: model ?? defaultModel,\n isFallbackAttempt: isFallback,\n // Most call sites (recordSuccess/recordFailure after a real\n // dispatch) thread a real 1 based attempt number through\n // `context.attempt`. Falls back to `1` for the sites that have\n // none, like `assertClosed`'s pre-dispatch check.\n attempt: callContext.attempt ?? 1,\n capabilities: { supportsJsonObjectMode },\n signal: callContext.signal,\n state: callContext.state,\n own: {},\n emit: noopEmit,\n context: callScopeFor(callContext.state)?.context,\n ...middlewareContextNames(middleware),\n };\n\n emitEvent(event, ctx, reportEvent, middleware, middlewareTimeoutMs, logger);\n\n // A caller supplied onStateChange would otherwise be silently\n // discarded, since this wrapper replaces it. Chain it instead, same\n // try/catch treatment as every other user supplied callback so it\n // can't break breaker bookkeeping or the call that triggered it.\n if (!userOnStateChange) return;\n\n callHookSafely(logger, 'circuitBreaker.onStateChange', () =>\n userOnStateChange(from, to, consecutiveFailures, model, context),\n );\n };\n}\n\n/** One subscriber set per adapter, keyed weakly. See `wireAdapterOnStateChange`. */\nconst adapterSubscribers = new WeakMap<\n CircuitBreakerAdapter,\n Set<CircuitBreakerStateChangeHandler>\n>();\n\n/** Adapters that have already triggered the sharing warning below, so it fires once ever per adapter, not once per every additional build against it. */\nconst warnedAboutSharing = new WeakSet<CircuitBreakerAdapter>();\n\n/**\n * Subscribes a target to an adapter's state changes. The first call installs one dispatcher, rather\n * than wrapping again per target, and it calls the adapter's original handler once per transition\n * however many targets share it.\n */\nfunction wireAdapterOnStateChange(\n adapter: CircuitBreakerAdapter,\n subscriber: CircuitBreakerStateChangeHandler,\n logger: Logger,\n): void {\n let subscribers = adapterSubscribers.get(adapter);\n\n if (!subscribers) {\n subscribers = new Set();\n adapterSubscribers.set(adapter, subscribers);\n\n const originalOnStateChange = adapter.onStateChange;\n const currentSubscribers = subscribers;\n\n adapter.onStateChange = (from, to, consecutiveFailures, model, context) => {\n for (const sub of currentSubscribers) {\n callHookSafely(logger, 'circuitBreaker.onStateChange', () =>\n sub(from, to, consecutiveFailures, model, context),\n );\n }\n\n callHookSafely(logger, 'circuitBreaker.onStateChange', () =>\n originalOnStateChange(from, to, consecutiveFailures, model, context),\n );\n };\n } else if (!warnedAboutSharing.has(adapter)) {\n warnedAboutSharing.add(adapter);\n logger.warn(\n \"[VernLLM] circuitBreaker: this adapter instance is already wired to another target. circuit_state events for it will now be reported to both, each tagged with its own provider/model. If that's intentional (a breaker genuinely shared across targets or clients), no action needed. If not, e.g. constructing VernLLM repeatedly with the same adapter instance, each wiring is kept for the life of the process, review whether the adapter should be constructed fresh per target instead.\",\n );\n }\n\n subscribers.add(subscriber);\n}\n\n/**\n * Builds one target's breaker: a `CircuitBreaker`, the caller's adapter, or `undefined`. Built\n * before its executor, so it reports events through `onEvent` directly. Takes only the fields it\n * needs so primary and fallback targets use it alike.\n */\nexport function buildCircuitBreaker(\n circuitBreakerOption: CircuitBreakerOption | undefined,\n providerName: string,\n defaultModel: string,\n onEvent: ((event: VernLLMEvent) => void) | undefined,\n logger: Logger,\n middleware: VernLLMMiddleware[],\n middlewareTimeoutMs: number,\n isFallback: boolean,\n supportsJsonObjectMode: boolean,\n adapter: AdapterInfo = CUSTOM_ADAPTER,\n): CircuitBreakerAdapter | undefined {\n if (!circuitBreakerOption) return undefined;\n\n const reportEvent = makeEventReporter(onEvent, logger);\n\n const wrap = (userOnStateChange: CircuitBreakerStateChangeHandler | undefined) =>\n wrapOnStateChange(\n userOnStateChange,\n providerName,\n defaultModel,\n reportEvent,\n logger,\n middleware,\n middlewareTimeoutMs,\n isFallback,\n supportsJsonObjectMode,\n adapter,\n );\n\n if (typeof circuitBreakerOption === 'object') {\n const { attemptsAdapter, missing, invalid } =\n classifyCircuitBreakerOption(circuitBreakerOption);\n\n if (attemptsAdapter && missing.length > 0) {\n throw new LLMError(\n `circuitBreaker looks like a CircuitBreakerAdapter but is missing: ${missing.join(', ')}. All four members (${REQUIRED_ADAPTER_METHOD_NAMES.join(', ')}) are required.`,\n 'invalid_params',\n );\n }\n\n if (attemptsAdapter && hasInvalidPrepareTimeout(circuitBreakerOption)) {\n throw new LLMError(\n `circuitBreaker's prepareTimeoutMs (${String((circuitBreakerOption as Partial<CircuitBreakerAdapter>).prepareTimeoutMs)}) must be a finite number greater than 0. It is optional, omit it to use the default.`,\n 'invalid_params',\n );\n }\n\n if (invalid.length > 0) {\n const candidate = circuitBreakerOption as Partial<CircuitBreakerAdapter>;\n const described = invalid.map((name) => `${name} (${typeof candidate[name]})`).join(', ');\n\n throw new LLMError(\n `circuitBreaker's ${described} must be a function when present. ${invalid.length === 1 ? 'It is' : 'They are'} optional, omit entirely rather than assigning a non function value.`,\n 'invalid_params',\n );\n }\n\n // A complete adapter keeps its own state; VernLLM only subscribes through the shared\n // dispatcher. The dispatcher calls the adapter's original handler, so this subscriber passes\n // `undefined` to avoid calling it once per target.\n if (attemptsAdapter) {\n const adapter = circuitBreakerOption as CircuitBreakerAdapter;\n wireAdapterOnStateChange(adapter, wrap(undefined), logger);\n // Declared `void`, but an async adapter may return a promise anyway.\n reportRejection(\n logger,\n '[VernLLM] circuitBreaker.setLogger rejected',\n adapter.setLogger?.(logger),\n );\n\n return adapter;\n }\n }\n\n const breakerOptions =\n typeof circuitBreakerOption === 'object' ? circuitBreakerOption : undefined;\n\n return new CircuitBreaker({\n ...breakerOptions,\n onStateChange: wrap(breakerOptions?.onStateChange),\n });\n}\n","/**\n * A continuously refilling capacity. Per minute buckets refill at `capacity / 60000` per ms; a\n * concurrency bucket refills only through `give`. Mutable so AIMD can `resize()` it.\n */\nexport class TokenBucket {\n private available: number;\n private lastRefill = Date.now();\n\n constructor(\n private capacity: number,\n private 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 jump counts as no time passing, so it never shrinks `available`.\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 * Ms until `amount` is available, assuming nothing else takes from it. 0 if it already is,\n * `Infinity` for a bucket that only refills through `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 * Returns capacity, capped at `capacity`. Not floored at 0: a bad estimate can push it negative,\n * and refill corrects that.\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 /** Refills, then reports how much capacity is available right now. */\n getAvailable(): number {\n this.refill();\n return this.available;\n }\n\n /**\n * Changes capacity in place, clamping `available` on a shrink and rescaling the refill rate by\n * the same ratio.\n */\n resize(newCapacity: number): void {\n this.refill();\n\n if (this.refillPerMs > 0) {\n this.refillPerMs = (this.refillPerMs / this.capacity) * newCapacity;\n }\n\n this.capacity = newCapacity;\n this.available = Math.min(this.available, newCapacity);\n }\n}\n","import { LLMError } from '../../../types/errors.js';\nimport { MAX_TIMER_DELAY_MS } from '../../execution/utils/deadline.utils.js';\n\nimport type { AimdOptions, RateLimitOptions } from '../../../rateLimit.js';\n\n/**\n * Validates `estimateFraction`. Non-finite or `<= 0` would zero or invert the reservation, so it\n * throws; above 1 is only wasteful, so it is clamped.\n */\nexport function buildEstimateFraction(fraction: number | undefined): number {\n if (fraction === undefined) return 1;\n\n if (!Number.isFinite(fraction) || fraction <= 0) {\n throw new LLMError(\n `estimateFraction (${fraction}) must be a finite number greater than 0.`,\n 'invalid_params',\n );\n }\n\n return Math.min(fraction, 1);\n}\n\n/**\n * Validates and clamps `AimdOptions`. An out of range `decreaseFactor` or negative `increaseBy` is\n * clamped. `minCapacity` above `maxCapacity`, or either below 1, throws: every acquire takes 1, and\n * a ceiling of 0 would also zero the refill rate with no way back.\n */\nexport function buildAimdOptions(option: AimdOptions | undefined): AimdOptions | undefined {\n if (!option) return undefined;\n\n const assertFinite = (name: 'minCapacity' | 'maxCapacity' | 'increaseBy' | 'decreaseFactor') => {\n if (!Number.isFinite(option[name])) {\n throw new LLMError(\n `aimd.${name} (${option[name]}) must be a finite number.`,\n 'invalid_params',\n );\n }\n };\n\n for (const name of ['minCapacity', 'maxCapacity', 'increaseBy', 'decreaseFactor'] as const) {\n assertFinite(name);\n }\n\n if (option.minCapacity < 1 || option.maxCapacity < 1) {\n throw new LLMError(\n `aimd.minCapacity (${option.minCapacity}) and aimd.maxCapacity (${option.maxCapacity}) must both be at least 1, since the requests bucket always takes 1 per acquire; a capacity below 1 could never be satisfied.`,\n 'invalid_params',\n );\n }\n\n if (option.minCapacity > option.maxCapacity) {\n throw new LLMError(\n `aimd.minCapacity (${option.minCapacity}) must not exceed aimd.maxCapacity (${option.maxCapacity}).`,\n 'invalid_params',\n );\n }\n\n return {\n increaseBy: Math.max(0, option.increaseBy),\n decreaseFactor: Math.min(1, Math.max(Number.MIN_VALUE, option.decreaseFactor)),\n minCapacity: option.minCapacity,\n maxCapacity: option.maxCapacity,\n proactiveFloor: option.proactiveFloor ?? 0,\n };\n}\n\n/**\n * Validates the bucket and queue limits. Each mistake would otherwise misbehave silently: NaN reads\n * as unlimited, a negative ceiling blocks everything, `Infinity` or an out of range `maxQueueMs`\n * times out at once, and a ceiling between 0 and 1 can never be met. `0` stays valid where it means\n * unlimited.\n */\nexport function assertValidLimits(options: RateLimitOptions): void {\n const invalid = (message: string): never => {\n throw new LLMError(message, 'invalid_params');\n };\n\n for (const name of ['requestsPerMinute', 'tokensPerMinute'] as const) {\n const value = options[name];\n if (value === undefined || value === 0) continue;\n\n if (!Number.isFinite(value) || value < 1) {\n invalid(`${name} (${value}) must be 0 (unlimited) or a finite number of at least 1.`);\n }\n }\n\n // A fractional slot count can't describe calls in flight.\n for (const name of ['maxConcurrent', 'maxQueueSize'] as const) {\n const value = options[name];\n if (value === undefined) continue;\n\n if (!Number.isInteger(value) || value < 0) {\n invalid(`${name} (${value}) must be a non-negative integer (0 means unlimited).`);\n }\n }\n\n const { maxQueueMs } = options;\n if (\n maxQueueMs !== undefined &&\n (!Number.isFinite(maxQueueMs) || maxQueueMs < 0 || maxQueueMs > MAX_TIMER_DELAY_MS)\n ) {\n invalid(\n `maxQueueMs (${maxQueueMs}) must be a finite number from 0 to ${MAX_TIMER_DELAY_MS}. Pass 0 to wait indefinitely.`,\n );\n }\n\n const { aimd } = options;\n if (!aimd) return;\n\n // Without it there is no ceiling to adjust, so AIMD would do nothing.\n if (!options.requestsPerMinute) {\n invalid('aimd requires requestsPerMinute to be set.');\n }\n\n const floor = aimd.proactiveFloor;\n if (floor !== undefined && (!Number.isFinite(floor) || floor < 0)) {\n invalid(`aimd.proactiveFloor (${floor}) must be a finite number that is not negative.`);\n }\n}\n","import type { WireRequest } from '../../../rateLimit.js';\n\n/**\n * Tokens reserved per image by `defaultEstimateTokens`. Providers bill an\n * image by its pixel dimensions, not its base64 size, and a large image\n * lands around 1,100 to 1,600 tokens on every supported provider. The top\n * of that range errs toward over reserving, which `release` reconciles\n * against real usage anyway.\n */\nconst IMAGE_TOKEN_ESTIMATE = 1_600;\n\n/** Counts text chars and images in one message's content, so base64 image data is never read as text. */\nfunction measureContent(content: unknown): { chars: number; images: number } {\n if (typeof content === 'string') return { chars: content.length, images: 0 };\n if (content === undefined || content === null) return { chars: 0, images: 0 };\n\n if (Array.isArray(content)) {\n let chars = 0;\n let images = 0;\n\n for (const block of content as Array<{ type?: unknown; text?: unknown }>) {\n if (block?.type === 'image') images += 1;\n else if (block?.type === 'text' && typeof block.text === 'string') chars += block.text.length;\n else chars += safeJsonLength(block);\n }\n\n return { chars, images };\n }\n\n return { chars: safeJsonLength(content), images: 0 };\n}\n\nfunction safeJsonLength(value: unknown): number {\n try {\n return JSON.stringify(value)?.length ?? 0;\n } catch {\n return 0;\n }\n}\n\n/**\n * Default `estimateTokens`: chars/4 over every message's text, plus\n * `IMAGE_TOKEN_ESTIMATE` per image, plus the requested `max_tokens`.\n */\nexport function defaultEstimateTokens(request: WireRequest): number {\n let chars = 0;\n let images = 0;\n\n for (const message of request.messages) {\n const measured = measureContent((message as { content?: unknown }).content);\n chars += measured.chars;\n images += measured.images;\n }\n\n return Math.ceil(chars / 4) + images * IMAGE_TOKEN_ESTIMATE + (request.max_tokens ?? 0);\n}\n","import { MAX_TIMER_DELAY_MS } from './internal/execution/utils/deadline.utils.js';\nimport { TokenBucket } from './internal/tokenBucket.js';\nimport {\n assertValidLimits,\n buildAimdOptions,\n buildEstimateFraction,\n} from './internal/utils/rate-limit/rateLimitOptions.utils.js';\nimport { defaultEstimateTokens } from './internal/utils/rate-limit/tokenEstimate.utils.js';\nimport { LLMError } from './types/errors.js';\n\nimport type { ProviderRateLimitHint } from './internal/utils/rate-limit/rateLimitHint.utils.js';\nimport type { Logger } from './logger.js';\nimport type { LLMClient } from './types/client.js';\n\nexport { defaultEstimateTokens };\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 or pass 0 for unlimited. Otherwise a finite number of at least 1. */\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 or\n * pass 0 for unlimited. Otherwise a finite number of at least 1.\n */\n tokensPerMinute?: number;\n /** Max requests in flight at once, as a non-negative integer. 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. At most 2147483647, the longest timer delay.\n */\n maxQueueMs?: number;\n /** Max queued calls before new ones reject immediately instead of queueing, as a non-negative integer. Default 0, unbounded. */\n maxQueueSize?: number;\n /**\n * Pre-flight token estimate for `tokensPerMinute`. Defaults to a\n * chars/4 heuristic over message text, a flat amount per image, plus\n * `max_tokens`.\n */\n estimateTokens?: (request: WireRequest) => number;\n /**\n * Scales the token estimate reserved against `tokensPerMinute`, since most calls use less than\n * `max_tokens`. Limiter bookkeeping only; `release` reconciles against real usage. Default 1,\n * must be above 0, clamped to 1.\n */\n estimateFraction?: number;\n /**\n * AIMD against the `requestsPerMinute` bucket. Omit for a fixed\n * ceiling, today's behavior. Requires `requestsPerMinute`; throws\n * without it.\n */\n aimd?: AimdOptions;\n}\n\nexport interface AimdOptions {\n /** Added to the requests-per-minute ceiling on every clean release. */\n increaseBy: number;\n /** Multiplied against the ceiling on a rate-limit signal. Must be greater than `0` and at most `1`; clamped otherwise. */\n decreaseFactor: number;\n /** Floor the ceiling never shrinks below. */\n minCapacity: number;\n /** Ceiling the bucket never grows above. */\n maxCapacity: number;\n /**\n * Shrink proactively once a provider hint reports `remainingRequests`\n * at or below this, before a real 429 happens. Default 0, meaning\n * off.\n */\n proactiveFloor?: number;\n}\n\nexport interface RateLimitState {\n /** Requests still available this window, or `undefined` if `requestsPerMinute` isn't configured. */\n requestsRemaining?: number;\n /** Tokens still available this window, or `undefined` if `tokensPerMinute` isn't configured. */\n tokensRemaining?: number;\n /** Concurrency slots currently in use, or `undefined` if `maxConcurrent` isn't configured. */\n concurrentInFlight?: number;\n}\n\nexport interface RateLimitAcquireResult {\n /**\n * Frees the concurrency slot and reconciles tokens when `actualTokens` is given. Only the first\n * call counts. Call it in a `finally` so a failed attempt never leaks a slot.\n */\n release: (actualTokens?: number, success?: boolean) => 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/** Same amount used by `tryAcquireBuckets` and `scheduleWake`, stated once so the two can't drift apart. tpm spends `estimatedTokens`, everything else spends 1. */\nfunction amountFor(reason: RateLimitReason, estimatedTokens: number): number {\n return reason === 'tpm' ? estimatedTokens : 1;\n}\n\n/** `requests`/`tokens` share this \"per minute\" refill formula. `concurrency` doesn't, it only refills via `release`. */\nfunction buildPerMinuteBucket(capacityPerMinute: number | undefined): TokenBucket | undefined {\n if (!capacityPerMinute) return undefined;\n return new TokenBucket(capacityPerMinute, capacityPerMinute / 60_000);\n}\n\n/**\n * Minimum gap between AIMD shrinks, one full refill. A burst of 429s from calls already in flight\n * describes one overload, so shrinking per response would collapse the ceiling from a single spike.\n */\nconst AIMD_SHRINK_WINDOW_MS = 60_000;\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 * What VernLLM needs from a limiter. Pass your own for cross-process coordination. Every method is\n * required; no-op the AIMD ones when unused, as `RateLimiter` does.\n */\nexport interface RateLimiterAdapter {\n estimate(request: WireRequest): number;\n acquire(estimatedTokens: number, signal?: AbortSignal): Promise<RateLimitAcquireResult>;\n signalRateLimit(): void;\n reactToRateLimitHint(hint: ProviderRateLimitHint | undefined): void;\n /** Optional: current bucket levels, for introspection. Omit if the adapter has no state worth reporting. */\n getState?(): RateLimitState;\n /** Optional: live bucket levels for `VernLLM.readRateLimitState()`, the async counterpart of `getState`. */\n readState?(): Promise<RateLimitState>;\n /** Optional: receives the instance's `Logger` once, when `VernLLM` wires this adapter in. */\n setLogger?(logger: Logger): void;\n}\n\n/**\n * Per target limiter: up to three buckets (requests, tokens, concurrency) behind one FIFO queue, so\n * a large call isn't starved by small ones. An omitted bucket never blocks.\n */\nexport class RateLimiter implements RateLimiterAdapter {\n private readonly requests?: TokenBucket;\n private readonly tokens?: TokenBucket;\n private readonly concurrency?: TokenBucket;\n\n /** Buckets in acquire precedence order (concurrency, rpm, tpm), omitted ones filtered out. Built once so order can't drift between `tryAcquireBuckets` and `scheduleWake`. */\n private readonly buckets: ReadonlyArray<{ reason: RateLimitReason; bucket: TokenBucket }>;\n\n private readonly maxQueueMs: number;\n private readonly maxQueueSize: number;\n private readonly estimateTokensFn: (request: WireRequest) => number;\n private readonly estimateFraction: number;\n private readonly aimd?: AimdOptions;\n\n private readonly queue: Waiter[] = [];\n\n /**\n * A scheduled recheck of the queue head when it waits on a bucket that refills by time, so the\n * queue doesn't wait for an unrelated acquire or release. A concurrency block only clears on\n * release.\n */\n private wakeTimer?: ReturnType<typeof setTimeout>;\n\n /** When AIMD last shrank the ceiling, see `AIMD_SHRINK_WINDOW_MS`. */\n private lastShrinkAt?: number;\n\n constructor(options: RateLimitOptions) {\n assertValidLimits(options);\n\n this.requests = buildPerMinuteBucket(options.requestsPerMinute);\n this.tokens = buildPerMinuteBucket(options.tokensPerMinute);\n\n if (options.maxConcurrent) {\n this.concurrency = new TokenBucket(options.maxConcurrent, 0);\n }\n\n this.buckets = (\n [\n { reason: 'concurrency', bucket: this.concurrency },\n { reason: 'rpm', bucket: this.requests },\n { reason: 'tpm', bucket: this.tokens },\n ] as const\n ).flatMap(({ reason, bucket }) => (bucket ? [{ reason, bucket }] : []));\n\n this.maxQueueMs = options.maxQueueMs ?? 30_000;\n this.maxQueueSize = options.maxQueueSize ?? 0;\n this.estimateTokensFn = options.estimateTokens ?? defaultEstimateTokens;\n this.estimateFraction = buildEstimateFraction(options.estimateFraction);\n this.aimd = buildAimdOptions(options.aimd);\n }\n\n /**\n * The token estimate reserved against `tokensPerMinute`, scaled by `estimateFraction`. The\n * request's `max_tokens` is never changed.\n */\n estimate(request: WireRequest): number {\n return Math.ceil(this.estimateTokensFn(request) * this.estimateFraction);\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 wake was scheduled for, so drain now rather\n // than waiting on a stale timer.\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 // Defensive: each waiter is removed at most once, so `index` is always found. Guards\n // `splice(-1, 1)` against removing another waiter if that ever changes.\n /* v8 ignore next */\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 /** Takes from every configured bucket as one atomic unit, in `this.buckets`' order. Rolls back whatever was already taken if any bucket lacks capacity. */\n private tryAcquireBuckets(\n estimatedTokens: number,\n ): { ok: true } | { ok: false; reason: RateLimitReason } {\n const taken: Array<{ bucket: TokenBucket; amount: number }> = [];\n\n for (const { reason, bucket } of this.buckets) {\n const amount = amountFor(reason, estimatedTokens);\n\n if (!bucket.tryTake(amount)) {\n for (const entry of taken) entry.bucket.give(entry.amount);\n return { ok: false, reason };\n }\n\n taken.push({ bucket, amount });\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 one recheck for when the bucket blocking the head should have capacity. No-op for a\n * concurrency block or while a wake is pending.\n */\n private scheduleWake(reason: RateLimitReason, estimatedTokens: number): void {\n if (this.wakeTimer) return;\n if (reason === 'concurrency') return;\n\n const bucket = this.buckets.find((entry) => entry.reason === reason)?.bucket;\n const ms = bucket?.msUntilAvailable(amountFor(reason, estimatedTokens));\n\n // Defensive: validation keeps every per minute ceiling at 1 or more, so\n // refill never stops and the wait is always finite. Guards a timer\n // with an Infinity/NaN delay, which fires at once, if that changes.\n /* v8 ignore next */\n if (ms === undefined || !Number.isFinite(ms)) return;\n\n // Capped at the timer limit. `drain()` rereads bucket state on every wake, so an early wake\n // just reschedules.\n const delay = Math.min(Math.max(1, Math.ceil(ms)), MAX_TIMER_DELAY_MS);\n\n this.wakeTimer = setTimeout(() => {\n this.wakeTimer = undefined;\n this.drain();\n }, delay);\n }\n\n /**\n * The one-shot release for an acquired slot. Concurrency is given back, requests only recover by\n * refill, and tokens are reconciled against real usage. AIMD grows only when `success` is true,\n * so a failed attempt can't undo a shrink.\n */\n private makeRelease(estimatedTokens: number): (actualTokens?: number, success?: boolean) => void {\n let released = false;\n\n return (actualTokens?: number, success = false) => {\n if (released) return;\n released = true;\n\n this.concurrency?.give(1);\n\n // A NaN would poison the bucket and silently stop limiting, so a non-finite `actualTokens`\n // skips reconciliation and keeps the safer estimated debit.\n if (this.tokens && actualTokens !== undefined && Number.isFinite(actualTokens)) {\n this.tokens.give(estimatedTokens - actualTokens);\n }\n\n if (success) this.growOnSuccess();\n this.drain();\n };\n }\n\n /** Shared guard and resize call behind both AIMD halves below; only the arithmetic differs. */\n private resizeRequestsCeiling(next: (aimd: AimdOptions, current: number) => number): void {\n if (!this.aimd || !this.requests) return;\n\n this.requests.resize(next(this.aimd, this.requests.getCapacity()));\n }\n\n /** AIMD's additive-increase half: grows the ceiling by `aimd.increaseBy` on a clean release. No-op without `aimd`/`requestsPerMinute`. */\n private growOnSuccess(): void {\n this.resizeRequestsCeiling((aimd, current) =>\n Math.min(current + aimd.increaseBy, aimd.maxCapacity),\n );\n }\n\n /**\n * AIMD's decrease, on a real 429 or a low remaining hint. Only adjusts the ceiling, never throws.\n * Shrinks at most once per `AIMD_SHRINK_WINDOW_MS`.\n */\n signalRateLimit(): void {\n if (!this.aimd || !this.requests) return;\n\n const now = Date.now();\n\n // A clock that moved backwards reads as a new window, so a skewed\n // `lastShrinkAt` can never block shrinking for longer than one window.\n if (\n this.lastShrinkAt !== undefined &&\n now >= this.lastShrinkAt &&\n now - this.lastShrinkAt < AIMD_SHRINK_WINDOW_MS\n ) {\n return;\n }\n\n this.lastShrinkAt = now;\n this.resizeRequestsCeiling((aimd, current) =>\n Math.max(current * aimd.decreaseFactor, aimd.minCapacity),\n );\n }\n\n /**\n * AIMD's proactive entry point: shrinks via `signalRateLimit()` if\n * `hint.remainingRequests` is at or below `aimd.proactiveFloor`.\n */\n reactToRateLimitHint(hint: ProviderRateLimitHint | undefined): void {\n if (!this.aimd || !hint || hint.remainingRequests === undefined) return;\n\n // Defensive: `buildAimdOptions` always normalizes `proactiveFloor` to\n // a number (`?? 0`) at construction, so `this.aimd.proactiveFloor` is\n // never actually undefined here. Guards against a `NaN`/`undefined`\n // floor silently breaking the comparison below if that invariant is\n // ever broken by a future change.\n /* v8 ignore next */\n const floor = this.aimd.proactiveFloor ?? 0;\n if (floor > 0 && hint.remainingRequests <= floor) {\n this.signalRateLimit();\n }\n }\n\n /**\n * Current bucket levels, read live rather than cached. `concurrency`\n * tracks free slots internally, so `concurrentInFlight` is reported as\n * `capacity - available`, the inverse of what the bucket itself holds.\n */\n getState(): RateLimitState {\n return {\n requestsRemaining: this.requests?.getAvailable(),\n tokensRemaining: this.tokens?.getAvailable(),\n concurrentInFlight: this.concurrency\n ? this.concurrency.getCapacity() - this.concurrency.getAvailable()\n : undefined,\n };\n }\n}\n","import { RateLimiter, type RateLimiterAdapter, type RateLimitOptions } from '../../../rateLimit.js';\nimport { LLMError } from '../../../types/errors.js';\n\nimport type { Logger } from '../../../logger.js';\n\n/** Not exported. Internal shorthand only, so this union isn't duplicated between the public option fields and `buildRateLimit`'s own signature. */\nexport type RateLimitOption = RateLimitOptions | RateLimiterAdapter;\n\nconst ADAPTER_METHOD_NAMES = [\n 'estimate',\n 'acquire',\n 'signalRateLimit',\n 'reactToRateLimitHint',\n] as const;\n\n/** Optional `RateLimiterAdapter` members that must be functions when present. */\nconst OPTIONAL_FUNCTION_MEMBER_NAMES = ['getState', 'readState', 'setLogger'] as const;\n\n/**\n * Optional members that are set but not functions, caught now rather than as a confusing \"not a\n * function\" later.\n */\nfunction invalidOptionalMembers(\n option: RateLimitOption,\n): (typeof OPTIONAL_FUNCTION_MEMBER_NAMES)[number][] {\n const candidate = option as Partial<RateLimiterAdapter>;\n return OPTIONAL_FUNCTION_MEMBER_NAMES.filter(\n (name) => candidate[name] !== undefined && typeof candidate[name] !== 'function',\n );\n}\n\n/** All four required `RateLimiterAdapter` methods present and callable, and the optional ones (if present at all) also callable. They stay optional, see `invalidOptionalMembers`. */\nfunction isRateLimiterAdapter(option: RateLimitOption): option is RateLimiterAdapter {\n const candidate = option as Partial<RateLimiterAdapter>;\n return (\n ADAPTER_METHOD_NAMES.every((name) => typeof candidate[name] === 'function') &&\n invalidOptionalMembers(option).length === 0\n );\n}\n\n/** At least one adapter method present, but not all four, an incomplete adapter rather than plain config. */\nfunction isIncompleteRateLimiterAdapter(option: RateLimitOption): boolean {\n const candidate = option as Partial<RateLimiterAdapter>;\n return ADAPTER_METHOD_NAMES.some((name) => typeof candidate[name] === 'function');\n}\n\n/**\n * Resolves `rateLimit` into an adapter, or `undefined` for no limiting. An object with only some\n * adapter methods, or a non-function optional member, throws now instead of failing later.\n */\nexport function buildRateLimit(\n option: RateLimitOption | undefined,\n logger?: Logger,\n): RateLimiterAdapter | undefined {\n if (option === undefined) return undefined;\n if (isRateLimiterAdapter(option)) {\n if (logger) option.setLogger?.(logger);\n return option;\n }\n\n if (isIncompleteRateLimiterAdapter(option)) {\n const missing = ADAPTER_METHOD_NAMES.filter(\n (name) => typeof (option as Partial<RateLimiterAdapter>)[name] !== 'function',\n );\n\n if (missing.length > 0) {\n throw new LLMError(\n `rateLimit looks like a RateLimiterAdapter but is missing: ${missing.join(', ')}. All four methods (${ADAPTER_METHOD_NAMES.join(', ')}) are required.`,\n 'invalid_params',\n );\n }\n }\n\n const invalid = invalidOptionalMembers(option);\n if (invalid.length > 0) {\n const candidate = option as Partial<RateLimiterAdapter>;\n const described = invalid.map((name) => `${name} (${typeof candidate[name]})`).join(', ');\n\n throw new LLMError(\n `rateLimit's ${described} must be a function. ${invalid.length === 1 ? 'It is' : 'They are'} optional; omit entirely rather than assigning a non-function value.`,\n 'invalid_params',\n );\n }\n\n return new RateLimiter(option);\n}\n","import type { FallbackTarget } from '../../types/fallback.js';\n\n/**\n * One name per target, primary first. Throws when two targets share a name, since usage and events\n * identify a target by it.\n */\nexport function resolveTargetNames(\n targets: readonly FallbackTarget[],\n providerName: string,\n): string[] {\n const names = targets.map(\n // Defaults are 0-indexed among fallbacks, so `i - 1`, matching `FallbackAttempt.index`.\n (target, i) => target.name ?? (i > 0 ? `fallback[${i - 1}]` : providerName),\n );\n\n // A config mistake caught once at construction, so a plain Error rather than an LLMError.\n // Only hand set names can collide, including one that matches another target's default.\n const duplicate = names.find((name, i) => names.indexOf(name) !== i);\n if (duplicate !== undefined) {\n throw new Error(\n `target name \"${duplicate}\" is used by more than one target; names identify targets in usage and events`,\n );\n }\n\n return names;\n}\n","import { CallExecutor } from './execution/callExecutor.js';\nimport { DEFAULT_MAX_DELAY_MS } from './execution/utils/retry/retry.utils.js';\nimport { RetryBudget } from './retryBudget.js';\nimport { resolveAdapterInfo } from './utils/adapterInfo.utils.js';\nimport { buildCircuitBreaker } from './utils/circuit-breaker/circuitBreakerAdapter.utils.js';\nimport { buildRateLimit } from './utils/rate-limit/rateLimitAdapter.utils.js';\nimport { resolveTargetNames } from './utils/targetNames.utils.js';\n\nimport type { Logger } from '../logger.js';\nimport type { DetectSoftFailure } from '../types/call.js';\nimport type { LLMError } from '../types/errors.js';\nimport type { FallbackTarget } from '../types/fallback.js';\nimport type { TokenUsage, VernLLMEvent, VernLLMMiddleware } from '../types/index.js';\n\n/**\n * What `buildExecutors` needs besides the targets: the primary's resolved defaults and the instance\n * options each target falls back to.\n */\nexport interface ExecutorFactoryShared {\n /** This instance's provider label, used as the primary target's name unless it sets its own. */\n providerName: string;\n /** The primary's resolved `defaultTemperature`. Fallback targets that don't set their own inherit this, not `undefined`. */\n primaryDefaultTemperature: number | null;\n primaryDefaultReasoningEffort?: 'minimal' | 'low' | 'medium' | 'high';\n primaryDefaultBudgetTokens?: number;\n maxRetries?: number;\n timeoutMs?: number;\n chunkIdleTimeoutMs?: number;\n readerStallTimeoutMs?: number;\n baseDelayMs?: number;\n maxRetryAfterMs?: number;\n defaultMaxTokens?: number;\n nonRetryableStatus?: number[];\n parseJson?: (content: string) => unknown;\n redact?: (text: string) => string;\n onUsage?: (usage: TokenUsage) => void;\n onUsageFailure?: (usage: TokenUsage, error: LLMError) => void;\n onEvent?: (event: VernLLMEvent) => void;\n logger: Logger;\n middleware: VernLLMMiddleware[];\n /** `wrap` nesting order, which `dispatch` hooks nest in too. */\n dispatchOrder?: VernLLMMiddleware[];\n middlewareTimeoutMs: number;\n detectSoftFailure?: DetectSoftFailure;\n}\n\n/**\n * One `CallExecutor` per target, primary first, then fallbacks in order. A target inherits an\n * option only when it leaves it unset; breaker and limiter are never inherited.\n */\nexport function buildExecutors(\n primaryTarget: FallbackTarget,\n declaredFallbacks: FallbackTarget[],\n shared: ExecutorFactoryShared,\n): CallExecutor[] {\n const targets = [primaryTarget, ...declaredFallbacks];\n const names = resolveTargetNames(targets, shared.providerName);\n\n return targets.map((target, i) => {\n const isFallback = i > 0;\n const name = names[i]!;\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 shared.onEvent,\n shared.logger,\n shared.middleware,\n shared.middlewareTimeoutMs,\n isFallback,\n target.client.supportsJsonObjectMode ?? true,\n resolveAdapterInfo(target.client),\n );\n\n // Independent of `breaker`, never inherited from `shared`, same as\n // `circuitBreaker`/`rateLimit`: a budget tuned for one target's\n // capacity is rarely right for another's.\n const budget = target.retryBudget ? new RetryBudget(target.retryBudget) : undefined;\n\n return new CallExecutor(name, target.client, target.model, {\n maxRetries: target.maxRetries ?? shared.maxRetries ?? 1,\n timeoutMs: target.timeoutMs ?? shared.timeoutMs ?? 25_000,\n chunkIdleTimeoutMs: target.chunkIdleTimeoutMs ?? shared.chunkIdleTimeoutMs ?? 30_000,\n readerStallTimeoutMs: target.readerStallTimeoutMs ?? shared.readerStallTimeoutMs,\n baseDelayMs: target.baseDelayMs ?? shared.baseDelayMs ?? 500,\n maxRetryAfterMs: target.maxRetryAfterMs ?? shared.maxRetryAfterMs ?? DEFAULT_MAX_DELAY_MS,\n defaultMaxTokens: target.defaultMaxTokens ?? shared.defaultMaxTokens ?? 1000,\n defaultTemperature:\n target.defaultTemperature === undefined\n ? shared.primaryDefaultTemperature\n : target.defaultTemperature,\n defaultReasoningEffort:\n target.defaultReasoningEffort === undefined\n ? shared.primaryDefaultReasoningEffort\n : target.defaultReasoningEffort,\n defaultBudgetTokens:\n target.defaultBudgetTokens === undefined\n ? shared.primaryDefaultBudgetTokens\n : target.defaultBudgetTokens,\n nonRetryableStatus: target.nonRetryableStatus ??\n shared.nonRetryableStatus ?? [400, 401, 402, 403, 404, 413, 422],\n parseJson: shared.parseJson,\n logger: shared.logger,\n redact: shared.redact,\n onUsage: shared.onUsage,\n onUsageFailure: shared.onUsageFailure,\n onEvent: shared.onEvent,\n breaker,\n budget,\n limiter: buildRateLimit(target.rateLimit, shared.logger),\n isFallback,\n middleware: shared.middleware,\n dispatchOrder: shared.dispatchOrder,\n middlewareTimeoutMs: shared.middlewareTimeoutMs,\n detectSoftFailure: target.detectSoftFailure ?? shared.detectSoftFailure,\n });\n });\n}\n","import {\n middlewareContextNames,\n middlewareLabel,\n middlewareLabels,\n type MiddlewareContextNames,\n} from './utils/middlewareLabels.utils.js';\n\nimport type { Logger } from '../logger.js';\nimport type {\n MiddlewareRef,\n RequiredMiddlewareRef,\n VernLLMMiddleware,\n} from '../types/middleware.js';\n\nexport { middlewareContextNames, middlewareLabel, middlewareLabels, type MiddlewareContextNames };\n\n/**\n * Every resolved view of middleware order, built once at `VernLLM`\n * construction time. Nothing downstream computes order itself; each\n * consumer reads the one field it needs.\n */\nexport interface MiddlewarePipeline {\n /** `transform`/`onEvent` order: `priority`, `runsAfter`/`runsBefore` resolved, ties by original index. */\n transformOrder: VernLLMMiddleware[];\n /** `wrap` nesting order: `transformOrder` with any `position` pins applied. Identical to `transformOrder` when nothing sets `position`. */\n wrapOrder: VernLLMMiddleware[];\n /** Every entry's resolved label, in `transformOrder`, frozen. Powers `registeredMiddlewareNames` on context. */\n names: readonly string[];\n /** `names` narrowed to entries that define a `transform`, frozen. Powers `transformMiddlewareNames` on context. */\n transformNames: readonly string[];\n}\n\n/** `name`, or the array index. Not the bracketed display label: this is the ordering graph's id. */\nexport function idFor(entry: VernLLMMiddleware, index: number): string {\n return entry.name ?? String(index);\n}\n\n/**\n * Throws if two entries publish the same label. Graph ids can differ while labels clash, e.g. one\n * named `\"[1]\"` and an unnamed entry at position 1.\n */\nfunction assertNoDuplicatePublishedLabels(labels: readonly string[]): void {\n const seen = new Set<string>();\n for (const label of labels) {\n if (seen.has(label)) {\n throw new Error(\n `middleware has a duplicate label \"${label}\"; a name can't match an unnamed middleware's bracketed position`,\n );\n }\n seen.add(label);\n }\n}\n\n/**\n * One entry in the ordering graph: its id, entry, original index for tie breaks, and the ids that\n * must come after it.\n */\ninterface Node {\n id: string;\n entry: VernLLMMiddleware;\n index: number;\n /** Ids of entries that must be placed after this one. Kahn's algorithm walks this directly instead of rescanning a flat edge list on every pop. */\n mustPrecede: string[];\n}\n\n/** Throws if two entries resolve to the same `idFor` label. Duplicate labels would silently merge two middleware into one `Node` in `buildNodes`, corrupting edges and `registeredMiddlewareNames`. */\nfunction assertNoDuplicateLabels(entries: readonly VernLLMMiddleware[]): void {\n const ids = entries.map(idFor);\n const seen = new Set<string>();\n for (const id of ids) {\n if (seen.has(id)) {\n throw new Error(\n `middleware ordering has a duplicate name \"${id}\"; every middleware's resolved name must be unique`,\n );\n }\n seen.add(id);\n }\n}\n\n/**\n * Throws if two entries share a `ref`. Runs even when no entry has edges, so a duplicate can't sit\n * unnoticed until an edge targets it.\n */\nfunction assertNoDuplicateRefs(entries: readonly VernLLMMiddleware[]): void {\n const seen = new Map<MiddlewareRef, number>();\n entries.forEach((entry, index) => {\n const ref = entry.ref;\n if (!ref) return;\n const firstIndex = seen.get(ref);\n if (firstIndex !== undefined) {\n throw new Error(\n `middleware ordering has a ref reused across two entries (\"${idFor(entries[firstIndex]!, firstIndex)}\" and \"${idFor(entry, index)}\"); each middleware's ref must be unique to that middleware`,\n );\n }\n seen.set(ref, index);\n });\n}\n\n/**\n * Splits a `runsAfter` or `runsBefore` entry into its ref and whether it is required. Only\n * `requireRef` output has a `ref` property.\n */\nfunction unwrapReference(target: MiddlewareRef | RequiredMiddlewareRef): {\n ref: MiddlewareRef;\n required: boolean;\n} {\n return 'ref' in target ? { ref: target.ref, required: true } : { ref: target, required: false };\n}\n\n/**\n * Turns one `runsAfter` or `runsBefore` entry into a graph edge, matched by ref identity, never by\n * `name`. An unresolved bare ref warns and is dropped; an unresolved required ref throws.\n */\nfunction resolveReference(\n byId: Map<string, Node>,\n byRef: Map<MiddlewareRef, Node>,\n fromId: string,\n target: MiddlewareRef | RequiredMiddlewareRef,\n precedes: boolean,\n logger?: Logger,\n): void {\n const { ref, required } = unwrapReference(target);\n const targetNode = byRef.get(ref);\n\n if (!targetNode) {\n if (required) {\n throw new Error(\n `middleware \"${fromId}\" requires ref \"${ref.debugName}\", which is not registered; this dependency is not optional`,\n );\n }\n\n logger?.warn?.(\n `[VernLLM] middleware \"${fromId}\" references unknown ref \"${ref.debugName}\" in runsAfter/runsBefore, ignoring it`,\n );\n\n return;\n }\n // precedes true: target (runsAfter) must come before fromId.\n // precedes false: target (runsBefore) must come after fromId.\n const before = precedes ? targetNode.id : fromId;\n const after = precedes ? fromId : targetNode.id;\n byId.get(before)!.mustPrecede.push(after);\n}\n\nfunction buildNodes(entries: readonly VernLLMMiddleware[], logger?: Logger): Node[] {\n const ids = entries.map(idFor);\n const nodes = entries.map((entry, index): Node => ({\n id: ids[index]!,\n entry,\n index,\n mustPrecede: [],\n }));\n const byId = new Map(nodes.map((node) => [node.id, node]));\n\n // Only entries with a `ref` can be targeted, keyed by the ref object so labels never affect\n // order. Refs are already known to be unique here.\n const byRef = new Map(\n nodes.filter((node) => node.entry.ref).map((node) => [node.entry.ref!, node]),\n );\n\n for (const node of nodes) {\n for (const target of node.entry.runsAfter ?? []) {\n resolveReference(byId, byRef, node.id, target, true, logger);\n }\n for (const target of node.entry.runsBefore ?? []) {\n resolveReference(byId, byRef, node.id, target, false, logger);\n }\n }\n\n return nodes;\n}\n\n/** Ascending by `priority` (default `0`), ties broken by original array index. */\nfunction byPriorityThenIndex(a: Node, b: Node): number {\n const priorityDiff = (a.entry.priority ?? 0) - (b.entry.priority ?? 0);\n return priorityDiff !== 0 ? priorityDiff : a.index - b.index;\n}\n\n/**\n * Kahn's algorithm, ties broken by `byPriorityThenIndex`. Nodes left unvisited form a cycle, so\n * this is also the cycle check. Throws a plain `Error`, since a cycle is a construction time\n * mistake.\n */\nfunction topologicalSort(nodes: Node[]): VernLLMMiddleware[] {\n const byId = new Map(nodes.map((node) => [node.id, node]));\n const indegree = new Map(nodes.map((node) => [node.id, 0]));\n for (const node of nodes) {\n for (const after of node.mustPrecede) indegree.set(after, indegree.get(after)! + 1);\n }\n\n // A small heap would beat re-sorting the ready set on every pop for a\n // large graph, but middleware lists are small in practice; re-sorting\n // a handful of ready ids each iteration is simpler and fast enough.\n const ready = nodes.filter((node) => indegree.get(node.id) === 0);\n const result: VernLLMMiddleware[] = [];\n const emitted = new Set<string>();\n\n while (ready.length > 0) {\n ready.sort(byPriorityThenIndex);\n const node = ready.shift()!;\n result.push(node.entry);\n emitted.add(node.id);\n\n for (const afterId of node.mustPrecede) {\n const remaining = indegree.get(afterId)! - 1;\n indegree.set(afterId, remaining);\n if (remaining === 0) ready.push(byId.get(afterId)!);\n }\n }\n\n if (result.length < nodes.length) {\n const stuck = nodes.filter((node) => !emitted.has(node.id)).map((node) => node.id);\n throw new Error(`middleware ordering has a cycle among: ${stuck.join(', ')}`);\n }\n\n return result;\n}\n\n/**\n * Sorts `entries` once, at construction. Without `runsAfter` or `runsBefore` this is a plain\n * `priority` sort, ties by index; with edges it runs the graph sort.\n */\nexport function resolveMiddlewareOrder(\n entries: readonly VernLLMMiddleware[],\n logger?: Logger,\n): VernLLMMiddleware[] {\n assertNoDuplicateLabels(entries);\n assertNoDuplicateRefs(entries);\n\n const hasEdges = entries.some((entry) => entry.runsAfter?.length || entry.runsBefore?.length);\n\n if (entries.length <= 1 && !hasEdges) return [...entries];\n\n if (!hasEdges) {\n // Same comparator the graph path uses for tie-breaking among\n // simultaneously-ready nodes, so \"what does a tie mean\" has one\n // definition regardless of which path an entry set takes.\n const asNodes = entries.map((entry, index): Node => ({\n id: idFor(entry, index),\n entry,\n index,\n mustPrecede: [],\n }));\n return asNodes.sort(byPriorityThenIndex).map((node) => node.entry);\n }\n\n const nodes = buildNodes(entries, logger);\n return topologicalSort(nodes);\n}\n\n/**\n * Stable sort for `wrapOrder`: `'outermost'` first, `'innermost'` last, numeric or missing (`0`)\n * positions in between like `priority`. Among several outermost claimants the first registered is\n * outermost; among innermost claimants the last registered is innermost.\n */\nfunction applyPositionOverride(\n order: readonly VernLLMMiddleware[],\n entries: readonly VernLLMMiddleware[],\n): VernLLMMiddleware[] {\n const outermost: VernLLMMiddleware[] = [];\n const innermost: VernLLMMiddleware[] = [];\n const middle: VernLLMMiddleware[] = [];\n\n // Single pass instead of three separate `.filter()` walks over\n // `order`; each entry lands in exactly one bucket, so there's no risk\n // of the buckets' predicates drifting out of sync with each other as\n // position values are added later.\n for (const entry of order) {\n if (entry.position === 'outermost') outermost.push(entry);\n else if (entry.position === 'innermost') innermost.push(entry);\n else middle.push(entry);\n }\n\n const sortedMiddle = [...middle].sort((a, b) => {\n const aPos = typeof a.position === 'number' ? a.position : 0;\n const bPos = typeof b.position === 'number' ? b.position : 0;\n return aPos - bPos;\n });\n // Registration order, not `order`'s: `order` is sorted by priority, which would let a\n // claimant's `transform` priority decide who wraps whom.\n const registered = (a: VernLLMMiddleware, b: VernLLMMiddleware): number =>\n entries.indexOf(a) - entries.indexOf(b);\n outermost.sort(registered);\n innermost.sort(registered);\n\n return [...outermost, ...sortedMiddle, ...innermost];\n}\n\n/**\n * Builds the one `MiddlewarePipeline` an instance uses. Nothing downstream computes order itself.\n */\nexport function buildMiddlewarePipeline(\n entries: readonly VernLLMMiddleware[],\n logger?: Logger,\n): MiddlewarePipeline {\n const transformOrder = resolveMiddlewareOrder(entries, logger);\n const { registeredMiddlewareNames: names, transformMiddlewareNames: transformNames } =\n middlewareContextNames(transformOrder);\n assertNoDuplicatePublishedLabels(names);\n return {\n transformOrder,\n wrapOrder: applyPositionOverride(transformOrder, entries),\n names,\n transformNames,\n };\n}\n","import {\n InMemoryCacheAdapter,\n type CacheAdapter,\n type EvictionOption,\n} from '../../../types/cache.js';\n\n/**\n * Not exported. Internal shorthand for `VernLLMOptions.cache`, so the\n * union isn't duplicated between that field and `buildCache`'s own\n * signature. A caller never writes this type by name, either a config\n * object literal or a real `CacheAdapter`.\n */\nexport type CacheOption = { maxSize?: number; eviction?: EvictionOption } | CacheAdapter;\n\n/** A config object has neither `get` nor `set`, a `CacheAdapter` always has both. */\nfunction isCacheAdapter(option: CacheOption): option is CacheAdapter {\n const candidate = option as CacheAdapter;\n return typeof candidate.get === 'function' && typeof candidate.set === 'function';\n}\n\n/** Resolves `VernLLMOptions.cache` into a real `CacheAdapter`. Same placement reasoning as `buildCircuitBreaker`: a construction time concern of `VernLLM`, not the adapter itself. */\nexport function buildCache(option: CacheOption | undefined): CacheAdapter {\n if (option === undefined) return new InMemoryCacheAdapter();\n if (isCacheAdapter(option)) return option;\n\n if (\n option.maxSize !== undefined &&\n (!Number.isFinite(option.maxSize) || option.maxSize < 0 || !Number.isInteger(option.maxSize))\n ) {\n throw new RangeError(\n `cache.maxSize must be a finite, non-negative integer, got ${String(option.maxSize)}`,\n );\n }\n\n return new InMemoryCacheAdapter(option.maxSize, option.eviction);\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 { CacheOrchestrator } from './internal/cache/cacheOrchestrator.js';\nimport { claimMetaHolder, type MetaHolder } from './internal/cache/utils/metaHolder.utils.js';\nimport { CallExecutor } from './internal/execution/callExecutor.js';\nimport { type LogicalCallDependencies } from './internal/execution/logicalCall.js';\nimport { runReservedLogicalCall } from './internal/execution/reservedLogicalCall.js';\nimport { runOperation, type RunOperationDependencies } from './internal/execution/runOperation.js';\nimport {\n declaredTargets,\n narrowTargets,\n type ResolvedTarget,\n} from './internal/execution/targetOrder.js';\nimport { combineSignals, setupCallSignal } from './internal/execution/utils/callSignal.utils.js';\nimport { setupDeadline, stampDeadlineCode } from './internal/execution/utils/deadline.utils.js';\nimport {\n createCallScope,\n type CallScopeDependencies,\n} from './internal/execution/utils/middleware/customEvent.utils.js';\nimport { DEFAULT_MIDDLEWARE_TIMEOUT_MS } from './internal/execution/utils/middleware/middleware.utils.js';\nimport { buildExecutors } from './internal/executorFactory.js';\nimport { buildMiddlewarePipeline } from './internal/resolveMiddlewareOrder.js';\nimport { buildCache } from './internal/utils/cache/cacheAdapter.utils.js';\nimport {\n prepareCallContext,\n registerCallScope,\n validateStateEntries,\n} from './internal/utils/callScope.utils.js';\nimport {\n makeEventReporter,\n resolveExecutor,\n warnIfModelUnsupported,\n} from './internal/utils/circuit-breaker/circuitBreaker.utils.js';\nimport { createSafeLogger, logError, NoopLogger } from './internal/utils/logger.utils.js';\nimport { ConsoleLogger, type Logger } from './logger.js';\nimport {\n LLMError,\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 FallbackTarget,\n type JsonModeDisabledCallParams,\n type JsonModeEnabledCallParams,\n type JsonValue,\n type LLMErrorCode,\n type StreamCallResult,\n type StreamConditionalStringToolCallParams,\n type StreamEnabledCallParams,\n type StreamJsonModeDisabledCallParams,\n type StreamJsonModeEnabledCallParams,\n type CachedStreamJsonModeDisabledCallParams,\n type CachedStreamJsonModeEnabledCallParams,\n type TargetCircuitState,\n type CircuitTarget,\n type ToolDefinition,\n type ToolEnabledCallParams,\n type ToolsDisabledCallParams,\n type VernLLMOptions,\n} from './types/index.js';\nimport { createMiddlewareStateBag, type MiddlewareStateBag } from './types/middleware.js';\n\nimport type { CircuitState } from './circuitBreaker.js';\nimport type { InternalCacheParams } from './internal/cache/utils/cache.utils.js';\nimport type { RateLimitState } from './rateLimit.js';\n\n/**\n * The LLM call framework: retries, timeouts, circuit breaking, fallback, rate limiting, caching and\n * middleware around any provider adapter.\n */\nexport class VernLLM {\n private readonly logger: Logger;\n\n /** One per target: index 0 is the primary, then each fallback in declared order. */\n private readonly executors: CallExecutor[];\n\n /** Owns cache reads, writes and in-flight coalescing for `cachedCall()`. */\n private readonly cacheOrchestrator: CacheOrchestrator;\n\n /** Every target in declared order, the pool `targets` selects from. */\n private readonly declaredTargets: readonly ResolvedTarget[];\n\n /** Everything but `targets`, which each call sets for its own order. */\n private readonly logicalCallDependencies: Omit<LogicalCallDependencies, 'targets'>;\n private readonly runOperationDependencies: RunOperationDependencies;\n\n /** What each call's scope needs to deliver a `ctx.emit` event. */\n private readonly callScopeDependencies: CallScopeDependencies;\n\n /**\n * Marks `cachedCall()`'s inner call params with its state bag, so the inner\n * `runOperation` skips `wrap` and reuses that bag. Keyed by object identity,\n * since concurrent `cachedCall()`s can share an explicit `requestId`.\n */\n private readonly cachedCallInnerParams = new WeakMap<CallParams<unknown>, MiddlewareStateBag>();\n\n /** Shared `CallMeta` holders per resolved cache key. See `claimMetaHolder`. */\n private readonly cachedCallMeta = new Map<string, MetaHolder>();\n\n /** @param options Client, model and tunables. See `VernLLMOptions` for each default. */\n constructor(options: VernLLMOptions) {\n this.logger = createSafeLogger(\n options.logger === 'silent'\n ? new NoopLogger()\n : (options.logger ?? new ConsoleLogger(options.debug ?? false)),\n );\n\n const providerName = options.name ?? 'primary';\n\n this.cacheOrchestrator = new CacheOrchestrator(buildCache(options.cache), this.logger);\n\n const reportEvent = makeEventReporter(options.onEvent, this.logger);\n const pipeline = buildMiddlewarePipeline(options.middleware ?? [], this.logger);\n const middlewareTimeoutMs = options.middlewareTimeoutMs ?? DEFAULT_MIDDLEWARE_TIMEOUT_MS;\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 as a `FallbackTarget` so it goes through the same build loop. Fallback\n // targets never inherit its breaker or limiter.\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 readerStallTimeoutMs: options.readerStallTimeoutMs,\n baseDelayMs: options.baseDelayMs,\n maxRetryAfterMs: options.maxRetryAfterMs,\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 retryBudget: options.retryBudget,\n detectSoftFailure: options.detectSoftFailure,\n };\n\n const declaredFallbacks: FallbackTarget[] = Array.isArray(options.fallback)\n ? options.fallback\n : options.fallback\n ? [options.fallback]\n : [];\n\n this.executors = buildExecutors(primaryTarget, declaredFallbacks, {\n providerName,\n primaryDefaultTemperature,\n primaryDefaultReasoningEffort,\n primaryDefaultBudgetTokens,\n maxRetries: options.maxRetries,\n timeoutMs: options.timeoutMs,\n chunkIdleTimeoutMs: options.chunkIdleTimeoutMs,\n readerStallTimeoutMs: options.readerStallTimeoutMs,\n baseDelayMs: options.baseDelayMs,\n maxRetryAfterMs: options.maxRetryAfterMs,\n defaultMaxTokens: options.defaultMaxTokens,\n nonRetryableStatus: options.nonRetryableStatus,\n parseJson: options.parseJson,\n redact: options.redact,\n onUsage: options.onUsage,\n onUsageFailure: options.onUsageFailure,\n onEvent: options.onEvent,\n logger: this.logger,\n middleware: pipeline.transformOrder,\n dispatchOrder: pipeline.wrapOrder,\n middlewareTimeoutMs,\n detectSoftFailure: options.detectSoftFailure,\n });\n\n this.declaredTargets = declaredTargets(this.executors);\n\n this.logicalCallDependencies = {\n fallbackOn: options.fallbackOn ?? defaultFallbackOn,\n reportEvent,\n middleware: pipeline.transformOrder,\n middlewareTimeoutMs,\n logger: this.logger,\n };\n this.callScopeDependencies = {\n reportEvent,\n middleware: pipeline.transformOrder,\n middlewareTimeoutMs,\n logger: this.logger,\n };\n this.runOperationDependencies = {\n pipeline,\n primaryExecutor: this.executors[0]!,\n targets: this.declaredTargets,\n middlewareTimeoutMs,\n logger: this.logger,\n reportEvent,\n };\n }\n\n /**\n * Makes one logical call, with retries, fallback and the breaker applied. Rejects with a\n * normalized `LLMError`. See the Tool Calling and Streaming docs for the return shapes.\n *\n * @param params Content plus per call overrides. See `CallParams`.\n * @returns The parsed response, a `CallWithToolsResult<T>` with `tools`, or a `StreamCallResult`\n * with `stream: true`.\n */\n async call<T = unknown, const Tools extends readonly ToolDefinition[] = ToolDefinition[]>(\n params: StreamEnabledCallParams<T, Tools> & ToolsDisabledCallParams<T, Tools>,\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, const Tools extends readonly ToolDefinition[] = ToolDefinition[]>(\n params: ToolsDisabledCallParams<T, Tools>,\n ): 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 ?? globalThis.crypto.randomUUID();\n\n // Read from the original `params` object, before any clone drops the marker.\n const cachedCallState = this.cachedCallInnerParams.get(params);\n const isCachedCallInner = cachedCallState !== undefined;\n\n // Validated before any timer or hook exists. The inner call of `cachedCall` skips it, since\n // `cachedCall` already validated the same `context` and registered the scope.\n const callContext = isCachedCallInner ? undefined : prepareCallContext(params.context);\n const stateEntries = isCachedCallInner ? undefined : validateStateEntries(params.state);\n const targets = this.resolveTargets(params.targets);\n\n const {\n params: effectiveParams,\n signal: effectiveSignal,\n breakController,\n dispose,\n } = setupCallSignal(params, !isCachedCallInner);\n\n // One bag per logical call, shared by `wrap` and `transform` on every target.\n const middlewareState = cachedCallState ?? createMiddlewareStateBag(stateEntries);\n registerCallScope(middlewareState, createCallScope(this.callScopeDependencies, callContext));\n\n try {\n // `wrap` also spans the sole target breaker check, so a circuit open\n // rejection is visible to it.\n const wrapped = await runOperation(\n this.runOperationDependencies,\n effectiveParams,\n requestId,\n middlewareState,\n targets,\n (chosen) =>\n runReservedLogicalCall(\n { ...this.logicalCallDependencies, targets: chosen },\n effectiveParams,\n {\n requestId,\n middlewareState,\n breakController,\n onRefundError: (logMessage, error) => logError(this.logger, logMessage, error),\n },\n ),\n isCachedCallInner,\n );\n\n return wrapped.value as\n | T\n | CallWithToolsResult<T>\n | StreamCallResult<T | CallWithToolsResult<T>>;\n } catch (error) {\n throw stampDeadlineCode(error, effectiveSignal);\n } finally {\n dispose();\n }\n }\n\n /**\n * The order a call starts with: `requested` by name, or every target as declared. Throws before\n * any timer or hook exists, so an invalid order never starts a call.\n */\n private resolveTargets(requested: readonly string[] | undefined): ResolvedTarget[] {\n return narrowTargets(this.declaredTargets, this.declaredTargets, requested);\n }\n\n /** Kept on `VernLLM` since tests drive the caching core directly through it. */\n private runCached<T>(params: InternalCacheParams<T>) {\n return this.cacheOrchestrator.runCached(params);\n }\n\n /**\n * Removes a cached response when the adapter supports deletion. Invalidation is up to the app.\n *\n * @param key The raw cache key, resolved through the adapter's `resolveKey` first.\n */\n async deleteCache(key: string): Promise<void> {\n await this.cacheOrchestrator.deleteCache(key);\n }\n\n /**\n * `call()` with caching. Concurrent misses for one `cacheKey` share a single in-flight call.\n * Works with `stream` and `tools`; with tools the whole result is cached, tool call decisions\n * included. A caller's own abort or deadline only ends its wait; the shared request is aborted\n * once every caller has left.\n *\n * @param params Cache settings plus `call`, the `CallParams` for the underlying call.\n * @returns The cached value on a hit, or the fresh 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 const restCallParams = callParams as CallParams<T>;\n\n // The per call hooks would be silently dropped, since the cached value\n // may be shared by several callers.\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 const requestId = restCallParams.requestId ?? globalThis.crypto.randomUUID();\n const middlewareState = createMiddlewareStateBag(validateStateEntries(restCallParams.state));\n registerCallScope(\n middlewareState,\n createCallScope(this.callScopeDependencies, prepareCallContext(restCallParams.context)),\n );\n // Before the cache is touched or a meta holder claimed, like `context` above.\n const targets = this.resolveTargets(restCallParams.targets);\n\n const resolvedCacheKey = await this.cacheOrchestrator.resolveCacheKey(cacheParams.cacheKey);\n const { holder: metaHolder, release: releaseMetaHolder } = claimMetaHolder(\n this.cachedCallMeta,\n resolvedCacheKey,\n (key) => this.cacheOrchestrator.inFlightFor(key),\n );\n\n const callerMeta = restCallParams.meta;\n const syncCallerMeta = () => {\n if (callerMeta) callerMeta.current = metaHolder.current;\n };\n\n // These end only this caller's wait. The shared request has its own signal\n // from the orchestrator, aborted once every participant has left.\n const { signal: participantSignal, timer: deadlineTimer } = setupDeadline(\n restCallParams.deadlineMs,\n combineSignals([cacheParams.signal, restCallParams.signal]),\n );\n const participantCacheParams = { ...cacheParams, signal: participantSignal };\n\n const participantParams = {\n ...restCallParams,\n requestId,\n signal: participantSignal,\n } as CallParams<T>;\n\n // The inner call runs once for all participants, so it takes the shared\n // signal and no per caller deadline. Marked so its own `runOperation`\n // skips `wrap` and reuses this state bag.\n // Only the caller that runs the call gets to choose its targets: a coalesced follower's are\n // ignored, and `targets` is not part of the cache key. The inner call gets the order `wrap`\n // left, by name, so it resolves to the same targets.\n const callShared = (sharedSignal: AbortSignal, chosen: readonly ResolvedTarget[]) => {\n const { deadlineMs: _deadlineMs, ...sharedParams } = participantParams;\n const innerParams = {\n ...sharedParams,\n targets: chosen.map((target) => target.executor.providerName),\n signal: sharedSignal,\n meta: metaHolder,\n };\n this.cachedCallInnerParams.set(innerParams, middlewareState);\n return this.call(innerParams).finally(() => {\n syncCallerMeta();\n this.cachedCallInnerParams.delete(innerParams);\n });\n };\n\n // A stream hands the holder's release to `finalResult`, since a joiner may\n // still attach after this returns.\n let releaseOnSettle = false;\n\n try {\n const wrapped = await runOperation(\n this.runOperationDependencies,\n participantParams,\n requestId,\n middlewareState,\n targets,\n async (chosen) => {\n const value = restCallParams.stream\n ? await this.cacheOrchestrator.runCachedStream(\n {\n ...participantCacheParams,\n openStream: (sharedSignal) =>\n callShared(sharedSignal, chosen) as Promise<StreamCallResult<unknown>>,\n },\n Boolean(restCallParams.tools),\n )\n : await this.runCached({\n ...participantCacheParams,\n fn: (sharedSignal) => callShared(sharedSignal, chosen),\n });\n\n return { value, meta: metaHolder.current };\n },\n );\n\n if (restCallParams.stream) {\n const streamResult = wrapped.value as StreamCallResult<T | CallWithToolsResult<T>>;\n const onStreamSettled = () => {\n syncCallerMeta();\n releaseMetaHolder();\n };\n\n releaseOnSettle = true;\n void streamResult.finalResult.then(onStreamSettled, onStreamSettled);\n\n return streamResult;\n }\n\n syncCallerMeta();\n\n return wrapped.value as T | CallWithToolsResult<T>;\n } catch (error) {\n throw stampDeadlineCode(error, participantSignal);\n } finally {\n if (!releaseOnSettle) releaseMetaHolder();\n clearTimeout(deadlineTimer);\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.\n */\n getCircuitState(target?: CircuitTarget): CircuitState | undefined {\n const executor = resolveExecutor(this.executors, target?.index ?? 0, 'getCircuitState');\n warnIfModelUnsupported(executor.isolateByModel, target?.model, 'getCircuitState', this.logger);\n\n return executor.getCircuitState(target?.model ?? executor.model);\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 Failure counts by `LLMErrorCode`, `'unknown'` for a missing\n * code, or `undefined` if that target has no breaker.\n * @throws {RangeError} If `target.index` names no target.\n */\n getFailureBreakdown(\n target?: CircuitTarget,\n ): Partial<Record<LLMErrorCode | 'unknown', number>> | undefined {\n const executor = resolveExecutor(this.executors, target?.index ?? 0, 'getFailureBreakdown');\n warnIfModelUnsupported(\n executor.isolateByModel,\n target?.model,\n 'getFailureBreakdown',\n this.logger,\n );\n\n return executor.getFailureBreakdown(target?.model ?? executor.model);\n }\n\n /**\n * @param target.index Which target to read. Defaults to the primary.\n * @returns The retry traffic and ratio in the trailing window, or `undefined` without a budget.\n * Budgets are per target, not per model.\n * @throws {RangeError} If `target.index` names no target.\n */\n getRetryBudgetState(\n target?: Pick<CircuitTarget, 'index'>,\n ): { attempts: number; retryRatio: number } | undefined {\n const executor = resolveExecutor(this.executors, target?.index ?? 0, 'getRetryBudgetState');\n return executor.getRetryBudgetState();\n }\n\n /**\n * @param target.index Which target to read. Defaults to the primary.\n * @returns Current rate limit levels, or `undefined` without a limiter. Limiters are per target,\n * not per model.\n * @throws {RangeError} If `target.index` names no target.\n */\n getRateLimitState(target?: Pick<CircuitTarget, 'index'>): RateLimitState | undefined {\n const executor = resolveExecutor(this.executors, target?.index ?? 0, 'getRateLimitState');\n return executor.getRateLimitState();\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 * The live counterpart of `getRateLimitState`, asking the limiter for its current levels.\n *\n * @param target.index Which target to read. Defaults to the primary.\n * @returns This target's live rate limit levels, or `undefined` if that target has no limiter\n * configured.\n * @throws {RangeError} If `target.index` names no target.\n */\n async readRateLimitState(\n target?: Pick<CircuitTarget, 'index'>,\n ): Promise<RateLimitState | undefined> {\n const executor = resolveExecutor(this.executors, target?.index ?? 0, 'readRateLimitState');\n return executor.readRateLimitState();\n }\n\n /**\n * The live counterpart of `getCircuitStates`, asking each breaker for its current state.\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 async readCircuitStates(model?: string): Promise<TargetCircuitState[]> {\n return Promise.all(\n this.executors.map(async (executor, index) => ({\n provider: executor.providerName,\n index,\n isFallback: index > 0,\n isolateByModel: executor.isolateByModel,\n state: await executor.readCircuitState(model ?? executor.model),\n })),\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 = resolveExecutor(this.executors, target?.index ?? 0, 'openCircuit');\n warnIfModelUnsupported(executor.isolateByModel, target?.model, 'openCircuit', this.logger);\n // No logical call behind a manual invocation, so mint a fresh one.\n executor.openCircuit(target?.model ?? executor.model, {\n requestId: globalThis.crypto.randomUUID(),\n state: createMiddlewareStateBag(),\n });\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 = resolveExecutor(this.executors, target?.index ?? 0, 'closeCircuit');\n warnIfModelUnsupported(executor.isolateByModel, target?.model, 'closeCircuit', this.logger);\n // See `openCircuit`.\n executor.closeCircuit(target?.model ?? executor.model, {\n requestId: globalThis.crypto.randomUUID(),\n state: createMiddlewareStateBag(),\n });\n }\n}\n","import type { CachedCallParams, CallParams } from './types/index.js';\n\n/**\n * Keeps `params`' precise type for a reusable variable. A `CallParams<T>` annotation would widen\n * `tools` and lose the conditional tools overload. Pin `T` through `llm.call<T>(params)`.\n */\nexport function defineCallParams<P extends CallParams<unknown>>(params: P): P {\n return params;\n}\n\n/**\n * `cachedCall()` counterpart to `defineCallParams`, keeping the whole `{ cacheKey, ttl, call }`\n * type.\n */\nexport function defineCachedCallParams<P extends CachedCallParams<unknown>>(params: P): P {\n return params;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["isPromiseLike","OPTIONAL_FUNCTION_MEMBER_NAMES","invalidOptionalMembers","ADAPTER_METHOD_NAMES","OPTIONAL_FUNCTION_MEMBER_NAMES","hasIssues","isLLMError","readRateLimitHint","LLMError","toRequestSnapshot","FIFO","store","touch","key","value","LRU","buildEviction","option","isLiveTtl","ttl","isFaithfullyCloneable","type","object","seen","item","prototype","descriptor","InMemoryCacheAdapter","maxSize","eviction","entry","now","victim","NormalizedCacheAdapter","inner","TieredCacheAdapter","l1","l2","l1Ttl","l1Result","l2Result","fallback","expiresAt","heapPush","oldest","trackedKey","trackedExpiry","heapPop","heap","record","index","parent","top","last","left","right","smallest","defineTool","tool","isToolCallResult","result","candidate","isPromiseLike$1","isAsyncIterable","isStreamResult","TOOL_CONTRACT_CODES","defaultFallbackOn","error","FallbackExhaustedError","attempts","a","isFallbackExhaustedError","err","metaRef","createIdentityToken","createStateKey","debugName","createMiddlewareRef","requireRef","stateEntry","createMiddlewareStateBag","entries","createMiddleware","rest","options","onError","next","ctx","isBilledCost","toTokenUsage","reasoningTokens","wireUsage","details","meta","reserve","params","signal","makeRefund","refundError","onRefundError","logMessage","withReservedUsage","reserved","coalesced","refund","getResult","withReservedUsageForStream","opened","openStream","finalResult","onEarlyExit","activeReaders","iterator","chunks","active","ended","end","onExit","cancelOnBreak","controller","stream","settled","markSettled","createDeferred","resolve","reject","res","rej","logHookError","logError","logger","hookName","errorMessage","message","callHookSafely","fn","createSafeLogger","safe","method","args","swallowRejection","isPromiseLike","NoopLogger","createInFlightRegistry","inFlight","get","track","promise","toReplayText","buildReplayChunks","items","hasTools","toolCall","buildReplayChunksFromPromise","createSharedAbort","participants","released","abortedError","raceAbort","onAbort","abortableChunks","CacheOrchestrator","cache","resolvedKey","shared","release","existing","cached","resolvedParams","cacheKey","resolveShared","rejectShared","started","start","running","run","resultPromise","onTriggerFailed","openedStream","openShared","triggerSignal","streamPromise","onFailed","claimMetaHolder","holders","holder","deleteHolder","inFlightFor","RollingRatio","windowMs","elapsed","drop","shiftCount","i","head","failed","t","b","f","validateMinCalls","label","validateRatio","RetryBudget","isRetry","CUSTOM_ADAPTER","resolveAdapterInfo","info","client","makeEventReporter","onEvent","event","usageHooks","resolveExecutor","executor","executors","caller","warnIfModelUnsupported","model","isolateByModel","reportRejection","runPrepare","context","timeoutMs","breaker","pending","warnFailed","timer","outcome","DEADLINE_REASON","MAX_TIMER_DELAY_MS","setupDeadline","deadlineMs","callerSignal","stampDeadlineCode","createCallFacts","hasDeadline","targets","callFactsFor","scopes","state","registerCallScope","scope","callScopeFor","noopEmit","isPlainObject","isJson","ancestors","valid","deepFreeze","prepareCallContext","isStateEntry","validateStateEntries","middlewareLabel","middleware","middlewareLabels","ordered","contextNamesCache","middlewareContextNames","names","labels","DEFAULT_MAX_DELAY_MS","RETRY_AFTER_CANDIDATES","readHeader","getter","headers","name","match","clampOrUndefined","rawMs","maxDelayMs","extractRetryAfterMs","raw","kind","dateMs","validateMaxRetryAfterMs","maxRetryAfterMs","providerName","resolveActiveTimeoutMs","ms","clampTimeoutMs","withTimeout","activeTimeoutMs","externalSignal","timeoutError","timeoutPromise","withChunkIdleTimeout","onIdle","fullJitter","exp","getBackoffDelay","baseDelayMs","rateLimited","serverError","attempt","waitForRetry","delay","shouldRetry","status","extractStatus","nonRetryableStatus","recoverDelay","retryAfterMs","retryAfterHonored","requestId","maxRetries","emitEvent","normalizeError","buildEventContext","reportEvent","middlewareTimeoutMs","normalizeMaxRetries","retryWithBackoff","lastError","lastRequestForAttempt","recoverDelayForAttempt","onAttempt","req","shouldRetryAttempt","NETWORK_ERROR_CODES","NETWORK_ERROR_MESSAGES","isNetworkError","cause","formatSafely","describeError","codeForStatus","NO_BODY_MESSAGE_PATTERN","isEmptyObject","hasNoDiagnosticDetail","errorField","isEmptyString","isEmptyStruct","trimmed","description","code","isRequestValidationStatus","createOnceAsync","called","resolved","call","PATCH_FIELDS","mergePatch","rawPatch","patch","patchedFields","field","request","assertNoDuplicateTools","duplicates","assertModelAndResponseFormatUnchanged","after","before","ownStores","chainTables","chainTableFor","table","recordWrapLayers","layers","recordChainStart","chain","ownerChain","layer","current","withOwn","byChain","own","data","raceTimeout","resolveEnabled","enabled","applyMiddlewareTransforms","middlewareEntry","buildContext","enabledEntries","runTransform","merged","reclassifyMiddlewareThrow","runDispatch","hooks","send","provider","runLayer","hookFailure","normalized","stamped","withCallContext","reportEventInstance","dispatchEventToMiddleware","fields","invokeOnEvent","isEnabled","buildDispatchHooks","transformOrder","indexByEntry","order","limiterFailures","isLimiterFailure","acquireRateLimit","limiter","acquired","onRateLimited","prepareAttempt","p","middlewareState","built","requestBuilder","gateway","onRequest","dispatchHooks","hook","prepareTargetAttempt","env","redactText","text","finalizeDependencies","countsTowardBreaker","toWireTools","tools","toWireToolCalls","toolCalls","tc","parseWireToolCalls","wireToolCalls","parsedArgs","wc","parseAndValidate","parsed","parseJson","content","schema","validateToolCallArguments","known","seenIds","toolIssues","unknownTool","issue","primary","definition","refusalError","shapeResponse","callParams","rawContent","refusal","debugOutput","truncated","textContent","useJson","finalizeResponse","deps","withThinking","thinking","softFailureCode","detectSoftFailureSafely","detectSoftFailure","usageReporter","usage","asTruncationError","stack","KNOWN","toFinishReason","mapped","reason","refused","reactToRateLimitError","dispatchToProvider","providerFailure","dispatch","redactResponseBody","executeCall","acquiredRelease","response","attemptSignal","actualTokens","choice","finishReason","finalized","createBackpressureChannel","stallTimeoutMs","stallError","buffered","done","failure","hasLoggedEviction","spaceWaiters","stall","stallTimer","detachStalledReaders","releaseProducer","waiters","push","waiter","capacity","finish","fail","owner","MAX_TOOL_CALLS","MAX_TOOL_ARGUMENTS_LENGTH","createToolCallAccumulator","apply","delta","argumentsDelta","indexA","indexB","createStreamAccumulation","chunk","onRateLimitHint","usageMeta","closeIterator","streamController","untilSpaceOrAbort","signals","s","space","buildStreamResult","resolveFinal","rejectFinal","channel","readerStallTimeoutMs","accumulation","first","chunkIdleTimeoutMs","executeStreamCall","completions","createStream","combinedExternal","streamIterator","firstResult","onOpened","readUntilContent","releaseAtOpen","hint","textAcc","held","isContentChunk","lastUsage","onFailedUsage","queue","queued","serializeAssistantContent","validateTools","toolChoice","resolveJsonMode","jsonMode","jsonModeExplicit","supportsJsonObjectMode","jsonSchema","hasSchema","buildResponseFormat","buildWireToolChoice","turnToWireMessages","turn","tr","assertValidThinking","blockIndex","block","validateHistory","previousTurn","history","requestedIds","resultIds","unknownIds","id","duplicateIds","missingIds","RequestBuilder","temperature","reasoningEffort","budgetTokens","responseFormat","maxTokens","systemPrompt","userContent","createUsageReporter","cacheReadsCount","extract","actualTokensFor","total","counted","reportSuccess","reportFailure","displayTokens","attemptText","terminal","combineSignals","present","setupCallSignal","breakController","cancellable","chainBySignal","chainSignal","markChain","number","chainFields","createBreakerGateway","buildAttemptContext","isFallback","middlewareNames","buildCallContext","settleQuietly","operation","runAttemptLoop","resolvedState","normalize","budgetExhaustedError","budget","recordBudgetAttempt","logLabel","defaultParseJson","CallExecutor","resolvedModel","declaredTargets","describeTargets","modelFor","noEligibleTargets","narrowTargets","requested","narrowed","all","target","allowed","onDropped","modelForTarget","targetIndex","paramsForTarget","runFallbackChain","fallbackAttempts","dependencies","position","targetModel","startedAt","attemptCount","skipBreakerCheckForFirst","checking","normalizedError","isLastTarget","policyDecision","reportFallback","nextExecutor","metaFor","buildCallResult","executeLogicalCall","soleTarget","executeLogicalStreamCall","resolveOpened","runReservedLogicalCall","soleModel","breakerContext","captureMeta","ChainSet","incoming","reruns","keptEntry","kept","keepMeta","warnedNoChainKept","settleChains","chains","warnNoChainKept","runOperation","main","wrapOrder","skipWrap","coreOperation","transformIndexByEntry","middlewareIndex","transformNames","narrow","requestedTargets","onceNext","targetsLeft","mainChain","wrapNext","again","rerunChain","resolvedResult","createCallScope","delivered","delivering","warned","source","isValidCustomEvent","buildCooldownBackoff","baseCooldownMs","multiplier","reopenCount","maxMs","floor","newBucket","keyFor","trialPermits","claimsCurrentTrial","bucket","attributeFailure","resetBucket","ConsecutiveTripping","threshold","RollingTripping","minCalls","failureRatio","ratio","buildTripping","CircuitBreaker","rawProbes","rawRatio","cooldown","computed","admitted","to","from","trial","REQUIRED_ADAPTER_METHOD_NAMES","ADAPTER_ONLY_METHOD_NAMES","OPTIONAL_FUNCTION_MEMBER_NAMES$2","invalidOptionalMembers$1","hasInvalidPrepareTimeout","prepareTimeoutMs","classifyCircuitBreakerOption","wrapOnStateChange","defaultModel","callContext","userOnStateChange","consecutiveFailures","adapterSubscribers","warnedAboutSharing","wireAdapterOnStateChange","subscribers","adapter","originalOnStateChange","currentSubscribers","sub","subscriber","buildCircuitBreaker","circuitBreakerOption","wrap","attemptsAdapter","missing","invalid","described","breakerOptions","TokenBucket","refillPerMs","elapsedMs","amount","newCapacity","buildEstimateFraction","fraction","buildAimdOptions","assertFinite","assertValidLimits","maxQueueMs","aimd","measureContent","chars","images","safeJsonLength","defaultEstimateTokens","measured","amountFor","estimatedTokens","buildPerMinuteBucket","capacityPerMinute","RateLimiter","initialReason","cleanup","resolvePromise","rejectPromise","queueTimer","taken","waitedMs","success","ADAPTER_METHOD_NAMES$1","OPTIONAL_FUNCTION_MEMBER_NAMES$1","invalidOptionalMembers","isRateLimiterAdapter","isIncompleteRateLimiterAdapter","buildRateLimit","ADAPTER_METHOD_NAMES","OPTIONAL_FUNCTION_MEMBER_NAMES","buildRetryBudget","members","isFunction","resolveTargetNames","duplicate","buildExecutors","primaryTarget","declaredFallbacks","idFor","assertNoDuplicatePublishedLabels","assertNoDuplicateLabels","ids","assertNoDuplicateRefs","ref","firstIndex","unwrapReference","resolveReference","targetNode","byRef","required","fromId","precedes","byId","buildNodes","nodes","node","byPriorityThenIndex","priorityDiff","topologicalSort","indegree","ready","emitted","afterId","remaining","stuck","resolveMiddlewareOrder","hasEdges","applyPositionOverride","outermost","innermost","middle","sortedMiddle","registered","buildMiddlewarePipeline","isCacheAdapter","buildCache","ConsoleLogger","debugEnabled","VernLLM","pipeline","primaryDefaultTemperature","primaryDefaultReasoningEffort","primaryDefaultBudgetTokens","cachedCallState","isCachedCallInner","stateEntries","effectiveParams","effectiveSignal","chosen","dispose","cacheParams","restCallParams","resolvedCacheKey","metaHolder","releaseMetaHolder","callerMeta","rerunMetas","metaFromRerun","syncCallerMeta","participantSignal","deadlineTimer","participantCacheParams","participantParams","callInner","_deadlineMs","sharedParams","innerParams","callShared","sharedSignal","cacheOutcome","onOutcome","releaseOnSettle","wrapped","freshMeta","freshParams","waitParams","streamResult","onStreamSettled","defineCallParams","defineCachedCallParams"],"sources":["../src/types/cache.ts","../src/types/tools.ts","../src/types/stream.ts","../src/types/fallback.ts","../src/types/middleware.ts","../src/types/createMiddleware.ts","../src/internal/execution/utils/response/usage.utils.ts","../src/internal/execution/utils/stream/earlyExit.utils.ts","../src/internal/utils/deferred.utils.ts","../src/internal/utils/logger.utils.ts","../src/internal/cache/utils/inFlightRegistry.utils.ts","../src/internal/cache/utils/replay.utils.ts","../src/internal/cache/utils/sharedAbort.utils.ts","../src/internal/cache/cacheOrchestrator.ts","../src/internal/cache/utils/metaHolder.utils.ts","../src/internal/rollingRatio.ts","../src/internal/utils/validate.utils.ts","../src/retryBudget.ts","../src/internal/utils/adapterInfo.utils.ts","../src/internal/utils/circuit-breaker/circuitBreaker.utils.ts","../src/internal/utils/circuit-breaker/prepareBreaker.utils.ts","../src/internal/execution/utils/deadline.utils.ts","../src/internal/utils/callScope.utils.ts","../src/internal/utils/middlewareLabels.utils.ts","../src/internal/execution/utils/retry/retryAfter.utils.ts","../src/internal/execution/utils/retry/timeout.utils.ts","../src/internal/execution/utils/retry/retry.utils.ts","../src/internal/execution/utils/errors.utils.ts","../src/internal/execution/utils/once.utils.ts","../src/internal/execution/utils/middleware/transformPatch.utils.ts","../src/internal/execution/utils/middleware/middleware.utils.ts","../src/internal/execution/utils/dispatch/rateLimitDispatch.utils.ts","../src/internal/execution/utils/dispatch/attemptDispatch.utils.ts","../src/internal/execution/attempt/attemptEnvironment.ts","../src/internal/execution/utils/wire.utils.ts","../src/internal/execution/utils/response/responseShape.utils.ts","../src/internal/execution/responseFinalizer.ts","../src/internal/execution/utils/response/finishReason.utils.ts","../src/internal/execution/attempt/providerDispatch.ts","../src/internal/execution/attempt/nonStreamAttempt.ts","../src/internal/execution/utils/stream/chunkBuffer.utils.ts","../src/internal/execution/utils/stream/toolCallAccumulator.utils.ts","../src/internal/execution/utils/stream/streamAccumulation.utils.ts","../src/internal/execution/streamAccumulator.ts","../src/internal/execution/attempt/streamAttempt.ts","../src/internal/execution/utils/request/requestShape.utils.ts","../src/internal/execution/requestBuilder.ts","../src/internal/execution/usageReporter.ts","../src/internal/execution/utils/callSignal.utils.ts","../src/internal/utils/chain.utils.ts","../src/internal/execution/circuitBreakerContext.ts","../src/internal/execution/utils/dispatch/attemptLoop.utils.ts","../src/internal/execution/utils/parse.utils.ts","../src/internal/execution/callExecutor.ts","../src/internal/execution/targetOrder.ts","../src/internal/execution/logicalCall.ts","../src/internal/execution/reservedLogicalCall.ts","../src/internal/execution/utils/middleware/chains.utils.ts","../src/internal/execution/runOperation.ts","../src/internal/execution/utils/middleware/customEvent.utils.ts","../src/internal/utils/circuit-breaker/circuitBucket.utils.ts","../src/circuitBreaker.ts","../src/internal/utils/circuit-breaker/circuitBreakerAdapter.utils.ts","../src/internal/tokenBucket.ts","../src/internal/utils/rate-limit/rateLimitOptions.utils.ts","../src/internal/utils/rate-limit/tokenEstimate.utils.ts","../src/rateLimit.ts","../src/internal/utils/rate-limit/rateLimitAdapter.utils.ts","../src/internal/utils/retry-budget/retryBudgetAdapter.utils.ts","../src/internal/utils/targetNames.utils.ts","../src/internal/executorFactory.ts","../src/internal/resolveMiddlewareOrder.ts","../src/internal/utils/cache/cacheAdapter.utils.ts","../src/logger.ts","../src/vernLLM.ts","../src/paramsHelpers.ts"],"sourcesContent":["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 * Which entry `InMemoryCacheAdapter` evicts once `maxSize` is exceeded.\n * `'fifo'` (default) drops the oldest inserted entry. `'lru'` drops the\n * least recently read or written entry.\n */\nexport type EvictionOption = 'fifo' | 'lru';\n\n/** Not exported. `onAccess`/`onInsert` mark recency, `getEvictee` picks the next victim. */\ninterface Eviction {\n onAccess(store: Map<string, unknown>, key: string): void;\n onInsert(store: Map<string, unknown>, key: string): void;\n getEvictee(store: Map<string, unknown>): string | undefined;\n}\n\nconst FIFO: Eviction = {\n onAccess() {},\n onInsert() {},\n getEvictee: (store) => store.keys().next().value,\n};\n\n/** Moves `key` to the end of `store`'s iteration order. No-op if `key` isn't present. */\nfunction touch(store: Map<string, unknown>, key: string): void {\n // Defensive: both call sites (onAccess in get(), onInsert in set())\n // only invoke this after confirming the key is already in the store,\n // so this guard never actually trips today. Kept in case a future\n // eviction policy calls touch() from a context that can't make the\n // same guarantee.\n /* v8 ignore next */\n if (!store.has(key)) return;\n\n const value = store.get(key);\n store.delete(key);\n store.set(key, value);\n}\n\nconst LRU: Eviction = {\n onAccess: touch,\n onInsert: touch,\n getEvictee: (store) => store.keys().next().value,\n};\n\n/** Not exported. Resolves the shorthand into the shared `Eviction` instance. */\nfunction buildEviction(option: EvictionOption): Eviction {\n return option === 'lru' ? LRU : FIFO;\n}\n\n/**\n * True for a ttl that can actually expire an entry. `undefined` and NaN\n * would otherwise produce a NaN expiry that never compares as due, and a\n * zero or negative ttl is already expired on arrival.\n */\nfunction isLiveTtl(ttl: number): boolean {\n return typeof ttl === 'number' && ttl > 0;\n}\n\n/**\n * Whether `structuredClone` copies `value` faithfully all the way down. A class instance would lose\n * its methods, and functions or symbols can't be cloned.\n */\nfunction isFaithfullyCloneable(value: unknown, seen = new Set<object>()): boolean {\n if (value === null) return true;\n\n const type = typeof value;\n if (type === 'function' || type === 'symbol') return false;\n if (type !== 'object') return true;\n\n const object = value as object;\n if (seen.has(object)) return true;\n seen.add(object);\n\n if (\n object instanceof Date ||\n object instanceof RegExp ||\n object instanceof ArrayBuffer ||\n ArrayBuffer.isView(object)\n ) {\n return true;\n }\n\n if (object instanceof Map) {\n for (const [key, item] of object) {\n if (!isFaithfullyCloneable(key, seen) || !isFaithfullyCloneable(item, seen)) return false;\n }\n return true;\n }\n\n if (object instanceof Set) {\n for (const item of object) {\n if (!isFaithfullyCloneable(item, seen)) return false;\n }\n return true;\n }\n\n const prototype = Object.getPrototypeOf(object);\n if (!Array.isArray(object) && prototype !== Object.prototype && prototype !== null) return false;\n\n // Symbol keys and accessors are dropped or flattened by structuredClone.\n if (Object.getOwnPropertySymbols(object).length > 0) return false;\n\n for (const descriptor of Object.values(Object.getOwnPropertyDescriptors(object))) {\n if (!('value' in descriptor)) return false;\n if (!isFaithfullyCloneable(descriptor.value, seen)) return false;\n }\n\n return true;\n}\n\n/**\n * The default in-process cache. Not shared across processes; use a shared backend in production.\n * Values are copied on `set` and `get`, so mutating a result never changes the next hit. A value\n * that can't be copied faithfully, or a missing, NaN, zero or negative `ttl`, is not stored and\n * drops any existing entry.\n */\nexport class InMemoryCacheAdapter<T = unknown> implements CacheAdapter<T> {\n private store = new Map<string, { value: T; expiresAt: number }>();\n private readonly eviction: Eviction;\n\n constructor(\n private readonly maxSize = 1000,\n eviction: EvictionOption = 'fifo',\n ) {\n this.eviction = buildEviction(eviction);\n }\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 this.eviction.onAccess(this.store, key);\n // Only faithfully cloneable values are ever stored, see `set`.\n return { hit: true, value: structuredClone(entry.value) };\n }\n\n async set(key: string, value: T, ttl: number): Promise<void> {\n this.cleanupExpiredEntries();\n\n if (!isLiveTtl(ttl) || !isFaithfullyCloneable(value)) {\n // The caller asked to replace this key, so an older value must not survive.\n this.store.delete(key);\n return;\n }\n\n this.store.set(key, {\n value: structuredClone(value),\n expiresAt: Date.now() + ttl * 1000,\n });\n this.eviction.onInsert(this.store, key);\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 victim = this.eviction.getEvictee(this.store);\n\n if (victim === undefined) break;\n\n this.store.delete(victim);\n }\n }\n}\n\n/**\n * Normalizes keys to avoid duplicates from formatting that can't change a prompt's meaning: Unicode\n * composition, line endings and outer whitespace. Case, punctuation and inner whitespace are kept,\n * since `\"2+2\"` and `\"2-2\"` must never share an answer.\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.normalize('NFC').replace(/\\r\\n?/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/** Upper bound on tracked L2 expiries, so a long running process can't grow the map forever. */\nconst MAX_TRACKED_EXPIRIES = 10_000;\n\n/**\n * Two tier cache: fast local L1, shared L2, with L2 hits promoted to L1. An L1 entry never outlives\n * an L2 entry this adapter wrote. A promoted entry another process wrote keeps `l1Ttl`, since L2\n * doesn't report remaining ttl.\n */\nexport class TieredCacheAdapter<T = unknown> implements CacheAdapter<T> {\n /** L2 expiry (epoch ms) per key this adapter wrote, oldest write first. */\n private readonly l2ExpiresAt = new Map<string, number>();\n\n /**\n * Expiries as a min heap, so a write only visits expired records. Stale heap entries are skipped\n * unless the map still holds that exact expiry.\n */\n private expiryHeap: Array<{ key: string; expiresAt: number }> = [];\n\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.promotionTtl(key));\n }\n\n return l2Result;\n }\n\n async set(key: string, value: T, ttl: number): Promise<void> {\n this.trackExpiry(key, ttl);\n\n // An L1 ttl above the L2 ttl would keep serving the value after L2 dropped it.\n const l1Ttl = this.l1Ttl === undefined ? ttl : Math.min(this.l1Ttl, ttl);\n\n await Promise.all([this.l1.set(key, value, l1Ttl), this.l2.set(key, value, ttl)]);\n }\n\n async delete(key: string): Promise<void> {\n this.l2ExpiresAt.delete(key);\n await Promise.all([this.l1.delete?.(key), this.l2.delete?.(key)]);\n }\n\n /** L1 ttl for a promoted entry, capped at the seconds L2 has left when that is known. */\n private promotionTtl(key: string): number {\n const fallback = this.l1Ttl ?? 60;\n const expiresAt = this.l2ExpiresAt.get(key);\n\n if (expiresAt === undefined) return fallback;\n\n // L2 still served a key whose tracked write has expired, so another\n // process rewrote it since. The record describes an entry that no\n // longer exists; treat the hit like any other external entry.\n if (expiresAt <= Date.now()) {\n this.l2ExpiresAt.delete(key);\n return fallback;\n }\n\n return Math.min(fallback, (expiresAt - Date.now()) / 1000);\n }\n\n private trackExpiry(key: string, ttl: number): void {\n const now = Date.now();\n\n this.pruneExpired(now);\n\n // Reinserted so the map's order stays oldest write first for the cap below.\n this.l2ExpiresAt.delete(key);\n\n // A ttl that isn't a number stays untracked, so promotion falls back to l1Ttl.\n if (typeof ttl !== 'number' || Number.isNaN(ttl)) return;\n\n const expiresAt = now + ttl * 1000;\n this.l2ExpiresAt.set(key, expiresAt);\n heapPush(this.expiryHeap, { key, expiresAt });\n\n while (this.l2ExpiresAt.size > MAX_TRACKED_EXPIRIES) {\n const oldest = this.l2ExpiresAt.keys().next().value;\n /* v8 ignore next */\n if (oldest === undefined) break;\n this.l2ExpiresAt.delete(oldest);\n }\n\n // Stale heap entries (rewrites, deletes, capped keys) would otherwise\n // pile up for keys that never expire soon. Rebuilding from the map is\n // O(n) and only runs once the heap holds twice what it needs.\n if (this.expiryHeap.length > 2 * this.l2ExpiresAt.size + 64) {\n this.expiryHeap = [];\n for (const [trackedKey, trackedExpiry] of this.l2ExpiresAt) {\n heapPush(this.expiryHeap, { key: trackedKey, expiresAt: trackedExpiry });\n }\n }\n }\n\n /** Drops every tracked record that has expired, visiting only those. */\n private pruneExpired(now: number): void {\n while (this.expiryHeap.length > 0 && this.expiryHeap[0]!.expiresAt <= now) {\n const { key, expiresAt } = heapPop(this.expiryHeap)!;\n if (this.l2ExpiresAt.get(key) === expiresAt) this.l2ExpiresAt.delete(key);\n }\n }\n}\n\ntype ExpiryRecord = { key: string; expiresAt: number };\n\n/** Adds `record` to a min-heap ordered by `expiresAt`. */\nfunction heapPush(heap: ExpiryRecord[], record: ExpiryRecord): void {\n heap.push(record);\n let index = heap.length - 1;\n\n while (index > 0) {\n const parent = (index - 1) >> 1;\n if (heap[parent]!.expiresAt <= heap[index]!.expiresAt) break;\n [heap[parent], heap[index]] = [heap[index]!, heap[parent]!];\n index = parent;\n }\n}\n\n/** Removes and returns the soonest record of a min-heap ordered by `expiresAt`. */\nfunction heapPop(heap: ExpiryRecord[]): ExpiryRecord | undefined {\n const top = heap[0];\n const last = heap.pop();\n if (top === undefined || last === undefined || heap.length === 0) return top;\n\n heap[0] = last;\n let index = 0;\n\n for (;;) {\n const left = 2 * index + 1;\n const right = left + 1;\n let smallest = index;\n\n if (left < heap.length && heap[left]!.expiresAt < heap[smallest]!.expiresAt) smallest = left;\n if (right < heap.length && heap[right]!.expiresAt < heap[smallest]!.expiresAt) smallest = right;\n if (smallest === index) return top;\n\n [heap[smallest], heap[index]] = [heap[index]!, heap[smallest]!];\n index = smallest;\n }\n}\n","import type { ThinkingBlock } from './call.js';\nimport 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 * Validates the parsed `arguments`, using the same `safeParse` shape as `schema`. Failure throws\n * `LLMError('validation')`; on success `ToolCall.arguments` is the schema's output, defaults and\n * transforms applied. Without it, arguments are parsed as JSON only. Types flow into `ToolCall`\n * when the tool's `name` is literal, see `defineTool()`.\n */\n argumentsSchema?: SchemaLike<Args>;\n}\n\n/**\n * Keeps a tool's literal `name` and inferred `Args`, so `ToolCall` narrows by name. A plain object\n * literal widens `name` to `string` without `as const`, which breaks narrowing once a second tool\n * is added.\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 * One tool call from the model. With a literal `Tools` tuple this is a union keyed by `name`, so\n * checking `name` narrows `arguments`. Otherwise `arguments` is `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 * Marks a failed tool execution. Sent as Anthropic's `is_error` and Bedrock's error status;\n * OpenAI-compatible adapters prefix the content with `Error: `; Gemini has no equivalent and\n * ignores it.\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 * Claude's reasoning blocks before this tool request, when thinking is\n * on (`fromAnthropic` and `fromBedrock`). Put them on the assistant\n * history turn with `toolCalls` so the tool loop can continue.\n */\n thinking?: ThinkingBlock[];\n}\n\nexport type CallWithToolsResult<T, Tools extends readonly ToolDefinition[] = ToolDefinition[]> =\n | ContentResult<T>\n | ToolCallResult<Tools>;\n\n/** Recovers `Tools` from a `result` already typed `ContentResult<T> | ToolCallResult<Tools>`. Falls back to `ToolDefinition[]`. */\ntype ExtractTools<R> =\n Extract<R, ToolCallResult<ToolDefinition[]>> extends ToolCallResult<infer Tools>\n ? Tools\n : ToolDefinition[];\n\n/** Explicit `Tools` type argument if given, otherwise inferred via `ExtractTools`. `never` marks \"unset\". */\ntype ResolvedTools<Tools, R> = [Tools] extends [never] ? ExtractTools<R> : Tools;\n\n/**\n * Whether a `call()` result is a tool calls result. Use it whenever `tools` was set conditionally.\n * `toolCalls[number].arguments` is typed per tool; pass `Tools` explicitly to override inference,\n * e.g. `isToolCallResult<typeof tools>(result)`.\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 if (typeof result !== 'object' || result === null) return false;\n\n const candidate = result as Partial<ToolCallResult>;\n return candidate.type === 'tool_calls' && Array.isArray(candidate.toolCalls);\n}\n\n/** What the model should do about tools on a given call. */\nexport type ToolChoice = 'auto' | 'none' | 'required' | { name: string };\n","import type { ProviderRateLimitHint } from '../internal/utils/rate-limit/rateLimitHint.utils.js';\nimport type {\n CachedCallInput,\n CallParams,\n ConditionalStringToolCallParams,\n JsonValue,\n LLMRequestShape,\n ThinkingBlock,\n} from './call.js';\nimport type { ToolDefinition } from './tools.js';\nimport type { TokenUsage } from './usage.js';\n\n/** One incremental unit of a streaming response, as delivered to the caller. */\nexport type StreamChunk =\n | { type: 'text-delta'; delta: string }\n | {\n type: 'tool_call_delta';\n index: number;\n id?: string;\n name?: string;\n argsDelta?: string;\n /**\n * True when `argsDelta` holds the whole arguments rather than a fragment, as with Gemini and\n * cache replays.\n */\n complete?: boolean;\n }\n | { type: 'usage'; usage: TokenUsage };\n\n/**\n * What `call()` returns with `stream: true`. `finalResult` resolves to the same shape a\n * non-streaming call returns. `chunks` is single use; see the streaming docs.\n */\nexport interface StreamCallResult<R> {\n chunks: AsyncIterable<StreamChunk>;\n finalResult: Promise<R>;\n}\n\n/** `CallParams` with `stream: true`, selecting the overload that returns `StreamCallResult`. */\nexport type StreamEnabledCallParams<\n T,\n Tools extends readonly ToolDefinition[] = ToolDefinition[],\n> = CallParams<T, Tools> & { stream: true };\n\n/** Streaming conditional tool-call parameters whose non-tool result is text. */\nexport type StreamConditionalStringToolCallParams<\n Tools extends readonly ToolDefinition[] = ToolDefinition[],\n> = StreamEnabledCallParams<string, Tools> & ConditionalStringToolCallParams<Tools>;\n\n/** Recovers `T` from a `result` already typed `T | StreamCallResult<T>`. Falls back to `unknown`. */\ntype ExtractStreamValue<R> =\n Extract<R, StreamCallResult<unknown>> extends StreamCallResult<infer V> ? V : unknown;\n\n/** Minimal duck-typed `PromiseLike` check: anything with a callable `.then`. */\nfunction isPromiseLike(value: unknown): value is PromiseLike<unknown> {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as { then?: unknown }).then === 'function'\n );\n}\n\n/** Minimal duck-typed `AsyncIterable` check: anything with a callable `Symbol.asyncIterator`. */\nfunction isAsyncIterable(value: unknown): value is AsyncIterable<unknown> {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as { [Symbol.asyncIterator]?: unknown })[Symbol.asyncIterator] === 'function'\n );\n}\n\n/**\n * Whether a `call()` result is a `StreamCallResult`. Useful when `stream` was set conditionally,\n * since the overloads only pick the streaming shape for a literal `stream: true`.\n */\nexport function isStreamResult<R = unknown>(\n result: R,\n): result is R & StreamCallResult<ExtractStreamValue<R>> {\n if (typeof result !== 'object' || result === null) return false;\n\n const candidate = result as Partial<StreamCallResult<unknown>>;\n return isAsyncIterable(candidate.chunks) && isPromiseLike(candidate.finalResult);\n}\n\n/**\n * Streaming `jsonMode: false`, with `finalResult` as a `string`. `jsonSchema` is `never`, as in\n * `JsonModeDisabledCallParams`.\n */\nexport type StreamJsonModeDisabledCallParams = Omit<\n StreamEnabledCallParams<unknown>,\n 'jsonSchema'\n> & {\n jsonMode: false;\n jsonSchema?: never;\n};\n\n/**\n * Streaming `jsonMode: true` without `schema`, with `finalResult` as `JsonValue`. `schema` is\n * `never`, as in `JsonModeEnabledCallParams`.\n */\nexport type StreamJsonModeEnabledCallParams = Omit<StreamEnabledCallParams<JsonValue>, 'schema'> & {\n jsonMode: true;\n schema?: never;\n};\n\n/**\n * The adapter-facing, pre-normalization shape a `createStream` client\n * implementation emits, analogous to how `WireMessage`/`WireToolCall`\n * already sit between `CallParams` and each provider's own wire format.\n */\nexport type WireStreamChunk =\n | { type: 'text-delta'; delta: string }\n | {\n type: 'tool_call_delta';\n index: number;\n id?: string;\n name?: string;\n argumentsDelta?: string;\n /** Same meaning as `StreamChunk`'s `tool_call_delta.complete`. */\n complete?: boolean;\n }\n | {\n type: 'usage';\n usage: {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n completion_tokens_details?: { reasoning_tokens?: number };\n /** Cache split of `prompt_tokens`. Follows OpenAI and OpenRouter naming. */\n prompt_tokens_details?: {\n cached_tokens?: number;\n cache_write_tokens?: number;\n /** Writes by TTL label, e.g. `{ '5m': 1200, '1h': 800 }`. */\n cache_write_tokens_by_ttl?: Record<string, number>;\n };\n /** What the provider billed for the call, in USD. OpenRouter reports it as `usage.cost`. */\n cost?: number;\n };\n }\n | {\n /** A provider keep-alive with no content. Resets the idle timeout; never reaches callers. */\n type: 'ping';\n }\n | {\n /**\n * A rate limit hint from the stream's response headers, yielded as early as possible for\n * AIMD. The streaming counterpart of `attachRateLimitHint`. Never reaches callers.\n */\n type: 'rate_limit_hint';\n hint: ProviderRateLimitHint;\n }\n | {\n /** The provider declined. Never reaches callers: with no content, the call fails as `model_refused`. */\n type: 'refusal';\n delta?: string;\n }\n | {\n /** Why generation stopped, as the provider spells it. Never reaches callers; core maps it onto `FinishReason`. */\n type: 'finish';\n reason: string;\n }\n | {\n /**\n * One complete reasoning block, yielded once it has fully arrived.\n * Collected onto `ToolCallResult.thinking`, never surfaced to\n * callers as a `StreamChunk`.\n */\n type: 'thinking_block';\n block: ThinkingBlock;\n };\n\n/**\n * A cached streaming call without tools. A miss relays live chunks; a hit replays the cached value\n * as chunks. `reserveUsage` and `refundUsage` go at the top level.\n */\nexport type CachedStreamCallParams<T> = CachedCallInput & {\n call: LLMRequestShape<T> & { stream: true };\n};\n\n/** A cached streaming call with tools, caching the full `CallWithToolsResult<T>`. */\nexport type CachedStreamToolCallParams<\n T,\n Tools extends readonly ToolDefinition[] = ToolDefinition[],\n> = CachedCallInput & {\n call: LLMRequestShape<T, Tools> & {\n stream: true;\n tools: NonNullable<LLMRequestShape<T, Tools>['tools']>;\n };\n};\n\n/**\n * A cached streaming call with `call.tools` set conditionally, resolving to `T |\n * CallWithToolsResult<T>`.\n */\nexport type CachedStreamConditionalToolCallParams<\n T,\n Tools extends readonly ToolDefinition[] = ToolDefinition[],\n> = CachedCallInput & {\n call: LLMRequestShape<T, Tools> & { stream: true; tools: Tools | undefined };\n};\n\n/** Cached streaming conditional tool-call parameters whose non-tool result is text. */\nexport type CachedStreamConditionalStringToolCallParams<\n Tools extends readonly ToolDefinition[] = ToolDefinition[],\n> = CachedStreamConditionalToolCallParams<string, Tools> & {\n call: { jsonMode: false };\n};\n\n/**\n * Parameters for a cached, streaming LLM call with `jsonMode: false`.\n * Selects the `cachedCall()` overload whose `finalResult` (on a miss) or\n * cached value (on a hit) is a plain `string`.\n */\nexport type CachedStreamJsonModeDisabledCallParams = CachedCallInput & {\n call: Omit<LLMRequestShape<unknown>, 'jsonSchema'> & {\n stream: true;\n jsonMode: false;\n jsonSchema?: never;\n };\n};\n\n/**\n * Parameters for a cached, streaming LLM call with `jsonMode: true` and no\n * `schema`. Selects the `cachedCall()` overload whose `finalResult` (on a\n * miss) or cached value (on a hit) is a `JsonValue`.\n */\nexport type CachedStreamJsonModeEnabledCallParams = CachedCallInput & {\n call: Omit<LLMRequestShape<JsonValue>, 'schema'> & {\n stream: true;\n jsonMode: true;\n schema?: never;\n };\n};\n","import { LLMError, type RetryAttempt } from './errors.js';\n\nimport type { CircuitState } from '../circuitBreaker.js';\nimport type { CircuitBreakerOption } from '../internal/utils/circuit-breaker/circuitBreakerAdapter.utils.js';\nimport type { RateLimitOption } from '../internal/utils/rate-limit/rateLimitAdapter.utils.js';\nimport type { RetryBudgetOption } from '../internal/utils/retry-budget/retryBudgetAdapter.utils.js';\nimport type { DetectSoftFailure } from './call.js';\nimport type { AdapterInfo, LLMClient } from './client.js';\n\n/**\n * A provider tried after the primary fails, in the order given. Omitted overrides fall back to the\n * instance's options, except `circuitBreaker`, `rateLimit` and `retryBudget`, which are never\n * inherited since limits tuned for the primary rarely fit a fallback.\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 readerStallTimeoutMs?: number;\n baseDelayMs?: number;\n maxRetryAfterMs?: 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 breaker, or a shared `CircuitBreakerAdapter`. Not inherited from the parent's `circuitBreaker`. */\n circuitBreaker?: CircuitBreakerOption;\n /** This target's own rate limiter, independent of every other target's. Not inherited from the parent's `rateLimit`. */\n rateLimit?: RateLimitOption;\n /** This target's own retry budget, independent of every other target's. Not inherited from the parent's `retryBudget`. */\n retryBudget?: RetryBudgetOption;\n /**\n * Reclassifies a successful result from this target as a failure. Inherits the instance's\n * `detectSoftFailure` when omitted.\n */\n detectSoftFailure?: DetectSoftFailure;\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 */\n/**\n * Why the answering target stopped. Adapters map their provider's reason onto these. `'other'`\n * is any reason with no match here.\n */\nexport type FinishReason =\n | 'stop'\n | 'length'\n | 'tool_calls'\n | 'refusal'\n | 'guardrail'\n | 'content_filter'\n | 'other';\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 /** Position of the answering target in the order tried, 0 based. */\n position: number;\n /** Absent for the main chain, 1 and up for chains started with `next.again()`. */\n chain?: number;\n /**\n * Why the answering target stopped, when its adapter reports it. For a stream it is set once\n * `finalResult` resolves. Absent on a cache hit.\n */\n finishReason?: FinishReason;\n}\n\n/** One configured target, as a middleware sees it in `ctx.targets`. */\nexport interface TargetInfo {\n /** The name `targets` selects by. */\n name: string;\n /** Declared position: 0 is the primary. */\n index: number;\n model: string;\n adapter: AdapterInfo;\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. `index` is `-1` for the primary; `provider` and `model` name the target.\n */\nexport interface FallbackAttempt extends RetryAttempt {\n provider: string;\n model: string;\n}\n\n/** What `fallbackOn` is told about the failed target and what would come after it. */\nexport interface FallbackOnContext {\n /** Whether no target is left in the order tried. The chain stops after the last one whatever `fallbackOn` returns. */\n isLastTarget: boolean;\n /** The target that just failed. `model` is what it ran, so the per call `model` shows on the primary only. */\n failed: TargetInfo;\n /** The target that would be tried next. `undefined` on the last target. */\n next?: TargetInfo;\n}\n\n/**\n * Whether to try the next target (`'next'`) or give up (`'stop'`) after a target's own retries.\n * Called once per failed target.\n */\nexport type FallbackOn = (error: LLMError, context: FallbackOnContext) => 'next' | 'stop';\n\n/**\n * Tool contract failures another provider can't fix. Most are the model ignoring the request;\n * `duplicate_tool_call_id` is a provider protocol violation, but equally not something a fallback\n * would change.\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: (\n error: LLMError,\n context: Pick<FallbackOnContext, 'isLastTarget'>,\n) => 'next' | 'stop' = (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 // Caller input is rejected locally before any provider sees it, so every\n // target would reject it the same way. `unsupported_capability` is the\n // exception: it's one adapter's limit, and another target may support it.\n if (error.type === 'invalid_params' && error.code !== 'unsupported_capability') return 'stop';\n\n return 'next';\n};\n\n/**\n * Thrown when the chain gives up, carrying every attempt in order. Extends `LLMError` and takes the\n * last failure's `type`, `status` and `retryAfterMs`, so existing handling keeps working.\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 * Defers to the last attempt's `retryable`, since `fallback_exhausted` alone says nothing about\n * it.\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\n/**\n * An empty holder for `CallParams['meta']`, so `call()`'s `CallMeta` can be read without declaring\n * one by hand.\n *\n * @example\n * const meta = metaRef();\n * const result = await vern.call({ userContent: '...', meta });\n * meta.current?.provider;\n */\nexport function metaRef(): { current?: CallMeta } {\n return {};\n}\n","import type { CallContext, JsonValue } from './call.js';\nimport type { AdapterInfo, WireMessage, WireToolChoice } from './client.js';\nimport type { VernLLMEvent } from './events.js';\nimport type { CallMeta, TargetInfo } from './fallback.js';\n\n/** Capabilities of the target a middleware hook is currently looking at. */\nexport interface MiddlewareCapabilities {\n /**\n * Whether this target honors `response_format: { type: 'json_object' }`\n * as a real constraint. Mirrors `LLMClient.supportsJsonObjectMode`.\n * `false` for `fromAnthropic` and `fromBedrock`.\n */\n supportsJsonObjectMode: boolean;\n}\n\n/**\n * The `{ debugName }` shape shared by state keys and middleware refs, before each adds its own\n * brand.\n */\nfunction createIdentityToken(debugName: string): { debugName: string } {\n return { debugName };\n}\n\n/**\n * Brands `MiddlewareStateKey` so a ref, or a hand written `{ debugName }`, can't pass as a state\n * key. Only `createStateKey` can produce one.\n */\ndeclare const stateKeyBrand: unique symbol;\n\n/**\n * A typed reference to one slot in `ctx.state`. Create it with `createStateKey` and import it\n * wherever the value is shared, so a typo is a compile error instead of a new property.\n */\nexport interface MiddlewareStateKey<T> {\n readonly debugName: string;\n readonly [stateKeyBrand]: true;\n\n /**\n * Never set. Makes keys of different `T` distinct types, so `get` and `set` infer the value type.\n */\n readonly __phantom?: T;\n}\n\n/** Creates a new, distinct `MiddlewareStateKey`. `debugName` is used only in log lines and the `'middleware'` event; it never affects equality. */\nexport function createStateKey<T>(debugName: string): MiddlewareStateKey<T> {\n return createIdentityToken(debugName) as MiddlewareStateKey<T>;\n}\n\n/** Not exported. See `stateKeyBrand`; same reasoning, distinct symbol, so the two token types can't be cross-assigned either. */\ndeclare const middlewareRefBrand: unique symbol;\n\n/**\n * A typed reference to a middleware, used only as a `runsAfter` or `runsBefore` target, never as a\n * label. Create it with `createMiddlewareRef` and export it, so a typo is a compile error.\n */\nexport interface MiddlewareRef {\n readonly debugName: string;\n readonly [middlewareRefBrand]: true;\n}\n\n/** Creates a new, distinct `MiddlewareRef`. `debugName` is used only in error messages when a reference doesn't resolve; it never affects equality, so two refs with the same `debugName` never collide. */\nexport function createMiddlewareRef(debugName: string): MiddlewareRef {\n return createIdentityToken(debugName) as MiddlewareRef;\n}\n\n/**\n * A `runsAfter` or `runsBefore` entry, made with `requireRef`, that throws at construction when the\n * target isn't registered. A bare ref is optional and only warns.\n */\nexport interface RequiredMiddlewareRef {\n readonly ref: MiddlewareRef;\n}\n\n/** Wraps `ref` so `runsAfter`/`runsBefore` throws at `VernLLM` construction time if it doesn't resolve, instead of warning and continuing. */\nexport function requireRef(ref: MiddlewareRef): RequiredMiddlewareRef {\n return { ref };\n}\n\n/**\n * Typed per call storage that middleware share values through. VernLLM never reads or writes it.\n */\nexport interface MiddlewareStateBag {\n get<T>(key: MiddlewareStateKey<T>): T | undefined;\n set<T>(key: MiddlewareStateKey<T>, value: T): void;\n}\n\n/**\n * One `[key, value]` pair for a call's `state`. A tuple can't tie each value to its own key's type,\n * so `stateEntry` carries that check. Raw pairs are not type checked.\n */\nexport type MiddlewareStateEntry = readonly [MiddlewareStateKey<unknown>, unknown];\n\n/** Builds a type checked `state` entry: `value` must match the key's type. */\nexport function stateEntry<T>(key: MiddlewareStateKey<T>, value: T): MiddlewareStateEntry {\n return [key, value];\n}\n\n/** A plain, `Map`-backed `MiddlewareStateBag`, optionally seeded with `entries`. Later entries win. */\nexport function createMiddlewareStateBag(\n entries?: readonly MiddlewareStateEntry[],\n): MiddlewareStateBag {\n const store = new Map<MiddlewareStateKey<unknown>, unknown>(entries);\n\n return {\n get<T>(key: MiddlewareStateKey<T>): T | undefined {\n return store.get(key) as T | undefined;\n },\n set<T>(key: MiddlewareStateKey<T>, value: T): void {\n store.set(key, value);\n },\n };\n}\n\n/** Fields every `MiddlewareContext` variant carries, regardless of `stage`. */\nexport interface MiddlewareContextBase {\n requestId: string;\n\n /** Capabilities of the target this stage's identity fields describe. */\n capabilities: MiddlewareCapabilities;\n\n signal?: AbortSignal;\n\n /** Shared, collision-proof state for two middleware to deliberately coordinate through. See `MiddlewareStateBag`. */\n state: MiddlewareStateBag;\n\n /** Simple, string-keyed scratch space, pre-namespaced to this one middleware so two middleware can never collide here even by accident. */\n own: Record<string, unknown>;\n\n /**\n * Every registered middleware's label, in `transform` order, e.g. to skip work another known\n * middleware already does.\n */\n registeredMiddlewareNames: readonly string[];\n\n /**\n * The labels from `registeredMiddlewareNames` whose entry defines a\n * `transform`, in the same order, frozen. Lets a middleware tell\n * whether any entry after it can still change the request.\n */\n transformMiddlewareNames: readonly string[];\n\n /** Reports a `custom` event to `onEvent` and every middleware. Never throws. */\n emit(name: string, data?: JsonValue): void;\n\n /** The call's `context`, frozen. `undefined` when none was given. */\n context: CallContext | undefined;\n\n /** Whether the call asked for a stream. */\n streaming?: boolean;\n\n /** The call's own `targets`, when it passed one. The order a caller chose by hand. */\n callTargets?: readonly string[];\n\n /** When the call's `deadlineMs` runs out, as epoch milliseconds. Absent without a deadline. */\n deadlineAt?: number;\n\n /** Absent for the main chain, 1 and up for chains started with `next.again()`. */\n chain?: number;\n}\n\n/**\n * The `ctx` for `transform` and every attempt scoped event. Built once a target is selected, so\n * every field describes the real target.\n */\nexport interface AttemptContext extends MiddlewareContextBase {\n stage: 'attempt';\n\n /** The target this attempt is actually dispatched to. */\n requestedProvider: string;\n /** The adapter behind this target. `{ name: 'custom' }` when its client doesn't identify one. */\n adapter: AdapterInfo;\n requestedModel: string;\n isFallbackAttempt: boolean;\n\n /**\n * The current attempt number. A `'circuit_state'` event from the check before any attempt reports\n * 1.\n */\n attempt: number;\n}\n\n/**\n * The `ctx` for `wrap` and `onError`. Built before any target is chosen, so it only describes the\n * primary. Read `next()`'s `CallResult.meta` for what happened.\n */\nexport interface PreDispatchContext extends MiddlewareContextBase {\n stage: 'pre-dispatch';\n\n /** The primary target only, not necessarily who ends up answering. */\n primaryProvider: string;\n /** The adapter behind the primary target. `{ name: 'custom' }` when its client doesn't identify one. */\n primaryAdapter: AdapterInfo;\n primaryModel: string;\n\n /** The order so far: what this `wrap` may try, after every outer `wrap` narrowed it. */\n targets: readonly TargetInfo[];\n}\n\n/**\n * What `enabled` and `onEvent` receive, since they run in both stages. Narrow on `ctx.stage` before\n * reading stage specific fields.\n */\nexport type MiddlewareContext = AttemptContext | PreDispatchContext;\n\n/** The `response_format` shape `RequestBuilder` can put on the wire. */\nexport type WireResponseFormat =\n | { type: 'json_object' }\n | {\n type: 'json_schema';\n json_schema: {\n name: string;\n schema: Record<string, unknown>;\n strict?: boolean;\n description?: string;\n };\n };\n\n/** A tool as it appears on the wire, OpenAI's `function`-wrapped shape. */\nexport interface WireTool {\n type: 'function';\n function: {\n name: string;\n description: string;\n parameters: Record<string, unknown>;\n };\n}\n\n/**\n * The wire-shaped request `RequestBuilder.build()` produces for one call\n * attempt, before dispatch. Read only inside `transform`; return a patch\n * of the fields you want to change instead of the whole object.\n */\nexport interface WireCallRequest {\n model: string;\n temperature?: number;\n max_tokens: number;\n response_format?: WireResponseFormat;\n reasoning_effort?: 'minimal' | 'low' | 'medium' | 'high';\n budget_tokens?: number;\n tools?: WireTool[];\n tool_choice?: WireToolChoice;\n messages: WireMessage[];\n}\n\n/**\n * A patch `transform` returns, merged onto the built request. `model` and `response_format` can't\n * be patched, since targets are attributed by the values already resolved. `add*` fields append, so\n * two middleware can add without overwriting each other.\n */\nexport interface WireCallRequestPatch {\n temperature?: number;\n max_tokens?: number;\n reasoning_effort?: 'minimal' | 'low' | 'medium' | 'high';\n budget_tokens?: number;\n tool_choice?: WireToolChoice;\n\n /** Replaces the whole message list. Prefer `addMessages` unless a full replace is genuinely the intent. */\n messages?: WireMessage[];\n /** Appended after whatever earlier middleware already added. Never clobbers a prior addition. */\n addMessages?: WireMessage[];\n\n /** Replaces the whole tool list. Prefer `addTools`, same reasoning as `messages`/`addMessages`. */\n tools?: WireTool[];\n /** Appended after whatever earlier middleware already added. Never clobbers a prior addition. */\n addTools?: WireTool[];\n}\n\n/**\n * The settled outcome of one logical call, from `wrap`'s `next()`. `meta` is `undefined` on a\n * cache hit, and on a streamed `cachedCall` join, which returns before the shared call has answered.\n */\nexport interface CallResult<T = unknown> {\n value: T;\n meta?: CallMeta;\n /**\n * Set only by `cachedCall()` when no call of its own ran: `'hit'` served a stored value,\n * `'join'` shared another caller's in flight call. Unlike `meta` it is known when `next()`\n * returns, for streams too.\n */\n cache?: 'hit' | 'join';\n}\n\n/** Options for `wrap`'s `next()` and `next.again()`. */\nexport interface WrapNextOptions {\n /** Reorders or drops targets by name, never adds one. */\n targets?: readonly string[];\n}\n\n/** `wrap`'s `next`. Calling it runs everything inside this `wrap` once; later calls return the same result. */\nexport interface WrapNext {\n (options?: WrapNextOptions): Promise<CallResult>;\n\n /**\n * Runs everything inside this `wrap` again as a separate chain, at the same time as other chains\n * or after them. Set only for entries with `reruns: true`, and not after 4 per call. Inside\n * `cachedCall()` it's a fresh call for this caller: no cache read or joining, and its answer is\n * cached. Return a chain's result unchanged: when the `wrap` settles, every chain whose result it\n * didn't return is cancelled.\n */\n readonly again?: (options?: WrapNextOptions) => Promise<CallResult>;\n}\n\n/**\n * One entry in `VernLLMOptions.middleware`. Every hook is optional. See the middleware docs for how\n * hooks compose.\n */\nexport interface VernLLMMiddleware {\n /** Used in log lines and the `'middleware'` event. Defaults to this entry's array position when omitted. */\n name?: string;\n\n /**\n * This entry's identity for other entries' `runsAfter` and `runsBefore`. Unrelated to `name`,\n * which is only a label.\n */\n ref?: MiddlewareRef;\n\n /** Sort key for composition order, ascending, ties broken by array order. See the middleware docs for what \"lower runs first\" means for `wrap`. */\n priority?: number;\n\n /**\n * Middleware this entry runs after. An unresolved bare ref is dropped; wrap it with `requireRef`\n * to throw at construction instead. A cycle always throws.\n */\n runsAfter?: (MiddlewareRef | RequiredMiddlewareRef)[];\n\n /**\n * Other middleware this entry must run before. See `runsAfter`; a\n * bare reference is dropped if unresolved, a `requireRef`-wrapped one\n * throws.\n */\n runsBefore?: (MiddlewareRef | RequiredMiddlewareRef)[];\n\n /**\n * Pins this entry in `wrap` nesting only. `'outermost'` sees the net result of every retry and\n * fallback; `'innermost'` sits next to dispatch. A number works like `priority` for `wrap` only.\n */\n position?: 'outermost' | 'innermost' | number;\n\n /**\n * Boolean for a static on/off switch, or a predicate evaluated per\n * call. A throwing, rejecting, or timed-out predicate is logged and\n * treated as `false` for that call.\n */\n enabled?: boolean | ((ctx: MiddlewareContext) => boolean | Promise<boolean>);\n\n /** Per-middleware override of the instance-level `middlewareTimeoutMs`, applied to this entry's `transform` and function `enabled`. `<= 0` means unbounded (no timer at all). */\n timeoutMs?: number;\n\n /** Transforms the outgoing wire request for one attempt. Runs once per attempt, including retries. `ctx` is always accurate to the real target for this attempt. */\n transform?: (\n request: Readonly<WireCallRequest>,\n ctx: AttemptContext,\n ) => WireCallRequestPatch | Promise<WireCallRequestPatch>;\n\n /**\n * Wraps one whole logical call once, however many retries or targets ran. `ctx` describes the\n * primary and the order so far (`ctx.targets`); read `next()`'s `CallResult.meta` for what\n * happened. `next({ targets })` reorders or drops targets by name, never adds one.\n */\n wrap?: (\n request: Readonly<WireCallRequest>,\n next: WrapNext,\n ctx: PreDispatchContext,\n ) => Promise<CallResult>;\n\n /**\n * Gives this entry's `wrap` `next.again()`, and cancels every chain it starts but doesn't return,\n * when it settles. Off by default; entries without it run exactly as before.\n */\n reruns?: boolean;\n\n /**\n * Wraps one attempt's provider request, after the limiter and every `transform`. `request` is\n * exactly what the adapter gets. Runs per attempt, nested in `wrap` order.\n *\n * `next()` resolves when the response arrives, or at a stream's first content chunk; pings don't\n * count. It rejects with the attempt's `LLMError`. A hook can observe but not change the outcome:\n * returning or throwing without calling `next()` fails the attempt with code `middleware_threw`,\n * and a throw after it is only logged.\n */\n dispatch?: (\n request: Readonly<WireCallRequest>,\n next: () => Promise<void>,\n ctx: AttemptContext,\n ) => Promise<void>;\n\n /** Observes the same events reported on `VernLLMOptions.onEvent`, filtered by this middleware's own `enabled`. Called from both stages; narrow on `ctx.stage` before reading stage-specific fields. */\n onEvent?: (event: VernLLMEvent, ctx: MiddlewareContext) => void;\n}\n","import type { LLMError } from './errors.js';\nimport type { PreDispatchContext, VernLLMMiddleware } from './middleware.js';\n\n/**\n * `VernLLMMiddleware` plus `onError`, for middleware that only cares about failures. `wrap` can't\n * be set alongside it, since `onError` builds its own.\n */\nexport type CreateMiddlewareOptions = Omit<VernLLMMiddleware, 'wrap'> & {\n wrap?: undefined;\n /**\n * Called with the call's terminal error. Not called on success or when another `wrap` swallowed\n * the failure. Only observes: the error is always rethrown and a throwing `onError` is discarded.\n * `ctx` is `wrap`'s pre-dispatch context.\n */\n onError?: (error: LLMError, ctx: PreDispatchContext) => void | Promise<void>;\n};\n\n/**\n * Builds a middleware entry. With `onError`, adds a `wrap` that reports rejections and always\n * rethrows, so the call's outcome never changes.\n */\nexport function createMiddleware(options: CreateMiddlewareOptions): VernLLMMiddleware {\n const { onError, ...rest } = options;\n\n if (!onError) return rest;\n\n return {\n ...rest,\n wrap: async (_request, next, ctx) => {\n try {\n return await next();\n } catch (error) {\n try {\n await onError(error as LLMError, ctx);\n } catch {\n // onError is fire-and-forget, matching onUsage/onEvent: a\n // throwing observer never masks (or replaces) the real error\n // below.\n }\n throw error;\n }\n },\n };\n}\n","import {\n LLMError,\n type StreamChunk,\n type TokenUsage,\n type UsageHooks,\n} from '../../../../types/index.js';\n\n/** Usage shape shared by a non-streaming response and a stream's `usage` chunk. Both wire types agree field for field. */\nexport interface WireUsage {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n completion_tokens_details?: { reasoning_tokens?: number };\n /** Cache split of `prompt_tokens`. Follows OpenAI and OpenRouter naming. */\n prompt_tokens_details?: {\n cached_tokens?: number;\n cache_write_tokens?: number;\n /** Writes by TTL label, e.g. `{ '5m': 1200, '1h': 800 }`. */\n cache_write_tokens_by_ttl?: Record<string, number>;\n };\n /** What the provider billed for the call, in USD. OpenRouter reports it as `usage.cost`. */\n cost?: number;\n}\n\n/** Call-level fields stamped onto every `TokenUsage`, not carried by the wire usage itself. */\nexport interface TokenUsageMeta {\n requestId: string;\n model: string;\n providerName: string;\n isFallback: boolean;\n}\n\n/** A reported cost is only trusted as a finite number of at least zero. */\nfunction isBilledCost(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0;\n}\n\n/**\n * Maps a provider's wire usage block to `TokenUsage`. Shared by\n * `usageReporter.extract` (non-streaming) and `buildStreamResult` (the\n * `usage` stream chunk), since both wire shapes are identical.\n */\nexport function toTokenUsage(wireUsage: WireUsage, meta: TokenUsageMeta): TokenUsage {\n const reasoningTokens = wireUsage.completion_tokens_details?.reasoning_tokens;\n const details = wireUsage.prompt_tokens_details;\n\n return {\n promptTokens: wireUsage.prompt_tokens ?? 0,\n completionTokens: wireUsage.completion_tokens ?? 0,\n totalTokens: wireUsage.total_tokens ?? 0,\n ...(reasoningTokens !== undefined ? { reasoningTokens } : {}),\n ...(details?.cached_tokens !== undefined ? { cacheReadTokens: details.cached_tokens } : {}),\n ...(details?.cache_write_tokens !== undefined\n ? { cacheWriteTokens: details.cache_write_tokens }\n : {}),\n ...(details?.cache_write_tokens_by_ttl\n ? { cacheWriteTokensByTtl: { ...details.cache_write_tokens_by_ttl } }\n : {}),\n ...(isBilledCost(wireUsage.cost) ? { costUsd: wireUsage.cost } : {}),\n requestId: meta.requestId,\n model: meta.model,\n provider: meta.providerName,\n usedFallback: meta.isFallback,\n };\n}\n\n/**\n * Calls `reserveUsage` if set, mapping a failure to `quota_exceeded`, or `aborted` if the signal\n * fired. Returns whether a reservation was made, so callers know to refund.\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 * A refund function that logs a failing refund hook instead of throwing, so it never masks the\n * original error.\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` inside a usage reservation, refunding on failure or abort when a reservation was\n * made.\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`. Reserves before opening and refunds at once if\n * opening fails. Once open it returns straight away and defers the refund to `finalResult`, since\n * the outcome is only known then, well after this returns.\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","/**\n * Wraps `chunks` so that stopping before the end calls `onExit` once the\n * last active reader has left: a `break` out of `for await`, an exception\n * thrown in the loop body, or a direct `return()`. A reader is active from\n * its first pull until it reaches the end, its pull rejects, or it\n * returns. An early exit while another reader is still active doesn't\n * fire, since that reader still needs the stream. Reaching the end, or a\n * pull rejecting because the stream itself failed, never fires. The inner\n * iterator is closed either way.\n */\nexport function onEarlyExit<T>(chunks: AsyncIterable<T>, onExit: () => void): AsyncIterable<T> {\n let activeReaders = 0;\n\n return {\n [Symbol.asyncIterator]() {\n const iterator = chunks[Symbol.asyncIterator]();\n let active = false;\n let ended = false;\n\n // Runs once per reader, whichever way it ends.\n const end = (): void => {\n ended = true;\n if (active) {\n active = false;\n activeReaders--;\n }\n };\n\n return {\n async next(): Promise<IteratorResult<T>> {\n if (!active && !ended) {\n active = true;\n activeReaders++;\n }\n\n try {\n const result = await iterator.next();\n if (result.done) end();\n return result;\n } catch (error) {\n end();\n throw error;\n }\n },\n async return(): Promise<IteratorResult<T>> {\n if (!ended) {\n end();\n if (activeReaders === 0) onExit();\n }\n\n await iterator.return?.();\n return { done: true, value: undefined };\n },\n };\n },\n };\n}\n\n/**\n * Aborts `controller` when the last active reader of `chunks` stops early.\n * A no-op without a controller (`cachedCall()`'s inner call).\n */\nexport function cancelOnBreak<T, R>(\n stream: { chunks: AsyncIterable<T>; finalResult: Promise<R> },\n controller: AbortController | undefined,\n): { chunks: AsyncIterable<T>; finalResult: Promise<R> } {\n if (!controller) return stream;\n\n // Once settled there is nothing to cancel, and aborting would only flip\n // the signal middleware still holds.\n let settled = false;\n const markSettled = () => {\n settled = true;\n };\n void stream.finalResult.then(markSettled, markSettled);\n\n return {\n chunks: onEarlyExit(stream.chunks, () => {\n if (!settled) controller.abort();\n }),\n finalResult: stream.finalResult,\n };\n}\n","/** A promise with its settle functions exposed, for results settled from elsewhere. */\nexport interface Deferred<T> {\n promise: Promise<T>;\n resolve: (value: T) => void;\n reject: (error: unknown) => void;\n}\n\nexport function createDeferred<T>(): Deferred<T> {\n let resolve!: (value: T) => void;\n let reject!: (error: unknown) => void;\n const promise = new Promise<T>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n\n return { promise, resolve, reject };\n}\n","import type { Logger } from '../../logger.js';\n\n/** Logs a user hook that threw, as `[VernLLM] <hookName> failed` with message and stack. */\nexport function logHookError(logger: Logger, hookName: string, error: unknown): void {\n logError(logger, `[VernLLM] ${hookName} failed`, error);\n}\n\n/** An error's message, or `'unknown'` for a non-Error throw. */\nexport function errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : 'unknown';\n}\n\n/** Logs `message` at error level with the error's message and stack kept. */\nexport function logError(logger: Logger, message: string, error: unknown): void {\n logger.error(message, {\n message: errorMessage(error),\n stack: error instanceof Error ? error.stack : undefined,\n });\n}\n\n/**\n * Calls a synchronous, user-supplied hook and swallows/logs anything it\n * throws via `logHookError`, so a broken hook can never break the call\n * that triggered it.\n */\nexport function callHookSafely(logger: Logger, hookName: string, fn: () => void): void {\n try {\n fn();\n } catch (error) {\n logHookError(logger, hookName, error);\n }\n}\n\n/**\n * Wraps a user supplied `Logger` so a throwing one can never break the call it describes. Wrapped\n * once, so call sites need no guard.\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\n/** Discards every call. Used for `logger: 'silent'`. */\nexport class NoopLogger implements Logger {\n debug(_message: string): void {}\n warn(_message: string): void {}\n error(_message: string, _meta?: Record<string, unknown>): void {}\n}\n","/** A keyed registry of in-flight promises, returned by `createInFlightRegistry`. */\nexport interface InFlightRegistry<T> {\n /** The promise currently tracked under `key`, if any. */\n get(key: string): Promise<T> | undefined;\n /**\n * Registers `promise` under `key` synchronously and removes it once it settles. Returns `promise`\n * unchanged.\n */\n track(key: string, promise: Promise<T>): Promise<T>;\n}\n\n/** At most one in-flight promise per key, removed once it settles. */\nexport function createInFlightRegistry<T>(): InFlightRegistry<T> {\n const inFlight = new Map<string, Promise<T>>();\n\n function get(key: string): Promise<T> | undefined {\n return inFlight.get(key);\n }\n\n function track(key: string, promise: Promise<T>): Promise<T> {\n inFlight.set(key, promise);\n\n // The promise returned below is untouched, so its own rejection\n // still propagates normally to anyone who does await it. This\n // separate handle only exists so cleanup doesn't itself surface an\n // unhandled rejection for a promise nobody else observes.\n void promise\n .catch(() => {})\n .finally(() => {\n // Only remove this entry if it's still the one registered under\n // `key`: a newer `track()` call for the same key may have\n // already replaced it, and that replacement must survive this\n // (older) promise settling later.\n if (inFlight.get(key) === promise) {\n inFlight.delete(key);\n }\n });\n\n return promise;\n }\n\n return { get, track };\n}\n","import type { StreamChunk } from '../../../types/stream.js';\nimport type { CallWithToolsResult } from '../../../types/tools.js';\n\n/**\n * A cached value as replay text: strings as is, anything else stringified. Not the original\n * streamed text, but enough for loops that don't care whether they got a hit.\n */\nfunction toReplayText(value: unknown): string {\n return typeof value === 'string' ? value : (JSON.stringify(value) ?? '');\n}\n\n/**\n * A one-shot `chunks` replay of a cached value. No `usage` chunk, since a hit spends nothing.\n * `hasTools` must reflect the original call, since the value's shape alone can't tell a\n * `CallWithToolsResult` from a `T`.\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 * Replay for a joiner: waits for the in-flight value, then replays it. A rejection makes iterating\n * `chunks` throw, as a live stream would.\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 { LLMError } from '../../../types/errors.js';\n\nimport type { StreamChunk } from '../../../types/stream.js';\n\n/**\n * A signal owned by every caller coalesced onto one operation. It fires only once the last one has\n * left, so one caller's abort never cancels work others still wait on.\n */\nexport interface SharedAbort {\n /** Passed to the shared operation. Fires only when no participant remains. */\n readonly signal: AbortSignal;\n /** Number of callers still waiting on the shared operation. */\n readonly participants: number;\n /** Registers a participant. Returns an idempotent release function. */\n join(): () => void;\n /** Marks the shared operation settled, so a later release never aborts it. */\n settle(): void;\n}\n\nexport function createSharedAbort(): SharedAbort {\n const controller = new AbortController();\n let participants = 0;\n let settled = false;\n\n return {\n signal: controller.signal,\n get participants() {\n return participants;\n },\n join() {\n participants++;\n let released = false;\n\n return () => {\n if (released) return;\n released = true;\n participants--;\n\n if (participants === 0 && !settled && !controller.signal.aborted) {\n controller.abort(new LLMError('LLM request aborted', 'aborted'));\n }\n };\n },\n settle() {\n settled = true;\n },\n };\n}\n\nfunction abortedError(): LLMError {\n return new LLMError('LLM request aborted', 'aborted');\n}\n\n/**\n * Settles with `promise`, or rejects with an `aborted` LLMError as soon as\n * `signal` fires, whichever comes first. `promise` itself keeps running;\n * only this caller stops waiting on it.\n */\nexport function raceAbort<T>(promise: Promise<T>, signal: AbortSignal | undefined): Promise<T> {\n if (!signal) return promise;\n\n if (signal.aborted) {\n // Observed so an unawaited rejection of the shared promise stays quiet.\n promise.catch(() => {});\n return Promise.reject(abortedError());\n }\n\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => reject(abortedError());\n signal.addEventListener('abort', onAbort, { once: true });\n\n promise.then(\n (value) => {\n signal.removeEventListener('abort', onAbort);\n resolve(value);\n },\n (error: unknown) => {\n signal.removeEventListener('abort', onAbort);\n reject(error);\n },\n );\n });\n}\n\n/**\n * Relays `chunks` until `signal` fires, then throws `aborted` for this caller only. Leaving early\n * detaches this reader and leaves the shared stream running for the others.\n */\nexport function abortableChunks(\n chunks: AsyncIterable<StreamChunk>,\n signal: AbortSignal | undefined,\n): AsyncIterable<StreamChunk> {\n return {\n async *[Symbol.asyncIterator]() {\n const iterator = chunks[Symbol.asyncIterator]();\n\n try {\n while (true) {\n const next = await raceAbort(iterator.next(), signal);\n if (next.done) return;\n yield next.value;\n }\n } finally {\n // An async generator's own early exit doesn't close the iterator it\n // reads from, so close it here. On a stream channel that detaches\n // this reader instead of cancelling the stream.\n void Promise.resolve(iterator.return?.()).catch(() => {});\n }\n },\n };\n}\n","import {\n withReservedUsage,\n withReservedUsageForStream,\n} from '../execution/utils/response/usage.utils.js';\nimport { onEarlyExit } from '../execution/utils/stream/earlyExit.utils.js';\nimport { createDeferred } from '../utils/deferred.utils.js';\nimport { errorMessage, logError } from '../utils/logger.utils.js';\nimport { createInFlightRegistry } from './utils/inFlightRegistry.utils.js';\nimport { buildReplayChunks, buildReplayChunksFromPromise } from './utils/replay.utils.js';\nimport {\n abortableChunks,\n createSharedAbort,\n raceAbort,\n type SharedAbort,\n} from './utils/sharedAbort.utils.js';\n\nimport type { Logger } from '../../logger.js';\nimport type { LLMError } from '../../types/errors.js';\nimport type { CacheAdapter, StreamChunk, UsageHooks } from '../../types/index.js';\nimport type { InternalCacheParams, InternalCacheStreamParams } from './utils/cache.utils.js';\n\n/**\n * Cache key resolution, reads, writes and coalescing of concurrent misses. Knows nothing about\n * providers: the work is an opaque callback from `cachedCall`.\n */\nexport class CacheOrchestrator {\n private readonly inFlight = createInFlightRegistry<unknown>();\n /** The shared abort owned by each in-flight promise's participants. */\n private readonly sharedAborts = new WeakMap<Promise<unknown>, SharedAbort>();\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(`[VernLLM] cache delete failed: ${errorMessage(error)}`);\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(`[VernLLM] cache read failed: ${errorMessage(error)}`);\n\n return { hit: false };\n }\n }\n\n /**\n * Resolves `params.cacheKey` and reads the cache under that key in one\n * step. Shared by `runCached` and `runCachedStream`, which otherwise\n * duplicated this exact prefix.\n */\n private async resolveKeyAndReadCache<P extends { cacheKey: string }>(\n params: P,\n ): Promise<{ resolvedParams: P; cached: { hit: boolean; value?: unknown } }> {\n const resolvedKey = await this.resolveCacheKey(params.cacheKey);\n const resolvedParams: P =\n resolvedKey === params.cacheKey ? params : { ...params, cacheKey: resolvedKey };\n\n return { resolvedParams, cached: await this.getCached(resolvedKey) };\n }\n\n /** The shared in-flight promise for `key`, if any, so callers can wait for it to settle. */\n inFlightFor(key: string): Promise<unknown> | undefined {\n return this.inFlight.get(key);\n }\n\n /**\n * Returns the in-flight entry for `key` a new caller can still join, or\n * `undefined`. An entry whose shared signal already fired is doomed, so\n * it's skipped and the caller starts fresh work instead.\n */\n private joinable<T>(key: string): { promise: Promise<T>; shared: SharedAbort } | undefined {\n const promise = this.inFlight.get(key) as Promise<T> | undefined;\n if (!promise) return undefined;\n\n const shared = this.sharedAborts.get(promise);\n if (!shared || shared.signal.aborted) return undefined;\n\n return { promise, shared };\n }\n\n /**\n * Joins another caller's in-flight work, reserving usage as a coalesced spend. This caller's\n * signal only ends its own wait.\n */\n private joinInFlight<T, P extends UsageHooks & { signal?: AbortSignal }>(\n params: P,\n existing: Promise<T>,\n shared: SharedAbort,\n ): Promise<T> {\n const release = shared.join();\n\n const result = withReservedUsage(\n params,\n true,\n () => raceAbort(existing, params.signal),\n params.signal,\n (logMessage, error) => logError(this.logger, logMessage, error),\n );\n\n void result.then(release, release);\n\n return result;\n }\n\n /**\n * The caching core behind `cachedCall()`. Concurrent misses for one key share a single in-flight\n * call, aborted only once every waiting caller has left.\n *\n * @param params Cache settings plus `fn`, the work to run on a miss. See `InternalCacheParams`.\n * @returns The cached value on a hit, or `fn()`'s result on a miss.\n */\n async runCached<T>(params: InternalCacheParams<T>): Promise<T> {\n const { resolvedParams, cached } = await this.resolveKeyAndReadCache(params);\n\n if (cached.hit) {\n params.onOutcome?.('hit');\n return cached.value as T;\n }\n\n const existing = this.joinable<T>(resolvedParams.cacheKey);\n\n if (existing) {\n params.onOutcome?.('join');\n return this.joinInFlight(resolvedParams, existing.promise, existing.shared);\n }\n\n return this.registerTrigger(resolvedParams);\n }\n\n /**\n * Runs `fn` for this caller alone: no cache read, no joining, nothing others can join. Reserves\n * as a full spend and caches the answer on success, like a miss. Used for a rerun.\n */\n async runFresh<T>(params: InternalCacheParams<T> & { signal: AbortSignal }): Promise<T> {\n const cacheKey = await this.resolveCacheKey(params.cacheKey);\n\n return withReservedUsage(\n params,\n false,\n () => this.runAndCache({ ...params, cacheKey }, params.signal),\n params.signal,\n (logMessage, error) => logError(this.logger, logMessage, error),\n );\n }\n\n /**\n * Creates and registers the shared work synchronously, so a concurrent caller always sees it in\n * time to join. `start` runs it at most once.\n */\n private createShared<V>(key: string, run: (signal: AbortSignal) => Promise<V>) {\n const shared = createSharedAbort();\n const { promise, resolve: resolveShared, reject: rejectShared } = createDeferred<V>();\n\n void promise.then(shared.settle, shared.settle);\n this.sharedAborts.set(promise, shared);\n this.inFlight.track(key, promise);\n\n let started = false;\n\n // Called exactly once: by the trigger, or by `onTriggerFailed` when\n // the trigger failed before calling it.\n const start = (): Promise<V> => {\n started = true;\n const running = run(shared.signal);\n running.then(resolveShared, rejectShared);\n return running;\n };\n\n /**\n * Called when the trigger failed. If it never started the work, the\n * work starts anyway for any participant still waiting on an abort,\n * otherwise the shared promise fails with the trigger's error.\n */\n const onTriggerFailed = (error: unknown) => {\n if (started) return;\n\n // Before `start`, the trigger can only fail in usage reservation or\n // an abort check, and both throw an LLMError.\n if ((error as LLMError).type === 'aborted' && shared.participants > 0) {\n // `start` already routes a rejection into the shared promise.\n void start();\n return;\n }\n\n rejectShared(error);\n };\n\n return { shared, promise, start, onTriggerFailed };\n }\n\n /** Starts the shared fn() call for a cache miss and tracks it in the in-flight registry until it settles. */\n private registerTrigger<T>(params: InternalCacheParams<T>): Promise<T> {\n const { shared, promise, start, onTriggerFailed } = this.createShared<T>(\n params.cacheKey,\n (signal) => this.runAndCache(params, signal),\n );\n const release = shared.join();\n\n const resultPromise = withReservedUsage(\n params,\n false,\n () => raceAbort(start(), params.signal),\n params.signal,\n (logMessage, error) => logError(this.logger, logMessage, error),\n );\n\n void resultPromise.then(release, (error: unknown) => {\n release();\n onTriggerFailed(error);\n });\n\n // Observed so a shared rejection nobody else awaits stays quiet.\n promise.catch(() => {});\n\n return resultPromise;\n }\n\n /** Runs `fn` and writes its result to the cache. */\n private async runAndCache<T>(params: InternalCacheParams<T>, signal: AbortSignal): Promise<T> {\n const result = await params.fn(signal);\n await this.writeCache(params.cacheKey, result, params.ttl);\n return result;\n }\n\n /** Writes to the cache, logging instead of throwing on adapter failure. */\n private async writeCache(key: string, value: unknown, ttl: number): Promise<void> {\n // Never handed to the adapter: a custom one could turn a NaN expiry into\n // an entry that is never evicted. The warning is the only sign the\n // caller gets that nothing is being cached.\n if (typeof ttl !== 'number' || Number.isNaN(ttl)) {\n this.logger.warn(\n `[VernLLM] cachedCall ttl must be a number of seconds, got ${String(ttl)}. Nothing is cached.`,\n );\n return;\n }\n\n try {\n await this.cache.set(key, value, ttl);\n } catch (error) {\n this.logger.warn(`[VernLLM] cache write failed: ${errorMessage(error)}`);\n }\n }\n\n /**\n * Streaming counterpart to `runCached`. A hit returns the cached value with a one-shot replay of\n * `chunks`, and no usage hooks fire. A miss with nothing in flight opens the stream and relays it\n * live. A miss that finds work in flight replays once it resolves; streaming and plain calls for\n * a key coalesce with each other.\n */\n async runCachedStream<T>(\n params: InternalCacheStreamParams<T>,\n hasTools: boolean,\n ): Promise<{ chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> }> {\n const { resolvedParams, cached } = await this.resolveKeyAndReadCache(params);\n\n if (cached.hit) {\n params.onOutcome?.('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.joinable<T>(resolvedParams.cacheKey);\n\n if (existing) {\n params.onOutcome?.('join');\n const finalResult = this.joinInFlight(resolvedParams, existing.promise, existing.shared);\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 * Streaming counterpart to `runFresh`: caches when `finalResult` resolves, as a miss does.\n * Leaving `chunks` early cancels this stream, like leaving a plain call's.\n */\n async runFreshStream<T>(\n params: InternalCacheStreamParams<T> & { signal: AbortSignal },\n ): Promise<{ chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> }> {\n const cacheKey = await this.resolveCacheKey(params.cacheKey);\n const left = new AbortController();\n const signal = AbortSignal.any([params.signal, left.signal]);\n\n return withReservedUsageForStream(\n params,\n async () => {\n const opened = await params.openStream(signal);\n const finalResult = opened.finalResult.then(async (value) => {\n // Failed calls aren't cached, matching `runAndCache`.\n await this.writeCache(cacheKey, value, params.ttl);\n return value;\n });\n\n finalResult.catch(() => {});\n\n return { chunks: onEarlyExit(opened.chunks, () => left.abort()), finalResult };\n },\n params.signal,\n (logMessage, error) => logError(this.logger, logMessage, error),\n );\n }\n\n /**\n * Opens the shared stream for a miss and tracks it until it settles, caching on success only. The\n * stream runs under the shared signal, so joiners keep it after the trigger leaves; the trigger's\n * own `chunks` and `finalResult` stop at its signal.\n */\n private registerStreamTrigger<T>(\n params: InternalCacheStreamParams<T>,\n ): Promise<{ chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> }> {\n type Opened = { chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> };\n\n let openedStream: Promise<Opened> | undefined;\n\n const openShared = (signal: AbortSignal): Promise<Opened> => {\n openedStream ??= params.openStream(signal).then((opened) => ({\n chunks: opened.chunks,\n finalResult: opened.finalResult.then(async (value) => {\n // Failed calls aren't cached, matching `runAndCache`.\n await this.writeCache(params.cacheKey, value, params.ttl);\n return value;\n }),\n }));\n\n return openedStream;\n };\n\n const { shared, promise, start, onTriggerFailed } = this.createShared<T>(\n params.cacheKey,\n async (signal) => (await openShared(signal)).finalResult,\n );\n const release = shared.join();\n\n promise.catch(() => {});\n\n // Stopping `chunks` early leaves the shared stream the same way an\n // abort does: this trigger's `finalResult` rejects as aborted, and the\n // stream is cancelled only once no joiner is left waiting on it.\n const left = new AbortController();\n const triggerSignal = params.signal\n ? AbortSignal.any([params.signal, left.signal])\n : left.signal;\n\n const streamPromise = withReservedUsageForStream(\n params,\n async () => {\n void start().catch(() => {});\n const opened = await raceAbort(openShared(shared.signal), params.signal);\n const finalResult = raceAbort(opened.finalResult, triggerSignal);\n finalResult.catch(() => {});\n\n return {\n chunks: onEarlyExit(abortableChunks(opened.chunks, params.signal), () => left.abort()),\n finalResult,\n };\n },\n params.signal,\n (logMessage, error) => logError(this.logger, logMessage, error),\n );\n\n const onFailed = (error: unknown) => {\n release();\n onTriggerFailed(error);\n };\n\n streamPromise.then((opened) => {\n opened.finalResult.then(release, onFailed);\n }, onFailed);\n\n return streamPromise;\n }\n}\n","import type { CallMeta } from '../../../types/index.js';\n\nexport type MetaHolder = { current?: CallMeta };\n\n/**\n * Returns the `CallMeta` holder shared by every `cachedCall()` in flight for\n * `key`, so a joiner reports the trigger's metadata. A hit never creates one,\n * so it still reports none.\n *\n * `release` is a no-op for joiners. For the creator it deletes the holder once\n * the key's in-flight work settles, looked up at release time.\n */\nexport function claimMetaHolder(\n holders: Map<string, MetaHolder>,\n key: string,\n inFlightFor: (key: string) => Promise<unknown> | undefined,\n): { holder: MetaHolder; release: () => void } {\n const existing = holders.get(key);\n if (existing) return { holder: existing, release: () => {} };\n\n const holder: MetaHolder = {};\n holders.set(key, holder);\n\n const release = () => {\n const deleteHolder = () => holders.delete(key);\n const shared = inFlightFor(key);\n\n if (shared) void shared.then(deleteHolder, deleteHolder);\n else deleteHolder();\n };\n\n return { holder, release };\n}\n","/**\n * A fixed number of coarse time buckets rather than one entry per call, keeping memory bounded.\n * Rotated lazily on access, with no timer.\n */\nconst BUCKET_COUNT = 10;\n\n/**\n * A failure ratio over a trailing window with bounded memory. Shared by `RollingTripping` and\n * `RetryBudget`.\n */\nexport class RollingRatio {\n private buckets: { total: number; failures: number }[];\n private bucketStartMs = Date.now();\n private readonly bucketWidthMs: number;\n\n constructor(windowMs: number) {\n if (!Number.isFinite(windowMs) || windowMs <= 0) {\n throw new RangeError(`RollingRatio: windowMs must be a finite number > 0, got ${windowMs}`);\n }\n\n this.bucketWidthMs = windowMs / BUCKET_COUNT;\n this.buckets = Array.from({ length: BUCKET_COUNT }, () => ({ total: 0, failures: 0 }));\n }\n\n /** Drops buckets that have aged out of the window, replacing them with fresh, empty ones. */\n private rotate(): void {\n const elapsed = Date.now() - this.bucketStartMs;\n const drop = Math.floor(elapsed / this.bucketWidthMs);\n const shiftCount = Math.min(BUCKET_COUNT, drop);\n\n for (let i = 0; i < shiftCount; i++) {\n this.buckets.shift();\n this.buckets.push({ total: 0, failures: 0 });\n }\n\n if (drop > 0) this.bucketStartMs += drop * this.bucketWidthMs;\n }\n\n /** Records one call outcome into the current bucket. */\n record(failed: boolean): void {\n this.rotate();\n const head = this.buckets[BUCKET_COUNT - 1]!;\n head.total += 1;\n if (failed) head.failures += 1;\n }\n\n /** Fraction of recorded calls that failed within the window. 0 if nothing has been recorded yet. */\n getRatio(): number {\n this.rotate();\n const t = this.buckets.reduce((a, b) => a + b.total, 0);\n const f = this.buckets.reduce((a, b) => a + b.failures, 0);\n return t === 0 ? 0 : f / t;\n }\n\n /** Total calls recorded within the window. */\n getCount(): number {\n this.rotate();\n return this.buckets.reduce((a, b) => a + b.total, 0);\n }\n\n /** Clears every bucket and restarts the window from now. */\n reset(): void {\n this.buckets = Array.from({ length: BUCKET_COUNT }, () => ({ total: 0, failures: 0 }));\n this.bucketStartMs = Date.now();\n }\n}\n","/**\n * Throws `RangeError` unless `value` is a non-negative integer: the calls needed in the window\n * before a ratio is judged. `0` applies the check at once.\n */\nexport function validateMinCalls(value: number, label = 'minCalls'): void {\n if (!Number.isInteger(value) || value < 0) {\n throw new RangeError(`${label} must be a non-negative integer, got ${value}`);\n }\n}\n\n/**\n * Throws `RangeError` unless `value` is a finite fraction in `[0, 1]`. Anything else would always\n * or never trip.\n */\nexport function validateRatio(value: number, label: string): void {\n if (!Number.isFinite(value) || value < 0 || value > 1) {\n throw new RangeError(`${label} must be a finite number between 0 and 1, got ${value}`);\n }\n}\n","import { RollingRatio } from './internal/rollingRatio.js';\nimport { validateMinCalls, validateRatio } from './internal/utils/validate.utils.js';\nimport { LLMError } from './types/errors.js';\n\nimport type { Logger } from './logger.js';\n\n/**\n * `windowMs` and `minCalls` work as in `RollingTripping`: `minCalls` keeps a cold start from\n * tripping. `retryRatio` is the largest share of calls in the window that may be retries. Invalid\n * values throw `RangeError` at construction.\n */\nexport interface RetryBudgetOptions {\n windowMs: number;\n minCalls: number;\n retryRatio: number;\n}\n\n/** Traffic and retry ratio in a budget's trailing window. */\nexport interface RetryBudgetSnapshot {\n attempts: number;\n retryRatio: number;\n}\n\n/**\n * What `retryBudget` accepts in place of options, e.g. a budget shared across processes. Both\n * required methods run on the call path and are synchronous: keep remote state in a local copy.\n */\nexport interface RetryBudgetAdapter {\n /**\n * Throws an `LLMError` when no retry may run, normally `type: 'rate_limited'` with\n * `code: 'retry_budget_exhausted'`. Anything else it throws is logged and the retry goes ahead.\n */\n assertAvailable(): void;\n /** `isRetry` is false for a call's first attempt. Fire and forget: a returned rejection is logged. */\n recordAttempt(isRetry: boolean): void;\n /** Read by `VernLLM.getRetryBudgetState()`. */\n getSnapshot?(): RetryBudgetSnapshot;\n /** Live counterpart of `getSnapshot`, read by `VernLLM.readRetryBudgetState()`. */\n readState?(): Promise<RetryBudgetSnapshot>;\n /** Receives the instance's `Logger` once, when `VernLLM` wires this adapter in. */\n setLogger?(logger: Logger): void;\n}\n\n/**\n * Caps the share of a target's recent traffic that may be retries. The breaker asks whether the\n * provider is healthy; this asks whether retrying is still worth the capacity it costs.\n */\nexport class RetryBudget implements RetryBudgetAdapter {\n private readonly ratio: RollingRatio;\n\n constructor(private readonly options: RetryBudgetOptions) {\n this.ratio = new RollingRatio(options.windowMs);\n validateMinCalls(options.minCalls);\n validateRatio(options.retryRatio, 'retryRatio');\n }\n\n /**\n * Throws `LLMError('retry_budget_exhausted')` once at least `minCalls`\n * calls have landed in the trailing `windowMs` and the retry ratio\n * among them has reached `retryRatio`. A no-op otherwise.\n */\n assertAvailable(): void {\n if (\n this.ratio.getCount() >= this.options.minCalls &&\n this.ratio.getRatio() >= this.options.retryRatio\n ) {\n throw new LLMError('Retry budget exhausted', 'rate_limited', {\n code: 'retry_budget_exhausted',\n });\n }\n }\n\n /** Records one attempt. `isRetry` is false for a call's first attempt, true for every attempt after it. */\n recordAttempt(isRetry: boolean): void {\n this.ratio.record(isRetry);\n }\n\n /** Current traffic and retry ratio in the trailing window. */\n getSnapshot(): RetryBudgetSnapshot {\n return { attempts: this.ratio.getCount(), retryRatio: this.ratio.getRatio() };\n }\n}\n","import type { AdapterInfo, LLMClient } from '../../types/client.js';\n\n/** What middleware see for a client that doesn't identify its adapter. */\nexport const CUSTOM_ADAPTER: AdapterInfo = Object.freeze({ name: 'custom' });\n\n/**\n * `client.adapter`, copied and frozen so one middleware can't change what\n * the next one reads, or `CUSTOM_ADAPTER` when the client sets none. A\n * blank `name` counts as none, since it can't tell adapters apart.\n */\nexport function resolveAdapterInfo(client: LLMClient): AdapterInfo {\n const info = client.adapter;\n\n if (!info || typeof info.name !== 'string' || info.name.trim() === '') return CUSTOM_ADAPTER;\n\n return Object.freeze(\n typeof info.provider === 'string' && info.provider.trim() !== ''\n ? { name: info.name, provider: info.provider }\n : { name: info.name },\n );\n}\n","import { LLMError } from '../../../types/errors.js';\nimport { callHookSafely } from '../logger.utils.js';\n\nimport type { Logger } from '../../../logger.js';\nimport type { VernLLMEvent } from '../../../types/events.js';\nimport type { TokenUsage } from '../../../types/index.js';\nimport type { CallExecutor } from '../../execution/callExecutor.js';\n\n/** `onUsage`/`onUsageFailure` from `VernLLMOptions`, plumbed alongside `onEvent` so `makeEventReporter` can drive both off the one dispatch point. */\nexport interface UsageReporterHooks {\n onUsage?: (usage: TokenUsage) => void;\n onUsageFailure?: (usage: TokenUsage, error: LLMError) => void;\n}\n\n/**\n * An event reporter that logs, rather than throws, a failing `onEvent`. Kept free of the executor\n * since breakers report before one exists. Also drives `onUsage` and `onUsageFailure` from the\n * usage events, each called independently of `onEvent`.\n */\nexport function makeEventReporter(\n onEvent: ((event: VernLLMEvent) => void) | undefined,\n logger: Logger,\n usageHooks: UsageReporterHooks = {},\n): (event: VernLLMEvent) => void {\n return (event) => {\n if (onEvent) callHookSafely(logger, 'onEvent', () => onEvent(event));\n\n if (event.kind === 'usage' && usageHooks.onUsage) {\n callHookSafely(logger, 'onUsage', () => usageHooks.onUsage!(event.usage));\n }\n\n if (event.kind === 'usage_failure' && usageHooks.onUsageFailure) {\n callHookSafely(logger, 'onUsageFailure', () =>\n usageHooks.onUsageFailure!(event.usage, event.error),\n );\n }\n };\n}\n\n/** Resolves a target index so every circuit-breaker method agrees on what counts as valid. */\nexport function resolveExecutor(\n executors: CallExecutor[],\n index: number,\n caller: string,\n): CallExecutor {\n const executor = executors[index];\n\n if (!executor) {\n throw new RangeError(\n `${caller}: no target at index ${index} (chain has ${executors.length} target${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. */\nexport function warnIfModelUnsupported(\n isolateByModel: boolean,\n model: string | undefined,\n caller: string,\n logger: Logger,\n): void {\n if (model !== undefined && !isolateByModel) {\n 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 * A `void` adapter method with remote state may still return a promise nobody awaits, and an\n * unhandled rejection can end the Node process after the call succeeded. Logs the rejection\n * instead, so adapters don't each have to handle it.\n */\nexport function reportRejection(logger: Logger, message: string, result: unknown): void {\n void Promise.resolve(result).catch((error: unknown) => {\n try {\n logger.error(message, { message: error instanceof Error ? error.message : String(error) });\n } catch {\n // Reporting must never become a second, unhandled rejection: even\n // turning the reason into a string can throw.\n }\n });\n}\n","import { LLMError } from '../../../types/errors.js';\n\nimport type { CircuitBreakerAdapter, CircuitBreakerCallContext } from '../../../circuitBreaker.js';\nimport type { Logger } from '../../../logger.js';\n\n/** How long `VernLLM` waits for a breaker's `prepare` when the adapter declares no `prepareTimeoutMs`, in ms. */\nexport const DEFAULT_PREPARE_TIMEOUT_MS = 1000;\n\n/** A breaker known to have `prepare`, so it can be called on the adapter itself and keep its `this`. */\nexport type PreparableBreaker = CircuitBreakerAdapter &\n Required<Pick<CircuitBreakerAdapter, 'prepare'>>;\n\ntype PrepareOutcome = 'ready' | 'timeout' | 'aborted' | { failed: unknown };\n\n/**\n * Awaits `breaker.prepare` so `assertClosed` decides on fresh data, without letting a slow or\n * broken `prepare` block or fail the call. A rejection, throw or timeout is logged and the call\n * goes on with local state; only the call's own abort rejects, as `aborted`. A late rejection is\n * still handled.\n */\nexport async function runPrepare(\n breaker: PreparableBreaker,\n model: string,\n context: CircuitBreakerCallContext | undefined,\n logger: Logger,\n): Promise<void> {\n const signal = context?.signal;\n if (signal?.aborted) throw new LLMError('Circuit breaker check aborted', 'aborted');\n\n const timeoutMs = breaker.prepareTimeoutMs ?? DEFAULT_PREPARE_TIMEOUT_MS;\n\n let pending: Promise<void>;\n try {\n pending = Promise.resolve(breaker.prepare(model, context));\n } catch (error) {\n warnFailed(logger, error);\n return;\n }\n\n let timer: ReturnType<typeof setTimeout> | undefined;\n let onAbort: (() => void) | undefined;\n\n const outcome = await Promise.race<PrepareOutcome>([\n // Handles a rejection here, so a late one from a `prepare` that lost\n // the race below is never left unhandled.\n pending.then(\n () => 'ready' as const,\n (failed: unknown) => ({ failed }),\n ),\n new Promise<'timeout'>((resolve) => {\n timer = setTimeout(() => resolve('timeout'), timeoutMs);\n }),\n new Promise<'aborted'>((resolve) => {\n if (!signal) return;\n onAbort = () => resolve('aborted');\n signal.addEventListener('abort', onAbort, { once: true });\n // `prepare` may have aborted the signal synchronously, before the listener existed.\n if (signal.aborted) onAbort();\n }),\n ]).finally(() => {\n clearTimeout(timer);\n if (signal && onAbort) signal.removeEventListener('abort', onAbort);\n });\n\n if (outcome === 'aborted') throw new LLMError('Circuit breaker check aborted', 'aborted');\n\n if (outcome === 'timeout') {\n logger.warn(\n `[VernLLM] circuitBreaker.prepare took longer than ${timeoutMs}ms, continuing with the adapter's local state`,\n );\n } else if (outcome !== 'ready') {\n warnFailed(logger, outcome.failed);\n }\n}\n\nfunction warnFailed(logger: Logger, error: unknown): void {\n logger.warn(\n `[VernLLM] circuitBreaker.prepare failed, continuing with the adapter's local state: ${error instanceof Error ? error.message : String(error)}`,\n );\n}\n","import { LLMError } from '../../../types/errors.js';\n\n/**\n * Identity, not a message: never read for its text, only compared by\n * reference in `stampDeadlineCode`, so it can't collide with a reason a\n * caller's own `AbortController` happens to use.\n */\nexport const DEADLINE_REASON = Symbol('deadlineExceeded');\n\n/** Largest delay `setTimeout` honors (2^31 - 1 ms, about 24.8 days). */\nexport const MAX_TIMER_DELAY_MS = 2_147_483_647;\n\n/** The signal `call()` should actually use, and the timer to clear when done. */\nexport interface DeadlineSetup {\n signal: AbortSignal | undefined;\n timer: ReturnType<typeof setTimeout> | undefined;\n}\n\n/**\n * Joins `deadlineMs` into one signal the rest of `call()` treats like the caller's own. Without a\n * deadline the caller's signal passes through and no timer is created.\n */\nexport function setupDeadline(\n deadlineMs: number | undefined,\n callerSignal: AbortSignal | undefined,\n): DeadlineSetup {\n // setTimeout clamps anything above MAX_TIMER_DELAY_MS (and NaN) to about\n // 1ms, so an unbounded or out of range deadline would abort almost\n // immediately. Infinity and anything past the timer range mean no\n // deadline; NaN is treated the same as omitting it.\n if (deadlineMs === undefined || Number.isNaN(deadlineMs) || deadlineMs > MAX_TIMER_DELAY_MS) {\n return { signal: callerSignal, timer: undefined };\n }\n\n const controller = new AbortController();\n\n // A deadline of 0 (or negative) means the budget is already spent. A\n // `setTimeout(fn, 0)` still queues a macrotask, so it wouldn't reliably\n // beat dispatch, the abort has to happen synchronously here instead, the\n // same way an already-aborted caller signal is treated as a fail-fast\n // case rather than raced.\n if (deadlineMs <= 0) {\n controller.abort(DEADLINE_REASON);\n const signal = callerSignal\n ? AbortSignal.any([callerSignal, controller.signal])\n : controller.signal;\n return { signal, timer: undefined };\n }\n\n const timer = setTimeout(() => controller.abort(DEADLINE_REASON), deadlineMs);\n const signal = callerSignal\n ? AbortSignal.any([callerSignal, controller.signal])\n : controller.signal;\n\n return { signal, timer };\n}\n\n/**\n * Sets `code: 'deadline_exceeded'` on an aborted error without a code, only when the deadline\n * caused the abort rather than the caller's signal.\n */\nexport function stampDeadlineCode(error: unknown, signal: AbortSignal | undefined): unknown {\n if (\n error instanceof LLMError &&\n error.type === 'aborted' &&\n error.code === undefined &&\n signal?.reason === DEADLINE_REASON\n ) {\n error.code = 'deadline_exceeded';\n }\n\n return error;\n}\n","import { LLMError } from '../../types/errors.js';\nimport { MAX_TIMER_DELAY_MS } from '../execution/utils/deadline.utils.js';\n\nimport type { CallContext, JsonValue } from '../../types/call.js';\nimport type {\n MiddlewareContext,\n MiddlewareContextBase,\n MiddlewareStateBag,\n MiddlewareStateEntry,\n} from '../../types/middleware.js';\n\n/**\n * Per call machinery a middleware reaches through `ctx` but must not be able to read or replace,\n * so it is kept off the state bag, the same way `ownStores` is in `middleware.utils.ts`.\n */\nexport interface CallScope {\n /** The call's validated, frozen `context`. `undefined` when none was given. */\n context: CallContext | undefined;\n\n /** The call facts exposed on `ctx`. See `CallFacts`. */\n facts?: CallFacts;\n\n /** Reports a `custom` event. Never throws. See `createCallScope`. */\n emitCustom: (\n name: string,\n data: JsonValue | undefined,\n source: string,\n ctx: MiddlewareContext,\n ) => void;\n}\n\n/** Read only facts about how a call started, fixed for its whole life. */\nexport interface CallFacts {\n streaming?: boolean;\n callTargets?: readonly string[];\n deadlineAt?: number;\n}\n\n/**\n * Builds a call's facts from its params. `deadlineAt` is set only when `deadlineMs` is a real\n * deadline, matching `setupDeadline`: a missing, `NaN` or out of timer range value means none.\n */\nexport function createCallFacts(\n params: { stream?: boolean; targets?: readonly string[]; deadlineMs?: number },\n now: number = Date.now(),\n): CallFacts {\n const { stream, targets, deadlineMs } = params;\n const hasDeadline =\n deadlineMs !== undefined && !Number.isNaN(deadlineMs) && deadlineMs <= MAX_TIMER_DELAY_MS;\n\n return {\n streaming: stream === true,\n ...(targets === undefined ? {} : { callTargets: Object.freeze([...targets]) }),\n ...(hasDeadline ? { deadlineAt: now + deadlineMs } : {}),\n };\n}\n\n/** The facts to spread into a context, empty for a bag made outside a call. */\nexport function callFactsFor(state: MiddlewareStateBag): CallFacts {\n return scopes.get(state)?.facts ?? {};\n}\n\n/** One scope per logical call, keyed by that call's state bag. */\nconst scopes = new WeakMap<MiddlewareStateBag, CallScope>();\n\n/**\n * Attaches `scope` to a call's state bag. A second registration is ignored, since the inner call\n * of `cachedCall` reuses the bag the outer one already registered.\n */\nexport function registerCallScope(state: MiddlewareStateBag, scope: CallScope): void {\n if (!scopes.has(state)) scopes.set(state, scope);\n}\n\n/** The call's scope, or `undefined` for a bag made outside a call, like a manual `openCircuit()`. */\nexport function callScopeFor(state: MiddlewareStateBag): CallScope | undefined {\n return scopes.get(state);\n}\n\n/** The `emit` a freshly built context carries until `withOwn` binds it to a middleware. */\nexport const noopEmit: MiddlewareContextBase['emit'] = () => {};\n\n/** A plain `{}` or `Object.create(null)` object, not a class instance, `Date`, `Map` and so on. */\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== 'object' || value === null) return false;\n\n const prototype = Object.getPrototypeOf(value) as unknown;\n\n return prototype === Object.prototype || prototype === null;\n}\n\n/**\n * Whether `value` is plain JSON: plain objects, arrays, strings, finite numbers, booleans and\n * `null`. `undefined`, functions, symbols, `NaN`, `Infinity` and class instances are rejected.\n *\n * `ancestors` holds only the objects on the current path, so a cycle is rejected while a value\n * shared by two branches is not.\n */\nexport function isJson(value: unknown, ancestors: Set<object> = new Set()): value is JsonValue {\n if (value === null || typeof value === 'string' || typeof value === 'boolean') return true;\n if (typeof value === 'number') return Number.isFinite(value);\n\n // `Array.from` visits the holes of a sparse array as `undefined`, which are then rejected.\n const items = Array.isArray(value)\n ? Array.from(value as unknown[])\n : isPlainObject(value)\n ? Object.values(value)\n : undefined;\n\n if (items === undefined || ancestors.has(value as object)) return false;\n\n ancestors.add(value as object);\n\n const valid = items.every((item) => isJson(item, ancestors));\n\n ancestors.delete(value as object);\n\n return valid;\n}\n\n/** Freezes `value` and everything inside it. Only ever handed plain JSON, so it always ends. */\nfunction deepFreeze<T>(value: T): T {\n if (typeof value === 'object' && value !== null) {\n Object.values(value).forEach(deepFreeze);\n Object.freeze(value);\n }\n\n return value;\n}\n\n/**\n * Validates, clones and deep freezes a call's `context`. The clone means a caller mutating its\n * own object mid call can't change what middleware read. Throws `invalid_params` for anything\n * that isn't a plain JSON object.\n */\nexport function prepareCallContext(value: unknown): CallContext | undefined {\n if (value === undefined) return undefined;\n\n // Data nested deep enough to overflow the stack is as invalid as a cycle.\n let valid = false;\n\n try {\n valid = isPlainObject(value) && isJson(value);\n } catch {\n valid = false;\n }\n\n if (!valid) {\n throw new LLMError('`context` must be a plain JSON object', 'invalid_params', {\n code: 'invalid_context',\n });\n }\n\n return deepFreeze(structuredClone(value as CallContext));\n}\n\n/**\n * A `[key, value]` pair whose key looks like one made by `createStateKey`. `MiddlewareStateKey` is\n * a type level brand, so the only runtime trace of one is its string `debugName`.\n */\nfunction isStateEntry(entry: unknown): entry is MiddlewareStateEntry {\n if (!Array.isArray(entry) || entry.length !== 2) return false;\n\n const key: unknown = entry[0];\n\n return (\n typeof key === 'object' &&\n key !== null &&\n typeof (key as { debugName?: unknown }).debugName === 'string'\n );\n}\n\n/**\n * Checks that `state` is an array of `[key, value]` pairs, so a malformed entry fails here instead\n * of seeding a key nothing can read. Throws a plain `invalid_params`, with no `code`, since it\n * only happens when a caller bypasses the types.\n */\nexport function validateStateEntries(state: unknown): readonly MiddlewareStateEntry[] | undefined {\n if (state === undefined) return undefined;\n\n if (!Array.isArray(state) || !state.every(isStateEntry)) {\n throw new LLMError(\n '`state` must be an array of [key, value] pairs, with keys made by createStateKey',\n 'invalid_params',\n );\n }\n\n return state;\n}\n","import type { VernLLMMiddleware } from '../../types/middleware.js';\n\n/**\n * A middleware's label everywhere a caller can see one: logs, the\n * `'middleware'` event, and `registeredMiddlewareNames`. `name`, or the\n * bracketed `transformOrder` position when unnamed. The brackets keep an\n * unnamed entry from ever reading like one named `\"0\"`.\n */\nexport function middlewareLabel(middleware: VernLLMMiddleware, index: number): string {\n return middleware.name ?? `[${index}]`;\n}\n\n/** `middlewareLabel` for every entry of an already ordered array. */\nexport function middlewareLabels(ordered: readonly VernLLMMiddleware[]): readonly string[] {\n return Object.freeze(ordered.map((entry, index) => middlewareLabel(entry, index)));\n}\n\n/** The two label lists every middleware context carries. */\nexport interface MiddlewareContextNames {\n registeredMiddlewareNames: readonly string[];\n transformMiddlewareNames: readonly string[];\n}\n\n/**\n * Keyed by array identity: every call site passes the same\n * `transformOrder` array, so the labels are built once per instance\n * instead of once per event or attempt.\n */\nconst contextNamesCache = new WeakMap<readonly VernLLMMiddleware[], MiddlewareContextNames>();\n\n/** `registeredMiddlewareNames` and `transformMiddlewareNames` for an already ordered array. */\nexport function middlewareContextNames(\n ordered: readonly VernLLMMiddleware[],\n): MiddlewareContextNames {\n let names = contextNamesCache.get(ordered);\n\n if (!names) {\n const labels = middlewareLabels(ordered);\n names = {\n registeredMiddlewareNames: labels,\n transformMiddlewareNames: Object.freeze(\n labels.filter((_, index) => ordered[index]!.transform !== undefined),\n ),\n };\n contextNamesCache.set(ordered, names);\n }\n\n return names;\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\ntype HeaderKind = 'ms' | 'seconds' | 'date';\n\n/**\n * Headers checked in order. The millisecond forms come first for finer timing; Retry-After is read\n * as seconds and as an HTTP date.\n */\nconst RETRY_AFTER_CANDIDATES: { name: string; kind: HeaderKind }[] = [\n { name: 'Retry-After-Ms', kind: 'ms' },\n { name: 'X-Retry-After-Ms', kind: 'ms' },\n { name: 'Retry-After', kind: 'seconds' },\n { name: 'Retry-After', kind: 'date' },\n];\n\n/** Reads a header from a `Headers` object or a plain object, case insensitively. */\nfunction readHeader(headers: object, name: string): string | undefined {\n const getter = headers as { get?: (n: string) => string | null };\n\n if (typeof getter.get === 'function') {\n return getter.get(name) ?? undefined;\n }\n\n const match = Object.entries(headers as Record<string, unknown>).find(\n ([key]) => key.toLowerCase() === name.toLowerCase(),\n )?.[1];\n\n return typeof match === 'string' ? match : undefined;\n}\n\n/**\n * A negative value (a malformed delta or a past date) gave no usable timing, so it counts as absent\n * rather than a 0ms retry.\n */\nfunction clampOrUndefined(rawMs: number, maxDelayMs: number): number | undefined {\n return rawMs < 0 ? undefined : Math.min(rawMs, maxDelayMs);\n}\n\n/**\n * Provider retry timing in ms from an unknown error: known millisecond headers first, then\n * Retry-After as seconds or an HTTP date. Reads `.headers`, then `.response.headers`. Capped at\n * `maxDelayMs`; `undefined` when nothing usable is present.\n */\nexport function extractRetryAfterMs(\n err: unknown,\n maxDelayMs: number = 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 for (const { name, kind } of RETRY_AFTER_CANDIDATES) {\n const raw = readHeader(headers, name)?.trim();\n if (!raw) continue;\n\n if (kind === 'ms' && /^\\d+$/.test(raw)) {\n return clampOrUndefined(Number(raw), maxDelayMs);\n }\n\n if (kind === 'seconds' && /^\\d+(\\.\\d+)?$/.test(raw)) {\n return clampOrUndefined(Number(raw) * 1000, maxDelayMs);\n }\n\n if (kind === 'date') {\n const dateMs = Date.parse(raw);\n if (!Number.isNaN(dateMs)) return clampOrUndefined(dateMs - Date.now(), maxDelayMs);\n }\n }\n\n return undefined;\n}\n\n/**\n * Returns the cap unchanged or throws. `0` (retry at once) and `Infinity` (no cap) are valid;\n * negative or NaN throws at construction.\n */\nexport function validateMaxRetryAfterMs(maxRetryAfterMs: number, providerName: string): number {\n if (typeof maxRetryAfterMs !== 'number' || Number.isNaN(maxRetryAfterMs) || maxRetryAfterMs < 0) {\n throw new RangeError(\n `${providerName}: maxRetryAfterMs must be 0 or more (Infinity for no cap), got ${String(maxRetryAfterMs)}`,\n );\n }\n\n return maxRetryAfterMs;\n}\n","import { LLMError } from '../../../../types/errors.js';\nimport { MAX_TIMER_DELAY_MS } from '../deadline.utils.js';\n\nimport type { Logger } from '../../../../logger.js';\n\n// `setTimeout` clamps anything above MAX_TIMER_DELAY_MS, or Infinity, to about 1ms,\n// so the helpers below treat those as no timeout rather than an instant one.\n\n/**\n * The delay `setTimeout` should use, or `undefined` when the timeout is off (0, negative or\n * `Infinity`).\n */\nexport function 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. */\nexport function clampTimeoutMs(ms: number): number {\n return Math.min(ms, MAX_TIMER_DELAY_MS);\n}\n\n/**\n * Runs `fn` with a timeout, joined with any external signal. The call is raced against the timer,\n * so a client that ignores the signal still times out. After the timer fires any error becomes\n * `LLMError('timeout')`; an external abort stays `aborted`. `Infinity`, or any value past the timer\n * range, disables the timeout.\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 signal = externalSignal\n ? AbortSignal.any([externalSignal, controller.signal])\n : controller.signal;\n\n const timeoutError = () =>\n new LLMError('Request timed out', 'timeout', { code: 'request_timeout' });\n\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n // Raced against `fn`, so a client that ignores the signal still times out.\n const timeoutPromise = new Promise<never>((_, reject) => {\n if (activeTimeoutMs === undefined) return;\n\n timer = setTimeout(() => {\n controller.abort();\n reject(timeoutError());\n }, clampTimeoutMs(activeTimeoutMs));\n });\n\n try {\n return await Promise.race([fn(signal), timeoutPromise]);\n } catch (err) {\n // Any error raised after the internal timer fired counts as a timeout,\n // whatever abort error type the client threw. External aborts propagate.\n if (controller.signal.aborted && !externalSignal?.aborted) {\n throw err instanceof LLMError && err.type === 'timeout' ? err : timeoutError();\n }\n\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Races one `iterator.next()` against an idle timer, bounding the gap between chunks, measured from\n * the latest chunk. Rejects with `LLMError('timeout')`; 0, undefined or `Infinity` disable it.\n * `onIdle` fires first so the transport can be aborted. `logger` records a `next()` that settles\n * after the timeout, since that late chunk, possibly usage, would otherwise vanish.\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","import { LLMError, type LLMRequestSnapshot, type RetryAttempt } from '../../../../types/errors.js';\nimport { DEFAULT_MAX_DELAY_MS, extractRetryAfterMs } from './retryAfter.utils.js';\nimport { clampTimeoutMs } from './timeout.utils.js';\n\nimport type { Logger } from '../../../../logger.js';\nimport type {\n AttemptContext,\n MiddlewareStateBag,\n VernLLMEvent,\n VernLLMMiddleware,\n} from '../../../../types/index.js';\n\nexport {\n DEFAULT_MAX_DELAY_MS,\n extractRetryAfterMs,\n validateMaxRetryAfterMs,\n} from './retryAfter.utils.js';\nexport {\n clampTimeoutMs,\n resolveActiveTimeoutMs,\n withChunkIdleTimeout,\n withTimeout,\n} from './timeout.utils.js';\n\n/**\n * Full jitter: uniform over `[0, exp]`. Shared by retry backoff and the breaker's cooldown backoff.\n */\nexport function fullJitter(exp: number): number {\n return Math.random() * exp;\n}\n\n/**\n * Exponential backoff with full jitter, capped at `maxDelayMs`. Without a Retry-After, a 429 backs\n * off hardest and a 5xx more than the default curve; `rateLimited` wins when both are set.\n */\nexport function getBackoffDelay(\n baseDelayMs: number,\n attempt: number,\n maxDelayMs = DEFAULT_MAX_DELAY_MS,\n rateLimited = false,\n serverError = false,\n): number {\n const multiplier = rateLimited ? 2 : serverError ? 1.5 : 1;\n const exp = Math.min(baseDelayMs * multiplier * 2 ** attempt, maxDelayMs);\n return fullJitter(exp);\n}\n\n/** Waits `delay` ms before a retry. Rejects as aborted at once when `signal` fires. */\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 // A Retry-After cap of Infinity can hand over a delay setTimeout would\n // wrap to ~1ms, the opposite of the wait the provider asked for.\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, clampTimeoutMs(delay));\n\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n\n/**\n * Whether a failed attempt is worth retrying, per `LLMError.retryable`\n * and `nonRetryableStatus`. Takes `extractStatus` as a param instead of\n * importing it, since `errors.utils.ts` already imports from this file.\n */\nexport function shouldRetry(\n error: unknown,\n nonRetryableStatus: number[],\n extractStatus: (err: unknown) => number | undefined,\n signal?: AbortSignal,\n): boolean {\n if (signal?.aborted) return false;\n\n if (error instanceof LLMError && !error.retryable) return false;\n\n const status = extractStatus(error);\n\n return !(status !== undefined && nonRetryableStatus.includes(status));\n}\n\n/**\n * Everything `recoverDelay` needs. `extractStatus`, `normalizeError`, and\n * `emitEvent` are injected instead of imported, since `errors.utils.ts`\n * already imports from this file.\n */\nexport interface RecoverDelayParams {\n requestId: string;\n model: string;\n attempt: number;\n error: unknown;\n state: MiddlewareStateBag;\n signal: AbortSignal | undefined;\n providerName: string;\n maxRetries: number;\n baseDelayMs: number;\n /** See `VernLLMOptions.maxRetryAfterMs`. Omitted means the 10s default. */\n maxRetryAfterMs?: number;\n middleware: VernLLMMiddleware[];\n middlewareTimeoutMs: number;\n logger: Logger;\n reportEvent: (event: VernLLMEvent) => void;\n buildEventContext: (\n requestId: string,\n model: string,\n attempt: number,\n signal: AbortSignal | undefined,\n state: MiddlewareStateBag,\n ) => AttemptContext;\n extractStatus: (err: unknown) => number | undefined;\n normalizeError: (err: unknown, signal?: AbortSignal) => LLMError;\n emitEvent: (\n event: VernLLMEvent,\n ctx: AttemptContext,\n reportEvent: (event: VernLLMEvent) => void,\n middleware: VernLLMMiddleware[],\n middlewareTimeoutMs: number,\n logger: Logger,\n ) => void;\n}\n\n/**\n * Waits before a retry, honoring the failed attempt's Retry-After when present, otherwise the\n * backoff curve for its status. Both are capped at the same max delay.\n */\nexport async function recoverDelay(params: RecoverDelayParams): Promise<void> {\n const {\n requestId,\n model,\n attempt,\n error,\n state,\n signal,\n providerName,\n maxRetries,\n baseDelayMs,\n maxRetryAfterMs,\n middleware,\n middlewareTimeoutMs,\n logger,\n reportEvent,\n buildEventContext,\n extractStatus,\n normalizeError,\n emitEvent,\n } = params;\n\n const retryAfterMs = extractRetryAfterMs(error, maxRetryAfterMs);\n const status = extractStatus(error);\n const delay =\n retryAfterMs ??\n getBackoffDelay(\n baseDelayMs,\n attempt,\n undefined,\n status === 429,\n status !== undefined && status >= 500 && status <= 599,\n );\n const retryAfterHonored = retryAfterMs !== undefined;\n\n logger.warn(\n `[VernLLM:${requestId}] recovery attempt ${attempt}/${maxRetries}, waiting ${Math.ceil(delay)}ms` +\n (retryAfterHonored ? ' (honoring Retry-After)' : ''),\n );\n\n emitEvent(\n {\n kind: 'retry',\n requestId,\n provider: providerName,\n model,\n attempt,\n maxRetries,\n delayMs: delay,\n retryAfterHonored,\n error: normalizeError(error, signal),\n },\n buildEventContext(requestId, model, attempt, signal, state),\n reportEvent,\n middleware,\n middlewareTimeoutMs,\n logger,\n );\n\n await waitForRetry(delay, signal);\n}\n\n/**\n * Runs `fn` with retries. Each retried failure is recorded in `attempts` as a snapshot; the final\n * failure is the thrown error itself.\n */\nexport interface RetryWithBackoffParams<T> {\n fn: (\n attempt: number,\n onRequest: (snapshot: LLMRequestSnapshot | undefined) => void,\n ) => Promise<T>;\n maxRetries: number;\n signal?: AbortSignal;\n onAttempt?: () => void;\n attempts?: RetryAttempt[];\n shouldRetryAttempt: (error: unknown, signal?: AbortSignal) => boolean;\n recoverDelayForAttempt: (attempt: number, error: unknown) => Promise<void>;\n /** Injected for the same reason as on `RecoverDelayParams`. */\n normalizeError: (err: unknown, signal?: AbortSignal) => LLMError;\n}\n\n/**\n * A usable retry count. NaN, negative or non-number values would skip the loop and make no call, so\n * they mean one attempt. Fractions round down; `Infinity` stays.\n */\nexport function normalizeMaxRetries(maxRetries: number): number {\n if (typeof maxRetries !== 'number' || Number.isNaN(maxRetries) || maxRetries < 0) return 0;\n return Math.floor(maxRetries);\n}\n\nexport async function retryWithBackoff<T>(params: RetryWithBackoffParams<T>): Promise<T> {\n const {\n fn,\n signal,\n onAttempt,\n attempts,\n shouldRetryAttempt,\n recoverDelayForAttempt,\n normalizeError,\n } = params;\n const maxRetries = normalizeMaxRetries(params.maxRetries);\n\n let lastError: unknown;\n let lastRequestForAttempt: LLMRequestSnapshot | undefined;\n\n for (let attempt = 0; attempt <= 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 // recoverDelayForAttempt 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 recoverDelayForAttempt(attempt, lastError);\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 < maxRetries && shouldRetryAttempt(error, signal);\n if (!willRetry) break;\n\n attempts?.push({\n index: attempt,\n error: normalizeError(error, signal).toSnapshot(),\n request: lastRequestForAttempt,\n });\n }\n }\n\n throw lastError;\n}\n","import { LLMError, type LLMErrorCode, type RetryAttempt } from '../../../types/errors.js';\nimport { extractRetryAfterMs } from './retry/retry.utils.js';\n\n/**\n * The HTTP status on an unknown error: `status`, then `statusCode`, then the AWS SDK's\n * `$metadata.httpStatusCode`. `undefined` when none is present.\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/** Error codes that can only mean the connection itself failed, never an application error. */\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 a transport failure that never reached the provider. Only well known signals\n * count, so an unknown error isn't misread as a connection failure.\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 // Node's `fetch` wraps the real error in `TypeError('fetch failed', { cause })`. This catches it\n // by the cause's code when the wrapper message differs.\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 * A readable description of a thrown value: its `error` field (the provider body), else `message`.\n * Always a safe string.\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 * The `LLMErrorCode` for an HTTP status, shared by new and already normalized errors so they can't\n * drift.\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 * Some providers answer a non-2xx with no body, which SDKs render as `\"400 status code (no body)\"`.\n * Detail is read from the `error` and `message` fields directly, since `describeError` falls back\n * to echoing the whole value.\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 // Defensive: this function's only call site (below, in normalizeError)\n // reaches it via a status extracted by extractStatus, which itself\n // only returns a status for an object input, so `error` is always an\n // object here in practice. Kept for callers this function doesn't\n // control yet, and as a safe fallback if that invariant ever changes.\n /* v8 ignore next */\n if (error && typeof error === 'object') {\n const { error: errorField, message } = error as { error?: unknown; message?: unknown };\n\n // A non-empty `error` is the provider's body and counts as detail. `null`, `''` and `{}` are\n // placeholders and fall through.\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. Also unreachable in practice for\n // the same reason as the guard above (extractStatus already filters\n // non-object errors before this function is ever called).\n /* v8 ignore next */\n return true;\n}\n\n/**\n * Converts any thrown value into an `LLMError`. `attempts` goes through the constructor like every\n * other field.\n */\nexport function normalizeError(\n error: unknown,\n signal?: AbortSignal,\n attempts?: RetryAttempt[],\n maxRetryAfterMs?: number,\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 // Same cap a header parsed below gets, so a thrown LLMError can't\n // outwait the target's maxRetryAfterMs. `!== undefined` keeps a 0 cap.\n if (maxRetryAfterMs !== undefined && error.retryAfterMs !== undefined) {\n error.retryAfterMs = Math.min(error.retryAfterMs, maxRetryAfterMs);\n }\n\n return error;\n }\n\n const status = extractStatus(error);\n const retryAfterMs = extractRetryAfterMs(error, maxRetryAfterMs);\n\n if (status !== undefined) {\n const description = describeError(error);\n\n // The provider's description goes into the message itself, so it is there without debug\n // logging.\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","/** A memoized async call, returned by `createOnceAsync`. */\nexport interface OnceAsync<T> {\n /**\n * Calls the wrapped function on the first invocation; every later call\n * returns that same promise, whether it has settled yet or not.\n */\n call(): Promise<T>;\n /** Whether `call()` has been invoked yet. */\n wasCalled(): boolean;\n /**\n * The value `call()`'s promise resolved to, once it has. Stays\n * `undefined` before that settles, and if it rejects instead.\n */\n resolvedValue(): T | undefined;\n}\n\n/**\n * Runs `fn` at most once, reusing the first promise, and marks it handled so a discarded result\n * never becomes an unhandled rejection. A `wrap` may call `next()` more than once or not await it.\n */\nexport function createOnceAsync<T>(fn: () => Promise<T>): OnceAsync<T> {\n let called = false;\n let resolved: T | undefined;\n let promise: Promise<T> | undefined;\n\n function call(): Promise<T> {\n if (promise) return promise;\n\n called = true;\n\n // Not `async`: assigning `promise` here, synchronously, before any\n // `await`, is what makes two `call()`s issued back to back with no\n // `await` between them (e.g. `Promise.all([call(), call()])`) still\n // see the first call's promise already in place.\n promise = fn().then((value) => {\n resolved = value;\n return value;\n });\n\n // The promise returned below is untouched, so its own rejection\n // still propagates normally to anyone who does await it. This\n // separate handle only exists to swallow a rejection nobody else\n // ever observes.\n promise.catch(() => {});\n\n return promise;\n }\n\n return {\n call,\n wasCalled: () => called,\n resolvedValue: () => resolved,\n };\n}\n","import {\n LLMError,\n type WireCallRequest,\n type WireCallRequestPatch,\n} from '../../../../types/index.js';\n\nconst PATCH_FIELDS: (keyof WireCallRequestPatch)[] = [\n 'temperature',\n 'max_tokens',\n 'reasoning_effort',\n 'budget_tokens',\n 'tool_choice',\n 'messages',\n 'addMessages',\n 'tools',\n 'addTools',\n];\n\n/**\n * Merges one `transform` patch onto the request. `addMessages` and `addTools` append; everything\n * else overwrites. Returns the request and which fields changed, for the `'middleware'` event.\n */\nexport function mergePatch(\n request: WireCallRequest,\n patch: WireCallRequestPatch,\n): { request: WireCallRequest; patchedFields: string[] } {\n // `model` and `response_format` aren't on the patch type, but untyped code can still set them.\n // Copied through so the unchanged check can catch them.\n const rawPatch = patch as WireCallRequestPatch & {\n model?: unknown;\n response_format?: unknown;\n };\n\n const patchedFields: string[] = PATCH_FIELDS.filter((field) => patch[field] !== undefined);\n if (rawPatch.model !== undefined) patchedFields.push('model');\n if (rawPatch.response_format !== undefined) patchedFields.push('response_format');\n\n if (patchedFields.length === 0) {\n return { request, patchedFields: [] };\n }\n\n const next: WireCallRequest = { ...request };\n\n if (rawPatch.model !== undefined) next.model = rawPatch.model as string;\n if (rawPatch.response_format !== undefined) {\n next.response_format = rawPatch.response_format as WireCallRequest['response_format'];\n }\n\n if (patch.temperature !== undefined) next.temperature = patch.temperature;\n if (patch.max_tokens !== undefined) next.max_tokens = patch.max_tokens;\n if (patch.reasoning_effort !== undefined) next.reasoning_effort = patch.reasoning_effort;\n if (patch.budget_tokens !== undefined) next.budget_tokens = patch.budget_tokens;\n if (patch.tool_choice !== undefined) next.tool_choice = patch.tool_choice;\n\n if (patch.messages !== undefined) {\n next.messages = patch.messages;\n }\n if (patch.addMessages !== undefined && patch.addMessages.length > 0) {\n next.messages = [...next.messages, ...patch.addMessages];\n }\n\n if (patch.tools !== undefined) {\n next.tools = patch.tools;\n }\n if (patch.addTools !== undefined && patch.addTools.length > 0) {\n next.tools = [...(next.tools ?? []), ...patch.addTools];\n }\n\n return { request: next, patchedFields };\n}\n\n/** Throws `LLMError('invalid_params')` naming `label` if `merged.tools` has a duplicate name, run right after the addTools merge that could have introduced one. */\nexport function assertNoDuplicateTools(request: WireCallRequest, label: string): void {\n if (!request.tools) return;\n\n const seen = new Set<string>();\n const duplicates = new Set<string>();\n\n for (const tool of request.tools) {\n if (seen.has(tool.function.name)) duplicates.add(tool.function.name);\n seen.add(tool.function.name);\n }\n\n if (duplicates.size > 0) {\n throw new LLMError(\n `middleware \"${label}\" added tool(s) with 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/** Backstop for callers who bypass the type system: `transform` can't express a change to `model`/`response_format` in TypeScript, this catches it at runtime for `any`/plain-JS callers. */\nexport function assertModelAndResponseFormatUnchanged(\n before: WireCallRequest,\n after: WireCallRequest,\n label: string,\n): void {\n if (after.model !== before.model) {\n throw new LLMError(\n `middleware \"${label}\" changed \\`model\\` via transform, which isn't supported. Configure the target's model instead.`,\n 'invalid_params',\n );\n }\n\n if (JSON.stringify(after.response_format) !== JSON.stringify(before.response_format)) {\n throw new LLMError(\n `middleware \"${label}\" changed \\`response_format\\` via transform, which isn't supported.`,\n 'invalid_params',\n );\n }\n}\n","import {\n LLMError,\n type AttemptContext,\n type MiddlewareContext,\n type MiddlewareStateBag,\n type VernLLMEvent,\n type VernLLMMiddleware,\n type WireCallRequest,\n type WireCallRequestPatch,\n} from '../../../../types/index.js';\nimport { callScopeFor } from '../../../utils/callScope.utils.js';\nimport { logError, logHookError } from '../../../utils/logger.utils.js';\nimport { middlewareLabel } from '../../../utils/middlewareLabels.utils.js';\nimport { normalizeError } from '../errors.utils.js';\nimport { createOnceAsync } from '../once.utils.js';\nimport {\n assertModelAndResponseFormatUnchanged,\n assertNoDuplicateTools,\n mergePatch,\n} from './transformPatch.utils.js';\n\nimport type { Logger } from '../../../../logger.js';\n\n/** Default `middlewareTimeoutMs`, used both as `VernLLMOptions`'s own default and as the instance-level bound `CallExecutor` falls back to when none is passed in. Bounds `transform` and a function `enabled`; `wrap` itself is never bounded by this. */\nexport const DEFAULT_MIDDLEWARE_TIMEOUT_MS = 5000;\n\nexport {\n assertModelAndResponseFormatUnchanged,\n assertNoDuplicateTools,\n mergePatch,\n} from './transformPatch.utils.js';\n\n/** `middleware.name`, or its array position if unnamed. Used in log lines and the `'middleware'` event. */\nexport { middlewareLabel };\n\n/**\n * Each middleware's `ctx.own`, per logical call (keyed by that call's state bag) and per chain\n * (0 for the main chain).\n */\nconst ownStores = new WeakMap<\n MiddlewareStateBag,\n Map<VernLLMMiddleware, Map<number, Record<string, unknown>>>\n>();\n\n/** Where a chain began: the chain it was started from, and the `wrap` layer that started it. */\ninterface ChainStart {\n parent: number;\n layer: number;\n}\n\n/** Per call: how each chain began, and each entry's position in the `wrap` nesting. */\ninterface ChainTable {\n starts: Map<number, ChainStart>;\n layers: ReadonlyMap<VernLLMMiddleware, number>;\n}\n\nconst chainTables = new WeakMap<MiddlewareStateBag, ChainTable>();\n\nfunction chainTableFor(state: MiddlewareStateBag): ChainTable {\n let table = chainTables.get(state);\n\n if (!table) {\n table = { starts: new Map(), layers: new Map() };\n chainTables.set(state, table);\n }\n\n return table;\n}\n\n/** Records each entry's position in the `wrap` nesting for this call. */\nexport function recordWrapLayers(\n state: MiddlewareStateBag,\n layers: ReadonlyMap<VernLLMMiddleware, number>,\n): void {\n chainTableFor(state).layers = layers;\n}\n\n/** Records that `chain` was started from `parent` by the `wrap` at `layer`. */\nexport function recordChainStart(\n state: MiddlewareStateBag,\n chain: number,\n start: ChainStart,\n): void {\n chainTableFor(state).starts.set(chain, start);\n}\n\n/**\n * The chain whose `own` this entry uses: the chain its `wrap` ran in. An entry inside a rerunning\n * `wrap` has one per chain; an entry outside it (or that `wrap` itself) keeps the one of the chain\n * that `wrap` ran in, in every hook. An entry with no known layer counts as innermost.\n */\nfunction ownerChain(state: MiddlewareStateBag, chain: number, entry: VernLLMMiddleware): number {\n const table = chainTables.get(state);\n const layer = table?.layers.get(entry) ?? Number.POSITIVE_INFINITY;\n let current = chain;\n\n while (current > 0) {\n const start = table?.starts.get(current);\n\n if (start === undefined || layer > start.layer) break;\n current = start.parent;\n }\n\n return current;\n}\n\n/**\n * `ctx` with `own` set to this middleware's scratch object for the call and chain, and `emit` bound\n * to its `label` so a custom event says who reported it. The same `own` object is returned for every\n * hook in a chain, so a value set in `wrap` is there in `transform`. Collected with the call's state\n * bag.\n */\nexport function withOwn<C extends MiddlewareContext>(\n ctx: C,\n entry: VernLLMMiddleware,\n label: string,\n): C {\n let store = ownStores.get(ctx.state);\n\n if (!store) {\n store = new Map();\n ownStores.set(ctx.state, store);\n }\n\n let byChain = store.get(entry);\n\n if (!byChain) {\n byChain = new Map();\n store.set(entry, byChain);\n }\n\n const chain = ownerChain(ctx.state, ctx.chain ?? 0, entry);\n let own = byChain.get(chain);\n\n if (!own) {\n own = {};\n byChain.set(chain, own);\n }\n\n return {\n ...ctx,\n own,\n // A bag made outside a call, like a manual `openCircuit()`'s, has no scope to report to.\n emit: (name, data) => callScopeFor(ctx.state)?.emitCustom(name, data, label, ctx),\n };\n}\n\n/**\n * Bounds `transform` and a function `enabled`, which take no signal, with a plain race. A hung\n * middleware keeps running but is no longer awaited. The rejection names `label` and uses code\n * `middleware_timeout`, which is never retried. `timeoutMs <= 0` means unbounded.\n */\nfunction raceTimeout<T>(fn: () => Promise<T>, timeoutMs: number, label: string): Promise<T> {\n if (timeoutMs <= 0) return fn();\n\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(\n new LLMError(`middleware \"${label}\" timed out after ${timeoutMs}ms`, 'timeout', {\n code: 'middleware_timeout',\n }),\n );\n }, timeoutMs);\n\n fn().then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (error) => {\n clearTimeout(timer);\n reject(error);\n },\n );\n });\n}\n\n/**\n * Resolves `enabled` for one call. A throwing or timed out predicate is logged and treated as\n * `false`.\n */\nexport async function resolveEnabled(\n middleware: VernLLMMiddleware,\n ctx: MiddlewareContext,\n label: string,\n middlewareTimeoutMs: number,\n logger: Logger,\n): Promise<boolean> {\n const { enabled } = middleware;\n\n if (enabled === undefined) return true;\n if (typeof enabled === 'boolean') return enabled;\n\n const timeoutMs = middleware.timeoutMs ?? middlewareTimeoutMs;\n\n try {\n return await raceTimeout(\n async () => enabled(withOwn(ctx, middleware, label)),\n timeoutMs,\n label,\n );\n } catch (error) {\n logError(\n logger,\n `[VernLLM] middleware \"${label}\".enabled threw or timed out, treating as disabled`,\n error,\n );\n return false;\n }\n}\n\n/** Everything `applyMiddlewareTransforms` needs beyond the request itself. */\nexport interface ApplyMiddlewareTransformsParams {\n request: WireCallRequest;\n requestId: string;\n attempt: number;\n signal: AbortSignal | undefined;\n state: MiddlewareStateBag;\n /** Already in `transform`/`onEvent` order. Order is decided once, at `VernLLM` construction time, by `buildMiddlewarePipeline`/`resolveMiddlewareOrder` (`resolveMiddlewareOrder.ts`); this function trusts the order it's handed and never re-sorts it. */\n middleware: VernLLMMiddleware[];\n middlewareTimeoutMs: number;\n logger: Logger;\n reportEvent: (event: VernLLMEvent) => void;\n buildContext: (\n attempt: number,\n signal: AbortSignal | undefined,\n state: MiddlewareStateBag,\n ) => AttemptContext;\n /**\n * Filled with every entry whose `enabled` resolved true for this\n * attempt, so `dispatch` reuses the same decision instead of asking a\n * predicate twice and possibly getting a different answer.\n */\n enabledEntries?: Set<VernLLMMiddleware>;\n}\n\n/**\n * Runs each applicable `transform` in order, merging each patch at once so later ones see it.\n * Reports a `'middleware'` event for each change and each skip.\n */\nexport async function applyMiddlewareTransforms(\n params: ApplyMiddlewareTransformsParams,\n): Promise<WireCallRequest> {\n const {\n request,\n requestId,\n attempt,\n signal,\n state,\n middleware,\n middlewareTimeoutMs,\n logger,\n reportEvent,\n buildContext,\n enabledEntries,\n } = params;\n\n if (middleware.length === 0) return request;\n\n const before = request;\n let current = request;\n\n for (const [index, middlewareEntry] of middleware.entries()) {\n const label = middlewareLabel(middlewareEntry, index);\n\n const ctx = buildContext(attempt, signal, state);\n\n const isEnabled = await resolveEnabled(\n middlewareEntry,\n ctx,\n label,\n middlewareTimeoutMs,\n logger,\n );\n\n if (!isEnabled) {\n if (middlewareEntry.enabled !== undefined) {\n emitEvent(\n { kind: 'middleware', requestId, middleware: label, hook: 'enabled_skip' },\n ctx,\n reportEvent,\n middleware,\n middlewareTimeoutMs,\n logger,\n );\n }\n continue;\n }\n\n enabledEntries?.add(middlewareEntry);\n\n if (!middlewareEntry.transform) continue;\n\n const patch = await runTransform(\n middlewareEntry,\n structuredClone(current),\n ctx,\n label,\n middlewareTimeoutMs,\n );\n const { request: merged, patchedFields } = mergePatch(current, patch);\n\n if (patchedFields.length > 0) {\n if (patch.tools !== undefined || patch.addTools?.length) {\n assertNoDuplicateTools(merged, label);\n }\n emitEvent(\n { kind: 'middleware', requestId, middleware: label, hook: 'transform', patchedFields },\n ctx,\n reportEvent,\n middleware,\n middlewareTimeoutMs,\n logger,\n );\n }\n\n current = merged;\n }\n\n assertModelAndResponseFormatUnchanged(before, current, 'chain');\n\n return current;\n}\n\n/**\n * Runs one `transform` within its timeout. A throw is normalized, and only an unrecognizable one\n * becomes `invalid_params` naming the middleware.\n */\nexport async function runTransform(\n middleware: VernLLMMiddleware,\n request: Readonly<WireCallRequest>,\n ctx: AttemptContext,\n label: string,\n middlewareTimeoutMs: number,\n): Promise<WireCallRequestPatch> {\n if (!middleware.transform) return {};\n\n const timeoutMs = middleware.timeoutMs ?? middlewareTimeoutMs;\n\n try {\n return await raceTimeout(\n async () => middleware.transform!(request, withOwn(ctx, middleware, label)),\n timeoutMs,\n label,\n );\n } catch (error) {\n throw reclassifyMiddlewareThrow(error, label, ctx.signal);\n }\n}\n\n/** One `dispatch` hook to run, with the label logs and errors use for it. */\nexport interface DispatchHook {\n entry: VernLLMMiddleware & { dispatch: NonNullable<VernLLMMiddleware['dispatch']> };\n label: string;\n}\n\n/** Everything `runDispatch` needs. */\nexport interface RunDispatchParams {\n /** The final request, after every `transform`. Each hook gets its own copy. */\n request: WireCallRequest;\n /** Outermost first. Already filtered to entries enabled for this attempt. */\n hooks: readonly DispatchHook[];\n ctx: AttemptContext;\n /** Sends the provider request. Rejects with an `LLMError`. */\n send: () => Promise<void>;\n logger: Logger;\n}\n\n/**\n * Runs `send` inside every `dispatch` hook, outermost first, settling with `send`'s outcome. Once\n * `next()` was called a hook throw is only logged; a hook that never called it fails the attempt.\n */\nexport async function runDispatch(params: RunDispatchParams): Promise<void> {\n const { request, hooks, ctx, send, logger } = params;\n\n if (hooks.length === 0) return send();\n\n const provider = createOnceAsync(send);\n\n const runLayer = async (index: number): Promise<void> => {\n if (index === hooks.length) return provider.call();\n\n const { entry, label } = hooks[index]!;\n const inner = createOnceAsync(() => runLayer(index + 1));\n let hookFailure: { error: unknown } | undefined;\n\n try {\n await entry.dispatch(structuredClone(request), inner.call, withOwn(ctx, entry, label));\n } catch (error) {\n hookFailure = { error };\n }\n\n if (!inner.wasCalled()) {\n if (hookFailure) throw reclassifyMiddlewareThrow(hookFailure.error, label, ctx.signal);\n\n throw new LLMError(\n `middleware \"${label}\".dispatch returned without calling next(), so no request was sent`,\n 'invalid_params',\n { code: 'middleware_threw' },\n );\n }\n\n try {\n await inner.call();\n } catch (error) {\n // A hook rethrowing the provider's own error is the normal path, not a hook bug.\n if (hookFailure && hookFailure.error !== error) {\n logHookError(logger, `middleware \"${label}\".dispatch`, hookFailure.error);\n }\n throw error;\n }\n\n if (hookFailure) logHookError(logger, `middleware \"${label}\".dispatch`, hookFailure.error);\n };\n\n return runLayer(0);\n}\n\n/**\n * A middleware throw keeps any classification `normalizeError` recognizes. Only an unrecognizable\n * one becomes `invalid_params`.\n */\nexport function reclassifyMiddlewareThrow(\n error: unknown,\n label: string,\n signal?: AbortSignal,\n): LLMError {\n const normalized = normalizeError(error, signal);\n\n if (normalized.type !== 'unknown') {\n return normalized;\n }\n\n return new LLMError(`middleware \"${label}\" threw: ${normalized.message}`, 'invalid_params', {\n code: 'middleware_threw',\n cause: error,\n });\n}\n\n/**\n * Reports `event` through the instance-level reporter, then fans it out to every applicable\n * middleware's own `onEvent`. Never throws or rejects.\n *\n * Handlers of entries with a static (or absent) `enabled` run synchronously, in registration\n * order, before this returns. Emit sites sit on the call path, so a token attribute or a span\n * ended off a `usage` event is visible before the code after `next()` resumes.\n */\nexport function emitEvent(\n event: VernLLMEvent,\n ctx: MiddlewareContext,\n reportEventInstance: (event: VernLLMEvent) => void,\n middleware: VernLLMMiddleware[],\n middlewareTimeoutMs: number,\n logger: Logger,\n): void {\n const stamped = withCallContext(event, ctx);\n\n reportEventInstance(stamped);\n\n if (middleware.length === 0) return;\n\n dispatchEventToMiddleware(middleware, stamped, ctx, middlewareTimeoutMs, logger);\n}\n\n/**\n * `event` with the call's `context` on it, and on its `usage` too, so `onUsage` and a cost\n * middleware see which tenant spent the tokens, plus the `chain` it came from. Stamped here, the\n * one place every event passes through. An event with no call behind it, like a manual\n * `openCircuit()`'s, carries none.\n */\nfunction withCallContext(event: VernLLMEvent, ctx: MiddlewareContext): VernLLMEvent {\n const { context, chain } = ctx;\n\n if (context === undefined && chain === undefined) return event;\n\n const fields = {\n ...(context === undefined ? {} : { context }),\n ...(chain === undefined ? {} : { chain }),\n };\n\n if (context !== undefined && (event.kind === 'usage' || event.kind === 'usage_failure')) {\n return { ...event, ...fields, usage: { ...event.usage, context } };\n }\n\n return { ...event, ...fields };\n}\n\n/** Calls `onEvent`, logging a sync throw or a rejection instead of propagating either. */\nfunction invokeOnEvent(\n entry: VernLLMMiddleware,\n label: string,\n event: VernLLMEvent,\n ctx: MiddlewareContext,\n logger: Logger,\n): void {\n try {\n void Promise.resolve(entry.onEvent!(event, withOwn(ctx, entry, label))).catch(\n (error: unknown) => {\n logHookError(logger, `middleware \"${label}\".onEvent`, error);\n },\n );\n } catch (error) {\n logHookError(logger, `middleware \"${label}\".onEvent`, error);\n }\n}\n\n/**\n * Calls `onEvent` on every enabled middleware. A function `enabled` resolves per entry, so it never\n * holds back the others.\n */\nfunction dispatchEventToMiddleware(\n middleware: VernLLMMiddleware[],\n event: VernLLMEvent,\n ctx: MiddlewareContext,\n middlewareTimeoutMs: number,\n logger: Logger,\n): void {\n for (let index = 0; index < middleware.length; index++) {\n const entry = middleware[index]!;\n if (!entry.onEvent) continue;\n\n const label = middlewareLabel(entry, index);\n const { enabled } = entry;\n\n if (enabled === undefined || enabled === true) {\n invokeOnEvent(entry, label, event, ctx, logger);\n } else if (enabled === false) {\n continue;\n } else {\n void resolveEnabled(entry, ctx, label, middlewareTimeoutMs, logger).then((isEnabled) => {\n if (isEnabled) invokeOnEvent(entry, label, event, ctx, logger);\n });\n }\n }\n}\n\n/**\n * Every entry with a `dispatch`, in `order` (outermost first), labeled by its\n * `transformOrder` position so an unnamed entry reads the same as in\n * `registeredMiddlewareNames` whatever `position` it pins.\n */\nexport function buildDispatchHooks(\n transformOrder: VernLLMMiddleware[],\n order: VernLLMMiddleware[] = transformOrder,\n): readonly DispatchHook[] {\n const indexByEntry = new Map(transformOrder.map((entry, index) => [entry, index]));\n\n return order.flatMap((entry) =>\n entry.dispatch\n ? [\n {\n entry: entry as DispatchHook['entry'],\n label: middlewareLabel(entry, indexByEntry.get(entry)!),\n },\n ]\n : [],\n );\n}\n","import { normalizeError } from '../errors.utils.js';\n\nimport type { RateLimiterAdapter, RateLimitReason, WireRequest } from '../../../../rateLimit.js';\nimport type { LLMError } from '../../../../types/errors.js';\n\n/**\n * Errors thrown while acquiring limiter capacity. Tracked by identity\n * rather than a new error code, so the error's own `type`, `code`, and\n * retry behaviour stay exactly what the limiter produced.\n */\nconst limiterFailures = new WeakSet<LLMError>();\n\n/**\n * Whether `error` came from the limiter. Never counts toward the breaker, since no request was\n * made; a shared limiter losing its store would otherwise open a healthy provider's circuit.\n */\nexport function isLimiterFailure(error: LLMError): boolean {\n return limiterFailures.has(error);\n}\n\n/** Reports the `'rate_limited'` trace event; called only when `acquireRateLimit` actually waited. */\nexport type RateLimitedEventReporter = (waitedMs: number, reason: RateLimitReason) => void;\n\n/**\n * Acquires capacity for one attempt, reporting `'rate_limited'` when it had to wait. Returns `{}`\n * without a limiter. Run `release` in a `finally`. A limiter failure is normalized and marked so it\n * never counts toward the breaker.\n */\nexport async function acquireRateLimit(\n limiter: RateLimiterAdapter | undefined,\n request: WireRequest,\n signal: AbortSignal | undefined,\n onRateLimited: RateLimitedEventReporter,\n): Promise<{ release?: (actualTokens?: number, success?: boolean) => void }> {\n if (!limiter) return {};\n\n let acquired;\n\n try {\n acquired = await limiter.acquire(limiter.estimate(request), signal);\n } catch (error) {\n const normalized = normalizeError(error, signal);\n limiterFailures.add(normalized);\n throw normalized;\n }\n\n if (acquired.waitedMs > 0) {\n onRateLimited(acquired.waitedMs, acquired.reason ?? 'rpm');\n }\n\n return { release: acquired.release };\n}\n","import { toRequestSnapshot, type LLMRequestSnapshot } from '../../../../types/errors.js';\nimport { createMiddlewareStateBag } from '../../../../types/middleware.js';\nimport {\n applyMiddlewareTransforms,\n emitEvent,\n runDispatch,\n type DispatchHook,\n} from '../middleware/middleware.utils.js';\nimport { acquireRateLimit } from './rateLimitDispatch.utils.js';\n\nimport type { Logger } from '../../../../logger.js';\nimport type { RateLimiterAdapter } from '../../../../rateLimit.js';\nimport type {\n CallParams,\n MiddlewareStateBag,\n VernLLMEvent,\n VernLLMMiddleware,\n WireCallRequest,\n} from '../../../../types/index.js';\nimport type { BreakerGateway } from '../../circuitBreakerContext.js';\nimport type { RequestBuilder } from '../../requestBuilder.js';\n\n/** Receives a snapshot of the built request, just before dispatch. */\nexport type OnRequest = (snapshot: LLMRequestSnapshot) => void;\n\n/** Everything `prepareAttempt` needs beyond the per-attempt request params. */\nexport interface PrepareAttemptParams<T> {\n params: CallParams<T>;\n requestId: string;\n attempt: number;\n onRequest: OnRequest | undefined;\n middlewareState: MiddlewareStateBag | undefined;\n gateway: BreakerGateway;\n requestBuilder: RequestBuilder;\n providerName: string;\n limiter: RateLimiterAdapter | undefined;\n middleware: VernLLMMiddleware[];\n /** Every entry with a `dispatch`, outermost first. Filtered per attempt by `enabled`. */\n dispatchHooks: readonly DispatchHook[];\n middlewareTimeoutMs: number;\n logger: Logger;\n reportEvent: (event: VernLLMEvent) => void;\n}\n\n/** Everything one dispatched attempt needs before it proceeds, shared by the non-streaming and streaming paths. */\nexport interface PreparedAttempt {\n request: WireCallRequest;\n model: string;\n useJson: boolean;\n state: MiddlewareStateBag;\n /**\n * Present unless no `limiter` was configured. Must run in a `finally`\n * block so a slot is never leaked on a failed attempt (see `acquireRateLimit`).\n */\n release?: (actualTokens?: number, success?: boolean) => void;\n /**\n * Runs `send`, the provider request, inside this attempt's enabled\n * `dispatch` hooks. Settles with `send`'s own outcome, see `runDispatch`.\n */\n dispatch: (send: () => Promise<void>) => Promise<void>;\n}\n\n/**\n * Shared start of both attempt paths: build the request, run `transform`s, snapshot it through\n * `onRequest`, and acquire rate limit capacity.\n */\nexport async function prepareAttempt<T>(p: PrepareAttemptParams<T>): Promise<PreparedAttempt> {\n const {\n params,\n requestId,\n attempt,\n onRequest,\n middlewareState,\n gateway,\n requestBuilder,\n providerName,\n limiter,\n middleware,\n dispatchHooks,\n middlewareTimeoutMs,\n logger,\n reportEvent,\n } = p;\n\n const state = middlewareState ?? createMiddlewareStateBag();\n const built = requestBuilder.build(params);\n const { useJson, model } = built;\n const enabledEntries = new Set<VernLLMMiddleware>();\n\n const request = await applyMiddlewareTransforms({\n request: built.request,\n requestId,\n attempt,\n signal: params.signal,\n state,\n middleware,\n middlewareTimeoutMs,\n logger,\n reportEvent,\n buildContext: (attempt, signal, state) => gateway.buildAttemptContext(attempt, signal, state),\n enabledEntries,\n });\n\n onRequest?.(toRequestSnapshot(providerName, model, request, undefined, Date.now()));\n\n const { release } = await acquireRateLimit(\n limiter,\n request,\n params.signal,\n (waitedMs, reason) => {\n emitEvent(\n {\n kind: 'rate_limited',\n requestId,\n provider: providerName,\n model,\n waitedMs,\n reason,\n },\n gateway.buildAttemptContext(attempt, params.signal, state),\n reportEvent,\n middleware,\n middlewareTimeoutMs,\n logger,\n );\n },\n );\n\n const hooks = dispatchHooks.filter((hook) => enabledEntries.has(hook.entry));\n\n const dispatch = (send: () => Promise<void>): Promise<void> =>\n runDispatch({\n request,\n hooks,\n ctx: gateway.buildAttemptContext(attempt, params.signal, state),\n send,\n logger,\n });\n\n return { request, model, useJson, state, release, dispatch };\n}\n","import { prepareAttempt, type OnRequest } from '../utils/dispatch/attemptDispatch.utils.js';\nimport { isLimiterFailure } from '../utils/dispatch/rateLimitDispatch.utils.js';\n\nimport type { Logger } from '../../../logger.js';\nimport type { RateLimiterAdapter } from '../../../rateLimit.js';\nimport type { LLMError } from '../../../types/errors.js';\nimport type {\n CallParams,\n DetectSoftFailure,\n FinishReason,\n LLMClient,\n MiddlewareStateBag,\n VernLLMEvent,\n VernLLMMiddleware,\n} from '../../../types/index.js';\nimport type { BreakerGateway } from '../circuitBreakerContext.js';\nimport type { RequestBuilder } from '../requestBuilder.js';\nimport type { FinalizeResponseDeps } from '../responseFinalizer.js';\nimport type { UsageReporter } from '../usageReporter.js';\nimport type { DispatchHook } from '../utils/middleware/middleware.utils.js';\n\n/** One target's fixed settings for a single attempt, built once per `CallExecutor`. */\nexport interface AttemptEnvironment {\n client: LLMClient;\n providerName: string;\n isFallback: boolean;\n timeoutMs: number;\n chunkIdleTimeoutMs: number;\n readerStallTimeoutMs?: number;\n maxRetryAfterMs: number;\n parseJson: (content: string) => unknown;\n logger: Logger;\n redact?: (text: string) => string;\n usageReporter: UsageReporter;\n reportEvent: (event: VernLLMEvent) => void;\n limiter?: RateLimiterAdapter;\n requestBuilder: RequestBuilder;\n middleware: VernLLMMiddleware[];\n dispatchHooks: readonly DispatchHook[];\n middlewareTimeoutMs: number;\n detectSoftFailure?: DetectSoftFailure;\n}\n\n/** What changes from one attempt to the next. */\nexport interface AttemptArgs<T> {\n params: CallParams<T>;\n requestId: string;\n attempt: number;\n onRequest: OnRequest | undefined;\n middlewareState: MiddlewareStateBag | undefined;\n gateway: BreakerGateway;\n /** Called with the finish reason once this attempt returns a value. A failed attempt never calls it. */\n onFinish?: (reason: FinishReason | undefined) => void;\n}\n\nexport function prepareTargetAttempt<T>(env: AttemptEnvironment, args: AttemptArgs<T>) {\n return prepareAttempt({\n ...args,\n requestBuilder: env.requestBuilder,\n providerName: env.providerName,\n limiter: env.limiter,\n middleware: env.middleware,\n dispatchHooks: env.dispatchHooks,\n middlewareTimeoutMs: env.middlewareTimeoutMs,\n logger: env.logger,\n reportEvent: env.reportEvent,\n });\n}\n\nexport function redactText(env: AttemptEnvironment, text: string): string {\n return env.redact ? env.redact(text) : text;\n}\n\nexport function finalizeDependencies(\n env: AttemptEnvironment,\n gateway: BreakerGateway,\n model: string,\n): FinalizeResponseDeps {\n return {\n gateway,\n usageReporter: env.usageReporter,\n logger: env.logger,\n redactText: (text) => redactText(env, text),\n parseJson: env.parseJson,\n detectSoftFailure: env.detectSoftFailure,\n providerName: env.providerName,\n isFallback: env.isFallback,\n model,\n };\n}\n\n/**\n * Whether a failed attempt counts toward the breaker. Response defects, caller\n * mistakes, quota rejections and anything the limiter threw say nothing about\n * provider health, so they are excluded.\n */\nexport function countsTowardBreaker(error: LLMError): boolean {\n return error.countsTowardBreaker && !isLimiterFailure(error);\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 { parseWireToolCalls } from '../wire.utils.js';\n\nimport type { Logger } from '../../../../logger.js';\nimport type {\n CallParams,\n CallWithToolsResult,\n ToolIssue,\n WireToolCall,\n} from '../../../../types/index.js';\n\n/** Parses response content as JSON and validates it against `schema` when supplied. */\nexport function parseAndValidate<T>(\n content: string,\n schema: CallParams<T>['schema'] | undefined,\n parseJson: (content: string) => unknown,\n): T {\n let parsed: unknown;\n\n try {\n parsed = 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 * Checks each `ToolCall` against the offered tools, then runs each `argumentsSchema`. Unknown names\n * and duplicate ids are collected into one `validation` error with every issue, since retrying\n * can't fix them. A schema failure keeps its own single error. Returns the calls with `arguments`\n * replaced by the schema output; the input is left untouched.\n */\nexport function validateToolCallArguments<\n Call extends { id: string; name: string; arguments: unknown },\n>(toolCalls: Call[], tools: NonNullable<CallParams<unknown>['tools']>): Call[] {\n const known = new Map(tools.map((tool) => [tool.name, tool]));\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((issue) => issue.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 return toolCalls.map((call) => {\n const definition = known.get(call.name);\n\n if (!definition?.argumentsSchema) return call;\n\n const result = definition.argumentsSchema.safeParse(call.arguments);\n\n if (!result.success) {\n throw new LLMError(`Arguments for tool call \"${call.name}\" failed validation`, 'validation', {\n issues: result.error,\n });\n }\n\n return { ...call, arguments: result.data };\n });\n}\n\n/** A refusal with no content. Never retried. The refusal text is left out, as it can echo the prompt. */\nexport function refusalError(): LLMError {\n return new LLMError('The model refused the request', 'invalid_params', {\n code: 'model_refused',\n });\n}\n\n/** Everything `shapeResponse` needs beyond the raw response itself. */\nexport interface ShapeResponseParams<T> {\n rawContent: string | null | undefined;\n wireToolCalls: WireToolCall[] | undefined;\n /** The provider's refusal. Only read when there is no content and no tool call. */\n refusal?: string | null;\n params: CallParams<T>;\n useJson: boolean;\n parseJson: (content: string) => unknown;\n requestId: string;\n logger: Pick<Logger, 'debug'>;\n redactText: (text: string) => string;\n}\n\n/**\n * Shapes a complete response into `T` or a `CallWithToolsResult<T>`, for streaming too once the\n * stream is buffered. Throws on an empty response, a tool contract violation, or a JSON or schema\n * failure. Reporting happens a layer up.\n */\nexport function shapeResponse<T>(params: ShapeResponseParams<T>): T | CallWithToolsResult<T> {\n const {\n rawContent,\n wireToolCalls,\n refusal,\n params: callParams,\n useJson,\n parseJson,\n requestId,\n logger,\n redactText,\n } = params;\n\n // `.trim()` runs unguarded: a malformed response shape (e.g. a\n // non-string `content`) throws here, same as every other post-response\n // failure, and is normalized by the caller.\n const content = rawContent?.trim();\n\n if (!content && !wireToolCalls?.length) {\n if (refusal) throw refusalError();\n\n throw new LLMError('Empty LLM response', 'api', { code: 'empty_response' });\n }\n\n // wireToolCalls is guaranteed to have at least one entry whenever content\n // is falsy: the throw above only lets us reach this line when content ||\n // wireToolCalls?.length is true (De Morgan's law on that guard), so if\n // content is falsy, wireToolCalls?.length must be truthy.\n const debugOutput = redactText(content ?? `[${wireToolCalls!.length} tool call(s)]`);\n const truncated = debugOutput.length > 800;\n\n logger.debug(\n `[VernLLM:${requestId}] output:\\n` +\n debugOutput.slice(0, 800) +\n (truncated ? `... (truncated, ${debugOutput.length} chars total)` : ''),\n );\n\n if (wireToolCalls?.length) {\n if (!callParams.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 (callParams.toolChoice === 'none') {\n // Returning tool calls under `toolChoice: 'none'` would break the `ContentResult<T>` type\n // guarantee. The same request repeats it, so it is a non-retryable contract violation.\n throw new LLMError(\"Provider returned tool_calls despite toolChoice: 'none'.\", 'validation', {\n code: 'tool_choice_none_violated',\n });\n }\n\n const toolCalls = validateToolCallArguments(\n parseWireToolCalls(wireToolCalls),\n callParams.tools,\n );\n\n return { type: 'tool_calls', toolCalls, ...(content ? { content } : {}) };\n }\n\n // No tool_calls here, so content must be present: the empty-response\n // guard above throws unless content is truthy when wireToolCalls is\n // empty, so the `?? ''` fallback here is defensive only.\n /* v8 ignore next */\n const textContent = content ?? '';\n\n if (!useJson) {\n return callParams.tools ? { type: 'content', content: textContent as T } : (textContent as T);\n }\n\n const result = parseAndValidate<T>(textContent, callParams.schema, parseJson);\n\n return callParams.tools ? { type: 'content', content: result } : result;\n}\n","import { LLMError } from '../../types/errors.js';\nimport { isToolCallResult } from '../../types/tools.js';\nimport { normalizeError } from './utils/errors.utils.js';\nimport { shapeResponse } from './utils/response/responseShape.utils.js';\n\nimport type { Logger } from '../../logger.js';\nimport type {\n CallParams,\n CallWithToolsResult,\n DetectSoftFailure,\n MiddlewareStateBag,\n ThinkingBlock,\n TokenUsage,\n WireToolCall,\n} from '../../types/index.js';\nimport type { BreakerGateway } from './circuitBreakerContext.js';\nimport type { UsageReporter } from './usageReporter.js';\n\n/** Everything `finalizeResponse` needs beyond the raw response and outcome trackers. */\nexport interface FinalizeResponseDeps {\n gateway: BreakerGateway;\n usageReporter: UsageReporter;\n logger: Pick<Logger, 'debug' | 'warn'>;\n redactText: (text: string) => string;\n parseJson: (content: string) => unknown;\n /** See `VernLLMOptions.detectSoftFailure`. Absent when no hook was configured. */\n detectSoftFailure?: DetectSoftFailure;\n providerName: string;\n isFallback: boolean;\n /** The resolved model this attempt actually targeted. */\n model: string;\n}\n\n/**\n * Shapes a complete response and reports the outcome: breaker and usage success when clean, a usage\n * failure otherwise. Breaker failures are decided a layer up, once retries run out.\n * `detectSoftFailure` runs inside the same `try`, so a soft failure takes the normal failure path.\n * With `truncated` set, a parse failure becomes the retryable `response_truncated`. `thinking` is\n * kept only on a tool call result, the one place it must go back.\n */\nexport function finalizeResponse<T>(\n rawContent: string | null | undefined,\n wireToolCalls: WireToolCall[] | undefined,\n params: CallParams<T>,\n useJson: boolean,\n usage: TokenUsage | undefined,\n requestId: string,\n attempt: number,\n state: MiddlewareStateBag,\n deps: FinalizeResponseDeps,\n truncated = false,\n thinking?: ThinkingBlock[],\n refusal?: string | null,\n): T | CallWithToolsResult<T> {\n const { gateway, usageReporter, logger, redactText, parseJson, detectSoftFailure } = deps;\n\n try {\n const result = withThinking(\n shapeResponse<T>({\n rawContent,\n wireToolCalls,\n refusal,\n params,\n useJson,\n parseJson,\n requestId,\n logger,\n redactText,\n }),\n thinking,\n );\n\n const softFailureCode = detectSoftFailureSafely(\n detectSoftFailure,\n result,\n {\n requestId,\n model: deps.model,\n providerName: deps.providerName,\n isFallback: deps.isFallback,\n attempt: attempt + 1,\n usage,\n },\n logger,\n );\n\n if (softFailureCode !== undefined) {\n // `'api'`, not `'validation'`, which is never retried whatever the code. The returned code\n // alone decides retry and breaker counting.\n throw new LLMError('Soft failure detected', 'api', { code: softFailureCode });\n }\n\n gateway.recordSuccess(attempt, params.signal, state);\n usageReporter.reportSuccess(usage, gateway.buildAttemptContext(attempt, params.signal, state));\n\n return result;\n } catch (error) {\n // Normalized first so `onUsageFailure` gets an `LLMError`, including for aborts. A soft failure\n // is already one and is reported once, here.\n const normalized = asTruncationError(normalizeError(error, params.signal), truncated);\n\n if (usage && normalized.type !== 'aborted') {\n usageReporter.reportFailure(\n usage,\n normalized,\n attempt,\n gateway.buildAttemptContext(attempt, params.signal, state),\n );\n }\n\n throw normalized;\n }\n}\n\n/** Adds `thinking` to a tool call result. Any other result is returned as is. */\nfunction withThinking<T>(\n result: T | CallWithToolsResult<T>,\n thinking: ThinkingBlock[] | undefined,\n): T | CallWithToolsResult<T> {\n if (!thinking?.length || !isToolCallResult(result)) return result;\n\n return { ...result, thinking };\n}\n\n/**\n * Replaces a parse failure on output that was cut off at `max_tokens`\n * with a `response_truncated` error, keeping the original as `cause`.\n * Anything else, or a response that wasn't cut off, passes through.\n */\nfunction asTruncationError(error: LLMError, truncated: boolean): LLMError {\n if (!truncated || error.type !== 'parse') return error;\n\n return new LLMError(\n `Response was cut off at max_tokens before it could be parsed: ${error.message}`,\n 'parse',\n { code: 'response_truncated', cause: error },\n );\n}\n\n/**\n * Runs `detectSoftFailure` and returns its code. A throwing hook is logged and ignored, so it can't\n * fail every call.\n */\nfunction detectSoftFailureSafely<T>(\n detectSoftFailure: DetectSoftFailure | undefined,\n result: T | CallWithToolsResult<T>,\n meta: Parameters<DetectSoftFailure>[1],\n logger: Pick<Logger, 'warn'>,\n) {\n if (!detectSoftFailure) return undefined;\n\n try {\n return detectSoftFailure(result, meta);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const stack = error instanceof Error && error.stack ? `\\n${error.stack}` : '';\n logger.warn(\n `[VernLLM] detectSoftFailure threw and was ignored, treated as no soft failure: ${message}${stack}`,\n );\n return undefined;\n }\n}\n","import type { FinishReason } from '../../../../types/index.js';\n\nconst KNOWN: ReadonlySet<string> = new Set<FinishReason>([\n 'stop',\n 'length',\n 'tool_calls',\n 'refusal',\n 'guardrail',\n 'content_filter',\n 'other',\n]);\n\n/**\n * Maps a wire `finish_reason` onto `FinishReason`. Adapters send the shared names, and OpenAI's\n * own values are the same apart from the legacy `function_call`. A provider refusal that came back\n * with a plain stop is reported as `'refusal'`.\n */\nexport function toFinishReason(\n reason: string | null | undefined,\n refused = false,\n): FinishReason | undefined {\n const mapped = !reason ? undefined : reason === 'function_call' ? 'tool_calls' : reason;\n const known =\n mapped === undefined ? undefined : KNOWN.has(mapped) ? (mapped as FinishReason) : 'other';\n\n return refused && (known === undefined || known === 'stop') ? 'refusal' : known;\n}\n","import { redactResponseBody } from '../../utils/errors/responseBody.utils.js';\nimport { extractStatus, normalizeError } from '../utils/errors.utils.js';\n\nimport type { RateLimiterAdapter } from '../../../rateLimit.js';\nimport type { AttemptEnvironment } from './attemptEnvironment.js';\n\n/** Tells the limiter about a provider 429 so AIMD can shrink. */\nexport function reactToRateLimitError(\n limiter: RateLimiterAdapter | undefined,\n error: unknown,\n): void {\n if (!limiter) return;\n if (extractStatus(error) !== 429) return;\n limiter.signalRateLimit();\n}\n\n/**\n * Runs `send` inside the attempt's `dispatch` hooks. A provider failure is\n * redacted and reported to the limiter, and hooks see it normalized. The raw\n * error is rethrown afterwards, not the `LLMError` hooks saw, since retry\n * timing reads `Retry-After` off it. Anything else, such as a hook that never\n * sent the request, is thrown as is.\n */\nexport async function dispatchToProvider(\n env: AttemptEnvironment,\n dispatch: (send: () => Promise<void>) => Promise<void>,\n signal: AbortSignal | undefined,\n send: () => Promise<void>,\n): Promise<void> {\n let providerFailure: { error: unknown } | undefined;\n\n try {\n await dispatch(async () => {\n try {\n await send();\n } catch (error) {\n if (env.redact) redactResponseBody(error, env.redact);\n reactToRateLimitError(env.limiter, error);\n providerFailure = { error };\n throw normalizeError(error, signal, undefined, env.maxRetryAfterMs);\n }\n });\n } catch (error) {\n throw providerFailure ? providerFailure.error : error;\n }\n}\n","import { readRateLimitHint } from '../../utils/rate-limit/rateLimitHint.utils.js';\nimport { finalizeResponse } from '../responseFinalizer.js';\nimport { toFinishReason } from '../utils/response/finishReason.utils.js';\nimport { withTimeout } from '../utils/retry/retry.utils.js';\nimport {\n finalizeDependencies,\n prepareTargetAttempt,\n type AttemptArgs,\n type AttemptEnvironment,\n} from './attemptEnvironment.js';\nimport { dispatchToProvider } from './providerDispatch.js';\n\nimport type { CallWithToolsResult, LLMClient } from '../../../types/index.js';\n\n/**\n * One non-streaming attempt: acquire, dispatch with a timeout, then shape the\n * response. Capacity is acquired per attempt, since a retry is a real request.\n */\nexport async function executeCall<T>(\n env: AttemptEnvironment,\n args: AttemptArgs<T>,\n): Promise<T | CallWithToolsResult<T>> {\n const { params, requestId, attempt, gateway } = args;\n const {\n request,\n model,\n useJson,\n state,\n release: acquiredRelease,\n dispatch,\n } = await prepareTargetAttempt(env, args);\n let release = acquiredRelease;\n\n try {\n let response!: Awaited<ReturnType<LLMClient['chat']['completions']['create']>>;\n\n await dispatchToProvider(env, dispatch, params.signal, async () => {\n response = await withTimeout(\n (attemptSignal) => env.client.chat.completions.create(request, { signal: attemptSignal }),\n env.timeoutMs,\n params.signal,\n );\n });\n\n // AIMD's proactive path.\n env.limiter?.reactToRateLimitHint(readRateLimitHint(response));\n\n // Taken before anything else touches the response, so a later failure\n // still reports usage.\n const usage = env.usageReporter.extract(response, requestId, model);\n const actualTokens = env.usageReporter.actualTokensFor(usage);\n\n // Raw on purpose: extraction happens inside `finalizeResponse`'s\n // try/catch, so a malformed response is still normalized.\n const choice = response.choices?.[0];\n const rawContent = choice?.message?.content;\n const wireToolCalls = choice?.message?.tool_calls;\n const truncated = choice?.finish_reason === 'length';\n const thinking = choice?.message?.thinking;\n const refusal = choice?.message?.refusal;\n const finishReason = toFinishReason(choice?.finish_reason, Boolean(refusal));\n\n let finalized: T | CallWithToolsResult<T>;\n\n try {\n finalized = finalizeResponse(\n rawContent,\n wireToolCalls,\n params,\n useJson,\n usage,\n requestId,\n attempt,\n state,\n finalizeDependencies(env, gateway, model),\n truncated,\n thinking,\n refusal,\n );\n } catch (error) {\n // Reconcile usage and free the slot, but never grow AIMD for a\n // response VernLLM itself rejected.\n release?.(actualTokens);\n release = undefined;\n throw error;\n }\n\n release?.(actualTokens, true);\n release = undefined;\n args.onFinish?.(finishReason);\n\n return finalized;\n } finally {\n // Only reached with a live release when dispatch itself threw.\n release?.();\n }\n}\n","import { clampTimeoutMs, resolveActiveTimeoutMs } from '../retry/retry.utils.js';\n\nimport type { Logger } from '../../../../logger.js';\n\n/** Everything `createBackpressureChannel` needs. Generic over the item type: no knowledge of `StreamChunk`. */\nexport interface BackpressureChannelOptions {\n /**\n * Cap on buffered items while nothing is pulling. The buffer grows to twice this before trimming\n * in one batch, keeping eviction cheap per push.\n */\n capacity: number;\n logger: Pick<Logger, 'warn'>;\n /**\n * Folded into the eviction warning so different channels are\n * distinguishable in logs, e.g. `'stream chunk'`.\n */\n label: string;\n /**\n * How long a reader may hold the producer back on a full buffer before\n * it is detached. `0`, negative, NaN, or `Infinity` waits forever.\n */\n stallTimeoutMs?: number;\n /** What a detached reader's next pull rejects with. Required for `stallTimeoutMs` to apply. */\n stallError?: () => unknown;\n}\n\n/** A push/pull async channel with a bounded buffer, returned by `createBackpressureChannel`. */\nexport interface BackpressureChannel<T> {\n /**\n * Delivers `value` to a waiting puller, or buffers it. Returns a promise\n * when a consumer is reading and the buffer is full; the producer should\n * await it before pushing more. Returns `undefined` otherwise.\n */\n push(value: T): Promise<void> | undefined;\n /** Marks the channel done. Every future pull resolves `{ done: true }`. */\n finish(): void;\n /** Marks the channel failed. Every future pull rejects with `error`. */\n fail(error: unknown): void;\n /** Consumed by callers to pull values as they arrive. */\n iterable: AsyncIterable<T>;\n}\n\n/**\n * A bounded push channel whose producer runs whether or not anyone reads. Buffer size caps memory,\n * since the producer can outrace the first read. Once a reader starts, a full buffer holds the\n * producer back instead of evicting, so a slow reader never loses items; eviction only applies\n * while no reader is active.\n */\nexport function createBackpressureChannel<T>(\n options: BackpressureChannelOptions,\n): BackpressureChannel<T> {\n const { capacity, logger, label, stallError } = options;\n const stallTimeoutMs = stallError ? resolveActiveTimeoutMs(options.stallTimeoutMs) : undefined;\n\n const buffered: T[] = [];\n // `owner` ties a pull to the iterator that made it, so one reader's\n // `return()` only settles its own pull.\n const pending: Array<{\n owner: object;\n resolve: (result: IteratorResult<T>) => void;\n reject: (error: unknown) => void;\n }> = [];\n let done = false;\n let failed = false;\n let failure: unknown;\n let hasLoggedEviction = false;\n // Iterators that have pulled and not returned. A full buffer only holds\n // the producer back while there is one; otherwise the eviction path\n // below applies, so a reader that left can't stall the producer.\n let activeReaders = 0;\n let spaceWaiters: Array<() => void> = [];\n // Set once a reader held the producer back past `stallTimeoutMs`. From\n // then on every pull rejects with it and nothing is buffered, so the\n // producer runs to the end on its own instead of waiting forever.\n let stall: { error: unknown } | undefined;\n let stallTimer: ReturnType<typeof setTimeout> | undefined;\n\n function detachStalledReaders(): void {\n stallTimer = undefined;\n stall = { error: stallError!() };\n logger.warn(\n `[VernLLM] ${label} reader held a full buffer for ${stallTimeoutMs}ms; detaching it so the stream can finish.`,\n );\n buffered.length = 0;\n releaseProducer();\n }\n\n function releaseProducer(): void {\n clearTimeout(stallTimer);\n stallTimer = undefined;\n\n const waiters = spaceWaiters;\n\n spaceWaiters = [];\n for (const resolve of waiters) resolve();\n }\n\n function push(value: T): Promise<void> | undefined {\n if (stall) return undefined;\n\n const waiter = pending.shift();\n\n if (waiter) {\n waiter.resolve({ done: false, value });\n return undefined;\n }\n\n buffered.push(value);\n\n if (activeReaders > 0) {\n if (buffered.length < capacity) return undefined;\n\n if (stallTimeoutMs !== undefined && stallTimer === undefined) {\n stallTimer = setTimeout(detachStalledReaders, clampTimeoutMs(stallTimeoutMs));\n }\n\n return new Promise((resolve) => {\n spaceWaiters.push(resolve);\n });\n }\n\n if (buffered.length > capacity * 2) {\n // Nothing else surfaces this: without a log, a caller that never\n // read (or fell behind on) `iterable` has no way to tell eviction,\n // not a producer bug, is why items are missing. Logged once, not\n // on every crossing, so an ignored high-volume channel doesn't\n // spam dozens of near-identical lines.\n if (!hasLoggedEviction) {\n hasLoggedEviction = true;\n logger.warn(\n `[VernLLM] ${label} buffer exceeded cap (${capacity}), evicting ` +\n `${buffered.length - capacity} oldest item(s); buffered=${buffered.length}. ` +\n 'The iterable was never read (or fell far behind) for this channel.',\n );\n }\n\n // Trimmed in one batch once the buffer reaches twice the cap. A `shift()` per push is O(n)\n // every time and stalled for seconds in benchmarks; one `splice` per `capacity` pushes keeps\n // the cost O(1) on average.\n buffered.splice(0, buffered.length - capacity);\n }\n }\n\n function finish(): void {\n done = true;\n releaseProducer();\n\n for (const waiter of pending.splice(0)) {\n waiter.resolve({ done: true, value: undefined });\n }\n }\n\n function fail(error: unknown): void {\n done = true;\n failed = true;\n failure = error;\n releaseProducer();\n\n for (const waiter of pending.splice(0)) {\n waiter.reject(error);\n }\n }\n\n const iterable: AsyncIterable<T> = {\n [Symbol.asyncIterator]() {\n const owner = {};\n let active = false;\n\n return {\n next(): Promise<IteratorResult<T>> {\n if (!active) {\n active = true;\n activeReaders++;\n }\n\n if (stall) return Promise.reject(stall.error);\n\n if (buffered.length) {\n const value = buffered.shift() as T;\n\n if (buffered.length < capacity) releaseProducer();\n\n return Promise.resolve({ done: false, value });\n }\n\n if (done) {\n return failed\n ? Promise.reject(failure)\n : Promise.resolve({ done: true, value: undefined });\n }\n\n return new Promise((resolve, reject) => {\n pending.push({ owner, resolve, reject });\n });\n },\n // Detaches this reader without stopping the producer. Cancelling\n // on a `break` happens a layer up (see `onEarlyExit`), since only\n // the caller knows whether anyone else still needs the stream.\n return(): Promise<IteratorResult<T>> {\n if (active) {\n active = false;\n activeReaders--;\n }\n\n for (let i = pending.length - 1; i >= 0; i--) {\n if (pending[i]!.owner !== owner) continue;\n pending.splice(i, 1)[0]!.resolve({ done: true, value: undefined });\n }\n\n if (activeReaders === 0) releaseProducer();\n\n return Promise.resolve({ done: true, value: undefined });\n },\n };\n },\n };\n\n return { push, finish, fail, iterable };\n}\n","import { LLMError } from '../../../../types/errors.js';\n\nimport type { StreamChunk, WireToolCall } 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/** One incoming tool call delta, matching `WireStreamChunk`'s `tool_call_delta` variant. */\nexport interface ToolCallDelta {\n index: number;\n id?: string;\n name?: string;\n argumentsDelta?: string;\n complete?: boolean;\n}\n\n/** Accumulates streamed tool call deltas, returned by `createToolCallAccumulator`. */\nexport interface ToolCallAccumulator {\n /**\n * Folds one delta in and returns the matching `StreamChunk` to push\n * onward. Throws `LLMError('validation')` if the delta would push the\n * accumulator past its call count or argument length limit.\n */\n apply(delta: ToolCallDelta): StreamChunk;\n /** Shapes everything accumulated so far into wire tool calls, sorted by index. Undefined if nothing arrived. */\n toWireToolCalls(): WireToolCall[] | undefined;\n}\n\n/**\n * Tracks tool call deltas by index as they stream in, merging each\n * delta's `id`/`name`/`argumentsDelta` into a running entry. Pulled out\n * of `buildStreamResult` since it's self contained state with no\n * dependency on the iterator, the chunk buffer, or the final result\n * promise.\n */\nexport function createToolCallAccumulator(): ToolCallAccumulator {\n const entries = new Map<number, { id?: string; name?: string; args: string }>();\n\n function apply(delta: ToolCallDelta): StreamChunk {\n let entry = entries.get(delta.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 (entries.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 = delta.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 ??= delta.id;\n entry.name ??= delta.name;\n entry.args += argumentsDelta;\n entries.set(delta.index, entry);\n\n return {\n type: 'tool_call_delta',\n index: delta.index,\n id: delta.id,\n name: delta.name,\n argsDelta: delta.argumentsDelta,\n complete: delta.complete,\n };\n }\n\n function toWireToolCalls(): WireToolCall[] | undefined {\n if (!entries.size) return undefined;\n\n return [...entries.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 }\n\n return { apply, toWireToolCalls };\n}\n","import { toFinishReason } from '../response/finishReason.utils.js';\nimport { toTokenUsage, type TokenUsageMeta } from '../response/usage.utils.js';\nimport { createToolCallAccumulator } from './toolCallAccumulator.utils.js';\n\nimport type {\n FinishReason,\n StreamChunk,\n ThinkingBlock,\n TokenUsage,\n WireStreamChunk,\n WireToolCall,\n} from '../../../../types/index.js';\nimport type { ProviderRateLimitHint } from '../../../utils/rate-limit/rateLimitHint.utils.js';\n\nexport interface StreamAccumulation {\n /** Folds one wire chunk in. Returns the push's space promise when a chunk reached the caller. */\n apply: (chunk: WireStreamChunk) => Promise<void> | undefined;\n readonly usage: TokenUsage | undefined;\n /** What `finalize` receives once the stream ends. */\n result: () => {\n text: string;\n wireToolCalls: WireToolCall[] | undefined;\n usage: TokenUsage | undefined;\n thinking: ThinkingBlock[] | undefined;\n finishReason: FinishReason | undefined;\n };\n}\n\n/**\n * Collects text, tool calls, usage and thinking from wire chunks and forwards\n * caller visible chunks through `push`. Pings, hints and refusal chunks push nothing, and\n * thinking stays in the result only.\n */\nexport function createStreamAccumulation(\n usageMeta: TokenUsageMeta,\n push: (chunk: StreamChunk) => Promise<void> | undefined,\n onRateLimitHint?: (hint: ProviderRateLimitHint) => void,\n): StreamAccumulation {\n const toolCalls = createToolCallAccumulator();\n const thinking: ThinkingBlock[] = [];\n let text = '';\n let usage: TokenUsage | undefined;\n let finish: string | undefined;\n let refused = false;\n\n return {\n apply(chunk) {\n switch (chunk.type) {\n case 'rate_limit_hint':\n // Fired right away, not deferred to the end.\n onRateLimitHint?.(chunk.hint);\n return undefined;\n case 'text-delta':\n text += chunk.delta;\n return push({ type: 'text-delta', delta: chunk.delta });\n case 'tool_call_delta':\n return push(toolCalls.apply(chunk));\n case 'thinking_block':\n thinking.push(chunk.block);\n return undefined;\n case 'usage':\n usage = toTokenUsage(chunk.usage, usageMeta);\n return push({ type: 'usage', usage });\n case 'finish':\n finish = chunk.reason;\n return undefined;\n case 'refusal':\n refused = true;\n return undefined;\n default:\n // A ping only resets the idle clock on the next read.\n return undefined;\n }\n },\n get usage() {\n return usage;\n },\n result: () => ({\n text,\n wireToolCalls: toolCalls.toWireToolCalls(),\n usage,\n thinking: thinking.length ? thinking : undefined,\n finishReason: toFinishReason(finish, refused),\n }),\n };\n}\n","import { LLMError } from '../../types/errors.js';\nimport { createDeferred } from '../utils/deferred.utils.js';\nimport { normalizeError } from './utils/errors.utils.js';\nimport { withChunkIdleTimeout } from './utils/retry/retry.utils.js';\nimport { createBackpressureChannel } from './utils/stream/chunkBuffer.utils.js';\nimport { createStreamAccumulation } from './utils/stream/streamAccumulation.utils.js';\n\nimport type { Logger } from '../../logger.js';\nimport type {\n CallWithToolsResult,\n StreamChunk,\n FinishReason,\n ThinkingBlock,\n TokenUsage,\n WireStreamChunk,\n WireToolCall,\n} from '../../types/index.js';\nimport type { ProviderRateLimitHint } from '../utils/rate-limit/rateLimitHint.utils.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 /** See `VernLLMOptions.readerStallTimeoutMs`. Off when omitted. */\n readerStallTimeoutMs?: number;\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 /** The target's `maxRetryAfterMs`, forwarded to `normalizeError` so a mid-stream failure gets the same retry cap. */\n maxRetryAfterMs?: number;\n /**\n * Fires once when the transport loop ends cleanly, before `finalize`. Success itself is decided\n * by `finalize`, which can still reject the response.\n */\n onStreamSuccess: (usage: TokenUsage | undefined) => void;\n /** Fires once when the transport loop fails, before `finalResult` rejects. */\n onStreamFailure: (normalized: LLMError, usage: TokenUsage | undefined) => void;\n /**\n * Fires as soon as a `rate_limit_hint` arrives. Reacting to a hint is safe whatever the attempt's\n * outcome, unlike growing the ceiling.\n */\n onRateLimitHint?: (hint: ProviderRateLimitHint) => void;\n /**\n * Builds the final result once the stream completes. Its throws are already normalized and\n * reported, as with `finalizeResponse`.\n */\n finalize: (\n textAcc: string,\n wireToolCalls: WireToolCall[] | undefined,\n usage: TokenUsage | undefined,\n thinking: ThinkingBlock[] | undefined,\n finishReason: FinishReason | undefined,\n ) => T | CallWithToolsResult<T>;\n}\n\n/**\n * Cleanup after a throw while processing. Both layers run, since SDKs differ: `return()` closes a\n * stream that supports it, and `abort()` closes one that follows the signal. A cleanup failure is\n * swallowed.\n */\nasync function closeIterator(\n iterator: AsyncIterator<WireStreamChunk>,\n streamController: AbortController,\n): Promise<void> {\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\n/** Resolves once `space` does or any of `signals` aborts, whichever comes first. */\nfunction untilSpaceOrAbort(\n space: Promise<void>,\n signals: Array<AbortSignal | undefined>,\n): Promise<void> {\n const active = signals.filter((s): s is AbortSignal => s !== undefined);\n\n if (active.some((s) => s.aborted)) return Promise.resolve();\n\n return new Promise((resolve) => {\n const done = () => {\n for (const s of active) s.removeEventListener('abort', done);\n resolve();\n };\n\n for (const s of active) s.addEventListener('abort', done, { once: true });\n void space.then(done);\n });\n}\n\n/**\n * Pumps wire chunks to the caller as they arrive, with no total duration bound, and builds\n * `finalResult` when the stream ends. Transport errors are normalized and reported here; `finalize`\n * errors already were.\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 readerStallTimeoutMs,\n streamController,\n logger,\n signal,\n maxRetryAfterMs,\n onRateLimitHint,\n } = options;\n\n const {\n promise: finalResult,\n resolve: resolveFinal,\n reject: rejectFinal,\n } = createDeferred<T | CallWithToolsResult<T>>();\n\n // Avoid an unhandled-rejection warning for callers that only read `chunks`.\n finalResult.catch(() => {});\n\n // A push channel rather than a pulled generator, so the pump drives `finalResult` to completion\n // even if `chunks` is never read. The buffer size caps memory before a reader starts; once\n // reading, a full buffer pauses the pump. A reader that leaves early is detached and `call()`\n // aborts the stream.\n const MAX_BUFFERED_CHUNKS = 10_000;\n const channel = createBackpressureChannel<StreamChunk>({\n capacity: MAX_BUFFERED_CHUNKS,\n logger,\n label: 'stream chunk',\n stallTimeoutMs: readerStallTimeoutMs,\n stallError: () =>\n new LLMError(\n `The chunks reader stopped pulling for ${readerStallTimeoutMs}ms with a full buffer, so it was detached. finalResult still settles.`,\n 'timeout',\n { code: 'reader_stall_timeout' },\n ),\n });\n const { push, finish, fail } = channel;\n const chunks = channel.iterable;\n\n const accumulation = createStreamAccumulation(\n { requestId, model, providerName, isFallback },\n push,\n onRateLimitHint,\n );\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 space = accumulation.apply(result.value);\n\n // Waiting here, not inside `withChunkIdleTimeout`, so a slow reader\n // never counts as the provider going idle. An abort ends the wait, so\n // the `next()` below surfaces it even if nobody reads again.\n if (space) await untilSpaceOrAbort(space, [streamController.signal, signal]);\n\n // An adapter that ignores the signal would keep yielding, and the\n // call would still resolve after the caller cancelled it.\n if (signal?.aborted) throw new LLMError('LLM request aborted', 'aborted');\n\n result = await withChunkIdleTimeout(\n () => iterator.next(),\n chunkIdleTimeoutMs,\n () => streamController.abort(),\n logger,\n );\n }\n } catch (error) {\n await closeIterator(iterator, streamController);\n\n const normalized = normalizeError(error, signal, undefined, maxRetryAfterMs);\n\n try {\n options.onStreamFailure(normalized, accumulation.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(accumulation.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 { text, wireToolCalls, usage, thinking, finishReason } = accumulation.result();\n const finalized = options.finalize(text, wireToolCalls, usage, thinking, finishReason);\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 { LLMError } from '../../../types/errors.js';\nimport { finalizeResponse } from '../responseFinalizer.js';\nimport { buildStreamResult } from '../streamAccumulator.js';\nimport { normalizeError } from '../utils/errors.utils.js';\nimport { refusalError } from '../utils/response/responseShape.utils.js';\nimport { toTokenUsage } from '../utils/response/usage.utils.js';\nimport { withChunkIdleTimeout, withTimeout } from '../utils/retry/retry.utils.js';\nimport {\n countsTowardBreaker,\n finalizeDependencies,\n prepareTargetAttempt,\n type AttemptArgs,\n type AttemptEnvironment,\n} from './attemptEnvironment.js';\nimport { dispatchToProvider, reactToRateLimitError } from './providerDispatch.js';\n\nimport type { Logger } from '../../../logger.js';\nimport type { RateLimiterAdapter } from '../../../rateLimit.js';\nimport type { CallWithToolsResult, StreamChunk, WireStreamChunk } from '../../../types/index.js';\n\ntype WireUsageChunk = Extract<WireStreamChunk, { type: 'usage' }>['usage'];\n\n/**\n * Opens a stream for one attempt. The timeout covers `createStream` and the\n * first `next()` together, since a generator does no work until pulled.\n *\n * The attempt succeeds once the first content chunk arrives, so a failure\n * before that is retried and can fall back. A stream holds its connection for\n * its whole life, so capacity is released on completion, not on open.\n */\nexport async function executeStreamCall<T>(\n env: AttemptEnvironment,\n args: AttemptArgs<T>,\n onOpened?: () => void,\n): Promise<{\n chunks: AsyncIterable<StreamChunk>;\n finalResult: Promise<T | CallWithToolsResult<T>>;\n}> {\n const { params, requestId, attempt, gateway } = args;\n const completions = env.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 const {\n request,\n model,\n useJson,\n state,\n release: acquiredRelease,\n dispatch,\n } = await prepareTargetAttempt(env, args);\n let release = acquiredRelease;\n\n // One controller for the whole stream, threaded into the transport, so an\n // idle timeout mid-way also tears the connection down.\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 chunkIdleTimeoutMs = params.chunkIdleTimeoutMs ?? env.chunkIdleTimeoutMs;\n let opened!: {\n head: IteratorResult<WireStreamChunk>;\n rest: AsyncIterator<WireStreamChunk>;\n };\n\n await dispatchToProvider(env, dispatch, params.signal, async () => {\n const { iterator, first } = await withTimeout(\n async (attemptSignal) => {\n const streamIterator = createStream(request, { signal: attemptSignal })[\n Symbol.asyncIterator\n ]();\n let firstResult = await streamIterator.next();\n\n // A hint comes from headers, before any body. Counting it as the\n // open would skip retries and fallback on a failed first chunk.\n while (!firstResult.done && firstResult.value.type === 'rate_limit_hint') {\n env.limiter?.reactToRateLimitHint(firstResult.value.hint);\n firstResult = await streamIterator.next();\n }\n\n return { iterator: streamIterator, first: firstResult };\n },\n env.timeoutMs,\n combinedExternal,\n );\n\n // A ping counts as open, so a thinking phase longer than `timeoutMs`\n // only needs pings to stay open.\n if (!first.done) onOpened?.();\n\n // Until content arrives nothing has reached the caller, so a failure is\n // still an ordinary attempt failure. The idle timeout bounds the wait.\n // Read inside `dispatch`, so its hooks see the attempt settle where it\n // succeeds or fails, not at a keep-alive ping.\n opened = await readUntilContent(\n iterator,\n first,\n chunkIdleTimeoutMs,\n streamController,\n env.limiter,\n env.logger,\n (wireUsage, error) => {\n const usage = toTokenUsage(wireUsage, {\n requestId,\n model,\n providerName: env.providerName,\n isFallback: env.isFallback,\n });\n const normalized = normalizeError(error, params.signal, undefined, env.maxRetryAfterMs);\n\n if (normalized.type !== 'aborted') {\n env.usageReporter.reportFailure(\n usage,\n normalized,\n attempt,\n gateway.buildAttemptContext(attempt, params.signal, state),\n true,\n );\n }\n\n release?.(env.usageReporter.actualTokensFor(usage));\n release = undefined;\n },\n );\n });\n\n const { head, rest } = opened;\n\n // Same error as an empty non-streaming response, so retry treats both alike.\n if (head.done) {\n throw new LLMError('Empty LLM response', 'api');\n }\n\n // Snapshot: `release` is cleared below once ownership passes to the stream.\n const releaseAtOpen = release;\n\n const result = buildStreamResult(rest, head, {\n requestId,\n model,\n providerName: env.providerName,\n isFallback: env.isFallback,\n chunkIdleTimeoutMs,\n readerStallTimeoutMs: env.readerStallTimeoutMs,\n streamController,\n logger: env.logger,\n signal: params.signal,\n maxRetryAfterMs: env.maxRetryAfterMs,\n onRateLimitHint: (hint) => {\n env.limiter?.reactToRateLimitHint(hint);\n },\n onStreamSuccess: (_usage) => {\n // Nothing here: `finalize` decides success, since its shaping or\n // soft failure check can still reject the response.\n },\n onStreamFailure: (normalized, usage) => {\n // A 429 can also arrive after the stream opened.\n reactToRateLimitError(env.limiter, normalized);\n\n // Only an idle timeout trips the breaker mid-stream, or a provider\n // that hangs after one chunk would never open it.\n if (normalized.type === 'timeout') {\n gateway.recordFailure(attempt, params.signal, state, normalized.code);\n } else {\n gateway.releaseTrial(attempt, params.signal, state);\n }\n\n if (usage && normalized.type !== 'aborted') {\n env.usageReporter.reportFailure(\n usage,\n normalized,\n attempt,\n gateway.buildAttemptContext(attempt, params.signal, state),\n true,\n );\n }\n\n releaseAtOpen?.(env.usageReporter.actualTokensFor(usage));\n },\n finalize: (textAcc, wireToolCalls, usage, thinking, finishReason) => {\n const actualTokens = env.usageReporter.actualTokensFor(usage);\n\n try {\n const finalized = finalizeResponse(\n textAcc,\n wireToolCalls,\n params,\n useJson,\n usage,\n requestId,\n attempt,\n state,\n finalizeDependencies(env, gateway, model),\n finishReason === 'length',\n thinking,\n );\n\n releaseAtOpen?.(actualTokens, true);\n args.onFinish?.(finishReason);\n\n return finalized;\n } catch (error) {\n // Free the slot without growing AIMD for a rejected response.\n releaseAtOpen?.(actualTokens);\n\n // The retry loop already saw this attempt succeed when the stream\n // opened, so the breaker outcome is recorded here.\n if (error instanceof LLMError && countsTowardBreaker(error)) {\n gateway.recordFailure(attempt, params.signal, state, error.code);\n } else {\n gateway.releaseTrial(attempt, params.signal, state);\n }\n\n throw error;\n }\n },\n });\n\n release = undefined;\n\n return result;\n } finally {\n // Only reached with a live release when opening the stream threw.\n release?.();\n }\n}\n\n/**\n * Reads past pings and rate limit hints until the first content chunk or the\n * end. A usage chunk seen on the way is replayed ahead of that content. On\n * failure the stream is closed and any usage seen goes to `onFailedUsage`.\n * Runs inside `dispatchToProvider`, which feeds the error to AIMD.\n */\nasync function readUntilContent(\n iterator: AsyncIterator<WireStreamChunk>,\n first: IteratorResult<WireStreamChunk>,\n chunkIdleTimeoutMs: number | undefined,\n streamController: AbortController,\n limiter: RateLimiterAdapter | undefined,\n logger: Logger,\n onFailedUsage: (usage: WireUsageChunk, error: unknown) => void,\n): Promise<{ head: IteratorResult<WireStreamChunk>; rest: AsyncIterator<WireStreamChunk> }> {\n const held: WireStreamChunk[] = [];\n let current = first;\n let refused = false;\n\n try {\n while (!current.done && !isContentChunk(current.value)) {\n const chunk = current.value;\n\n if (chunk.type === 'rate_limit_hint') {\n limiter?.reactToRateLimitHint(chunk.hint);\n } else if (chunk.type !== 'ping') {\n // A refusal is held too, so one that comes before text is still seen by the accumulator.\n if (chunk.type === 'refusal') refused = true;\n held.push(chunk);\n }\n\n current = await withChunkIdleTimeout(\n () => iterator.next(),\n chunkIdleTimeoutMs,\n () => streamController.abort(),\n logger,\n );\n }\n\n // Read to the end first so the usage chunk after a refusal is reported. Content wins.\n if (current.done && refused) throw refusalError();\n } catch (error) {\n // Not awaited: after an idle timeout the generator can still be stuck in\n // its own await, and `return()` would wait for it. The abort is what\n // tears the transport down.\n streamController.abort();\n void Promise.resolve()\n .then(() => iterator.return?.())\n .catch(() => {});\n\n const lastUsage = [...held].reverse().find((chunk) => chunk.type === 'usage');\n if (lastUsage?.type === 'usage') onFailedUsage(lastUsage.usage, error);\n\n throw error;\n }\n\n if (current.done || held.length === 0) return { head: current, rest: iterator };\n\n // Replays the held chunks, then the content chunk, then the live stream.\n const queue: WireStreamChunk[] = [...held.slice(1), current.value];\n const rest: AsyncIterator<WireStreamChunk> = {\n next: () => {\n const queued = queue.shift();\n return queued ? Promise.resolve({ done: false, value: queued }) : iterator.next();\n },\n return: async () => iterator.return?.() ?? { done: true, value: undefined },\n };\n\n return { head: { done: false, value: held[0]! }, rest };\n}\n\n/** A non empty text delta or a tool call delta. An empty text delta is not content. */\nfunction isContentChunk(chunk: WireStreamChunk): boolean {\n return (chunk.type === 'text-delta' && chunk.delta !== '') || chunk.type === 'tool_call_delta';\n}\n","import { LLMError } from '../../../../types/errors.js';\nimport { 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 */\nexport function serializeAssistantContent(content: AssistantContent): string {\n return typeof content === 'string' ? content : JSON.stringify(content);\n}\n\n/**\n * Rejects an empty `tools`, duplicate names, `toolChoice` without `tools`, and a `toolChoice`\n * naming an unknown tool, all as `invalid_params`.\n */\nexport function validateTools(\n tools: CallParams<unknown>['tools'],\n toolChoice: CallParams<unknown>['toolChoice'],\n): void {\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\n/** Everything `resolveJsonMode` needs to decide `useJson` for one call. */\nexport interface ResolveJsonModeParams {\n /** `params.jsonMode` as the caller set it, `undefined` if they didn't. */\n jsonModeExplicit: boolean | undefined;\n /** Whether `tools` was set, since the default `jsonMode` depends on it. */\n hasTools: boolean;\n jsonSchema: CallParams<unknown>['jsonSchema'];\n /** Whether `schema` was set. */\n hasSchema: boolean;\n supportsJsonObjectMode: boolean;\n}\n\n/**\n * Whether to request and parse JSON. `jsonMode` defaults to off with `tools`, since forcing JSON\n * alongside tool calls is unreliable, and on otherwise. Clients without real `json_object` support\n * throw on an explicit `jsonMode: true` or a `schema` without `jsonSchema`, but quietly fall back\n * to text for the default. Throws `invalid_params` when `schema` is set but no JSON is requested.\n */\nexport function resolveJsonMode(params: ResolveJsonModeParams): boolean {\n const { jsonModeExplicit, hasTools, jsonSchema, hasSchema, supportsJsonObjectMode } = params;\n\n const jsonMode = jsonModeExplicit ?? !hasTools;\n\n if (!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 if (!supportsJsonObjectMode && !jsonSchema && jsonModeExplicit === undefined && hasSchema) {\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 // The default `jsonMode` falls back to text on clients without `json_object`, so `llm.call({\n // userContent })` works everywhere.\n const jsonModeEffective =\n !supportsJsonObjectMode && !jsonSchema && jsonModeExplicit === undefined ? false : jsonMode;\n\n const useJson = jsonModeEffective || Boolean(jsonSchema);\n\n if (hasSchema && !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 return useJson;\n}\n\n/** A native `jsonSchema` when given, else `json_object` when JSON is wanted, else no format. */\nexport function buildResponseFormat(\n jsonSchema: CallParams<unknown>['jsonSchema'],\n useJson: boolean,\n) {\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/** Maps VernLLM's app-facing `ToolChoice` onto the OpenAI-shaped wire `tool_choice`. */\nexport function 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 * One turn as wire messages. A tool turn expands to one `tool` message per result, since the wire\n * format wants one per `tool_call_id`.\n */\nexport function 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 ? { content: serializeAssistantContent(turn.content) } : {}),\n tool_calls: toWireToolCalls(turn.toolCalls),\n ...(turn.thinking?.length ? { thinking: turn.thinking } : {}),\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 ...(turn.thinking?.length ? { thinking: turn.thinking } : {}),\n },\n ];\n }\n\n return [{ role: turn.role as 'user', content: turn.content ?? '' }];\n}\n\n/**\n * Throws `LLMError('invalid_params')` unless `thinking` is an array of\n * well formed blocks. Checked locally since a malformed block would only\n * come back as a provider 400 after a round trip.\n */\nfunction assertValidThinking(thinking: unknown, index: number): void {\n if (!Array.isArray(thinking)) {\n throw new LLMError(`history[${index}].thinking must be an array`, 'invalid_params');\n }\n\n for (const [blockIndex, block] of thinking.entries()) {\n const candidate = block as Partial<Record<string, unknown>> | null;\n const valid =\n typeof candidate === 'object' &&\n candidate !== null &&\n ((candidate.type === 'thinking' &&\n typeof candidate.thinking === 'string' &&\n typeof candidate.signature === 'string') ||\n (candidate.type === 'redacted_thinking' && typeof candidate.data === 'string'));\n\n if (!valid) {\n throw new LLMError(\n `history[${index}].thinking[${blockIndex}] must be { type: 'thinking', thinking, signature } or { type: 'redacted_thinking', data }, as returned on ToolCallResult.thinking`,\n 'invalid_params',\n );\n }\n }\n}\n\n/**\n * Validates `history` alternates user/assistant turns, since providers\n * like Anthropic/Gemini reject or mishandle consecutive same-role turns.\n */\nexport function validateHistory(history: ConversationTurn[]): void {\n let previousTurn: ConversationTurn | undefined;\n\n for (const [index, turn] of history.entries()) {\n if (turn.role === 'assistant' && turn.thinking !== undefined) {\n assertValidThinking(turn.thinking, index);\n }\n\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","import {\n buildResponseFormat,\n buildWireToolChoice,\n resolveJsonMode,\n turnToWireMessages,\n validateHistory,\n validateTools,\n} from './utils/request/requestShape.utils.js';\nimport { toWireTools } from './utils/wire.utils.js';\n\nimport type { CallParams, WireMessage } from '../../types/index.js';\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 for one call from the target's defaults and the call's overrides. Owns\n * every check on the caller's own input, so every throw is `invalid_params`; `validation` is kept\n * for provider responses. The checks themselves live in `requestShape.utils.ts`.\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 validateTools(tools, toolChoice);\n\n const useJson = resolveJsonMode({\n jsonModeExplicit: params.jsonMode,\n hasTools: Boolean(tools),\n jsonSchema,\n hasSchema: Boolean(params.schema),\n supportsJsonObjectMode: this.supportsJsonObjectMode,\n });\n\n const responseFormat = buildResponseFormat(jsonSchema, useJson);\n\n 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: buildWireToolChoice(toolChoice) } : {}),\n messages: [\n ...(systemPrompt ? [{ role: 'system' as const, content: systemPrompt }] : []),\n ...history.flatMap((turn): WireMessage[] => turnToWireMessages(turn)),\n { role: 'user' as const, content: userContent },\n ] satisfies WireMessage[],\n };\n\n return { useJson, model, request };\n }\n}\n","import { toTokenUsage } from './utils/response/usage.utils.js';\n\nimport type { Logger } from '../../logger.js';\nimport type { LLMError } from '../../types/errors.js';\nimport type { VernLLMEvent } from '../../types/events.js';\nimport type { AttemptContext, LLMClient, TokenUsage } from '../../types/index.js';\n\n/** Everything one target's `UsageReporter` needs beyond the response/error being reported on. */\nexport interface UsageReporterOptions {\n providerName: string;\n /** True for every target after the primary. Stamped onto every reported `TokenUsage`. */\n isFallback: boolean;\n maxRetries: number;\n /** Whether cache reads count toward the provider's token rate limit. Default `true`. */\n cacheReadsCountTowardRateLimit?: boolean;\n /**\n * Reports `'usage'` and `'usage_failure'` events through the shared event path. `onUsage` and\n * `onUsageFailure` are driven from those events, so usage has one reporting route.\n */\n emitEvent: (event: VernLLMEvent, ctx: AttemptContext) => void;\n logger: Logger;\n}\n\nexport interface UsageReporter {\n /**\n * `TokenUsage` from a raw response, if reported. Independent of the rest of the body, so a\n * malformed response can still yield usage.\n */\n extract(\n response: Awaited<ReturnType<LLMClient['chat']['completions']['create']>>,\n requestId: string,\n model: string,\n ): TokenUsage | undefined;\n /**\n * The token count to reconcile the limiter with: `totalTokens`, else prompt plus completion,\n * less cache reads when the provider's limit skips them. `undefined` when missing or nothing is\n * left, so the limiter keeps its estimate.\n */\n actualTokensFor(usage: TokenUsage | undefined): number | undefined;\n /** Reports token usage for a successful call as a `'usage'` event. `ctx` is this attempt's `AttemptContext`, used to fan the event out to middleware and to `onEvent`/`onUsage`. */\n reportSuccess(usage: TokenUsage | undefined, ctx: AttemptContext): void;\n /**\n * Reports usage spent on an attempt that then failed, as `'usage_failure'`, so it isn't lost with\n * the error.\n */\n reportFailure(\n usage: TokenUsage,\n error: LLMError,\n attempt: number,\n ctx: AttemptContext,\n terminal?: boolean,\n ): void;\n}\n\nexport function createUsageReporter(options: UsageReporterOptions): UsageReporter {\n const { providerName, isFallback, maxRetries, emitEvent, logger } = options;\n const cacheReadsCount = options.cacheReadsCountTowardRateLimit ?? true;\n\n function extract(\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 return toTokenUsage(response.usage, { requestId, model, providerName, isFallback });\n }\n\n function actualTokensFor(usage: TokenUsage | undefined): number | undefined {\n if (!usage) return undefined;\n\n const total = usage.totalTokens || usage.promptTokens + usage.completionTokens;\n\n // A real request always spends prompt tokens, so an all zero report\n // means the provider sent no usage. Reconciling against it would\n // refund the whole estimate for tokens that were actually spent.\n if (cacheReadsCount) return total === 0 ? undefined : total;\n\n // Anthropic's limit skips cache reads; counting them would throttle cached traffic harder\n // than the provider does. Nothing left means the report carried no countable usage.\n const counted = total - (usage.cacheReadTokens ?? 0);\n\n return counted > 0 ? counted : undefined;\n }\n\n function reportSuccess(usage: TokenUsage | undefined, ctx: AttemptContext): void {\n if (!usage) return;\n\n emitEvent({ kind: 'usage', requestId: usage.requestId, usage }, ctx);\n }\n\n function reportFailure(\n usage: TokenUsage,\n error: LLMError,\n attempt: number,\n ctx: AttemptContext,\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}/${maxRetries + 1}`;\n\n logger.warn(\n `[VernLLM:${usage.requestId}] usage failure, ${attemptText}: ` +\n `type=${error.type} tokens=${displayTokens}`,\n );\n\n emitEvent({ kind: 'usage_failure', requestId: usage.requestId, usage, error }, ctx);\n }\n\n return { extract, actualTokensFor, reportSuccess, reportFailure };\n}\n","import { setupDeadline } from './deadline.utils.js';\n\n/** One signal that aborts when any given signal does, or `undefined` when none is given. */\nexport function combineSignals(\n signals: readonly (AbortSignal | undefined)[],\n): AbortSignal | undefined {\n const present = signals.filter((signal): signal is AbortSignal => signal !== undefined);\n return present.length > 1 ? AbortSignal.any(present) : present[0];\n}\n\nexport interface CallSignalSetup<P> {\n /** `params` with the effective signal, or `params` itself when nothing was added. */\n params: P;\n signal: AbortSignal | undefined;\n /** Aborted when the caller stops reading `chunks` early. Only set for a cancellable stream. */\n breakController: AbortController | undefined;\n dispose: () => void;\n}\n\n/**\n * Joins the caller signal, a break controller for streams, and `deadlineMs` into the\n * one signal the rest of the call reads. `cancellable` is false for `cachedCall()`'s\n * inner call, whose stream is shared and left by the cache instead.\n */\nexport function setupCallSignal<\n P extends { signal?: AbortSignal; deadlineMs?: number; stream?: boolean },\n>(params: P, cancellable: boolean): CallSignalSetup<P> {\n const breakController = params.stream && cancellable ? new AbortController() : undefined;\n const { signal, timer } = setupDeadline(\n params.deadlineMs,\n combineSignals([params.signal, breakController?.signal]),\n );\n\n return {\n params: signal === params.signal ? params : { ...params, signal },\n signal,\n breakController,\n dispose: () => clearTimeout(timer),\n };\n}\n","import { combineSignals } from '../execution/utils/callSignal.utils.js';\n\n/** Chain number by the signal a chain runs with. Only chains 1 and up are recorded. */\nconst chainBySignal = new WeakMap<AbortSignal, number>();\n\n/**\n * The signal a chain runs with: its parent's, combined with the chain's own cancel signal.\n * Recorded under `number`, so code that only sees the signal can tell which chain it's in.\n */\nexport function chainSignal(\n parent: AbortSignal | undefined,\n own: AbortSignal,\n number: number,\n): AbortSignal {\n return markChain(combineSignals([parent, own])!, number);\n}\n\n/**\n * Records `signal` as belonging to chain `number` and returns it. For a signal derived from a\n * chain's own, such as one that also ends when a stream is left early.\n */\nexport function markChain(signal: AbortSignal, number: number): AbortSignal {\n if (number > 0) chainBySignal.set(signal, number);\n return signal;\n}\n\n/** `{ chain }` to spread into a context, event or meta; empty for the main chain. */\nexport function chainFields(signal: AbortSignal | undefined): { chain?: number } {\n const chain = signal === undefined ? undefined : chainBySignal.get(signal);\n return chain === undefined ? {} : { chain };\n}\n","import { callFactsFor, callScopeFor, noopEmit } from '../utils/callScope.utils.js';\nimport { chainFields } from '../utils/chain.utils.js';\nimport { reportRejection } from '../utils/circuit-breaker/circuitBreaker.utils.js';\n\nimport type { CircuitBreakerAdapter, CircuitBreakerCallContext } from '../../circuitBreaker.js';\nimport type { Logger } from '../../logger.js';\nimport type {\n AdapterInfo,\n AttemptContext,\n LLMErrorCode,\n MiddlewareStateBag,\n} from '../../types/index.js';\nimport type { MiddlewareContextNames } from '../utils/middlewareLabels.utils.js';\n\n/** Everything one logical call needs to build attempt context and talk to its breaker. */\nexport interface BreakerGatewayOptions {\n breaker?: CircuitBreakerAdapter;\n /** Where a breaker adapter's rejected background promise is reported, see `settleQuietly`. */\n logger: Logger;\n requestId: string;\n model: string;\n providerName: string;\n isFallback: boolean;\n supportsJsonObjectMode: boolean;\n /** Threaded through for `AttemptContext.registeredMiddlewareNames` and `transformMiddlewareNames`. */\n middlewareNames: MiddlewareContextNames;\n /** Threaded through for `AttemptContext.adapter`. */\n adapter: AdapterInfo;\n}\n\n/**\n * Builds `AttemptContext`/`CircuitBreakerCallContext` for one logical\n * call's attempts, and records success/failure against `breaker`.\n * `attempt` stays 0-based at every call site; the 1-based conversion\n * happens once, inside `buildCallContext`/`buildAttemptContext`.\n */\nexport interface BreakerGateway {\n buildAttemptContext(\n attempt: number,\n signal: AbortSignal | undefined,\n state: MiddlewareStateBag,\n ): AttemptContext;\n buildCallContext(\n attempt: number,\n signal: AbortSignal | undefined,\n state: MiddlewareStateBag,\n ): CircuitBreakerCallContext;\n /** No-op if no breaker was configured. */\n recordSuccess(attempt: number, signal: AbortSignal | undefined, state: MiddlewareStateBag): void;\n /** No-op if no breaker was configured or it has no `releaseTrial`. Gives back a half-open trial when the call ended without recording an outcome. */\n releaseTrial(attempt: number, signal: AbortSignal | undefined, state: MiddlewareStateBag): void;\n /** No-op if no breaker was configured. `code`, when present, is forwarded to the breaker for future attribution use. */\n recordFailure(\n attempt: number,\n signal: AbortSignal | undefined,\n state: MiddlewareStateBag,\n code?: LLMErrorCode,\n ): void;\n}\n\nexport function createBreakerGateway(options: BreakerGatewayOptions): BreakerGateway {\n const {\n breaker,\n logger,\n requestId,\n model,\n providerName,\n isFallback,\n supportsJsonObjectMode,\n middlewareNames,\n adapter,\n } = options;\n\n function buildAttemptContext(\n attempt: number,\n signal: AbortSignal | undefined,\n state: MiddlewareStateBag,\n ): AttemptContext {\n return {\n stage: 'attempt',\n requestId,\n requestedProvider: providerName,\n adapter,\n requestedModel: model,\n isFallbackAttempt: isFallback,\n attempt: attempt + 1,\n capabilities: { supportsJsonObjectMode },\n signal,\n ...chainFields(signal),\n state,\n own: {},\n emit: noopEmit,\n context: callScopeFor(state)?.context,\n ...callFactsFor(state),\n ...middlewareNames,\n };\n }\n\n function buildCallContext(\n attempt: number,\n signal: AbortSignal | undefined,\n state: MiddlewareStateBag,\n ): CircuitBreakerCallContext {\n return { requestId, state, signal, attempt: attempt + 1 };\n }\n\n function settleQuietly(operation: string, result: unknown): void {\n reportRejection(logger, `[VernLLM:${requestId}] circuitBreaker.${operation} rejected`, result);\n }\n\n return {\n buildAttemptContext,\n buildCallContext,\n recordSuccess(attempt, signal, state) {\n settleQuietly(\n 'recordSuccess',\n breaker?.recordSuccess(model, buildCallContext(attempt, signal, state)),\n );\n },\n recordFailure(attempt, signal, state, code) {\n settleQuietly(\n 'recordFailure',\n breaker?.recordFailure(model, buildCallContext(attempt, signal, state), code),\n );\n },\n releaseTrial(attempt, signal, state) {\n settleQuietly(\n 'releaseTrial',\n breaker?.releaseTrial?.(model, buildCallContext(attempt, signal, state)),\n );\n },\n };\n}\n","import { LLMError, type LLMRequestSnapshot, type RetryAttempt } from '../../../../types/errors.js';\nimport { createMiddlewareStateBag } from '../../../../types/middleware.js';\nimport { reportRejection } from '../../../utils/circuit-breaker/circuitBreaker.utils.js';\nimport { logError } from '../../../utils/logger.utils.js';\nimport { middlewareContextNames } from '../../../utils/middlewareLabels.utils.js';\nimport { createBreakerGateway, type BreakerGateway } from '../../circuitBreakerContext.js';\nimport { describeError, extractStatus, normalizeError } from '../errors.utils.js';\nimport { emitEvent } from '../middleware/middleware.utils.js';\nimport { recoverDelay, retryWithBackoff, shouldRetry } from '../retry/retry.utils.js';\n\nimport type { CircuitBreakerAdapter } from '../../../../circuitBreaker.js';\nimport type { Logger } from '../../../../logger.js';\nimport type { RetryBudgetAdapter } from '../../../../retryBudget.js';\nimport type {\n AdapterInfo,\n MiddlewareStateBag,\n VernLLMEvent,\n VernLLMMiddleware,\n} from '../../../../types/index.js';\n\n/** Everything `runAttemptLoop` needs besides the per attempt `fn`. */\nexport interface RunAttemptLoopParams<T> {\n fn: (\n attempt: number,\n onRequest: (snapshot: LLMRequestSnapshot | undefined) => void,\n state: MiddlewareStateBag,\n gateway: BreakerGateway,\n ) => Promise<T>;\n requestId: string;\n model: string;\n providerName: string;\n isFallback: boolean;\n supportsJsonObjectMode: boolean;\n /** See `AttemptContext.adapter`. */\n adapter: AdapterInfo;\n breaker?: CircuitBreakerAdapter;\n /**\n * Caps how much of this target's recent traffic is allowed to be\n * retries, independent of `breaker`. See `RetryBudgetAdapter`.\n * Undefined means no budget, exactly today's behavior.\n */\n budget?: RetryBudgetAdapter;\n maxRetries: number;\n baseDelayMs: number;\n /** See `VernLLMOptions.maxRetryAfterMs`. Omitted means the 10s default. */\n maxRetryAfterMs?: number;\n nonRetryableStatus: number[];\n signal?: AbortSignal;\n onAttempt?: () => void;\n state?: MiddlewareStateBag;\n middleware: VernLLMMiddleware[];\n middlewareTimeoutMs: number;\n logger: Logger;\n reportEvent: (event: VernLLMEvent) => void;\n /**\n * Label folded into the debug log line on terminal failure, e.g.\n * `'error'` for `run`, `'stream-open error'` for `runStream`, so the\n * two calls stay distinguishable in logs despite sharing this loop.\n */\n logLabel: string;\n /** Applied to the logged error description. See `VernLLMOptions.redact`. */\n redactText: (text: string) => string;\n /**\n * Decides whether the terminal failure counts toward the breaker's\n * failure threshold. See `CallExecutor`'s own `countsTowardBreaker`,\n * which this is injected from.\n */\n countsTowardBreaker: (error: LLMError) => boolean;\n}\n\n/**\n * Retries `fn` with backoff through one shared `BreakerGateway`. On final failure it normalizes,\n * records against the breaker when `countsTowardBreaker` allows, logs under `logLabel`, and\n * rethrows.\n */\nexport async function runAttemptLoop<T>(params: RunAttemptLoopParams<T>): Promise<T> {\n const {\n fn,\n requestId,\n model,\n providerName,\n isFallback,\n supportsJsonObjectMode,\n adapter,\n breaker,\n budget,\n maxRetries,\n baseDelayMs,\n maxRetryAfterMs,\n nonRetryableStatus,\n signal,\n onAttempt,\n middleware,\n middlewareTimeoutMs,\n logger,\n reportEvent,\n logLabel,\n redactText,\n countsTowardBreaker,\n } = params;\n\n const resolvedState = params.state ?? createMiddlewareStateBag();\n // Every error this loop builds reports `retryAfterMs` under the same cap\n // the wait itself honors, so the two never disagree.\n const normalize = (error: unknown, signal?: AbortSignal, attempts?: RetryAttempt[]) =>\n normalizeError(error, signal, attempts, maxRetryAfterMs);\n const attempts: RetryAttempt[] = [];\n const gateway = createBreakerGateway({\n breaker,\n logger,\n requestId,\n model,\n providerName,\n isFallback,\n supportsJsonObjectMode,\n middlewareNames: middlewareContextNames(middleware),\n adapter,\n });\n\n // Set only when `budget.assertAvailable()` is what actually stopped a\n // retry, so the terminal error below can report *that*, not whichever\n // failure happened to be current when the budget ran out.\n let budgetExhaustedError: LLMError | undefined;\n\n try {\n return await retryWithBackoff({\n fn: (attempt, onRequest) => {\n if (budget) recordBudgetAttempt(budget, attempt > 0, logger);\n return fn(attempt, onRequest, resolvedState, gateway);\n },\n maxRetries,\n signal,\n onAttempt,\n attempts,\n shouldRetryAttempt: (error, signal) => {\n if (!shouldRetry(error, nonRetryableStatus, extractStatus, signal)) return false;\n if (budget) {\n try {\n budget.assertAvailable();\n } catch (err) {\n // Only an LLMError is a decision. Anything else is a broken adapter, and a broken\n // budget must not cost the call its retries, so it fails open.\n if (!(err instanceof LLMError)) {\n logError(logger, '[VernLLM] retryBudget.assertAvailable threw a non-LLMError', err);\n return true;\n }\n budgetExhaustedError = err;\n return false;\n }\n }\n return true;\n },\n recoverDelayForAttempt: (attempt, error) =>\n recoverDelay({\n requestId,\n model,\n attempt,\n error,\n state: resolvedState,\n signal,\n providerName,\n maxRetries,\n baseDelayMs,\n maxRetryAfterMs,\n middleware,\n middlewareTimeoutMs,\n logger,\n reportEvent,\n buildEventContext: (_requestId, _model, attempt, signal, state) =>\n gateway.buildAttemptContext(attempt, signal, state),\n extractStatus,\n normalizeError: normalize,\n emitEvent,\n }),\n normalizeError: normalize,\n });\n } catch (error) {\n // An empty `attempts` becomes `undefined`, per `LLMError.attempts`. The budget error goes\n // through `normalizeError` too, which adds the history without changing its type or code.\n const normalized = normalize(\n budgetExhaustedError ?? error,\n signal,\n attempts.length > 0 ? attempts : undefined,\n );\n\n if (countsTowardBreaker(normalized)) {\n // `attempts` only holds prior attempts that were retried past (see\n // above), so the attempt that actually exhausted the retries/broke\n // the loop is one past that. `recordFailure` converts to 1-based\n // itself.\n gateway.recordFailure(attempts.length, signal, resolvedState, normalized.code);\n } else {\n // Nothing was recorded, so a half-open trial this call claimed would\n // otherwise stay held forever. Idempotent, a no-op when it holds none.\n gateway.releaseTrial(attempts.length, signal, resolvedState);\n }\n\n logger.debug(`[VernLLM:${requestId}] ${logLabel}:\\n${redactText(describeError(error))}`);\n\n throw normalized;\n }\n}\n\n/**\n * Records an attempt without letting the budget break the call: a remote adapter's throw or\n * rejected promise is logged, never thrown or left unhandled.\n */\nfunction recordBudgetAttempt(budget: RetryBudgetAdapter, isRetry: boolean, logger: Logger): void {\n try {\n // Declared `void`, but a remote adapter may return a promise anyway.\n reportRejection(\n logger,\n '[VernLLM] retryBudget.recordAttempt rejected',\n budget.recordAttempt(isRetry),\n );\n } catch (error) {\n logError(logger, '[VernLLM] retryBudget.recordAttempt threw', error);\n }\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 { type RetryBudgetAdapter } from '../../retryBudget.js';\nimport { resolveAdapterInfo } from '../utils/adapterInfo.utils.js';\nimport {\n makeEventReporter,\n reportRejection,\n} from '../utils/circuit-breaker/circuitBreaker.utils.js';\nimport {\n runPrepare,\n type PreparableBreaker,\n} from '../utils/circuit-breaker/prepareBreaker.utils.js';\nimport { callHookSafely } from '../utils/logger.utils.js';\nimport {\n countsTowardBreaker,\n redactText,\n type AttemptArgs,\n type AttemptEnvironment,\n} from './attempt/attemptEnvironment.js';\nimport { executeCall } from './attempt/nonStreamAttempt.js';\nimport { executeStreamCall } from './attempt/streamAttempt.js';\nimport { RequestBuilder } from './requestBuilder.js';\nimport { createUsageReporter } from './usageReporter.js';\nimport { type OnRequest } from './utils/dispatch/attemptDispatch.utils.js';\nimport { runAttemptLoop, type RunAttemptLoopParams } from './utils/dispatch/attemptLoop.utils.js';\nimport {\n DEFAULT_MIDDLEWARE_TIMEOUT_MS,\n buildDispatchHooks,\n emitEvent,\n} from './utils/middleware/middleware.utils.js';\nimport { defaultParseJson } from './utils/parse.utils.js';\nimport { normalizeMaxRetries, validateMaxRetryAfterMs } from './utils/retry/retry.utils.js';\n\nimport type { CircuitBreakerAdapter, CircuitBreakerCallContext } from '../../circuitBreaker.js';\nimport type { Logger } from '../../logger.js';\nimport type { RateLimiterAdapter } from '../../rateLimit.js';\nimport type { LLMError } from '../../types/errors.js';\nimport type {\n AdapterInfo,\n CallParams,\n CallWithToolsResult,\n DetectSoftFailure,\n LLMClient,\n MiddlewareStateBag,\n StreamChunk,\n TokenUsage,\n VernLLMEvent,\n VernLLMMiddleware,\n WireCallRequest,\n} from '../../types/index.js';\n\nexport type { OnRequest };\n\n/** Everything one `CallExecutor` needs beyond the client and model. */\nexport interface CallExecutorOptions {\n maxRetries: number;\n timeoutMs: number;\n chunkIdleTimeoutMs: number;\n /** See `VernLLMOptions.readerStallTimeoutMs`. Off when omitted. */\n readerStallTimeoutMs?: number;\n baseDelayMs: number;\n /** See `VernLLMOptions.maxRetryAfterMs`. */\n maxRetryAfterMs: 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?: CircuitBreakerAdapter;\n /** Caps retries against this target independent of `breaker`. See `VernLLMOptions.retryBudget`. */\n budget?: RetryBudgetAdapter;\n limiter?: RateLimiterAdapter;\n /** True for every target after the primary. Stamped onto reported `TokenUsage`. */\n isFallback?: boolean;\n /** See `VernLLMOptions.middleware`. */\n middleware?: VernLLMMiddleware[];\n /**\n * `wrap` nesting order (`position` applied), which `dispatch` hooks nest\n * in too. Defaults to `middleware`'s order.\n */\n dispatchOrder?: VernLLMMiddleware[];\n /** See `VernLLMOptions.middlewareTimeoutMs`. */\n middlewareTimeoutMs?: number;\n /** See `VernLLMOptions.detectSoftFailure`. */\n detectSoftFailure?: DetectSoftFailure;\n}\n\n/**\n * One provider target: request building, retries, and its own breaker and limiter. `VernLLM` holds\n * one per target and adds fallback and caching on top.\n */\nexport class CallExecutor {\n private readonly maxRetries: number;\n private readonly baseDelayMs: number;\n private readonly nonRetryableStatus: number[];\n private readonly logger: Logger;\n private readonly breaker?: CircuitBreakerAdapter;\n private readonly budget?: RetryBudgetAdapter;\n private readonly limiter?: RateLimiterAdapter;\n private readonly isFallback: boolean;\n private readonly supportsJsonObjectMode: boolean;\n /** Everything a single attempt reads. Shared by both attempt paths. */\n private readonly env: AttemptEnvironment;\n /** See `AttemptContext.adapter`. */\n readonly adapter: AdapterInfo;\n\n constructor(\n readonly providerName: string,\n client: LLMClient,\n readonly model: string,\n options: CallExecutorOptions,\n ) {\n this.maxRetries = normalizeMaxRetries(options.maxRetries);\n this.baseDelayMs = options.baseDelayMs;\n const maxRetryAfterMs = validateMaxRetryAfterMs(options.maxRetryAfterMs, providerName);\n this.nonRetryableStatus = options.nonRetryableStatus;\n this.logger = options.logger;\n\n if (this.maxRetries !== options.maxRetries) {\n this.logger.warn(\n `[VernLLM] ${providerName}: maxRetries must be a non-negative whole number, got ${String(options.maxRetries)}. Using ${this.maxRetries}.`,\n );\n }\n\n const reportEvent = makeEventReporter(options.onEvent, this.logger, {\n onUsage: options.onUsage,\n onUsageFailure: options.onUsageFailure,\n });\n\n this.breaker = options.breaker;\n this.budget = options.budget;\n this.limiter = options.limiter;\n this.isFallback = options.isFallback ?? false;\n const middleware = options.middleware ?? [];\n const dispatchHooks = buildDispatchHooks(middleware, options.dispatchOrder);\n this.adapter = resolveAdapterInfo(client);\n callHookSafely(this.logger, 'client.setLogger', () => client.setLogger?.(this.logger));\n const middlewareTimeoutMs = options.middlewareTimeoutMs ?? DEFAULT_MIDDLEWARE_TIMEOUT_MS;\n this.supportsJsonObjectMode = client.supportsJsonObjectMode ?? true;\n\n const usageReporter = createUsageReporter({\n providerName,\n isFallback: this.isFallback,\n maxRetries: this.maxRetries,\n cacheReadsCountTowardRateLimit: client.cacheReadsCountTowardRateLimit,\n emitEvent: (event, ctx) =>\n emitEvent(event, ctx, reportEvent, middleware, middlewareTimeoutMs, this.logger),\n logger: this.logger,\n });\n\n const requestBuilder = new RequestBuilder({\n model,\n defaultMaxTokens: options.defaultMaxTokens,\n defaultTemperature: options.defaultTemperature,\n defaultReasoningEffort: options.defaultReasoningEffort,\n defaultBudgetTokens: options.defaultBudgetTokens,\n supportsJsonObjectMode: this.supportsJsonObjectMode,\n });\n\n this.env = {\n client,\n providerName,\n isFallback: this.isFallback,\n timeoutMs: options.timeoutMs,\n chunkIdleTimeoutMs: options.chunkIdleTimeoutMs,\n readerStallTimeoutMs: options.readerStallTimeoutMs,\n maxRetryAfterMs,\n parseJson: options.parseJson ?? defaultParseJson,\n logger: this.logger,\n redact: options.redact,\n usageReporter,\n reportEvent,\n limiter: this.limiter,\n requestBuilder,\n middleware,\n dispatchHooks,\n middlewareTimeoutMs,\n detectSoftFailure: options.detectSoftFailure,\n };\n }\n\n /**\n * This target's wire request for `params`, without dispatch or `transform`.\n * Gives `wrap` a representative request before the real one exists.\n */\n previewRequest<T>(params: CallParams<T>): { model: string; request: WireCallRequest } {\n const { model, request } = this.env.requestBuilder.build(params);\n return { model, request };\n }\n\n /** Whether the client supports `response_format: 'json_object'`. */\n get jsonObjectModeSupported(): boolean {\n return this.supportsJsonObjectMode;\n }\n\n getCircuitState(model?: string) {\n return this.breaker?.getState?.(model);\n }\n\n /** The breaker's `readState` if it has one, otherwise `getState`. */\n async readCircuitState(model?: string) {\n return this.breaker?.readState\n ? this.breaker.readState(model)\n : this.breaker?.getState?.(model);\n }\n\n getFailureBreakdown(model?: string) {\n return this.breaker?.getFailureBreakdown?.(model);\n }\n\n getRetryBudgetState() {\n return this.budget?.getSnapshot?.();\n }\n\n /** The budget's `readState` if it has one, otherwise `getSnapshot`. */\n async readRetryBudgetState() {\n return this.budget?.readState ? this.budget.readState() : this.budget?.getSnapshot?.();\n }\n\n getRateLimitState() {\n return this.limiter?.getState?.();\n }\n\n /** The limiter's `readState` if it has one, otherwise `getState`. */\n async readRateLimitState() {\n return this.limiter?.readState ? this.limiter.readState() : this.limiter?.getState?.();\n }\n\n /** `false` without a breaker, or when the breaker doesn't report it. */\n get isolateByModel(): boolean {\n return this.breaker?.isolateByModel ?? false;\n }\n\n openCircuit(model?: string, context?: CircuitBreakerCallContext): void {\n this.breaker?.open?.(model, context);\n }\n\n closeCircuit(model?: string, context?: CircuitBreakerCallContext): void {\n this.breaker?.close?.(model, context);\n }\n\n /**\n * Throws if the breaker is open. May claim a half-open trial, so it runs\n * once per logical call, from `VernLLM` or the fallback chain, never from\n * `run`. Returns a promise only when the breaker has a `prepare`, so a plain\n * breaker adds no tick.\n */\n assertBreakerClosed(model?: string, context?: CircuitBreakerCallContext): void | Promise<void> {\n const breaker = this.breaker;\n const resolvedModel = model ?? this.model;\n\n if (!breaker?.prepare) {\n breaker?.assertClosed(resolvedModel, context);\n return;\n }\n\n return runPrepare(breaker as PreparableBreaker, resolvedModel, context, this.logger).then(() =>\n breaker.assertClosed(resolvedModel, context),\n );\n }\n\n /** Gives back a trial `assertBreakerClosed` may have claimed. Idempotent. */\n releaseBreakerTrial(model?: string, context?: CircuitBreakerCallContext): void {\n // Declared `void`, but a remote adapter may return a promise anyway.\n reportRejection(\n this.logger,\n '[VernLLM] circuitBreaker.releaseTrial rejected',\n this.breaker?.releaseTrial?.(model ?? this.model, context),\n );\n }\n\n /** One logical call against this target, with retries. The breaker check stays with the caller. */\n async run<T>(\n params: CallParams<T>,\n requestId: string,\n onAttempt?: () => void,\n state?: MiddlewareStateBag,\n onFinish?: AttemptArgs<T>['onFinish'],\n ): Promise<T | CallWithToolsResult<T>> {\n return runAttemptLoop(\n this.attemptLoopParams(\n params,\n requestId,\n onAttempt,\n state,\n 'error',\n (attempt, onRequest, middlewareState, gateway) =>\n executeCall(this.env, {\n params,\n requestId,\n attempt,\n onRequest,\n middlewareState,\n gateway,\n onFinish,\n }),\n ),\n );\n }\n\n /**\n * Streaming counterpart to `run`. `onOpened` fires when any attempt's stream\n * opens, a ping included. See `executeLogicalStreamCall`.\n */\n async runStream<T>(\n params: CallParams<T>,\n requestId: string,\n onAttempt?: () => void,\n state?: MiddlewareStateBag,\n onOpened?: () => void,\n onFinish?: AttemptArgs<T>['onFinish'],\n ): Promise<{\n chunks: AsyncIterable<StreamChunk>;\n finalResult: Promise<T | CallWithToolsResult<T>>;\n }> {\n return runAttemptLoop(\n this.attemptLoopParams(\n params,\n requestId,\n onAttempt,\n state,\n 'stream-open error',\n (attempt, onRequest, middlewareState, gateway) =>\n executeStreamCall(\n this.env,\n { params, requestId, attempt, onRequest, middlewareState, gateway, onFinish },\n onOpened,\n ),\n ),\n );\n }\n\n private attemptLoopParams<R>(\n params: CallParams<unknown>,\n requestId: string,\n onAttempt: (() => void) | undefined,\n state: MiddlewareStateBag | undefined,\n logLabel: RunAttemptLoopParams<R>['logLabel'],\n fn: RunAttemptLoopParams<R>['fn'],\n ): RunAttemptLoopParams<R> {\n return {\n fn,\n requestId,\n model: params.model ?? this.model,\n providerName: this.providerName,\n isFallback: this.isFallback,\n supportsJsonObjectMode: this.supportsJsonObjectMode,\n adapter: this.adapter,\n breaker: this.breaker,\n budget: this.budget,\n maxRetries: this.maxRetries,\n baseDelayMs: this.baseDelayMs,\n maxRetryAfterMs: this.env.maxRetryAfterMs,\n nonRetryableStatus: this.nonRetryableStatus,\n signal: params.signal,\n onAttempt,\n state,\n middleware: this.env.middleware,\n middlewareTimeoutMs: this.env.middlewareTimeoutMs,\n logger: this.logger,\n reportEvent: this.env.reportEvent,\n logLabel,\n redactText: (text) => redactText(this.env, text),\n countsTowardBreaker,\n };\n }\n}\n","import { LLMError } from '../../types/errors.js';\n\nimport type { TargetInfo } from '../../types/fallback.js';\nimport type { CallExecutor } from './callExecutor.js';\n\n/** One configured target, with the declared position that stays its identity in events and meta. */\nexport interface ResolvedTarget {\n executor: CallExecutor;\n /** Declared index: 0 is the primary. Unchanged by any reordering. */\n index: number;\n}\n\n/** Every target in declared order. */\nexport function declaredTargets(executors: readonly CallExecutor[]): ResolvedTarget[] {\n return executors.map((executor, index) => ({ executor, index }));\n}\n\n/**\n * The targets as `ctx.targets` shows them. `model` is what the target would run, so the per call\n * `model` override shows on the primary only.\n */\nexport function describeTargets(\n targets: readonly ResolvedTarget[],\n modelFor: (index: number) => string | undefined,\n): TargetInfo[] {\n return targets.map(({ executor, index }) => ({\n name: executor.providerName,\n index,\n model: modelFor(index) ?? executor.model,\n adapter: executor.adapter,\n }));\n}\n\nfunction noEligibleTargets(message: string): LLMError {\n return new LLMError(message, 'invalid_params', { code: 'no_eligible_targets' });\n}\n\n/**\n * Applies `requested` on top of `current`, both by target name. Names in `all` but outside\n * `current` were removed by an outer layer, so they are dropped and reported through `onDropped`\n * rather than added back. `onDropped` is optional since, when `current` is `all`, nothing can have\n * been removed. Throws `invalid_params` before any provider is contacted:\n * `unknown_target` for a name in no target, `no_eligible_targets` for an empty or repeating list\n * or one that ends up empty.\n */\nexport function narrowTargets(\n all: readonly ResolvedTarget[],\n current: readonly ResolvedTarget[],\n requested: readonly string[] | undefined,\n onDropped?: (name: string) => void,\n): ResolvedTarget[] {\n if (requested === undefined) return [...current];\n\n // Only a caller bypassing the types gets here, so this carries no `code`.\n if (!Array.isArray(requested) || requested.some((name) => typeof name !== 'string')) {\n throw new LLMError('`targets` must be an array of target names', 'invalid_params');\n }\n\n if (requested.length === 0 || new Set(requested).size !== requested.length) {\n throw noEligibleTargets('`targets` must name at least one target, each at most once');\n }\n\n const narrowed: ResolvedTarget[] = [];\n\n for (const name of requested) {\n if (!all.some((target) => target.executor.providerName === name)) {\n const valid = all.map((target) => `\"${target.executor.providerName}\"`).join(', ');\n throw new LLMError(`Unknown target \"${name}\". Valid targets: ${valid}`, 'invalid_params', {\n code: 'unknown_target',\n });\n }\n\n const allowed = current.find((target) => target.executor.providerName === name);\n\n if (allowed) narrowed.push(allowed);\n else onDropped?.(name);\n }\n\n if (narrowed.length === 0) {\n throw noEligibleTargets(\n 'No target is left: every requested target was removed by an outer layer',\n );\n }\n\n return narrowed;\n}\n","import { LLMError } from '../../types/errors.js';\nimport { FallbackExhaustedError } from '../../types/fallback.js';\nimport { callFactsFor, callScopeFor, noopEmit } from '../utils/callScope.utils.js';\nimport { chainFields } from '../utils/chain.utils.js';\nimport { createDeferred } from '../utils/deferred.utils.js';\nimport { middlewareContextNames } from '../utils/middlewareLabels.utils.js';\nimport { describeTargets, type ResolvedTarget } from './targetOrder.js';\nimport { normalizeError } from './utils/errors.utils.js';\nimport { emitEvent } from './utils/middleware/middleware.utils.js';\n\nimport type { Logger } from '../../logger.js';\nimport type {\n AttemptContext,\n CallParams,\n CallMeta,\n CallResult,\n CallWithToolsResult,\n FallbackAttempt,\n FallbackOn,\n FinishReason,\n MiddlewareStateBag,\n StreamChunk,\n TargetInfo,\n VernLLMEvent,\n VernLLMMiddleware,\n} from '../../types/index.js';\nimport type { CallExecutor } from './callExecutor.js';\n\n/** What the logical call functions need from `VernLLM`, so they can live outside the class. */\nexport interface LogicalCallDependencies {\n /**\n * The targets this call may try, in the order to try them. Every target as declared, unless the\n * call's `targets` or a `wrap` narrowed or reordered it. Set per call.\n */\n targets: readonly ResolvedTarget[];\n /** Decides whether a failed target is followed by the next one or the chain stops. See `VernLLMOptions['fallbackOn']`. */\n fallbackOn: FallbackOn;\n /** Reports a `'fallback'` event when the chain moves to the next target. */\n reportEvent: (event: VernLLMEvent) => void;\n /** See `VernLLMOptions.middleware`. Already in `transform`/`onEvent` order: `priority`, with `runsAfter`/`runsBefore` resolved first. */\n middleware: VernLLMMiddleware[];\n /** See `VernLLMOptions.middlewareTimeoutMs`. */\n middlewareTimeoutMs: number;\n logger: Logger;\n}\n\n/**\n * The chain's outcome: the winning result, which target answered, its declared index and its\n * position in the order tried, and how many attempts that target made.\n */\nexport interface FallbackChainOutcome<TResult> {\n result: TResult;\n executor: CallExecutor;\n /** Declared index, see `ResolvedTarget`. */\n index: number;\n /** Position in the order tried, 0 based. */\n position: number;\n attemptCount: number;\n /** The model the winning target actually ran, see `modelForTarget`. */\n model: string;\n}\n\n/**\n * The per call `model` override for this target, or `undefined` to use its own. The override names\n * a model on the primary's provider, so a fallback on another provider can only fail with it.\n */\nexport function modelForTarget(\n params: Pick<CallParams<unknown>, 'model'>,\n targetIndex: number,\n): string | undefined {\n return targetIndex === 0 ? params.model : undefined;\n}\n\n/** `params` as the target at `targetIndex` should see it, see `modelForTarget`. */\nexport function paramsForTarget<P extends Pick<CallParams<unknown>, 'model'>>(\n params: P,\n targetIndex: number,\n): P {\n if (targetIndex === 0 || params.model === undefined) return params;\n return { ...params, model: undefined };\n}\n\n/**\n * Tries each of `dependencies.targets` in order until one succeeds. `skipBreakerCheckForFirst` is\n * set when `call()` already checked the sole target, since checking again would see its own\n * claimed trial. Throws the lone failure when one target was tried, else `FallbackExhaustedError`\n * with every attempt. Events and attempts keep declared indices, whatever the order.\n */\nexport async function runFallbackChain<R>(\n dependencies: LogicalCallDependencies,\n params: Pick<CallParams<unknown>, 'model' | 'signal'>,\n requestId: string,\n middlewareState: MiddlewareStateBag,\n attempt: (\n executor: CallExecutor,\n onAttempt: () => void,\n targetIndex: number,\n position: number,\n ) => Promise<R>,\n skipBreakerCheckForFirst = false,\n): Promise<FallbackChainOutcome<R>> {\n const fallbackAttempts: FallbackAttempt[] = [];\n\n const { targets } = dependencies;\n\n for (let position = 0; position < targets.length; position++) {\n const { executor, index: targetIndex } = targets[position]!;\n const targetModel = modelForTarget(params, targetIndex);\n const startedAt = Date.now();\n let attemptCount = 0;\n\n try {\n // Claiming a half-open trial is a side effect, so a target already checked by `call()` isn't\n // checked twice.\n if (!(position === 0 && skipBreakerCheckForFirst)) {\n const checking = executor.assertBreakerClosed(targetModel, {\n requestId,\n state: middlewareState,\n signal: params.signal,\n });\n // Only a breaker with a `prepare` hands back something to wait for.\n if (checking) await checking;\n }\n\n const result = await attempt(\n executor,\n () => {\n attemptCount += 1;\n },\n targetIndex,\n position,\n );\n return {\n result,\n executor,\n index: targetIndex,\n position,\n attemptCount,\n model: targetModel ?? executor.model,\n };\n } catch (error) {\n const normalizedError = normalizeError(error, params.signal);\n\n // Whatever ended this target, a half-open trial it claimed and never\n // settled must not stay held. Idempotent, so this is also safe when\n // the failure was already recorded against the breaker.\n executor.releaseBreakerTrial(targetModel, {\n requestId,\n state: middlewareState,\n signal: params.signal,\n });\n\n fallbackAttempts.push({\n index: targetIndex - 1,\n provider: executor.providerName,\n model: targetModel ?? 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: normalizedError.toSnapshot(),\n });\n\n const isLastTarget = position === targets.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\n // no next executor to fall over to.\n const [failed, next] = describeTargets(targets.slice(position, position + 2), (index) =>\n modelForTarget(params, index),\n ) as [TargetInfo, TargetInfo | undefined];\n const policyDecision = dependencies.fallbackOn(normalizedError, {\n isLastTarget,\n failed,\n ...(next ? { next } : {}),\n });\n const decision = isLastTarget ? '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 fallbackAttempts.length > 1\n ? new FallbackExhaustedError(fallbackAttempts)\n : normalizedError;\n }\n\n reportFallback(dependencies, {\n requestId,\n failed: targets[position]!,\n next: targets[position + 1]!,\n failedModel: targetModel ?? executor.model,\n attempt: attemptCount,\n error: normalizedError,\n elapsedMs: Date.now() - startedAt,\n signal: params.signal,\n middlewareState,\n });\n }\n }\n\n // Unreachable: the loop above always either returns or throws before\n // running out of targets (the last iteration's `isLastTarget` forces\n // a throw). Kept only to satisfy the return type.\n throw new LLMError('No provider targets configured', 'invalid_params');\n}\n\n/**\n * Emits the `'fallback'` event for the `failed` target, moving on to `next`. The context describes\n * the failed target, not the next one. Indices are the declared ones.\n */\nfunction reportFallback(\n dependencies: LogicalCallDependencies,\n failure: {\n requestId: string;\n failed: ResolvedTarget;\n next: ResolvedTarget;\n failedModel: string;\n attempt: number;\n error: LLMError;\n elapsedMs: number;\n signal: AbortSignal | undefined;\n middlewareState: MiddlewareStateBag;\n },\n): void {\n const { requestId, signal } = failure;\n const { executor, index: targetIndex } = failure.failed;\n const nextExecutor = failure.next.executor;\n\n const ctx: AttemptContext = {\n stage: 'attempt',\n requestId,\n requestedProvider: executor.providerName,\n adapter: executor.adapter,\n requestedModel: failure.failedModel,\n isFallbackAttempt: targetIndex > 0,\n // Stays 0 when the breaker check threw before any attempt; the field is 1-based.\n attempt: failure.attempt || 1,\n capabilities: { supportsJsonObjectMode: executor.jsonObjectModeSupported },\n signal,\n ...chainFields(signal),\n state: failure.middlewareState,\n own: {},\n emit: noopEmit,\n context: callScopeFor(failure.middlewareState)?.context,\n ...callFactsFor(failure.middlewareState),\n ...middlewareContextNames(dependencies.middleware),\n };\n\n emitEvent(\n {\n kind: 'fallback',\n requestId,\n from: executor.providerName,\n to: nextExecutor.providerName,\n fromIndex: targetIndex - 1,\n toIndex: failure.next.index - 1,\n error: failure.error,\n elapsedMs: failure.elapsedMs,\n },\n ctx,\n dependencies.reportEvent,\n dependencies.middleware,\n dependencies.middlewareTimeoutMs,\n dependencies.logger,\n );\n}\n\n/** The `CallResult.meta` fields for whichever target answered. */\nfunction metaFor(\n executor: CallExecutor,\n index: number,\n position: number,\n attemptCount: number,\n model: string,\n signal: AbortSignal | undefined,\n): CallMeta {\n return {\n provider: executor.providerName,\n model,\n // Declared, so they keep meaning \"a declared fallback answered\" in any order.\n fallbackIndex: index - 1,\n usedFallback: index > 0,\n attempts: attemptCount,\n position,\n ...chainFields(signal),\n };\n}\n\n/**\n * Builds `CallResult.meta` from the chain's outcome and writes it to `params.meta.current` when\n * given.\n */\nfunction buildCallResult<R>(\n outcome: FallbackChainOutcome<R>,\n params: Pick<CallParams<unknown>, 'meta' | 'signal'>,\n finishReason?: FinishReason,\n): CallResult<R> {\n const meta = metaFor(\n outcome.executor,\n outcome.index,\n outcome.position,\n outcome.attemptCount,\n outcome.model,\n params.signal,\n );\n if (finishReason) meta.finishReason = finishReason;\n\n // `params` here is the same object `VernLLM.call()` received from the\n // caller, not a clone, so this write is visible on the caller's own\n // `meta` out-parameter too.\n if (params.meta) {\n params.meta.current = meta;\n }\n\n return { value: outcome.result, meta };\n}\n\n/**\n * The fallback chain and retries of one non-streaming call, without `wrap`. Each caller wraps it\n * once, so no value passes through `wrap` twice.\n */\nexport async function executeLogicalCall<T>(\n dependencies: LogicalCallDependencies,\n params: CallParams<T>,\n requestId: string,\n soleTarget: boolean,\n middlewareState: MiddlewareStateBag,\n): Promise<CallResult<T | CallWithToolsResult<T>>> {\n let finishReason: FinishReason | undefined;\n\n const fallbackChainOutcome = await runFallbackChain(\n dependencies,\n params,\n requestId,\n middlewareState,\n (executor, onAttempt, targetIndex) =>\n executor.run(\n paramsForTarget(params, targetIndex),\n requestId,\n onAttempt,\n middlewareState,\n (reason) => {\n finishReason = reason;\n },\n ),\n soleTarget,\n );\n\n return buildCallResult(fallbackChainOutcome, params, finishReason);\n}\n\n/**\n * Streaming counterpart to `executeLogicalCall`. Resolves when the first stream opens, a ping\n * included, while the chain keeps running behind it until content arrives: a failure before content\n * still retries and falls back, and `chunks` and `finalResult` follow whichever attempt answers.\n * `meta` is updated in place once that target is known.\n */\nexport async function executeLogicalStreamCall<T>(\n dependencies: LogicalCallDependencies,\n params: CallParams<T>,\n requestId: string,\n soleTarget: boolean,\n middlewareState: MiddlewareStateBag,\n): Promise<\n CallResult<{\n chunks: AsyncIterable<StreamChunk>;\n finalResult: Promise<T | CallWithToolsResult<T>>;\n }>\n> {\n type Opened = { executor: CallExecutor; index: number; position: number; attempts: number };\n\n const { promise: opened, resolve: resolveOpened } = createDeferred<Opened>();\n let finishReason: FinishReason | undefined;\n\n const chain = runFallbackChain(\n dependencies,\n params,\n requestId,\n middlewareState,\n (executor, onAttempt, targetIndex, position) => {\n let attempts = 0;\n return executor.runStream(\n paramsForTarget(params, targetIndex),\n requestId,\n () => {\n attempts += 1;\n onAttempt();\n },\n middlewareState,\n () => resolveOpened({ executor, index: targetIndex, position, attempts }),\n (reason) => {\n finishReason = reason;\n },\n );\n },\n soleTarget,\n );\n\n // Handled through `finalResult` and `chunks` once the stream has opened.\n chain.catch(() => {});\n\n const first = await Promise.race([\n opened.then((value) => ({ kind: 'opened' as const, value })),\n chain.then((value) => ({ kind: 'settled' as const, value })),\n ]);\n\n if (first.kind === 'settled') return buildCallResult(first.value, params);\n\n const { executor, index, position, attempts } = first.value;\n const meta = metaFor(\n executor,\n index,\n position,\n attempts,\n modelForTarget(params, index) ?? executor.model,\n params.signal,\n );\n if (params.meta) params.meta.current = meta;\n\n const finalResult = chain.then(async (outcome) => {\n // Same object the caller already holds, so a reopened stream shows up in it.\n Object.assign(\n meta,\n metaFor(\n outcome.executor,\n outcome.index,\n outcome.position,\n outcome.attemptCount,\n outcome.model,\n params.signal,\n ),\n );\n const value = await outcome.result.finalResult;\n\n // Known only once the stream has ended, so it is set on that same object.\n if (finishReason) meta.finishReason = finishReason;\n\n return value;\n });\n\n // Avoid an unhandled rejection for a caller that only reads `chunks`.\n finalResult.catch(() => {});\n\n const chunks: AsyncIterable<StreamChunk> = {\n async *[Symbol.asyncIterator]() {\n const outcome = await chain;\n yield* outcome.result.chunks;\n },\n };\n\n return { value: { chunks, finalResult }, meta };\n}\n","import { LLMError } from '../../types/errors.js';\nimport {\n executeLogicalCall,\n executeLogicalStreamCall,\n modelForTarget,\n type LogicalCallDependencies,\n} from './logicalCall.js';\nimport { withReservedUsage, withReservedUsageForStream } from './utils/response/usage.utils.js';\nimport { cancelOnBreak } from './utils/stream/earlyExit.utils.js';\n\nimport type { CallMeta, CallParams, CallResult } from '../../types/index.js';\nimport type { MiddlewareStateBag } from '../../types/middleware.js';\n\nexport interface ReservedLogicalCallOptions {\n requestId: string;\n middlewareState: MiddlewareStateBag;\n /** Aborted when the caller leaves `chunks` early. See `setupCallSignal`. */\n breakController: AbortController | undefined;\n onRefundError: (logMessage: string, error: unknown) => void;\n}\n\n/**\n * The part of `call()` inside `wrap`: the sole target breaker check, usage\n * reservation, then the logical call over `dependencies.targets`.\n *\n * With one target the breaker is checked here, before usage is reserved, so a\n * blocked call never pays a reserve and refund round trip. That also covers a\n * call narrowed to one target. With more, the check stays inside\n * `runFallbackChain`, since claiming a half-open trial must happen once per\n * call and an open first target is just another target failure there.\n */\nexport async function runReservedLogicalCall<T>(\n dependencies: LogicalCallDependencies,\n params: CallParams<T>,\n { requestId, middlewareState, breakController, onRefundError }: ReservedLogicalCallOptions,\n): Promise<CallResult> {\n const soleTarget = dependencies.targets.length === 1;\n // The per call `model` override belongs to the primary only, so a sole fallback runs its own.\n const soleModel = modelForTarget(params, dependencies.targets[0]!.index);\n const breakerContext = () => ({ requestId, state: middlewareState, signal: params.signal });\n\n if (soleTarget) {\n // An abort during `wrap` must not claim the trial: the call would then fail\n // before any outcome is recorded and leave the breaker stuck mid-trial.\n if (params.signal?.aborted) {\n throw new LLMError('LLM request aborted', 'aborted');\n }\n\n const checking = dependencies.targets[0]!.executor.assertBreakerClosed(\n soleModel,\n breakerContext(),\n );\n // Only a breaker with `prepare` hands back something to wait for.\n if (checking) await checking;\n }\n\n try {\n let meta: CallMeta | undefined;\n const captureMeta = async <V>(result: Promise<{ value: V; meta?: CallMeta }>) => {\n const settled = await result;\n meta = settled.meta;\n return settled.value;\n };\n\n if (params.stream) {\n // Refund and reporting wait on `finalResult`, since the outcome is only\n // known after `call()` has returned the stream.\n const value = await withReservedUsageForStream(\n params,\n () =>\n captureMeta(\n executeLogicalStreamCall(dependencies, params, requestId, soleTarget, middlewareState),\n ),\n params.signal,\n onRefundError,\n );\n\n // Wrapped inside `wrap`, so middleware hands back the same cancelling `chunks`.\n return { value: cancelOnBreak(value, breakController), meta };\n }\n\n const value = await withReservedUsage(\n params,\n false,\n () =>\n captureMeta(\n executeLogicalCall(dependencies, params, requestId, soleTarget, middlewareState),\n ),\n params.signal,\n onRefundError,\n );\n\n return { value, meta };\n } catch (error) {\n // A trial may have been claimed above; releasing is idempotent if the\n // fallback chain already did.\n if (soleTarget) {\n dependencies.targets[0]!.executor.releaseBreakerTrial(soleModel, breakerContext());\n }\n throw error;\n }\n}\n","import { LLMError } from '../../../../types/errors.js';\nimport { chainSignal } from '../../../utils/chain.utils.js';\nimport { recordChainStart } from './middleware.utils.js';\n\nimport type { CallParams, CallResult, MiddlewareStateBag } from '../../../../types/index.js';\n\n/** At most this many chains started with `next.again()` per call, counted across nested layers. */\nexport const MAX_RERUNS_PER_CALL = 4;\n\n/** One chain of the layers inside a `wrap`: the main chain (0) or a rerun (1 and up). */\nexport interface Chain {\n number: number;\n /** The params this chain runs with: the call's, or a copy with this chain's signal. */\n params: CallParams<unknown>;\n}\n\ntype Run = (chain: Chain) => Promise<CallResult>;\n\n/** The chain a `keep` matched: its number, and the result it produced itself. */\nexport interface KeptChain {\n number: number;\n result: CallResult;\n}\n\ninterface Entry {\n number: number;\n controller: AbortController;\n result?: CallResult;\n}\n\n/** One `reruns: true` layer's chains: start, limit, keep one, cancel the rest. */\nexport class ChainSet {\n private readonly entries: Entry[] = [];\n /** Results in the order they resolved, for a `wrap` that throws after one did. */\n private readonly resolved: CallResult[] = [];\n\n constructor(\n private readonly incoming: Chain,\n /** Shared by every layer of the call. */\n private readonly reruns: { count: number },\n /** This layer's position in the `wrap` nesting. */\n private readonly layer: number,\n private readonly state: MiddlewareStateBag,\n ) {}\n\n /** The main chain: same number and `meta` as the incoming chain, but cancellable. */\n main(run: Run): Promise<CallResult> {\n return this.start(this.incoming.number, true, run);\n }\n\n get canRerun(): boolean {\n return this.reruns.count < MAX_RERUNS_PER_CALL;\n }\n\n /** A new chain. Its params drop `meta`, so it never writes the caller's while running. */\n rerun(run: Run): Promise<CallResult> {\n if (!this.canRerun) {\n return Promise.reject(\n new LLMError(\n `At most ${MAX_RERUNS_PER_CALL} chains can run again per call`,\n 'invalid_params',\n ),\n );\n }\n\n this.reruns.count++;\n recordChainStart(this.state, this.reruns.count, {\n parent: this.incoming.number,\n layer: this.layer,\n });\n\n return this.start(this.reruns.count, false, run);\n }\n\n get startedAny(): boolean {\n return this.entries.length > 0;\n }\n\n firstResolved(): CallResult | undefined {\n return this.resolved[0];\n }\n\n /**\n * Cancels every chain whose result isn't `kept`, pending ones included, and returns the kept\n * chain's number and own result. `kept` undefined cancels them all.\n */\n keep(kept: CallResult | undefined): KeptChain | undefined {\n // The result itself first, then any chain whose value it returned: a `wrap` may rebuild the\n // `CallResult` around a chain's value. Only one chain is kept, even when values are equal.\n const keptEntry =\n kept === undefined\n ? undefined\n : (this.entries.find((entry) => entry.result === kept) ??\n this.entries.find(\n (entry) => entry.result !== undefined && entry.result.value === kept.value,\n ));\n\n for (const entry of this.entries) {\n if (entry !== keptEntry) entry.controller.abort();\n }\n\n return keptEntry?.result ? { number: keptEntry.number, result: keptEntry.result } : undefined;\n }\n\n private start(number: number, keepMeta: boolean, run: Run): Promise<CallResult> {\n const controller = new AbortController();\n const entry: Entry = { number, controller };\n const params = this.incoming.params;\n\n this.entries.push(entry);\n\n // A `run` that throws before returning a promise still rejects, never throws from here.\n let promise: Promise<CallResult>;\n\n try {\n promise = run({\n number,\n params: {\n ...params,\n signal: chainSignal(params.signal, controller.signal, number),\n ...(keepMeta ? {} : { meta: undefined }),\n },\n });\n } catch (error) {\n promise = Promise.reject(error);\n }\n\n // Records the result, and keeps a chain nobody awaits from rejecting unhandled.\n promise.then(\n (result) => {\n entry.result = result;\n this.resolved.push(result);\n },\n () => {},\n );\n\n return promise;\n }\n}\n","import { isLLMError } from '../../types/errors.js';\nimport { callFactsFor, callScopeFor, noopEmit } from '../utils/callScope.utils.js';\nimport { logError } from '../utils/logger.utils.js';\nimport { modelForTarget } from './logicalCall.js';\nimport { describeTargets, narrowTargets, type ResolvedTarget } from './targetOrder.js';\nimport { ChainSet, type Chain, type KeptChain } from './utils/middleware/chains.utils.js';\nimport {\n emitEvent,\n reclassifyMiddlewareThrow,\n middlewareLabel,\n recordWrapLayers,\n resolveEnabled,\n withOwn,\n} from './utils/middleware/middleware.utils.js';\nimport { createOnceAsync } from './utils/once.utils.js';\n\nimport type { Logger } from '../../logger.js';\nimport type {\n CallParams,\n CallResult,\n MiddlewareStateBag,\n PreDispatchContext,\n VernLLMEvent,\n VernLLMMiddleware,\n WrapNext,\n WrapNextOptions,\n} from '../../types/index.js';\nimport type { MiddlewarePipeline } from '../resolveMiddlewareOrder.js';\nimport type { CallExecutor } from './callExecutor.js';\n\n/** Entries already warned about a returned value no chain produced, so each warns once. */\nconst warnedNoChainKept = new WeakSet<VernLLMMiddleware>();\n\n/**\n * Everything `runOperation` needs from `VernLLM` itself, gathered into\n * one small object so it can live outside the class as a plain,\n * independently testable function instead of a private method.\n */\nexport interface RunOperationDependencies {\n /**\n * Middleware order, built once at construction. `wrap` nests by `wrapOrder`; labels and events\n * use `transformOrder`.\n */\n pipeline: MiddlewarePipeline;\n /** The primary target, used to build the `previewRequest` handed to every `wrap` (and the `primaryProvider`/`primaryModel` its `ctx` carries). */\n primaryExecutor: CallExecutor;\n /** Every configured target in declared order, the pool a `wrap`'s `next({ targets })` picks from. */\n targets: readonly ResolvedTarget[];\n /** See `VernLLMOptions.middlewareTimeoutMs`. Bounds `transform` and a function `enabled`; `wrap` itself is never bounded by this. */\n middlewareTimeoutMs: number;\n logger: Logger;\n /** Reports the `'middleware'` trace event for an `enabled_skip` or `wrap_short_circuit`. */\n reportEvent: (event: VernLLMEvent) => void;\n}\n\n/**\n * Ends a `reruns` layer: cancels every chain but the one `result` came from, and returns it. The\n * main chain wrote the caller's `meta` itself; a kept rerun's own `meta` is written here, never the\n * returned wrapper's.\n */\nfunction settleChains(chains: ChainSet, result: CallResult, chain: Chain): KeptChain | undefined {\n const kept = chains.keep(result);\n\n if (kept !== undefined && kept.number !== chain.number && chain.params.meta) {\n chain.params.meta.current = kept.result.meta;\n }\n\n return kept;\n}\n\nfunction warnNoChainKept(logger: Logger, middleware: VernLLMMiddleware, label: string): void {\n if (warnedNoChainKept.has(middleware)) return;\n\n warnedNoChainKept.add(middleware);\n logger.warn(\n `[VernLLM] middleware \"${label}\" returned a value no chain produced; every chain was cancelled`,\n );\n}\n\n/** One layer of the nesting: the order it may use, and the chain it runs in. */\ntype Inner = (targets: readonly ResolvedTarget[], chain: Chain) => Promise<CallResult>;\n\n/**\n * Wraps one whole logical call in every applicable `wrap`, lower priority outermost. `ctx` is a\n * `PreDispatchContext` with a preview request from the primary, since no attempt has started yet.\n * A `wrap` that never calls `next()` skips everything inside it.\n *\n * `targets` is the order the call starts with. Each `wrap` sees it as `ctx.targets` and may\n * reorder or drop through `next({ targets })`, never widen it, and `coreOperation` runs the order\n * that is left.\n */\nexport async function runOperation(\n dependencies: RunOperationDependencies,\n params: CallParams<unknown>,\n requestId: string,\n state: MiddlewareStateBag,\n targets: readonly ResolvedTarget[],\n coreOperation: (targets: readonly ResolvedTarget[], chain: Chain) => Promise<CallResult>,\n /**\n * True when `cachedCall()` already wraps this call, so `wrap` runs once per logical call. Keyed\n * by the params object, not `requestId`, since concurrent `cachedCall()`s can share one.\n */\n skipWrap = false,\n): Promise<CallResult> {\n const { wrapOrder, transformOrder, names, transformNames } = dependencies.pipeline;\n const main: Chain = { number: 0, params };\n\n if (wrapOrder.length === 0 || skipWrap) {\n return coreOperation(targets, main);\n }\n\n const primary = dependencies.primaryExecutor;\n const { model, request } = primary.previewRequest(params);\n\n // `position` can reorder `wrapOrder`, so labels come from each entry's `transformOrder` index to\n // match `registeredMiddlewareNames`.\n const transformIndexByEntry = new Map(transformOrder.map((entry, index) => [entry, index]));\n\n recordWrapLayers(state, new Map(wrapOrder.map((entry, index) => [entry, index])));\n\n // Reruns started so far, shared by every layer of the call.\n const reruns = { count: 0 };\n\n // Each level takes the order left by the levels outside it, and the chain it runs in.\n let next: Inner = coreOperation;\n\n for (let middlewareIndex = wrapOrder.length - 1; middlewareIndex >= 0; middlewareIndex--) {\n const middleware = wrapOrder[middlewareIndex]!;\n const label = middlewareLabel(middleware, transformIndexByEntry.get(middleware)!);\n const inner = next;\n\n next = async (current, chain): Promise<CallResult> => {\n const ctx: PreDispatchContext = {\n stage: 'pre-dispatch',\n requestId,\n primaryProvider: primary.providerName,\n primaryAdapter: primary.adapter,\n primaryModel: model,\n targets: describeTargets(current, (index) => modelForTarget(params, index)),\n capabilities: { supportsJsonObjectMode: primary.jsonObjectModeSupported },\n signal: chain.params.signal,\n ...(chain.number > 0 ? { chain: chain.number } : {}),\n state,\n own: {},\n emit: noopEmit,\n context: callScopeFor(state)?.context,\n ...callFactsFor(state),\n registeredMiddlewareNames: names,\n transformMiddlewareNames: transformNames,\n };\n\n const isEnabled = await resolveEnabled(\n middleware,\n ctx,\n label,\n dependencies.middlewareTimeoutMs,\n dependencies.logger,\n );\n\n if (!isEnabled) {\n if (middleware.enabled !== undefined) {\n emitEvent(\n { kind: 'middleware', requestId, middleware: label, hook: 'enabled_skip' },\n ctx,\n dependencies.reportEvent,\n transformOrder,\n dependencies.middlewareTimeoutMs,\n dependencies.logger,\n );\n }\n return inner(current, chain);\n }\n\n if (!middleware.wrap) return inner(current, chain);\n\n // Only an entry with `reruns` gets chains of its own; every other entry passes the incoming\n // chain straight through, so it runs exactly as it always did.\n const chains =\n middleware.reruns === true\n ? new ChainSet(chain, reruns, middlewareIndex, state)\n : undefined;\n\n // Narrowed against what this layer may use, for `next()` and `next.again()` alike.\n const narrow = (requestedTargets: readonly string[] | undefined) =>\n narrowTargets(dependencies.targets, current, requestedTargets, (name) =>\n dependencies.logger.warn(\n `[VernLLM:${requestId}] middleware \"${label}\" asked for target \"${name}\", which an outer layer removed; ignoring it`,\n ),\n );\n\n // The first `next()` call runs `inner` and reads this synchronously, so a later call's\n // options change nothing, like its result.\n let requested: readonly string[] | undefined;\n const onceNext = createOnceAsync(async () => {\n const targetsLeft = narrow(requested);\n\n return chains\n ? chains.main((mainChain) => inner(targetsLeft, mainChain))\n : inner(targetsLeft, chain);\n });\n const wrapNext = ((options?: WrapNextOptions): Promise<CallResult> => {\n requested = options?.targets;\n return onceNext.call();\n }) as WrapNext;\n\n if (chains) {\n const again = (options?: WrapNextOptions): Promise<CallResult> => {\n // Validated before a chain starts, so a bad `targets` rejects like next()'s does and\n // doesn't use up one of the call's reruns.\n let targetsLeft: ResolvedTarget[];\n\n try {\n targetsLeft = narrow(options?.targets);\n } catch (error) {\n return Promise.reject(error);\n }\n\n return chains.rerun((rerunChain) => inner(targetsLeft, rerunChain));\n };\n\n // A getter, so `next.again` reads undefined once the call has used its reruns.\n Object.defineProperty(wrapNext, 'again', {\n get: () => (chains.canRerun ? again : undefined),\n });\n }\n\n try {\n const result = await middleware.wrap(request, wrapNext, withOwn(ctx, middleware, label));\n\n if (!onceNext.wasCalled() && !chains?.startedAny) {\n emitEvent(\n { kind: 'middleware', requestId, middleware: label, hook: 'wrap_short_circuit' },\n ctx,\n dependencies.reportEvent,\n transformOrder,\n dependencies.middlewareTimeoutMs,\n dependencies.logger,\n );\n }\n\n if (chains) {\n const kept = settleChains(chains, result, chain);\n\n if (kept === undefined && chains.firstResolved() !== undefined) {\n warnNoChainKept(dependencies.logger, middleware, label);\n }\n }\n\n return result;\n } catch (error) {\n const resolvedResult = chains ? chains.firstResolved() : onceNext.resolvedValue();\n\n if (resolvedResult !== undefined) {\n // A deliberate refusal of the result, not a bug in post-processing: pass it through.\n if (isLLMError(error) && error.code === 'content_blocked') {\n chains?.keep(undefined);\n throw error;\n }\n\n // Rule 3: thrown strictly after next() already resolved\n // successfully. A bug in post-processing can never turn a\n // successful, already-billed call into a false failure.\n logError(\n dependencies.logger,\n `[VernLLM] middleware \"${label}\".wrap threw after next() resolved; keeping the original result`,\n error,\n );\n if (chains) settleChains(chains, resolvedResult, chain);\n return resolvedResult;\n }\n\n // Rules 1/2: thrown before next() was called, or before it\n // resolved. Passed through normalizeError first so a\n // recognizable status/network error, or an already-built\n // LLMError, keeps its own classification. A chain still running is cancelled.\n chains?.keep(undefined);\n throw reclassifyMiddlewareThrow(error, label, ctx.signal);\n }\n };\n }\n\n return next(targets, main);\n}\n","import { isJson, type CallFacts, type CallScope } from '../../../utils/callScope.utils.js';\nimport { emitEvent } from './middleware.utils.js';\n\nimport type { Logger } from '../../../../logger.js';\nimport type { CallContext, VernLLMEvent, VernLLMMiddleware } from '../../../../types/index.js';\n\n/** The most `custom` events one call delivers. Anything past it is dropped, with one warning. */\nexport const MAX_CUSTOM_EVENTS_PER_CALL = 100;\n\n/** What `createCallScope` needs to deliver an event, all of it fixed for the instance. */\nexport interface CallScopeDependencies {\n reportEvent: (event: VernLLMEvent) => void;\n /** Already in `onEvent` order. */\n middleware: VernLLMMiddleware[];\n middlewareTimeoutMs: number;\n logger: Logger;\n}\n\ntype DropReason = 'invalid' | 'reentrant' | 'limit';\n\n/**\n * The scope for one logical call, holding its `context`. `emitCustom` validates the event and delivers it through the\n * same `emitEvent` every other event uses, so it reaches `onEvent` and every enabled\n * middleware's `onEvent`, the emitter included.\n *\n * A handler can emit from inside `onEvent`, so two guards keep that from looping: an emit made\n * synchronously while a custom event is being delivered is dropped, and a call delivers at most\n * `MAX_CUSTOM_EVENTS_PER_CALL`. The second also covers a loop through an async `enabled`, whose\n * delivery is deferred and so escapes the first. Each drop is warned once per call.\n */\nexport function createCallScope(\n dependencies: CallScopeDependencies,\n context: CallContext | undefined,\n facts: CallFacts = {},\n): CallScope {\n const { reportEvent, middleware, middlewareTimeoutMs, logger } = dependencies;\n\n let delivered = 0;\n let delivering = false;\n const warned = new Set<DropReason>();\n\n return {\n context,\n facts,\n emitCustom(name, data, source, ctx) {\n const drop = (reason: DropReason, message: string): void => {\n if (warned.has(reason)) return;\n\n warned.add(reason);\n logger.warn(`[VernLLM:${ctx.requestId}] middleware \"${source}\" ${message}`);\n };\n\n if (!isValidCustomEvent(name, data)) {\n drop(\n 'invalid',\n 'called ctx.emit with an empty name or data that is not plain JSON, dropping the event',\n );\n return;\n }\n\n if (delivering) {\n drop(\n 'reentrant',\n `emitted \"${name}\" while a custom event was being delivered, dropping it`,\n );\n return;\n }\n\n if (delivered >= MAX_CUSTOM_EVENTS_PER_CALL) {\n drop(\n 'limit',\n `emitted more than ${MAX_CUSTOM_EVENTS_PER_CALL} custom events in one call, dropping the rest`,\n );\n return;\n }\n\n delivered++;\n delivering = true;\n\n try {\n emitEvent(\n {\n kind: 'custom',\n requestId: ctx.requestId,\n name,\n source,\n ...(data === undefined ? {} : { data }),\n },\n ctx,\n reportEvent,\n middleware,\n middlewareTimeoutMs,\n logger,\n );\n } finally {\n delivering = false;\n }\n },\n };\n}\n\n/** `data` may be absent. A throw, from data nested deep enough to overflow the stack, is invalid. */\nfunction isValidCustomEvent(name: unknown, data: unknown): boolean {\n if (typeof name !== 'string' || name === '') return false;\n\n try {\n return data === undefined || isJson(data);\n } catch {\n return false;\n }\n}\n","import { fullJitter } from '../../execution/utils/retry/retry.utils.js';\n\nimport type {\n CircuitBreakerCallContext,\n CircuitState,\n CooldownBackoff,\n ExponentialBackoffOptions,\n} from '../../../circuitBreaker.js';\nimport type { LLMErrorCode } from '../../../types/errors.js';\n\n/**\n * Jitters only the growth above `baseCooldownMs`, so several\n * instances don't reopen in lockstep but none ever cools down for less\n * than the configured base.\n */\nexport function buildCooldownBackoff(\n option: ExponentialBackoffOptions | CooldownBackoff | undefined,\n): CooldownBackoff | undefined {\n if (option === undefined) return undefined;\n if (typeof option === 'function') return option;\n\n const { multiplier, maxMs = Infinity } = option;\n return (reopenCount, baseCooldownMs) => {\n const exp = Math.min(baseCooldownMs * multiplier ** reopenCount, maxMs);\n // Only an explicit `maxMs` below the base may lower the floor; a\n // shrinking `multiplier` must not. The ternary also maps a NaN `exp` to the floor.\n const floor = Math.min(baseCooldownMs, maxMs);\n const upper = exp > floor ? exp : floor;\n return floor + fullJitter(upper - floor);\n };\n}\n\n/** Mutable state for one circuit, either the single shared one or one model's bucket under `isolateByModel`. */\nexport interface CircuitBucket {\n state: CircuitState;\n /** True consecutive failures since the last success. Reporting only, independent of `tripping`. */\n consecutiveFailures: number;\n openedAt: number;\n /** Non null only while `state` is half-open. */\n trial: { slotsRemaining: number; successes: number; failures: number } | null;\n /** Times this bucket has reopened after a failed trial. Feeds `cooldownBackoff`. */\n reopenCount: number;\n /** Failure counts by `LLMErrorCode`, `'unknown'` for a missing code. Attribution only. */\n failuresByReason: Map<LLMErrorCode | 'unknown', number>;\n /** Cooldown for this open period, sampled once so a jittered value doesn't change mid-cooldown. */\n cooldownMsForOpen: number;\n /** Breaker-wide generation this bucket last opened in, 0 if never opened. */\n openedInGeneration: number;\n}\n\nexport function newBucket(): CircuitBucket {\n return {\n state: 'closed',\n consecutiveFailures: 0,\n openedAt: 0,\n trial: null,\n reopenCount: 0,\n failuresByReason: new Map(),\n cooldownMsForOpen: 0,\n openedInGeneration: 0,\n };\n}\n\n/** Key a bucket lookup falls into when the call omitted `model` under `isolateByModel`. Also the `tripping` key for the single shared bucket when `isolateByModel` is off. */\nexport const UNLABELED_MODEL = '';\n\n/** Resolves the map key for a model, collapsing an omitted `model` to `UNLABELED_MODEL`. */\nexport function keyFor(model: string | undefined): string {\n return model ?? UNLABELED_MODEL;\n}\n\n/** Maps a call's `state` to the trial object it claimed a slot in, so a stale permit can be told apart from a current one. */\nexport const trialPermits = new WeakMap<object, object>();\n\n/** True if this outcome's call claimed a permit for `bucket`'s current trial. No `context` always counts, matching pre-permit-tracking behavior. */\nexport function claimsCurrentTrial(\n bucket: CircuitBucket,\n context: CircuitBreakerCallContext | undefined,\n): boolean {\n if (!context) return true;\n return trialPermits.get(context.state) === bucket.trial;\n}\n\n/** Records `code` (or `'unknown'` if omitted) against `bucket.failuresByReason`. */\nexport function attributeFailure(bucket: CircuitBucket, code: LLMErrorCode | undefined): void {\n const key = code ?? 'unknown';\n bucket.failuresByReason.set(key, (bucket.failuresByReason.get(key) ?? 0) + 1);\n}\n\n/** Clears a bucket's failure history, as every return to closed does. */\nexport function resetBucket(bucket: CircuitBucket): void {\n bucket.consecutiveFailures = 0;\n bucket.trial = null;\n bucket.reopenCount = 0;\n bucket.failuresByReason.clear();\n}\n","import { RollingRatio } from './internal/rollingRatio.js';\nimport {\n attributeFailure,\n buildCooldownBackoff,\n claimsCurrentTrial,\n keyFor,\n newBucket,\n resetBucket,\n trialPermits,\n UNLABELED_MODEL,\n type CircuitBucket,\n} from './internal/utils/circuit-breaker/circuitBucket.utils.js';\nimport { validateMinCalls, validateRatio } from './internal/utils/validate.utils.js';\nimport { LLMError, type LLMErrorCode } from './types/errors.js';\n\nimport type { Logger } from './logger.js';\nimport type { MiddlewareStateBag } from './types/middleware.js';\n\n/** The call this mutation happened as part of, forwarded to `onStateChange` untouched. */\nexport interface CircuitBreakerCallContext {\n requestId: string;\n state: MiddlewareStateBag;\n signal?: AbortSignal;\n /** Omitted for calls before any attempt exists, like `assertClosed`'s pre-dispatch check. */\n attempt?: number;\n}\n\n/**\n * Fires after every real state change. `model` is the triggering call's resolved model. Shared by\n * the options and the adapter interface, so custom adapters report changes the same way.\n */\nexport type CircuitBreakerStateChangeHandler = (\n from: CircuitState,\n to: CircuitState,\n consecutiveFailures: number,\n model?: string,\n context?: CircuitBreakerCallContext,\n) => void;\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 onStateChange?: CircuitBreakerStateChangeHandler;\n /**\n * Track a separate circuit per resolved model instead of one shared\n * circuit. Default false. A call that omits `model` falls into one\n * shared bucket alongside every other call that also omits it.\n */\n isolateByModel?: boolean;\n /** Trial calls allowed through per half-open cycle. Default 1, clamped to at least 1. */\n halfOpenProbes?: number;\n /** Fraction of `halfOpenProbes` that must succeed to close the circuit. Default 1, clamped to `[0, 1]`. */\n halfOpenSuccessRatio?: number;\n /**\n * Grows `cooldownMs` on each repeat open instead of a fixed wait.\n * `{ multiplier, maxMs }` covers exponential growth; a `CooldownBackoff`\n * function covers anything else. Omitted means `cooldownMs` stays fixed.\n */\n cooldownBackoff?: ExponentialBackoffOptions | CooldownBackoff;\n /**\n * When failures open the circuit. `{ kind: 'consecutive', threshold }` (default) opens after that\n * many in a row; `{ kind: 'rolling', windowMs, minCalls, failureRatio }` opens once `minCalls`\n * calls in the window reach `failureRatio`. Invalid values throw `RangeError` at construction. A\n * custom `TrippingPolicy` is shared across models, keyed per model.\n */\n tripping?: TrippingOption;\n}\n\n/** Computes the cooldown for a bucket's `reopenCount`-th repeat open. */\nexport type CooldownBackoff = (reopenCount: number, baseCooldownMs: number) => number;\n\nexport interface ExponentialBackoffOptions {\n /** Growth factor applied per repeat open, e.g. 2 doubles each time. */\n multiplier: number;\n /** Upper bound on the computed cooldown, in ms. Default `Infinity`. */\n maxMs?: number;\n}\n\n/**\n * Decides when failures open the circuit. Keyed by model (or one shared key), so one instance\n * serves every bucket.\n */\nexport interface TrippingPolicy {\n onSuccess(key: string): void;\n /** Returns true if this failure should open the circuit for `key`. */\n onFailure(key: string): boolean;\n reset(key: string): void;\n /**\n * Called when `key`'s circuit is reset closed, so a keyed policy can drop that key's state. Not\n * called on an ordinary success, whose state a rolling window still needs.\n */\n forget?(key: string): void;\n}\n\nexport class ConsecutiveTripping implements TrippingPolicy {\n private failuresByKey = new Map<string, number>();\n\n constructor(private readonly threshold: number) {}\n\n onSuccess(key: string): void {\n // Delete rather than store 0: same count, and an idle key holds no memory.\n this.failuresByKey.delete(key);\n }\n\n onFailure(key: string): boolean {\n const next = (this.failuresByKey.get(key) ?? 0) + 1;\n this.failuresByKey.set(key, next);\n return next >= this.threshold;\n }\n\n reset(key: string): void {\n this.failuresByKey.set(key, 0);\n }\n\n forget(key: string): void {\n this.failuresByKey.delete(key);\n }\n}\n\nexport class RollingTripping implements TrippingPolicy {\n private ratiosByKey = new Map<string, RollingRatio>();\n\n constructor(\n private readonly windowMs: number,\n private readonly minCalls: number,\n private readonly failureRatio: number,\n ) {\n // Fail at construction rather than on the first recorded outcome.\n new RollingRatio(windowMs);\n validateMinCalls(minCalls);\n validateRatio(failureRatio, 'failureRatio');\n }\n\n private ratioFor(key: string): RollingRatio {\n let ratio = this.ratiosByKey.get(key);\n if (!ratio) {\n ratio = new RollingRatio(this.windowMs);\n this.ratiosByKey.set(key, ratio);\n }\n return ratio;\n }\n\n onSuccess(key: string): void {\n this.ratioFor(key).record(false);\n }\n\n onFailure(key: string): boolean {\n const ratio = this.ratioFor(key);\n ratio.record(true);\n return ratio.getCount() >= this.minCalls && ratio.getRatio() >= this.failureRatio;\n }\n\n reset(key: string): void {\n this.ratiosByKey.delete(key);\n }\n\n forget(key: string): void {\n this.ratiosByKey.delete(key);\n }\n}\n\n/** Not exported. Internal shorthand union for `CircuitBreakerOptions.tripping`. */\ntype TrippingOption =\n | { kind: 'consecutive'; threshold: number }\n | { kind: 'rolling'; windowMs: number; minCalls: number; failureRatio: number }\n | TrippingPolicy;\n\n/** Resolves the shorthand into a real `TrippingPolicy`. One instance total, shared safely across every bucket since it's keyed. */\nfunction buildTripping(option: TrippingOption): TrippingPolicy {\n if ('onFailure' in option) return option;\n\n return option.kind === 'consecutive'\n ? new ConsecutiveTripping(option.threshold)\n : new RollingTripping(option.windowMs, option.minCalls, option.failureRatio);\n}\n\nexport type CircuitState = 'closed' | 'open' | 'half-open';\n\n/**\n * What VernLLM needs from a breaker. Pass your own for cross-process coordination. `onStateChange`\n * is required so `circuit_state` events can't go missing; `() => {}` is fine. Omitting an optional\n * member makes that call a no-op, as with no breaker. `open` and `close` are optional, since a\n * distributed adapter may not allow forced transitions.\n */\nexport interface CircuitBreakerAdapter {\n /** Throws when the circuit is open (or half open with no trial slot free) for `model`. */\n assertClosed(model?: string, context?: CircuitBreakerCallContext): void;\n recordSuccess(model?: string, context?: CircuitBreakerCallContext): void;\n /** `code`, when present, is the failing call's `LLMErrorCode`. */\n recordFailure(model?: string, context?: CircuitBreakerCallContext, code?: LLMErrorCode): void;\n getState?(model?: string): CircuitState;\n /** Failure counts by `LLMErrorCode` for `model`'s bucket, `'unknown'` for one that carried no code. */\n getFailureBreakdown?(model?: string): Partial<Record<LLMErrorCode | 'unknown', number>>;\n /** Whether this adapter tracks failures per model, mirroring `CircuitBreakerOptions.isolateByModel`. Read by `warnIfModelUnsupported`'s diagnostic warning and by `VernLLM.getCircuitStates()`'s public output; omit if the notion doesn't apply to your adapter, `false` is assumed. */\n isolateByModel?: boolean;\n /** Manually opens the circuit, as if enough consecutive failures had just happened. Optional: an adapter that doesn't want external callers forcing a transition can omit it. */\n open?(model?: string, context?: CircuitBreakerCallContext): void;\n /** Manually closes the circuit, without requiring a real success first. Same opt-in reasoning as `open`. */\n close?(model?: string, context?: CircuitBreakerCallContext): void;\n /** Gives back a half-open trial slot when a call ends without `recordSuccess` or `recordFailure`. Idempotent, and a no-op for a call that holds no slot. */\n releaseTrial?(model?: string, context?: CircuitBreakerCallContext): void;\n /** Awaited right before `assertClosed` to refresh local state. Never blocks or fails a call: a rejection or `prepareTimeoutMs` is logged and the call carries on. */\n prepare?(model?: string, context?: CircuitBreakerCallContext): Promise<void>;\n /** How long to wait for `prepare`, in ms. Default 1000. */\n prepareTimeoutMs?: number;\n /** Live counterpart of `getState`, read by `VernLLM.readCircuitStates()`. */\n readState?(model?: string): Promise<CircuitState>;\n /** Receives the instance's `Logger` once, when `VernLLM` wires this adapter in. */\n setLogger?(logger: Logger): void;\n /**\n * Called after every real state change, after VernLLM reports its `circuit_state` event. A throw\n * here is caught and logged.\n */\n onStateChange: CircuitBreakerStateChangeHandler;\n}\n\n/**\n * Per retry VernLLM-instance circuit breaker. Tracks consecutive failures\n * across calls. Once the threshold is hit, short-circuits new calls with\n * LLMError('circuit_open') until the cooldown elapses and a trial succeeds.\n */\nexport class CircuitBreaker implements CircuitBreakerAdapter {\n private readonly cooldownMs: number;\n /** Satisfies `CircuitBreakerAdapter.onStateChange`, required there. Defaults to a no-op when `options.onStateChange` is omitted. */\n readonly onStateChange: CircuitBreakerStateChangeHandler;\n /** Whether this breaker tracks failures per model instead of one shared circuit. */\n readonly isolateByModel: boolean;\n private readonly halfOpenProbes: number;\n private readonly halfOpenSuccessRatio: number;\n private readonly cooldownBackoff?: CooldownBackoff;\n /** One instance, keyed per model internally. See `TrippingPolicy`. */\n private readonly tripping: TrippingPolicy;\n\n // Exactly one of these is used, chosen once at construction by `isolateByModel`.\n private readonly sharedBucket: CircuitBucket = newBucket();\n private readonly bucketsByModel = new Map<string, CircuitBucket>();\n\n /**\n * Breaker-wide rather than per bucket, since an evicted bucket is\n * recreated with no history and a per bucket generation would restart.\n */\n private generation = 0;\n /** Each call's generation at admission, keyed by its `state`, so its outcome can be told apart from a later generation's. */\n private readonly admittedInGeneration = new WeakMap<object, number>();\n\n constructor(options: CircuitBreakerOptions = {}) {\n const threshold = options.threshold ?? 5;\n this.cooldownMs = options.cooldownMs ?? 30_000;\n this.onStateChange = options.onStateChange ?? (() => {});\n this.isolateByModel = options.isolateByModel ?? false;\n // Clamped rather than thrown, same as `TokenBucket.give`.\n const rawProbes = options.halfOpenProbes;\n this.halfOpenProbes = Number.isFinite(rawProbes) ? Math.max(1, Math.floor(rawProbes!)) : 1;\n\n const rawRatio = options.halfOpenSuccessRatio;\n this.halfOpenSuccessRatio = Number.isFinite(rawRatio) ? Math.min(1, Math.max(0, rawRatio!)) : 1;\n\n this.cooldownBackoff = buildCooldownBackoff(options.cooldownBackoff);\n this.tripping = buildTripping(options.tripping ?? { kind: 'consecutive', threshold });\n }\n\n /**\n * Throws if the circuit is open and the cooldown hasn't elapsed, or if\n * half-open with every trial slot claimed. Otherwise claims a trial slot.\n */\n assertClosed(model?: string, context?: CircuitBreakerCallContext): void {\n const bucket = this.ensureBucketFor(model);\n\n if (bucket.state === 'closed') {\n this.markAdmitted(context);\n return;\n }\n\n if (bucket.state === 'open') {\n const elapsed = Date.now() - bucket.openedAt;\n const cooldown = bucket.cooldownMsForOpen;\n if (elapsed < cooldown) {\n throw new LLMError(\n `Circuit open, provider has failed ${bucket.consecutiveFailures} times in a row. Retry in ${Math.ceil((cooldown - elapsed) / 1000)}s.`,\n 'circuit_open',\n { code: 'circuit_cooling_down' },\n );\n }\n\n // Set before transition() so a synchronous re-entrant caller sees the slot as already claimed.\n bucket.trial = { slotsRemaining: this.halfOpenProbes - 1, successes: 0, failures: 0 };\n if (context) trialPermits.set(context.state, bucket.trial);\n this.markAdmitted(context);\n this.transition(bucket, 'half-open', model, context);\n return;\n }\n\n // state === 'half-open'\n if (!bucket.trial || bucket.trial.slotsRemaining <= 0) {\n throw new LLMError(\n 'Circuit half-open. Every trial slot is already in flight. Try again shortly.',\n 'circuit_open',\n { code: 'circuit_trial_in_flight' },\n );\n }\n\n bucket.trial.slotsRemaining -= 1;\n if (context) trialPermits.set(context.state, bucket.trial);\n this.markAdmitted(context);\n }\n\n recordSuccess(model?: string, context?: CircuitBreakerCallContext): void {\n const bucket = this.lookupBucket(model);\n\n if (!bucket) {\n return;\n }\n\n if (this.isFromEarlierGeneration(bucket, context)) return;\n\n if (bucket.state === 'half-open' && bucket.trial && claimsCurrentTrial(bucket, context)) {\n // Outcome recorded, so this call's permit is spent: a later\n // `releaseTrial` for the same call must not hand its slot back.\n if (context) trialPermits.delete(context.state);\n bucket.trial.successes += 1;\n this.settleTrialIfComplete(bucket, model, context);\n return;\n }\n\n // Stale trial permit: ignore, don't settle a trial it wasn't part of.\n if (bucket.state === 'half-open') return;\n\n // A call admitted before the circuit opened can finish after it. Only\n // a half-open trial may close an open circuit, never a late straggler.\n if (bucket.state === 'open') return;\n\n resetBucket(bucket);\n this.tripping.onSuccess(this.trippingKeyFor(model));\n this.transition(bucket, 'closed', model, context);\n\n // Drop only the idle bucket. The tripping state stays, since a rolling\n // window must keep this success and earlier failures to ever trip.\n if (this.isolateByModel && bucket.state === 'closed' && bucket.consecutiveFailures === 0) {\n this.dropBucket(model);\n }\n }\n\n /** `code`, when present, is the failing `LLMError`'s `code`. Missing attributes to `'unknown'`. */\n recordFailure(model?: string, context?: CircuitBreakerCallContext, code?: LLMErrorCode): void {\n const bucket = this.ensureBucketFor(model);\n\n if (this.isFromEarlierGeneration(bucket, context)) return;\n\n if (bucket.state === 'half-open' && bucket.trial && claimsCurrentTrial(bucket, context)) {\n if (context) trialPermits.delete(context.state);\n bucket.trial.failures += 1;\n attributeFailure(bucket, code);\n this.settleTrialIfComplete(bucket, model, context);\n return;\n }\n\n // Stale trial permit: ignore, don't fall through to the closed-state counter below.\n if (bucket.state === 'half-open') return;\n\n // A late failure from a call admitted before the circuit opened would\n // otherwise re-trip it, restamping `openedAt` and extending the cooldown.\n if (bucket.state === 'open') return;\n\n bucket.consecutiveFailures += 1;\n attributeFailure(bucket, code);\n\n if (this.tripping.onFailure(this.trippingKeyFor(model))) {\n this.openBucket(bucket, model, context);\n }\n }\n\n /**\n * Gives back the trial slot `context`'s call claimed when it ended without an outcome. Safe to\n * call on any failure path: a no-op without a live permit.\n */\n releaseTrial(model?: string, context?: CircuitBreakerCallContext): void {\n if (!context) return;\n\n const bucket = this.lookupBucket(model);\n if (!bucket || bucket.state !== 'half-open' || !bucket.trial) return;\n if (!claimsCurrentTrial(bucket, context)) return;\n\n trialPermits.delete(context.state);\n bucket.trial.slotsRemaining += 1;\n }\n\n /**\n * The current state. Ignores `model` unless isolated by model. An open circuit past its cooldown\n * reports `'half-open'`, though the real transition waits for the next call.\n */\n getState(model?: string): CircuitState {\n const bucket = this.lookupBucket(model);\n if (!bucket) return 'closed';\n if (bucket.state === 'open' && Date.now() - bucket.openedAt >= bucket.cooldownMsForOpen) {\n return 'half-open';\n }\n return bucket.state;\n }\n\n /** Failure counts by `LLMErrorCode` for `model`'s bucket. Returned as a plain object copy. */\n getFailureBreakdown(model?: string): Partial<Record<LLMErrorCode | 'unknown', number>> {\n const bucket = this.lookupBucket(model);\n return bucket ? Object.fromEntries(bucket.failuresByReason) : {};\n }\n\n /** Manually opens the circuit, as if `threshold` consecutive failures had just happened. */\n open(model?: string, context?: CircuitBreakerCallContext): void {\n const bucket = this.ensureBucketFor(model);\n bucket.trial = null;\n this.openBucket(bucket, model, context);\n }\n\n /** Manually closes the circuit and resets its failure count, without requiring a real success first. */\n close(model?: string, context?: CircuitBreakerCallContext): void {\n const bucket = this.ensureBucketFor(model);\n\n resetBucket(bucket);\n this.tripping.reset(this.trippingKeyFor(model));\n this.transition(bucket, 'closed', model, context);\n\n // transition() may have synchronously re-entered, so re-check state rather than assuming it still holds.\n if (this.isolateByModel && bucket.state === 'closed' && bucket.consecutiveFailures === 0) {\n this.forgetModel(model);\n }\n }\n\n /**\n * Stamps the open time and cooldown, then transitions to open. Callers have already cleared\n * `trial`.\n */\n private openBucket(\n bucket: CircuitBucket,\n model: string | undefined,\n context: CircuitBreakerCallContext | undefined,\n ): void {\n bucket.openedAt = Date.now();\n bucket.cooldownMsForOpen = this.computeCooldown(bucket);\n bucket.openedInGeneration = ++this.generation;\n this.transition(bucket, 'open', model, context);\n }\n\n /** Computes and clamps the cooldown for `bucket`'s current `reopenCount`. Called once, on open. */\n private computeCooldown(bucket: CircuitBucket): number {\n if (!this.cooldownBackoff) return this.cooldownMs;\n\n const computed = this.cooldownBackoff(bucket.reopenCount, this.cooldownMs);\n if (Number.isNaN(computed)) return 0;\n return Math.max(0, computed);\n }\n\n private markAdmitted(context: CircuitBreakerCallContext | undefined): void {\n if (context) this.admittedInGeneration.set(context.state, this.generation);\n }\n\n /**\n * True if this call was admitted before `bucket` last opened, so its outcome belongs to an ended\n * generation. A call without context always counts.\n */\n private isFromEarlierGeneration(\n bucket: CircuitBucket,\n context: CircuitBreakerCallContext | undefined,\n ): boolean {\n if (!context) return false;\n const admitted = this.admittedInGeneration.get(context.state);\n return admitted !== undefined && admitted < bucket.openedInGeneration;\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 return this.bucketsByModel.get(keyFor(model));\n }\n\n /**\n * The key for `tripping`: per model when isolated by model, otherwise one shared key, matching\n * which bucket a call lands in.\n */\n private trippingKeyFor(model: string | undefined): string {\n return this.isolateByModel ? keyFor(model) : UNLABELED_MODEL;\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 = keyFor(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 /** Drops an idle model's bucket, keeping its tripping state. */\n private dropBucket(model: string | undefined): void {\n this.bucketsByModel.delete(keyFor(model));\n }\n\n /** Drops a reset model's bucket and lets `tripping` release that key's state too. */\n private forgetModel(model: string | undefined): void {\n this.dropBucket(model);\n this.tripping.forget?.(this.trippingKeyFor(model));\n }\n\n /** Every state mutation routes through here, so `onStateChange` fires exactly once per real change. */\n private transition(\n bucket: CircuitBucket,\n to: CircuitState,\n model: string | undefined,\n context: CircuitBreakerCallContext | undefined,\n ): 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, context);\n }\n\n /** Once every admitted trial has reported in, closes or reopens based on `halfOpenSuccessRatio`. */\n private settleTrialIfComplete(\n bucket: CircuitBucket,\n model: string | undefined,\n context: CircuitBreakerCallContext | undefined,\n ): void {\n const trial = bucket.trial;\n if (!trial || trial.successes + trial.failures < this.halfOpenProbes) return;\n\n const ratio = trial.successes / this.halfOpenProbes;\n bucket.trial = null;\n\n if (ratio >= this.halfOpenSuccessRatio) {\n resetBucket(bucket);\n // Reset rather than record a success, so failures from before the\n // circuit opened can't push a rolling window straight back over\n // its threshold. Same as the manual `close()`.\n this.tripping.reset(this.trippingKeyFor(model));\n this.transition(bucket, 'closed', model, context);\n\n if (this.isolateByModel && bucket.state === 'closed') {\n this.forgetModel(model);\n }\n return;\n }\n\n // Trial failed: reopen, reset the cooldown window, count the repeat.\n bucket.reopenCount += 1;\n this.openBucket(bucket, model, context);\n }\n}\n","import {\n CircuitBreaker,\n type CircuitBreakerAdapter,\n type CircuitBreakerOptions,\n type CircuitBreakerStateChangeHandler,\n} from '../../../circuitBreaker.js';\nimport { LLMError } from '../../../types/errors.js';\nimport { createMiddlewareStateBag } from '../../../types/middleware.js';\nimport { emitEvent } from '../../execution/utils/middleware/middleware.utils.js';\nimport { CUSTOM_ADAPTER } from '../adapterInfo.utils.js';\nimport { callFactsFor, callScopeFor, noopEmit } from '../callScope.utils.js';\nimport { chainFields } from '../chain.utils.js';\nimport { middlewareContextNames } from '../middlewareLabels.utils.js';\nimport { callHookSafely } from './../logger.utils.js';\nimport { makeEventReporter, reportRejection } from './circuitBreaker.utils.js';\n\nimport type { Logger } from '../../../logger.js';\nimport type { VernLLMEvent } from '../../../types/events.js';\nimport type { AdapterInfo, AttemptContext, VernLLMMiddleware } from '../../../types/index.js';\n\n/** The `circuitBreaker` option union, shared by `VernLLMOptions` and `buildCircuitBreaker`. */\nexport type CircuitBreakerOption = boolean | CircuitBreakerOptions | CircuitBreakerAdapter;\n\nconst REQUIRED_ADAPTER_METHOD_NAMES = [\n 'assertClosed',\n 'recordSuccess',\n 'recordFailure',\n 'onStateChange',\n] as const;\n\n/** Members only an adapter has. `onStateChange` is left out since plain options have it too. */\nconst ADAPTER_ONLY_METHOD_NAMES = ['assertClosed', 'recordSuccess', 'recordFailure'] as const;\n\n/**\n * Optional adapter members that must be functions. `isolateByModel` is left out since plain options\n * have it as a boolean.\n */\nconst OPTIONAL_FUNCTION_MEMBER_NAMES = [\n 'getState',\n 'getFailureBreakdown',\n 'open',\n 'close',\n 'releaseTrial',\n 'setLogger',\n 'prepare',\n 'readState',\n] as const;\n\n/** Any of `OPTIONAL_FUNCTION_MEMBER_NAMES` present but not callable, the same mistake `rateLimitAdapter.utils.ts` guards against for `getState`. */\nfunction invalidOptionalMembers(\n option: CircuitBreakerOptions | CircuitBreakerAdapter,\n): (typeof OPTIONAL_FUNCTION_MEMBER_NAMES)[number][] {\n const candidate = option as Partial<CircuitBreakerAdapter>;\n return OPTIONAL_FUNCTION_MEMBER_NAMES.filter(\n (name) => candidate[name] !== undefined && typeof candidate[name] !== 'function',\n );\n}\n\n/** `prepareTimeoutMs` present but not a finite number greater than 0. Only meaningful on an adapter, plain `CircuitBreakerOptions` has no such field. */\nfunction hasInvalidPrepareTimeout(option: CircuitBreakerOptions | CircuitBreakerAdapter): boolean {\n const { prepareTimeoutMs } = option as Partial<CircuitBreakerAdapter>;\n return (\n prepareTimeoutMs !== undefined && (!Number.isFinite(prepareTimeoutMs) || prepareTimeoutMs <= 0)\n );\n}\n\n/**\n * Classifies the option in one pass: plain options, a complete adapter, an incomplete adapter, or\n * options with an invalid optional member.\n */\nfunction classifyCircuitBreakerOption(option: CircuitBreakerOptions | CircuitBreakerAdapter): {\n /** At least one of the three adapter-only methods is present, so this is clearly an attempted adapter, not plain options. */\n attemptsAdapter: boolean;\n /** Required members not present as functions. Only meaningful when `attemptsAdapter` is true. */\n missing: (typeof REQUIRED_ADAPTER_METHOD_NAMES)[number][];\n /** Present-but-non-function optional members, checked regardless of `attemptsAdapter`, see `OPTIONAL_FUNCTION_MEMBER_NAMES`. */\n invalid: (typeof OPTIONAL_FUNCTION_MEMBER_NAMES)[number][];\n} {\n const candidate = option as Partial<CircuitBreakerAdapter>;\n return {\n attemptsAdapter: ADAPTER_ONLY_METHOD_NAMES.some(\n (name) => typeof candidate[name] === 'function',\n ),\n missing: REQUIRED_ADAPTER_METHOD_NAMES.filter((name) => typeof candidate[name] !== 'function'),\n invalid: invalidOptionalMembers(option),\n };\n}\n\n/**\n * Wraps a caller's `onStateChange` so every real change first reports a `circuit_state` event, then\n * calls the handler safely. Shared by the built in breaker and custom adapters.\n */\nfunction wrapOnStateChange(\n userOnStateChange: CircuitBreakerStateChangeHandler | undefined,\n providerName: string,\n defaultModel: string,\n reportEvent: (event: VernLLMEvent) => void,\n logger: Logger,\n middleware: VernLLMMiddleware[],\n middlewareTimeoutMs: number,\n isFallback: boolean,\n supportsJsonObjectMode: boolean,\n adapter: AdapterInfo,\n): CircuitBreakerStateChangeHandler {\n return (from, to, consecutiveFailures, model, context) => {\n const event: VernLLMEvent = {\n kind: 'circuit_state',\n provider: providerName,\n model: model ?? defaultModel,\n from,\n to,\n consecutiveFailures,\n };\n\n // `context` is absent when the breaker changes state outside any call:\n // called directly, or (for a shared adapter) a change another process\n // made. Middleware still need to see it, so it gets a fresh call\n // identity of its own, like a manual `openCircuit()`.\n const callContext = context ?? {\n requestId: globalThis.crypto.randomUUID(),\n state: createMiddlewareStateBag(),\n };\n\n const ctx: AttemptContext = {\n stage: 'attempt',\n requestId: callContext.requestId,\n requestedProvider: providerName,\n adapter,\n requestedModel: model ?? defaultModel,\n isFallbackAttempt: isFallback,\n // Most call sites (recordSuccess/recordFailure after a real\n // dispatch) thread a real 1 based attempt number through\n // `context.attempt`. Falls back to `1` for the sites that have\n // none, like `assertClosed`'s pre-dispatch check.\n attempt: callContext.attempt ?? 1,\n capabilities: { supportsJsonObjectMode },\n signal: callContext.signal,\n ...chainFields(callContext.signal),\n state: callContext.state,\n own: {},\n emit: noopEmit,\n context: callScopeFor(callContext.state)?.context,\n ...callFactsFor(callContext.state),\n ...middlewareContextNames(middleware),\n };\n\n emitEvent(event, ctx, reportEvent, middleware, middlewareTimeoutMs, logger);\n\n // A caller supplied onStateChange would otherwise be silently\n // discarded, since this wrapper replaces it. Chain it instead, same\n // try/catch treatment as every other user supplied callback so it\n // can't break breaker bookkeeping or the call that triggered it.\n if (!userOnStateChange) return;\n\n callHookSafely(logger, 'circuitBreaker.onStateChange', () =>\n userOnStateChange(from, to, consecutiveFailures, model, context),\n );\n };\n}\n\n/** One subscriber set per adapter, keyed weakly. See `wireAdapterOnStateChange`. */\nconst adapterSubscribers = new WeakMap<\n CircuitBreakerAdapter,\n Set<CircuitBreakerStateChangeHandler>\n>();\n\n/** Adapters that have already triggered the sharing warning below, so it fires once ever per adapter, not once per every additional build against it. */\nconst warnedAboutSharing = new WeakSet<CircuitBreakerAdapter>();\n\n/**\n * Subscribes a target to an adapter's state changes. The first call installs one dispatcher, rather\n * than wrapping again per target, and it calls the adapter's original handler once per transition\n * however many targets share it.\n */\nfunction wireAdapterOnStateChange(\n adapter: CircuitBreakerAdapter,\n subscriber: CircuitBreakerStateChangeHandler,\n logger: Logger,\n): void {\n let subscribers = adapterSubscribers.get(adapter);\n\n if (!subscribers) {\n subscribers = new Set();\n adapterSubscribers.set(adapter, subscribers);\n\n const originalOnStateChange = adapter.onStateChange;\n const currentSubscribers = subscribers;\n\n adapter.onStateChange = (from, to, consecutiveFailures, model, context) => {\n for (const sub of currentSubscribers) {\n callHookSafely(logger, 'circuitBreaker.onStateChange', () =>\n sub(from, to, consecutiveFailures, model, context),\n );\n }\n\n callHookSafely(logger, 'circuitBreaker.onStateChange', () =>\n originalOnStateChange(from, to, consecutiveFailures, model, context),\n );\n };\n } else if (!warnedAboutSharing.has(adapter)) {\n warnedAboutSharing.add(adapter);\n logger.warn(\n \"[VernLLM] circuitBreaker: this adapter instance is already wired to another target. circuit_state events for it will now be reported to both, each tagged with its own provider/model. If that's intentional (a breaker genuinely shared across targets or clients), no action needed. If not, e.g. constructing VernLLM repeatedly with the same adapter instance, each wiring is kept for the life of the process, review whether the adapter should be constructed fresh per target instead.\",\n );\n }\n\n subscribers.add(subscriber);\n}\n\n/**\n * Builds one target's breaker: a `CircuitBreaker`, the caller's adapter, or `undefined`. Built\n * before its executor, so it reports events through `onEvent` directly. Takes only the fields it\n * needs so primary and fallback targets use it alike.\n */\nexport function buildCircuitBreaker(\n circuitBreakerOption: CircuitBreakerOption | undefined,\n providerName: string,\n defaultModel: string,\n onEvent: ((event: VernLLMEvent) => void) | undefined,\n logger: Logger,\n middleware: VernLLMMiddleware[],\n middlewareTimeoutMs: number,\n isFallback: boolean,\n supportsJsonObjectMode: boolean,\n adapter: AdapterInfo = CUSTOM_ADAPTER,\n): CircuitBreakerAdapter | undefined {\n if (!circuitBreakerOption) return undefined;\n\n const reportEvent = makeEventReporter(onEvent, logger);\n\n const wrap = (userOnStateChange: CircuitBreakerStateChangeHandler | undefined) =>\n wrapOnStateChange(\n userOnStateChange,\n providerName,\n defaultModel,\n reportEvent,\n logger,\n middleware,\n middlewareTimeoutMs,\n isFallback,\n supportsJsonObjectMode,\n adapter,\n );\n\n if (typeof circuitBreakerOption === 'object') {\n const { attemptsAdapter, missing, invalid } =\n classifyCircuitBreakerOption(circuitBreakerOption);\n\n if (attemptsAdapter && missing.length > 0) {\n throw new LLMError(\n `circuitBreaker looks like a CircuitBreakerAdapter but is missing: ${missing.join(', ')}. All four members (${REQUIRED_ADAPTER_METHOD_NAMES.join(', ')}) are required.`,\n 'invalid_params',\n );\n }\n\n if (attemptsAdapter && hasInvalidPrepareTimeout(circuitBreakerOption)) {\n throw new LLMError(\n `circuitBreaker's prepareTimeoutMs (${String((circuitBreakerOption as Partial<CircuitBreakerAdapter>).prepareTimeoutMs)}) must be a finite number greater than 0. It is optional, omit it to use the default.`,\n 'invalid_params',\n );\n }\n\n if (invalid.length > 0) {\n const candidate = circuitBreakerOption as Partial<CircuitBreakerAdapter>;\n const described = invalid.map((name) => `${name} (${typeof candidate[name]})`).join(', ');\n\n throw new LLMError(\n `circuitBreaker's ${described} must be a function when present. ${invalid.length === 1 ? 'It is' : 'They are'} optional, omit entirely rather than assigning a non function value.`,\n 'invalid_params',\n );\n }\n\n // A complete adapter keeps its own state; VernLLM only subscribes through the shared\n // dispatcher. The dispatcher calls the adapter's original handler, so this subscriber passes\n // `undefined` to avoid calling it once per target.\n if (attemptsAdapter) {\n const adapter = circuitBreakerOption as CircuitBreakerAdapter;\n wireAdapterOnStateChange(adapter, wrap(undefined), logger);\n // Declared `void`, but an async adapter may return a promise anyway.\n reportRejection(\n logger,\n '[VernLLM] circuitBreaker.setLogger rejected',\n adapter.setLogger?.(logger),\n );\n\n return adapter;\n }\n }\n\n const breakerOptions =\n typeof circuitBreakerOption === 'object' ? circuitBreakerOption : undefined;\n\n return new CircuitBreaker({\n ...breakerOptions,\n onStateChange: wrap(breakerOptions?.onStateChange),\n });\n}\n","/**\n * A continuously refilling capacity. Per minute buckets refill at `capacity / 60000` per ms; a\n * concurrency bucket refills only through `give`. Mutable so AIMD can `resize()` it.\n */\nexport class TokenBucket {\n private available: number;\n private lastRefill = Date.now();\n\n constructor(\n private capacity: number,\n private 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 jump counts as no time passing, so it never shrinks `available`.\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 * Ms until `amount` is available, assuming nothing else takes from it. 0 if it already is,\n * `Infinity` for a bucket that only refills through `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 * Returns capacity, capped at `capacity`. Not floored at 0: a bad estimate can push it negative,\n * and refill corrects that.\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 /** Refills, then reports how much capacity is available right now. */\n getAvailable(): number {\n this.refill();\n return this.available;\n }\n\n /**\n * Changes capacity in place, clamping `available` on a shrink and rescaling the refill rate by\n * the same ratio.\n */\n resize(newCapacity: number): void {\n this.refill();\n\n if (this.refillPerMs > 0) {\n this.refillPerMs = (this.refillPerMs / this.capacity) * newCapacity;\n }\n\n this.capacity = newCapacity;\n this.available = Math.min(this.available, newCapacity);\n }\n}\n","import { LLMError } from '../../../types/errors.js';\nimport { MAX_TIMER_DELAY_MS } from '../../execution/utils/deadline.utils.js';\n\nimport type { AimdOptions, RateLimitOptions } from '../../../rateLimit.js';\n\n/**\n * Validates `estimateFraction`. Non-finite or `<= 0` would zero or invert the reservation, so it\n * throws; above 1 is only wasteful, so it is clamped.\n */\nexport function buildEstimateFraction(fraction: number | undefined): number {\n if (fraction === undefined) return 1;\n\n if (!Number.isFinite(fraction) || fraction <= 0) {\n throw new LLMError(\n `estimateFraction (${fraction}) must be a finite number greater than 0.`,\n 'invalid_params',\n );\n }\n\n return Math.min(fraction, 1);\n}\n\n/**\n * Validates and clamps `AimdOptions`. An out of range `decreaseFactor` or negative `increaseBy` is\n * clamped. `minCapacity` above `maxCapacity`, or either below 1, throws: every acquire takes 1, and\n * a ceiling of 0 would also zero the refill rate with no way back.\n */\nexport function buildAimdOptions(option: AimdOptions | undefined): AimdOptions | undefined {\n if (!option) return undefined;\n\n const assertFinite = (name: 'minCapacity' | 'maxCapacity' | 'increaseBy' | 'decreaseFactor') => {\n if (!Number.isFinite(option[name])) {\n throw new LLMError(\n `aimd.${name} (${option[name]}) must be a finite number.`,\n 'invalid_params',\n );\n }\n };\n\n for (const name of ['minCapacity', 'maxCapacity', 'increaseBy', 'decreaseFactor'] as const) {\n assertFinite(name);\n }\n\n if (option.minCapacity < 1 || option.maxCapacity < 1) {\n throw new LLMError(\n `aimd.minCapacity (${option.minCapacity}) and aimd.maxCapacity (${option.maxCapacity}) must both be at least 1, since the requests bucket always takes 1 per acquire; a capacity below 1 could never be satisfied.`,\n 'invalid_params',\n );\n }\n\n if (option.minCapacity > option.maxCapacity) {\n throw new LLMError(\n `aimd.minCapacity (${option.minCapacity}) must not exceed aimd.maxCapacity (${option.maxCapacity}).`,\n 'invalid_params',\n );\n }\n\n return {\n increaseBy: Math.max(0, option.increaseBy),\n decreaseFactor: Math.min(1, Math.max(Number.MIN_VALUE, option.decreaseFactor)),\n minCapacity: option.minCapacity,\n maxCapacity: option.maxCapacity,\n proactiveFloor: option.proactiveFloor ?? 0,\n };\n}\n\n/**\n * Validates the bucket and queue limits. Each mistake would otherwise misbehave silently: NaN reads\n * as unlimited, a negative ceiling blocks everything, `Infinity` or an out of range `maxQueueMs`\n * times out at once, and a ceiling between 0 and 1 can never be met. `0` stays valid where it means\n * unlimited.\n */\nexport function assertValidLimits(options: RateLimitOptions): void {\n const invalid = (message: string): never => {\n throw new LLMError(message, 'invalid_params');\n };\n\n for (const name of ['requestsPerMinute', 'tokensPerMinute'] as const) {\n const value = options[name];\n if (value === undefined || value === 0) continue;\n\n if (!Number.isFinite(value) || value < 1) {\n invalid(`${name} (${value}) must be 0 (unlimited) or a finite number of at least 1.`);\n }\n }\n\n // A fractional slot count can't describe calls in flight.\n for (const name of ['maxConcurrent', 'maxQueueSize'] as const) {\n const value = options[name];\n if (value === undefined) continue;\n\n if (!Number.isInteger(value) || value < 0) {\n invalid(`${name} (${value}) must be a non-negative integer (0 means unlimited).`);\n }\n }\n\n const { maxQueueMs } = options;\n if (\n maxQueueMs !== undefined &&\n (!Number.isFinite(maxQueueMs) || maxQueueMs < 0 || maxQueueMs > MAX_TIMER_DELAY_MS)\n ) {\n invalid(\n `maxQueueMs (${maxQueueMs}) must be a finite number from 0 to ${MAX_TIMER_DELAY_MS}. Pass 0 to wait indefinitely.`,\n );\n }\n\n const { aimd } = options;\n if (!aimd) return;\n\n // Without it there is no ceiling to adjust, so AIMD would do nothing.\n if (!options.requestsPerMinute) {\n invalid('aimd requires requestsPerMinute to be set.');\n }\n\n const floor = aimd.proactiveFloor;\n if (floor !== undefined && (!Number.isFinite(floor) || floor < 0)) {\n invalid(`aimd.proactiveFloor (${floor}) must be a finite number that is not negative.`);\n }\n}\n","import type { WireRequest } from '../../../rateLimit.js';\n\n/**\n * Tokens reserved per image by `defaultEstimateTokens`. Providers bill an\n * image by its pixel dimensions, not its base64 size, and a large image\n * lands around 1,100 to 1,600 tokens on every supported provider. The top\n * of that range errs toward over reserving, which `release` reconciles\n * against real usage anyway.\n */\nconst IMAGE_TOKEN_ESTIMATE = 1_600;\n\n/** Counts text chars and images in one message's content, so base64 image data is never read as text. */\nfunction measureContent(content: unknown): { chars: number; images: number } {\n if (typeof content === 'string') return { chars: content.length, images: 0 };\n if (content === undefined || content === null) return { chars: 0, images: 0 };\n\n if (Array.isArray(content)) {\n let chars = 0;\n let images = 0;\n\n for (const block of content as Array<{ type?: unknown; text?: unknown }>) {\n if (block?.type === 'image') images += 1;\n else if (block?.type === 'text' && typeof block.text === 'string') chars += block.text.length;\n else chars += safeJsonLength(block);\n }\n\n return { chars, images };\n }\n\n return { chars: safeJsonLength(content), images: 0 };\n}\n\nfunction safeJsonLength(value: unknown): number {\n try {\n return JSON.stringify(value)?.length ?? 0;\n } catch {\n return 0;\n }\n}\n\n/**\n * Default `estimateTokens`: chars/4 over every message's text, plus\n * `IMAGE_TOKEN_ESTIMATE` per image, plus the requested `max_tokens`.\n */\nexport function defaultEstimateTokens(request: WireRequest): number {\n let chars = 0;\n let images = 0;\n\n for (const message of request.messages) {\n const measured = measureContent((message as { content?: unknown }).content);\n chars += measured.chars;\n images += measured.images;\n }\n\n return Math.ceil(chars / 4) + images * IMAGE_TOKEN_ESTIMATE + (request.max_tokens ?? 0);\n}\n","import { MAX_TIMER_DELAY_MS } from './internal/execution/utils/deadline.utils.js';\nimport { TokenBucket } from './internal/tokenBucket.js';\nimport {\n assertValidLimits,\n buildAimdOptions,\n buildEstimateFraction,\n} from './internal/utils/rate-limit/rateLimitOptions.utils.js';\nimport { defaultEstimateTokens } from './internal/utils/rate-limit/tokenEstimate.utils.js';\nimport { LLMError } from './types/errors.js';\n\nimport type { ProviderRateLimitHint } from './internal/utils/rate-limit/rateLimitHint.utils.js';\nimport type { Logger } from './logger.js';\nimport type { LLMClient } from './types/client.js';\n\nexport { defaultEstimateTokens };\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 or pass 0 for unlimited. Otherwise a finite number of at least 1. */\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 or\n * pass 0 for unlimited. Otherwise a finite number of at least 1.\n */\n tokensPerMinute?: number;\n /** Max requests in flight at once, as a non-negative integer. 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. At most 2147483647, the longest timer delay.\n */\n maxQueueMs?: number;\n /** Max queued calls before new ones reject immediately instead of queueing, as a non-negative integer. Default 0, unbounded. */\n maxQueueSize?: number;\n /**\n * Pre-flight token estimate for `tokensPerMinute`. Defaults to a\n * chars/4 heuristic over message text, a flat amount per image, plus\n * `max_tokens`.\n */\n estimateTokens?: (request: WireRequest) => number;\n /**\n * Scales the token estimate reserved against `tokensPerMinute`, since most calls use less than\n * `max_tokens`. Limiter bookkeeping only; `release` reconciles against real usage. Default 1,\n * must be above 0, clamped to 1.\n */\n estimateFraction?: number;\n /**\n * AIMD against the `requestsPerMinute` bucket. Omit for a fixed\n * ceiling, today's behavior. Requires `requestsPerMinute`; throws\n * without it.\n */\n aimd?: AimdOptions;\n}\n\nexport interface AimdOptions {\n /** Added to the requests-per-minute ceiling on every clean release. */\n increaseBy: number;\n /** Multiplied against the ceiling on a rate-limit signal. Must be greater than `0` and at most `1`; clamped otherwise. */\n decreaseFactor: number;\n /** Floor the ceiling never shrinks below. */\n minCapacity: number;\n /** Ceiling the bucket never grows above. */\n maxCapacity: number;\n /**\n * Shrink proactively once a provider hint reports `remainingRequests`\n * at or below this, before a real 429 happens. Default 0, meaning\n * off.\n */\n proactiveFloor?: number;\n}\n\nexport interface RateLimitState {\n /** Requests still available this window, or `undefined` if `requestsPerMinute` isn't configured. */\n requestsRemaining?: number;\n /** Tokens still available this window, or `undefined` if `tokensPerMinute` isn't configured. */\n tokensRemaining?: number;\n /** Concurrency slots currently in use, or `undefined` if `maxConcurrent` isn't configured. */\n concurrentInFlight?: number;\n}\n\nexport interface RateLimitAcquireResult {\n /**\n * Frees the concurrency slot and reconciles tokens when `actualTokens` is given. Only the first\n * call counts. Call it in a `finally` so a failed attempt never leaks a slot.\n */\n release: (actualTokens?: number, success?: boolean) => 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/** Same amount used by `tryAcquireBuckets` and `scheduleWake`, stated once so the two can't drift apart. tpm spends `estimatedTokens`, everything else spends 1. */\nfunction amountFor(reason: RateLimitReason, estimatedTokens: number): number {\n return reason === 'tpm' ? estimatedTokens : 1;\n}\n\n/** `requests`/`tokens` share this \"per minute\" refill formula. `concurrency` doesn't, it only refills via `release`. */\nfunction buildPerMinuteBucket(capacityPerMinute: number | undefined): TokenBucket | undefined {\n if (!capacityPerMinute) return undefined;\n return new TokenBucket(capacityPerMinute, capacityPerMinute / 60_000);\n}\n\n/**\n * Minimum gap between AIMD shrinks, one full refill. A burst of 429s from calls already in flight\n * describes one overload, so shrinking per response would collapse the ceiling from a single spike.\n */\nconst AIMD_SHRINK_WINDOW_MS = 60_000;\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 * What VernLLM needs from a limiter. Pass your own for cross-process coordination. Every method is\n * required; no-op the AIMD ones when unused, as `RateLimiter` does.\n */\nexport interface RateLimiterAdapter {\n estimate(request: WireRequest): number;\n acquire(estimatedTokens: number, signal?: AbortSignal): Promise<RateLimitAcquireResult>;\n signalRateLimit(): void;\n reactToRateLimitHint(hint: ProviderRateLimitHint | undefined): void;\n /** Optional: current bucket levels, for introspection. Omit if the adapter has no state worth reporting. */\n getState?(): RateLimitState;\n /** Optional: live bucket levels for `VernLLM.readRateLimitState()`, the async counterpart of `getState`. */\n readState?(): Promise<RateLimitState>;\n /** Optional: receives the instance's `Logger` once, when `VernLLM` wires this adapter in. */\n setLogger?(logger: Logger): void;\n}\n\n/**\n * Per target limiter: up to three buckets (requests, tokens, concurrency) behind one FIFO queue, so\n * a large call isn't starved by small ones. An omitted bucket never blocks.\n */\nexport class RateLimiter implements RateLimiterAdapter {\n private readonly requests?: TokenBucket;\n private readonly tokens?: TokenBucket;\n private readonly concurrency?: TokenBucket;\n\n /** Buckets in acquire precedence order (concurrency, rpm, tpm), omitted ones filtered out. Built once so order can't drift between `tryAcquireBuckets` and `scheduleWake`. */\n private readonly buckets: ReadonlyArray<{ reason: RateLimitReason; bucket: TokenBucket }>;\n\n private readonly maxQueueMs: number;\n private readonly maxQueueSize: number;\n private readonly estimateTokensFn: (request: WireRequest) => number;\n private readonly estimateFraction: number;\n private readonly aimd?: AimdOptions;\n\n private readonly queue: Waiter[] = [];\n\n /**\n * A scheduled recheck of the queue head when it waits on a bucket that refills by time, so the\n * queue doesn't wait for an unrelated acquire or release. A concurrency block only clears on\n * release.\n */\n private wakeTimer?: ReturnType<typeof setTimeout>;\n\n /** When AIMD last shrank the ceiling, see `AIMD_SHRINK_WINDOW_MS`. */\n private lastShrinkAt?: number;\n\n constructor(options: RateLimitOptions) {\n assertValidLimits(options);\n\n this.requests = buildPerMinuteBucket(options.requestsPerMinute);\n this.tokens = buildPerMinuteBucket(options.tokensPerMinute);\n\n if (options.maxConcurrent) {\n this.concurrency = new TokenBucket(options.maxConcurrent, 0);\n }\n\n this.buckets = (\n [\n { reason: 'concurrency', bucket: this.concurrency },\n { reason: 'rpm', bucket: this.requests },\n { reason: 'tpm', bucket: this.tokens },\n ] as const\n ).flatMap(({ reason, bucket }) => (bucket ? [{ reason, bucket }] : []));\n\n this.maxQueueMs = options.maxQueueMs ?? 30_000;\n this.maxQueueSize = options.maxQueueSize ?? 0;\n this.estimateTokensFn = options.estimateTokens ?? defaultEstimateTokens;\n this.estimateFraction = buildEstimateFraction(options.estimateFraction);\n this.aimd = buildAimdOptions(options.aimd);\n }\n\n /**\n * The token estimate reserved against `tokensPerMinute`, scaled by `estimateFraction`. The\n * request's `max_tokens` is never changed.\n */\n estimate(request: WireRequest): number {\n return Math.ceil(this.estimateTokensFn(request) * this.estimateFraction);\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 wake was scheduled for, so drain now rather\n // than waiting on a stale timer.\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 // Defensive: each waiter is removed at most once, so `index` is always found. Guards\n // `splice(-1, 1)` against removing another waiter if that ever changes.\n /* v8 ignore next */\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 /** Takes from every configured bucket as one atomic unit, in `this.buckets`' order. Rolls back whatever was already taken if any bucket lacks capacity. */\n private tryAcquireBuckets(\n estimatedTokens: number,\n ): { ok: true } | { ok: false; reason: RateLimitReason } {\n const taken: Array<{ bucket: TokenBucket; amount: number }> = [];\n\n for (const { reason, bucket } of this.buckets) {\n const amount = amountFor(reason, estimatedTokens);\n\n if (!bucket.tryTake(amount)) {\n for (const entry of taken) entry.bucket.give(entry.amount);\n return { ok: false, reason };\n }\n\n taken.push({ bucket, amount });\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 one recheck for when the bucket blocking the head should have capacity. No-op for a\n * concurrency block or while a wake is pending.\n */\n private scheduleWake(reason: RateLimitReason, estimatedTokens: number): void {\n if (this.wakeTimer) return;\n if (reason === 'concurrency') return;\n\n const bucket = this.buckets.find((entry) => entry.reason === reason)?.bucket;\n const ms = bucket?.msUntilAvailable(amountFor(reason, estimatedTokens));\n\n // Defensive: validation keeps every per minute ceiling at 1 or more, so\n // refill never stops and the wait is always finite. Guards a timer\n // with an Infinity/NaN delay, which fires at once, if that changes.\n /* v8 ignore next */\n if (ms === undefined || !Number.isFinite(ms)) return;\n\n // Capped at the timer limit. `drain()` rereads bucket state on every wake, so an early wake\n // just reschedules.\n const delay = Math.min(Math.max(1, Math.ceil(ms)), MAX_TIMER_DELAY_MS);\n\n this.wakeTimer = setTimeout(() => {\n this.wakeTimer = undefined;\n this.drain();\n }, delay);\n }\n\n /**\n * The one-shot release for an acquired slot. Concurrency is given back, requests only recover by\n * refill, and tokens are reconciled against real usage. AIMD grows only when `success` is true,\n * so a failed attempt can't undo a shrink.\n */\n private makeRelease(estimatedTokens: number): (actualTokens?: number, success?: boolean) => void {\n let released = false;\n\n return (actualTokens?: number, success = false) => {\n if (released) return;\n released = true;\n\n this.concurrency?.give(1);\n\n // A NaN would poison the bucket and silently stop limiting, so a non-finite `actualTokens`\n // skips reconciliation and keeps the safer estimated debit.\n if (this.tokens && actualTokens !== undefined && Number.isFinite(actualTokens)) {\n this.tokens.give(estimatedTokens - actualTokens);\n }\n\n if (success) this.growOnSuccess();\n this.drain();\n };\n }\n\n /** Shared guard and resize call behind both AIMD halves below; only the arithmetic differs. */\n private resizeRequestsCeiling(next: (aimd: AimdOptions, current: number) => number): void {\n if (!this.aimd || !this.requests) return;\n\n this.requests.resize(next(this.aimd, this.requests.getCapacity()));\n }\n\n /** AIMD's additive-increase half: grows the ceiling by `aimd.increaseBy` on a clean release. No-op without `aimd`/`requestsPerMinute`. */\n private growOnSuccess(): void {\n this.resizeRequestsCeiling((aimd, current) =>\n Math.min(current + aimd.increaseBy, aimd.maxCapacity),\n );\n }\n\n /**\n * AIMD's decrease, on a real 429 or a low remaining hint. Only adjusts the ceiling, never throws.\n * Shrinks at most once per `AIMD_SHRINK_WINDOW_MS`.\n */\n signalRateLimit(): void {\n if (!this.aimd || !this.requests) return;\n\n const now = Date.now();\n\n // A clock that moved backwards reads as a new window, so a skewed\n // `lastShrinkAt` can never block shrinking for longer than one window.\n if (\n this.lastShrinkAt !== undefined &&\n now >= this.lastShrinkAt &&\n now - this.lastShrinkAt < AIMD_SHRINK_WINDOW_MS\n ) {\n return;\n }\n\n this.lastShrinkAt = now;\n this.resizeRequestsCeiling((aimd, current) =>\n Math.max(current * aimd.decreaseFactor, aimd.minCapacity),\n );\n }\n\n /**\n * AIMD's proactive entry point: shrinks via `signalRateLimit()` if\n * `hint.remainingRequests` is at or below `aimd.proactiveFloor`.\n */\n reactToRateLimitHint(hint: ProviderRateLimitHint | undefined): void {\n if (!this.aimd || !hint || hint.remainingRequests === undefined) return;\n\n // Defensive: `buildAimdOptions` always normalizes `proactiveFloor` to\n // a number (`?? 0`) at construction, so `this.aimd.proactiveFloor` is\n // never actually undefined here. Guards against a `NaN`/`undefined`\n // floor silently breaking the comparison below if that invariant is\n // ever broken by a future change.\n /* v8 ignore next */\n const floor = this.aimd.proactiveFloor ?? 0;\n if (floor > 0 && hint.remainingRequests <= floor) {\n this.signalRateLimit();\n }\n }\n\n /**\n * Current bucket levels, read live rather than cached. `concurrency`\n * tracks free slots internally, so `concurrentInFlight` is reported as\n * `capacity - available`, the inverse of what the bucket itself holds.\n */\n getState(): RateLimitState {\n return {\n requestsRemaining: this.requests?.getAvailable(),\n tokensRemaining: this.tokens?.getAvailable(),\n concurrentInFlight: this.concurrency\n ? this.concurrency.getCapacity() - this.concurrency.getAvailable()\n : undefined,\n };\n }\n}\n","import { RateLimiter, type RateLimiterAdapter, type RateLimitOptions } from '../../../rateLimit.js';\nimport { LLMError } from '../../../types/errors.js';\n\nimport type { Logger } from '../../../logger.js';\n\n/** Not exported. Internal shorthand only, so this union isn't duplicated between the public option fields and `buildRateLimit`'s own signature. */\nexport type RateLimitOption = RateLimitOptions | RateLimiterAdapter;\n\nconst ADAPTER_METHOD_NAMES = [\n 'estimate',\n 'acquire',\n 'signalRateLimit',\n 'reactToRateLimitHint',\n] as const;\n\n/** Optional `RateLimiterAdapter` members that must be functions when present. */\nconst OPTIONAL_FUNCTION_MEMBER_NAMES = ['getState', 'readState', 'setLogger'] as const;\n\n/**\n * Optional members that are set but not functions, caught now rather than as a confusing \"not a\n * function\" later.\n */\nfunction invalidOptionalMembers(\n option: RateLimitOption,\n): (typeof OPTIONAL_FUNCTION_MEMBER_NAMES)[number][] {\n const candidate = option as Partial<RateLimiterAdapter>;\n return OPTIONAL_FUNCTION_MEMBER_NAMES.filter(\n (name) => candidate[name] !== undefined && typeof candidate[name] !== 'function',\n );\n}\n\n/** All four required `RateLimiterAdapter` methods present and callable, and the optional ones (if present at all) also callable. They stay optional, see `invalidOptionalMembers`. */\nfunction isRateLimiterAdapter(option: RateLimitOption): option is RateLimiterAdapter {\n const candidate = option as Partial<RateLimiterAdapter>;\n return (\n ADAPTER_METHOD_NAMES.every((name) => typeof candidate[name] === 'function') &&\n invalidOptionalMembers(option).length === 0\n );\n}\n\n/** At least one adapter method present, but not all four, an incomplete adapter rather than plain config. */\nfunction isIncompleteRateLimiterAdapter(option: RateLimitOption): boolean {\n const candidate = option as Partial<RateLimiterAdapter>;\n return ADAPTER_METHOD_NAMES.some((name) => typeof candidate[name] === 'function');\n}\n\n/**\n * Resolves `rateLimit` into an adapter, or `undefined` for no limiting. An object with only some\n * adapter methods, or a non-function optional member, throws now instead of failing later.\n */\nexport function buildRateLimit(\n option: RateLimitOption | undefined,\n logger?: Logger,\n): RateLimiterAdapter | undefined {\n if (option === undefined) return undefined;\n if (isRateLimiterAdapter(option)) {\n if (logger) option.setLogger?.(logger);\n return option;\n }\n\n if (isIncompleteRateLimiterAdapter(option)) {\n const missing = ADAPTER_METHOD_NAMES.filter(\n (name) => typeof (option as Partial<RateLimiterAdapter>)[name] !== 'function',\n );\n\n if (missing.length > 0) {\n throw new LLMError(\n `rateLimit looks like a RateLimiterAdapter but is missing: ${missing.join(', ')}. All four methods (${ADAPTER_METHOD_NAMES.join(', ')}) are required.`,\n 'invalid_params',\n );\n }\n }\n\n const invalid = invalidOptionalMembers(option);\n if (invalid.length > 0) {\n const candidate = option as Partial<RateLimiterAdapter>;\n const described = invalid.map((name) => `${name} (${typeof candidate[name]})`).join(', ');\n\n throw new LLMError(\n `rateLimit's ${described} must be a function. ${invalid.length === 1 ? 'It is' : 'They are'} optional; omit entirely rather than assigning a non-function value.`,\n 'invalid_params',\n );\n }\n\n return new RateLimiter(option);\n}\n","import {\n RetryBudget,\n type RetryBudgetAdapter,\n type RetryBudgetOptions,\n} from '../../../retryBudget.js';\nimport { LLMError } from '../../../types/errors.js';\n\nimport type { Logger } from '../../../logger.js';\n\n/** What `retryBudget` accepts: options for the built in budget, or an adapter. */\nexport type RetryBudgetOption = RetryBudgetOptions | RetryBudgetAdapter;\n\nconst ADAPTER_METHOD_NAMES = ['assertAvailable', 'recordAttempt'] as const;\n\n/** Optional `RetryBudgetAdapter` members that must be functions when present. */\nconst OPTIONAL_FUNCTION_MEMBER_NAMES = ['getSnapshot', 'readState', 'setLogger'] as const;\n\n/**\n * Resolves `retryBudget` into an adapter, or `undefined` for no budget. Any adapter method makes\n * the object an adapter, so a half built one throws now instead of being read as options.\n */\nexport function buildRetryBudget(\n option: RetryBudgetOption | undefined,\n logger?: Logger,\n): RetryBudgetAdapter | undefined {\n // Falsy disables it, as before adapters existed, so `retryBudget: enabled && {...}` still works.\n if (!option) return undefined;\n\n const members = option as unknown as Record<string, unknown>;\n const isFunction = (name: string) => typeof members[name] === 'function';\n if (!ADAPTER_METHOD_NAMES.some(isFunction)) return new RetryBudget(option as RetryBudgetOptions);\n\n const missing = ADAPTER_METHOD_NAMES.filter((name) => !isFunction(name));\n if (missing.length > 0) {\n throw new LLMError(\n `retryBudget looks like a RetryBudgetAdapter but is missing: ${missing.join(', ')}. Both ${ADAPTER_METHOD_NAMES.join(' and ')} are required.`,\n 'invalid_params',\n );\n }\n\n const invalid = OPTIONAL_FUNCTION_MEMBER_NAMES.filter(\n (name) => members[name] !== undefined && !isFunction(name),\n );\n if (invalid.length > 0) {\n const described = invalid.map((name) => `${name} (${typeof members[name]})`).join(', ');\n throw new LLMError(\n `retryBudget's ${described} must be a function. ${invalid.length === 1 ? 'It is' : 'They are'} optional; omit entirely rather than assigning a non-function value.`,\n 'invalid_params',\n );\n }\n\n const adapter = option as RetryBudgetAdapter;\n if (logger) adapter.setLogger?.(logger);\n return adapter;\n}\n","import type { FallbackTarget } from '../../types/fallback.js';\n\n/**\n * One name per target, primary first. Throws when two targets share a name, since usage and events\n * identify a target by it.\n */\nexport function resolveTargetNames(\n targets: readonly FallbackTarget[],\n providerName: string,\n): string[] {\n const names = targets.map(\n // Defaults are 0-indexed among fallbacks, so `i - 1`, matching `FallbackAttempt.index`.\n (target, i) => target.name ?? (i > 0 ? `fallback[${i - 1}]` : providerName),\n );\n\n // A config mistake caught once at construction, so a plain Error rather than an LLMError.\n // Only hand set names can collide, including one that matches another target's default.\n const duplicate = names.find((name, i) => names.indexOf(name) !== i);\n if (duplicate !== undefined) {\n throw new Error(\n `target name \"${duplicate}\" is used by more than one target; names identify targets in usage and events`,\n );\n }\n\n return names;\n}\n","import { CallExecutor } from './execution/callExecutor.js';\nimport { DEFAULT_MAX_DELAY_MS } from './execution/utils/retry/retry.utils.js';\nimport { resolveAdapterInfo } from './utils/adapterInfo.utils.js';\nimport { buildCircuitBreaker } from './utils/circuit-breaker/circuitBreakerAdapter.utils.js';\nimport { buildRateLimit } from './utils/rate-limit/rateLimitAdapter.utils.js';\nimport { buildRetryBudget } from './utils/retry-budget/retryBudgetAdapter.utils.js';\nimport { resolveTargetNames } from './utils/targetNames.utils.js';\n\nimport type { Logger } from '../logger.js';\nimport type { DetectSoftFailure } from '../types/call.js';\nimport type { LLMError } from '../types/errors.js';\nimport type { FallbackTarget } from '../types/fallback.js';\nimport type { TokenUsage, VernLLMEvent, VernLLMMiddleware } from '../types/index.js';\n\n/**\n * What `buildExecutors` needs besides the targets: the primary's resolved defaults and the instance\n * options each target falls back to.\n */\nexport interface ExecutorFactoryShared {\n /** This instance's provider label, used as the primary target's name unless it sets its own. */\n providerName: string;\n /** The primary's resolved `defaultTemperature`. Fallback targets that don't set their own inherit this, not `undefined`. */\n primaryDefaultTemperature: number | null;\n primaryDefaultReasoningEffort?: 'minimal' | 'low' | 'medium' | 'high';\n primaryDefaultBudgetTokens?: number;\n maxRetries?: number;\n timeoutMs?: number;\n chunkIdleTimeoutMs?: number;\n readerStallTimeoutMs?: number;\n baseDelayMs?: number;\n maxRetryAfterMs?: number;\n defaultMaxTokens?: number;\n nonRetryableStatus?: number[];\n parseJson?: (content: string) => unknown;\n redact?: (text: string) => string;\n onUsage?: (usage: TokenUsage) => void;\n onUsageFailure?: (usage: TokenUsage, error: LLMError) => void;\n onEvent?: (event: VernLLMEvent) => void;\n logger: Logger;\n middleware: VernLLMMiddleware[];\n /** `wrap` nesting order, which `dispatch` hooks nest in too. */\n dispatchOrder?: VernLLMMiddleware[];\n middlewareTimeoutMs: number;\n detectSoftFailure?: DetectSoftFailure;\n}\n\n/**\n * One `CallExecutor` per target, primary first, then fallbacks in order. A target inherits an\n * option only when it leaves it unset; breaker and limiter are never inherited.\n */\nexport function buildExecutors(\n primaryTarget: FallbackTarget,\n declaredFallbacks: FallbackTarget[],\n shared: ExecutorFactoryShared,\n): CallExecutor[] {\n const targets = [primaryTarget, ...declaredFallbacks];\n const names = resolveTargetNames(targets, shared.providerName);\n\n return targets.map((target, i) => {\n const isFallback = i > 0;\n const name = names[i]!;\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 shared.onEvent,\n shared.logger,\n shared.middleware,\n shared.middlewareTimeoutMs,\n isFallback,\n target.client.supportsJsonObjectMode ?? true,\n resolveAdapterInfo(target.client),\n );\n\n // Independent of `breaker`, never inherited from `shared`, same as\n // `circuitBreaker`/`rateLimit`: a budget tuned for one target's\n // capacity is rarely right for another's.\n const budget = buildRetryBudget(target.retryBudget, shared.logger);\n\n return new CallExecutor(name, target.client, target.model, {\n maxRetries: target.maxRetries ?? shared.maxRetries ?? 1,\n timeoutMs: target.timeoutMs ?? shared.timeoutMs ?? 25_000,\n chunkIdleTimeoutMs: target.chunkIdleTimeoutMs ?? shared.chunkIdleTimeoutMs ?? 30_000,\n readerStallTimeoutMs: target.readerStallTimeoutMs ?? shared.readerStallTimeoutMs,\n baseDelayMs: target.baseDelayMs ?? shared.baseDelayMs ?? 500,\n maxRetryAfterMs: target.maxRetryAfterMs ?? shared.maxRetryAfterMs ?? DEFAULT_MAX_DELAY_MS,\n defaultMaxTokens: target.defaultMaxTokens ?? shared.defaultMaxTokens ?? 1000,\n defaultTemperature:\n target.defaultTemperature === undefined\n ? shared.primaryDefaultTemperature\n : target.defaultTemperature,\n defaultReasoningEffort:\n target.defaultReasoningEffort === undefined\n ? shared.primaryDefaultReasoningEffort\n : target.defaultReasoningEffort,\n defaultBudgetTokens:\n target.defaultBudgetTokens === undefined\n ? shared.primaryDefaultBudgetTokens\n : target.defaultBudgetTokens,\n nonRetryableStatus: target.nonRetryableStatus ??\n shared.nonRetryableStatus ?? [400, 401, 402, 403, 404, 413, 422],\n parseJson: shared.parseJson,\n logger: shared.logger,\n redact: shared.redact,\n onUsage: shared.onUsage,\n onUsageFailure: shared.onUsageFailure,\n onEvent: shared.onEvent,\n breaker,\n budget,\n limiter: buildRateLimit(target.rateLimit, shared.logger),\n isFallback,\n middleware: shared.middleware,\n dispatchOrder: shared.dispatchOrder,\n middlewareTimeoutMs: shared.middlewareTimeoutMs,\n detectSoftFailure: target.detectSoftFailure ?? shared.detectSoftFailure,\n });\n });\n}\n","import {\n middlewareContextNames,\n middlewareLabel,\n middlewareLabels,\n type MiddlewareContextNames,\n} from './utils/middlewareLabels.utils.js';\n\nimport type { Logger } from '../logger.js';\nimport type {\n MiddlewareRef,\n RequiredMiddlewareRef,\n VernLLMMiddleware,\n} from '../types/middleware.js';\n\nexport { middlewareContextNames, middlewareLabel, middlewareLabels, type MiddlewareContextNames };\n\n/**\n * Every resolved view of middleware order, built once at `VernLLM`\n * construction time. Nothing downstream computes order itself; each\n * consumer reads the one field it needs.\n */\nexport interface MiddlewarePipeline {\n /** `transform`/`onEvent` order: `priority`, `runsAfter`/`runsBefore` resolved, ties by original index. */\n transformOrder: VernLLMMiddleware[];\n /** `wrap` nesting order: `transformOrder` with any `position` pins applied. Identical to `transformOrder` when nothing sets `position`. */\n wrapOrder: VernLLMMiddleware[];\n /** Every entry's resolved label, in `transformOrder`, frozen. Powers `registeredMiddlewareNames` on context. */\n names: readonly string[];\n /** `names` narrowed to entries that define a `transform`, frozen. Powers `transformMiddlewareNames` on context. */\n transformNames: readonly string[];\n}\n\n/** `name`, or the array index. Not the bracketed display label: this is the ordering graph's id. */\nexport function idFor(entry: VernLLMMiddleware, index: number): string {\n return entry.name ?? String(index);\n}\n\n/**\n * Throws if two entries publish the same label. Graph ids can differ while labels clash, e.g. one\n * named `\"[1]\"` and an unnamed entry at position 1.\n */\nfunction assertNoDuplicatePublishedLabels(labels: readonly string[]): void {\n const seen = new Set<string>();\n for (const label of labels) {\n if (seen.has(label)) {\n throw new Error(\n `middleware has a duplicate label \"${label}\"; a name can't match an unnamed middleware's bracketed position`,\n );\n }\n seen.add(label);\n }\n}\n\n/**\n * One entry in the ordering graph: its id, entry, original index for tie breaks, and the ids that\n * must come after it.\n */\ninterface Node {\n id: string;\n entry: VernLLMMiddleware;\n index: number;\n /** Ids of entries that must be placed after this one. Kahn's algorithm walks this directly instead of rescanning a flat edge list on every pop. */\n mustPrecede: string[];\n}\n\n/** Throws if two entries resolve to the same `idFor` label. Duplicate labels would silently merge two middleware into one `Node` in `buildNodes`, corrupting edges and `registeredMiddlewareNames`. */\nfunction assertNoDuplicateLabels(entries: readonly VernLLMMiddleware[]): void {\n const ids = entries.map(idFor);\n const seen = new Set<string>();\n for (const id of ids) {\n if (seen.has(id)) {\n throw new Error(\n `middleware ordering has a duplicate name \"${id}\"; every middleware's resolved name must be unique`,\n );\n }\n seen.add(id);\n }\n}\n\n/**\n * Throws if two entries share a `ref`. Runs even when no entry has edges, so a duplicate can't sit\n * unnoticed until an edge targets it.\n */\nfunction assertNoDuplicateRefs(entries: readonly VernLLMMiddleware[]): void {\n const seen = new Map<MiddlewareRef, number>();\n entries.forEach((entry, index) => {\n const ref = entry.ref;\n if (!ref) return;\n const firstIndex = seen.get(ref);\n if (firstIndex !== undefined) {\n throw new Error(\n `middleware ordering has a ref reused across two entries (\"${idFor(entries[firstIndex]!, firstIndex)}\" and \"${idFor(entry, index)}\"); each middleware's ref must be unique to that middleware`,\n );\n }\n seen.set(ref, index);\n });\n}\n\n/**\n * Splits a `runsAfter` or `runsBefore` entry into its ref and whether it is required. Only\n * `requireRef` output has a `ref` property.\n */\nfunction unwrapReference(target: MiddlewareRef | RequiredMiddlewareRef): {\n ref: MiddlewareRef;\n required: boolean;\n} {\n return 'ref' in target ? { ref: target.ref, required: true } : { ref: target, required: false };\n}\n\n/**\n * Turns one `runsAfter` or `runsBefore` entry into a graph edge, matched by ref identity, never by\n * `name`. An unresolved bare ref warns and is dropped; an unresolved required ref throws.\n */\nfunction resolveReference(\n byId: Map<string, Node>,\n byRef: Map<MiddlewareRef, Node>,\n fromId: string,\n target: MiddlewareRef | RequiredMiddlewareRef,\n precedes: boolean,\n logger?: Logger,\n): void {\n const { ref, required } = unwrapReference(target);\n const targetNode = byRef.get(ref);\n\n if (!targetNode) {\n if (required) {\n throw new Error(\n `middleware \"${fromId}\" requires ref \"${ref.debugName}\", which is not registered; this dependency is not optional`,\n );\n }\n\n logger?.warn?.(\n `[VernLLM] middleware \"${fromId}\" references unknown ref \"${ref.debugName}\" in runsAfter/runsBefore, ignoring it`,\n );\n\n return;\n }\n // precedes true: target (runsAfter) must come before fromId.\n // precedes false: target (runsBefore) must come after fromId.\n const before = precedes ? targetNode.id : fromId;\n const after = precedes ? fromId : targetNode.id;\n byId.get(before)!.mustPrecede.push(after);\n}\n\nfunction buildNodes(entries: readonly VernLLMMiddleware[], logger?: Logger): Node[] {\n const ids = entries.map(idFor);\n const nodes = entries.map((entry, index): Node => ({\n id: ids[index]!,\n entry,\n index,\n mustPrecede: [],\n }));\n const byId = new Map(nodes.map((node) => [node.id, node]));\n\n // Only entries with a `ref` can be targeted, keyed by the ref object so labels never affect\n // order. Refs are already known to be unique here.\n const byRef = new Map(\n nodes.filter((node) => node.entry.ref).map((node) => [node.entry.ref!, node]),\n );\n\n for (const node of nodes) {\n for (const target of node.entry.runsAfter ?? []) {\n resolveReference(byId, byRef, node.id, target, true, logger);\n }\n for (const target of node.entry.runsBefore ?? []) {\n resolveReference(byId, byRef, node.id, target, false, logger);\n }\n }\n\n return nodes;\n}\n\n/** Ascending by `priority` (default `0`), ties broken by original array index. */\nfunction byPriorityThenIndex(a: Node, b: Node): number {\n const priorityDiff = (a.entry.priority ?? 0) - (b.entry.priority ?? 0);\n return priorityDiff !== 0 ? priorityDiff : a.index - b.index;\n}\n\n/**\n * Kahn's algorithm, ties broken by `byPriorityThenIndex`. Nodes left unvisited form a cycle, so\n * this is also the cycle check. Throws a plain `Error`, since a cycle is a construction time\n * mistake.\n */\nfunction topologicalSort(nodes: Node[]): VernLLMMiddleware[] {\n const byId = new Map(nodes.map((node) => [node.id, node]));\n const indegree = new Map(nodes.map((node) => [node.id, 0]));\n for (const node of nodes) {\n for (const after of node.mustPrecede) indegree.set(after, indegree.get(after)! + 1);\n }\n\n // A small heap would beat re-sorting the ready set on every pop for a\n // large graph, but middleware lists are small in practice; re-sorting\n // a handful of ready ids each iteration is simpler and fast enough.\n const ready = nodes.filter((node) => indegree.get(node.id) === 0);\n const result: VernLLMMiddleware[] = [];\n const emitted = new Set<string>();\n\n while (ready.length > 0) {\n ready.sort(byPriorityThenIndex);\n const node = ready.shift()!;\n result.push(node.entry);\n emitted.add(node.id);\n\n for (const afterId of node.mustPrecede) {\n const remaining = indegree.get(afterId)! - 1;\n indegree.set(afterId, remaining);\n if (remaining === 0) ready.push(byId.get(afterId)!);\n }\n }\n\n if (result.length < nodes.length) {\n const stuck = nodes.filter((node) => !emitted.has(node.id)).map((node) => node.id);\n throw new Error(`middleware ordering has a cycle among: ${stuck.join(', ')}`);\n }\n\n return result;\n}\n\n/**\n * Sorts `entries` once, at construction. Without `runsAfter` or `runsBefore` this is a plain\n * `priority` sort, ties by index; with edges it runs the graph sort.\n */\nexport function resolveMiddlewareOrder(\n entries: readonly VernLLMMiddleware[],\n logger?: Logger,\n): VernLLMMiddleware[] {\n assertNoDuplicateLabels(entries);\n assertNoDuplicateRefs(entries);\n\n const hasEdges = entries.some((entry) => entry.runsAfter?.length || entry.runsBefore?.length);\n\n if (entries.length <= 1 && !hasEdges) return [...entries];\n\n if (!hasEdges) {\n // Same comparator the graph path uses for tie-breaking among\n // simultaneously-ready nodes, so \"what does a tie mean\" has one\n // definition regardless of which path an entry set takes.\n const asNodes = entries.map((entry, index): Node => ({\n id: idFor(entry, index),\n entry,\n index,\n mustPrecede: [],\n }));\n return asNodes.sort(byPriorityThenIndex).map((node) => node.entry);\n }\n\n const nodes = buildNodes(entries, logger);\n return topologicalSort(nodes);\n}\n\n/**\n * Stable sort for `wrapOrder`: `'outermost'` first, `'innermost'` last, numeric or missing (`0`)\n * positions in between like `priority`. Among several outermost claimants the first registered is\n * outermost; among innermost claimants the last registered is innermost.\n */\nfunction applyPositionOverride(\n order: readonly VernLLMMiddleware[],\n entries: readonly VernLLMMiddleware[],\n): VernLLMMiddleware[] {\n const outermost: VernLLMMiddleware[] = [];\n const innermost: VernLLMMiddleware[] = [];\n const middle: VernLLMMiddleware[] = [];\n\n // Single pass instead of three separate `.filter()` walks over\n // `order`; each entry lands in exactly one bucket, so there's no risk\n // of the buckets' predicates drifting out of sync with each other as\n // position values are added later.\n for (const entry of order) {\n if (entry.position === 'outermost') outermost.push(entry);\n else if (entry.position === 'innermost') innermost.push(entry);\n else middle.push(entry);\n }\n\n const sortedMiddle = [...middle].sort((a, b) => {\n const aPos = typeof a.position === 'number' ? a.position : 0;\n const bPos = typeof b.position === 'number' ? b.position : 0;\n return aPos - bPos;\n });\n // Registration order, not `order`'s: `order` is sorted by priority, which would let a\n // claimant's `transform` priority decide who wraps whom.\n const registered = (a: VernLLMMiddleware, b: VernLLMMiddleware): number =>\n entries.indexOf(a) - entries.indexOf(b);\n outermost.sort(registered);\n innermost.sort(registered);\n\n return [...outermost, ...sortedMiddle, ...innermost];\n}\n\n/**\n * Builds the one `MiddlewarePipeline` an instance uses. Nothing downstream computes order itself.\n */\nexport function buildMiddlewarePipeline(\n entries: readonly VernLLMMiddleware[],\n logger?: Logger,\n): MiddlewarePipeline {\n const transformOrder = resolveMiddlewareOrder(entries, logger);\n const { registeredMiddlewareNames: names, transformMiddlewareNames: transformNames } =\n middlewareContextNames(transformOrder);\n assertNoDuplicatePublishedLabels(names);\n return {\n transformOrder,\n wrapOrder: applyPositionOverride(transformOrder, entries),\n names,\n transformNames,\n };\n}\n","import {\n InMemoryCacheAdapter,\n type CacheAdapter,\n type EvictionOption,\n} from '../../../types/cache.js';\n\n/**\n * Not exported. Internal shorthand for `VernLLMOptions.cache`, so the\n * union isn't duplicated between that field and `buildCache`'s own\n * signature. A caller never writes this type by name, either a config\n * object literal or a real `CacheAdapter`.\n */\nexport type CacheOption = { maxSize?: number; eviction?: EvictionOption } | CacheAdapter;\n\n/** A config object has neither `get` nor `set`, a `CacheAdapter` always has both. */\nfunction isCacheAdapter(option: CacheOption): option is CacheAdapter {\n const candidate = option as CacheAdapter;\n return typeof candidate.get === 'function' && typeof candidate.set === 'function';\n}\n\n/** Resolves `VernLLMOptions.cache` into a real `CacheAdapter`. Same placement reasoning as `buildCircuitBreaker`: a construction time concern of `VernLLM`, not the adapter itself. */\nexport function buildCache(option: CacheOption | undefined): CacheAdapter {\n if (option === undefined) return new InMemoryCacheAdapter();\n if (isCacheAdapter(option)) return option;\n\n if (\n option.maxSize !== undefined &&\n (!Number.isFinite(option.maxSize) || option.maxSize < 0 || !Number.isInteger(option.maxSize))\n ) {\n throw new RangeError(\n `cache.maxSize must be a finite, non-negative integer, got ${String(option.maxSize)}`,\n );\n }\n\n return new InMemoryCacheAdapter(option.maxSize, option.eviction);\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 { CacheOrchestrator } from './internal/cache/cacheOrchestrator.js';\nimport { claimMetaHolder, type MetaHolder } from './internal/cache/utils/metaHolder.utils.js';\nimport { CallExecutor } from './internal/execution/callExecutor.js';\nimport { type LogicalCallDependencies } from './internal/execution/logicalCall.js';\nimport { runReservedLogicalCall } from './internal/execution/reservedLogicalCall.js';\nimport { runOperation, type RunOperationDependencies } from './internal/execution/runOperation.js';\nimport {\n declaredTargets,\n narrowTargets,\n type ResolvedTarget,\n} from './internal/execution/targetOrder.js';\nimport { combineSignals, setupCallSignal } from './internal/execution/utils/callSignal.utils.js';\nimport { setupDeadline, stampDeadlineCode } from './internal/execution/utils/deadline.utils.js';\nimport {\n createCallScope,\n type CallScopeDependencies,\n} from './internal/execution/utils/middleware/customEvent.utils.js';\nimport { DEFAULT_MIDDLEWARE_TIMEOUT_MS } from './internal/execution/utils/middleware/middleware.utils.js';\nimport { buildExecutors } from './internal/executorFactory.js';\nimport { buildMiddlewarePipeline } from './internal/resolveMiddlewareOrder.js';\nimport { buildCache } from './internal/utils/cache/cacheAdapter.utils.js';\nimport {\n createCallFacts,\n prepareCallContext,\n registerCallScope,\n validateStateEntries,\n} from './internal/utils/callScope.utils.js';\nimport { markChain } from './internal/utils/chain.utils.js';\nimport {\n makeEventReporter,\n resolveExecutor,\n warnIfModelUnsupported,\n} from './internal/utils/circuit-breaker/circuitBreaker.utils.js';\nimport { createSafeLogger, logError, NoopLogger } from './internal/utils/logger.utils.js';\nimport { ConsoleLogger, type Logger } from './logger.js';\nimport {\n LLMError,\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 CallMeta,\n type CallParams,\n type CallWithToolsResult,\n type ConditionalToolCallParams,\n type ConditionalStringToolCallParams,\n type ContentResult,\n type FallbackTarget,\n type JsonModeDisabledCallParams,\n type JsonModeEnabledCallParams,\n type JsonValue,\n type LLMErrorCode,\n type StreamCallResult,\n type StreamConditionalStringToolCallParams,\n type StreamEnabledCallParams,\n type StreamJsonModeDisabledCallParams,\n type StreamJsonModeEnabledCallParams,\n type CachedStreamJsonModeDisabledCallParams,\n type CachedStreamJsonModeEnabledCallParams,\n type TargetCircuitState,\n type CircuitTarget,\n type ToolDefinition,\n type ToolEnabledCallParams,\n type ToolsDisabledCallParams,\n type VernLLMOptions,\n} from './types/index.js';\nimport { createMiddlewareStateBag, type MiddlewareStateBag } from './types/middleware.js';\n\nimport type { CircuitState } from './circuitBreaker.js';\nimport type { InternalCacheParams } from './internal/cache/utils/cache.utils.js';\nimport type { RateLimitState } from './rateLimit.js';\nimport type { RetryBudgetSnapshot } from './retryBudget.js';\n\n/**\n * The LLM call framework: retries, timeouts, circuit breaking, fallback, rate limiting, caching and\n * middleware around any provider adapter.\n */\nexport class VernLLM {\n private readonly logger: Logger;\n\n /** One per target: index 0 is the primary, then each fallback in declared order. */\n private readonly executors: CallExecutor[];\n\n /** Owns cache reads, writes and in-flight coalescing for `cachedCall()`. */\n private readonly cacheOrchestrator: CacheOrchestrator;\n\n /** Every target in declared order, the pool `targets` selects from. */\n private readonly declaredTargets: readonly ResolvedTarget[];\n\n /** Everything but `targets`, which each call sets for its own order. */\n private readonly logicalCallDependencies: Omit<LogicalCallDependencies, 'targets'>;\n private readonly runOperationDependencies: RunOperationDependencies;\n\n /** What each call's scope needs to deliver a `ctx.emit` event. */\n private readonly callScopeDependencies: CallScopeDependencies;\n\n /**\n * Marks `cachedCall()`'s inner call params with its state bag, so the inner\n * `runOperation` skips `wrap` and reuses that bag. Keyed by object identity,\n * since concurrent `cachedCall()`s can share an explicit `requestId`.\n */\n private readonly cachedCallInnerParams = new WeakMap<CallParams<unknown>, MiddlewareStateBag>();\n\n /** Shared `CallMeta` holders per resolved cache key. See `claimMetaHolder`. */\n private readonly cachedCallMeta = new Map<string, MetaHolder>();\n\n /** @param options Client, model and tunables. See `VernLLMOptions` for each default. */\n constructor(options: VernLLMOptions) {\n this.logger = createSafeLogger(\n options.logger === 'silent'\n ? new NoopLogger()\n : (options.logger ?? new ConsoleLogger(options.debug ?? false)),\n );\n\n const providerName = options.name ?? 'primary';\n\n this.cacheOrchestrator = new CacheOrchestrator(buildCache(options.cache), this.logger);\n\n const reportEvent = makeEventReporter(options.onEvent, this.logger);\n const pipeline = buildMiddlewarePipeline(options.middleware ?? [], this.logger);\n const middlewareTimeoutMs = options.middlewareTimeoutMs ?? DEFAULT_MIDDLEWARE_TIMEOUT_MS;\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 as a `FallbackTarget` so it goes through the same build loop. Fallback\n // targets never inherit its breaker or limiter.\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 readerStallTimeoutMs: options.readerStallTimeoutMs,\n baseDelayMs: options.baseDelayMs,\n maxRetryAfterMs: options.maxRetryAfterMs,\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 retryBudget: options.retryBudget,\n detectSoftFailure: options.detectSoftFailure,\n };\n\n const declaredFallbacks: FallbackTarget[] = Array.isArray(options.fallback)\n ? options.fallback\n : options.fallback\n ? [options.fallback]\n : [];\n\n this.executors = buildExecutors(primaryTarget, declaredFallbacks, {\n providerName,\n primaryDefaultTemperature,\n primaryDefaultReasoningEffort,\n primaryDefaultBudgetTokens,\n maxRetries: options.maxRetries,\n timeoutMs: options.timeoutMs,\n chunkIdleTimeoutMs: options.chunkIdleTimeoutMs,\n readerStallTimeoutMs: options.readerStallTimeoutMs,\n baseDelayMs: options.baseDelayMs,\n maxRetryAfterMs: options.maxRetryAfterMs,\n defaultMaxTokens: options.defaultMaxTokens,\n nonRetryableStatus: options.nonRetryableStatus,\n parseJson: options.parseJson,\n redact: options.redact,\n onUsage: options.onUsage,\n onUsageFailure: options.onUsageFailure,\n onEvent: options.onEvent,\n logger: this.logger,\n middleware: pipeline.transformOrder,\n dispatchOrder: pipeline.wrapOrder,\n middlewareTimeoutMs,\n detectSoftFailure: options.detectSoftFailure,\n });\n\n this.declaredTargets = declaredTargets(this.executors);\n\n this.logicalCallDependencies = {\n fallbackOn: options.fallbackOn ?? defaultFallbackOn,\n reportEvent,\n middleware: pipeline.transformOrder,\n middlewareTimeoutMs,\n logger: this.logger,\n };\n this.callScopeDependencies = {\n reportEvent,\n middleware: pipeline.transformOrder,\n middlewareTimeoutMs,\n logger: this.logger,\n };\n this.runOperationDependencies = {\n pipeline,\n primaryExecutor: this.executors[0]!,\n targets: this.declaredTargets,\n middlewareTimeoutMs,\n logger: this.logger,\n reportEvent,\n };\n }\n\n /**\n * Makes one logical call, with retries, fallback and the breaker applied. Rejects with a\n * normalized `LLMError`. See the Tool Calling and Streaming docs for the return shapes.\n *\n * @param params Content plus per call overrides. See `CallParams`.\n * @returns The parsed response, a `CallWithToolsResult<T>` with `tools`, or a `StreamCallResult`\n * with `stream: true`.\n */\n async call<T = unknown, const Tools extends readonly ToolDefinition[] = ToolDefinition[]>(\n params: StreamEnabledCallParams<T, Tools> & ToolsDisabledCallParams<T, Tools>,\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, const Tools extends readonly ToolDefinition[] = ToolDefinition[]>(\n params: ToolsDisabledCallParams<T, Tools>,\n ): 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 ?? globalThis.crypto.randomUUID();\n\n // Read from the original `params` object, before any clone drops the marker.\n const cachedCallState = this.cachedCallInnerParams.get(params);\n const isCachedCallInner = cachedCallState !== undefined;\n\n // Validated before any timer or hook exists. The inner call of `cachedCall` skips it, since\n // `cachedCall` already validated the same `context` and registered the scope.\n const callContext = isCachedCallInner ? undefined : prepareCallContext(params.context);\n const stateEntries = isCachedCallInner ? undefined : validateStateEntries(params.state);\n const targets = this.resolveTargets(params.targets);\n\n const {\n params: effectiveParams,\n signal: effectiveSignal,\n breakController,\n dispose,\n } = setupCallSignal(params, !isCachedCallInner);\n\n // One bag per logical call, shared by `wrap` and `transform` on every target.\n const middlewareState = cachedCallState ?? createMiddlewareStateBag(stateEntries);\n registerCallScope(\n middlewareState,\n createCallScope(this.callScopeDependencies, callContext, createCallFacts(params)),\n );\n\n try {\n // `wrap` also spans the sole target breaker check, so a circuit open\n // rejection is visible to it.\n const wrapped = await runOperation(\n this.runOperationDependencies,\n effectiveParams,\n requestId,\n middlewareState,\n targets,\n (chosen, chain) =>\n runReservedLogicalCall(\n { ...this.logicalCallDependencies, targets: chosen },\n chain.params,\n {\n requestId,\n middlewareState,\n breakController,\n onRefundError: (logMessage, error) => logError(this.logger, logMessage, error),\n },\n ),\n isCachedCallInner,\n );\n\n return wrapped.value as\n | T\n | CallWithToolsResult<T>\n | StreamCallResult<T | CallWithToolsResult<T>>;\n } catch (error) {\n throw stampDeadlineCode(error, effectiveSignal);\n } finally {\n dispose();\n }\n }\n\n /**\n * The order a call starts with: `requested` by name, or every target as declared. Throws before\n * any timer or hook exists, so an invalid order never starts a call.\n */\n private resolveTargets(requested: readonly string[] | undefined): ResolvedTarget[] {\n return narrowTargets(this.declaredTargets, this.declaredTargets, requested);\n }\n\n /** Kept on `VernLLM` since tests drive the caching core directly through it. */\n private runCached<T>(params: InternalCacheParams<T>) {\n return this.cacheOrchestrator.runCached(params);\n }\n\n /**\n * Removes a cached response when the adapter supports deletion. Invalidation is up to the app.\n *\n * @param key The raw cache key, resolved through the adapter's `resolveKey` first.\n */\n async deleteCache(key: string): Promise<void> {\n await this.cacheOrchestrator.deleteCache(key);\n }\n\n /**\n * `call()` with caching. Concurrent misses for one `cacheKey` share a single in-flight call.\n * Works with `stream` and `tools`; with tools the whole result is cached, tool call decisions\n * included. A caller's own abort or deadline only ends its wait; the shared request is aborted\n * once every caller has left.\n *\n * @param params Cache settings plus `call`, the `CallParams` for the underlying call.\n * @returns The cached value on a hit, or the fresh 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 const restCallParams = callParams as CallParams<T>;\n\n // The per call hooks would be silently dropped, since the cached value\n // may be shared by several callers.\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 const requestId = restCallParams.requestId ?? globalThis.crypto.randomUUID();\n const middlewareState = createMiddlewareStateBag(validateStateEntries(restCallParams.state));\n registerCallScope(\n middlewareState,\n createCallScope(\n this.callScopeDependencies,\n prepareCallContext(restCallParams.context),\n createCallFacts(restCallParams),\n ),\n );\n // Before the cache is touched or a meta holder claimed, like `context` above.\n const targets = this.resolveTargets(restCallParams.targets);\n\n const resolvedCacheKey = await this.cacheOrchestrator.resolveCacheKey(cacheParams.cacheKey);\n const { holder: metaHolder, release: releaseMetaHolder } = claimMetaHolder(\n this.cachedCallMeta,\n resolvedCacheKey,\n (key) => this.cacheOrchestrator.inFlightFor(key),\n );\n\n const callerMeta = restCallParams.meta;\n // The meta of every rerun's answer. When the one the core kept is among them, it was written to\n // the caller's already, and the shared call finishing later must not replace it.\n const rerunMetas = new Set<CallMeta | undefined>();\n let metaFromRerun = false;\n const syncCallerMeta = () => {\n if (callerMeta && !metaFromRerun) callerMeta.current = metaHolder.current;\n };\n\n // These end only this caller's wait. The shared request has its own signal\n // from the orchestrator, aborted once every participant has left.\n const { signal: participantSignal, timer: deadlineTimer } = setupDeadline(\n restCallParams.deadlineMs,\n combineSignals([cacheParams.signal, restCallParams.signal]),\n );\n const participantCacheParams = { ...cacheParams, signal: participantSignal };\n\n const participantParams = {\n ...restCallParams,\n requestId,\n signal: participantSignal,\n } as CallParams<T>;\n\n // The inner call runs once for all participants, so it takes the shared\n // signal and no per caller deadline. Marked so its own `runOperation`\n // skips `wrap` and reuses this state bag.\n // Only the caller that runs the call gets to choose its targets: a coalesced follower's are\n // ignored, and `targets` is not part of the cache key. The inner call gets the order `wrap`\n // left, by name, so it resolves to the same targets.\n const callInner = (\n signal: AbortSignal,\n chosen: readonly ResolvedTarget[],\n meta: { current?: CallMeta },\n ) => {\n const { deadlineMs: _deadlineMs, ...sharedParams } = participantParams;\n const innerParams = {\n ...sharedParams,\n targets: chosen.map((target) => target.executor.providerName),\n signal,\n meta,\n };\n this.cachedCallInnerParams.set(innerParams, middlewareState);\n return this.call(innerParams).finally(() => {\n this.cachedCallInnerParams.delete(innerParams);\n });\n };\n const callShared = (sharedSignal: AbortSignal, chosen: readonly ResolvedTarget[]) =>\n callInner(sharedSignal, chosen, metaHolder).finally(syncCallerMeta);\n\n let cacheOutcome: 'hit' | 'join' | undefined;\n const onOutcome = (outcome: 'hit' | 'join') => {\n cacheOutcome = outcome;\n };\n\n // A stream hands the holder's release to `finalResult`, since a joiner may\n // still attach after this returns.\n let releaseOnSettle = false;\n\n try {\n const wrapped = await runOperation(\n this.runOperationDependencies,\n participantParams,\n requestId,\n middlewareState,\n targets,\n async (chosen, chain) => {\n if (chain.number > 0) {\n // A rerun: a fresh call for this caller, never the cache path. Its own meta holder keeps\n // the caller's meta and the shared call's untouched while it runs.\n const freshMeta: { current?: CallMeta } = {};\n const freshParams = { ...participantCacheParams, signal: chain.params.signal! };\n const value = restCallParams.stream\n ? await this.cacheOrchestrator.runFreshStream({\n ...freshParams,\n openStream: (signal) =>\n callInner(markChain(signal, chain.number), chosen, freshMeta) as Promise<\n StreamCallResult<unknown>\n >,\n })\n : await this.cacheOrchestrator.runFresh({\n ...freshParams,\n fn: (signal) => callInner(markChain(signal, chain.number), chosen, freshMeta),\n });\n\n rerunMetas.add(freshMeta.current);\n\n return { value, meta: freshMeta.current };\n }\n\n // The main chain is the cache path as today. It waits with the chain's signal, so\n // cancelling it ends this caller's wait and leaves the shared call to anyone else on it.\n const waitParams = {\n ...participantCacheParams,\n signal: chain.params.signal ?? participantSignal,\n };\n\n const value = restCallParams.stream\n ? await this.cacheOrchestrator.runCachedStream(\n {\n ...waitParams,\n onOutcome,\n openStream: (sharedSignal) =>\n callShared(sharedSignal, chosen) as Promise<StreamCallResult<unknown>>,\n },\n Boolean(restCallParams.tools),\n )\n : await this.runCached({\n ...waitParams,\n onOutcome,\n fn: (sharedSignal) => callShared(sharedSignal, chosen),\n });\n\n return cacheOutcome\n ? { value, meta: metaHolder.current, cache: cacheOutcome }\n : { value, meta: metaHolder.current };\n },\n );\n\n // Decided from what the core wrote to the caller's meta, not from the returned wrapper.\n metaFromRerun = callerMeta?.current !== undefined && rerunMetas.has(callerMeta.current);\n\n if (restCallParams.stream) {\n const streamResult = wrapped.value as StreamCallResult<T | CallWithToolsResult<T>>;\n const onStreamSettled = () => {\n syncCallerMeta();\n releaseMetaHolder();\n };\n\n releaseOnSettle = true;\n void streamResult.finalResult.then(onStreamSettled, onStreamSettled);\n\n return streamResult;\n }\n\n syncCallerMeta();\n\n return wrapped.value as T | CallWithToolsResult<T>;\n } catch (error) {\n throw stampDeadlineCode(error, participantSignal);\n } finally {\n if (!releaseOnSettle) releaseMetaHolder();\n clearTimeout(deadlineTimer);\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.\n */\n getCircuitState(target?: CircuitTarget): CircuitState | undefined {\n const executor = resolveExecutor(this.executors, target?.index ?? 0, 'getCircuitState');\n warnIfModelUnsupported(executor.isolateByModel, target?.model, 'getCircuitState', this.logger);\n\n return executor.getCircuitState(target?.model ?? executor.model);\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 Failure counts by `LLMErrorCode`, `'unknown'` for a missing\n * code, or `undefined` if that target has no breaker.\n * @throws {RangeError} If `target.index` names no target.\n */\n getFailureBreakdown(\n target?: CircuitTarget,\n ): Partial<Record<LLMErrorCode | 'unknown', number>> | undefined {\n const executor = resolveExecutor(this.executors, target?.index ?? 0, 'getFailureBreakdown');\n warnIfModelUnsupported(\n executor.isolateByModel,\n target?.model,\n 'getFailureBreakdown',\n this.logger,\n );\n\n return executor.getFailureBreakdown(target?.model ?? executor.model);\n }\n\n /**\n * @param target.index Which target to read. Defaults to the primary.\n * @returns The retry traffic and ratio in the trailing window, or `undefined` without a budget.\n * Budgets are per target, not per model.\n * @throws {RangeError} If `target.index` names no target.\n */\n getRetryBudgetState(target?: Pick<CircuitTarget, 'index'>): RetryBudgetSnapshot | undefined {\n const executor = resolveExecutor(this.executors, target?.index ?? 0, 'getRetryBudgetState');\n return executor.getRetryBudgetState();\n }\n\n /**\n * @param target.index Which target to read. Defaults to the primary.\n * @returns Current rate limit levels, or `undefined` without a limiter. Limiters are per target,\n * not per model.\n * @throws {RangeError} If `target.index` names no target.\n */\n getRateLimitState(target?: Pick<CircuitTarget, 'index'>): RateLimitState | undefined {\n const executor = resolveExecutor(this.executors, target?.index ?? 0, 'getRateLimitState');\n return executor.getRateLimitState();\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 * The live counterpart of `getRateLimitState`, asking the limiter for its current levels.\n *\n * @param target.index Which target to read. Defaults to the primary.\n * @returns This target's live rate limit levels, or `undefined` if that target has no limiter\n * configured.\n * @throws {RangeError} If `target.index` names no target.\n */\n async readRateLimitState(\n target?: Pick<CircuitTarget, 'index'>,\n ): Promise<RateLimitState | undefined> {\n const executor = resolveExecutor(this.executors, target?.index ?? 0, 'readRateLimitState');\n return executor.readRateLimitState();\n }\n\n /**\n * The live counterpart of `getCircuitStates`, asking each breaker for its current state.\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 async readCircuitStates(model?: string): Promise<TargetCircuitState[]> {\n return Promise.all(\n this.executors.map(async (executor, index) => ({\n provider: executor.providerName,\n index,\n isFallback: index > 0,\n isolateByModel: executor.isolateByModel,\n state: await executor.readCircuitState(model ?? executor.model),\n })),\n );\n }\n\n /**\n * The live counterpart of `getRetryBudgetState`, asking the budget for its current window.\n *\n * @param target.index Which target to read. Defaults to the primary.\n * @returns This target's live retry traffic and ratio, or `undefined` without a budget.\n * @throws {RangeError} If `target.index` names no target.\n */\n async readRetryBudgetState(\n target?: Pick<CircuitTarget, 'index'>,\n ): Promise<RetryBudgetSnapshot | undefined> {\n const executor = resolveExecutor(this.executors, target?.index ?? 0, 'readRetryBudgetState');\n return executor.readRetryBudgetState();\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 = resolveExecutor(this.executors, target?.index ?? 0, 'openCircuit');\n warnIfModelUnsupported(executor.isolateByModel, target?.model, 'openCircuit', this.logger);\n // No logical call behind a manual invocation, so mint a fresh one.\n executor.openCircuit(target?.model ?? executor.model, {\n requestId: globalThis.crypto.randomUUID(),\n state: createMiddlewareStateBag(),\n });\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 = resolveExecutor(this.executors, target?.index ?? 0, 'closeCircuit');\n warnIfModelUnsupported(executor.isolateByModel, target?.model, 'closeCircuit', this.logger);\n // See `openCircuit`.\n executor.closeCircuit(target?.model ?? executor.model, {\n requestId: globalThis.crypto.randomUUID(),\n state: createMiddlewareStateBag(),\n });\n }\n}\n","import type { CachedCallParams, CallParams } from './types/index.js';\n\n/**\n * Keeps `params`' precise type for a reusable variable. A `CallParams<T>` annotation would widen\n * `tools` and lose the conditional tools overload. Pin `T` through `llm.call<T>(params)`.\n */\nexport function defineCallParams<P extends CallParams<unknown>>(params: P): P {\n return params;\n}\n\n/**\n * `cachedCall()` counterpart to `defineCallParams`, keeping the whole `{ cacheKey, ttl, call }`\n * type.\n */\nexport function defineCachedCallParams<P extends CachedCallParams<unknown>>(params: P): P {\n return params;\n}\n"],"mappings":"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"}