vern-llm 1.7.0 → 2.0.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.cjs","names":["message: string","type: LLMErrorType","status?: number","issues?: unknown","cause?: unknown","retryAfterMs?: number","err: unknown","options: CircuitBreakerOptions","content: string","err: unknown","value: unknown","fn: (signal: AbortSignal) => Promise<T>","timeoutMs: number","externalSignal?: AbortSignal","error: unknown","signal?: AbortSignal","baseDelayMs: number","attempt: number","delay: number","params: UsageHooks","coalesced: boolean","getResult: () => Promise<T>","signal: AbortSignal | undefined","onRefundError: (logMessage: string, error: unknown) => void","logMessage: string","result: T","debugEnabled: boolean","message: string","meta?: Record<string, unknown>","key: string","value: T","ttl: number","inner: CacheAdapter<T>","l1: CacheAdapter<T>","l2: CacheAdapter<T>","l1Ttl?: number","options: VernLLMOptions","key: string","params: CallParams<T>","fn: () => Promise<T>","requestId: string","signal?: AbortSignal","lastError: unknown","history: ConversationTurn[]","previousRole: 'user' | 'assistant' | undefined","jsonSchema: CallParams<unknown>['jsonSchema']","useJson: boolean","response: Awaited<ReturnType<LLMClient['chat']['completions']['create']>>","model: string","content: string","schema?: CallParams<T>['schema']","parsed: unknown","attempt: number","error: unknown","params: CachedCallParams<T>","coalesced: boolean","logMessage: string","params: Omit<CachedCallParams<T>, 'fn'> & { call: CallParams<T> }","mimeType: string","blocks: ContentBlock[]","anthropicClient: AnthropicClient","jsonInstruction: string | undefined","tools:\n | NonNullable<Parameters<AnthropicClient['messages']['create']>[0]['tools']>\n | undefined","text: string","blocks: ContentBlock[]","geminiClient: GeminiClient","generationConfig: NonNullable<\n Parameters<GeminiClient['generateContent']>[0]['generationConfig']\n >","mimeType: string","data: string","blocks: ContentBlock[]","bedrockClient: BedrockConverseClient","options?: BedrockAdapterOptions","jsonInstruction: string | undefined","toolConfig:\n | NonNullable<Parameters<BedrockConverseClient['converse']>[0]['toolConfig']>\n | undefined","text","text: string","config: FetchAdapterConfig","blocks: ContentBlock[]","client: unknown"],"sources":["../src/types/errors.ts","../src/circuitBreaker.ts","../src/internal/vernLLM.utils.ts","../src/logger.ts","../src/types/cache.ts","../src/vernLLM.ts","../src/internal/imageFormat.ts","../src/adapters/anthropic.ts","../src/adapters/gemini.ts","../src/adapters/bedrock.ts","../src/adapters/fetch.ts","../src/adapters/openaiCompatible.ts"],"sourcesContent":["export type LLMErrorType =\n | 'timeout'\n | 'api'\n | 'parse'\n | 'validation'\n | 'circuit_open'\n | 'quota_exceeded'\n | 'unknown'\n | 'aborted';\n\nexport class LLMError extends Error {\n constructor(\n message: string,\n public type: LLMErrorType,\n public status?: number,\n public issues?: unknown,\n public cause?: unknown,\n public retryAfterMs?: number,\n ) {\n super(message);\n this.name = 'LLMError';\n }\n}\n\nexport function isLLMError(err: unknown): err is LLMError {\n return err instanceof LLMError;\n}\n","import { LLMError } from './types/errors.js';\n\nexport interface CircuitBreakerOptions {\n /** Consecutive failures before the circuit opens, default 5 */\n threshold?: number;\n /** How long the circuit stays open before allowing a trial request, in ms. Default 30000 */\n cooldownMs?: number;\n}\n\ntype CircuitState = 'closed' | 'open' | 'half-open';\n\n/**\n * Per retry VernLLM-instance circuit breaker. Tracks consecutive failures across\n * calls. Once the threshold is hit, short-circuits new calls with an\n * LLMError('circuit_open') instead of hitting the provider, until the\n * cooldown elapses and a single trial call is allowed through\n */\nexport class CircuitBreaker {\n private state: CircuitState = 'closed';\n private consecutiveFailures = 0;\n private openedAt = 0;\n private threshold: number;\n private cooldownMs: number;\n /**\n * True while a single half-open trial call is in flight. Guards against\n * multiple concurrent callers all treating themselves as \"the\" trial once\n * the cooldown elapses\n */\n private trialInFlight = false;\n\n constructor(options: CircuitBreakerOptions = {}) {\n this.threshold = options.threshold ?? 5;\n this.cooldownMs = options.cooldownMs ?? 30_000;\n }\n\n /**\n * Throws if the circuit is open and the cooldown hasn't elapsed, or if\n * the circuit is half-open and a trial call is already in flight.\n * Otherwise, if the circuit just became eligible for a trial (cooldown\n * elapsed, or half-open with no trial currently running), this call\n * becomes that trial\n */\n assertClosed(): void {\n if (this.state === 'closed') return;\n\n if (this.state === 'open') {\n const elapsed = Date.now() - this.openedAt;\n if (elapsed < this.cooldownMs) {\n throw new LLMError(\n `Circuit open — provider has failed ${this.consecutiveFailures} times in a row. Retry in ${Math.ceil((this.cooldownMs - elapsed) / 1000)}s.`,\n 'circuit_open',\n );\n }\n\n this.state = 'half-open';\n this.trialInFlight = true;\n return;\n }\n\n // state === 'half-open'\n if (this.trialInFlight) {\n throw new LLMError(\n 'Circuit half-open. A trial request is already in flight. Try again shortly.',\n 'circuit_open',\n );\n }\n\n this.trialInFlight = true;\n }\n\n recordSuccess(): void {\n this.consecutiveFailures = 0;\n this.state = 'closed';\n this.trialInFlight = false;\n }\n\n recordFailure(): void {\n this.consecutiveFailures += 1;\n this.trialInFlight = false;\n\n if (this.state === 'half-open') {\n // Trial call failed: reopen and reset the cooldown window.\n this.state = 'open';\n this.openedAt = Date.now();\n return;\n }\n\n if (this.consecutiveFailures >= this.threshold) {\n this.state = 'open';\n this.openedAt = Date.now();\n }\n }\n\n getState(): CircuitState {\n return this.state;\n }\n}\n","import { LLMError } from '../types/errors.js';\n\nimport type { UsageHooks } from '../types/usage.js';\n\nexport function defaultParseJson(content: string): unknown {\n try {\n return JSON.parse(content);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Looks inside an unknown error value and pulls out an http status code\n * if one is present. Checks the status field first then the status code\n * field since different client libraries use different names for this.\n * Returns undefined when the error is not an object or carries no status\n */\nexport function extractStatus(err: unknown): number | undefined {\n if (!err || typeof err !== 'object') return undefined;\n\n const error = err as {\n status?: unknown;\n statusCode?: unknown;\n };\n\n if (typeof error.status === 'number') return error.status;\n if (typeof error.statusCode === 'number') return error.statusCode;\n\n return undefined;\n}\n\nfunction formatSafely(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2) ?? String(value);\n } catch {\n try {\n return String(value);\n } catch {\n return '[unprintable error]';\n }\n }\n}\n\n/**\n * Looks inside an unknown thrown value and pulls out a human-readable\n * description of it. Checks the `error` field first (the provider's raw\n * rejection body, JSON-stringified if possible) then falls back to the\n * message` field. Always returns a safe string, even when the thrown value\n * has hostile properties or cannot be serialized normally.\n */\nexport function describeError(err: unknown): string {\n if (err && typeof err === 'object') {\n try {\n const error = err as { message?: unknown; error?: unknown };\n\n if (error.error !== undefined) {\n return formatSafely(error.error);\n }\n\n if (typeof error.message === 'string') {\n return error.message;\n }\n } catch {\n // Fall through to safe string.\n }\n }\n\n return formatSafely(err);\n}\n\n/**\n * Runs an async function and cancels it if it takes longer than the given\n * timeout. Creates an internal abort controller that fires after the\n * timeout elapses, and combines it with any external signal the caller\n * passed in so either one can cancel the underlying call. If the internal\n * timeout triggers and the underlying operation aborts, the error is\n * converted into an LLMError with type \"timeout\". External cancellations\n * continue to propagate as aborted errors. The internal timer is always\n * cleared afterward, whether the function succeeds, fails, or is aborted,\n * so nothing is left running in the background.\n */\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 timer = setTimeout(() => {\n controller.abort();\n }, timeoutMs);\n\n const signal = externalSignal\n ? AbortSignal.any([externalSignal, controller.signal])\n : controller.signal;\n\n try {\n return await fn(signal);\n } catch (err) {\n if (\n controller.signal.aborted &&\n !externalSignal?.aborted &&\n err instanceof DOMException &&\n err.name === 'AbortError'\n ) {\n throw new LLMError('Request timed out', 'timeout');\n }\n\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Default cap (ms) for both exponential backoff and honored Retry-After\n * values, so a misbehaving/adversarial Retry-After can't stall a caller\n * indefinitely\n */\nexport const DEFAULT_MAX_DELAY_MS = 10_000;\n\n/**\n * Looks inside an unknown error value for a Retry-After header and\n * converts it to milliseconds. Checks `.headers` first (fetch-style,\n * Headers-like with `.get()`), then `.response.headers` (axios-style,\n * plain object) since different client libraries surface headers\n * differently. Supports both the delta-seconds form (\"30\") and the\n * HTTP-date form (\"Wed, 21 Oct 2015 07:28:00 GMT\"). The result is capped\n * at maxDelayMs. Returns undefined when no usable Retry-After is present\n */\nexport function extractRetryAfterMs(\n err: unknown,\n maxDelayMs = DEFAULT_MAX_DELAY_MS,\n): number | undefined {\n if (!err || typeof err !== 'object') return undefined;\n\n const error = err as { headers?: unknown; response?: { headers?: unknown } };\n const headers = error.headers ?? error.response?.headers;\n\n if (!headers || typeof headers !== 'object') return undefined;\n\n const getter = headers as { get?: (name: string) => string | null };\n\n const raw =\n typeof getter.get === 'function'\n ? getter.get('Retry-After')\n : Object.entries(headers as Record<string, string>)\n .find(([name]) => name.toLowerCase() === 'retry-after')\n ?.at(1);\n\n if (typeof raw !== 'string' || raw.trim() === '') return undefined;\n\n const trimmed = raw.trim();\n\n if (/^\\d+$/.test(trimmed)) {\n return Math.max(0, Math.min(Number(trimmed) * 1000, maxDelayMs));\n }\n\n const dateMs = Date.parse(trimmed);\n if (!Number.isNaN(dateMs)) {\n return Math.max(0, Math.min(dateMs - Date.now(), maxDelayMs));\n }\n\n return undefined;\n}\n\n/** Converts any thrown value into a well-typed LLMError. */\nexport function normalizeError(error: unknown, signal?: AbortSignal): LLMError {\n if (signal?.aborted) {\n return new LLMError('LLM request aborted', 'aborted');\n }\n\n if (error instanceof LLMError) return error;\n\n const status = extractStatus(error);\n const retryAfterMs = extractRetryAfterMs(error);\n\n if (status !== undefined) {\n return new LLMError('LLM request failed', 'api', status, undefined, error, retryAfterMs);\n }\n\n return new LLMError('LLM request failed', 'unknown', undefined, undefined, error, retryAfterMs);\n}\n\n/**\n * Exponential backoff with jitter, capped at maxDelayMs.\n * Jitter avoids thundering-herd retries when many callers back off in lockstep,\n * the cap prevents unbounded delays when maxRetries is high\n */\nexport function getBackoffDelay(\n baseDelayMs: number,\n attempt: number,\n maxDelayMs = DEFAULT_MAX_DELAY_MS,\n): number {\n const exp = Math.min(baseDelayMs * 2 ** attempt, maxDelayMs);\n return exp / 2 + Math.random() * (exp / 2);\n}\n\n/**\n * Pauses execution for the given delay before a retry attempt. If an\n * abort signal is provided and it fires while waiting, the pending\n * timer is cancelled immediately and the wait rejects right away with\n * an aborted error instead of continuing to sit idle until the delay\n * would have finished on its own\n */\nexport async function waitForRetry(delay: number, signal?: AbortSignal): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const onAbort = () => {\n clearTimeout(timer);\n reject(new LLMError('Operation aborted', 'aborted'));\n };\n\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, delay);\n\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n\n/**\n * Runs `getResult` after reserving usage, if a `reserveUsage` hook was\n * provided. `refundUsage` fires only if a reservation was actually made.\n * `onRefundError` is called (instead of throwing) whenever a refund attempt\n * itself fails, so a broken refund hook never masks the original error.\n */\nexport async function withReservedUsage<T>(\n params: UsageHooks,\n coalesced: boolean,\n getResult: () => Promise<T>,\n signal: AbortSignal | undefined,\n onRefundError: (logMessage: string, error: unknown) => void,\n): Promise<T> {\n if (signal?.aborted) {\n throw new LLMError('LLM request aborted', 'aborted');\n }\n\n let reserved = false;\n\n try {\n if (params.reserveUsage) {\n await params.reserveUsage({ coalesced, signal });\n reserved = true;\n }\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 undefined,\n undefined,\n error,\n );\n }\n\n const refund = async (logMessage: string) => {\n try {\n await params.refundUsage?.({ coalesced, signal });\n } catch (refundError) {\n onRefundError(logMessage, refundError);\n }\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 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","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","export interface CacheAdapter<T = unknown> {\n get(key: string): Promise<{ hit: boolean; value: T | null }>;\n set(key: string, value: T, ttl: number): Promise<void>;\n delete?(key: string): Promise<void>;\n resolveKey?(key: string): Promise<string>;\n}\n\n/**\n * Trivial default so the package works out of the box with no external deps\n * Not shared across processes, swap in Redis/Upstash/etc for production\n */\nexport class InMemoryCacheAdapter<T = unknown> implements CacheAdapter<T> {\n private store = new Map<string, { value: T; expiresAt: number }>();\n\n constructor(private readonly maxSize = 1000) {}\n\n async get(key: string): Promise<{ hit: boolean; value: T | null }> {\n const entry = this.store.get(key);\n\n if (!entry) return { hit: false, value: null };\n\n if (Date.now() >= entry.expiresAt) {\n this.store.delete(key);\n return { hit: false, value: null };\n }\n\n return { hit: true, value: entry.value };\n }\n\n async set(key: string, value: T, ttl: number): Promise<void> {\n this.cleanupExpiredEntries();\n\n this.store.set(key, {\n value,\n expiresAt: Date.now() + ttl * 1000,\n });\n\n this.enforceSizeLimit();\n }\n\n async delete(key: string): Promise<void> {\n this.store.delete(key);\n }\n\n private cleanupExpiredEntries(): void {\n const now = Date.now();\n\n for (const [key, entry] of this.store) {\n if (now >= entry.expiresAt) {\n this.store.delete(key);\n }\n }\n }\n\n private enforceSizeLimit(): void {\n while (this.store.size > this.maxSize) {\n const oldestKey = this.store.keys().next().value;\n\n if (oldestKey === undefined) break;\n\n this.store.delete(oldestKey);\n }\n }\n}\n\n/**\n * Normalizes keys before caching to avoid duplicate entries from formatting differences.\n */\nexport class NormalizedCacheAdapter<T = unknown> implements CacheAdapter<T> {\n constructor(private readonly inner: CacheAdapter<T> = new InMemoryCacheAdapter<T>()) {}\n\n private normalize(key: string): string {\n return key\n .toLowerCase()\n .trim()\n .replace(/[^\\p{L}\\p{N}\\s]/gu, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n }\n\n async resolveKey(key: string): Promise<string> {\n return this.normalize(key);\n }\n\n async get(key: string): Promise<{ hit: boolean; value: T | null }> {\n return this.inner.get(this.normalize(key));\n }\n\n async set(key: string, value: T, ttl: number): Promise<void> {\n await this.inner.set(this.normalize(key), value, ttl);\n }\n\n async delete(key: string): Promise<void> {\n await this.inner.delete?.(this.normalize(key));\n }\n}\n\n/**\n * Two-tier cache with fast local L1 and shared L2.\n * L2 hits are promoted back to L1.\n */\nexport class TieredCacheAdapter<T = unknown> implements CacheAdapter<T> {\n constructor(\n private readonly l1: CacheAdapter<T>,\n private readonly l2: CacheAdapter<T>,\n private readonly l1Ttl?: number,\n ) {}\n\n /**\n * Forwards to L1's `resolveKey` if it has one, otherwise L2's. L1 is\n * preferred since `get()` checks L1 first, so its notion of \"the same\n * key\" is the one that determines whether a lookup can skip L2 entirely.\n */\n async resolveKey(key: string): Promise<string> {\n if (this.l1.resolveKey) return this.l1.resolveKey(key);\n if (this.l2.resolveKey) return this.l2.resolveKey(key);\n return key;\n }\n\n async get(key: string): Promise<{ hit: boolean; value: T | null }> {\n const l1Result = await this.l1.get(key);\n if (l1Result.hit) return l1Result;\n\n const l2Result = await this.l2.get(key);\n\n if (l2Result.hit) {\n await this.l1.set(key, l2Result.value as T, this.l1Ttl ?? 60);\n }\n\n return l2Result;\n }\n\n async set(key: string, value: T, ttl: number): Promise<void> {\n await Promise.all([this.l1.set(key, value, this.l1Ttl ?? ttl), this.l2.set(key, value, ttl)]);\n }\n\n async delete(key: string): Promise<void> {\n await Promise.all([this.l1.delete?.(key), this.l2.delete?.(key)]);\n }\n}\n","import { randomUUID } from 'crypto';\n\nimport { CircuitBreaker } from './circuitBreaker.js';\nimport {\n defaultParseJson,\n extractStatus,\n extractRetryAfterMs,\n withTimeout,\n getBackoffDelay,\n waitForRetry,\n describeError,\n withReservedUsage,\n normalizeError,\n} from './internal/vernLLM.utils.js';\nimport { ConsoleLogger, type Logger } from './logger.js';\nimport {\n InMemoryCacheAdapter,\n LLMError,\n type CacheAdapter,\n type CachedCallParams,\n type CallParams,\n type ConversationTurn,\n type LLMClient,\n type VernLLMOptions,\n} from './types/index.js';\n\n/**\n * A resilient layer around an LLM chat completions client, this is VernLLM!\n *\n * Adds retry with backoff/jitter, per-attempt timeouts, an optional circuit breaker,\n * JSON parsing with optional schema validation, usage tracking, and an\n * optional response cache, all configurable, all opt-in beyond sensible\n * defaults.\n */\nexport class VernLLM {\n private readonly client: LLMClient;\n private readonly model: string;\n\n private readonly maxRetries: number;\n private readonly timeoutMs: number;\n private readonly baseDelayMs: number;\n private readonly defaultMaxTokens: number;\n\n private readonly cache: CacheAdapter<unknown>;\n private readonly nonRetryableStatus: number[];\n\n private readonly inFlight = new Map<string, Promise<unknown>>();\n\n private readonly parseJson: (content: string) => unknown;\n private readonly onUsage?: VernLLMOptions['onUsage'];\n\n private readonly logger: Logger;\n private readonly breaker?: CircuitBreaker;\n\n /**\n * @param options - Client, model, and tunables. Notable defaults:\n * `maxRetries` 1, `timeoutMs` 25000, `baseDelayMs` 500 (exponential backoff\n * base), `defaultMaxTokens` 1000, `cache` an in-memory adapter,\n * `nonRetryableStatus` `[400, 401, 403, 404, 422]`, `debug` false.\n */\n constructor(options: VernLLMOptions) {\n this.client = options.client;\n this.model = options.model;\n\n this.maxRetries = options.maxRetries ?? 1;\n this.timeoutMs = options.timeoutMs ?? 25_000;\n this.baseDelayMs = options.baseDelayMs ?? 500;\n this.defaultMaxTokens = options.defaultMaxTokens ?? 1000;\n\n this.cache = options.cache ?? new InMemoryCacheAdapter();\n this.nonRetryableStatus = options.nonRetryableStatus ?? [400, 401, 403, 404, 422];\n\n this.parseJson = options.parseJson ?? defaultParseJson;\n this.onUsage = options.onUsage;\n\n this.logger = options.logger ?? new ConsoleLogger(options.debug ?? false);\n this.breaker = options.circuitBreaker\n ? new CircuitBreaker(options.circuitBreaker === true ? undefined : options.circuitBreaker)\n : undefined;\n }\n\n /** Resolves a cache key through the adapter when it supports normalization. */\n private async resolveCacheKey(key: string): Promise<string> {\n return this.cache.resolveKey ? await this.cache.resolveKey(key) : key;\n }\n\n /**\n * Makes a single logical LLM call, retrying on failure per the configured\n * policy. Fails fast if the breaker is open or the signal is already\n * aborted. On exhausting retries, records a breaker failure and rejects\n * with a normalized LLMError.\n *\n * @param params - System/user content plus per-call overrides (model,\n * temperature, jsonMode, schema, signal, etc). See `CallParams`.\n * @returns The parsed (and optionally schema-validated) response, or the\n * raw string content when `jsonMode` is false and no `jsonSchema` is set.\n */\n async call<T = unknown>(params: CallParams<T>): Promise<T> {\n this.breaker?.assertClosed();\n\n if (params.signal?.aborted) {\n throw new LLMError('LLM request aborted', 'aborted');\n }\n\n const requestId = params.requestId ?? randomUUID();\n\n return withReservedUsage(\n params,\n false,\n async () => {\n try {\n return await this.retryWithBackoff(\n () => this.executeCall(params, requestId),\n requestId,\n params.signal,\n );\n } catch (error) {\n const normalized = normalizeError(error, params.signal);\n\n if (\n normalized.type !== 'validation' &&\n normalized.type !== 'parse' &&\n normalized.type !== 'aborted'\n ) {\n this.breaker?.recordFailure();\n }\n\n this.logger.debug(`[vern:${requestId}] error:\\n${describeError(error)}`);\n\n throw normalized;\n }\n },\n params.signal,\n (logMessage, error) => this.logRefundError(logMessage, error),\n );\n }\n\n /** Runs `fn`, retrying with backoff according to `shouldRetry`. */\n private async retryWithBackoff<T>(\n fn: () => Promise<T>,\n requestId: string,\n signal?: AbortSignal,\n ): Promise<T> {\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n try {\n if (attempt > 0) {\n await this.recoverDelay(requestId, attempt, lastError, signal);\n }\n\n return await fn();\n } catch (error) {\n lastError = error;\n\n if (!this.shouldRetry(error, signal)) break;\n }\n }\n\n throw lastError;\n }\n\n /**\n * Performs a single attempt: builds the request, dispatches it with a\n * timeout, and shapes the response. Throws on an empty response so the\n * retry loop treats it like any other transient failure.\n */\n private async executeCall<T>(params: CallParams<T>, requestId: string): Promise<T> {\n const { useJson, model, request } = this.buildRequestPayload(params);\n\n const response = await withTimeout(\n (attemptSignal) => this.client.chat.completions.create(request, { signal: attemptSignal }),\n this.timeoutMs,\n params.signal,\n );\n\n const content = response.choices?.[0]?.message?.content?.trim();\n\n if (!content) {\n throw new LLMError('Empty LLM response', 'api');\n }\n\n this.logger.debug(`[vern:${requestId}] output:\\n${content.slice(0, 800)}`);\n\n this.recordUsage(response, requestId, model);\n\n if (!useJson) {\n this.breaker?.recordSuccess();\n return content as T;\n }\n\n const result = this.parseAndValidate(content, params.schema);\n this.breaker?.recordSuccess();\n\n return result;\n }\n\n /**\n * Validates `history` alternates user/assistant turns, since providers\n * like Anthropic/Gemini reject or mishandle consecutive same-role turns.\n */\n private validateHistory(history: ConversationTurn[]): void {\n let previousRole: 'user' | 'assistant' | undefined;\n\n for (const [index, turn] of history.entries()) {\n if (turn.role !== 'user' && turn.role !== 'assistant') {\n throw new LLMError(\n `Invalid history[${index}].role \"${turn.role}\": must be \"user\" or \"assistant\"`,\n 'validation',\n );\n }\n\n if (turn.role === previousRole) {\n throw new LLMError(\n `history must alternate user/assistant turns: consecutive \"${turn.role}\" turns at history[${index - 1}] and history[${index}]`,\n 'validation',\n );\n }\n\n previousRole = turn.role;\n }\n\n if (previousRole === 'user') {\n throw new LLMError(\n 'The last entry in history is a \"user\" turn, which would collide with the current userContent turn. history must end with an \"assistant\" turn (or be empty).',\n 'validation',\n );\n }\n }\n\n /** Applies per-call defaults and shapes params into the client's request object. */\n private buildRequestPayload<T>(params: CallParams<T>) {\n const {\n systemPrompt,\n userContent,\n history = [],\n temperature = 0.2,\n jsonMode = true,\n maxTokens = this.defaultMaxTokens,\n model = this.model,\n reasoningEffort,\n jsonSchema,\n } = params;\n\n const useJson = jsonMode || Boolean(jsonSchema);\n\n if (params.schema && !useJson) {\n throw new LLMError(\n 'schema was provided but jsonMode: false disables JSON parsing, so nothing would validate it. Remove jsonMode: false, set jsonSchema, or remove schema.',\n 'validation',\n );\n }\n\n const responseFormat = this.buildResponseFormat(jsonSchema, useJson);\n\n this.validateHistory(history);\n\n const request = {\n model,\n temperature,\n max_tokens: maxTokens,\n ...(responseFormat ? { response_format: responseFormat } : {}),\n ...(reasoningEffort ? { reasoning_effort: reasoningEffort } : {}),\n messages: [\n ...(systemPrompt ? [{ role: 'system' as const, content: systemPrompt }] : []),\n ...history.map((turn) => ({ role: turn.role, content: turn.content })),\n { role: 'user' as const, content: userContent },\n ],\n };\n\n return { useJson, model, request };\n }\n\n /**\n * Chooses the response format: a provider-native `jsonSchema` takes\n * priority when supplied (constrains generation directly), otherwise\n * falls back to the looser `json_object` mode when JSON output is\n * requested, or no format at all for plain text responses.\n */\n private buildResponseFormat(jsonSchema: CallParams<unknown>['jsonSchema'], useJson: boolean) {\n if (jsonSchema) {\n return {\n type: 'json_schema' as const,\n json_schema: {\n name: jsonSchema.name,\n schema: jsonSchema.schema,\n strict: jsonSchema.strict ?? true,\n description: jsonSchema.description,\n },\n };\n }\n\n return useJson ? { type: 'json_object' as const } : undefined;\n }\n\n /** Reports token usage to `onUsage`, swallowing and logging any error it throws. */\n private recordUsage(\n response: Awaited<ReturnType<LLMClient['chat']['completions']['create']>>,\n requestId: string,\n model: string,\n ): void {\n if (!response.usage || !this.onUsage) return;\n\n try {\n this.onUsage({\n promptTokens: response.usage.prompt_tokens ?? 0,\n completionTokens: response.usage.completion_tokens ?? 0,\n totalTokens: response.usage.total_tokens ?? 0,\n requestId,\n model,\n });\n } catch (error) {\n this.logger.error('[VernLLM] onUsage failed', {\n message: error instanceof Error ? error.message : 'unknown',\n });\n }\n }\n\n /** Parses response content as JSON and validates it against `schema` when supplied. */\n private parseAndValidate<T>(content: string, schema?: CallParams<T>['schema']): T {\n let parsed: unknown;\n\n try {\n parsed = this.parseJson(content);\n } catch {\n throw new LLMError('Invalid JSON response', 'parse');\n }\n\n if (parsed === null || parsed === undefined) {\n throw new LLMError('Invalid JSON response', 'parse');\n }\n\n if (!schema) return parsed as T;\n\n const result = schema.safeParse(parsed);\n\n if (!result.success) {\n throw new LLMError('Schema validation failed', 'validation', undefined, result.error);\n }\n\n return result.data;\n }\n\n /**\n * Waits out the backoff delay for a retry attempt, honoring a\n * Retry-After header on the failed attempt's error when present.\n * Both Retry-After and plain exponential backoff are capped at the same\n * max delay (see `DEFAULT_MAX_DELAY_MS` in `vernLLM.utils.ts`).\n */\n private async recoverDelay(\n requestId: string,\n attempt: number,\n error: unknown,\n signal?: AbortSignal,\n ) {\n const retryAfterMs = extractRetryAfterMs(error);\n const delay = retryAfterMs ?? getBackoffDelay(this.baseDelayMs, attempt);\n\n this.logger.warn(\n `[vern:${requestId}] recovery attempt ${attempt}/${this.maxRetries}, waiting ${delay}ms` +\n (retryAfterMs !== undefined ? ' (honoring Retry-After)' : ''),\n );\n\n await waitForRetry(delay, signal);\n }\n\n /** Decides whether a failed attempt is worth retrying. */\n private shouldRetry(error: unknown, signal?: AbortSignal): boolean {\n if (signal?.aborted) return false;\n\n if (error instanceof LLMError && (error.type === 'parse' || error.type === 'validation')) {\n return false;\n }\n\n const status = extractStatus(error);\n\n return !(status !== undefined && this.nonRetryableStatus.includes(status));\n }\n\n /**\n * Removes a cached response by key when the configured cache adapter\n * supports deletion. Cache invalidation is the caller's responsibility;\n * only the application knows when cached data is stale.\n *\n * @param key - The raw cache key (resolved through the adapter's\n * `resolveKey`, if any, before deletion).\n */\n async deleteCache(key: string): Promise<void> {\n if (!this.cache.delete) return;\n\n await this.cache.delete(await this.resolveCacheKey(key));\n }\n\n /**\n * Cache wrapper around caller-supplied logic. Concurrent misses for the\n * same `cacheKey` share a single in-flight call, avoiding cache stampedes.\n *\n * @param params - `cacheKey`, `ttl`, `fn` (the work to run on a cache\n * miss, typically `() => this.call(...)`), and optional\n * `reserveUsage`/`refundUsage`/`signal`. See `CachedCallParams`.\n * @returns The cached value on a hit, or the result of `fn()` on a miss.\n */\n async cachedCall<T>(params: CachedCallParams<T>): Promise<T> {\n const resolvedKey = await this.resolveCacheKey(params.cacheKey);\n const resolvedParams =\n resolvedKey === params.cacheKey ? params : { ...params, cacheKey: resolvedKey };\n\n const cached = await this.cache.get(resolvedKey);\n\n if (cached.hit) return cached.value as T;\n\n const existing = this.inFlight.get(resolvedKey) as Promise<T> | undefined;\n\n if (existing) {\n return withReservedUsage(\n resolvedParams,\n true,\n () => existing,\n params.signal,\n (logMessage, error) => this.logRefundError(logMessage, error),\n );\n }\n\n return this.registerTrigger(resolvedParams, false);\n }\n\n /** Starts the shared fn() call for a cache miss and tracks it in the in-flight map until it settles. */\n private registerTrigger<T>(params: CachedCallParams<T>, coalesced: boolean): Promise<T> {\n const resultPromise = withReservedUsage(\n params,\n coalesced,\n () => this.runAndCache(params),\n params.signal,\n (logMessage, error) => this.logRefundError(logMessage, error),\n );\n\n this.inFlight.set(params.cacheKey, resultPromise);\n\n void resultPromise\n .catch(() => {})\n .finally(() => {\n this.inFlight.delete(params.cacheKey);\n });\n\n return resultPromise;\n }\n\n /** Runs `fn` and writes its result to the cache. */\n private async runAndCache<T>(params: CachedCallParams<T>): Promise<T> {\n const result = await params.fn();\n\n try {\n await this.cache.set(params.cacheKey, result, params.ttl);\n } catch (error) {\n this.logger.error('[VernLLM] cache write failed', {\n message: error instanceof Error ? error.message : 'unknown',\n });\n }\n\n return result;\n }\n\n /** Logs a failed refundUsage attempt via the configured logger. */\n private logRefundError(logMessage: string, error: unknown): void {\n this.logger.error(logMessage, {\n message: error instanceof Error ? error.message : 'unknown',\n });\n }\n\n /**\n * Convenience wrapper composing `call` + `cachedCall`, so cached LLM calls\n * automatically get retry/timeout/circuit-breaker behavior. `reserveUsage`/\n * `refundUsage` are read from the top-level params only.\n *\n * @param params - `cachedCall` params (`cacheKey`, `ttl`, etc, minus `fn`)\n * plus `call`, the `CallParams` to pass through to `this.call(...)`.\n * @returns The cached value on a hit, or the freshly-called result on a miss.\n */\n async cachedLLMCall<T>(\n params: Omit<CachedCallParams<T>, 'fn'> & { call: CallParams<T> },\n ): Promise<T> {\n const { call: callParams, ...cacheParams } = params;\n const {\n reserveUsage: innerReserveUsage,\n refundUsage: innerRefundUsage,\n ...restCallParams\n } = callParams;\n\n if (innerReserveUsage || innerRefundUsage) {\n this.logger.warn(\n '[VernLLM] reserveUsage/refundUsage on `call` are ignored by cachedLLMCall; set them at the top level instead.',\n );\n }\n\n return this.cachedCall({ ...cacheParams, fn: () => this.call(restCallParams) });\n }\n\n /**\n * @returns The current circuit breaker state (`'closed' | 'open' |\n * 'half-open'`), or undefined if no circuit breaker was configured.\n */\n getCircuitState() {\n return this.breaker?.getState();\n }\n}\n","import { LLMError } from '../types/index.js';\n\n/**\n * MIME types accepted for `ImageBlock.mimeType` across all adapters. This is\n * the intersection of what Anthropic, Gemini, OpenAI-compatible, and Bedrock\n * Converse all natively support, so a `ContentBlock[]` that validates for\n * one provider validates for all of them.\n */\nexport const SUPPORTED_IMAGE_MIME_TYPES = [\n 'image/png',\n 'image/jpeg',\n 'image/gif',\n 'image/webp',\n] as const;\n\nexport type SupportedImageMimeType = (typeof SUPPORTED_IMAGE_MIME_TYPES)[number];\n\n/**\n * Validates an `ImageBlock.mimeType` against the shared supported set.\n * Throws a non-retryable `LLMError('validation')`, since an unsupported\n * mimeType is a permanent failure, retrying the same input can't fix it,\n * the same way a schema-validation or JSON-parse failure isn't retried.\n */\nexport function assertSupportedImageMimeType(mimeType: string): SupportedImageMimeType {\n if ((SUPPORTED_IMAGE_MIME_TYPES as readonly string[]).includes(mimeType)) {\n return mimeType as SupportedImageMimeType;\n }\n\n throw new LLMError(\n `Unsupported image mimeType \"${mimeType}\": expected one of ${SUPPORTED_IMAGE_MIME_TYPES.join(', ')}`,\n 'validation',\n );\n}\n","import { assertSupportedImageMimeType } from '../internal/imageFormat.js';\n\nimport type { ContentBlock, LLMClient } from '../types/index.js';\n\n/** Anthropic's native per-block content shape for a message. */\ntype AnthropicContentBlock =\n | { type: 'text'; text: string }\n | { type: 'image'; source: { type: 'base64'; media_type: string; data: string } };\n\n/** Minimal structural type for the Anthropic SDK's `messages.create` */\nexport interface AnthropicClient {\n messages: {\n create(\n params: {\n model: string;\n max_tokens: number;\n temperature?: number;\n system?: string;\n messages: Array<{ role: 'user' | 'assistant'; content: string | AnthropicContentBlock[] }>;\n tools?: Array<{\n name: string;\n description?: string;\n input_schema: Record<string, unknown>;\n strict?: boolean;\n }>;\n tool_choice?: { type: 'tool'; name: string };\n },\n options: { signal: AbortSignal },\n ): Promise<{\n content: Array<{ type: string; text?: string; name?: string; input?: unknown }>;\n usage?: { input_tokens?: number; output_tokens?: number };\n }>;\n };\n}\n\n/**\n * Translates a VernLLM `ContentBlock[]` (our provider-agnostic multimodal\n * shape) into Anthropic's native content-block array: text blocks pass\n * through as-is, image blocks become `{ type: 'image', source: { type:\n * 'base64', media_type, data } }`.\n */\nfunction toAnthropicContent(blocks: ContentBlock[]): AnthropicContentBlock[] {\n return blocks.map((block) =>\n block.type === 'image'\n ? {\n type: 'image',\n source: {\n type: 'base64',\n media_type: assertSupportedImageMimeType(block.mimeType),\n data: block.data,\n },\n }\n : { type: 'text', text: block.text },\n );\n}\n\n/**\n * Wraps an Anthropic SDK client so it satisfies the same `LLMClient`\n * interface VernLLM uses for OpenAI/Groq.\n *\n * `response_format: json_schema` is mapped to Anthropic's forced tool-use:\n * a single tool is defined with `input_schema` set to the caller's schema,\n * `description` forwarded when provided, and `strict` forwarded when set.\n * `tool_choice` forces the model to call it. Provider-constrained schema\n * matching applies only when `strict: true` is forwarded and supported.\n *\n * `response_format: json_object` (no schema to build a tool from) falls\n * back to a system-prompt instruction, since there's nothing to constrain\n * generation against.\n */\nexport function fromAnthropic(anthropicClient: AnthropicClient): LLMClient {\n return {\n chat: {\n completions: {\n async create(params, options) {\n const systemMessage = params.messages.find((m) => m.role === 'system');\n\n // Keep both user and assistant turns, in order, so multi-turn history\n // survives instead of collapsing to consecutive user messages.\n const conversationMessages = params.messages.filter(\n (m): m is typeof m & { role: 'user' | 'assistant' } =>\n m.role === 'user' || m.role === 'assistant',\n );\n\n const toolName =\n params.response_format?.type === 'json_schema'\n ? params.response_format.json_schema.name\n : undefined;\n\n let jsonInstruction: string | undefined;\n let tools:\n | NonNullable<Parameters<AnthropicClient['messages']['create']>[0]['tools']>\n | undefined;\n\n if (params.response_format?.type === 'json_schema' && toolName) {\n const { schema, description, strict } = params.response_format.json_schema;\n\n tools = [\n {\n name: toolName,\n description,\n input_schema: schema,\n strict,\n },\n ];\n } else if (params.response_format?.type === 'json_object') {\n // No schema to build a tool from, fall back to a prompt instruction\n jsonInstruction = 'Respond with valid JSON only, no prose or markdown fences.';\n }\n\n // `reasoning_effort` (OpenAI o-series/gpt-5 style) has no direct Anthropic\n // equivalent. Claude's extended thinking uses a token budget, not a tier\n // string, so it's intentionally dropped here rather than guessed at.\n\n const system = [systemMessage?.content, jsonInstruction].filter(Boolean).join('\\n\\n');\n\n const response = await anthropicClient.messages.create(\n {\n model: params.model,\n max_tokens: params.max_tokens,\n temperature: params.temperature,\n system: system || undefined,\n messages: conversationMessages.map((m) => ({\n role: m.role,\n content: Array.isArray(m.content) ? toAnthropicContent(m.content) : m.content,\n })),\n ...(tools ? { tools, tool_choice: { type: 'tool' as const, name: toolName! } } : {}),\n },\n options,\n );\n\n let text: string;\n\n if (toolName) {\n const toolUse = response.content.find(\n (block) => block.type === 'tool_use' && block.name === toolName,\n );\n\n text = toolUse ? JSON.stringify(toolUse.input) : '';\n } else {\n text = response.content.find((block) => block.type === 'text')?.text ?? '';\n }\n\n return {\n choices: [{ message: { content: text } }],\n usage: {\n prompt_tokens: response.usage?.input_tokens,\n completion_tokens: response.usage?.output_tokens,\n total_tokens:\n (response.usage?.input_tokens ?? 0) + (response.usage?.output_tokens ?? 0),\n },\n };\n },\n },\n },\n };\n}\n","import { assertSupportedImageMimeType } from '../internal/imageFormat.js';\n\nimport type { ContentBlock, LLMClient } from '../types/index.js';\n\n/** Gemini's native per-part content shape for a `contents` entry. */\ntype GeminiPart = { text: string } | { inlineData: { mimeType: string; data: string } };\n\n/**\n * Minimal structural type for VernLLM's two-argument wrapper around Gemini\n * `generateContent`. The wrapper exposes a request shape aligned with the\n * adapter interface, with top-level `systemInstruction` and\n * `generationConfig` fields, while transport options (such as `AbortSignal`)\n * are passed separately as the second argument.\n */\nexport interface GeminiClient {\n generateContent(\n params: {\n model?: string;\n contents: Array<{ role: 'user' | 'model'; parts: GeminiPart[] }>;\n systemInstruction?: { parts: Array<{ text: string }> };\n generationConfig?: {\n temperature?: number;\n maxOutputTokens?: number;\n responseMimeType?: string;\n responseSchema?: Record<string, unknown>;\n };\n },\n options: { signal: AbortSignal },\n ): Promise<{\n candidates?: Array<{ content?: { parts?: Array<{ text?: string }> } }>;\n usageMetadata?: {\n promptTokenCount?: number;\n candidatesTokenCount?: number;\n totalTokenCount?: number;\n };\n }>;\n}\n\n/**\n * Translates a VernLLM `ContentBlock[]` into Gemini's native `parts` array:\n * text blocks become `{ text }`, image blocks become inline data parts\n * (`{ inlineData: { mimeType, data } }`), Gemini's shape for embedding raw\n * base64 image bytes directly in the request.\n */\nfunction toGeminiParts(blocks: ContentBlock[]): GeminiPart[] {\n return blocks.map((block) =>\n block.type === 'image'\n ? { inlineData: { mimeType: assertSupportedImageMimeType(block.mimeType), data: block.data } }\n : { text: block.text },\n );\n}\n\n/**\n * Wraps a Gemini client so it satisfies the `LLMClient` interface VernLLM\n * uses for OpenAI-compatible APIs. Gemini's shape differs on nearly every\n * axis: a `contents` array instead of `messages`, a separate\n * `systemInstruction` field instead of a `system` role message,\n * `generationConfig` instead of top-level `temperature`/`max_tokens`, and\n * native JSON Schema support via `responseMimeType: 'application/json'` +\n * `responseSchema`. `reasoning_effort` has no equivalent. Gemini's thinking\n * models use a token budget, not an effort tier, so it's dropped, same as\n * Anthropic.\n */\nexport function fromGemini(geminiClient: GeminiClient): LLMClient {\n return {\n chat: {\n completions: {\n async create(params, options) {\n const systemMessage = params.messages.find((m) => m.role === 'system');\n // Keep both user and assistant turns, in order. Gemini calls the\n // assistant role 'model' rather than 'assistant'.\n const conversationMessages = params.messages.filter(\n (m) => m.role === 'user' || m.role === 'assistant',\n );\n\n const wantsJson = Boolean(params.response_format);\n const generationConfig: NonNullable<\n Parameters<GeminiClient['generateContent']>[0]['generationConfig']\n > = {\n temperature: params.temperature,\n maxOutputTokens: params.max_tokens,\n };\n\n if (wantsJson) {\n generationConfig.responseMimeType = 'application/json';\n }\n\n if (params.response_format?.type === 'json_schema') {\n const { schema, description } = params.response_format.json_schema;\n\n generationConfig.responseSchema = {\n ...schema,\n ...(description ? { description } : {}),\n };\n }\n\n const response = await geminiClient.generateContent(\n {\n model: params.model,\n contents: conversationMessages.map((m) => ({\n role: m.role === 'assistant' ? ('model' as const) : ('user' as const),\n parts: Array.isArray(m.content) ? toGeminiParts(m.content) : [{ text: m.content }],\n })),\n systemInstruction: systemMessage\n ? // System turns are always plain strings; only user turns can carry ContentBlock[]\n { parts: [{ text: systemMessage.content as string }] }\n : undefined,\n generationConfig,\n },\n options,\n );\n\n const text =\n response.candidates?.[0]?.content?.parts?.map((p) => p.text ?? '').join('') ?? '';\n\n return {\n choices: [{ message: { content: text } }],\n usage: {\n prompt_tokens: response.usageMetadata?.promptTokenCount,\n completion_tokens: response.usageMetadata?.candidatesTokenCount,\n total_tokens: response.usageMetadata?.totalTokenCount,\n },\n };\n },\n },\n },\n };\n}\n","import { assertSupportedImageMimeType } from '../internal/imageFormat.js';\nimport { LLMError, type ContentBlock, type LLMClient } from '../types/index.js';\n\n/** Bedrock Converse's supported inline image formats. */\ntype BedrockImageFormat = 'png' | 'jpeg' | 'gif' | 'webp';\n\n/** Bedrock Converse's native per-block content shape for a message. */\ntype BedrockContentBlock =\n | { text: string }\n | { image: { format: BedrockImageFormat; source: { bytes: Uint8Array } } };\n\n/**\n * Minimal structural type matching AWS Bedrock's Converse API. This is\n * intentionally NOT `BedrockRuntimeClient` itself, the AWS SDK v3 client\n * exposes `.send(command)`, not a direct `.converse()` method, and pulling\n * in `@aws-sdk/client-bedrock-runtime` as a dependency just for its types\n * isn't worth it for a structural adapter. Wrap your client, e.g:\n *\n * ```ts\n * import { BedrockRuntimeClient, ConverseCommand } from '@aws-sdk/client-bedrock-runtime';\n * const client = new BedrockRuntimeClient({ region: 'us-east-1' });\n * const converseClient = {\n * converse: (params, options) =>\n * client.send(new ConverseCommand(params), { abortSignal: options.signal }),\n * };\n * ```\n */\nexport interface BedrockConverseClient {\n converse(\n params: {\n modelId: string;\n messages: Array<{ role: 'user' | 'assistant'; content: BedrockContentBlock[] }>;\n system?: Array<{ text: string }>;\n inferenceConfig?: { temperature?: number; maxTokens?: number };\n toolConfig?: {\n tools: Array<{\n toolSpec: {\n name: string;\n description?: string;\n inputSchema: { json: Record<string, unknown> };\n strict?: boolean;\n };\n }>;\n toolChoice?: { tool: { name: string } };\n };\n },\n options: { signal: AbortSignal },\n ): Promise<{\n output?: {\n message?: {\n content?: Array<{ text?: string; toolUse?: { name?: string; input?: unknown } }>;\n };\n };\n usage?: { inputTokens?: number; outputTokens?: number; totalTokens?: number };\n }>;\n}\n\n/** Maps a `ContentBlock` image MIME type, already validated, to Converse's `format` enum. */\nfunction toBedrockImageFormat(mimeType: string): BedrockImageFormat {\n switch (assertSupportedImageMimeType(mimeType)) {\n case 'image/png':\n return 'png';\n case 'image/jpeg':\n return 'jpeg';\n case 'image/gif':\n return 'gif';\n case 'image/webp':\n return 'webp';\n }\n}\n\n/**\n * Decodes base64 image data into the raw `Uint8Array` bytes Converse's\n * `image.source.bytes` expects (unlike Anthropic/Gemini/OpenAI, which all\n * take base64 strings directly). Uses `Buffer`, since this adapter, like\n * the rest of the package, targets Node.\n */\nfunction decodeBase64(data: string): Uint8Array {\n return new Uint8Array(Buffer.from(data, 'base64'));\n}\n\n/**\n * Translates a VernLLM `ContentBlock[]` into Converse's native content-block\n * array: text blocks pass through as `{ text }`, image blocks become\n * `{ image: { format, source: { bytes } } }` with the base64 payload decoded\n * to raw bytes, since Converse doesn't accept base64 strings directly.\n */\nfunction toBedrockContent(blocks: ContentBlock[]): BedrockContentBlock[] {\n return blocks.map((block) =>\n block.type === 'image'\n ? {\n image: {\n format: toBedrockImageFormat(block.mimeType),\n source: { bytes: decodeBase64(block.data) },\n },\n }\n : { text: block.text },\n );\n}\n\n/**\n * Optional configuration for `fromBedrock`.\n */\nexport interface BedrockAdapterOptions {\n /**\n * Optional preflight check for tool-use support, needed for `jsonSchema`\n * structured output. VernLLM never guesses capability from a failed\n * call's error message (AWS's error text isn't a documented, stable\n * contract), so this is opt-in: pass either a static list of tool-use\n * -capable model IDs, or a predicate function, and VernLLM will reject\n * unsupported models with a clear `LLMError('validation')` *before*\n * dispatching the request, instead of on the wire.\n *\n * Left unset (default), no preflight check runs, and a `jsonSchema` call\n * to an unsupported model surfaces Bedrock's raw `converse` error as-is.\n */\n toolUseSupportedModels?: string[] | ((modelId: string) => boolean);\n}\n\n/**\n * Wraps a Bedrock Converse-API client so it satisfies the `LLMClient`\n * interface VernLLM uses for OpenAI/Groq. The Converse API is unified\n * across Bedrock's model families (Anthropic, Titan, Llama, Mistral, etc.),\n * so unlike raw per-model Bedrock invocation, this one adapter works\n * regardless of which underlying model `modelId` points at, as long as\n * that model supports Converse (most current-generation ones do)\n *\n * `response_format: json_schema` is mapped to Converse's `toolConfig`: a\n * single tool is defined from the schema, description, and strictness settings,\n * and `toolChoice` forces the model to call it. Provider-constrained schema\n * matching applies only when `strict: true` is forwarded and supported.\n * Native tool support varies by model family; pass\n * `toolUseSupportedModels` to preflight-check it (see\n * `BedrockAdapterOptions`), otherwise a `jsonSchema` call to an\n * unsupported model surfaces Bedrock's raw error unchanged.\n *\n * `response_format: json_object` (no schema to build a tool from) and\n * `reasoning_effort` (no Converse equivalent) fall back to a system-prompt\n * instruction and are dropped respectively.\n */\nexport function fromBedrock(\n bedrockClient: BedrockConverseClient,\n options?: BedrockAdapterOptions,\n): LLMClient {\n const toolUseSupportedModels = options?.toolUseSupportedModels;\n\n return {\n chat: {\n completions: {\n async create(params, requestOptions) {\n const systemMessage = params.messages.find((m) => m.role === 'system');\n\n // Keep both user and assistant turns, in order, so conversation\n // history survives instead of collapsing to consecutive user turns.\n const conversationMessages = params.messages.filter(\n (m): m is typeof m & { role: 'user' | 'assistant' } =>\n m.role === 'user' || m.role === 'assistant',\n );\n\n const jsonSchema =\n params.response_format?.type === 'json_schema'\n ? params.response_format.json_schema\n : undefined;\n\n const toolName = jsonSchema?.name.trim();\n\n if (jsonSchema && !toolName) {\n throw new LLMError('json_schema.name must not be empty.', 'validation');\n }\n\n let jsonInstruction: string | undefined;\n let toolConfig:\n | NonNullable<Parameters<BedrockConverseClient['converse']>[0]['toolConfig']>\n | undefined;\n\n if (jsonSchema) {\n const { schema, description, strict } = jsonSchema;\n\n toolConfig = {\n tools: [\n {\n toolSpec: {\n name: toolName!,\n description,\n inputSchema: { json: schema },\n strict,\n },\n },\n ],\n toolChoice: { tool: { name: toolName! } },\n };\n } else if (params.response_format?.type === 'json_object') {\n // No schema to build a tool from, fall back to a prompt instruction\n jsonInstruction = 'Respond with valid JSON only, no prose or markdown fences.';\n }\n\n if (jsonSchema && toolUseSupportedModels) {\n const isSupported = Array.isArray(toolUseSupportedModels)\n ? toolUseSupportedModels.includes(params.model)\n : toolUseSupportedModels(params.model);\n\n if (!isSupported) {\n throw new LLMError(\n `Bedrock model \"${params.model}\" is not listed in toolUseSupportedModels, but jsonSchema structured output requires Converse tool use.`,\n 'validation',\n );\n }\n }\n\n const systemParts = [systemMessage?.content, jsonInstruction].filter((s): s is string =>\n Boolean(s),\n );\n\n const response = await bedrockClient.converse(\n {\n modelId: params.model,\n messages: conversationMessages.map((m) => ({\n role: m.role,\n content: Array.isArray(m.content)\n ? toBedrockContent(m.content)\n : [{ text: m.content }],\n })),\n system: systemParts.length ? systemParts.map((text) => ({ text })) : undefined,\n inferenceConfig: {\n temperature: params.temperature,\n maxTokens: params.max_tokens,\n },\n ...(toolConfig ? { toolConfig } : {}),\n },\n requestOptions,\n );\n\n let text: string;\n\n if (toolName) {\n // Forced tool-use: the schema-conforming payload arrives as the\n // toolUse content block's already-parsed `input`, not as text.\n // Re-serialize it to JSON so it flows through the same\n // string-content contract every other adapter uses.\n const toolUseBlock = response.output?.message?.content?.find(\n (block) => block.toolUse?.name === toolName,\n );\n\n text = toolUseBlock?.toolUse ? JSON.stringify(toolUseBlock.toolUse.input) : '';\n } else {\n text = response.output?.message?.content?.map((c) => c.text ?? '').join('') ?? '';\n }\n\n return {\n choices: [{ message: { content: text } }],\n usage: {\n prompt_tokens: response.usage?.inputTokens,\n completion_tokens: response.usage?.outputTokens,\n total_tokens: response.usage?.totalTokens,\n },\n };\n },\n },\n },\n };\n}\n","import type { LLMClient } from '../types/index.js';\n\n/** The chat-completion-shaped request VernLLM builds internally */\ntype ChatRequest = Parameters<LLMClient['chat']['completions']['create']>[0];\n\n/**\n * The minimal shape the fetch adapter needs from a response object.\n * Native `fetch`'s `Response` satisfies this, but so do wrappers around\n * `axios`, `node-fetch`, `undici`, etc, which makes `request` swappable\n * without forcing consumers to polyfill the full `Response` interface\n */\nexport interface ResponseLike {\n ok: boolean;\n status: number;\n headers: {\n get(name: string): string | null;\n };\n text(): Promise<string>;\n json(): Promise<unknown>;\n}\n\n/** A fetch-compatible request function; defaults to native `fetch` */\nexport type RequestLike = (\n url: string,\n init: {\n method: string;\n headers: Record<string, string>;\n body?: string;\n signal?: AbortSignal;\n },\n) => Promise<ResponseLike>;\n\nexport interface FetchAdapterConfig {\n /** Endpoint URL, or a function of the request in case it depends on model/params */\n url: string | ((params: ChatRequest) => string);\n /** Static headers, or a function (sync or async) for things like refreshed auth tokens */\n headers?:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>);\n /** HTTP method. Default 'POST' */\n method?: string;\n /**\n * The function used to make the HTTP request. Defaults to native `fetch`.\n * Swap in `axios`, `node-fetch`, or any other transport, as long as it\n * resolves to a `ResponseLike` object\n */\n request?: RequestLike;\n /** Maps VernLLMs internal chat-completion request into the providers raw request body */\n mapRequest: (params: ChatRequest) => unknown;\n /**\n * Maps the providers raw JSON response into `{ content, usage? }`\n * `content` is the assistants text (JSON string when JSON mode was requested)\n */\n mapResponse: (json: unknown) => {\n content: string;\n usage?: { promptTokens?: number; completionTokens?: number; totalTokens?: number };\n };\n}\n\n/**\n * A fetch-based escape hatch for providers with no SDK, or where pulling one\n * in isnt worth it. You supply the URL, headers, and two small mapping\n * functions; this handles the HTTP call and slots the result into the same\n * `LLMClient` shape every other adapter produces, so retries, timeouts,\n * the circuit breaker, and JSON/schema handling all still work unmodified\n *\n * Non-2xx responses throw an error with `.status` set to the HTTP status\n * code, so VernLLMs `nonRetryableStatus` handling (e.g. failing fast on\n * 401/403) applies here too\n */\nexport function fromFetch(config: FetchAdapterConfig): LLMClient {\n return {\n chat: {\n completions: {\n async create(params, options) {\n const url = typeof config.url === 'function' ? config.url(params) : config.url;\n const headers =\n typeof config.headers === 'function' ? await config.headers() : config.headers;\n const method = config.method ?? 'POST';\n const request = config.request ?? fetch;\n\n // GET/HEAD requests can't carry a body, so skip both the body and\n // the Content-Type header for them rather than sending a body a\n // server may reject\n const supportsBody = !['GET', 'HEAD'].includes(method.toUpperCase());\n\n const res = await request(url, {\n method,\n headers: supportsBody\n ? { 'Content-Type': 'application/json', ...headers }\n : { ...headers },\n ...(supportsBody ? { body: JSON.stringify(config.mapRequest(params)) } : {}),\n signal: options.signal,\n });\n\n if (!res.ok) {\n const body = await res.text().catch(() => '');\n const err = new Error(\n `Fetch adapter request failed (${res.status}): ${body.slice(0, 500)}`,\n ) as Error & { status?: number; headers?: ResponseLike['headers'] };\n err.status = res.status;\n // Attach headers so downstream retry logic (e.g. rate-limit\n // handling) can read things like `Retry-After`\n err.headers = res.headers;\n throw err;\n }\n\n const json = await res.json();\n const { content, usage } = config.mapResponse(json);\n\n return {\n choices: [{ message: { content } }],\n usage: usage\n ? {\n prompt_tokens: usage.promptTokens,\n completion_tokens: usage.completionTokens,\n total_tokens: usage.totalTokens,\n }\n : undefined,\n };\n },\n },\n },\n };\n}\n","import { assertSupportedImageMimeType } from '../internal/imageFormat.js';\n\nimport type { ContentBlock, LLMClient } from '../types/index.js';\n\n/** OpenAI's native per-part content shape for a user message. */\ntype OpenAIContentPart =\n | { type: 'text'; text: string }\n | { type: 'image_url'; image_url: { url: string } };\n\n/**\n * Translates a VernLLM `ContentBlock[]` into OpenAI's wire-level content\n * array. Text blocks become `{ type: 'text', text }`; image blocks become\n * `{ type: 'image_url', image_url: { url } }` with the base64 payload\n * inlined as a `data:` URL, since our `ContentBlock` shape (`{ type:\n * 'image', data, mimeType }`) is provider-agnostic and doesn't itself match\n * OpenAI's wire format.\n */\nfunction toOpenAIContent(blocks: ContentBlock[]): OpenAIContentPart[] {\n return blocks.map((block) =>\n block.type === 'image'\n ? {\n type: 'image_url',\n image_url: {\n url: `data:${assertSupportedImageMimeType(block.mimeType)};base64,${block.data}`,\n },\n }\n : { type: 'text', text: block.text },\n );\n}\n\n/**\n * Adapter for any SDK/client whose `chat.completions.create` already\n * matches the OpenAI wire format: this covers most hosted inference\n * providers, since \"OpenAI-compatible\" is a de facto standard for chat\n * completion APIs. Almost everything passes straight through untouched,\n * this exists purely so call sites read clearly (`fromMistral(client)` vs\n * handing a Mistral client to something typed for OpenAI) and so a real\n * transformation could be added later, per-provider, without a breaking\n * change.\n *\n * The one thing that isn't a pure passthrough: a `ContentBlock[]`\n * `userContent` is translated into OpenAI's native `image_url` content-part\n * shape, since VernLLM's `ContentBlock` is intentionally provider-agnostic\n * rather than a copy of any one provider's wire format.\n *\n * Not every SDKs own TypeScript types line up exactly with `LLMClient`\n * (extra fields, stricter unions, etc.), so this takes `unknown` and casts:\n * the actual compatibility contract is the JSON each provider sends and\n * receives over the wire, not the SDKs TS types.\n */\nexport function fromOpenAICompatible(client: unknown): LLMClient {\n const raw = client as LLMClient;\n\n return {\n chat: {\n completions: {\n async create(params, options) {\n const messages = params.messages.map((m) =>\n m.role === 'user' && Array.isArray(m.content)\n ? { ...m, content: toOpenAIContent(m.content) }\n : m,\n );\n\n return raw.chat.completions.create(\n { ...params, messages } as Parameters<LLMClient['chat']['completions']['create']>[0],\n options,\n );\n },\n },\n },\n };\n}\n\n// LLM aliases\n\n/** Groqs SDK matches the OpenAI wire format */\nexport const fromGroq = fromOpenAICompatible;\n\n/** Mistrals `chat.completions`-shaped client (or their OpenAI-compat endpoint) */\nexport const fromMistral = fromOpenAICompatible;\n\n/** DeepSeeks API is OpenAI-compatible */\nexport const fromDeepSeek = fromOpenAICompatible;\n\n/** Cerebras inference API is OpenAI-compatible */\nexport const fromCerebras = fromOpenAICompatible;\n\n/** Together AIs API is OpenAI-compatible */\nexport const fromTogether = fromOpenAICompatible;\n\n/** Fireworks AIs API is OpenAI-compatible */\nexport const fromFireworks = fromOpenAICompatible;\n\n/**\n * Ollama exposes an OpenAI-compatible endpoint at `/v1/chat/completions`\n * (as opposed to its native `/api/chat` format, which differs). Point an\n * OpenAI SDK instances `baseURL` at your Ollama server and pass it here:\n * this does not talk to Ollamas native API directly.\n */\nexport const fromOllama = fromOpenAICompatible;\n\n/** OpenRouter's API is OpenAI-compatible */\nexport const fromOpenRouter = fromOpenAICompatible;\n\n/** Perplexity's API is OpenAI-compatible */\nexport const fromPerplexity = fromOpenAICompatible;\n\n/** DeepInfra's API is OpenAI-compatible */\nexport const fromDeepInfra = fromOpenAICompatible;\n\n/** Novita's API is OpenAI-compatible */\nexport const fromNovita = fromOpenAICompatible;\n\n/** Hyperbolic's API is OpenAI-compatible */\nexport const fromHyperbolic = fromOpenAICompatible;\n\n/** Moonshot's (Kimi) API is OpenAI-compatible */\nexport const fromMoonshot = fromOpenAICompatible;\n\n/** Zhipu's (GLM) API is OpenAI-compatible */\nexport const fromZhipu = fromOpenAICompatible;\n\n/**\n * LM Studio exposes an OpenAI-compatible endpoint at `/v1/chat/completions`.\n * Point an OpenAI SDK instance's `baseURL` at your local LM Studio server.\n */\nexport const fromLMStudio = fromOpenAICompatible;\n\n/**\n * vLLM's OpenAI-compatible server mode exposes `/v1/chat/completions`.\n * Point an OpenAI SDK instance's `baseURL` at your vLLM server.\n */\nexport const fromVLLM = fromOpenAICompatible;\n\n/** xAI's Grok API is OpenAI-compatible */\nexport const fromXAI = fromOpenAICompatible;\n\n/** NVIDIA NIM's hosted and self-hosted endpoints are OpenAI-compatible */\nexport const fromNvidiaNIM = fromOpenAICompatible;\n\n/** Vercel AI Gateway is OpenAI-compatible */\nexport const fromVercelAIGateway = fromOpenAICompatible;\n\n/** Cloudflare Workers AI exposes an OpenAI-compatible endpoint */\nexport const fromCloudflareWorkersAI = fromOpenAICompatible;\n\n/** GitHub Models is OpenAI-compatible */\nexport const fromGitHubModels = fromOpenAICompatible;\n\n/** Nebius AI Studio is OpenAI-compatible */\nexport const fromNebius = fromOpenAICompatible;\n\n/** SambaNova Cloud's API is OpenAI-compatible */\nexport const fromSambaNova = fromOpenAICompatible;\n\n/** Baseten's model hosting exposes an OpenAI-compatible endpoint */\nexport const fromBaseten = fromOpenAICompatible;\n\n/** Featherless AI's API is OpenAI-compatible */\nexport const fromFeatherless = fromOpenAICompatible;\n\n/** Friendli AI's serving endpoint is OpenAI-compatible */\nexport const fromFriendli = fromOpenAICompatible;\n\n/** SiliconFlow's API is OpenAI-compatible */\nexport const fromSiliconFlow = fromOpenAICompatible;\n\n/** Parasail's inference API is OpenAI-compatible */\nexport const fromParasail = fromOpenAICompatible;\n\n/** StepFun's API is OpenAI-compatible */\nexport const fromStepFun = fromOpenAICompatible;\n\n/** MiniMax's API is OpenAI-compatible */\nexport const fromMiniMax = fromOpenAICompatible;\n\n/** Lambda Labs' Inference API is OpenAI-compatible */\nexport const fromLambdaLabs = fromOpenAICompatible;\n\n/** Snowflake Cortex's LLM endpoint is OpenAI-compatible */\nexport const fromSnowflakeCortex = fromOpenAICompatible;\n\n/** Anyscale Endpoints' API is OpenAI-compatible */\nexport const fromAnyscale = fromOpenAICompatible;\n\n/** Lepton AI's inference API is OpenAI-compatible */\nexport const fromLepton = fromOpenAICompatible;\n\n/** kluster.ai's inference API is OpenAI-compatible */\nexport const fromKlusterAI = fromOpenAICompatible;\n\n/** Inference.net's API is OpenAI-compatible */\nexport const fromInferenceNet = fromOpenAICompatible;\n\n/** Infermatic's API is OpenAI-compatible */\nexport const fromInfermatic = fromOpenAICompatible;\n\n/** AtlasCloud's inference API is OpenAI-compatible */\nexport const fromAtlasCloud = fromOpenAICompatible;\n\n/** 01.AI's (Yi models) API is OpenAI-compatible */\nexport const from01AI = fromOpenAICompatible;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["message: string","type: LLMErrorType","status?: number","issues?: unknown","cause?: unknown","retryAfterMs?: number","err: unknown","options: CircuitBreakerOptions","tools: ToolDefinition[]","toolCalls: ToolCall[]","wireToolCalls: WireToolCall[]","parsedArgs: unknown","content: string","err: unknown","value: unknown","ms: number | undefined","ms: number","fn: (signal: AbortSignal) => Promise<T>","timeoutMs: number","externalSignal?: AbortSignal","next: () => Promise<IteratorResult<T>>","timeoutMs: number | undefined","onIdle?: () => void","logger?: Pick<Logger, 'debug'>","error: unknown","signal?: AbortSignal","baseDelayMs: number","attempt: number","delay: number","params: UsageHooks","coalesced: boolean","getResult: () => Promise<T>","signal: AbortSignal | undefined","onRefundError: (logMessage: string, error: unknown) => void","logMessage: string","result: T","openStream: () => Promise<{ chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> }>","opened: { chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> }","value: T | CallWithToolsResult<T>","hasTools: boolean","items: StreamChunk[]","promise: Promise<T | CallWithToolsResult<T>>","debugEnabled: boolean","message: string","meta?: Record<string, unknown>","key: string","value: T","ttl: number","inner: CacheAdapter<T>","l1: CacheAdapter<T>","l2: CacheAdapter<T>","l1Ttl?: number","result: unknown","options: VernLLMOptions","key: string","params: CallParams<T>","requestId: string","attempt: number","rawContent: string | null | undefined","wireToolCalls: WireToolCall[] | undefined","useJson: boolean","usage: TokenUsage | undefined","iterator: AsyncIterator<WireStreamChunk>","first: IteratorResult<WireStreamChunk>","model: string","streamController: AbortController","resolveFinal!: (value: T | CallWithToolsResult<T>) => void","rejectFinal!: (error: unknown) => void","buffered: StreamChunk[]","pending: Array<{\n resolve: (result: IteratorResult<StreamChunk>) => void;\n reject: (error: unknown) => void;\n }>","streamError: unknown","chunk: StreamChunk","error: unknown","chunks: AsyncIterable<StreamChunk>","result: IteratorResult<WireStreamChunk>","toolCalls: { name: string; arguments: unknown }[]","tools: NonNullable<CallParams<unknown>['tools']>","fn: (attempt: number) => Promise<T>","signal?: AbortSignal","lastError: unknown","history: ConversationTurn[]","previousTurn: ConversationTurn | undefined","toolChoice: CallParams<unknown>['toolChoice']","turn: ConversationTurn","jsonSchema: CallParams<unknown>['jsonSchema']","response: Awaited<ReturnType<LLMClient['chat']['completions']['create']>>","usage: TokenUsage","error: LLMError","content: string","schema?: CallParams<T>['schema']","parsed: unknown","params: InternalCacheParams<T>","coalesced: boolean","params: InternalCacheStreamParams<T>","hasTools: boolean","resolveInFlight!: (value: T) => void","rejectInFlight!: (error: unknown) => void","trackedResult: Promise<T>","logMessage: string","params:\n | CachedCallParams<T>\n | CachedToolCallParams<T>\n | CachedStreamCallParams<T>\n | CachedStreamToolCallParams<T>","source: AsyncIterable<Uint8Array | string>","text: string","boundary","frame: string","dataLines: string[]","mimeType: string","blocks: ContentBlock[]","schema: Record<string, unknown>","toolName: string","toolChoice: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice']","params: Parameters<LLMClient['chat']['completions']['create']>[0]","jsonInstruction: string | undefined","tools: NonNullable<Parameters<AnthropicClient['messages']['create']>[0]['tools']> | undefined","toolChoice: Parameters<AnthropicClient['messages']['create']>[0]['tool_choice']","body: AnthropicRequestBody","anthropicClient: AnthropicClient","text: string","wireToolCalls: WireToolCall[] | undefined","mergeConsecutiveToolResults","messages: { role: 'user' | 'assistant'; content: string | AnthropicContentBlock[] }[]","m: (typeof messages)[number]","merged: (typeof messages)[number][]","m: Extract<\n Parameters<LLMClient['chat']['completions']['create']>[0]['messages'][number],\n { role: 'user' | 'assistant' | 'tool' }\n >","blocks: AnthropicContentBlock[]","input: unknown","blocks: ContentBlock[]","toolChoice: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice']","m: Extract<\n Parameters<LLMClient['chat']['completions']['create']>[0]['messages'][number],\n { role: 'user' | 'assistant' | 'tool' }\n >","parts: GeminiPart[]","text: string","toolName: string","parsed: unknown","contents: { role: 'user' | 'model'; parts: GeminiPart[] }[]","c: (typeof contents)[number]","merged: (typeof contents)[number][]","params: Parameters<LLMClient['chat']['completions']['create']>[0]","config: GeminiConfig","geminiClient: GeminiClient","wireToolCalls: WireToolCall[] | undefined","lastUsage:\n | NonNullable<Awaited<ReturnType<GeminiClient['generateContent']>>['usageMetadata']>\n | undefined","mimeType: string","data: string","blocks: ContentBlock[]","params: Parameters<LLMClient['chat']['completions']['create']>[0]","toolUseSupportedModels: BedrockAdapterOptions['toolUseSupportedModels']","jsonInstruction: string | undefined","toolConfig: NonNullable<BedrockRequest['toolConfig']> | undefined","request: BedrockRequest","bedrockClient: BedrockConverseClient","options?: BedrockAdapterOptions","text: string","wireToolCalls: WireToolCall[] | undefined","toolChoice: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice']","m: Extract<\n Parameters<LLMClient['chat']['completions']['create']>[0]['messages'][number],\n { role: 'user' | 'assistant' | 'tool' }\n >","blocks: BedrockContentBlock[]","input: unknown","messages: { role: 'user' | 'assistant'; content: BedrockContentBlock[] }[]","m: (typeof messages)[number]","merged: (typeof messages)[number][]","stream: ReadableStream<Uint8Array>","url: string","init: { method: string; headers: Record<string, string>; body?: string; signal?: AbortSignal }","config: FetchAdapterConfig","params: ChatRequest","requestBody: unknown","wireToolCalls: WireToolCall[] | undefined","blocks: ContentBlock[]","params: Parameters<LLMClient['chat']['completions']['create']>[0]","chunk: OpenAIStreamChunk","client: unknown","options: OpenAICompatibleAdapterOptions","options"],"sources":["../src/types/errors.ts","../src/circuitBreaker.ts","../src/internal/vernLLM.utils.ts","../src/logger.ts","../src/types/cache.ts","../src/types/tools.ts","../src/vernLLM.ts","../src/internal/sse.ts","../src/internal/imageFormat.ts","../src/adapters/anthropic.ts","../src/adapters/gemini.ts","../src/adapters/bedrock.ts","../src/adapters/fetch.ts","../src/adapters/openaiCompatible.ts"],"sourcesContent":["export type LLMErrorType =\n | 'timeout'\n | 'api'\n | 'parse'\n | 'validation'\n | 'circuit_open'\n | 'quota_exceeded'\n | 'unknown'\n | 'aborted';\n\nexport class LLMError extends Error {\n constructor(\n message: string,\n public type: LLMErrorType,\n public status?: number,\n public issues?: unknown,\n public cause?: unknown,\n public retryAfterMs?: number,\n ) {\n super(message);\n this.name = 'LLMError';\n }\n}\n\nexport function isLLMError(err: unknown): err is LLMError {\n return err instanceof LLMError;\n}\n","import { LLMError } from './types/errors.js';\n\nexport interface CircuitBreakerOptions {\n /** Consecutive failures before the circuit opens, default 5 */\n threshold?: number;\n /** How long the circuit stays open before allowing a trial request, in ms. Default 30000 */\n cooldownMs?: number;\n}\n\ntype CircuitState = 'closed' | 'open' | 'half-open';\n\n/**\n * Per retry VernLLM-instance circuit breaker. Tracks consecutive failures across\n * calls. Once the threshold is hit, short-circuits new calls with an\n * LLMError('circuit_open') instead of hitting the provider, until the\n * cooldown elapses and a single trial call is allowed through\n */\nexport class CircuitBreaker {\n private state: CircuitState = 'closed';\n private consecutiveFailures = 0;\n private openedAt = 0;\n private threshold: number;\n private cooldownMs: number;\n /**\n * True while a single half-open trial call is in flight. Guards against\n * multiple concurrent callers all treating themselves as \"the\" trial once\n * the cooldown elapses\n */\n private trialInFlight = false;\n\n constructor(options: CircuitBreakerOptions = {}) {\n this.threshold = options.threshold ?? 5;\n this.cooldownMs = options.cooldownMs ?? 30_000;\n }\n\n /**\n * Throws if the circuit is open and the cooldown hasn't elapsed, or if\n * the circuit is half-open and a trial call is already in flight.\n * Otherwise, if the circuit just became eligible for a trial (cooldown\n * elapsed, or half-open with no trial currently running), this call\n * becomes that trial\n */\n assertClosed(): void {\n if (this.state === 'closed') return;\n\n if (this.state === 'open') {\n const elapsed = Date.now() - this.openedAt;\n if (elapsed < this.cooldownMs) {\n throw new LLMError(\n `Circuit open, provider has failed ${this.consecutiveFailures} times in a row. Retry in ${Math.ceil((this.cooldownMs - elapsed) / 1000)}s.`,\n 'circuit_open',\n );\n }\n\n this.state = 'half-open';\n this.trialInFlight = true;\n return;\n }\n\n // state === 'half-open'\n if (this.trialInFlight) {\n throw new LLMError(\n 'Circuit half-open. A trial request is already in flight. Try again shortly.',\n 'circuit_open',\n );\n }\n\n this.trialInFlight = true;\n }\n\n recordSuccess(): void {\n this.consecutiveFailures = 0;\n this.state = 'closed';\n this.trialInFlight = false;\n }\n\n recordFailure(): void {\n this.consecutiveFailures += 1;\n this.trialInFlight = false;\n\n if (this.state === 'half-open') {\n // Trial call failed: reopen and reset the cooldown window.\n this.state = 'open';\n this.openedAt = Date.now();\n return;\n }\n\n if (this.consecutiveFailures >= this.threshold) {\n this.state = 'open';\n this.openedAt = Date.now();\n }\n }\n\n getState(): CircuitState {\n return this.state;\n }\n}\n","import { LLMError } from '../types/errors.js';\n\nimport type { Logger } from '../logger.js';\nimport type { LLMClient, WireToolCall } from '../types/client.js';\nimport type { StreamChunk } from '../types/stream.js';\nimport type { CallWithToolsResult, ToolCall, ToolDefinition } from '../types/tools.js';\nimport type { UsageHooks } from '../types/usage.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 }\n\n return { id: wc.id, name: wc.function.name, arguments: parsedArgs };\n });\n}\n\nexport function defaultParseJson(content: string): unknown {\n try {\n return JSON.parse(content);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Looks inside an unknown error value and pulls out an http status code\n * if one is present. Checks the status field first then the status code\n * field since different client libraries use different names for this,\n * falling back to AWS SDK v3's `$metadata.httpStatusCode` (e.g. Bedrock's\n * `ThrottlingException`), which doesn't set either of the other two.\n * Returns undefined when the error is not an object or carries no status\n */\nexport function extractStatus(err: unknown): number | undefined {\n if (!err || typeof err !== 'object') return undefined;\n\n const error = err as {\n status?: unknown;\n statusCode?: unknown;\n $metadata?: { httpStatusCode?: unknown };\n };\n\n if (typeof error.status === 'number') return error.status;\n if (typeof error.statusCode === 'number') return error.statusCode;\n if (typeof error.$metadata?.httpStatusCode === 'number') return error.$metadata.httpStatusCode;\n\n return undefined;\n}\n\nfunction formatSafely(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2) ?? String(value);\n } catch {\n try {\n return String(value);\n } catch {\n return '[unprintable error]';\n }\n }\n}\n\n/**\n * Looks inside an unknown thrown value and pulls out a human-readable\n * description of it. Checks the `error` field first (the provider's raw\n * rejection body, JSON-stringified if possible) then falls back to the\n * message` field. Always returns a safe string, even when the thrown value\n * has hostile properties or cannot be serialized normally.\n */\nexport function describeError(err: unknown): string {\n if (err && typeof err === 'object') {\n try {\n const error = err as { message?: unknown; error?: unknown };\n\n if (error.error !== undefined) {\n return formatSafely(error.error);\n }\n\n if (typeof error.message === 'string') {\n return error.message;\n }\n } catch {\n // Fall through to safe string.\n }\n }\n\n return formatSafely(err);\n}\n\n/**\n * `setTimeout` silently clamps any delay above this (~24.8 days) or\n * `Infinity` down to ~1ms instead of erroring, so a caller passing\n * `Infinity` as \"no timeout\" gets the opposite of what they asked for.\n * Both timeout helpers below guard against this explicitly.\n */\nconst MAX_SETTIMEOUT_MS = 2_147_483_647;\n\n/** True when a timeout value should be treated as \"disabled\" rather than passed to `setTimeout`. */\nfunction isTimeoutDisabled(ms: number | undefined): boolean {\n return !ms || ms <= 0 || ms === Infinity;\n}\n\n/** Caps a timeout at the largest delay `setTimeout` actually honors. */\nfunction clampTimeoutMs(ms: number): number {\n return Math.min(ms, MAX_SETTIMEOUT_MS);\n}\n\n/**\n * Runs an async function and cancels it if it takes longer than the given\n * timeout. Creates an internal abort controller that fires after the\n * timeout elapses, and combines it with any external signal the caller\n * passed in so either one can cancel the underlying call. If the internal\n * timeout triggers and the underlying operation aborts, the error is\n * converted into an LLMError with type \"timeout\". External cancellations\n * continue to propagate as aborted errors. The internal timer is always\n * cleared afterward, whether the function succeeds, fails, or is aborted,\n * so nothing is left running in the background.\n *\n * `timeoutMs` of `Infinity` (or any value beyond what `setTimeout` can\n * represent) disables the timeout rather than firing almost immediately.\n */\nexport async function withTimeout<T>(\n fn: (signal: AbortSignal) => Promise<T>,\n timeoutMs: number,\n externalSignal?: AbortSignal,\n): Promise<T> {\n const controller = new AbortController();\n\n const timer = isTimeoutDisabled(timeoutMs)\n ? undefined\n : setTimeout(() => {\n controller.abort();\n }, clampTimeoutMs(timeoutMs));\n\n const signal = externalSignal\n ? AbortSignal.any([externalSignal, controller.signal])\n : controller.signal;\n\n try {\n return await fn(signal);\n } catch (err) {\n if (\n controller.signal.aborted &&\n !externalSignal?.aborted &&\n err instanceof DOMException &&\n err.name === 'AbortError'\n ) {\n throw new LLMError('Request timed out', 'timeout');\n }\n\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Races one `iterator.next()` call against a per-call idle timer, to\n * bound the gap *between* chunks (unlike `withTimeout`, which only bounds\n * opening the stream and its first chunk). Without this, a connection\n * that streams one chunk then hangs would never fail.\n *\n * `timeoutMs` of 0/undefined/`Infinity` disables the check. Otherwise\n * rejects with `LLMError('timeout')` if `next()` doesn't settle in time.\n * The clock resets on every call, so the window is measured from the most\n * recent chunk, not from stream start.\n *\n * `onIdle`, if given, is called the moment the timer fires (before the\n * rejection), so callers can abort the underlying transport instead of\n * just walking away from an unread promise. `logger`, if given, records a\n * debug line if `next()` still settles *after* the idle timeout already\n * rejected. `resolve`/`reject` on an already-settled promise is otherwise\n * a silent no-op, so without this the late chunk (possibly the final\n * usage chunk) would vanish with no trace.\n */\nexport function withChunkIdleTimeout<T>(\n next: () => Promise<IteratorResult<T>>,\n timeoutMs: number | undefined,\n onIdle?: () => void,\n logger?: Pick<Logger, 'debug'>,\n): Promise<IteratorResult<T>> {\n if (isTimeoutDisabled(timeoutMs)) {\n return next();\n }\n\n const activeTimeoutMs = timeoutMs as number;\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(`No stream chunk received for ${activeTimeoutMs}ms (idle timeout)`, 'timeout'),\n );\n }, clampTimeoutMs(activeTimeoutMs));\n\n next().then(\n (result) => {\n clearTimeout(timer);\n if (settled) {\n logger?.debug('[VernLLM] chunk resolved after idle timeout already fired; discarding');\n return;\n }\n settled = true;\n resolve(result);\n },\n (error: unknown) => {\n clearTimeout(timer);\n if (settled) {\n logger?.debug(\n '[VernLLM] chunk rejection arrived after idle timeout already fired; discarding',\n );\n return;\n }\n settled = true;\n reject(error);\n },\n );\n });\n}\n\n/**\n * Default cap (ms) for both exponential backoff and honored Retry-After\n * values, so a misbehaving/adversarial Retry-After can't stall a caller\n * indefinitely\n */\nexport const DEFAULT_MAX_DELAY_MS = 10_000;\n\n/**\n * Looks inside an unknown error value for a Retry-After header and\n * converts it to milliseconds. Checks `.headers` first (fetch-style,\n * Headers-like with `.get()`), then `.response.headers` (axios-style,\n * plain object) since different client libraries surface headers\n * differently. Supports both the delta-seconds form (\"30\") and the\n * HTTP-date form (\"Wed, 21 Oct 2015 07:28:00 GMT\"). The result is capped\n * at maxDelayMs. Returns undefined when no usable Retry-After is present\n */\nexport function extractRetryAfterMs(\n err: unknown,\n maxDelayMs = DEFAULT_MAX_DELAY_MS,\n): number | undefined {\n if (!err || typeof err !== 'object') return undefined;\n\n const error = err as { headers?: unknown; response?: { headers?: unknown } };\n const headers = error.headers ?? error.response?.headers;\n\n if (!headers || typeof headers !== 'object') return undefined;\n\n const getter = headers as { get?: (name: string) => string | null };\n\n const raw =\n typeof getter.get === 'function'\n ? getter.get('Retry-After')\n : Object.entries(headers as Record<string, string>)\n .find(([name]) => name.toLowerCase() === 'retry-after')\n ?.at(1);\n\n if (typeof raw !== 'string' || raw.trim() === '') return undefined;\n\n const trimmed = raw.trim();\n\n if (/^\\d+$/.test(trimmed)) {\n return Math.max(0, Math.min(Number(trimmed) * 1000, maxDelayMs));\n }\n\n const dateMs = Date.parse(trimmed);\n if (!Number.isNaN(dateMs)) {\n return Math.max(0, Math.min(dateMs - Date.now(), maxDelayMs));\n }\n\n return undefined;\n}\n\n/** Converts any thrown value into a well-typed LLMError. */\nexport function normalizeError(error: unknown, signal?: AbortSignal): LLMError {\n if (signal?.aborted) {\n return new LLMError('LLM request aborted', 'aborted');\n }\n\n if (error instanceof LLMError) return error;\n\n const status = extractStatus(error);\n const retryAfterMs = extractRetryAfterMs(error);\n\n if (status !== undefined) {\n return new LLMError('LLM request failed', 'api', status, undefined, error, retryAfterMs);\n }\n\n return new LLMError('LLM request failed', 'unknown', undefined, undefined, error, retryAfterMs);\n}\n\n/**\n * Exponential backoff with jitter, capped at maxDelayMs.\n * Jitter avoids thundering-herd retries when many callers back off in lockstep,\n * the cap prevents unbounded delays when maxRetries is high\n */\nexport function getBackoffDelay(\n baseDelayMs: number,\n attempt: number,\n maxDelayMs = DEFAULT_MAX_DELAY_MS,\n): number {\n const exp = Math.min(baseDelayMs * 2 ** attempt, maxDelayMs);\n return exp / 2 + Math.random() * (exp / 2);\n}\n\n/**\n * Pauses execution for the given delay before a retry attempt. If an\n * abort signal is provided and it fires while waiting, the pending\n * timer is cancelled immediately and the wait rejects right away with\n * an aborted error instead of continuing to sit idle until the delay\n * would have finished on its own\n */\nexport async function waitForRetry(delay: number, signal?: AbortSignal): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const onAbort = () => {\n clearTimeout(timer);\n reject(new LLMError('Operation aborted', 'aborted'));\n };\n\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, delay);\n\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n\n/**\n * Runs `getResult` after reserving usage, if a `reserveUsage` hook was\n * provided. `refundUsage` fires only if a reservation was actually made.\n * `onRefundError` is called (instead of throwing) whenever a refund attempt\n * itself fails, so a broken refund hook never masks the original error.\n */\nexport async function withReservedUsage<T>(\n params: UsageHooks,\n coalesced: boolean,\n getResult: () => Promise<T>,\n signal: AbortSignal | undefined,\n onRefundError: (logMessage: string, error: unknown) => void,\n): Promise<T> {\n if (signal?.aborted) {\n throw new LLMError('LLM request aborted', 'aborted');\n }\n\n let reserved = false;\n\n try {\n if (params.reserveUsage) {\n await params.reserveUsage({ coalesced, signal });\n reserved = true;\n }\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 undefined,\n undefined,\n error,\n );\n }\n\n const refund = async (logMessage: string) => {\n try {\n await params.refundUsage?.({ coalesced, signal });\n } catch (refundError) {\n onRefundError(logMessage, refundError);\n }\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 let result: T;\n\n try {\n result = await getResult();\n } catch (error) {\n if (reserved) await refund('[VernLLM] refundUsage failed');\n throw error;\n }\n\n if (signal?.aborted) {\n if (reserved) await refund('[VernLLM] refundUsage failed after abort');\n throw new LLMError('LLM request aborted', 'aborted');\n }\n\n return result;\n}\n\n/**\n * Streaming counterpart to `withReservedUsage`. `withReservedUsage` assumes\n * `getResult()` settling *is* the operation's final outcome, awaiting it\n * synchronously before reserve/refund resolve. Streaming can't satisfy that:\n * `call()` must return `{ chunks, finalResult }` as soon as the stream\n * opens, well before the real outcome (validation, schema/tool-call checks)\n * is known.\n *\n * Reserves usage before `openStream` runs, same failure mode as the\n * non-streaming path if `reserveUsage` itself throws (mapped to\n * `quota_exceeded`, nothing opened). If `openStream` itself throws (stream\n * never opened), refunds synchronously and rethrows, exactly like\n * `withReservedUsage` does today. If it succeeds, returns `{ chunks,\n * finalResult }` immediately, refund/report is deferred onto\n * `finalResult`'s continuation, since that's the only point the real\n * outcome is known. This means `onUsageFailure` (and any refund) can fire\n * well after this function itself has returned.\n */\nexport async function withReservedUsageForStream<T>(\n params: UsageHooks,\n openStream: () => Promise<{ chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> }>,\n signal: AbortSignal | undefined,\n onRefundError: (logMessage: string, error: unknown) => void,\n): Promise<{ chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> }> {\n if (signal?.aborted) {\n throw new LLMError('LLM request aborted', 'aborted');\n }\n\n let reserved = false;\n\n try {\n if (params.reserveUsage) {\n await params.reserveUsage({ coalesced: false, signal });\n reserved = true;\n }\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 undefined,\n undefined,\n error,\n );\n }\n\n const refund = async (logMessage: string) => {\n try {\n await params.refundUsage?.({ coalesced: false, signal });\n } catch (refundError) {\n onRefundError(logMessage, refundError);\n }\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/**\n * Converts an already-known cache value back into a plausible \"text\" form\n * for a one-shot replay chunk: passed through unchanged if it's already a\n * string (the `jsonMode: false` case), otherwise `JSON.stringify`'d (the\n * `jsonMode: true` case, where the cached value is the *parsed* result, not\n * the original raw text). This is a reasonable reconstruction, not a\n * byte-identical replay of whatever text the model originally streamed,\n * good enough for `for await (const c of chunks)` call sites that don't\n * branch on hit vs. miss, which is the only thing a cache-hit replay needs\n * to support.\n */\nfunction toReplayText(value: unknown): string {\n return typeof value === 'string' ? value : JSON.stringify(value);\n}\n\n/**\n * Builds a trivially-exhausted one-shot `chunks` iterable from an\n * already-known value, used for a `cachedCall` cache hit, where there's no\n * live generation to relay (see `VernLLM.cachedCall`'s docs). No `usage`\n * chunk is emitted: a cache hit spent no real tokens, so there's nothing to\n * report, matching how non-streaming `cachedCall` never calls `onUsage` on\n * a hit either.\n *\n * `hasTools` must reflect whether the *original* call that produced this\n * cached value had `tools` set, that's what determines whether `value` is\n * `T` directly or a `CallWithToolsResult<T>` wrapper, and it isn't\n * something that can be reliably guessed from the value's shape alone\n * (a `schema`-validated `T` could coincidentally look like a\n * `CallWithToolsResult`).\n */\nexport function buildReplayChunks<T>(\n value: T | CallWithToolsResult<T>,\n hasTools: boolean,\n): AsyncIterable<StreamChunk> {\n const items: StreamChunk[] = [];\n\n if (hasTools) {\n const result = value as CallWithToolsResult<T>;\n\n if (result.type === 'tool_calls') {\n result.toolCalls.forEach((toolCall, index) => {\n items.push({\n type: 'tool_call_delta',\n index,\n id: toolCall.id,\n name: toolCall.name,\n argsDelta: JSON.stringify(toolCall.arguments ?? {}),\n // A replay is always the whole value in one shot, never a\n // fragment, same as Gemini's one-shot tool_call_delta chunks.\n complete: true,\n });\n });\n\n if (result.content) items.push({ type: 'text-delta', delta: result.content });\n } else {\n items.push({ type: 'text-delta', delta: toReplayText(result.content) });\n }\n } else {\n items.push({ type: 'text-delta', delta: toReplayText(value) });\n }\n\n return {\n async *[Symbol.asyncIterator]() {\n for (const item of items) yield item;\n },\n };\n}\n\n/**\n * Streaming counterpart to `buildReplayChunks` for a `cachedCall` that\n * *joined* an already-in-flight call for the same key rather than\n * triggering one itself (see `runCachedStream`'s in-flight-coalescing\n * path): there's no live stream to relay (it isn't this call's stream to\n * relay, see the joiner-path comment in `runCachedStream`), but there's\n * also no value yet, only a pending promise for one. Waits for `promise`,\n * then delegates to `buildReplayChunks`. If `promise` rejects, iterating\n * `chunks` throws that same error, consistent with how a live stream's\n * `chunks` throws on a mid-stream failure.\n */\nexport function buildReplayChunksFromPromise<T>(\n promise: Promise<T | CallWithToolsResult<T>>,\n hasTools: boolean,\n): AsyncIterable<StreamChunk> {\n return {\n async *[Symbol.asyncIterator]() {\n const value = await promise;\n\n yield* buildReplayChunks(value, hasTools);\n },\n };\n}\n","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","export interface CacheAdapter<T = unknown> {\n get(key: string): Promise<{ hit: boolean; value: T | null }>;\n set(key: string, value: T, ttl: number): Promise<void>;\n delete?(key: string): Promise<void>;\n resolveKey?(key: string): Promise<string>;\n}\n\n/**\n * Trivial default so the package works out of the box with no external deps\n * Not shared across processes, swap in Redis/Upstash/etc for production\n */\nexport class InMemoryCacheAdapter<T = unknown> implements CacheAdapter<T> {\n private store = new Map<string, { value: T; expiresAt: number }>();\n\n constructor(private readonly maxSize = 1000) {}\n\n async get(key: string): Promise<{ hit: boolean; value: T | null }> {\n const entry = this.store.get(key);\n\n if (!entry) return { hit: false, value: null };\n\n if (Date.now() >= entry.expiresAt) {\n this.store.delete(key);\n return { hit: false, value: null };\n }\n\n return { hit: true, value: entry.value };\n }\n\n async set(key: string, value: T, ttl: number): Promise<void> {\n this.cleanupExpiredEntries();\n\n this.store.set(key, {\n value,\n expiresAt: Date.now() + ttl * 1000,\n });\n\n this.enforceSizeLimit();\n }\n\n async delete(key: string): Promise<void> {\n this.store.delete(key);\n }\n\n private cleanupExpiredEntries(): void {\n const now = Date.now();\n\n for (const [key, entry] of this.store) {\n if (now >= entry.expiresAt) {\n this.store.delete(key);\n }\n }\n }\n\n private enforceSizeLimit(): void {\n while (this.store.size > this.maxSize) {\n const oldestKey = this.store.keys().next().value;\n\n if (oldestKey === undefined) break;\n\n this.store.delete(oldestKey);\n }\n }\n}\n\n/**\n * Normalizes keys before caching to avoid duplicate entries from formatting differences.\n */\nexport class NormalizedCacheAdapter<T = unknown> implements CacheAdapter<T> {\n constructor(private readonly inner: CacheAdapter<T> = new InMemoryCacheAdapter<T>()) {}\n\n private normalize(key: string): string {\n return key\n .toLowerCase()\n .trim()\n .replace(/[^\\p{L}\\p{N}\\s]/gu, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n }\n\n async resolveKey(key: string): Promise<string> {\n return this.normalize(key);\n }\n\n async get(key: string): Promise<{ hit: boolean; value: T | null }> {\n return this.inner.get(this.normalize(key));\n }\n\n async set(key: string, value: T, ttl: number): Promise<void> {\n await this.inner.set(this.normalize(key), value, ttl);\n }\n\n async delete(key: string): Promise<void> {\n await this.inner.delete?.(this.normalize(key));\n }\n}\n\n/**\n * Two-tier cache with fast local L1 and shared L2.\n * L2 hits are promoted back to L1.\n */\nexport class TieredCacheAdapter<T = unknown> implements CacheAdapter<T> {\n constructor(\n private readonly l1: CacheAdapter<T>,\n private readonly l2: CacheAdapter<T>,\n private readonly l1Ttl?: number,\n ) {}\n\n /**\n * Forwards to L1's `resolveKey` if it has one, otherwise L2's. L1 is\n * preferred since `get()` checks L1 first, so its notion of \"the same\n * key\" is the one that determines whether a lookup can skip L2 entirely.\n */\n async resolveKey(key: string): Promise<string> {\n if (this.l1.resolveKey) return this.l1.resolveKey(key);\n if (this.l2.resolveKey) return this.l2.resolveKey(key);\n return key;\n }\n\n async get(key: string): Promise<{ hit: boolean; value: T | null }> {\n const l1Result = await this.l1.get(key);\n if (l1Result.hit) return l1Result;\n\n const l2Result = await this.l2.get(key);\n\n if (l2Result.hit) {\n await this.l1.set(key, l2Result.value as T, this.l1Ttl ?? 60);\n }\n\n return l2Result;\n }\n\n async set(key: string, value: T, ttl: number): Promise<void> {\n await Promise.all([this.l1.set(key, value, this.l1Ttl ?? ttl), this.l2.set(key, value, ttl)]);\n }\n\n async delete(key: string): Promise<void> {\n await Promise.all([this.l1.delete?.(key), this.l2.delete?.(key)]);\n }\n}\n","import type { SchemaLike } from './schema.js';\n\n/**\n * Describes a capability the model may request, not the capability\n * itself. VernLLM transports this to the provider and parses what comes\n * back; it never executes anything.\n */\nexport interface ToolDefinition {\n name: string;\n description: string;\n /** JSON Schema for the tool's input. */\n parameters: Record<string, unknown>;\n /**\n * Optional client-side validator run on the parsed `arguments` before\n * they're handed back to the caller, mirroring the `schema: SchemaLike<T>`\n * pattern already used for response validation (see `types/schema.ts`).\n * Reuses that zero-dependency, `safeParse`-compatible shape instead of\n * requiring a JSON Schema validator (e.g. ajv) as a new dependency.\n * Failed validation throws `LLMError('validation')`. If omitted, VernLLM\n * parses arguments as JSON but does not validate them further.\n */\n argumentsSchema?: SchemaLike<unknown>;\n}\n\n/** A single tool invocation requested by the model. */\nexport interface ToolCall {\n id: string;\n name: string;\n /** Parsed JSON arguments (and validated, if `argumentsSchema` was set). */\n arguments: unknown;\n}\n\n/** The application's result of executing a `ToolCall`, sent back to the model. */\nexport interface ToolResult {\n toolCallId: string;\n content: unknown;\n /**\n * Signals a failed tool execution back to the model (matches Anthropic's\n * native `is_error` on tool_result blocks). Only `fromAnthropic` honors\n * this today, Gemini and Bedrock have no equivalent wire concept, so\n * other adapters ignore it silently.\n */\n isError?: boolean;\n}\n\n/** `call()` result when `tools` was set and the model produced a normal answer. */\nexport interface ContentResult<T> {\n type: 'content';\n content: T;\n}\n\n/** `call()` result when `tools` was set and the model requested one or more tools. */\nexport interface ToolCallResult {\n type: 'tool_calls';\n toolCalls: ToolCall[];\n /** Any text the model produced alongside the tool request, if present. */\n content?: string;\n}\n\nexport type CallWithToolsResult<T> = ContentResult<T> | ToolCallResult;\n\n/**\n * Runtime-safe check for whether a `call()` result is a `tool_calls`\n * result. Prefer this over relying on TypeScript's static narrowing\n * whenever `params` passed to `call()` wasn't a literal with `tools`\n * inlined (see the \"note on the overload\" in `VernLLM.call`'s docs), in\n * that case TS may have typed the result as plain `T` even though it's\n * actually a `CallWithToolsResult<T>` at runtime, and this check works\n * either way.\n */\nexport function isToolCallResult(result: unknown): result is ToolCallResult {\n return (\n typeof result === 'object' &&\n result !== null &&\n 'type' in result &&\n (result as { type: unknown }).type === 'tool_calls' &&\n Array.isArray((result as { toolCalls?: unknown }).toolCalls)\n );\n}\n\n/** What the model should do about tools on a given call. */\nexport type ToolChoice = 'auto' | 'none' | 'required' | { name: string };\n","import { randomUUID } from 'crypto';\n\nimport { CircuitBreaker } from './circuitBreaker.js';\nimport {\n defaultParseJson,\n extractStatus,\n extractRetryAfterMs,\n withTimeout,\n withChunkIdleTimeout,\n getBackoffDelay,\n waitForRetry,\n describeError,\n withReservedUsage,\n withReservedUsageForStream,\n normalizeError,\n toWireTools,\n toWireToolCalls,\n parseWireToolCalls,\n buildReplayChunks,\n buildReplayChunksFromPromise,\n} from './internal/vernLLM.utils.js';\nimport { ConsoleLogger, type Logger } from './logger.js';\nimport {\n InMemoryCacheAdapter,\n LLMError,\n type CacheAdapter,\n type CachedCallParams,\n type CachedStreamCallParams,\n type CachedStreamToolCallParams,\n type CachedToolCallParams,\n type CallParams,\n type CallWithToolsResult,\n type ConversationTurn,\n type LLMClient,\n type StreamCallResult,\n type StreamChunk,\n type StreamEnabledCallParams,\n type TokenUsage,\n type ToolEnabledCallParams,\n type VernLLMOptions,\n type WireMessage,\n type WireStreamChunk,\n type WireToolCall,\n type WireToolChoice,\n} from './types/index.js';\n\nimport type { InternalCacheParams, InternalCacheStreamParams } from './internal/cache.utils.js';\n\n/**\n * A resilient layer around an LLM chat completions client. This is VernLLM!\n *\n * Adds retry with backoff and jitter, per-attempt timeouts, an optional\n * circuit breaker, JSON parsing with optional schema validation, usage\n * tracking, and an optional response cache. All configurable, all opt-in\n * beyond sensible defaults.\n */\nexport class VernLLM {\n private readonly client: LLMClient;\n private readonly model: string;\n\n private readonly maxRetries: number;\n private readonly timeoutMs: number;\n private readonly chunkIdleTimeoutMs: number;\n private readonly baseDelayMs: number;\n private readonly defaultMaxTokens: number;\n private readonly defaultTemperature: number | null;\n\n private readonly cache: CacheAdapter<unknown>;\n private readonly nonRetryableStatus: number[];\n\n private readonly inFlight = new Map<string, Promise<unknown>>();\n\n private readonly parseJson: (content: string) => unknown;\n private readonly onUsage?: VernLLMOptions['onUsage'];\n private readonly onUsageFailure?: VernLLMOptions['onUsageFailure'];\n\n private readonly logger: Logger;\n private readonly breaker?: CircuitBreaker;\n\n /**\n * @param options Client, model, and tunables. Defaults: `maxRetries` 1,\n * `timeoutMs` 25000, `baseDelayMs` 500, `defaultMaxTokens` 1000,\n * `defaultTemperature` 0.2, `cache` an in-memory adapter,\n * `nonRetryableStatus` `[400, 401, 403, 404, 422]`, `debug` false.\n */\n constructor(options: VernLLMOptions) {\n this.client = options.client;\n this.model = options.model;\n\n this.maxRetries = options.maxRetries ?? 1;\n this.timeoutMs = options.timeoutMs ?? 25_000;\n this.chunkIdleTimeoutMs = options.chunkIdleTimeoutMs ?? 30_000;\n this.baseDelayMs = options.baseDelayMs ?? 500;\n this.defaultMaxTokens = options.defaultMaxTokens ?? 1000;\n this.defaultTemperature =\n options.defaultTemperature === undefined ? 0.2 : options.defaultTemperature;\n\n this.cache = options.cache ?? new InMemoryCacheAdapter();\n this.nonRetryableStatus = options.nonRetryableStatus ?? [400, 401, 403, 404, 422];\n\n this.parseJson = options.parseJson ?? defaultParseJson;\n this.onUsage = options.onUsage;\n this.onUsageFailure = options.onUsageFailure;\n\n this.logger = options.logger ?? new ConsoleLogger(options.debug ?? false);\n this.breaker = options.circuitBreaker\n ? new CircuitBreaker(options.circuitBreaker === true ? undefined : options.circuitBreaker)\n : undefined;\n }\n\n /** Resolves a cache key through the adapter when it supports normalization. */\n private async resolveCacheKey(key: string): Promise<string> {\n return this.cache.resolveKey ? await this.cache.resolveKey(key) : key;\n }\n\n /**\n * Makes a single logical LLM call, retrying on failure per the configured\n * policy. Fails fast if the breaker is open or the signal is already\n * aborted. Rejects with a normalized LLMError on exhausted retries.\n *\n * When `tools` is set, returns a `CallWithToolsResult<T>` instead of `T`:\n * `{ type: 'content', content }` or `{ type: 'tool_calls', toolCalls,\n * content? }`. VernLLM never executes tools; run them yourself and\n * continue via `history` (see `ConversationTurn`). Mutually exclusive\n * with `jsonSchema`/`schema`.\n *\n * TypeScript only picks the tools-aware overload when `tools` is\n * statically present on `params`. If set conditionally on a plain\n * `CallParams<T>`, use `isToolCallResult()` to check the shape at\n * runtime instead. See the Tool Calling docs for details.\n *\n * The same static-vs-dynamic caveat applies to `stream`: TypeScript only\n * selects the streaming overload (returning `StreamCallResult<...>`) when\n * `stream: true` is statically present on `params`. A `stream` value set\n * conditionally on a plain `CallParams<T>` still resolves to `Promise<T>`\n * (or `Promise<CallWithToolsResult<T>>`) at the type level even though\n * the actual runtime result is the `{ chunks, finalResult }` streaming\n * shape whenever `stream` evaluates to `true`, callers doing this should\n * narrow/cast accordingly rather than relying on the static return type.\n *\n * @param params System/user content plus per-call overrides. See `CallParams`.\n * @returns Without `tools` or `stream`: the parsed response, or raw\n * string if `jsonMode` is false. With `tools`: a `CallWithToolsResult<T>`.\n * With `stream: true` (statically): a `{ chunks, finalResult }`\n * `StreamCallResult`, `finalResult` resolving to whichever of the above\n * shapes applies once the stream completes. See `StreamCallResult`.\n */\n async call<T = unknown>(\n params: StreamEnabledCallParams<T> & ToolEnabledCallParams<T>,\n ): Promise<StreamCallResult<CallWithToolsResult<T>>>;\n\n async call<T = unknown>(params: StreamEnabledCallParams<T>): Promise<StreamCallResult<T>>;\n\n async call<T = unknown>(params: ToolEnabledCallParams<T>): Promise<CallWithToolsResult<T>>;\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 this.breaker?.assertClosed();\n\n if (params.signal?.aborted) {\n throw new LLMError('LLM request aborted', 'aborted');\n }\n\n const requestId = params.requestId ?? randomUUID();\n\n if (params.stream) {\n // Same normalize/breaker/logging treatment as non-streaming, applied\n // around opening the stream; mid-stream failures are handled\n // separately in buildStreamResult. Usage refund/report is deferred\n // onto finalResult, since call() must return { chunks, finalResult }\n // before the real outcome is known.\n return withReservedUsageForStream(\n params,\n async () => {\n try {\n return await this.retryWithBackoff(\n (attempt) => this.executeStreamCall(params, requestId, attempt),\n requestId,\n params.signal,\n );\n } catch (error) {\n const normalized = normalizeError(error, params.signal);\n\n if (\n normalized.type !== 'validation' &&\n normalized.type !== 'parse' &&\n normalized.type !== 'aborted'\n ) {\n this.breaker?.recordFailure();\n }\n\n this.logger.debug(`[VernLLM:${requestId}] stream-open error:\\n${describeError(error)}`);\n\n throw normalized;\n }\n },\n params.signal,\n (logMessage, error) => this.logRefundError(logMessage, error),\n );\n }\n\n return withReservedUsage(\n params,\n false,\n async () => {\n try {\n return await this.retryWithBackoff(\n (attempt) => this.executeCall(params, requestId, attempt),\n requestId,\n params.signal,\n );\n } catch (error) {\n const normalized = normalizeError(error, params.signal);\n\n if (\n normalized.type !== 'validation' &&\n normalized.type !== 'parse' &&\n normalized.type !== 'aborted'\n ) {\n this.breaker?.recordFailure();\n }\n\n this.logger.debug(`[VernLLM:${requestId}] error:\\n${describeError(error)}`);\n\n throw normalized;\n }\n },\n params.signal,\n (logMessage, error) => this.logRefundError(logMessage, error),\n );\n }\n\n /**\n * Performs a single attempt: builds the request (translating `tools` to\n * wire shape when present), dispatches it with a timeout, and shapes the\n * response into `T` or a `CallWithToolsResult<T>` when `params.tools` was\n * set. Throws on an empty response (no text and no tool_calls) so the\n * retry loop treats it like any other transient failure.\n */\n private async executeCall<T>(\n params: CallParams<T>,\n requestId: string,\n attempt: number,\n ): Promise<T | CallWithToolsResult<T>> {\n const { useJson, model, request } = this.buildRequestPayload(params);\n\n const response = await withTimeout(\n (attemptSignal) => this.client.chat.completions.create(request, { signal: attemptSignal }),\n this.timeoutMs,\n params.signal,\n );\n\n // Extracted right after the response arrives, before anything else\n // touches it, so a post-response failure still gets its usage reported.\n const usage = this.extractUsage(response, requestId, model);\n\n // Raw and unvalidated on purpose. Extraction (including `.trim()`,\n // which throws on a non-string `content`) happens inside\n // `finalizeResponse`'s try/catch, so a malformed response still gets\n // normalized and its usage failure reported.\n const rawContent = response.choices?.[0]?.message?.content;\n const wireToolCalls = response.choices?.[0]?.message?.tool_calls;\n\n return this.finalizeResponse(\n rawContent,\n wireToolCalls,\n params,\n useJson,\n usage,\n requestId,\n attempt,\n );\n }\n\n /**\n * Shapes a fully-arrived response (content and/or tool_calls, already\n * extracted from the provider's payload) into `T` or a\n * `CallWithToolsResult<T>`. Reused by the streaming path once it has\n * buffered the full text/tool-call deltas, so there's no separate\n * parsing/validation logic for streaming.\n *\n * Normalizes and reports usage failure on error itself, so every caller\n * gets identical error handling without duplicating it.\n */\n private finalizeResponse<T>(\n rawContent: string | null | undefined,\n wireToolCalls: WireToolCall[] | undefined,\n params: CallParams<T>,\n useJson: boolean,\n usage: TokenUsage | undefined,\n requestId: string,\n attempt: number,\n ): T | CallWithToolsResult<T> {\n try {\n // `.trim()` runs inside this try: a malformed response shape\n // (e.g. a non-string `content`) throws here and is normalized and\n // reported like any other post-response failure.\n const content = rawContent?.trim();\n\n if (!content && !wireToolCalls?.length) {\n throw new LLMError('Empty LLM response', 'api');\n }\n\n this.logger.debug(\n `[VernLLM:${requestId}] output:\\n${(content ?? `[${wireToolCalls?.length ?? 0} tool call(s)]`).slice(0, 800)}`,\n );\n\n if (wireToolCalls?.length) {\n if (!params.tools) {\n throw new LLMError(\n 'Provider returned tool_calls but no `tools` were sent with this call.',\n 'api',\n );\n }\n\n const toolCalls = parseWireToolCalls(wireToolCalls);\n\n this.validateToolCallArguments(toolCalls, params.tools);\n this.breaker?.recordSuccess();\n this.reportUsage(usage);\n\n return { type: 'tool_calls', toolCalls, ...(content ? { content } : {}) };\n }\n\n // No tool_calls here, so content must be present.\n const textContent = content ?? '';\n\n if (!useJson) {\n this.breaker?.recordSuccess();\n this.reportUsage(usage);\n\n return params.tools ? { type: 'content', content: textContent as T } : (textContent as T);\n }\n\n const result = this.parseAndValidate<T>(textContent, params.schema);\n this.breaker?.recordSuccess();\n this.reportUsage(usage);\n\n return params.tools ? { type: 'content', content: result } : result;\n } catch (error) {\n // Normalized first so onUsageFailure always gets a real LLMError.\n // Also covers aborted signals: normalizeError returns type\n // 'aborted' in that case.\n const normalized = normalizeError(error, params.signal);\n\n if (usage && normalized.type !== 'aborted') {\n this.reportUsageFailure(usage, normalized, attempt);\n }\n\n throw normalized;\n }\n }\n\n /**\n * Opens a stream for a single attempt: builds the request exactly like\n * `executeCall`, then requires `createStream` on the client (a clear\n * `validation` error if the adapter doesn't support it). The timeout\n * wraps stream construction and the first `.next()` together, not just\n * construction: calling an `async function*` returns an iterator\n * synchronously without running its body until `.next()` is first\n * invoked, so timing only construction would time an operation that's\n * always instant, not the actual connection. Both are folded into a\n * single `withTimeout` so the same abort signal reaches whatever the\n * adapter's `createStream` uses internally for its first network\n * round-trip.\n *\n * Circuit-breaker success is recorded once the stream fully completes,\n * not on the first chunk arriving, so a connection that opens but then\n * dies mid-stream isn't masked as a success (see `buildStreamResult`).\n */\n private async executeStreamCall<T>(\n params: CallParams<T>,\n requestId: string,\n attempt: number,\n ): Promise<{\n chunks: AsyncIterable<StreamChunk>;\n finalResult: Promise<T | CallWithToolsResult<T>>;\n }> {\n const { useJson, model, request } = this.buildRequestPayload(params);\n\n const createStream = this.client.chat.completions.createStream;\n\n if (!createStream) {\n throw new LLMError('stream: true requires a client/adapter with createStream', 'validation');\n }\n\n // One controller for the entire stream, not just opening it. Adapters\n // already thread this signal into their transport for the life of the\n // request (that's how user-initiated cancellation works today), so\n // reusing it for the idle timeout means the same abort() call that\n // fires when the stream goes idle mid-way also tears down the\n // underlying connection, instead of only rejecting VernLLM's own\n // promise while the transport stays open.\n const streamController = new AbortController();\n const combinedExternal = params.signal\n ? AbortSignal.any([params.signal, streamController.signal])\n : streamController.signal;\n\n const { iterator, first } = await withTimeout(\n async (attemptSignal) => {\n const streamIterator = createStream(request, { signal: attemptSignal })[\n Symbol.asyncIterator\n ]();\n const firstResult = await streamIterator.next();\n\n return { iterator: streamIterator, first: firstResult };\n },\n this.timeoutMs,\n combinedExternal,\n );\n\n // An immediately-exhausted stream (no chunks at all) is the streaming\n // equivalent of `executeCall`'s empty-response check: surface the same\n // `LLMError('Empty LLM response', 'api')` so retry behaves identically\n // whether the empty result came from a non-streaming or streaming\n // attempt.\n if (first.done) {\n throw new LLMError('Empty LLM response', 'api');\n }\n\n return this.buildStreamResult(\n iterator,\n first,\n params,\n useJson,\n requestId,\n model,\n attempt,\n streamController,\n );\n }\n\n /**\n * The streaming accumulator: wraps the raw `WireStreamChunk` iterator in\n * an async generator that yields translated `StreamChunk`s to the caller\n * live, as they arrive, with no per-chunk timeout and no bound on total\n * duration, and accumulates text/tool-call deltas internally so that\n * `finalizeResponse` can produce `finalResult` once the stream completes.\n *\n * Two separate try/catches: the iteration loop's catch handles errors\n * the transport itself throws, which aren't normalized yet, so that\n * happens here along with the one `reportUsageFailure` call for them.\n * The second catch, around `finalizeResponse`, does not re-normalize or\n * re-report since `finalizeResponse` already does both internally.\n * Circuit-breaker success is only recorded once the stream fully\n * completes, not when the first chunk arrives, so a connection that\n * opens and then dies mid-way still counts as a failure below instead\n * of masking it.\n */\n private buildStreamResult<T>(\n iterator: AsyncIterator<WireStreamChunk>,\n first: IteratorResult<WireStreamChunk>,\n params: CallParams<T>,\n useJson: boolean,\n requestId: string,\n model: string,\n attempt: number,\n streamController: AbortController,\n ): { chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T | CallWithToolsResult<T>> } {\n let resolveFinal!: (value: T | CallWithToolsResult<T>) => void;\n let rejectFinal!: (error: unknown) => void;\n\n const finalResult = new Promise<T | CallWithToolsResult<T>>((resolve, reject) => {\n resolveFinal = resolve;\n rejectFinal = reject;\n });\n\n // Avoid an unhandled-rejection warning for callers that only read `chunks`.\n finalResult.catch(() => {});\n\n // Push-based, not a pulled generator, so the pump always drives\n // `finalResult` to completion even if `chunks` is never read. Buffer\n // size (not \"has anyone started iterating yet\") is what caps memory,\n // since the pump can outrace the caller starting iteration.\n const MAX_BUFFERED_CHUNKS = 10_000;\n const buffered: StreamChunk[] = [];\n const pending: Array<{\n resolve: (result: IteratorResult<StreamChunk>) => void;\n reject: (error: unknown) => void;\n }> = [];\n let streamDone = false;\n let streamError: unknown;\n let hasLoggedEviction = false;\n\n const push = (chunk: StreamChunk) => {\n const waiter = pending.shift();\n\n if (waiter) {\n waiter.resolve({ done: false, value: chunk });\n return;\n }\n\n buffered.push(chunk);\n\n if (buffered.length > MAX_BUFFERED_CHUNKS * 2) {\n // Nothing else surfaces this: without a log, a caller that never\n // read (or fell behind on) `chunks` has no way to tell eviction,\n // not a provider or transport bug, is why chunks are missing.\n // Logged once per stream, not on every crossing, so an ignored\n // high-volume stream doesn't spam dozens of near-identical lines.\n if (!hasLoggedEviction) {\n hasLoggedEviction = true;\n this.logger.debug(\n `[VernLLM] stream chunk buffer exceeded cap (${MAX_BUFFERED_CHUNKS}), evicting ` +\n `${buffered.length - MAX_BUFFERED_CHUNKS} oldest chunk(s); buffered=${buffered.length}. ` +\n 'The chunks iterable was never read (or fell far behind) for this stream.',\n );\n }\n\n // Trim back down to the cap in one batch operation instead of\n // `shift()`ing a single element off on every push once the cap is\n // reached. A per-push `shift()` here is O(current length) in the\n // worst case, cheap for a handful of calls, but that cost is\n // paid on *every* push for the remainder of an ignored stream,\n // and its real-world cost isn't a stable, engine-independent\n // property: benchmarking this exact pattern at a similar backing\n // -array size showed multi-second stalls for what should be\n // sub-millisecond work. Letting the array grow to 2x the cap\n // before trimming amortizes the O(n) `splice` across\n // `MAX_BUFFERED_CHUNKS` pushes, so the average cost per push\n // stays O(1) regardless of how far past the cap the array is\n // allowed to grow before trimming.\n buffered.splice(0, buffered.length - MAX_BUFFERED_CHUNKS);\n }\n };\n\n const finish = () => {\n streamDone = true;\n\n for (const waiter of pending.splice(0)) {\n waiter.resolve({ done: true, value: undefined });\n }\n };\n\n const fail = (error: unknown) => {\n streamDone = true;\n streamError = error;\n\n for (const waiter of pending.splice(0)) {\n waiter.reject(error);\n }\n };\n\n const chunks: AsyncIterable<StreamChunk> = {\n [Symbol.asyncIterator]() {\n return {\n next(): Promise<IteratorResult<StreamChunk>> {\n if (buffered.length) {\n return Promise.resolve({ done: false, value: buffered.shift() as StreamChunk });\n }\n\n if (streamDone) {\n return streamError\n ? Promise.reject(streamError)\n : Promise.resolve({ done: true, value: undefined });\n }\n\n return new Promise((resolve, reject) => {\n pending.push({ resolve, reject });\n });\n },\n };\n },\n };\n\n const toolCallAcc = new Map<number, { id?: string; name?: string; args: string }>();\n\n let textAcc = '';\n let usage: TokenUsage | undefined;\n\n // Fires immediately, not lazily, so it always drives finalResult to\n // completion regardless of whether the caller reads chunks.\n void (async () => {\n try {\n let result: IteratorResult<WireStreamChunk> = first;\n\n while (!result.done) {\n const wireChunk = result.value;\n\n if (wireChunk.type === 'ping') {\n // No content to accumulate or push. Just resolving here\n // resets the idle-timeout clock on the next .next() call.\n } else if (wireChunk.type === 'text-delta') {\n textAcc += wireChunk.delta;\n push({ type: 'text-delta', delta: wireChunk.delta });\n } else if (wireChunk.type === 'tool_call_delta') {\n const entry = toolCallAcc.get(wireChunk.index) ?? { args: '' };\n\n entry.id ??= wireChunk.id;\n entry.name ??= wireChunk.name;\n entry.args += wireChunk.argumentsDelta ?? '';\n toolCallAcc.set(wireChunk.index, entry);\n\n push({\n type: 'tool_call_delta',\n index: wireChunk.index,\n id: wireChunk.id,\n name: wireChunk.name,\n argsDelta: wireChunk.argumentsDelta,\n complete: wireChunk.complete,\n });\n } else if (wireChunk.type === 'usage') {\n usage = {\n promptTokens: wireChunk.usage.prompt_tokens ?? 0,\n completionTokens: wireChunk.usage.completion_tokens ?? 0,\n totalTokens: wireChunk.usage.total_tokens ?? 0,\n requestId,\n model,\n };\n push({ type: 'usage', usage });\n }\n\n result = await withChunkIdleTimeout(\n () => iterator.next(),\n params.chunkIdleTimeoutMs ?? this.chunkIdleTimeoutMs,\n () => streamController.abort(),\n this.logger,\n );\n }\n } catch (error) {\n // Best-effort cleanup for a processing-time throw (as opposed to\n // `iterator.next()` rejecting, which usually means the adapter's\n // own generator already cleaned up). Two independent layers,\n // since neither is guaranteed to reach every SDK on its own:\n //\n // 1. `iterator.return()`: `iterator` is the async generator\n // returned by the adapter's `createStream`, and every\n // adapter's `createStream` body is a `for await...of` over\n // the SDK's raw stream. Calling `.return()` on a generator\n // suspended inside a `for await...of` forwards `.return()` to\n // the iterable being iterated, standard IteratorClose\n // behavior, so this one call closes the whole chain down to\n // the SDK's own stream, as long as the SDK's stream\n // implements `.return()` (true for every adapter here, see\n // the \"propagates .return()\" test in each adapter's stream\n // unit tests).\n // 2. `streamController.abort()`: aborts the same signal every\n // adapter received for this call. SDKs that honor an\n // AbortSignal for the life of the request, arguably the more\n // common pattern than implementing custom `.return()`\n // forwarding, get closed this way even if layer 1 has nothing\n // to forward to.\n try {\n await iterator.return?.();\n } catch {\n // Cleanup failing isn't the error being reported; swallow it.\n }\n streamController.abort();\n\n const normalized = normalizeError(error, params.signal);\n\n // Idle timeout is the one mid-stream failure that trips the\n // breaker: otherwise a provider that hangs after one chunk would\n // always record a success and never open it.\n if (normalized.type === 'timeout') {\n this.breaker?.recordFailure();\n }\n\n if (usage && normalized.type !== 'aborted') {\n this.reportUsageFailure(usage, normalized, attempt, true);\n }\n\n fail(normalized);\n rejectFinal(normalized);\n\n return;\n }\n\n finish();\n this.breaker?.recordSuccess();\n\n try {\n const wireToolCalls: WireToolCall[] | undefined = toolCallAcc.size\n ? [...toolCallAcc.entries()]\n .sort(([indexA], [indexB]) => indexA - indexB)\n .map(([, entry]) => ({\n id: entry.id ?? '',\n type: 'function' as const,\n function: { name: entry.name ?? '', arguments: entry.args },\n }))\n : undefined;\n\n const finalized = this.finalizeResponse(\n textAcc,\n wireToolCalls,\n params,\n useJson,\n usage,\n requestId,\n attempt,\n );\n\n resolveFinal(finalized);\n } catch (error) {\n // finalizeResponse has already normalized this error and reported\n // the usage failure internally. Just propagate it.\n rejectFinal(error);\n }\n })();\n\n return { chunks, finalResult };\n }\n\n /**\n * Checks every `ToolCall` against the `tools` that were offered, catching\n * a hallucinated tool name early instead of letting it reach the\n * application's dispatch table. Then runs each tool's `argumentsSchema`,\n * if present, throwing `LLMError('validation')` on failure.\n */\n private validateToolCallArguments(\n toolCalls: { name: string; arguments: unknown }[],\n tools: NonNullable<CallParams<unknown>['tools']>,\n ): void {\n const knownNames = new Set(tools.map((t) => t.name));\n\n for (const call of toolCalls) {\n if (!knownNames.has(call.name)) {\n throw new LLMError(\n `Model requested tool \"${call.name}\", which was not in the tools offered ([${[...knownNames].join(', ')}]).`,\n 'api',\n );\n }\n\n const definition = tools.find((t) => t.name === call.name);\n\n if (!definition?.argumentsSchema) continue;\n\n const result = definition.argumentsSchema.safeParse(call.arguments);\n\n if (!result.success) {\n throw new LLMError(\n `Arguments for tool call \"${call.name}\" failed validation`,\n 'validation',\n undefined,\n result.error,\n );\n }\n }\n }\n\n /** Runs `fn`, retrying with backoff according to `shouldRetry`. */\n private async retryWithBackoff<T>(\n fn: (attempt: number) => Promise<T>,\n requestId: string,\n signal?: AbortSignal,\n ): Promise<T> {\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n try {\n if (attempt > 0) {\n await this.recoverDelay(requestId, attempt, lastError, signal);\n }\n\n return await fn(attempt);\n } catch (error) {\n lastError = error;\n\n if (!this.shouldRetry(error, signal)) break;\n }\n }\n\n throw lastError;\n }\n\n /**\n * Validates `history` alternates user/assistant turns, since providers\n * like Anthropic/Gemini reject or mishandle consecutive same-role turns.\n */\n private validateHistory(history: ConversationTurn[]): void {\n let previousTurn: ConversationTurn | undefined;\n\n for (const [index, turn] of history.entries()) {\n if (turn.role === 'tool') {\n if (previousTurn?.role !== 'assistant' || !previousTurn.toolCalls?.length) {\n throw new LLMError(\n `history[${index}] is a \"tool\" turn, but must immediately follow an \"assistant\" turn that requested tools`,\n 'validation',\n );\n }\n\n if (!turn.toolResults?.length) {\n throw new LLMError(\n `history[${index}] is a \"tool\" turn but has no toolResults`,\n 'validation',\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 'validation',\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 'validation',\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 'validation',\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 'validation',\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 'validation',\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 'validation',\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 'validation',\n );\n }\n }\n\n /** Applies per-call defaults and shapes params into the client's request object. */\n private buildRequestPayload<T>(params: CallParams<T>) {\n const {\n systemPrompt,\n userContent,\n history = [],\n maxTokens = this.defaultMaxTokens,\n model = this.model,\n reasoningEffort,\n jsonSchema,\n tools,\n toolChoice,\n } = params;\n\n const temperature =\n params.temperature === undefined ? this.defaultTemperature : params.temperature;\n\n if (tools && (jsonSchema || params.schema)) {\n throw new LLMError(\n '`tools` cannot be combined with `jsonSchema`/`schema`: on Anthropic and Bedrock, ' +\n 'jsonSchema is implemented internally as a forced single-tool call, which would ' +\n 'collide with real tools. Use one or the other.',\n 'validation',\n );\n }\n\n if (tools && tools.length === 0) {\n throw new LLMError(\n '`tools` was an empty array. This is almost always a bug (e.g. a filtered tool list ' +\n 'that ended up empty). An empty `tools` array still switches on tool-call mode ' +\n '(response shape, jsonMode default, wire format) with nothing for the model to call. ' +\n 'Omit `tools` entirely for a normal call, or make sure the array is non-empty.',\n 'validation',\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 'validation',\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 'validation',\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 'validation',\n );\n }\n\n // Defaults to false when tools are set and the caller didn't say otherwise,\n // since forcing a JSON response format alongside tool calling is unreliable\n // across providers.\n const jsonMode = params.jsonMode ?? (tools ? false : true);\n const useJson = jsonMode || Boolean(jsonSchema);\n\n if (params.schema && !useJson) {\n throw new LLMError(\n 'schema was provided but jsonMode: false disables JSON parsing, so nothing would validate it. Remove jsonMode: false, set jsonSchema, or remove schema.',\n 'validation',\n );\n }\n\n const responseFormat = this.buildResponseFormat(jsonSchema, useJson);\n\n this.validateHistory(history);\n\n const request = {\n model,\n ...(temperature !== null ? { temperature } : {}),\n max_tokens: maxTokens,\n ...(responseFormat ? { response_format: responseFormat } : {}),\n ...(reasoningEffort ? { reasoning_effort: reasoningEffort } : {}),\n ...(tools ? { tools: toWireTools(tools) } : {}),\n ...(tools ? { tool_choice: this.buildWireToolChoice(toolChoice) } : {}),\n messages: [\n ...(systemPrompt ? [{ role: 'system' as const, content: systemPrompt }] : []),\n ...history.flatMap((turn): WireMessage[] => this.turnToWireMessages(turn)),\n { role: 'user' as const, content: userContent },\n ] satisfies WireMessage[],\n };\n\n return { useJson, model, request };\n }\n\n /** Maps VernLLM's app-facing `ToolChoice` onto the OpenAI-shaped wire `tool_choice`. */\n private buildWireToolChoice(toolChoice: CallParams<unknown>['toolChoice']): WireToolChoice {\n if (!toolChoice || toolChoice === 'auto') return 'auto';\n if (toolChoice === 'none' || toolChoice === 'required') return toolChoice;\n\n return { type: 'function', function: { name: toolChoice.name } };\n }\n\n /**\n * Expands one `ConversationTurn` into one or more wire messages. Plain\n * user/assistant turns map 1:1. An assistant turn with `toolCalls` maps\n * to an assistant message carrying wire-shaped `tool_calls`. A `'tool'`\n * turn expands into one wire `tool` message per `toolResult`, since\n * OpenAI-shaped wire format wants one message per tool_call_id.\n */\n private turnToWireMessages(turn: ConversationTurn): WireMessage[] {\n if (turn.role === 'tool') {\n return (turn.toolResults ?? []).map((tr) => ({\n role: 'tool' as const,\n tool_call_id: tr.toolCallId,\n content: typeof tr.content === 'string' ? tr.content : JSON.stringify(tr.content ?? null),\n ...(tr.isError ? { is_error: true } : {}),\n }));\n }\n\n if (turn.role === 'assistant' && turn.toolCalls?.length) {\n return [\n {\n role: 'assistant' as const,\n ...(turn.content ? { content: turn.content } : {}),\n tool_calls: toWireToolCalls(turn.toolCalls),\n },\n ];\n }\n\n return [{ role: turn.role as 'user' | 'assistant', content: turn.content ?? '' }];\n }\n\n /**\n * Chooses the response format: a provider-native `jsonSchema` takes\n * priority when supplied (constrains generation directly), otherwise\n * falls back to the looser `json_object` mode when JSON output is\n * requested, or no format at all for plain text responses.\n */\n private buildResponseFormat(jsonSchema: CallParams<unknown>['jsonSchema'], useJson: boolean) {\n if (jsonSchema) {\n return {\n type: 'json_schema' as const,\n json_schema: {\n name: jsonSchema.name,\n schema: jsonSchema.schema,\n strict: jsonSchema.strict ?? true,\n description: jsonSchema.description,\n },\n };\n }\n\n return useJson ? { type: 'json_object' as const } : undefined;\n }\n\n /**\n * Pulls `TokenUsage` out of a raw response, if the provider reported it.\n * Extraction doesn't depend on what happens to the response afterward, so\n * a malformed body can still yield usage if the provider's usage block\n * itself came through intact.\n */\n private extractUsage(\n response: Awaited<ReturnType<LLMClient['chat']['completions']['create']>>,\n requestId: string,\n model: string,\n ): TokenUsage | undefined {\n if (!response.usage) return undefined;\n\n return {\n promptTokens: response.usage.prompt_tokens ?? 0,\n completionTokens: response.usage.completion_tokens ?? 0,\n totalTokens: response.usage.total_tokens ?? 0,\n requestId,\n model,\n };\n }\n\n /** Reports token usage for a successful call, swallowing and logging any error `onUsage` throws. */\n private reportUsage(usage: TokenUsage | undefined): void {\n if (!usage || !this.onUsage) return;\n\n try {\n this.onUsage(usage);\n } catch (error) {\n this.logger.error('[VernLLM] onUsage failed', {\n message: error instanceof Error ? error.message : 'unknown',\n });\n }\n }\n\n /**\n * Reports token usage spent on an attempt that then failed, so it isn't\n * dropped alongside the error. Covers any error thrown after usage\n * extraction, since all of them happen only after a response (real\n * spend) already arrived. Swallows and logs any error `onUsageFailure`\n * itself throws.\n */\n private reportUsageFailure(\n usage: TokenUsage,\n error: LLMError,\n attempt: number,\n terminal = false,\n ): void {\n // Falls back to promptTokens + completionTokens if totalTokens is 0\n // (e.g. a hand-rolled client that omits the total), so the log\n // doesn't understate real spend.\n const displayTokens = usage.totalTokens || usage.promptTokens + usage.completionTokens;\n\n // A mid-stream failure is terminal for that call (no further attempts\n // for this stream), unlike a stream-open failure where attempt N+1 may\n // still follow. Label them differently so the log doesn't imply a\n // retry that isn't coming.\n const attemptText = terminal\n ? 'mid-stream failure (terminal, no further attempts)'\n : `attempt ${attempt + 1}/${this.maxRetries + 1}`;\n\n this.logger.warn(\n `[VernLLM:${usage.requestId}] usage failure, ${attemptText}: ` +\n `type=${error.type} tokens=${displayTokens}`,\n );\n\n if (!this.onUsageFailure) return;\n\n try {\n this.onUsageFailure(usage, error);\n } catch (hookError) {\n this.logger.error('[VernLLM] onUsageFailure failed', {\n message: hookError instanceof Error ? hookError.message : 'unknown',\n });\n }\n }\n\n /** Parses response content as JSON and validates it against `schema` when supplied. */\n private parseAndValidate<T>(content: string, schema?: CallParams<T>['schema']): T {\n let parsed: unknown;\n\n try {\n parsed = this.parseJson(content);\n } catch {\n throw new LLMError('Invalid JSON response', 'parse');\n }\n\n if (parsed === null || parsed === undefined) {\n throw new LLMError('Invalid JSON response', 'parse');\n }\n\n if (!schema) return parsed as T;\n\n const result = schema.safeParse(parsed);\n\n if (!result.success) {\n throw new LLMError('Schema validation failed', 'validation', undefined, result.error);\n }\n\n return result.data;\n }\n\n /**\n * Waits out the backoff delay for a retry attempt, honoring a\n * Retry-After header on the failed attempt's error when present.\n * Both Retry-After and plain exponential backoff are capped at the same\n * max delay (see `DEFAULT_MAX_DELAY_MS` in `vernLLM.utils.ts`).\n */\n private async recoverDelay(\n requestId: string,\n attempt: number,\n error: unknown,\n signal?: AbortSignal,\n ) {\n const retryAfterMs = extractRetryAfterMs(error);\n const delay = retryAfterMs ?? getBackoffDelay(this.baseDelayMs, attempt);\n\n this.logger.warn(\n `[VernLLM:${requestId}] recovery attempt ${attempt}/${this.maxRetries}, waiting ${delay}ms` +\n (retryAfterMs !== undefined ? ' (honoring Retry-After)' : ''),\n );\n\n await waitForRetry(delay, signal);\n }\n\n /** Decides whether a failed attempt is worth retrying. */\n private shouldRetry(error: unknown, signal?: AbortSignal): boolean {\n if (signal?.aborted) return false;\n\n if (error instanceof LLMError && (error.type === 'parse' || error.type === 'validation')) {\n return false;\n }\n\n const status = extractStatus(error);\n\n return !(status !== undefined && this.nonRetryableStatus.includes(status));\n }\n\n /**\n * Removes a cached response by key when the configured cache adapter\n * supports deletion. Cache invalidation is the caller's responsibility;\n * only the application knows when cached data is stale.\n *\n * @param key The raw cache key (resolved through the adapter's\n * `resolveKey`, if any, before deletion).\n */\n async deleteCache(key: string): Promise<void> {\n if (!this.cache.delete) return;\n\n await this.cache.delete(await this.resolveCacheKey(key));\n }\n\n /**\n * Internal cache primitive around caller-supplied logic. Concurrent misses\n * for the same `cacheKey` share a single in-flight call, avoiding cache\n * stampedes.\n *\n * Not part of the public API. Backs the public `cachedCall()`, which\n * always composes this with `call()` so cached results get the same\n * retry/timeout/circuit-breaker guarantees as any other LLM call.\n *\n * @param params `cacheKey`, `ttl`, `fn` (the work to run on a cache\n * miss, typically `() => this.call(...)`), and optional\n * `reserveUsage`/`refundUsage`/`signal`. See `InternalCacheParams`.\n * @returns The cached value on a hit, or the result of `fn()` on a miss.\n */\n private async runCached<T>(params: InternalCacheParams<T>): Promise<T> {\n const resolvedKey = await this.resolveCacheKey(params.cacheKey);\n const resolvedParams =\n resolvedKey === params.cacheKey ? params : { ...params, cacheKey: resolvedKey };\n\n const cached = await this.cache.get(resolvedKey);\n\n if (cached.hit) return cached.value as T;\n\n const existing = this.inFlight.get(resolvedKey) as Promise<T> | undefined;\n\n if (existing) {\n return withReservedUsage(\n resolvedParams,\n true,\n () => existing,\n params.signal,\n (logMessage, error) => this.logRefundError(logMessage, error),\n );\n }\n\n return this.registerTrigger(resolvedParams, false);\n }\n\n /** Starts the shared fn() call for a cache miss and tracks it in the in-flight map until it settles. */\n private registerTrigger<T>(params: InternalCacheParams<T>, coalesced: boolean): Promise<T> {\n const resultPromise = withReservedUsage(\n params,\n coalesced,\n () => this.runAndCache(params),\n params.signal,\n (logMessage, error) => this.logRefundError(logMessage, error),\n );\n\n this.inFlight.set(params.cacheKey, resultPromise);\n\n void resultPromise\n .catch(() => {})\n .finally(() => {\n this.inFlight.delete(params.cacheKey);\n });\n\n return resultPromise;\n }\n\n /** Runs `fn` and writes its result to the cache. */\n private async runAndCache<T>(params: InternalCacheParams<T>): Promise<T> {\n const result = await params.fn();\n\n try {\n await this.cache.set(params.cacheKey, result, params.ttl);\n } catch (error) {\n this.logger.error('[VernLLM] cache write failed', {\n message: error instanceof Error ? error.message : 'unknown',\n });\n }\n\n return result;\n }\n\n /**\n * Streaming counterpart to `runCached`. Three cases:\n *\n * - Hit: no live generation to relay. Returns immediately with\n * `finalResult` resolved to the cached value and a one-shot `chunks`\n * replay built from it, so `for await (const c of chunks)` call sites\n * work identically on a hit or a miss. No usage hooks fire, since\n * nothing was actually spent.\n * - Miss, nothing else in flight for this key: delegates to\n * `registerStreamTrigger`, which opens the stream and relays its\n * `chunks` live.\n * - Miss, but another call for the same key is already in flight: this\n * call has no live chunks of its own to relay, so it's treated like a\n * delayed hit. `finalResult` shares the trigger's in-flight promise\n * (the same `this.inFlight` map non-streaming `runCached` uses, so\n * streaming and non-streaming `cachedCall`s for the same key coalesce\n * against each other too), and `chunks` is a one-shot replay built\n * once that promise resolves.\n */\n private async runCachedStream<T>(\n params: InternalCacheStreamParams<T>,\n hasTools: boolean,\n ): Promise<{ chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> }> {\n const resolvedKey = await this.resolveCacheKey(params.cacheKey);\n const resolvedParams =\n resolvedKey === params.cacheKey ? params : { ...params, cacheKey: resolvedKey };\n\n const cached = await this.cache.get(resolvedKey);\n\n if (cached.hit) {\n const value = cached.value as T;\n\n return { chunks: buildReplayChunks(value, hasTools), finalResult: Promise.resolve(value) };\n }\n\n const existing = this.inFlight.get(resolvedKey) as Promise<T> | undefined;\n\n if (existing) {\n const finalResult = withReservedUsage(\n resolvedParams,\n true,\n () => existing,\n params.signal,\n (logMessage, error) => this.logRefundError(logMessage, error),\n );\n\n return { chunks: buildReplayChunksFromPromise(finalResult, hasTools), finalResult };\n }\n\n return this.registerStreamTrigger(resolvedParams);\n }\n\n /**\n * Opens the shared stream for a cache miss and tracks its settled value\n * in `this.inFlight` until it resolves or rejects. Writes to the cache\n * on success only, matching `runAndCache`.\n *\n * Registers the in-flight promise synchronously, before anything async\n * runs, so a concurrent `cachedCall` for the same key always sees it in\n * time to join instead of triggering its own stream. Settlement is\n * wired onto the whole `withReservedUsageForStream` call rather than a\n * line inside its callback, so any failure point (reserving usage,\n * opening the stream, or the stream itself) reliably settles the\n * in-flight entry instead of leaving it stuck.\n */\n private registerStreamTrigger<T>(\n params: InternalCacheStreamParams<T>,\n ): Promise<{ chunks: AsyncIterable<StreamChunk>; finalResult: Promise<T> }> {\n let resolveInFlight!: (value: T) => void;\n let rejectInFlight!: (error: unknown) => void;\n\n const inFlightResult = new Promise<T>((resolve, reject) => {\n resolveInFlight = resolve;\n rejectInFlight = reject;\n });\n\n this.inFlight.set(params.cacheKey, inFlightResult);\n\n void inFlightResult\n .catch(() => {})\n .finally(() => {\n this.inFlight.delete(params.cacheKey);\n });\n\n const streamPromise = withReservedUsageForStream(\n params,\n async () => {\n const opened = await params.openStream();\n\n const trackedResult: Promise<T> = opened.finalResult.then(\n async (value) => {\n try {\n await this.cache.set(params.cacheKey, value, params.ttl);\n } catch (error) {\n this.logger.error('[VernLLM] cache write failed', {\n message: error instanceof Error ? error.message : 'unknown',\n });\n }\n\n return value;\n },\n (error: unknown) => {\n // Failed calls aren't cached, matching `runAndCache`, which\n // only calls `cache.set` after `fn()` succeeds. Rethrown\n // unchanged so both the refund logic attached downstream and\n // `inFlightResult` see the real failure.\n throw error;\n },\n );\n\n return { chunks: opened.chunks, finalResult: trackedResult };\n },\n params.signal,\n (logMessage, error) => this.logRefundError(logMessage, error),\n );\n\n // Settles `inFlightResult` (registered above) based on `streamPromise`'s\n // own outcome, not a line inside its callback. See this function's\n // docs for why.\n streamPromise.then(\n (opened) => {\n opened.finalResult.then(resolveInFlight, rejectInFlight);\n },\n (error: unknown) => {\n rejectInFlight(error);\n },\n );\n\n return streamPromise;\n }\n\n /** Logs a failed refundUsage attempt via the configured logger. */\n private logRefundError(logMessage: string, error: unknown): void {\n this.logger.error(logMessage, {\n message: error instanceof Error ? error.message : 'unknown',\n });\n }\n\n /**\n * Cache wrapper composing `call` + caching, so cached LLM calls\n * automatically get retry/timeout/circuit-breaker behavior. `reserveUsage`/\n * `refundUsage` are read from the top-level params only. Concurrent misses\n * for the same `cacheKey` share a single in-flight call, avoiding cache\n * stampedes. Supports `stream: true` and `tools` in any combination.\n *\n * When `call.tools` is set, this caches the whole `CallWithToolsResult`,\n * including `tool_calls` results, not just final answers. Whether\n * that's appropriate depends on the tool: caching \"the model decided to\n * call get_weather\" is usually fine to reuse briefly, but caching a\n * decision made under permissions or account state that can change\n * between calls is not. Use a short `ttl` or a separate `cacheKey` for\n * such tools if this distinction matters.\n *\n * There is no public way to cache an arbitrary non-LLM function through\n * `VernLLM`. This method always composes with `call()`. For\n * general-purpose caching unrelated to an LLM call, use a dedicated\n * caching library at the application level instead.\n *\n * @param params `cacheKey`, `ttl`, and optional\n * `reserveUsage`/`refundUsage`/`signal`, plus `call`, the `CallParams`\n * (optionally with `tools` and/or `stream`) to pass through to\n * `this.call(...)`. The top-level `signal` governs the cached operation\n * and its usage hooks only; to also abort the underlying provider\n * request, set `signal` inside `call`.\n * @returns The cached value on a hit, or the freshly-called result on a miss.\n */\n async cachedCall<T>(\n params: CachedStreamToolCallParams<T>,\n ): Promise<StreamCallResult<CallWithToolsResult<T>>>;\n\n async cachedCall<T>(params: CachedStreamCallParams<T>): Promise<StreamCallResult<T>>;\n\n async cachedCall<T>(params: CachedToolCallParams<T>): Promise<CallWithToolsResult<T>>;\n\n async cachedCall<T>(params: CachedCallParams<T>): Promise<T>;\n\n async cachedCall<T>(\n params:\n | CachedCallParams<T>\n | CachedToolCallParams<T>\n | CachedStreamCallParams<T>\n | CachedStreamToolCallParams<T>,\n ): Promise<T | CallWithToolsResult<T> | StreamCallResult<T | CallWithToolsResult<T>>> {\n const { call: callParams, ...cacheParams } = params;\n\n const { reserveUsage, refundUsage, ...restCallParams } = callParams;\n\n if (reserveUsage || refundUsage) {\n this.logger.warn(\n '[VernLLM] reserveUsage/refundUsage on `call` are ignored by cachedCall; set them at the top level instead.',\n );\n }\n\n if (restCallParams.stream) {\n const streamParams = restCallParams as StreamEnabledCallParams<T>;\n\n return this.runCachedStream(\n {\n ...cacheParams,\n openStream: () => this.call(streamParams),\n },\n Boolean(restCallParams.tools),\n );\n }\n\n return this.runCached({\n ...cacheParams,\n fn: () => this.call(restCallParams),\n });\n }\n\n /**\n * @returns The current circuit breaker state (`'closed' | 'open' |\n * 'half-open'`), or undefined if no circuit breaker was configured.\n */\n getCircuitState() {\n return this.breaker?.getState();\n }\n}\n","import { LLMError } from '../types/errors.js';\n\n/**\n * Parses a Server-Sent-Events byte/text stream into the JSON payload of\n * each `data:` frame, in arrival order. Generic over transport: works with\n * anything that hands back progressively-arriving `Uint8Array` or `string`\n * chunks via async iteration: native `fetch`'s `response.body` (wrapped\n * to be iterable, see `webStreamToAsyncIterable` in `fetch.ts`), axios's\n * Node `Readable` (already async-iterable, no wrapping needed), etc, so\n * this framing layer doesn't care which transport produced the bytes.\n *\n * Follows the SSE spec's frame-delimiting rules closely enough for LLM\n * streaming responses: frames are separated by a blank line, each frame\n * may carry one or more `data:` lines (joined with `\\n` per spec when\n * there's more than one), `:`-prefixed lines are comments and ignored, and\n * other SSE fields (`event:`, `id:`, `retry:`) are ignored since VernLLM\n * only needs the payload. A frame whose data is exactly `[DONE]` (the\n * sentinel several providers, notably OpenAI, send to mark stream end)\n * ends iteration without yielding it.\n *\n * Line endings: `\\r\\n` and bare `\\r` (both legal per the SSE spec, alongside `\\n`) are normalized\n * to `\\n` before frame splitting. A `\\r` at the very end of the currently-buffered text is left\n * alone until either more text arrives (in case it's the first half of a split `\\r\\n` pair) or the\n * stream ends, so a `\\r\\n` pair split across two transport chunks is never misread as two blank\n * lines.\n *\n * Malformed JSON in a frame throws `LLMError('parse')`, consistent with\n * how malformed JSON is handled elsewhere in VernLLM.\n */\nexport async function* parseSseStream(\n source: AsyncIterable<Uint8Array | string>,\n): AsyncGenerator<unknown> {\n // `fatal: true` makes invalid UTF-8 throw instead of silently decoding\n // to U+FFFD replacement characters, which could otherwise land inside a\n // JSON string and either corrupt it unnoticeably or, worse, still parse\n // as syntactically valid JSON with silently-wrong content.\n const decoder = new TextDecoder('utf-8', { fatal: true });\n let buffer = '';\n\n for await (const chunk of source) {\n let text: string;\n\n try {\n text = typeof chunk === 'string' ? chunk : decoder.decode(chunk, { stream: true });\n } catch (cause) {\n throw new LLMError('Invalid UTF-8 in SSE stream', 'parse', undefined, undefined, cause);\n }\n\n // Normalized against the whole buffer, not just the newly-arrived\n // chunk: a `\\r\\n` delimiter can straddle a chunk boundary (one chunk\n // ending in `\\r`, the next starting with `\\n`), and normalizing only\n // the new text would miss that split pair. A bare trailing `\\r` (not\n // followed by anything yet) is left as-is for the same reason; it's\n // converted once either more text or end-of-stream resolves whether\n // it was standalone or the start of a split `\\r\\n`.\n buffer = (buffer + text).replace(/\\r\\n/g, '\\n').replace(/\\r(?!$)/g, '\\n');\n\n let boundary = buffer.indexOf('\\n\\n');\n\n while (boundary !== -1) {\n const frame = buffer.slice(0, boundary);\n\n buffer = buffer.slice(boundary + 2);\n\n const event = parseSseFrame(frame);\n\n if (event === DONE) return;\n if (event !== NO_DATA) yield event;\n\n boundary = buffer.indexOf('\\n\\n');\n }\n }\n\n // Flush any bytes TextDecoder held back mid-decode, so a truncated\n // multi-byte char surfaces as a parse error instead of silently\n // vanishing (and possibly leaving behind valid-looking, wrong JSON).\n try {\n buffer += decoder.decode();\n } catch (cause) {\n throw new LLMError('Invalid UTF-8 in SSE stream', 'parse', undefined, undefined, cause);\n }\n\n // The stream has ended, so a trailing `\\r` still held back above (it\n // could have been the start of a split `\\r\\n` pair) can only be a bare\n // CR line ending now. Normalize it and re-check for any frame boundary\n // it just completed.\n buffer = buffer.replace(/\\r$/, '\\n');\n\n let boundary = buffer.indexOf('\\n\\n');\n\n while (boundary !== -1) {\n const frame = buffer.slice(0, boundary);\n\n buffer = buffer.slice(boundary + 2);\n\n const event = parseSseFrame(frame);\n\n if (event === DONE) return;\n if (event !== NO_DATA) yield event;\n\n boundary = buffer.indexOf('\\n\\n');\n }\n\n // Flush a final frame that arrived without a trailing blank line: some\n // servers close the connection right after the last `data:` line instead\n // of sending one more `\\n\\n` first.\n const trailing = buffer.trim();\n\n if (trailing) {\n const event = parseSseFrame(trailing);\n\n if (event !== DONE && event !== NO_DATA) yield event;\n }\n}\n\nconst DONE = Symbol('sse-stream-done');\nconst NO_DATA = Symbol('sse-frame-no-data');\n\n/**\n * Sentinel yielded by `parseSseStream` for a comment-only frame (no\n * `data:` payload), the mechanism providers use for SSE keep-alive\n * pings. Exported so a consumer (e.g. `fromFetch`) can react to \"still\n * alive\" separately from a genuinely empty frame (`NO_DATA`, kept internal).\n */\nexport const SSE_PING = Symbol('sse-frame-ping');\n\n/** Extracts and JSON-parses the `data:` payload of one SSE frame (the text between two blank lines). */\nfunction parseSseFrame(frame: string): unknown {\n const dataLines: string[] = [];\n let sawComment = false;\n\n for (const line of frame.split('\\n')) {\n if (line.startsWith(':')) {\n sawComment = true; // comment line, also used as a keep-alive ping\n continue;\n }\n if (!line.startsWith('data:')) continue; // ignore event:/id:/retry:/blank lines\n\n // A single space after the colon is stripped per the SSE spec; further\n // leading whitespace is preserved as part of the payload.\n dataLines.push(line.startsWith('data: ') ? line.slice(6) : line.slice(5));\n }\n\n if (!dataLines.length) return sawComment ? SSE_PING : NO_DATA;\n\n const data = dataLines.join('\\n');\n\n if (data === '[DONE]') return DONE;\n\n try {\n return JSON.parse(data);\n } catch (cause) {\n throw new LLMError(\n `Invalid JSON in SSE frame: ${data.slice(0, 200)}`,\n 'parse',\n undefined,\n undefined,\n cause,\n );\n }\n}\n","import { LLMError } from '../types/index.js';\n\n/**\n * MIME types accepted for `ImageBlock.mimeType` across all adapters. This is\n * the intersection of what Anthropic, Gemini, OpenAI-compatible, and Bedrock\n * Converse all natively support, so a `ContentBlock[]` that validates for\n * one provider validates for all of them.\n */\nexport const SUPPORTED_IMAGE_MIME_TYPES = [\n 'image/png',\n 'image/jpeg',\n 'image/gif',\n 'image/webp',\n] as const;\n\nexport type SupportedImageMimeType = (typeof SUPPORTED_IMAGE_MIME_TYPES)[number];\n\n/**\n * Validates an `ImageBlock.mimeType` against the shared supported set.\n * Throws a non-retryable `LLMError('validation')`, since an unsupported\n * mimeType is a permanent failure, retrying the same input can't fix it,\n * the same way a schema-validation or JSON-parse failure isn't retried.\n */\nexport function assertSupportedImageMimeType(mimeType: string): SupportedImageMimeType {\n if ((SUPPORTED_IMAGE_MIME_TYPES as readonly string[]).includes(mimeType)) {\n return mimeType as SupportedImageMimeType;\n }\n\n throw new LLMError(\n `Unsupported image mimeType \"${mimeType}\": expected one of ${SUPPORTED_IMAGE_MIME_TYPES.join(', ')}`,\n 'validation',\n );\n}\n","import {\n assertSupportedImageMimeType,\n type SupportedImageMimeType,\n} from '../internal/imageFormat.js';\nimport {\n LLMError,\n type ContentBlock,\n type LLMClient,\n type WireStreamChunk,\n type WireToolCall,\n} from '../types/index.js';\n\n/** Anthropic's native per-block content shape for a message. */\ntype AnthropicContentBlock =\n | { type: 'text'; text: string }\n | {\n type: 'image';\n source: { type: 'base64'; media_type: SupportedImageMimeType; data: string };\n }\n | { type: 'tool_use'; id: string; name: string; input: unknown }\n | { type: 'tool_result'; tool_use_id: string; content: string; is_error?: boolean };\n\n/** Minimal structural type for the Anthropic SDK's `messages.create` */\nexport interface AnthropicClient {\n messages: {\n create(\n params: {\n model: string;\n max_tokens: number;\n temperature?: number;\n system?: string;\n messages: Array<{ role: 'user' | 'assistant'; content: string | AnthropicContentBlock[] }>;\n tools?: Array<{\n name: string;\n description?: string;\n // The real Anthropic SDK's `Tool.input_schema` requires the\n // literal `type: 'object'` (VernLLM's own public `tools` API\n // accepts freeform JSON Schema, so this is narrower than that);\n // see the two call sites below for how a caller's schema is\n // asserted into this shape.\n input_schema: { type: 'object'; [key: string]: unknown };\n strict?: boolean;\n }>;\n tool_choice?:\n | { type: 'auto' }\n | { type: 'any' }\n | { type: 'none' }\n | { type: 'tool'; name: string };\n },\n options: { signal: AbortSignal },\n ): Promise<{\n content: Array<{ type: string; text?: string; id?: string; name?: string; input?: unknown }>;\n usage?: { input_tokens?: number; output_tokens?: number };\n }>;\n };\n}\n\n/**\n * Translates a VernLLM `ContentBlock[]` (our provider-agnostic multimodal\n * shape) into Anthropic's native content-block array: text blocks pass\n * through as-is, image blocks become `{ type: 'image', source: { type:\n * 'base64', media_type, data } }`.\n */\nfunction toAnthropicContent(blocks: ContentBlock[]): AnthropicContentBlock[] {\n return blocks.map((block) =>\n block.type === 'image'\n ? {\n type: 'image',\n source: {\n type: 'base64',\n media_type: assertSupportedImageMimeType(block.mimeType),\n data: block.data,\n },\n }\n : { type: 'text', text: block.text },\n );\n}\n\n/**\n * Asserts a caller-supplied JSON Schema is an object schema before it's\n * used as Anthropic's `Tool.input_schema`, which (like every other\n * provider's function-calling API) requires `type: 'object'`. VernLLM's own\n * public `tools`/`jsonSchema` APIs accept freeform `Record<string,\n * unknown>` JSON Schema, so nothing upstream guarantees this at compile\n * time; this is the runtime check that stands in for that, so a schema\n * missing (or mistyping) `type: 'object'` fails loudly and immediately\n * instead of being silently forwarded to Anthropic malformed.\n */\nfunction assertObjectSchema(\n schema: Record<string, unknown>,\n toolName: string,\n): { type: 'object'; [key: string]: unknown } {\n if (schema.type !== 'object') {\n throw new LLMError(\n `Tool \"${toolName}\"'s schema must have \"type\": \"object\" (Anthropic requires object-shaped tool parameters).`,\n 'validation',\n );\n }\n\n return schema as { type: 'object'; [key: string]: unknown };\n}\n\n/**\n * Translates VernLLM's OpenAI-shaped wire `tool_choice` into Anthropic's\n * `{ type: 'auto' | 'any' | 'none' | 'tool', name? }` shape. `'required'`\n * maps to `'any'` (Anthropic's \"must call some tool\" equivalent).\n */\nfunction toAnthropicToolChoice(\n toolChoice: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice'],\n):\n | { type: 'auto' }\n | { type: 'any' }\n | { type: 'none' }\n | { type: 'tool'; name: string }\n | undefined {\n if (!toolChoice || toolChoice === 'auto') return { type: 'auto' };\n if (toolChoice === 'none') return { type: 'none' };\n if (toolChoice === 'required') return { type: 'any' };\n\n return { type: 'tool', name: toolChoice.function.name };\n}\n\n/** One SSE event of an Anthropic `messages.create({ stream: true })` stream. */\ntype AnthropicStreamEvent =\n | { type: 'message_start'; message: { usage?: { input_tokens?: number } } }\n | {\n type: 'content_block_start';\n index: number;\n content_block: { type: string; id?: string; name?: string };\n }\n | {\n type: 'content_block_delta';\n index: number;\n delta:\n | { type: 'text_delta'; text: string }\n | { type: 'input_json_delta'; partial_json: string };\n }\n | { type: 'content_block_stop'; index: number }\n | { type: 'message_delta'; usage?: { output_tokens?: number } }\n | { type: 'message_stop' }\n // Keep-alive event during long streams (e.g. extended thinking). Modeled\n // so the event switch has somewhere to route it. See createStream.\n | { type: 'ping' };\n\ntype AnthropicRequestBody = Parameters<AnthropicClient['messages']['create']>[0];\n\n/**\n * Builds the Anthropic-shaped request body from VernLLM's wire params,\n * shared between `create` and `createStream` so both go through identical\n * translation (system prompt, message shaping, and the jsonSchema →\n * forced-single-tool mapping all happen exactly once, not once per entry\n * point).\n *\n * Returns `toolName` alongside the body: when set, the model was forced to\n * call a single synthetic tool standing in for `jsonSchema` output, and\n * both `create` and `createStream` need to know this so they can unwrap\n * that tool call back into plain text content instead of treating it like\n * a real tool call.\n */\nfunction buildAnthropicRequestBody(\n params: Parameters<LLMClient['chat']['completions']['create']>[0],\n): { body: AnthropicRequestBody; toolName: string | undefined } {\n const systemMessage = params.messages.find((m) => m.role === 'system');\n\n // Keep user, assistant, and tool turns, in order. Anthropic has no\n // separate 'tool' role: tool results travel as a user-role message\n // containing tool_result content blocks, and an assistant's tool\n // requests travel as tool_use content blocks on its own turn.\n const conversationMessages = params.messages.filter(\n (m) => m.role === 'user' || m.role === 'assistant' || m.role === 'tool',\n );\n\n const toolName =\n params.response_format?.type === 'json_schema'\n ? params.response_format.json_schema.name.trim()\n : undefined;\n\n if (params.response_format?.type === 'json_schema' && !toolName) {\n throw new LLMError('json_schema.name must not be empty.', 'validation');\n }\n\n let jsonInstruction: string | undefined;\n let tools: NonNullable<Parameters<AnthropicClient['messages']['create']>[0]['tools']> | undefined;\n let toolChoice: Parameters<AnthropicClient['messages']['create']>[0]['tool_choice'];\n\n if (params.response_format?.type === 'json_schema' && toolName) {\n // jsonSchema and real `tools` are mutually exclusive by the time\n // a call reaches here (enforced in vernLLM.ts), so this branch\n // and the `params.tools` branch below never both apply.\n const { schema, description, strict } = params.response_format.json_schema;\n\n // VernLLM's public `jsonSchema` API accepts a freeform JSON Schema\n // object (`Record<string, unknown>`), not necessarily typed with a\n // literal `type: 'object'`, but tool/function parameters are always\n // object schemas in practice (every provider's function-calling API\n // requires it), so this assertion reflects that existing convention\n // rather than changing behavior.\n tools = [\n { name: toolName, description, input_schema: assertObjectSchema(schema, toolName), strict },\n ];\n toolChoice = { type: 'tool', name: toolName };\n } else if (params.response_format?.type === 'json_object') {\n // No schema to build a tool from, fall back to a prompt instruction\n jsonInstruction = 'Respond with valid JSON only, no prose or markdown fences.';\n } else if (params.tools?.length) {\n tools = params.tools.map((t) => ({\n name: t.function.name,\n description: t.function.description,\n // Same convention as above: tool parameters are always object\n // schemas in practice.\n input_schema: assertObjectSchema(t.function.parameters, t.function.name),\n }));\n toolChoice = toAnthropicToolChoice(params.tool_choice);\n }\n\n // `reasoning_effort` (OpenAI o-series/gpt-5 style) has no direct Anthropic\n // equivalent. Claude's extended thinking uses a token budget, not a tier\n // string, so it's intentionally dropped here rather than guessed at.\n\n const system = [systemMessage?.content, jsonInstruction].filter(Boolean).join('\\n\\n');\n\n const body: AnthropicRequestBody = {\n model: params.model,\n max_tokens: params.max_tokens,\n ...(params.temperature !== undefined ? { temperature: params.temperature } : {}),\n system: system || undefined,\n messages: mergeConsecutiveToolResults(conversationMessages.map((m) => toAnthropicMessage(m))),\n ...(tools ? { tools, tool_choice: toolChoice } : {}),\n };\n\n return { body, toolName };\n}\n\n/**\n * Wraps an Anthropic SDK client so it satisfies the same `LLMClient`\n * interface VernLLM uses for OpenAI/Groq.\n *\n * `response_format: json_schema` is mapped to Anthropic's forced tool-use:\n * a single tool is defined with `input_schema` set to the caller's schema,\n * `description` forwarded when provided, and `strict` forwarded when set.\n * `tool_choice` forces the model to call it. Provider-constrained schema\n * matching applies only when `strict: true` is forwarded and supported.\n *\n * `response_format: json_object` (no schema to build a tool from) falls\n * back to a system-prompt instruction, since there's nothing to constrain\n * generation against.\n */\nexport function fromAnthropic(anthropicClient: AnthropicClient): LLMClient {\n // The Anthropic SDK's `messages.create`, called with `stream: true`,\n // returns an AsyncIterable of `AnthropicStreamEvent` rather than\n // `AnthropicClient['messages']['create']`'s normal single-message return\n // type, hence `unknown` here and a cast at the call site, same\n // rationale as `fromOpenAICompatible`'s `rawCreate`: the wire contract,\n // not the SDK's own TS types, is what's actually relied on.\n const rawMessagesCreate = anthropicClient.messages.create.bind(\n anthropicClient.messages,\n ) as unknown as (\n params: unknown,\n options: { signal: AbortSignal },\n ) => Promise<unknown> | AsyncIterable<AnthropicStreamEvent>;\n\n return {\n chat: {\n completions: {\n async create(params, options) {\n const { body, toolName } = buildAnthropicRequestBody(params);\n\n const response = await anthropicClient.messages.create(body, options);\n\n let text: string;\n let wireToolCalls: WireToolCall[] | undefined;\n if (toolName) {\n const toolUse = response.content.find(\n (block) => block.type === 'tool_use' && block.name === toolName,\n );\n\n if (!toolUse) {\n throw new LLMError(\n `Anthropic did not return the required structured output tool \"${toolName}\".`,\n 'validation',\n );\n }\n\n if (\n !toolUse.input ||\n typeof toolUse.input !== 'object' ||\n Array.isArray(toolUse.input)\n ) {\n throw new LLMError(\n `Anthropic returned invalid structured output for tool \"${toolName}\". Expected an object.`,\n 'validation',\n );\n }\n\n text = JSON.stringify(toolUse.input);\n } else {\n text = response.content\n .filter((block) => block.type === 'text')\n .map((block) => block.text ?? '')\n .join('');\n\n const toolUses = response.content.filter((block) => block.type === 'tool_use');\n\n if (toolUses.length) {\n wireToolCalls = toolUses.map((block) => ({\n id: block.id!,\n type: 'function' as const,\n function: { name: block.name!, arguments: JSON.stringify(block.input ?? {}) },\n }));\n }\n }\n\n return {\n choices: [\n {\n message: { content: text, ...(wireToolCalls ? { tool_calls: wireToolCalls } : {}) },\n },\n ],\n usage: {\n prompt_tokens: response.usage?.input_tokens,\n completion_tokens: response.usage?.output_tokens,\n total_tokens:\n (response.usage?.input_tokens ?? 0) + (response.usage?.output_tokens ?? 0),\n },\n };\n },\n\n async *createStream(params, options) {\n const { body, toolName } = buildAnthropicRequestBody(params);\n\n const stream = (await rawMessagesCreate(\n { ...body, stream: true },\n options,\n )) as AsyncIterable<AnthropicStreamEvent>;\n\n // Tracks which content-block index is which kind, since Anthropic\n // interleaves text and tool_use blocks under a shared `index`\n // sequence and later delta events only carry that index, not the\n // kind. `json-tool` is the forced single-tool-call standing in\n // for `jsonSchema` output (see `toolName` above): its\n // input_json_delta fragments are re-emitted as `text-delta`, not\n // `tool_call_delta`, so the accumulated result lands in\n // finalizeResponse's `content` path exactly like the\n // non-streaming `create` branch above unwraps it.\n const blockKinds = new Map<number, 'text' | 'tool_use' | 'json-tool'>();\n let inputTokens = 0;\n let sawJsonTool = false;\n\n for await (const event of stream) {\n if (event.type === 'message_start') {\n inputTokens = event.message.usage?.input_tokens ?? 0;\n } else if (event.type === 'content_block_start') {\n if (event.content_block.type === 'tool_use') {\n const kind = event.content_block.name === toolName ? 'json-tool' : 'tool_use';\n\n blockKinds.set(event.index, kind);\n\n if (kind === 'json-tool') {\n sawJsonTool = true;\n } else if (!toolName) {\n // Only surface tool_use blocks as tool_call_delta chunks\n // when there's no forced structured-output tool in play.\n // When `toolName` is set, any non-matching tool_use block\n // is unexpected (Anthropic forces exactly one tool), and\n // surfacing it would corrupt the caller's expectation of\n // receiving only the forced tool's JSON payload as text.\n yield {\n type: 'tool_call_delta',\n index: event.index,\n id: event.content_block.id,\n name: event.content_block.name,\n };\n }\n } else {\n blockKinds.set(event.index, 'text');\n }\n } else if (event.type === 'content_block_delta') {\n if (event.delta.type === 'text_delta') {\n // Only surfaced as real content when there's no forced\n // json-schema tool in play. When `toolName` is set, the\n // *only* content that should end up in the accumulated\n // text is the forced tool's own JSON payload (its\n // input_json_delta fragments, handled below), exactly\n // what the non-streaming `create` branch above does by\n // discarding every content block except the matching\n // tool_use one. Anthropic can still emit genuine text\n // blocks alongside a forced tool call (a model narrating\n // before calling it, say), and without this guard those\n // would get concatenated into the same buffer as the\n // tool's JSON, corrupting it.\n if (!toolName) {\n yield { type: 'text-delta', delta: event.delta.text };\n }\n } else if (event.delta.type === 'input_json_delta') {\n const kind = blockKinds.get(event.index);\n\n if (kind === 'json-tool') {\n yield { type: 'text-delta', delta: event.delta.partial_json };\n } else if (!toolName) {\n yield {\n type: 'tool_call_delta',\n index: event.index,\n argumentsDelta: event.delta.partial_json,\n };\n }\n }\n } else if (event.type === 'message_delta') {\n const outputTokens = event.usage?.output_tokens ?? 0;\n\n yield {\n type: 'usage',\n usage: {\n prompt_tokens: inputTokens,\n completion_tokens: outputTokens,\n total_tokens: inputTokens + outputTokens,\n },\n } satisfies WireStreamChunk;\n } else if (event.type === 'ping') {\n // Keep-alive with no content. Yielding it resets the\n // idle-timeout clock in VernLLM's stream loop.\n yield { type: 'ping' };\n }\n }\n\n if (toolName && !sawJsonTool) {\n throw new LLMError(\n `Anthropic did not return the required structured output tool \"${toolName}\".`,\n 'validation',\n );\n }\n },\n },\n },\n };\n}\n\n/**\n * Anthropic requires strict role alternation, so the per-wire-message\n * mapping above (one `{role:'user', content:[tool_result]}` per VernLLM\n * wire tool message) needs merging back together when an assistant turn\n * requested more than one tool: multiple consecutive user turns would\n * violate that alternation, and Anthropic's API rejects it outright. This\n * merges any run of tool-result-only user messages into one, with all\n * their tool_result blocks combined, the shape Anthropic expects for \"here\n * are the results of everything you just asked for.\"\n */\nfunction mergeConsecutiveToolResults(\n messages: { role: 'user' | 'assistant'; content: string | AnthropicContentBlock[] }[],\n): { role: 'user' | 'assistant'; content: string | AnthropicContentBlock[] }[] {\n const isToolResultOnly = (\n m: (typeof messages)[number],\n ): m is { role: 'user'; content: AnthropicContentBlock[] } =>\n m.role === 'user' &&\n Array.isArray(m.content) &&\n m.content.length > 0 &&\n m.content.every((b) => b.type === 'tool_result');\n\n const merged: (typeof messages)[number][] = [];\n\n for (const m of messages) {\n const prev = merged.at(-1);\n\n if (isToolResultOnly(m) && prev && isToolResultOnly(prev)) {\n prev.content.push(...m.content);\n } else {\n merged.push(m);\n }\n }\n\n return merged;\n}\n\n/**\n * Translates one VernLLM wire message (OpenAI-shaped: plain user/assistant\n * turns, an assistant turn with `tool_calls`, or a `tool` turn) into\n * Anthropic's `{ role: 'user' | 'assistant', content }` shape.\n */\nfunction toAnthropicMessage(\n m: Extract<\n Parameters<LLMClient['chat']['completions']['create']>[0]['messages'][number],\n { role: 'user' | 'assistant' | 'tool' }\n >,\n): { role: 'user' | 'assistant'; content: string | AnthropicContentBlock[] } {\n if (m.role === 'tool') {\n // Anthropic has no 'tool' role: results travel as a user turn with\n // tool_result blocks.\n return {\n role: 'user',\n content: [\n {\n type: 'tool_result',\n tool_use_id: m.tool_call_id,\n content: m.content,\n ...(m.is_error ? { is_error: true } : {}),\n },\n ],\n };\n }\n\n if (m.role === 'assistant' && m.tool_calls?.length) {\n const blocks: AnthropicContentBlock[] = [];\n\n if (m.content) blocks.push({ type: 'text', text: m.content });\n\n for (const tc of m.tool_calls) {\n let input: unknown;\n\n try {\n input = tc.function.arguments.trim() ? JSON.parse(tc.function.arguments) : {};\n } catch (cause) {\n throw new LLMError(\n `Assistant tool call \"${tc.function.name}\" (${tc.id}) has arguments that are not valid JSON.`,\n 'validation',\n undefined,\n undefined,\n cause,\n );\n }\n\n if (input === null || Array.isArray(input) || typeof input !== 'object') {\n throw new LLMError(\n `Assistant tool call \"${tc.function.name}\" (${tc.id}) arguments must be a JSON object.`,\n 'validation',\n );\n }\n\n blocks.push({ type: 'tool_use', id: tc.id, name: tc.function.name, input });\n }\n\n return { role: 'assistant', content: blocks };\n }\n\n return {\n role: m.role,\n content: Array.isArray(m.content) ? toAnthropicContent(m.content) : (m.content ?? ''),\n };\n}\n","import { assertSupportedImageMimeType } from '../internal/imageFormat.js';\nimport {\n LLMError,\n type ContentBlock,\n type LLMClient,\n type WireStreamChunk,\n type WireToolCall,\n} from '../types/index.js';\n\n/** Gemini's native per-part content shape for a `contents` entry. */\ntype GeminiPart =\n | { text: string }\n | { inlineData: { mimeType: string; data: string } }\n | { functionCall: { name: string; args: unknown } }\n | { functionResponse: { name: string; response: unknown } };\n\n/**\n * Structural type matching the real `@google/genai` SDK's `ai.models`\n * object: `generateContent`/`generateContentStream` both take a single\n * `{ model, contents, config }` argument (config carries\n * `systemInstruction`, `tools`, `toolConfig`, generation settings, and\n * `abortSignal` all together), matching the real SDK closely enough that\n * `fromGemini(ai.models)` works directly, e.g:\n *\n * ```ts\n * import { GoogleGenAI } from '@google/genai';\n * const ai = new GoogleGenAI({ apiKey: '...' });\n * const llm = new VernLLM({ client: fromGemini(ai.models), model: 'gemini-2.5-flash' });\n * ```\n */\nexport interface GeminiClient {\n generateContent(params: {\n model?: string;\n contents: Array<{ role: 'user' | 'model'; parts: GeminiPart[] }>;\n config?: {\n systemInstruction?: { parts: Array<{ text: string }> };\n temperature?: number;\n maxOutputTokens?: number;\n responseMimeType?: string;\n responseSchema?: Record<string, unknown>;\n tools?: Array<{\n functionDeclarations: Array<{\n name: string;\n description?: string;\n parameters: Record<string, unknown>;\n }>;\n }>;\n toolConfig?: {\n functionCallingConfig: {\n mode: 'AUTO' | 'ANY' | 'NONE';\n allowedFunctionNames?: string[];\n };\n };\n abortSignal?: AbortSignal;\n };\n }): Promise<{\n candidates?: Array<{\n content?: {\n parts?: Array<{ text?: string; functionCall?: { name: string; args: unknown } }>;\n };\n }>;\n usageMetadata?: {\n promptTokenCount?: number;\n candidatesTokenCount?: number;\n totalTokenCount?: number;\n };\n }>;\n\n /**\n * Optional. Required only for `stream: true` calls. Takes the same\n * request shape as `generateContent`. Matching the real SDK's own\n * `generateContentStream`, this resolves to an `AsyncIterable` (rather\n * than returning one synchronously) of partial responses, each chunk\n * holding the same `candidates[].content.parts[]` structure as\n * `generateContent`'s response, just incremental.\n */\n generateContentStream?(params: Parameters<GeminiClient['generateContent']>[0]): Promise<\n AsyncIterable<{\n candidates?: Array<{\n content?: {\n parts?: Array<{ text?: string; functionCall?: { name: string; args: unknown } }>;\n };\n }>;\n usageMetadata?: {\n promptTokenCount?: number;\n candidatesTokenCount?: number;\n totalTokenCount?: number;\n };\n }>\n >;\n}\n\n/**\n * Translates a VernLLM `ContentBlock[]` into Gemini's native `parts` array:\n * text blocks become `{ text }`, image blocks become inline data parts\n * (`{ inlineData: { mimeType, data } }`), Gemini's shape for embedding raw\n * base64 image bytes directly in the request.\n */\nfunction toGeminiParts(blocks: ContentBlock[]): GeminiPart[] {\n return blocks.map((block) =>\n block.type === 'image'\n ? { inlineData: { mimeType: assertSupportedImageMimeType(block.mimeType), data: block.data } }\n : { text: block.text },\n );\n}\n\n/** Maps VernLLM's OpenAI-shaped wire `tool_choice` onto Gemini's `functionCallingConfig`. */\nfunction toGeminiToolConfig(\n toolChoice: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice'],\n): NonNullable<\n NonNullable<Parameters<GeminiClient['generateContent']>[0]['config']>['toolConfig']\n> {\n if (!toolChoice || toolChoice === 'auto') {\n return { functionCallingConfig: { mode: 'AUTO' } };\n }\n if (toolChoice === 'none') {\n return { functionCallingConfig: { mode: 'NONE' } };\n }\n if (toolChoice === 'required') {\n return { functionCallingConfig: { mode: 'ANY' } };\n }\n\n return {\n functionCallingConfig: { mode: 'ANY', allowedFunctionNames: [toolChoice.function.name] },\n };\n}\n\n/**\n * Translates one VernLLM wire message into a Gemini `contents` entry.\n * Gemini has no separate 'tool' role: a prior assistant tool request\n * becomes a `'model'` turn with `functionCall` parts, and its result\n * becomes a `'user'` turn with `functionResponse` parts.\n */\nfunction toGeminiContent(\n m: Extract<\n Parameters<LLMClient['chat']['completions']['create']>[0]['messages'][number],\n { role: 'user' | 'assistant' | 'tool' }\n >,\n): { role: 'user' | 'model'; parts: GeminiPart[] } {\n if (m.role === 'tool') {\n // Gemini's functionResponse identifies the call by function *name*, and\n // the Gemini branch of this adapter sets wire tool_call ids equal to\n // the function name for exactly this reason, so tool_call_id here is\n // already the name Gemini expects.\n return {\n role: 'user',\n parts: [\n {\n functionResponse: {\n name: m.tool_call_id,\n response: parseToolResult(m.content),\n },\n },\n ],\n };\n }\n\n if (m.role === 'assistant' && m.tool_calls?.length) {\n const parts: GeminiPart[] = [];\n\n if (typeof m.content === 'string' && m.content) {\n parts.push({ text: m.content });\n }\n\n parts.push(\n ...m.tool_calls.map((tc) => ({\n functionCall: {\n name: tc.function.name,\n args: parseToolArguments(tc.function.arguments, tc.function.name),\n },\n })),\n );\n\n return {\n role: 'model',\n parts,\n };\n }\n\n return {\n role: m.role === 'assistant' ? 'model' : 'user',\n parts: Array.isArray(m.content) ? toGeminiParts(m.content) : [{ text: m.content ?? '' }],\n };\n}\n\nfunction parseToolArguments(text: string, toolName: string): Record<string, unknown> {\n let parsed: unknown;\n\n try {\n parsed = text.trim() ? JSON.parse(text) : {};\n } catch (cause) {\n throw new LLMError(\n `Tool call \"${toolName}\" arguments are not valid JSON.`,\n 'validation',\n undefined,\n undefined,\n cause,\n );\n }\n\n if (!parsed || Array.isArray(parsed) || typeof parsed !== 'object') {\n throw new LLMError(`Tool call \"${toolName}\" arguments must be a JSON object.`, 'validation');\n }\n\n return parsed as Record<string, unknown>;\n}\n\nfunction parseToolResult(text: string): unknown {\n try {\n return text.trim() ? JSON.parse(text) : '';\n } catch {\n return text;\n }\n}\n\n/**\n * Gemini expects the results of everything the model asked for in one turn\n * to arrive together as multiple `functionResponse` parts on a single\n * `'user'` entry, not as separate consecutive `'user'` entries. The\n * per-wire-message mapping above produces one `'user'` entry per VernLLM\n * wire tool message, so when an assistant turn requested more than one\n * tool, this merges the resulting run of functionResponse-only `'user'`\n * entries back into one.\n */\nfunction mergeConsecutiveFunctionResponses(\n contents: { role: 'user' | 'model'; parts: GeminiPart[] }[],\n): { role: 'user' | 'model'; parts: GeminiPart[] }[] {\n const isFunctionResponseOnly = (\n c: (typeof contents)[number],\n ): c is { role: 'user'; parts: GeminiPart[] } =>\n c.role === 'user' && c.parts.length > 0 && c.parts.every((p) => 'functionResponse' in p);\n\n const merged: (typeof contents)[number][] = [];\n\n for (const c of contents) {\n const prev = merged.at(-1);\n\n if (isFunctionResponseOnly(c) && prev && isFunctionResponseOnly(prev)) {\n prev.parts.push(...c.parts);\n } else {\n merged.push(c);\n }\n }\n\n return merged;\n}\n\ntype GeminiRequest = Parameters<GeminiClient['generateContent']>[0];\ntype GeminiConfig = NonNullable<GeminiRequest['config']>;\n\n/**\n * Builds the Gemini-shaped request from VernLLM's wire params, shared\n * between `create` and `createStream` so both go through identical\n * translation (contents shaping, `responseSchema`/`responseMimeType`\n * mapping, and tool/toolConfig translation all happen exactly once).\n * `abortSignal` is folded into `config` by the caller (`create`/\n * `createStream`), once the request options are available.\n */\nfunction buildGeminiRequest(\n params: Parameters<LLMClient['chat']['completions']['create']>[0],\n): GeminiRequest {\n const systemMessage = params.messages.find((m) => m.role === 'system');\n // Keep user, assistant, and tool turns, in order.\n const conversationMessages = params.messages.filter(\n (m) => m.role === 'user' || m.role === 'assistant' || m.role === 'tool',\n );\n\n const wantsJson = Boolean(params.response_format);\n const config: GeminiConfig = {\n ...(params.temperature !== undefined ? { temperature: params.temperature } : {}),\n maxOutputTokens: params.max_tokens,\n ...(systemMessage\n ? // System turns are always plain strings; only user turns can carry ContentBlock[]\n { systemInstruction: { parts: [{ text: systemMessage.content as string }] } }\n : {}),\n };\n\n if (wantsJson) {\n config.responseMimeType = 'application/json';\n }\n\n if (params.response_format?.type === 'json_schema') {\n const { schema, description } = params.response_format.json_schema;\n\n config.responseSchema = {\n ...schema,\n ...(description ? { description } : {}),\n };\n }\n\n if (params.tools?.length) {\n config.tools = [\n {\n functionDeclarations: params.tools.map((t) => ({\n name: t.function.name,\n description: t.function.description,\n parameters: t.function.parameters,\n })),\n },\n ];\n config.toolConfig = toGeminiToolConfig(params.tool_choice);\n }\n\n return {\n model: params.model,\n contents: mergeConsecutiveFunctionResponses(\n conversationMessages.map((m) => toGeminiContent(m)),\n ),\n config,\n };\n}\n\n/**\n * Wraps a Gemini client so it satisfies the `LLMClient` interface VernLLM\n * uses for OpenAI-compatible APIs. Gemini's shape differs on nearly every\n * axis: a `contents` array instead of `messages`, a separate\n * `systemInstruction` field instead of a `system` role message,\n * `generationConfig` instead of top-level `temperature`/`max_tokens`, and\n * native JSON Schema support via `responseMimeType: 'application/json'` +\n * `responseSchema`. `reasoning_effort` has no equivalent. Gemini's thinking\n * models use a token budget, not an effort tier, so it's dropped, same as\n * Anthropic.\n *\n * `tools` maps to Gemini's native `functionDeclarations`/`functionCall`;\n * `tool_choice` maps to `toolConfig.functionCallingConfig`. `jsonSchema`\n * and `tools` are mutually exclusive by the time a call reaches here\n * (enforced in vernLLM.ts), so `responseSchema` and `tools` never\n * both apply.\n *\n * `createStream` calls `generateContentStream` (optional on `GeminiClient`\n *, required only if the caller sets `stream: true`) and translates each\n * partial response into `WireStreamChunk`s. Unlike OpenAI/Anthropic,\n * Gemini's own function-calling API doesn't stream tool-call arguments\n * incrementally: a `functionCall` part always arrives whole in one chunk,\n * so each one is emitted as a single, complete `tool_call_delta` (a\n * one-shot \"delta\" containing the full arguments) rather than accumulated\n * fragments, that's a real difference in the underlying API, not\n * something this adapter can smooth over. `usageMetadata` is (per Gemini's\n * own behavior) only reliably present on the last chunk, so the `usage`\n * `WireStreamChunk` is emitted once, after the stream completes, from\n * whichever chunk's `usageMetadata` was seen last.\n */\nexport function fromGemini(geminiClient: GeminiClient): LLMClient {\n return {\n chat: {\n completions: {\n async create(params, options) {\n const request = buildGeminiRequest(params);\n request.config = { ...request.config, abortSignal: options.signal };\n\n const response = await geminiClient.generateContent(request);\n\n const parts = response.candidates?.[0]?.content?.parts ?? [];\n const text = parts.map((p) => p.text ?? '').join('');\n const functionCalls = parts.filter((p) => p.functionCall);\n\n let wireToolCalls: WireToolCall[] | undefined;\n\n if (functionCalls.length) {\n wireToolCalls = functionCalls.map((p) => ({\n // Gemini's functionResponse correlates by function *name*, not\n // a call id (Gemini has no call-id concept at all), so the id\n // here is just the name. This means two calls to the *same*\n // tool within one turn can't be told apart when results come\n // back, a real limitation of Gemini's own function-calling\n // API, not something VernLLM can paper over.\n id: p.functionCall!.name,\n type: 'function' as const,\n function: {\n name: p.functionCall!.name,\n arguments: JSON.stringify(p.functionCall!.args ?? {}),\n },\n }));\n }\n\n return {\n choices: [\n {\n message: { content: text, ...(wireToolCalls ? { tool_calls: wireToolCalls } : {}) },\n },\n ],\n usage: {\n prompt_tokens: response.usageMetadata?.promptTokenCount,\n completion_tokens: response.usageMetadata?.candidatesTokenCount,\n total_tokens: response.usageMetadata?.totalTokenCount,\n },\n };\n },\n\n async *createStream(params, options) {\n if (!geminiClient.generateContentStream) {\n throw new LLMError(\n 'stream: true requires a Gemini client with generateContentStream',\n 'validation',\n );\n }\n\n const request = buildGeminiRequest(params);\n request.config = { ...request.config, abortSignal: options.signal };\n\n const stream = await geminiClient.generateContentStream(request);\n\n let toolCallIndex = 0;\n let lastUsage:\n | NonNullable<Awaited<ReturnType<GeminiClient['generateContent']>>['usageMetadata']>\n | undefined;\n\n for await (const chunk of stream) {\n const parts = chunk.candidates?.[0]?.content?.parts ?? [];\n\n for (const part of parts) {\n if (part.text) {\n yield { type: 'text-delta', delta: part.text };\n }\n\n if (part.functionCall) {\n yield {\n type: 'tool_call_delta',\n index: toolCallIndex,\n id: part.functionCall.name,\n name: part.functionCall.name,\n argumentsDelta: JSON.stringify(part.functionCall.args ?? {}),\n // INVARIANT: assumes Gemini always sends a complete\n // function-call args blob per part, no incremental\n // streaming, per current API behavior. There is no field\n // on this minimal structural type to derive this from.\n // If Gemini ever starts streaming args incrementally,\n // this becomes silently wrong. See the test titled\n // \"INVARIANT: hardcodes complete: true on\n // tool_call_delta\" in gemini.stream.unit.test.ts, which\n // exists specifically to catch that drift.\n complete: true,\n } satisfies WireStreamChunk;\n toolCallIndex++;\n }\n }\n\n if (chunk.usageMetadata) {\n lastUsage = chunk.usageMetadata;\n }\n }\n\n if (lastUsage) {\n yield {\n type: 'usage',\n usage: {\n prompt_tokens: lastUsage.promptTokenCount,\n completion_tokens: lastUsage.candidatesTokenCount,\n total_tokens: lastUsage.totalTokenCount,\n },\n };\n }\n },\n },\n },\n };\n}\n","import { assertSupportedImageMimeType } from '../internal/imageFormat.js';\nimport {\n LLMError,\n type ContentBlock,\n type LLMClient,\n type WireStreamChunk,\n type WireToolCall,\n} from '../types/index.js';\n\n/** Bedrock Converse's supported inline image formats. */\ntype BedrockImageFormat = 'png' | 'jpeg' | 'gif' | 'webp';\n\n/** Bedrock Converse's native per-block content shape for a message. */\ntype BedrockContentBlock =\n | { text: string }\n | { image: { format: BedrockImageFormat; source: { bytes: Uint8Array } } }\n | { toolUse: { toolUseId: string; name: string; input: unknown } }\n | {\n toolResult: {\n toolUseId: string;\n content: Array<{ text: string }>;\n status?: 'success' | 'error';\n };\n };\n\n/**\n * Minimal structural type matching AWS Bedrock's Converse API. This is\n * intentionally NOT `BedrockRuntimeClient` itself, the AWS SDK v3 client\n * exposes `.send(command)`, not a direct `.converse()` method, and pulling\n * in `@aws-sdk/client-bedrock-runtime` as a dependency just for its types\n * isn't worth it for a structural adapter. Wrap your client, e.g:\n *\n * ```ts\n * import { BedrockRuntimeClient, ConverseCommand } from '@aws-sdk/client-bedrock-runtime';\n * const client = new BedrockRuntimeClient({ region: 'us-east-1' });\n * const converseClient = {\n * converse: (params, options) =>\n * client.send(new ConverseCommand(params), { abortSignal: options.signal }),\n * };\n * ```\n */\nexport interface BedrockConverseClient {\n converse(\n params: {\n modelId: string;\n messages: Array<{ role: 'user' | 'assistant'; content: BedrockContentBlock[] }>;\n system?: Array<{ text: string }>;\n inferenceConfig?: { temperature?: number; maxTokens?: number };\n toolConfig?: {\n tools: Array<{\n toolSpec: {\n name: string;\n description?: string;\n inputSchema: { json: Record<string, unknown> };\n strict?: boolean;\n };\n }>;\n toolChoice?:\n | { tool: { name: string } }\n | { auto: Record<string, never> }\n | { any: Record<string, never> };\n };\n },\n options: { signal: AbortSignal },\n ): Promise<{\n output?: {\n message?: {\n content?: Array<{\n text?: string;\n toolUse?: { toolUseId?: string; name?: string; input?: unknown };\n }>;\n };\n };\n usage?: { inputTokens?: number; outputTokens?: number; totalTokens?: number };\n }>;\n\n /**\n * Optional. Required only for `stream: true` calls. Takes the same\n * request shape `converse` does, returning `{ stream }`, matching\n * `ConverseStreamCommand`'s real AWS SDK v3 output shape, an\n * `AsyncIterable` of incremental events under a `stream` property,\n * rather than the whole response being the iterable directly.\n */\n converseStream?(\n params: Parameters<BedrockConverseClient['converse']>[0],\n options: { signal: AbortSignal },\n ): Promise<{ stream: AsyncIterable<BedrockConverseStreamEvent> }>;\n}\n\n/**\n * One event of a Bedrock `ConverseStreamCommand` response's `stream`.\n * Content blocks (text or toolUse) are identified by `contentBlockIndex`,\n * Converse's own convention for correlating start/delta/stop events across\n * possibly-interleaved blocks, mirrored directly by VernLLM's\n * `tool_call_delta.index`.\n */\ntype BedrockConverseStreamEvent =\n | { messageStart: { role: 'assistant' } }\n | {\n contentBlockStart: {\n contentBlockIndex: number;\n start?: { toolUse?: { toolUseId?: string; name?: string } };\n };\n }\n | {\n contentBlockDelta: {\n contentBlockIndex: number;\n delta?: { text?: string } | { toolUse?: { input?: string } };\n };\n }\n | { contentBlockStop: { contentBlockIndex: number } }\n | { messageStop: { stopReason?: string } }\n | {\n metadata: {\n usage?: { inputTokens?: number; outputTokens?: number; totalTokens?: number };\n };\n }\n // The above are the happy-path events. Bedrock Converse streams can also\n // emit these as in-band exception events (not promise rejections), so\n // they need to be modeled and handled explicitly below, an unmatched\n // event previously fell through the if/else chain silently, either\n // truncating output or leaving the stream hanging until an unrelated\n // idle timeout fired.\n | { internalServerException: { message?: string } }\n | { modelStreamErrorException: { message?: string; originalStatusCode?: number } }\n | { validationException: { message?: string } }\n | { throttlingException: { message?: string } }\n | { serviceUnavailableException: { message?: string } };\n\n/** Maps a `ContentBlock` image MIME type, already validated, to Converse's `format` enum. */\nfunction toBedrockImageFormat(mimeType: string): BedrockImageFormat {\n switch (assertSupportedImageMimeType(mimeType)) {\n case 'image/png':\n return 'png';\n case 'image/jpeg':\n return 'jpeg';\n case 'image/gif':\n return 'gif';\n case 'image/webp':\n return 'webp';\n }\n}\n\n/**\n * Decodes base64 image data into the raw `Uint8Array` bytes Converse's\n * `image.source.bytes` expects (unlike Anthropic/Gemini/OpenAI, which all\n * take base64 strings directly). Uses `Buffer`, since this adapter, like\n * the rest of the package, targets Node.\n */\nfunction decodeBase64(data: string): Uint8Array {\n return new Uint8Array(Buffer.from(data, 'base64'));\n}\n\n/**\n * Translates a VernLLM `ContentBlock[]` into Converse's native content-block\n * array: text blocks pass through as `{ text }`, image blocks become\n * `{ image: { format, source: { bytes } } }` with the base64 payload decoded\n * to raw bytes, since Converse doesn't accept base64 strings directly.\n */\nfunction toBedrockContent(blocks: ContentBlock[]): BedrockContentBlock[] {\n return blocks.map((block) =>\n block.type === 'image'\n ? {\n image: {\n format: toBedrockImageFormat(block.mimeType),\n source: { bytes: decodeBase64(block.data) },\n },\n }\n : { text: block.text },\n );\n}\n\n/**\n * Optional configuration for `fromBedrock`.\n */\nexport interface BedrockAdapterOptions {\n /**\n * Optional preflight check for tool-use support, needed for `jsonSchema`\n * structured output. VernLLM never guesses capability from a failed\n * call's error message (AWS's error text isn't a documented, stable\n * contract), so this is opt-in: pass either a static list of tool-use\n * -capable model IDs, or a predicate function, and VernLLM will reject\n * unsupported models with a clear `LLMError('validation')` *before*\n * dispatching the request, instead of on the wire.\n *\n * Left unset (default), no preflight check runs, and a `jsonSchema` call\n * to an unsupported model surfaces Bedrock's raw `converse` error as-is.\n */\n toolUseSupportedModels?: string[] | ((modelId: string) => boolean);\n}\n\ntype BedrockRequest = Parameters<BedrockConverseClient['converse']>[0];\n\n/**\n * Builds the Converse-shaped request from VernLLM's wire params, shared\n * between `create` and `createStream` so both go through identical\n * translation (system prompt, message shaping, the jsonSchema →\n * forced-single-tool mapping, and the `toolUseSupportedModels` preflight\n * check all happen exactly once).\n *\n * Returns `toolName` alongside the request: when set, the model was forced\n * to call a single synthetic tool standing in for `jsonSchema` output, and\n * both `create` and `createStream` need to know this so they can unwrap\n * that tool call back into plain text content instead of treating it like\n * a real tool call.\n */\nfunction buildBedrockRequest(\n params: Parameters<LLMClient['chat']['completions']['create']>[0],\n toolUseSupportedModels: BedrockAdapterOptions['toolUseSupportedModels'],\n): { request: BedrockRequest; toolName: string | undefined } {\n const systemMessage = params.messages.find((m) => m.role === 'system');\n\n // Keep user, assistant, and tool turns, in order. Converse has no\n // separate 'tool' role: tool results travel as a user-role message\n // with toolResult content blocks, and an assistant's tool\n // requests travel as toolUse content blocks on its own turn.\n const conversationMessages = params.messages.filter(\n (m) => m.role === 'user' || m.role === 'assistant' || m.role === 'tool',\n );\n\n const jsonSchema =\n params.response_format?.type === 'json_schema' ? params.response_format.json_schema : undefined;\n\n const toolName = jsonSchema?.name.trim();\n\n if (jsonSchema && !toolName) {\n throw new LLMError('json_schema.name must not be empty.', 'validation');\n }\n\n let jsonInstruction: string | undefined;\n let toolConfig: NonNullable<BedrockRequest['toolConfig']> | undefined;\n\n if (jsonSchema) {\n // jsonSchema and real `tools` are mutually exclusive by the time\n // a call reaches here (enforced in vernLLM.ts).\n const { schema, description, strict } = jsonSchema;\n\n toolConfig = {\n tools: [\n {\n toolSpec: {\n name: toolName!,\n description,\n inputSchema: { json: schema },\n strict,\n },\n },\n ],\n toolChoice: { tool: { name: toolName! } },\n };\n } else if (params.response_format?.type === 'json_object') {\n // No schema to build a tool from, fall back to a prompt instruction\n jsonInstruction = 'Respond with valid JSON only, no prose or markdown fences.';\n } else if (params.tools?.length) {\n toolConfig = {\n tools: params.tools.map((t) => ({\n toolSpec: {\n name: t.function.name,\n description: t.function.description,\n inputSchema: { json: t.function.parameters },\n },\n })),\n toolChoice: toBedrockToolChoice(params.tool_choice),\n };\n }\n\n if (jsonSchema && toolUseSupportedModels) {\n const isSupported = Array.isArray(toolUseSupportedModels)\n ? toolUseSupportedModels.includes(params.model)\n : toolUseSupportedModels(params.model);\n\n if (!isSupported) {\n throw new LLMError(\n `Bedrock model \"${params.model}\" is not listed in toolUseSupportedModels, but jsonSchema structured output requires Converse tool use.`,\n 'validation',\n );\n }\n }\n\n const systemParts = [systemMessage?.content, jsonInstruction].filter((s): s is string =>\n Boolean(s),\n );\n\n const request: BedrockRequest = {\n modelId: params.model,\n messages: mergeConsecutiveToolResults(conversationMessages.map((m) => toBedrockMessage(m))),\n system: systemParts.length ? systemParts.map((text) => ({ text })) : undefined,\n inferenceConfig: {\n ...(params.temperature !== undefined ? { temperature: params.temperature } : {}),\n maxTokens: params.max_tokens,\n },\n ...(toolConfig ? { toolConfig } : {}),\n };\n\n return { request, toolName };\n}\n\n/**\n * Wraps a Bedrock Converse-API client so it satisfies the `LLMClient`\n * interface VernLLM uses for OpenAI/Groq. The Converse API is unified\n * across Bedrock's model families (Anthropic, Titan, Llama, Mistral, etc.),\n * so unlike raw per-model Bedrock invocation, this one adapter works\n * regardless of which underlying model `modelId` points at, as long as\n * that model supports Converse (most current-generation ones do)\n *\n * `response_format: json_schema` is mapped to Converse's `toolConfig`: a\n * single tool is defined from the schema, description, and strictness settings,\n * and `toolChoice` forces the model to call it. Provider-constrained schema\n * matching applies only when `strict: true` is forwarded and supported.\n * Native tool support varies by model family; pass\n * `toolUseSupportedModels` to preflight-check it (see\n * `BedrockAdapterOptions`), otherwise a `jsonSchema` call to an\n * unsupported model surfaces Bedrock's raw error unchanged.\n *\n * `response_format: json_object` (no schema to build a tool from) and\n * `reasoning_effort` (no Converse equivalent) fall back to a system-prompt\n * instruction and are dropped respectively.\n *\n * `tools` maps to Converse's native `toolConfig`/`toolUse`/`toolResult`;\n * `tool_choice` maps to `toolConfig.toolChoice`. Mutually exclusive with\n * `jsonSchema` by the time a call reaches here (enforced in vernLLM.ts).\n *\n * `createStream` calls `converseStream` (optional on `BedrockConverseClient`\n *, required only if the caller sets `stream: true`) and translates its\n * `contentBlockStart`/`contentBlockDelta`/`metadata` events into\n * `WireStreamChunk`s. Content blocks are tracked by `contentBlockIndex`,\n * same as `fromAnthropic`'s block-index tracking (Converse's streaming\n * shape is structurally close to Anthropic's own, both being tool-use-aware\n * content-block streams), including the same `json-tool` unwrapping: a\n * `jsonSchema`-forced tool's `toolUse.input` deltas are re-emitted as\n * `text-delta`, not `tool_call_delta`, so the accumulated result lands in\n * `finalizeResponse`'s `content` path exactly like the non-streaming\n * `create` branch above unwraps it.\n */\nexport function fromBedrock(\n bedrockClient: BedrockConverseClient,\n options?: BedrockAdapterOptions,\n): LLMClient {\n const toolUseSupportedModels = options?.toolUseSupportedModels;\n\n return {\n chat: {\n completions: {\n async create(params, requestOptions) {\n const { request, toolName } = buildBedrockRequest(params, toolUseSupportedModels);\n\n const response = await bedrockClient.converse(request, requestOptions);\n\n let text: string;\n let wireToolCalls: WireToolCall[] | undefined;\n\n if (toolName) {\n // Forced tool-use: the schema-conforming payload arrives as the\n // toolUse content block's already-parsed `input`, not as text.\n // Re-serialize it to JSON so it flows through the same\n // string-content contract every other adapter uses.\n const toolUseBlock = response.output?.message?.content?.find(\n (block) => block.toolUse?.name === toolName,\n );\n\n text = toolUseBlock?.toolUse ? JSON.stringify(toolUseBlock.toolUse.input) : '';\n } else {\n const blocks = response.output?.message?.content ?? [];\n\n text = blocks.map((c) => c.text ?? '').join('');\n\n const toolUses = blocks.filter(\n (\n block,\n ): block is { toolUse: { toolUseId?: string; name?: string; input?: unknown } } =>\n Boolean(block.toolUse),\n );\n\n if (toolUses.length) {\n wireToolCalls = toolUses.map((block, i) => {\n const toolUse = block.toolUse;\n\n if (!toolUse.name) {\n throw new LLMError(\n `Bedrock returned a toolUse block without a name at index ${i}.`,\n 'validation',\n );\n }\n\n return {\n id: toolUse.toolUseId ?? `${toolUse.name}_${i}`,\n type: 'function' as const,\n function: {\n name: toolUse.name,\n arguments: JSON.stringify(toolUse.input ?? {}),\n },\n };\n });\n }\n }\n\n return {\n choices: [\n {\n message: { content: text, ...(wireToolCalls ? { tool_calls: wireToolCalls } : {}) },\n },\n ],\n usage: {\n prompt_tokens: response.usage?.inputTokens,\n completion_tokens: response.usage?.outputTokens,\n total_tokens: response.usage?.totalTokens,\n },\n };\n },\n\n async *createStream(params, requestOptions) {\n if (!bedrockClient.converseStream) {\n throw new LLMError(\n 'stream: true requires a Bedrock client with converseStream',\n 'validation',\n );\n }\n\n const { request, toolName } = buildBedrockRequest(params, toolUseSupportedModels);\n\n const { stream } = await bedrockClient.converseStream(request, requestOptions);\n\n const blockKinds = new Map<number, 'text' | 'tool_use' | 'json-tool'>();\n\n for await (const event of stream) {\n if ('contentBlockStart' in event) {\n const { contentBlockIndex, start } = event.contentBlockStart;\n\n if (start?.toolUse) {\n const kind = start.toolUse.name === toolName ? 'json-tool' : 'tool_use';\n\n blockKinds.set(contentBlockIndex, kind);\n\n if (kind === 'tool_use' && !toolName) {\n yield {\n type: 'tool_call_delta',\n index: contentBlockIndex,\n id: start.toolUse.toolUseId,\n name: start.toolUse.name,\n };\n }\n } else {\n blockKinds.set(contentBlockIndex, 'text');\n }\n } else if ('contentBlockDelta' in event) {\n const { contentBlockIndex, delta } = event.contentBlockDelta;\n\n // Only surfaced as real content when there's no forced\n // json-schema tool in play, see the identical guard (and\n // its full rationale) in `fromAnthropic`'s `createStream`.\n // Converse's streaming shape is structurally close enough to\n // Anthropic's own that the same corruption risk applies: a\n // genuine text block alongside a forced tool call would\n // otherwise get concatenated into the same buffer as the\n // tool's JSON payload.\n if (delta && 'text' in delta && delta.text !== undefined && !toolName) {\n yield { type: 'text-delta', delta: delta.text };\n } else if (delta && 'toolUse' in delta && delta.toolUse?.input !== undefined) {\n const kind = blockKinds.get(contentBlockIndex);\n\n if (kind === 'json-tool') {\n yield { type: 'text-delta', delta: delta.toolUse.input };\n } else if (!toolName) {\n yield {\n type: 'tool_call_delta',\n index: contentBlockIndex,\n argumentsDelta: delta.toolUse.input,\n } satisfies WireStreamChunk;\n }\n }\n } else if ('metadata' in event && event.metadata.usage) {\n yield {\n type: 'usage',\n usage: {\n prompt_tokens: event.metadata.usage.inputTokens,\n completion_tokens: event.metadata.usage.outputTokens,\n total_tokens: event.metadata.usage.totalTokens,\n },\n };\n } else if ('throttlingException' in event) {\n throw new LLMError(\n event.throttlingException.message ?? 'Bedrock throttled the request mid-stream',\n 'api',\n 429,\n );\n } else if ('validationException' in event) {\n throw new LLMError(\n event.validationException.message ?? 'Bedrock rejected the request mid-stream',\n 'validation',\n );\n } else if (\n 'internalServerException' in event ||\n 'serviceUnavailableException' in event ||\n 'modelStreamErrorException' in event\n ) {\n const detail =\n ('internalServerException' in event && event.internalServerException.message) ||\n ('serviceUnavailableException' in event &&\n event.serviceUnavailableException.message) ||\n ('modelStreamErrorException' in event && event.modelStreamErrorException.message) ||\n 'Bedrock reported a mid-stream error';\n\n const status =\n ('modelStreamErrorException' in event &&\n event.modelStreamErrorException.originalStatusCode) ||\n ('serviceUnavailableException' in event && 503) ||\n 500;\n\n throw new LLMError(detail, 'api', status);\n }\n }\n },\n },\n },\n };\n}\n\n/** Maps VernLLM's OpenAI-shaped wire `tool_choice` onto Converse's `toolChoice`. */\nfunction toBedrockToolChoice(\n toolChoice: Parameters<LLMClient['chat']['completions']['create']>[0]['tool_choice'],\n): NonNullable<Parameters<BedrockConverseClient['converse']>[0]['toolConfig']>['toolChoice'] {\n if (!toolChoice || toolChoice === 'auto') return { auto: {} };\n if (toolChoice === 'required') return { any: {} };\n\n if (toolChoice === 'none') {\n // Converse's toolConfig.toolChoice has no 'none' option. The only way\n // to guarantee no tool use is to omit toolConfig.tools entirely, which\n // isn't an option here since tools were explicitly requested. Silently\n // falling back to 'auto' would let the model call tools despite the\n // caller explicitly asking it not to, so this fails loudly instead.\n throw new LLMError(\n \"'none' is not supported by fromBedrock: Bedrock Converse has no \" +\n '`tool_choice` equivalent to forbidding tool use while tools are still offered. Omit ' +\n '`tools` entirely for this call instead.',\n 'validation',\n );\n }\n\n return { tool: { name: toolChoice.function.name } };\n}\n/**\n * Translates one VernLLM wire message into Converse's\n * `{ role: 'user' | 'assistant', content }` shape.\n */\nfunction toBedrockMessage(\n m: Extract<\n Parameters<LLMClient['chat']['completions']['create']>[0]['messages'][number],\n { role: 'user' | 'assistant' | 'tool' }\n >,\n): { role: 'user' | 'assistant'; content: BedrockContentBlock[] } {\n if (m.role === 'tool') {\n return {\n role: 'user',\n content: [\n {\n toolResult: {\n toolUseId: m.tool_call_id,\n content: [{ text: m.content }],\n status: m.is_error ? 'error' : 'success',\n },\n },\n ],\n };\n }\n\n if (m.role === 'assistant' && m.tool_calls?.length) {\n const blocks: BedrockContentBlock[] = [];\n\n if (m.content) blocks.push({ text: m.content });\n\n for (const tc of m.tool_calls) {\n let input: unknown;\n\n if (!tc.function.arguments.trim()) {\n input = {};\n } else {\n try {\n input = JSON.parse(tc.function.arguments);\n } catch (cause) {\n throw new LLMError(\n `Assistant tool call \"${tc.function.name}\" (${tc.id}) has arguments that are not valid JSON.`,\n 'validation',\n undefined,\n undefined,\n cause,\n );\n }\n }\n\n blocks.push({ toolUse: { toolUseId: tc.id, name: tc.function.name, input } });\n }\n\n return { role: 'assistant', content: blocks };\n }\n\n return {\n role: m.role,\n content: Array.isArray(m.content) ? toBedrockContent(m.content) : [{ text: m.content ?? '' }],\n };\n}\n\n/**\n * Converse expects the results of everything the model asked for in one\n * turn to arrive together as multiple `toolResult` content blocks on a\n * single `'user'` message, not as separate consecutive `'user'` messages.\n * The per-wire-message mapping above produces one `'user'` message per\n * VernLLM wire tool message, so when an assistant turn requested more than\n * one tool, this merges the resulting run of toolResult-only `'user'`\n * messages back into one.\n */\nfunction mergeConsecutiveToolResults(\n messages: { role: 'user' | 'assistant'; content: BedrockContentBlock[] }[],\n): { role: 'user' | 'assistant'; content: BedrockContentBlock[] }[] {\n const isToolResultOnly = (\n m: (typeof messages)[number],\n ): m is { role: 'user'; content: BedrockContentBlock[] } =>\n m.role === 'user' && m.content.length > 0 && m.content.every((b) => 'toolResult' in b);\n\n const merged: (typeof messages)[number][] = [];\n\n for (const m of messages) {\n const prev = merged.at(-1);\n\n if (isToolResultOnly(m) && prev && isToolResultOnly(prev)) {\n prev.content.push(...m.content);\n } else {\n merged.push(m);\n }\n }\n\n return merged;\n}\n","import { parseSseStream, SSE_PING } from '../internal/sse.js';\nimport {\n LLMError,\n type LLMClient,\n type WireStreamChunk,\n type WireToolCall,\n} from '../types/index.js';\n\n/** The chat-completion-shaped request VernLLM builds internally */\ntype ChatRequest = Parameters<LLMClient['chat']['completions']['create']>[0];\n\n/**\n * The minimal shape the fetch adapter needs from a response object.\n * Native `fetch`'s `Response` satisfies this, but so do wrappers around\n * `axios`, `node-fetch`, `undici`, etc, which makes `request` swappable\n * without forcing consumers to polyfill the full `Response` interface\n */\nexport interface ResponseLike {\n ok: boolean;\n status: number;\n headers: {\n get(name: string): string | null;\n };\n text(): Promise<string>;\n json(): Promise<unknown>;\n}\n\n/** A fetch-compatible request function; defaults to native `fetch` */\nexport type RequestLike = (\n url: string,\n init: {\n method: string;\n headers: Record<string, string>;\n body?: string;\n signal?: AbortSignal;\n },\n) => Promise<ResponseLike>;\n\n/**\n * A streaming-capable request function. Unlike `RequestLike`, which returns\n * a fully-buffered `ResponseLike`, this resolves to an `AsyncIterable` of\n * progressively-arriving chunks, the common ground across transports:\n * native `fetch`'s `response.body` (wrapped to be iterable; see\n * `webStreamToAsyncIterable` below), axios's Node `Readable` in\n * `responseType: 'stream'` mode (already async-iterable, no wrapping\n * needed), `node-fetch`, `undici`, etc, all satisfy this with little or no\n * glue code. Defaults to native `fetch`.\n */\nexport type StreamRequestLike = (\n url: string,\n init: {\n method: string;\n headers: Record<string, string>;\n body?: string;\n signal?: AbortSignal;\n },\n) => Promise<AsyncIterable<Uint8Array | string>>;\n\nexport interface FetchAdapterConfig {\n /** Endpoint URL, or a function of the request in case it depends on model/params */\n url: string | ((params: ChatRequest) => string);\n /** Static headers, or a function (sync or async) for things like refreshed auth tokens */\n headers?:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>);\n /** HTTP method. Default 'POST' */\n method?: string;\n /**\n * The function used to make the HTTP request. Defaults to native `fetch`.\n * Swap in `axios`, `node-fetch`, or any other transport, as long as it\n * resolves to a `ResponseLike` object\n */\n request?: RequestLike;\n /** Maps VernLLMs internal chat-completion request into the providers raw request body */\n mapRequest: (params: ChatRequest) => unknown;\n /**\n * Maps the providers raw JSON response into `{ content, usage?, toolCalls? }`\n * `content` is the assistants text (JSON string when JSON mode was requested).\n * `content` may be empty/omitted when the model responded with only tool\n * calls and no text.\n *\n * `toolCalls`, when the model requested one or more tools, is the list of\n * calls as flat `{ id, name, arguments }` entries (matching this config's\n * own `toolCalls?: Array<{ id: string; name: string; arguments: string }>`\n * return type below), each entry's `arguments` already JSON-*encoded* as a\n * string (not the parsed object), mirroring the wire format every\n * OpenAI-compatible provider uses. `fromFetch` itself converts these into\n * `WireToolCall`'s `type`/`function`-wrapped shape before returning them\n * from `create`. VernLLM parses (and validates, if `argumentsSchema` was\n * set) the arguments string internally, mapResponse doesn't need to do\n * that itself.\n */\n mapResponse: (json: unknown) => {\n content?: string;\n usage?: { promptTokens?: number; completionTokens?: number; totalTokens?: number };\n toolCalls?: Array<{ id: string; name: string; arguments: string }>;\n };\n\n /**\n * Optional. Required only for `stream: true` calls. The function used to\n * open a streaming HTTP request. Takes the same request shape as\n * `request`, but resolves to an `AsyncIterable` of progressively-arriving\n * `Uint8Array` or `string` chunks instead of a buffered `ResponseLike`.\n * Defaults to native `fetch`.\n */\n requestStream?: StreamRequestLike;\n\n /**\n * Optional. How the raw stream bytes are split into individual event\n * payloads. Defaults to Server-Sent Events framing (`data: ...` blocks\n * separated by a blank line, `[DONE]` sentinel honored, see\n * `parseSseStream`), which covers the large majority of LLM providers'\n * streaming HTTP endpoints. Override this for a provider that frames its\n * stream differently, e.g. newline-delimited JSON (NDJSON) with no SSE\n * envelope.\n */\n parseStreamFrames?: (chunks: AsyncIterable<Uint8Array | string>) => AsyncIterable<unknown>;\n\n /**\n * Optional. Required only for `stream: true` calls. Maps one parsed\n * stream event (already extracted from its frame by `parseStreamFrames`)\n * into zero, one, or more `WireStreamChunk`s, mirrors `mapResponse`'s\n * role for the non-streaming path, just per-event instead of once for\n * the whole body. Return `undefined` to skip an event that carries\n * nothing VernLLM needs (e.g. a provider's keep-alive ping). Configs\n * that don't implement this make `stream: true` throw a clear\n * `LLMError('validation')` rather than a confusing runtime failure or a\n * silently empty stream.\n */\n mapStreamEvent?: (event: unknown) => WireStreamChunk | WireStreamChunk[] | undefined;\n}\n\n/**\n * Wraps a WHATWG `ReadableStream` (what `response.body` is) so it can be\n * consumed with `for await`. Implemented via `getReader()` rather than\n * relying on `ReadableStream` having a native `Symbol.asyncIterator`,\n * that support varies across runtimes/versions, and this works everywhere\n * a `ReadableStream` does.\n */\nasync function* webStreamToAsyncIterable(\n stream: ReadableStream<Uint8Array>,\n): AsyncGenerator<Uint8Array> {\n const reader = stream.getReader();\n\n try {\n for (;;) {\n const { done, value } = await reader.read();\n\n if (done) return;\n if (value) yield value;\n }\n } finally {\n // Cancel before releasing the lock so an early-terminated or\n // downstream-failed consumer still tells the underlying source to\n // stop, instead of leaving it running with nothing left to read it.\n // An already-errored stream rejects cancel(); that rejection isn't\n // useful to the caller here, so it's swallowed.\n try {\n await reader.cancel();\n } catch {\n // Ignore: the stream may already be errored/closed.\n }\n\n reader.releaseLock();\n }\n}\n\n/** Default `requestStream`: native `fetch`, with the same error/`.status` contract non-streaming errors get. */\nasync function defaultRequestStream(\n url: string,\n init: { method: string; headers: Record<string, string>; body?: string; signal?: AbortSignal },\n): Promise<AsyncIterable<Uint8Array | string>> {\n const res = await fetch(url, init);\n\n if (!res.ok) {\n const body = await res.text().catch(() => '');\n const err = new Error(\n `Fetch adapter stream request failed (${res.status}): ${body.slice(0, 500)}`,\n ) as Error & { status?: number; headers?: ResponseLike['headers'] };\n\n err.status = res.status;\n err.headers = res.headers;\n\n throw err;\n }\n\n if (!res.body) {\n throw new Error('Fetch adapter stream request received a response with no body.');\n }\n\n return webStreamToAsyncIterable(res.body);\n}\n\n/** Builds the shared `{ method, headers, body? }` request-init for both `create` and `createStream`. */\nasync function buildRequestInit(\n config: FetchAdapterConfig,\n params: ChatRequest,\n requestBody: unknown,\n): Promise<{ url: string; method: string; headers: Record<string, string>; body?: string }> {\n const url = typeof config.url === 'function' ? config.url(params) : config.url;\n const headers = typeof config.headers === 'function' ? await config.headers() : config.headers;\n const method = config.method ?? 'POST';\n\n // GET/HEAD requests can't carry a body, so skip both the body and\n // the Content-Type header for them rather than sending a body a\n // server may reject\n const supportsBody = !['GET', 'HEAD'].includes(method.toUpperCase());\n\n return {\n url,\n method,\n headers: supportsBody ? { 'Content-Type': 'application/json', ...headers } : { ...headers },\n ...(supportsBody ? { body: JSON.stringify(requestBody) } : {}),\n };\n}\n\n/**\n * A fetch-based escape hatch for providers with no SDK, or where pulling one\n * in isnt worth it. You supply the URL, headers, and two small mapping\n * functions; this handles the HTTP call and slots the result into the same\n * `LLMClient` shape every other adapter produces, so retries, timeouts,\n * the circuit breaker, and JSON/schema handling all still work unmodified\n *\n * Non-2xx responses throw an error with `.status` set to the HTTP status\n * code, so VernLLMs `nonRetryableStatus` handling (e.g. failing fast on\n * 401/403) applies here too\n *\n * Tool calling works the same way as every other adapter: `mapRequest`\n * receives the full `ChatRequest`, including `tools`/`toolChoice`, so it can\n * translate them into whatever shape the provider's wire format expects\n * (typically an OpenAI-`function`-wrapped `tools` array plus a `tool_choice`\n * field). On the way back, `mapResponse` may return a `toolCalls` array\n * (id/name/JSON-encoded-arguments-string per call) alongside or instead of\n * `content`; VernLLM parses and (if `argumentsSchema` was set) validates\n * those arguments the same way it does for every other adapter. For\n * `stream: true`, tool-call deltas go through the existing\n * `mapStreamEvent` seam via `WireStreamChunk`'s `tool_call_delta` variant,\n * no separate config is needed for streaming vs non-streaming tool calls.\n *\n\n * `createStream` requires `mapStreamEvent` (there's no non-streaming\n * response to fall back on, unlike the other three optional streaming\n * seams). It opens the request via `requestStream` (defaults to native\n * `fetch`), splits the raw bytes into individual events via\n * `parseStreamFrames` (defaults to SSE framing, see `parseSseStream`),\n * and translates each event into `WireStreamChunk`(s) via\n * `mapStreamEvent`. Both seams are overridable per-config for providers\n * that don't fit the SSE-over-fetch default. If a custom `request`\n * transport is configured, `requestStream` must be configured too,\n * `requestStream` never silently falls back to `request` (see\n * `createStream`'s own comment for why), so a `stream: true` call with\n * `request` set but no `requestStream` throws a clear\n * `LLMError('validation')` instead of quietly using unrelated native\n * `fetch`.\n */\nexport function fromFetch(config: FetchAdapterConfig): LLMClient {\n return {\n chat: {\n completions: {\n async create(params, options) {\n const { url, method, headers, body } = await buildRequestInit(\n config,\n params,\n config.mapRequest(params),\n );\n const request = config.request ?? fetch;\n\n const res = await request(url, { method, headers, body, signal: options.signal });\n\n if (!res.ok) {\n const responseBody = await res.text().catch(() => '');\n const err = new Error(\n `Fetch adapter request failed (${res.status}): ${responseBody.slice(0, 500)}`,\n ) as Error & { status?: number; headers?: ResponseLike['headers'] };\n err.status = res.status;\n // Attach headers so downstream retry logic (e.g. rate-limit\n // handling) can read things like `Retry-After`\n err.headers = res.headers;\n throw err;\n }\n\n const json = await res.json();\n const { content, usage, toolCalls } = config.mapResponse(json);\n\n // `.length` guard, not just truthiness: an empty array is\n // semantically \"no tool calls\", same as `undefined`. Kept\n // explicit here rather than relying on downstream consumers\n // (e.g. `finalizeResponse`'s `wireToolCalls?.length` check) to\n // treat `[]` as absent, so this stays correct even if that\n // convention ever changes.\n const wireToolCalls: WireToolCall[] | undefined = toolCalls?.length\n ? toolCalls.map((tc) => ({\n id: tc.id,\n type: 'function' as const,\n function: { name: tc.name, arguments: tc.arguments },\n }))\n : undefined;\n\n return {\n choices: [\n {\n message: {\n content,\n ...(wireToolCalls ? { tool_calls: wireToolCalls } : {}),\n },\n },\n ],\n usage: usage\n ? {\n prompt_tokens: usage.promptTokens,\n completion_tokens: usage.completionTokens,\n total_tokens: usage.totalTokens,\n }\n : undefined,\n };\n },\n\n async *createStream(params, options) {\n if (!config.mapStreamEvent) {\n throw new LLMError(\n 'stream: true requires mapStreamEvent to be configured on fromFetch',\n 'validation',\n );\n }\n\n // A custom `request` transport (proxying, special auth, test\n // mocking, etc.) is silently irrelevant to streaming unless the\n // caller *also* configures `requestStream`, `requestStream`\n // defaults to plain native `fetch`, not to `config.request`,\n // since `RequestLike`'s buffered `ResponseLike` has no way to\n // expose a byte stream generically. Falling back to native\n // `fetch` anyway would be a surprising, easy-to-miss divergence\n // (bypassing whatever `request` was there for, a proxy, custom\n // auth, or a test's mocked transport, and potentially hitting\n // the real network). Failing loudly here instead of guessing.\n if (config.request && !config.requestStream) {\n throw new LLMError(\n '`stream: true` requires `requestStream` to be configured on fromFetch when a ' +\n 'custom `request` transport is set. `requestStream` does not fall back to ' +\n \"`request` (it needs an async-iterable byte stream, which `RequestLike`'s \" +\n 'buffered `ResponseLike` has no way to provide), without it, `stream: true` ' +\n 'would silently use plain native `fetch` instead of your configured transport. ' +\n 'Add a `requestStream` that opens the same connection your `request` does, or ' +\n 'omit `request` if native `fetch` is fine for both.',\n 'validation',\n );\n }\n\n const { url, method, headers, body } = await buildRequestInit(\n config,\n params,\n config.mapRequest(params),\n );\n const requestStream = config.requestStream ?? defaultRequestStream;\n const parseFrames = config.parseStreamFrames ?? parseSseStream;\n\n const byteStream = await requestStream(url, {\n method,\n headers,\n body,\n signal: options.signal,\n });\n\n for await (const event of parseFrames(byteStream)) {\n // Only the default parseSseStream produces this sentinel (an\n // SSE comment line used as a keep-alive ping). Handled here,\n // before mapStreamEvent, since provider-specific mapping\n // shouldn't need to know about SSE framing internals.\n if (event === SSE_PING) {\n yield { type: 'ping' };\n continue;\n }\n\n const wireChunks = config.mapStreamEvent(event);\n\n if (!wireChunks) continue;\n\n if (Array.isArray(wireChunks)) {\n yield* wireChunks;\n } else {\n yield wireChunks;\n }\n }\n },\n },\n },\n };\n}\n","import { assertSupportedImageMimeType } from '../internal/imageFormat.js';\n\nimport type { ContentBlock, LLMClient, WireStreamChunk } from '../types/index.js';\n\n/** OpenAI's native per-part content shape for a user message. */\ntype OpenAIContentPart =\n | { type: 'text'; text: string }\n | { type: 'image_url'; image_url: { url: string } };\n\n/**\n * Translates a VernLLM `ContentBlock[]` into OpenAI's wire-level content\n * array. Text blocks become `{ type: 'text', text }`; image blocks become\n * `{ type: 'image_url', image_url: { url } }` with the base64 payload\n * inlined as a `data:` URL, since our `ContentBlock` shape (`{ type:\n * 'image', data, mimeType }`) is provider-agnostic and doesn't itself match\n * OpenAI's wire format.\n */\nfunction toOpenAIContent(blocks: ContentBlock[]): OpenAIContentPart[] {\n return blocks.map((block) =>\n block.type === 'image'\n ? {\n type: 'image_url',\n image_url: {\n url: `data:${assertSupportedImageMimeType(block.mimeType)};base64,${block.data}`,\n },\n }\n : { type: 'text', text: block.text },\n );\n}\n\n/** One chunk of an OpenAI-shaped `chat.completions.create({ stream: true })` SSE stream. */\ninterface OpenAIStreamChunk {\n choices?: Array<{\n delta?: {\n content?: string | null;\n tool_calls?: Array<{\n index: number;\n id?: string;\n function?: { name?: string; arguments?: string };\n }>;\n };\n }>;\n usage?: { prompt_tokens?: number; completion_tokens?: number; total_tokens?: number };\n}\n\n/**\n * Translates VernLLM's provider-agnostic `messages` (the one part of a\n * request that isn't a pure passthrough for OpenAI-compatible clients) into\n * OpenAI's native wire shape. Shared between `create` and `createStream` so\n * both go through identical message translation.\n */\nfunction toOpenAIMessages(\n params: Parameters<LLMClient['chat']['completions']['create']>[0],\n): unknown[] {\n return params.messages.map((m) => {\n if (m.role === 'user' && Array.isArray(m.content)) {\n return { ...m, content: toOpenAIContent(m.content) };\n }\n\n if (m.role === 'tool') {\n const { is_error: _isError, ...openAIToolMessage } = m;\n return openAIToolMessage;\n }\n\n return m;\n });\n}\n\n/**\n * Translates one OpenAI-shaped SSE chunk into zero or more `WireStreamChunk`s.\n * A single chunk can carry a text delta, one or more tool-call argument\n * deltas (each keyed by `index`, OpenAI's own convention for streaming\n * parallel tool calls, mirrored directly by VernLLM's `tool_call_delta`\n * shape so accumulation composes without translation), and/or a final\n * usage block (present only when `stream_options.include_usage` is set,\n * which this adapter always sets).\n */\nfunction* toWireStreamChunks(chunk: OpenAIStreamChunk): Generator<WireStreamChunk> {\n const delta = chunk.choices?.[0]?.delta;\n\n if (delta?.content) {\n yield { type: 'text-delta', delta: delta.content };\n }\n\n if (delta?.tool_calls?.length) {\n for (const toolCall of delta.tool_calls) {\n yield {\n type: 'tool_call_delta',\n index: toolCall.index,\n id: toolCall.id,\n name: toolCall.function?.name,\n argumentsDelta: toolCall.function?.arguments,\n };\n }\n }\n\n if (chunk.usage) {\n yield { type: 'usage', usage: chunk.usage };\n }\n}\n\n/**\n * Adapter for any SDK/client whose `chat.completions.create` already\n * matches the OpenAI wire format: this covers most hosted inference\n * providers, since \"OpenAI-compatible\" is a de facto standard for chat\n * completion APIs. Almost everything passes straight through untouched,\n * this exists purely so call sites read clearly (`fromMistral(client)` vs\n * handing a Mistral client to something typed for OpenAI) and so a real\n * transformation could be added later, per-provider, without a breaking\n * change.\n *\n * The one thing that isn't a pure passthrough: a `ContentBlock[]`\n * `userContent` is translated into OpenAI's native `image_url` content-part\n * shape, since VernLLM's `ContentBlock` is intentionally provider-agnostic\n * rather than a copy of any one provider's wire format.\n *\n * Not every SDKs own TypeScript types line up exactly with `LLMClient`\n * (extra fields, stricter unions, etc.), so this takes `unknown` and casts:\n * the actual compatibility contract is the JSON each provider sends and\n * receives over the wire, not the SDKs TS types.\n *\n * `createStream` is implemented by calling the same underlying\n * `chat.completions.create` with `stream: true` (and, for providers that\n * support it, `stream_options: { include_usage: true }`, so a final usage\n * block arrives), the OpenAI SDK, and every OpenAI-compatible client\n * modeled on it, returns an `AsyncIterable` of SSE chunks instead of a\n * single completion object when `stream: true` is set. Each chunk is\n * translated into `WireStreamChunk`(s) via `toWireStreamChunks`.\n *\n * Note on long-running reasoning models: this adapter consumes the\n * underlying SDK's already-parsed stream rather than raw SSE bytes, so\n * unlike `fromFetch`/`fromAnthropic` it cannot see comment-only keep-alive\n * ping frames. Combined with `chunkIdleTimeoutMs`'s 30 second default and\n * `reasoningEffort` (documented to have long silent gaps for o-series and\n * similar models), a long-running reasoning call on this adapter can trip\n * the idle timeout even though the provider is still working. Raise or\n * disable `chunkIdleTimeoutMs` per call for those routes, see `CallParams`.\n */\nexport interface OpenAICompatibleAdapterOptions {\n /**\n * Whether the provider supports `stream_options.include_usage`. Not\n * every \"OpenAI-compatible\" provider is guaranteed to, so this defaults\n * to `true` (matching OpenAI, Groq, Mistral, and most others observed)\n * and should be set to `false` for a provider verified not to support\n * it. When `false`, `stream_options` is omitted entirely and no usage\n * block will arrive on the stream; callers relying on streamed `usage`\n * with such a provider won't get one.\n */\n supportsStreamUsage?: boolean;\n}\n\nexport function fromOpenAICompatible(\n client: unknown,\n options: OpenAICompatibleAdapterOptions = {},\n): LLMClient {\n const raw = client as LLMClient;\n const { supportsStreamUsage = true } = options;\n\n // The underlying client's `create`, called with `stream: true`, returns\n // an AsyncIterable of `OpenAIStreamChunk` rather than\n // `LLMClient['create']`'s normal single-completion return type, hence\n // `unknown` here and a cast at the call site, same rationale as casting\n // the whole client above: the wire contract, not the SDK's own TS types,\n // is what's actually being relied on.\n const rawCreate = raw.chat.completions.create.bind(raw.chat.completions) as unknown as (\n params: unknown,\n options: { signal: AbortSignal },\n ) => Promise<unknown> | AsyncIterable<OpenAIStreamChunk>;\n\n return {\n chat: {\n completions: {\n async create(params, options) {\n const messages = toOpenAIMessages(params);\n\n return raw.chat.completions.create(\n { ...params, messages } as Parameters<LLMClient['chat']['completions']['create']>[0],\n options,\n );\n },\n\n async *createStream(params, options) {\n const messages = toOpenAIMessages(params);\n\n const stream = (await rawCreate(\n {\n ...params,\n messages,\n stream: true,\n ...(supportsStreamUsage ? { stream_options: { include_usage: true } } : {}),\n },\n options,\n )) as AsyncIterable<OpenAIStreamChunk>;\n\n for await (const chunk of stream) {\n yield* toWireStreamChunks(chunk);\n }\n },\n },\n },\n };\n}\n\n// LLM aliases\n\n/** Groqs SDK matches the OpenAI wire format */\nexport const fromGroq = fromOpenAICompatible;\n\n/**\n * Mistrals `chat.completions`-shaped client (or their OpenAI-compat\n * endpoint). Mistral supports `stream_options.include_usage` (added after\n * an earlier period where it returned a 422 for unrecognized fields, per\n * Mistral's changelog and streaming docs), so this is a plain alias like\n * the others, `supportsStreamUsage` defaults to `true`.\n */\nexport const fromMistral = fromOpenAICompatible;\n\n/** DeepSeeks API is OpenAI-compatible */\nexport const fromDeepSeek = fromOpenAICompatible;\n\n/** Cerebras inference API is OpenAI-compatible */\nexport const fromCerebras = fromOpenAICompatible;\n\n/** Together AIs API is OpenAI-compatible */\nexport const fromTogether = fromOpenAICompatible;\n\n/** Fireworks AIs API is OpenAI-compatible */\nexport const fromFireworks = fromOpenAICompatible;\n\n/**\n * Ollama exposes an OpenAI-compatible endpoint at `/v1/chat/completions`\n * (as opposed to its native `/api/chat` format, which differs). Point an\n * OpenAI SDK instances `baseURL` at your Ollama server and pass it here:\n * this does not talk to Ollamas native API directly.\n */\nexport const fromOllama = fromOpenAICompatible;\n\n/** OpenRouter's API is OpenAI-compatible */\nexport const fromOpenRouter = fromOpenAICompatible;\n\n/** Perplexity's API is OpenAI-compatible */\nexport const fromPerplexity = fromOpenAICompatible;\n\n/** DeepInfra's API is OpenAI-compatible */\nexport const fromDeepInfra = fromOpenAICompatible;\n\n/** Novita's API is OpenAI-compatible */\nexport const fromNovita = fromOpenAICompatible;\n\n/** Hyperbolic's API is OpenAI-compatible */\nexport const fromHyperbolic = fromOpenAICompatible;\n\n/** Moonshot's (Kimi) API is OpenAI-compatible */\nexport const fromMoonshot = fromOpenAICompatible;\n\n/** Zhipu's (GLM) API is OpenAI-compatible */\nexport const fromZhipu = fromOpenAICompatible;\n\n/**\n * LM Studio exposes an OpenAI-compatible endpoint at `/v1/chat/completions`.\n * Point an OpenAI SDK instance's `baseURL` at your local LM Studio server.\n */\nexport const fromLMStudio = fromOpenAICompatible;\n\n/**\n * vLLM's OpenAI-compatible server mode exposes `/v1/chat/completions`.\n * Point an OpenAI SDK instance's `baseURL` at your vLLM server.\n */\nexport const fromVLLM = fromOpenAICompatible;\n\n/** xAI's Grok API is OpenAI-compatible */\nexport const fromXAI = fromOpenAICompatible;\n\n/** NVIDIA NIM's hosted and self-hosted endpoints are OpenAI-compatible */\nexport const fromNvidiaNIM = fromOpenAICompatible;\n\n/** Vercel AI Gateway is OpenAI-compatible */\nexport const fromVercelAIGateway = fromOpenAICompatible;\n\n/** Cloudflare Workers AI exposes an OpenAI-compatible endpoint */\nexport const fromCloudflareWorkersAI = fromOpenAICompatible;\n\n/** GitHub Models is OpenAI-compatible */\nexport const fromGitHubModels = fromOpenAICompatible;\n\n/** Nebius AI Studio is OpenAI-compatible */\nexport const fromNebius = fromOpenAICompatible;\n\n/** SambaNova Cloud's API is OpenAI-compatible */\nexport const fromSambaNova = fromOpenAICompatible;\n\n/** Baseten's model hosting exposes an OpenAI-compatible endpoint */\nexport const fromBaseten = fromOpenAICompatible;\n\n/** Featherless AI's API is OpenAI-compatible */\nexport const fromFeatherless = fromOpenAICompatible;\n\n/** Friendli AI's serving endpoint is OpenAI-compatible */\nexport const fromFriendli = fromOpenAICompatible;\n\n/** SiliconFlow's API is OpenAI-compatible */\nexport const fromSiliconFlow = fromOpenAICompatible;\n\n/** Parasail's inference API is OpenAI-compatible */\nexport const fromParasail = fromOpenAICompatible;\n\n/** StepFun's API is OpenAI-compatible */\nexport const fromStepFun = fromOpenAICompatible;\n\n/** MiniMax's API is OpenAI-compatible */\nexport const fromMiniMax = fromOpenAICompatible;\n\n/** Lambda Labs' Inference API is OpenAI-compatible */\nexport const fromLambdaLabs = fromOpenAICompatible;\n\n/** Snowflake Cortex's LLM endpoint is OpenAI-compatible */\nexport const fromSnowflakeCortex = fromOpenAICompatible;\n\n/** Anyscale Endpoints' API is OpenAI-compatible */\nexport const fromAnyscale = fromOpenAICompatible;\n\n/** Lepton AI's inference API is OpenAI-compatible */\nexport const fromLepton = fromOpenAICompatible;\n\n/** kluster.ai's inference API is OpenAI-compatible */\nexport const fromKlusterAI = fromOpenAICompatible;\n\n/** Inference.net's API is OpenAI-compatible */\nexport const fromInferenceNet = fromOpenAICompatible;\n\n/** Infermatic's API is OpenAI-compatible */\nexport const fromInfermatic = fromOpenAICompatible;\n\n/** AtlasCloud's inference API is OpenAI-compatible */\nexport const fromAtlasCloud = fromOpenAICompatible;\n\n/** 01.AI's (Yi models) API is OpenAI-compatible */\nexport const from01AI = fromOpenAICompatible;\n"],"mappings":"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"}