@happyvertical/ai 0.110.1 → 0.111.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -0
- package/dist/chunks/{anthropic-DhNGsQpl.js → anthropic-DQjBd3wu.js} +3 -3
- package/dist/chunks/{anthropic-DhNGsQpl.js.map → anthropic-DQjBd3wu.js.map} +1 -1
- package/dist/chunks/{bedrock-CrtUO8yx.js → bedrock-gtE6OU5Z.js} +3 -3
- package/dist/chunks/{bedrock-CrtUO8yx.js.map → bedrock-gtE6OU5Z.js.map} +1 -1
- package/dist/chunks/{bifrost-BU6OvIP9.js → bifrost-DSeAoUz-.js} +4 -4
- package/dist/chunks/{bifrost-BU6OvIP9.js.map → bifrost-DSeAoUz-.js.map} +1 -1
- package/dist/chunks/{byteplus-modelark-gG941oea.js → byteplus-modelark-C0rRxYwh.js} +3 -3
- package/dist/chunks/{byteplus-modelark-gG941oea.js.map → byteplus-modelark-C0rRxYwh.js.map} +1 -1
- package/dist/chunks/{claude-cli-CW_gIocm.js → claude-cli-DysSNpKY.js} +3 -3
- package/dist/chunks/{claude-cli-CW_gIocm.js.map → claude-cli-DysSNpKY.js.map} +1 -1
- package/dist/chunks/{continuation-BMGvMlzq.js → continuation-B-b0Iqgj.js} +52 -39
- package/dist/chunks/continuation-B-b0Iqgj.js.map +1 -0
- package/dist/chunks/{gateway-audio-models-DuXbi_2q.js → gateway-audio-models-57sR3hHE.js} +2 -2
- package/dist/chunks/{gateway-audio-models-DuXbi_2q.js.map → gateway-audio-models-57sR3hHE.js.map} +1 -1
- package/dist/chunks/{gemini-DCo6d-n1.js → gemini-BHdv492T.js} +3 -3
- package/dist/chunks/{gemini-DCo6d-n1.js.map → gemini-BHdv492T.js.map} +1 -1
- package/dist/chunks/{huggingface-jqjeFPdr.js → huggingface-vooWYknE.js} +3 -3
- package/dist/chunks/{huggingface-jqjeFPdr.js.map → huggingface-vooWYknE.js.map} +1 -1
- package/dist/chunks/{laya-D8o5TEO7.js → laya-B7aCsYqu.js} +3 -3
- package/dist/chunks/{laya-D8o5TEO7.js.map → laya-B7aCsYqu.js.map} +1 -1
- package/dist/chunks/{litellm-C4TKClkF.js → litellm-CV2uEz8Q.js} +4 -4
- package/dist/chunks/{litellm-C4TKClkF.js.map → litellm-CV2uEz8Q.js.map} +1 -1
- package/dist/chunks/{ollama-CuDjAyTy.js → ollama-pL2WCpkS.js} +11 -4
- package/dist/chunks/ollama-pL2WCpkS.js.map +1 -0
- package/dist/chunks/{openai-compat-video-ByTC2nzb.js → openai-compat-video-BoLwWXJM.js} +3 -3
- package/dist/chunks/{openai-compat-video-ByTC2nzb.js.map → openai-compat-video-BoLwWXJM.js.map} +1 -1
- package/dist/chunks/{qwen-tts-CWdO07D_.js → qwen-tts-BbGkn1oW.js} +2 -2
- package/dist/chunks/{qwen-tts-CWdO07D_.js.map → qwen-tts-BbGkn1oW.js.map} +1 -1
- package/dist/chunks/{rate-limit-Dwyde1BY.js → rate-limit-B3Kz6v4j.js} +2 -2
- package/dist/chunks/{rate-limit-Dwyde1BY.js.map → rate-limit-B3Kz6v4j.js.map} +1 -1
- package/dist/chunks/reasoning-DCCN0I3I.js +33 -0
- package/dist/chunks/reasoning-DCCN0I3I.js.map +1 -0
- package/dist/chunks/{seevio-B9V2nZtr.js → seevio-Dt8kWgpg.js} +3 -3
- package/dist/chunks/{seevio-B9V2nZtr.js.map → seevio-Dt8kWgpg.js.map} +1 -1
- package/dist/chunks/{src-ChaEcI7l.js → src-mOOK32QB.js} +275 -44
- package/dist/chunks/src-mOOK32QB.js.map +1 -0
- package/dist/chunks/{typesafe-B1_jGusy.js → typesafe-DDVSVUR_.js} +3 -3
- package/dist/chunks/{typesafe-B1_jGusy.js.map → typesafe-DDVSVUR_.js.map} +1 -1
- package/dist/chunks/{usage-DS7uDhi1.js → usage-yIT5lpQm.js} +37 -4
- package/dist/chunks/usage-yIT5lpQm.js.map +1 -0
- package/dist/chunks/{webllm-DVDsgVT7.js → webllm-DrwR5V-y.js} +2 -2
- package/dist/chunks/{webllm-DVDsgVT7.js.map → webllm-DrwR5V-y.js.map} +1 -1
- package/dist/index.js +2 -2
- package/dist/local.js +2 -2
- package/dist/node.js +3 -3
- package/dist/shared/chat-template-kwargs.d.ts +17 -0
- package/dist/shared/chat-template-kwargs.d.ts.map +1 -0
- package/dist/shared/continuation.d.ts.map +1 -1
- package/dist/shared/providers/connection-retry.d.ts +34 -0
- package/dist/shared/providers/connection-retry.d.ts.map +1 -0
- package/dist/shared/providers/ollama.d.ts.map +1 -1
- package/dist/shared/providers/openai.d.ts +21 -1
- package/dist/shared/providers/openai.d.ts.map +1 -1
- package/dist/shared/reasoning.d.ts +19 -0
- package/dist/shared/reasoning.d.ts.map +1 -0
- package/dist/shared/safety.d.ts +12 -0
- package/dist/shared/safety.d.ts.map +1 -1
- package/dist/shared/types.d.ts +81 -3
- package/dist/shared/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/chunks/continuation-BMGvMlzq.js.map +0 -1
- package/dist/chunks/ollama-CuDjAyTy.js.map +0 -1
- package/dist/chunks/src-ChaEcI7l.js.map +0 -1
- package/dist/chunks/usage-DS7uDhi1.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webllm-DVDsgVT7.js","names":[],"sources":["../../src/shared/providers/webllm.ts"],"sourcesContent":["// biome-ignore-all lint/style/useNamingConvention: WebLLM's OpenAI-shaped wire format and model records are snake_case.\n/**\n * WebLLM provider: runs a chat model entirely in the browser on WebGPU.\n *\n * Backed by `@mlc-ai/web-llm`, an optional peer dependency that is imported\n * lazily on first use, so neither the root entry nor `getAI()` for other\n * provider types ever loads it. Reachable through `getAI({ type: 'webllm' })`\n * and the `@happyvertical/ai/local` subpath.\n *\n * WebLLM's engine API is OpenAI-shaped, so requests and responses map almost\n * one to one. Structured output (`responseSchema`) becomes WebLLM's\n * grammar-constrained `response_format`, which keeps a small model from\n * emitting a value outside the schema.\n */\n\nimport {\n normalizeBaseAIOptions,\n normalizeChatOptions,\n type PreparedRequestControls,\n prepareRequestControls,\n} from '../safety';\nimport type {\n AICapabilities,\n AIInterface,\n AIMessage,\n AIModel,\n AIResponse,\n AIToolCall,\n ChatOptions,\n CompletionOptions,\n EmbeddingOptions,\n EmbeddingResponse,\n ImageDescriptionOptions,\n ImageEmbeddingOptions,\n ImageGenerationOptions,\n ImageGenerationResponse,\n MessageOptions,\n TokenUsage,\n TTSOptions,\n TTSResponse,\n VideoGenerationJob,\n VideoGenerationOptions,\n VideoGenerationResult,\n VideoGenerationStatusResult,\n Voice,\n VoiceCloneOptions,\n VoiceDesignOptions,\n VoiceListOptions,\n WebLLMEngineLike,\n WebLLMLoadProgress,\n WebLLMOptions,\n} from '../types';\nimport {\n AIError,\n ContextLengthError,\n extractTextContent,\n ModelNotFoundError,\n WebGPUUnavailableError,\n WebLLMPeerMissingError,\n} from '../types';\nimport { emitUsage } from './usage';\n\nconst PROVIDER = 'webllm';\n\n/** Small enough for most GPUs (about 0.9 GB of VRAM); override with `defaultModel`. */\nexport const DEFAULT_WEBLLM_MODEL = 'Llama-3.2-1B-Instruct-q4f16_1-MLC';\n\n/** Context window assumed when a model record does not declare one. */\nconst DEFAULT_CONTEXT_LENGTH = 4096;\n\nconst WEBLLM_CAPABILITIES: AICapabilities = {\n chat: true,\n completion: true,\n embeddings: false,\n streaming: true,\n functions: true,\n vision: false,\n fineTuning: false,\n imageEmbeddings: false,\n imageGeneration: false,\n videoGeneration: false,\n tts: false,\n voiceCloning: false,\n voiceDesign: false,\n maxContextLength: DEFAULT_CONTEXT_LENGTH,\n supportedOperations: ['chat', 'completion', 'streaming', 'functions'],\n};\n\n/** Structural subset of the `@mlc-ai/web-llm` module this provider uses. */\ninterface WebLLMModule {\n CreateMLCEngine(\n model: string,\n config?: {\n appConfig?: unknown;\n initProgressCallback?: (report: WebLLMLoadProgress) => void;\n },\n ): Promise<WebLLMEngineLike>;\n prebuiltAppConfig: { model_list: WebLLMModelRecord[] };\n functionCallingModelIds?: string[];\n}\n\ninterface WebLLMModelRecord {\n model_id: string;\n vram_required_MB?: number;\n low_resource_required?: boolean;\n /** WebLLM `ModelType`: 0 or absent = LLM, 1 = embedding, 2 = VLM. */\n model_type?: number;\n overrides?: { context_window_size?: number };\n}\n\ninterface EngineEntry {\n promise: Promise<WebLLMEngineLike>;\n listeners: Set<(report: WebLLMLoadProgress) => void>;\n}\n\n/**\n * Per-engine request queues. WebLLM runs one generation at a time per engine\n * and `interruptGenerate()` stops whichever one is running, so requests are\n * serialized here and only the running request may interrupt.\n */\nconst engineQueues = new WeakMap<object, Promise<void>>();\n\n/** Engines shared by every provider instance that uses the prebuilt model list. */\nconst sharedEngines = new Map<string, EngineEntry>();\n\n/**\n * Imports the optional peer. Isolated so a missing install becomes a typed\n * {@link WebLLMPeerMissingError} instead of a bare module-resolution failure.\n */\nexport async function importWebLLM(): Promise<WebLLMModule> {\n try {\n const loaded = (await import('@mlc-ai/web-llm')) as unknown as\n | (WebLLMModule & { default?: WebLLMModule })\n | undefined;\n const module =\n typeof loaded?.CreateMLCEngine === 'function' ? loaded : loaded?.default;\n if (typeof module?.CreateMLCEngine !== 'function') {\n throw new Error('@mlc-ai/web-llm did not export CreateMLCEngine');\n }\n return module;\n } catch (error) {\n throw new WebLLMPeerMissingError(error);\n }\n}\n\n/** True when this runtime exposes WebGPU (`navigator.gpu`). */\nexport function isWebGPUAvailable(): boolean {\n const nav = (globalThis as { navigator?: { gpu?: unknown } }).navigator;\n return Boolean(nav?.gpu);\n}\n\n/**\n * Unloads every engine this module created and forgets them. Caller-supplied\n * engines are never touched.\n */\nexport async function disposeWebLLMEngines(): Promise<void> {\n const entries = [...sharedEngines.values()];\n sharedEngines.clear();\n await Promise.allSettled(\n entries.map(async (entry) => (await entry.promise).unload?.()),\n );\n}\n\nfunction unsupported(feature: string): never {\n throw new AIError(\n `${feature} is not supported by the webllm provider.`,\n 'NOT_SUPPORTED',\n PROVIDER,\n );\n}\n\nfunction stripUndefined<T extends Record<string, unknown>>(value: T): T {\n return Object.fromEntries(\n Object.entries(value).filter(([, entry]) => entry !== undefined),\n ) as T;\n}\n\n/**\n * In-browser chat provider on WebLLM (WebGPU). See the module header.\n */\nexport class WebLLMProvider implements AIInterface {\n private options: WebLLMOptions;\n /** Model the caller named, if any; a supplied engine is loaded with it already. */\n private readonly explicitModel?: string;\n private factoryEngine?: Promise<WebLLMEngineLike>;\n private readonly localEngines = new Map<string, EngineEntry>();\n\n constructor(options: WebLLMOptions) {\n this.explicitModel = options.defaultModel ?? options.model;\n this.options = normalizeBaseAIOptions({\n ...options,\n defaultModel: this.explicitModel ?? DEFAULT_WEBLLM_MODEL,\n });\n }\n\n // --------------------------------------------------------------------------\n // Engine lifecycle\n // --------------------------------------------------------------------------\n\n private async acquireEngine(\n model: string,\n signal?: AbortSignal,\n ): Promise<WebLLMEngineLike> {\n const supplied = this.options.engine;\n if (supplied) {\n if (typeof supplied !== 'function') return supplied;\n this.factoryEngine ??= supplied().catch((error) => {\n this.factoryEngine = undefined;\n throw error;\n });\n return abortable(this.factoryEngine, signal);\n }\n\n if (!isWebGPUAvailable()) {\n throw new WebGPUUnavailableError(PROVIDER);\n }\n\n // A custom appConfig changes what a model id means, so it must not share\n // an engine with other callers.\n const cache = this.options.appConfig ? this.localEngines : sharedEngines;\n let entry = cache.get(model);\n if (!entry) {\n const listeners = new Set<(report: WebLLMLoadProgress) => void>();\n const created: EngineEntry = {\n listeners,\n promise: this.createEngine(model, listeners),\n };\n created.promise.catch(() => {\n if (cache.get(model) === created) cache.delete(model);\n });\n cache.set(model, created);\n entry = created;\n }\n\n const onProgress = this.options.onLoadProgress;\n if (onProgress) entry.listeners.add(onProgress);\n try {\n return await abortable(entry.promise, signal);\n } finally {\n if (onProgress) entry.listeners.delete(onProgress);\n }\n }\n\n private async createEngine(\n model: string,\n listeners: Set<(report: WebLLMLoadProgress) => void>,\n ): Promise<WebLLMEngineLike> {\n const webllm = await importWebLLM();\n return webllm.CreateMLCEngine(model, {\n ...(this.options.appConfig ? { appConfig: this.options.appConfig } : {}),\n initProgressCallback: (report) => {\n for (const listener of listeners) {\n try {\n listener(report);\n } catch {\n // A progress listener must never break model loading.\n }\n }\n },\n });\n }\n\n // --------------------------------------------------------------------------\n // Request / response mapping\n // --------------------------------------------------------------------------\n\n private mapMessages(messages: AIMessage[]): Record<string, unknown>[] {\n return messages.map((message) => {\n if (message.role === 'user' && Array.isArray(message.content)) {\n return {\n role: 'user',\n content: message.content.map((part) =>\n part.type === 'text'\n ? { type: 'text', text: part.text }\n : { type: 'image_url', image_url: { url: part.image_url.url } },\n ),\n ...(message.name ? { name: message.name } : {}),\n };\n }\n const content = extractTextContent(message.content);\n if (message.role === 'tool' || message.role === 'function') {\n return {\n role: 'tool',\n content,\n tool_call_id: message.tool_call_id ?? message.name ?? '',\n };\n }\n if (message.role === 'assistant') {\n return stripUndefined({\n role: 'assistant',\n content: content || (message.tool_calls?.length ? null : ''),\n tool_calls: message.tool_calls?.map((call) => ({\n id: call.id,\n type: call.type,\n function: {\n name: call.function.name,\n arguments: call.function.arguments,\n },\n })),\n });\n }\n return {\n role: message.role,\n content,\n ...(message.name ? { name: message.name } : {}),\n };\n });\n }\n\n private mapResponseFormat(\n options: Pick<ChatOptions, 'responseFormat' | 'responseSchema'>,\n ): Record<string, unknown> | undefined {\n if (options.responseSchema !== undefined) {\n const schema =\n typeof options.responseSchema === 'string'\n ? options.responseSchema\n : JSON.stringify(options.responseSchema);\n // WebLLM compiles the schema to a grammar and masks logits, so the\n // output cannot leave it.\n return { type: 'json_object', schema };\n }\n return options.responseFormat?.type === 'json_object'\n ? { type: 'json_object' }\n : undefined;\n }\n\n private buildRequest(\n messages: AIMessage[],\n options: ChatOptions & { maxTokens: number },\n model: string | undefined,\n stream: boolean,\n includeTools: boolean,\n ): Record<string, unknown> {\n const tools =\n includeTools && options.tools?.length\n ? options.tools.map((tool) => ({\n type: 'function' as const,\n function: {\n name: tool.function.name,\n description: tool.function.description,\n parameters: tool.function.parameters,\n },\n }))\n : undefined;\n return stripUndefined({\n model,\n messages: this.mapMessages(messages),\n max_tokens: options.maxTokens,\n temperature: options.temperature,\n top_p: options.topP,\n n: options.n,\n stop: options.stop,\n frequency_penalty: options.frequencyPenalty,\n presence_penalty: options.presencePenalty,\n seed: options.seed,\n tools,\n tool_choice: tools ? options.toolChoice : undefined,\n response_format: this.mapResponseFormat(options),\n stream,\n stream_options: stream ? { include_usage: true } : undefined,\n });\n }\n\n /** Model id to send. A caller-supplied engine already has its model loaded. */\n private requestModel(\n model: string,\n options: ChatOptions,\n ): string | undefined {\n if (!this.options.engine) return model;\n return options.model ?? this.explicitModel;\n }\n\n private mapUsage(usage: unknown): TokenUsage | undefined {\n const raw = usage as\n | {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n }\n | undefined\n | null;\n if (!raw) return undefined;\n return {\n promptTokens: raw.prompt_tokens ?? 0,\n completionTokens: raw.completion_tokens ?? 0,\n totalTokens: raw.total_tokens ?? 0,\n };\n }\n\n private mapFinishReason(reason: string | null | undefined) {\n switch (reason) {\n case 'length':\n return 'length' as const;\n case 'tool_calls':\n return 'tool_calls' as const;\n default:\n return 'stop' as const;\n }\n }\n\n /**\n * WebLLM reports `abort` when generation was interrupted. The provider's own\n * aborts are raised before this point, so reaching it means someone else\n * interrupted the engine (for example a caller sharing a supplied engine);\n * a truncated reply must not look like a normal stop.\n */\n private assertNotInterrupted(\n reason: string | null | undefined,\n model: string,\n ): void {\n if (reason === 'abort') {\n throw new AIError(\n 'Generation was interrupted before it finished',\n 'AI_INTERRUPTED',\n PROVIDER,\n model,\n true,\n );\n }\n }\n\n private mapError(error: unknown, model?: string): AIError {\n if (error instanceof AIError) return error;\n const name = (error as { name?: string } | undefined)?.name ?? '';\n const message = error instanceof Error ? error.message : String(error);\n if (name === 'WebGPUNotAvailableError' || name === 'WebGPUNotFoundError') {\n return new WebGPUUnavailableError(PROVIDER, message);\n }\n if (\n name === 'ContextWindowSizeExceededError' ||\n name === 'PrefillChunkSizeSmallerThanImageError'\n ) {\n return new ContextLengthError(PROVIDER, model);\n }\n if (\n name === 'ModelNotFoundError' ||\n name === 'SpecifiedModelNotFoundError' ||\n name === 'UnsupportedModelIdError' ||\n name === 'ModelNotLoadedError'\n ) {\n return new ModelNotFoundError(model ?? message, PROVIDER);\n }\n const mapped = new AIError(\n message,\n name === 'DeviceLostError' ? 'WEBGPU_DEVICE_LOST' : 'API_ERROR',\n PROVIDER,\n model,\n );\n mapped.cause = error;\n return mapped;\n }\n\n /** Throws the right AI error when the request ended by timeout or caller abort. */\n private abortError(\n controls: PreparedRequestControls | undefined,\n options: ChatOptions,\n model?: string,\n ): AIError | undefined {\n if (controls?.didTimeout()) {\n return new AIError(\n `AI request timed out after ${controls.timeout}ms`,\n 'AI_TIMEOUT',\n PROVIDER,\n model,\n );\n }\n if (options.signal?.aborted) {\n return new AIError(\n 'AI request aborted by caller',\n 'AI_ABORTED',\n PROVIDER,\n model,\n );\n }\n return undefined;\n }\n\n /**\n * Waits for this request's turn on the engine; resolves to a release fn. A\n * queued request that is aborted or times out leaves the queue at once and\n * never interrupts the generation ahead of it.\n */\n private async lockEngine(\n engine: WebLLMEngineLike,\n signal: AbortSignal,\n ): Promise<() => void> {\n const previous = engineQueues.get(engine) ?? Promise.resolve();\n let release: () => void = () => {};\n const mine = new Promise<void>((resolve) => {\n release = resolve;\n });\n engineQueues.set(\n engine,\n previous.then(() => mine),\n );\n try {\n await abortable(previous, signal);\n } catch (error) {\n release();\n throw error;\n }\n return release;\n }\n\n /** Interrupts generation when the composed signal fires; returns a detach fn. */\n private bindInterrupt(\n engine: WebLLMEngineLike,\n signal: AbortSignal,\n ): () => void {\n const interrupt = () => {\n try {\n void Promise.resolve(engine.interruptGenerate()).catch(() => {});\n } catch {\n // Best effort: the request is already being abandoned.\n }\n };\n if (signal.aborted) interrupt();\n signal.addEventListener('abort', interrupt, { once: true });\n return () => signal.removeEventListener('abort', interrupt);\n }\n\n // --------------------------------------------------------------------------\n // Chat\n // --------------------------------------------------------------------------\n\n async chat(\n messages: AIMessage[],\n options: ChatOptions = {},\n ): Promise<AIResponse> {\n const startTime = Date.now();\n let controls: PreparedRequestControls | undefined;\n let detach: (() => void) | undefined;\n let release: (() => void) | undefined;\n let pending: Promise<any> | undefined;\n let holdRelease: (() => Promise<unknown> | undefined) | undefined;\n const model =\n options.model || this.options.defaultModel || DEFAULT_WEBLLM_MODEL;\n try {\n options = normalizeChatOptions(this.options, options, PROVIDER, model);\n // Load before arming the request timeout: a multi-GB download must not\n // consume the generation budget.\n const engine = await this.acquireEngine(model, options.signal);\n controls = prepareRequestControls(this.options, options);\n release = await this.lockEngine(engine, controls.signal);\n detach = this.bindInterrupt(engine, controls.signal);\n\n pending = engine.chat.completions.create(\n this.buildRequest(\n messages,\n options as ChatOptions & { maxTokens: number },\n this.requestModel(model, options),\n false,\n true,\n ),\n );\n const started: Promise<unknown> = pending;\n let settled = false;\n const markSettled = () => {\n settled = true;\n };\n started.then(markSettled, markSettled);\n holdRelease = () => (settled ? undefined : started);\n const response = await abortable(pending, controls.signal);\n if (controls.signal.aborted) {\n throw (\n this.abortError(controls, options, model) ?? controls.signal.reason\n );\n }\n\n const choice = response?.choices?.[0];\n this.assertNotInterrupted(choice?.finish_reason, model);\n if (!choice) {\n throw new AIError(\n 'No choices returned from webllm',\n 'NO_CHOICES',\n PROVIDER,\n );\n }\n const usage = this.mapUsage(response.usage);\n emitUsage(\n this.options,\n PROVIDER,\n 'chat',\n response.model || model,\n usage,\n startTime,\n options.usageTags,\n );\n const toolCalls: AIToolCall[] | undefined =\n choice.message?.tool_calls?.map(\n (call: {\n id: string;\n function: { name: string; arguments: string };\n }) => ({\n id: call.id,\n type: 'function' as const,\n function: {\n name: call.function.name,\n arguments: call.function.arguments,\n },\n }),\n );\n return {\n content: choice.message?.content || '',\n usage,\n model: response.model || model,\n finishReason: this.mapFinishReason(choice.finish_reason),\n ...(toolCalls?.length ? { toolCalls } : {}),\n };\n } catch (error) {\n throw (\n this.abortError(controls, options, model) ?? this.mapError(error, model)\n );\n } finally {\n detach?.();\n releaseWhenIdle(release, holdRelease?.());\n controls?.cleanup();\n }\n }\n\n async complete(\n prompt: string,\n options: CompletionOptions = {},\n ): Promise<AIResponse> {\n return this.chat([{ role: 'user', content: prompt }], {\n model: options.model,\n maxTokens: options.maxTokens,\n temperature: options.temperature,\n topP: options.topP,\n n: options.n,\n stop: options.stop,\n stream: options.stream,\n onProgress: options.onProgress,\n signal: options.signal,\n timeout: options.timeout,\n reasoning: options.reasoning,\n usageTags: options.usageTags,\n continueOnLength: options.continueOnLength,\n });\n }\n\n async message(text: string, options: MessageOptions = {}): Promise<string> {\n const messages: AIMessage[] = [\n ...(options.history || []),\n { role: options.role || 'user', content: text },\n ];\n const response = await this.chat(messages, {\n model: options.model,\n maxTokens: options.maxTokens,\n temperature: options.temperature,\n topP: options.topP,\n stop: options.stop,\n stream: options.stream,\n frequencyPenalty: options.frequencyPenalty,\n presencePenalty: options.presencePenalty,\n responseFormat: options.responseFormat,\n responseSchema: options.responseSchema,\n seed: options.seed,\n tools: options.tools,\n toolChoice: options.toolChoice,\n onProgress: options.onProgress,\n signal: options.signal,\n timeout: options.timeout,\n reasoning: options.reasoning,\n usageTags: options.usageTags,\n continueOnLength: options.continueOnLength,\n });\n return response.content;\n }\n\n /**\n * Streams a chat completion as text chunks. Like the other providers, a\n * stream yields text only; use `chat()` for rounds that may call tools.\n * Breaking out of the loop interrupts generation on the engine.\n */\n async *stream(\n messages: AIMessage[],\n options: ChatOptions = {},\n ): AsyncIterable<string> {\n const startTime = Date.now();\n let controls: PreparedRequestControls | undefined;\n let detach: (() => void) | undefined;\n let engine: WebLLMEngineLike | undefined;\n let release: (() => void) | undefined;\n let iterator: AsyncIterator<WebLLMChunk> | undefined;\n let iteratorDone = false;\n let holdRelease: Promise<unknown> | undefined;\n const model =\n options.model || this.options.defaultModel || DEFAULT_WEBLLM_MODEL;\n try {\n options = normalizeChatOptions(this.options, options, PROVIDER, model);\n engine = await this.acquireEngine(model, options.signal);\n controls = prepareRequestControls(this.options, options);\n release = await this.lockEngine(engine, controls.signal);\n detach = this.bindInterrupt(engine, controls.signal);\n\n const pending: Promise<AsyncIterable<WebLLMChunk>> =\n engine.chat.completions.create(\n this.buildRequest(\n messages,\n options as ChatOptions & { maxTokens: number },\n this.requestModel(model, options),\n true,\n false,\n ),\n );\n let chunks: AsyncIterable<WebLLMChunk>;\n try {\n chunks = await abortable(pending, controls.signal);\n } catch (error) {\n // The caller is gone but the engine may still start this request.\n // Keep our queue closed until it has been interrupted and drained, or\n // the next request would wait behind it and could interrupt it.\n holdRelease = pending.then(\n (late) => abandonStream(late[Symbol.asyncIterator](), engine),\n () => {},\n );\n throw error;\n }\n // Iterated by hand: WebLLM releases its per-model lock only when its\n // generator runs to completion, never on an early `return()`.\n iterator = chunks[Symbol.asyncIterator]();\n\n let finishReason: string | null | undefined;\n let usage: TokenUsage | undefined;\n for (;;) {\n const step = await iterator.next();\n if (step.done) {\n iteratorDone = true;\n break;\n }\n const chunk = step.value;\n const choice = chunk.choices?.[0];\n finishReason = choice?.finish_reason ?? finishReason;\n if (chunk.usage) usage = this.mapUsage(chunk.usage);\n const content = choice?.delta?.content;\n if (content) {\n options.onProgress?.(content);\n yield content;\n }\n }\n if (controls.signal.aborted) {\n throw (\n this.abortError(controls, options, model) ?? controls.signal.reason\n );\n }\n this.assertNotInterrupted(finishReason, model);\n options.onFinishReason?.(this.mapFinishReason(finishReason));\n emitUsage(\n this.options,\n PROVIDER,\n 'stream',\n model,\n usage,\n startTime,\n options.usageTags,\n );\n } catch (error) {\n throw (\n this.abortError(controls, options, model) ?? this.mapError(error, model)\n );\n } finally {\n if (iterator && !iteratorDone && engine) {\n // Consumer stopped early (or the loop threw): stop the GPU, then let\n // the engine's generator finish so its lock is released before the\n // next request is admitted.\n try {\n void Promise.resolve(engine.interruptGenerate()).catch(() => {});\n } catch {\n // Best effort.\n }\n await drainIterator(iterator);\n }\n detach?.();\n releaseWhenIdle(release, holdRelease);\n controls?.cleanup();\n }\n }\n\n async countTokens(text: string): Promise<number> {\n // WebLLM exposes no standalone tokenizer; ~4 characters per token.\n return Math.ceil(text.length / 4);\n }\n\n // --------------------------------------------------------------------------\n // Models and capabilities\n // --------------------------------------------------------------------------\n\n async getModels(): Promise<AIModel[]> {\n const webllm = await importWebLLM();\n const list =\n (\n this.options.appConfig as\n | { model_list?: WebLLMModelRecord[] }\n | undefined\n )?.model_list ?? webllm.prebuiltAppConfig.model_list;\n const functionCalling = new Set(webllm.functionCallingModelIds ?? []);\n return list\n .filter((record) => record.model_type !== 1) // embedding models\n .map((record) => {\n const vision = record.model_type === 2;\n const functions = functionCalling.has(record.model_id);\n return {\n id: record.model_id,\n name: record.model_id,\n description: record.vram_required_MB\n ? `Runs on-device via WebGPU (~${Math.round(record.vram_required_MB)} MB VRAM)`\n : 'Runs on-device via WebGPU',\n contextLength:\n record.overrides?.context_window_size ?? DEFAULT_CONTEXT_LENGTH,\n capabilities: [\n 'text',\n 'chat',\n ...(functions ? ['functions'] : []),\n ...(vision ? ['vision'] : []),\n ],\n supportsFunctions: functions,\n supportsVision: vision,\n };\n });\n }\n\n async getCapabilities(): Promise<AICapabilities> {\n return { ...WEBLLM_CAPABILITIES };\n }\n\n // --------------------------------------------------------------------------\n // No in-browser equivalent\n // --------------------------------------------------------------------------\n\n async embed(\n _text: string | string[],\n _options: EmbeddingOptions = {},\n ): Promise<EmbeddingResponse> {\n return unsupported('Embeddings');\n }\n\n async embedImage(\n _image: string | Buffer,\n _options: ImageEmbeddingOptions = {},\n ): Promise<EmbeddingResponse> {\n return unsupported('Image embeddings');\n }\n\n async describeImage(\n _image: string | Buffer,\n _prompt?: string,\n _options: ImageDescriptionOptions = {},\n ): Promise<string> {\n return unsupported('Image description');\n }\n\n async generateImage(\n _prompt: string,\n _options: ImageGenerationOptions = {},\n ): Promise<ImageGenerationResponse> {\n return unsupported('Image generation');\n }\n\n async submitVideoGenerationJob(\n _options: VideoGenerationOptions,\n ): Promise<VideoGenerationJob> {\n return unsupported('Video generation');\n }\n\n async getVideoGenerationJob(\n _handle: VideoGenerationJob,\n ): Promise<VideoGenerationStatusResult> {\n return unsupported('Video generation');\n }\n\n async fetchVideoGenerationResult(\n _handle: VideoGenerationJob,\n ): Promise<VideoGenerationResult> {\n return unsupported('Video generation');\n }\n\n async cancelVideoGenerationJob(_handle: VideoGenerationJob): Promise<void> {\n return unsupported('Video generation');\n }\n\n async validateVideoGenerationAccess(): Promise<boolean> {\n return unsupported('Video generation');\n }\n\n async synthesizeSpeech(\n _text: string,\n _options?: TTSOptions,\n ): Promise<TTSResponse> {\n return unsupported('Text-to-speech');\n }\n\n streamSpeech(_text: string, _options?: TTSOptions): AsyncIterable<Buffer> {\n const error = new AIError(\n 'Text-to-speech streaming is not supported by the webllm provider.',\n 'NOT_SUPPORTED',\n PROVIDER,\n );\n return {\n [Symbol.asyncIterator]: () => ({\n next: () => Promise.reject(error),\n }),\n };\n }\n\n async cloneVoice(_options: VoiceCloneOptions): Promise<Voice> {\n return unsupported('Voice cloning');\n }\n\n async designVoice(_options: VoiceDesignOptions): Promise<Voice> {\n return unsupported('Voice design');\n }\n\n async getVoices(_options?: VoiceListOptions): Promise<Voice[]> {\n return unsupported('Voice listing');\n }\n}\n\n/** One streamed WebLLM chunk (structural subset). */\ninterface WebLLMChunk {\n choices?: Array<{\n delta?: { content?: string | null };\n finish_reason?: string | null;\n }>;\n usage?: unknown;\n}\n\n/** Runs a WebLLM stream to its end, ignoring errors; used after interrupting it. */\nasync function drainIterator(\n iterator: AsyncIterator<WebLLMChunk>,\n): Promise<void> {\n try {\n while (!(await iterator.next()).done) {\n // discard\n }\n } catch {\n // The engine already stopped; nothing more to release.\n }\n}\n\n/** Releases an engine queue slot now, or once `idle` has settled. */\nfunction releaseWhenIdle(\n release: (() => void) | undefined,\n idle?: Promise<unknown>,\n): void {\n if (!release) return;\n if (idle) void idle.then(release, release);\n else release();\n}\n\n/**\n * Finishes a stream nobody is reading. WebLLM resets its interrupt flag on the\n * first `next()`, so interrupt only after pulling one chunk, then drain it so\n * the engine's lock is released.\n */\nasync function abandonStream(\n iterator: AsyncIterator<WebLLMChunk>,\n engine: WebLLMEngineLike | undefined,\n): Promise<void> {\n try {\n if ((await iterator.next()).done) return;\n await Promise.resolve(engine?.interruptGenerate());\n } catch {\n return;\n }\n await drainIterator(iterator);\n}\n\n/** Rejects with the signal's reason if it fires first; the underlying work continues. */\nfunction abortable<T>(promise: Promise<T>, signal?: AbortSignal): Promise<T> {\n if (!signal) return promise;\n if (signal.aborted) {\n return Promise.reject(\n new AIError('AI request aborted by caller', 'AI_ABORTED', PROVIDER),\n );\n }\n return new Promise<T>((resolve, reject) => {\n const onAbort = () =>\n reject(\n new AIError('AI request aborted by caller', 'AI_ABORTED', PROVIDER),\n );\n signal.addEventListener('abort', onAbort, { once: true });\n promise.then(\n (value) => {\n signal.removeEventListener('abort', onAbort);\n resolve(value);\n },\n (error) => {\n signal.removeEventListener('abort', onAbort);\n reject(error);\n },\n );\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"webllm-DrwR5V-y.js","names":[],"sources":["../../src/shared/providers/webllm.ts"],"sourcesContent":["// biome-ignore-all lint/style/useNamingConvention: WebLLM's OpenAI-shaped wire format and model records are snake_case.\n/**\n * WebLLM provider: runs a chat model entirely in the browser on WebGPU.\n *\n * Backed by `@mlc-ai/web-llm`, an optional peer dependency that is imported\n * lazily on first use, so neither the root entry nor `getAI()` for other\n * provider types ever loads it. Reachable through `getAI({ type: 'webllm' })`\n * and the `@happyvertical/ai/local` subpath.\n *\n * WebLLM's engine API is OpenAI-shaped, so requests and responses map almost\n * one to one. Structured output (`responseSchema`) becomes WebLLM's\n * grammar-constrained `response_format`, which keeps a small model from\n * emitting a value outside the schema.\n */\n\nimport {\n normalizeBaseAIOptions,\n normalizeChatOptions,\n type PreparedRequestControls,\n prepareRequestControls,\n} from '../safety';\nimport type {\n AICapabilities,\n AIInterface,\n AIMessage,\n AIModel,\n AIResponse,\n AIToolCall,\n ChatOptions,\n CompletionOptions,\n EmbeddingOptions,\n EmbeddingResponse,\n ImageDescriptionOptions,\n ImageEmbeddingOptions,\n ImageGenerationOptions,\n ImageGenerationResponse,\n MessageOptions,\n TokenUsage,\n TTSOptions,\n TTSResponse,\n VideoGenerationJob,\n VideoGenerationOptions,\n VideoGenerationResult,\n VideoGenerationStatusResult,\n Voice,\n VoiceCloneOptions,\n VoiceDesignOptions,\n VoiceListOptions,\n WebLLMEngineLike,\n WebLLMLoadProgress,\n WebLLMOptions,\n} from '../types';\nimport {\n AIError,\n ContextLengthError,\n extractTextContent,\n ModelNotFoundError,\n WebGPUUnavailableError,\n WebLLMPeerMissingError,\n} from '../types';\nimport { emitUsage } from './usage';\n\nconst PROVIDER = 'webllm';\n\n/** Small enough for most GPUs (about 0.9 GB of VRAM); override with `defaultModel`. */\nexport const DEFAULT_WEBLLM_MODEL = 'Llama-3.2-1B-Instruct-q4f16_1-MLC';\n\n/** Context window assumed when a model record does not declare one. */\nconst DEFAULT_CONTEXT_LENGTH = 4096;\n\nconst WEBLLM_CAPABILITIES: AICapabilities = {\n chat: true,\n completion: true,\n embeddings: false,\n streaming: true,\n functions: true,\n vision: false,\n fineTuning: false,\n imageEmbeddings: false,\n imageGeneration: false,\n videoGeneration: false,\n tts: false,\n voiceCloning: false,\n voiceDesign: false,\n maxContextLength: DEFAULT_CONTEXT_LENGTH,\n supportedOperations: ['chat', 'completion', 'streaming', 'functions'],\n};\n\n/** Structural subset of the `@mlc-ai/web-llm` module this provider uses. */\ninterface WebLLMModule {\n CreateMLCEngine(\n model: string,\n config?: {\n appConfig?: unknown;\n initProgressCallback?: (report: WebLLMLoadProgress) => void;\n },\n ): Promise<WebLLMEngineLike>;\n prebuiltAppConfig: { model_list: WebLLMModelRecord[] };\n functionCallingModelIds?: string[];\n}\n\ninterface WebLLMModelRecord {\n model_id: string;\n vram_required_MB?: number;\n low_resource_required?: boolean;\n /** WebLLM `ModelType`: 0 or absent = LLM, 1 = embedding, 2 = VLM. */\n model_type?: number;\n overrides?: { context_window_size?: number };\n}\n\ninterface EngineEntry {\n promise: Promise<WebLLMEngineLike>;\n listeners: Set<(report: WebLLMLoadProgress) => void>;\n}\n\n/**\n * Per-engine request queues. WebLLM runs one generation at a time per engine\n * and `interruptGenerate()` stops whichever one is running, so requests are\n * serialized here and only the running request may interrupt.\n */\nconst engineQueues = new WeakMap<object, Promise<void>>();\n\n/** Engines shared by every provider instance that uses the prebuilt model list. */\nconst sharedEngines = new Map<string, EngineEntry>();\n\n/**\n * Imports the optional peer. Isolated so a missing install becomes a typed\n * {@link WebLLMPeerMissingError} instead of a bare module-resolution failure.\n */\nexport async function importWebLLM(): Promise<WebLLMModule> {\n try {\n const loaded = (await import('@mlc-ai/web-llm')) as unknown as\n | (WebLLMModule & { default?: WebLLMModule })\n | undefined;\n const module =\n typeof loaded?.CreateMLCEngine === 'function' ? loaded : loaded?.default;\n if (typeof module?.CreateMLCEngine !== 'function') {\n throw new Error('@mlc-ai/web-llm did not export CreateMLCEngine');\n }\n return module;\n } catch (error) {\n throw new WebLLMPeerMissingError(error);\n }\n}\n\n/** True when this runtime exposes WebGPU (`navigator.gpu`). */\nexport function isWebGPUAvailable(): boolean {\n const nav = (globalThis as { navigator?: { gpu?: unknown } }).navigator;\n return Boolean(nav?.gpu);\n}\n\n/**\n * Unloads every engine this module created and forgets them. Caller-supplied\n * engines are never touched.\n */\nexport async function disposeWebLLMEngines(): Promise<void> {\n const entries = [...sharedEngines.values()];\n sharedEngines.clear();\n await Promise.allSettled(\n entries.map(async (entry) => (await entry.promise).unload?.()),\n );\n}\n\nfunction unsupported(feature: string): never {\n throw new AIError(\n `${feature} is not supported by the webllm provider.`,\n 'NOT_SUPPORTED',\n PROVIDER,\n );\n}\n\nfunction stripUndefined<T extends Record<string, unknown>>(value: T): T {\n return Object.fromEntries(\n Object.entries(value).filter(([, entry]) => entry !== undefined),\n ) as T;\n}\n\n/**\n * In-browser chat provider on WebLLM (WebGPU). See the module header.\n */\nexport class WebLLMProvider implements AIInterface {\n private options: WebLLMOptions;\n /** Model the caller named, if any; a supplied engine is loaded with it already. */\n private readonly explicitModel?: string;\n private factoryEngine?: Promise<WebLLMEngineLike>;\n private readonly localEngines = new Map<string, EngineEntry>();\n\n constructor(options: WebLLMOptions) {\n this.explicitModel = options.defaultModel ?? options.model;\n this.options = normalizeBaseAIOptions({\n ...options,\n defaultModel: this.explicitModel ?? DEFAULT_WEBLLM_MODEL,\n });\n }\n\n // --------------------------------------------------------------------------\n // Engine lifecycle\n // --------------------------------------------------------------------------\n\n private async acquireEngine(\n model: string,\n signal?: AbortSignal,\n ): Promise<WebLLMEngineLike> {\n const supplied = this.options.engine;\n if (supplied) {\n if (typeof supplied !== 'function') return supplied;\n this.factoryEngine ??= supplied().catch((error) => {\n this.factoryEngine = undefined;\n throw error;\n });\n return abortable(this.factoryEngine, signal);\n }\n\n if (!isWebGPUAvailable()) {\n throw new WebGPUUnavailableError(PROVIDER);\n }\n\n // A custom appConfig changes what a model id means, so it must not share\n // an engine with other callers.\n const cache = this.options.appConfig ? this.localEngines : sharedEngines;\n let entry = cache.get(model);\n if (!entry) {\n const listeners = new Set<(report: WebLLMLoadProgress) => void>();\n const created: EngineEntry = {\n listeners,\n promise: this.createEngine(model, listeners),\n };\n created.promise.catch(() => {\n if (cache.get(model) === created) cache.delete(model);\n });\n cache.set(model, created);\n entry = created;\n }\n\n const onProgress = this.options.onLoadProgress;\n if (onProgress) entry.listeners.add(onProgress);\n try {\n return await abortable(entry.promise, signal);\n } finally {\n if (onProgress) entry.listeners.delete(onProgress);\n }\n }\n\n private async createEngine(\n model: string,\n listeners: Set<(report: WebLLMLoadProgress) => void>,\n ): Promise<WebLLMEngineLike> {\n const webllm = await importWebLLM();\n return webllm.CreateMLCEngine(model, {\n ...(this.options.appConfig ? { appConfig: this.options.appConfig } : {}),\n initProgressCallback: (report) => {\n for (const listener of listeners) {\n try {\n listener(report);\n } catch {\n // A progress listener must never break model loading.\n }\n }\n },\n });\n }\n\n // --------------------------------------------------------------------------\n // Request / response mapping\n // --------------------------------------------------------------------------\n\n private mapMessages(messages: AIMessage[]): Record<string, unknown>[] {\n return messages.map((message) => {\n if (message.role === 'user' && Array.isArray(message.content)) {\n return {\n role: 'user',\n content: message.content.map((part) =>\n part.type === 'text'\n ? { type: 'text', text: part.text }\n : { type: 'image_url', image_url: { url: part.image_url.url } },\n ),\n ...(message.name ? { name: message.name } : {}),\n };\n }\n const content = extractTextContent(message.content);\n if (message.role === 'tool' || message.role === 'function') {\n return {\n role: 'tool',\n content,\n tool_call_id: message.tool_call_id ?? message.name ?? '',\n };\n }\n if (message.role === 'assistant') {\n return stripUndefined({\n role: 'assistant',\n content: content || (message.tool_calls?.length ? null : ''),\n tool_calls: message.tool_calls?.map((call) => ({\n id: call.id,\n type: call.type,\n function: {\n name: call.function.name,\n arguments: call.function.arguments,\n },\n })),\n });\n }\n return {\n role: message.role,\n content,\n ...(message.name ? { name: message.name } : {}),\n };\n });\n }\n\n private mapResponseFormat(\n options: Pick<ChatOptions, 'responseFormat' | 'responseSchema'>,\n ): Record<string, unknown> | undefined {\n if (options.responseSchema !== undefined) {\n const schema =\n typeof options.responseSchema === 'string'\n ? options.responseSchema\n : JSON.stringify(options.responseSchema);\n // WebLLM compiles the schema to a grammar and masks logits, so the\n // output cannot leave it.\n return { type: 'json_object', schema };\n }\n return options.responseFormat?.type === 'json_object'\n ? { type: 'json_object' }\n : undefined;\n }\n\n private buildRequest(\n messages: AIMessage[],\n options: ChatOptions & { maxTokens: number },\n model: string | undefined,\n stream: boolean,\n includeTools: boolean,\n ): Record<string, unknown> {\n const tools =\n includeTools && options.tools?.length\n ? options.tools.map((tool) => ({\n type: 'function' as const,\n function: {\n name: tool.function.name,\n description: tool.function.description,\n parameters: tool.function.parameters,\n },\n }))\n : undefined;\n return stripUndefined({\n model,\n messages: this.mapMessages(messages),\n max_tokens: options.maxTokens,\n temperature: options.temperature,\n top_p: options.topP,\n n: options.n,\n stop: options.stop,\n frequency_penalty: options.frequencyPenalty,\n presence_penalty: options.presencePenalty,\n seed: options.seed,\n tools,\n tool_choice: tools ? options.toolChoice : undefined,\n response_format: this.mapResponseFormat(options),\n stream,\n stream_options: stream ? { include_usage: true } : undefined,\n });\n }\n\n /** Model id to send. A caller-supplied engine already has its model loaded. */\n private requestModel(\n model: string,\n options: ChatOptions,\n ): string | undefined {\n if (!this.options.engine) return model;\n return options.model ?? this.explicitModel;\n }\n\n private mapUsage(usage: unknown): TokenUsage | undefined {\n const raw = usage as\n | {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n }\n | undefined\n | null;\n if (!raw) return undefined;\n return {\n promptTokens: raw.prompt_tokens ?? 0,\n completionTokens: raw.completion_tokens ?? 0,\n totalTokens: raw.total_tokens ?? 0,\n };\n }\n\n private mapFinishReason(reason: string | null | undefined) {\n switch (reason) {\n case 'length':\n return 'length' as const;\n case 'tool_calls':\n return 'tool_calls' as const;\n default:\n return 'stop' as const;\n }\n }\n\n /**\n * WebLLM reports `abort` when generation was interrupted. The provider's own\n * aborts are raised before this point, so reaching it means someone else\n * interrupted the engine (for example a caller sharing a supplied engine);\n * a truncated reply must not look like a normal stop.\n */\n private assertNotInterrupted(\n reason: string | null | undefined,\n model: string,\n ): void {\n if (reason === 'abort') {\n throw new AIError(\n 'Generation was interrupted before it finished',\n 'AI_INTERRUPTED',\n PROVIDER,\n model,\n true,\n );\n }\n }\n\n private mapError(error: unknown, model?: string): AIError {\n if (error instanceof AIError) return error;\n const name = (error as { name?: string } | undefined)?.name ?? '';\n const message = error instanceof Error ? error.message : String(error);\n if (name === 'WebGPUNotAvailableError' || name === 'WebGPUNotFoundError') {\n return new WebGPUUnavailableError(PROVIDER, message);\n }\n if (\n name === 'ContextWindowSizeExceededError' ||\n name === 'PrefillChunkSizeSmallerThanImageError'\n ) {\n return new ContextLengthError(PROVIDER, model);\n }\n if (\n name === 'ModelNotFoundError' ||\n name === 'SpecifiedModelNotFoundError' ||\n name === 'UnsupportedModelIdError' ||\n name === 'ModelNotLoadedError'\n ) {\n return new ModelNotFoundError(model ?? message, PROVIDER);\n }\n const mapped = new AIError(\n message,\n name === 'DeviceLostError' ? 'WEBGPU_DEVICE_LOST' : 'API_ERROR',\n PROVIDER,\n model,\n );\n mapped.cause = error;\n return mapped;\n }\n\n /** Throws the right AI error when the request ended by timeout or caller abort. */\n private abortError(\n controls: PreparedRequestControls | undefined,\n options: ChatOptions,\n model?: string,\n ): AIError | undefined {\n if (controls?.didTimeout()) {\n return new AIError(\n `AI request timed out after ${controls.timeout}ms`,\n 'AI_TIMEOUT',\n PROVIDER,\n model,\n );\n }\n if (options.signal?.aborted) {\n return new AIError(\n 'AI request aborted by caller',\n 'AI_ABORTED',\n PROVIDER,\n model,\n );\n }\n return undefined;\n }\n\n /**\n * Waits for this request's turn on the engine; resolves to a release fn. A\n * queued request that is aborted or times out leaves the queue at once and\n * never interrupts the generation ahead of it.\n */\n private async lockEngine(\n engine: WebLLMEngineLike,\n signal: AbortSignal,\n ): Promise<() => void> {\n const previous = engineQueues.get(engine) ?? Promise.resolve();\n let release: () => void = () => {};\n const mine = new Promise<void>((resolve) => {\n release = resolve;\n });\n engineQueues.set(\n engine,\n previous.then(() => mine),\n );\n try {\n await abortable(previous, signal);\n } catch (error) {\n release();\n throw error;\n }\n return release;\n }\n\n /** Interrupts generation when the composed signal fires; returns a detach fn. */\n private bindInterrupt(\n engine: WebLLMEngineLike,\n signal: AbortSignal,\n ): () => void {\n const interrupt = () => {\n try {\n void Promise.resolve(engine.interruptGenerate()).catch(() => {});\n } catch {\n // Best effort: the request is already being abandoned.\n }\n };\n if (signal.aborted) interrupt();\n signal.addEventListener('abort', interrupt, { once: true });\n return () => signal.removeEventListener('abort', interrupt);\n }\n\n // --------------------------------------------------------------------------\n // Chat\n // --------------------------------------------------------------------------\n\n async chat(\n messages: AIMessage[],\n options: ChatOptions = {},\n ): Promise<AIResponse> {\n const startTime = Date.now();\n let controls: PreparedRequestControls | undefined;\n let detach: (() => void) | undefined;\n let release: (() => void) | undefined;\n let pending: Promise<any> | undefined;\n let holdRelease: (() => Promise<unknown> | undefined) | undefined;\n const model =\n options.model || this.options.defaultModel || DEFAULT_WEBLLM_MODEL;\n try {\n options = normalizeChatOptions(this.options, options, PROVIDER, model);\n // Load before arming the request timeout: a multi-GB download must not\n // consume the generation budget.\n const engine = await this.acquireEngine(model, options.signal);\n controls = prepareRequestControls(this.options, options);\n release = await this.lockEngine(engine, controls.signal);\n detach = this.bindInterrupt(engine, controls.signal);\n\n pending = engine.chat.completions.create(\n this.buildRequest(\n messages,\n options as ChatOptions & { maxTokens: number },\n this.requestModel(model, options),\n false,\n true,\n ),\n );\n const started: Promise<unknown> = pending;\n let settled = false;\n const markSettled = () => {\n settled = true;\n };\n started.then(markSettled, markSettled);\n holdRelease = () => (settled ? undefined : started);\n const response = await abortable(pending, controls.signal);\n if (controls.signal.aborted) {\n throw (\n this.abortError(controls, options, model) ?? controls.signal.reason\n );\n }\n\n const choice = response?.choices?.[0];\n this.assertNotInterrupted(choice?.finish_reason, model);\n if (!choice) {\n throw new AIError(\n 'No choices returned from webllm',\n 'NO_CHOICES',\n PROVIDER,\n );\n }\n const usage = this.mapUsage(response.usage);\n emitUsage(\n this.options,\n PROVIDER,\n 'chat',\n response.model || model,\n usage,\n startTime,\n options.usageTags,\n );\n const toolCalls: AIToolCall[] | undefined =\n choice.message?.tool_calls?.map(\n (call: {\n id: string;\n function: { name: string; arguments: string };\n }) => ({\n id: call.id,\n type: 'function' as const,\n function: {\n name: call.function.name,\n arguments: call.function.arguments,\n },\n }),\n );\n return {\n content: choice.message?.content || '',\n usage,\n model: response.model || model,\n finishReason: this.mapFinishReason(choice.finish_reason),\n ...(toolCalls?.length ? { toolCalls } : {}),\n };\n } catch (error) {\n throw (\n this.abortError(controls, options, model) ?? this.mapError(error, model)\n );\n } finally {\n detach?.();\n releaseWhenIdle(release, holdRelease?.());\n controls?.cleanup();\n }\n }\n\n async complete(\n prompt: string,\n options: CompletionOptions = {},\n ): Promise<AIResponse> {\n return this.chat([{ role: 'user', content: prompt }], {\n model: options.model,\n maxTokens: options.maxTokens,\n temperature: options.temperature,\n topP: options.topP,\n n: options.n,\n stop: options.stop,\n stream: options.stream,\n onProgress: options.onProgress,\n signal: options.signal,\n timeout: options.timeout,\n reasoning: options.reasoning,\n usageTags: options.usageTags,\n continueOnLength: options.continueOnLength,\n });\n }\n\n async message(text: string, options: MessageOptions = {}): Promise<string> {\n const messages: AIMessage[] = [\n ...(options.history || []),\n { role: options.role || 'user', content: text },\n ];\n const response = await this.chat(messages, {\n model: options.model,\n maxTokens: options.maxTokens,\n temperature: options.temperature,\n topP: options.topP,\n stop: options.stop,\n stream: options.stream,\n frequencyPenalty: options.frequencyPenalty,\n presencePenalty: options.presencePenalty,\n responseFormat: options.responseFormat,\n responseSchema: options.responseSchema,\n seed: options.seed,\n tools: options.tools,\n toolChoice: options.toolChoice,\n onProgress: options.onProgress,\n signal: options.signal,\n timeout: options.timeout,\n reasoning: options.reasoning,\n usageTags: options.usageTags,\n continueOnLength: options.continueOnLength,\n });\n return response.content;\n }\n\n /**\n * Streams a chat completion as text chunks. Like the other providers, a\n * stream yields text only; use `chat()` for rounds that may call tools.\n * Breaking out of the loop interrupts generation on the engine.\n */\n async *stream(\n messages: AIMessage[],\n options: ChatOptions = {},\n ): AsyncIterable<string> {\n const startTime = Date.now();\n let controls: PreparedRequestControls | undefined;\n let detach: (() => void) | undefined;\n let engine: WebLLMEngineLike | undefined;\n let release: (() => void) | undefined;\n let iterator: AsyncIterator<WebLLMChunk> | undefined;\n let iteratorDone = false;\n let holdRelease: Promise<unknown> | undefined;\n const model =\n options.model || this.options.defaultModel || DEFAULT_WEBLLM_MODEL;\n try {\n options = normalizeChatOptions(this.options, options, PROVIDER, model);\n engine = await this.acquireEngine(model, options.signal);\n controls = prepareRequestControls(this.options, options);\n release = await this.lockEngine(engine, controls.signal);\n detach = this.bindInterrupt(engine, controls.signal);\n\n const pending: Promise<AsyncIterable<WebLLMChunk>> =\n engine.chat.completions.create(\n this.buildRequest(\n messages,\n options as ChatOptions & { maxTokens: number },\n this.requestModel(model, options),\n true,\n false,\n ),\n );\n let chunks: AsyncIterable<WebLLMChunk>;\n try {\n chunks = await abortable(pending, controls.signal);\n } catch (error) {\n // The caller is gone but the engine may still start this request.\n // Keep our queue closed until it has been interrupted and drained, or\n // the next request would wait behind it and could interrupt it.\n holdRelease = pending.then(\n (late) => abandonStream(late[Symbol.asyncIterator](), engine),\n () => {},\n );\n throw error;\n }\n // Iterated by hand: WebLLM releases its per-model lock only when its\n // generator runs to completion, never on an early `return()`.\n iterator = chunks[Symbol.asyncIterator]();\n\n let finishReason: string | null | undefined;\n let usage: TokenUsage | undefined;\n for (;;) {\n const step = await iterator.next();\n if (step.done) {\n iteratorDone = true;\n break;\n }\n const chunk = step.value;\n const choice = chunk.choices?.[0];\n finishReason = choice?.finish_reason ?? finishReason;\n if (chunk.usage) usage = this.mapUsage(chunk.usage);\n const content = choice?.delta?.content;\n if (content) {\n options.onProgress?.(content);\n yield content;\n }\n }\n if (controls.signal.aborted) {\n throw (\n this.abortError(controls, options, model) ?? controls.signal.reason\n );\n }\n this.assertNotInterrupted(finishReason, model);\n options.onFinishReason?.(this.mapFinishReason(finishReason));\n emitUsage(\n this.options,\n PROVIDER,\n 'stream',\n model,\n usage,\n startTime,\n options.usageTags,\n );\n } catch (error) {\n throw (\n this.abortError(controls, options, model) ?? this.mapError(error, model)\n );\n } finally {\n if (iterator && !iteratorDone && engine) {\n // Consumer stopped early (or the loop threw): stop the GPU, then let\n // the engine's generator finish so its lock is released before the\n // next request is admitted.\n try {\n void Promise.resolve(engine.interruptGenerate()).catch(() => {});\n } catch {\n // Best effort.\n }\n await drainIterator(iterator);\n }\n detach?.();\n releaseWhenIdle(release, holdRelease);\n controls?.cleanup();\n }\n }\n\n async countTokens(text: string): Promise<number> {\n // WebLLM exposes no standalone tokenizer; ~4 characters per token.\n return Math.ceil(text.length / 4);\n }\n\n // --------------------------------------------------------------------------\n // Models and capabilities\n // --------------------------------------------------------------------------\n\n async getModels(): Promise<AIModel[]> {\n const webllm = await importWebLLM();\n const list =\n (\n this.options.appConfig as\n | { model_list?: WebLLMModelRecord[] }\n | undefined\n )?.model_list ?? webllm.prebuiltAppConfig.model_list;\n const functionCalling = new Set(webllm.functionCallingModelIds ?? []);\n return list\n .filter((record) => record.model_type !== 1) // embedding models\n .map((record) => {\n const vision = record.model_type === 2;\n const functions = functionCalling.has(record.model_id);\n return {\n id: record.model_id,\n name: record.model_id,\n description: record.vram_required_MB\n ? `Runs on-device via WebGPU (~${Math.round(record.vram_required_MB)} MB VRAM)`\n : 'Runs on-device via WebGPU',\n contextLength:\n record.overrides?.context_window_size ?? DEFAULT_CONTEXT_LENGTH,\n capabilities: [\n 'text',\n 'chat',\n ...(functions ? ['functions'] : []),\n ...(vision ? ['vision'] : []),\n ],\n supportsFunctions: functions,\n supportsVision: vision,\n };\n });\n }\n\n async getCapabilities(): Promise<AICapabilities> {\n return { ...WEBLLM_CAPABILITIES };\n }\n\n // --------------------------------------------------------------------------\n // No in-browser equivalent\n // --------------------------------------------------------------------------\n\n async embed(\n _text: string | string[],\n _options: EmbeddingOptions = {},\n ): Promise<EmbeddingResponse> {\n return unsupported('Embeddings');\n }\n\n async embedImage(\n _image: string | Buffer,\n _options: ImageEmbeddingOptions = {},\n ): Promise<EmbeddingResponse> {\n return unsupported('Image embeddings');\n }\n\n async describeImage(\n _image: string | Buffer,\n _prompt?: string,\n _options: ImageDescriptionOptions = {},\n ): Promise<string> {\n return unsupported('Image description');\n }\n\n async generateImage(\n _prompt: string,\n _options: ImageGenerationOptions = {},\n ): Promise<ImageGenerationResponse> {\n return unsupported('Image generation');\n }\n\n async submitVideoGenerationJob(\n _options: VideoGenerationOptions,\n ): Promise<VideoGenerationJob> {\n return unsupported('Video generation');\n }\n\n async getVideoGenerationJob(\n _handle: VideoGenerationJob,\n ): Promise<VideoGenerationStatusResult> {\n return unsupported('Video generation');\n }\n\n async fetchVideoGenerationResult(\n _handle: VideoGenerationJob,\n ): Promise<VideoGenerationResult> {\n return unsupported('Video generation');\n }\n\n async cancelVideoGenerationJob(_handle: VideoGenerationJob): Promise<void> {\n return unsupported('Video generation');\n }\n\n async validateVideoGenerationAccess(): Promise<boolean> {\n return unsupported('Video generation');\n }\n\n async synthesizeSpeech(\n _text: string,\n _options?: TTSOptions,\n ): Promise<TTSResponse> {\n return unsupported('Text-to-speech');\n }\n\n streamSpeech(_text: string, _options?: TTSOptions): AsyncIterable<Buffer> {\n const error = new AIError(\n 'Text-to-speech streaming is not supported by the webllm provider.',\n 'NOT_SUPPORTED',\n PROVIDER,\n );\n return {\n [Symbol.asyncIterator]: () => ({\n next: () => Promise.reject(error),\n }),\n };\n }\n\n async cloneVoice(_options: VoiceCloneOptions): Promise<Voice> {\n return unsupported('Voice cloning');\n }\n\n async designVoice(_options: VoiceDesignOptions): Promise<Voice> {\n return unsupported('Voice design');\n }\n\n async getVoices(_options?: VoiceListOptions): Promise<Voice[]> {\n return unsupported('Voice listing');\n }\n}\n\n/** One streamed WebLLM chunk (structural subset). */\ninterface WebLLMChunk {\n choices?: Array<{\n delta?: { content?: string | null };\n finish_reason?: string | null;\n }>;\n usage?: unknown;\n}\n\n/** Runs a WebLLM stream to its end, ignoring errors; used after interrupting it. */\nasync function drainIterator(\n iterator: AsyncIterator<WebLLMChunk>,\n): Promise<void> {\n try {\n while (!(await iterator.next()).done) {\n // discard\n }\n } catch {\n // The engine already stopped; nothing more to release.\n }\n}\n\n/** Releases an engine queue slot now, or once `idle` has settled. */\nfunction releaseWhenIdle(\n release: (() => void) | undefined,\n idle?: Promise<unknown>,\n): void {\n if (!release) return;\n if (idle) void idle.then(release, release);\n else release();\n}\n\n/**\n * Finishes a stream nobody is reading. WebLLM resets its interrupt flag on the\n * first `next()`, so interrupt only after pulling one chunk, then drain it so\n * the engine's lock is released.\n */\nasync function abandonStream(\n iterator: AsyncIterator<WebLLMChunk>,\n engine: WebLLMEngineLike | undefined,\n): Promise<void> {\n try {\n if ((await iterator.next()).done) return;\n await Promise.resolve(engine?.interruptGenerate());\n } catch {\n return;\n }\n await drainIterator(iterator);\n}\n\n/** Rejects with the signal's reason if it fires first; the underlying work continues. */\nfunction abortable<T>(promise: Promise<T>, signal?: AbortSignal): Promise<T> {\n if (!signal) return promise;\n if (signal.aborted) {\n return Promise.reject(\n new AIError('AI request aborted by caller', 'AI_ABORTED', PROVIDER),\n );\n }\n return new Promise<T>((resolve, reject) => {\n const onAbort = () =>\n reject(\n new AIError('AI request aborted by caller', 'AI_ABORTED', PROVIDER),\n );\n signal.addEventListener('abort', onAbort, { once: true });\n promise.then(\n (value) => {\n signal.removeEventListener('abort', onAbort);\n resolve(value);\n },\n (error) => {\n signal.removeEventListener('abort', onAbort);\n reject(error);\n },\n );\n });\n}\n"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as ChatGPTPlanSessionRevokedError, c as ChatGPTPlanWorkspaceError, d as getAI, f as getAIAuto, g as getOpenAI, h as getAIClient, i as ChatGPTPlanProvider, l as AIMessage, m as OpenAIClient, n as AIThread, o as ChatGPTPlanUsageLimitError, p as AIClient, r as ChatGPTPlanError, s as ChatGPTPlanUsageUnavailableError, t as PACKAGE_VERSION_INITIALIZED } from "./chunks/src-
|
|
1
|
+
import { S as isRateLimitRetryableSoon, _ as ModelNotFoundError, a as DEFAULT_AI_TIMEOUT_MS, b as WebLLMPeerMissingError, d as AIError, f as AI_PROVIDER_TYPES, g as DEFAULT_RATE_LIMIT_MAX_RETRY_DELAY_MS, h as ContextLengthError, i as DEFAULT_AI_MAX_RETRIES, m as ContentFilterError, p as AuthenticationError, r as DEFAULT_AI_GENERATION_LIMITS, v as RateLimitError, x as extractTextContent, y as WebGPUUnavailableError } from "./chunks/usage-yIT5lpQm.js";
|
|
2
|
+
import { a as ChatGPTPlanSessionRevokedError, c as ChatGPTPlanWorkspaceError, d as getAI, f as getAIAuto, g as getOpenAI, h as getAIClient, i as ChatGPTPlanProvider, l as AIMessage, m as OpenAIClient, n as AIThread, o as ChatGPTPlanUsageLimitError, p as AIClient, r as ChatGPTPlanError, s as ChatGPTPlanUsageUnavailableError, t as PACKAGE_VERSION_INITIALIZED } from "./chunks/src-mOOK32QB.js";
|
|
3
3
|
export { AIClient, AIError, AIMessage as AIMessageClass, AIThread, AI_PROVIDER_TYPES, AuthenticationError, ChatGPTPlanError, ChatGPTPlanProvider, ChatGPTPlanSessionRevokedError, ChatGPTPlanUsageLimitError, ChatGPTPlanUsageUnavailableError, ChatGPTPlanWorkspaceError, ContentFilterError, ContextLengthError, DEFAULT_AI_GENERATION_LIMITS, DEFAULT_AI_MAX_RETRIES, DEFAULT_AI_TIMEOUT_MS, DEFAULT_RATE_LIMIT_MAX_RETRY_DELAY_MS, ModelNotFoundError, OpenAIClient, PACKAGE_VERSION_INITIALIZED, RateLimitError, WebGPUUnavailableError, WebLLMPeerMissingError, extractTextContent, getAI, getAIAuto, getAIClient, getOpenAI, isRateLimitRetryableSoon };
|
package/dist/local.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as isWebGPUAvailable, i as importWebLLM, n as WebLLMProvider, r as disposeWebLLMEngines, t as DEFAULT_WEBLLM_MODEL } from "./chunks/webllm-
|
|
1
|
+
import { b as WebLLMPeerMissingError, y as WebGPUUnavailableError } from "./chunks/usage-yIT5lpQm.js";
|
|
2
|
+
import { a as isWebGPUAvailable, i as importWebLLM, n as WebLLMProvider, r as disposeWebLLMEngines, t as DEFAULT_WEBLLM_MODEL } from "./chunks/webllm-DrwR5V-y.js";
|
|
3
3
|
export { DEFAULT_WEBLLM_MODEL, WebGPUUnavailableError, WebLLMPeerMissingError, WebLLMProvider, disposeWebLLMEngines, importWebLLM, isWebGPUAvailable };
|
package/dist/node.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as ChatGPTPlanSessionRevokedError, c as ChatGPTPlanWorkspaceError, d as getAI, g as getOpenAI, h as getAIClient, i as ChatGPTPlanProvider, l as AIMessage, m as OpenAIClient, n as AIThread, o as ChatGPTPlanUsageLimitError, p as AIClient, r as ChatGPTPlanError, s as ChatGPTPlanUsageUnavailableError, t as PACKAGE_VERSION_INITIALIZED } from "./chunks/src-
|
|
1
|
+
import { S as isRateLimitRetryableSoon, _ as ModelNotFoundError, a as DEFAULT_AI_TIMEOUT_MS, b as WebLLMPeerMissingError, d as AIError, f as AI_PROVIDER_TYPES, g as DEFAULT_RATE_LIMIT_MAX_RETRY_DELAY_MS, h as ContextLengthError, i as DEFAULT_AI_MAX_RETRIES, m as ContentFilterError, p as AuthenticationError, r as DEFAULT_AI_GENERATION_LIMITS, v as RateLimitError, x as extractTextContent, y as WebGPUUnavailableError } from "./chunks/usage-yIT5lpQm.js";
|
|
2
|
+
import { a as ChatGPTPlanSessionRevokedError, c as ChatGPTPlanWorkspaceError, d as getAI, g as getOpenAI, h as getAIClient, i as ChatGPTPlanProvider, l as AIMessage, m as OpenAIClient, n as AIThread, o as ChatGPTPlanUsageLimitError, p as AIClient, r as ChatGPTPlanError, s as ChatGPTPlanUsageUnavailableError, t as PACKAGE_VERSION_INITIALIZED } from "./chunks/src-mOOK32QB.js";
|
|
3
3
|
import { ValidationError, loadEnvConfig } from "@happyvertical/utils";
|
|
4
4
|
//#region src/node/factory.ts
|
|
5
5
|
/**
|
|
@@ -104,7 +104,7 @@ async function getAIAuto(options = {}) {
|
|
|
104
104
|
return getAI(config);
|
|
105
105
|
}
|
|
106
106
|
try {
|
|
107
|
-
return await import("./chunks/src-
|
|
107
|
+
return await import("./chunks/src-mOOK32QB.js").then((n) => n.u).then((m) => m.getAIAuto(config));
|
|
108
108
|
} catch (_error) {}
|
|
109
109
|
const hasLiteLLMSignal = Boolean(process.env.LITELLM_BASE_URL || process.env.LITELLM_API_KEY);
|
|
110
110
|
if (Boolean(process.env.BIFROST_BASE_URL) && !config.type) return getAI({
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Largest accepted `chatTemplateKwargs`, measured as serialized JSON bytes. */
|
|
2
|
+
export declare const MAX_CHAT_TEMPLATE_KWARGS_BYTES = 8192;
|
|
3
|
+
/** Deepest accepted nesting of objects and arrays (the top level is 1). */
|
|
4
|
+
export declare const MAX_CHAT_TEMPLATE_KWARGS_DEPTH = 4;
|
|
5
|
+
/** Most keys accepted in any one object, and items in any one array. */
|
|
6
|
+
export declare const MAX_CHAT_TEMPLATE_KWARGS_ENTRIES = 32;
|
|
7
|
+
/**
|
|
8
|
+
* Validate `chatTemplateKwargs` and return a detached JSON copy to send as
|
|
9
|
+
* `chat_template_kwargs`, or `undefined` when the option is absent or empty.
|
|
10
|
+
* Objects may have `Object.prototype` or a null prototype
|
|
11
|
+
* (`Object.create(null)`); the copy is always an ordinary object.
|
|
12
|
+
*
|
|
13
|
+
* @throws {AIError} `AI_INVALID_CHAT_TEMPLATE_KWARGS` when the value is not a
|
|
14
|
+
* plain JSON object within the size, depth, and entry bounds.
|
|
15
|
+
*/
|
|
16
|
+
export declare function prepareChatTemplateKwargs(value: unknown, provider?: string, model?: string): Record<string, unknown> | undefined;
|
|
17
|
+
//# sourceMappingURL=chat-template-kwargs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-template-kwargs.d.ts","sourceRoot":"","sources":["../../src/shared/chat-template-kwargs.ts"],"names":[],"mappings":"AAcA,gFAAgF;AAChF,eAAO,MAAM,8BAA8B,OAAO,CAAC;AACnD,2EAA2E;AAC3E,eAAO,MAAM,8BAA8B,IAAI,CAAC;AAChD,wEAAwE;AACxE,eAAO,MAAM,gCAAgC,KAAK,CAAC;AAiInD;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,OAAO,EACd,QAAQ,CAAC,EAAE,MAAM,EACjB,KAAK,CAAC,EAAE,MAAM,GACb,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAYrC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"continuation.d.ts","sourceRoot":"","sources":["../../src/shared/continuation.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"continuation.d.ts","sourceRoot":"","sources":["../../src/shared/continuation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,WAAW,EACX,SAAS,EACT,UAAU,EACV,aAAa,EACb,WAAW,EACX,sBAAsB,EAEvB,MAAM,YAAS,CAAC;AAGjB,oEAAoE;AACpE,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAO3C,eAAO,MAAM,eAAe,iHACoF,CAAC;AAEjH,UAAU,oBAAoB;IAC5B,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,eAAe,EAAE,aAAa,EAC9B,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,OAAO,GAAG,gBAAgB,GAAG,gBAAgB,CAAC,GAAG;IAC1E,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;CAC3C,GACA,oBAAoB,GAAG,SAAS,CAuBlC;AAmBD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,GACX,MAAM,CAUR;AAkCD;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,EAAE,OAAO,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,UAAU,CAAC,EAC3E,eAAe,EAAE,aAAa,EAC9B,QAAQ,EAAE,SAAS,EAAE,EACrB,OAAO,GAAE,WAAW,GAAG;IAAE,gBAAgB,CAAC,EAAE,sBAAsB,CAAA;CAAO,GACxE,OAAO,CAAC,UAAU,CAAC,CAiDrB;AAED;;;;GAIG;AACH,wBAAuB,sBAAsB,CAC3C,MAAM,EAAE,CACN,QAAQ,EAAE,SAAS,EAAE,EACrB,OAAO,CAAC,EAAE,WAAW,KAClB,aAAa,CAAC,MAAM,CAAC,EAC1B,eAAe,EAAE,aAAa,EAC9B,QAAQ,EAAE,SAAS,EAAE,EACrB,OAAO,GAAE,WAAW,GAAG;IAAE,gBAAgB,CAAC,EAAE,sBAAsB,CAAA;CAAO,GACxE,aAAa,CAAC,MAAM,CAAC,CAmEvB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,WAAW,EACtD,MAAM,EAAE,CAAC,EACT,eAAe,EAAE,aAAa,EAC9B,OAAO,GAAE,WAAoB,GAC5B,CAAC,CAsDH"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-shot retry for stale keep-alive connections in the OpenAI-compatible
|
|
3
|
+
* providers (#1467).
|
|
4
|
+
*
|
|
5
|
+
* A pooled socket the server closed while idle fails the next request
|
|
6
|
+
* (ECONNRESET, EPIPE, undici `UND_ERR_SOCKET`, "socket hang up"). Callers
|
|
7
|
+
* decide when a resend is safe: `chat()` only before response headers,
|
|
8
|
+
* `stream()` only before its first yielded chunk. HTTP status responses,
|
|
9
|
+
* timeouts, and caller aborts are never retried.
|
|
10
|
+
*/
|
|
11
|
+
import { type AIAttemptRecorder } from "../safety.js";
|
|
12
|
+
/**
|
|
13
|
+
* True when `error` (or anything on its `cause` chain) is a stale
|
|
14
|
+
* connection failure: the OpenAI SDK's `APIConnectionError` (not its timeout
|
|
15
|
+
* subclass) or a socket error coded ECONNRESET / EPIPE / UND_ERR_SOCKET /
|
|
16
|
+
* "socket hang up". Any timeout, abort, or HTTP status on the chain wins and
|
|
17
|
+
* makes the error non-retryable.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isStaleConnectionError(error: unknown): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Decide whether a failed attempt gets its single transparent retry, and
|
|
22
|
+
* record it on the per-call attempt recorder when it does.
|
|
23
|
+
*/
|
|
24
|
+
export declare function shouldRetryConnection(error: unknown, state: {
|
|
25
|
+
enabled: boolean | undefined;
|
|
26
|
+
alreadyRetried: boolean;
|
|
27
|
+
signal: AbortSignal;
|
|
28
|
+
callerSignal?: AbortSignal;
|
|
29
|
+
didTimeout: () => boolean;
|
|
30
|
+
recorder?: AIAttemptRecorder;
|
|
31
|
+
}): boolean;
|
|
32
|
+
/** The per-call attempt recorder the observed client attaches, if any. */
|
|
33
|
+
export declare function attemptRecorderFrom(options: object): AIAttemptRecorder | undefined;
|
|
34
|
+
//# sourceMappingURL=connection-retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection-retry.d.ts","sourceRoot":"","sources":["../../../src/shared/providers/connection-retry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAuB,KAAK,iBAAiB,EAAE,MAAM,cAAW,CAAC;AAKxE;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAoC9D;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,EACd,KAAK,EAAE;IACL,OAAO,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,cAAc,EAAE,OAAO,CAAC;IACxB,MAAM,EAAE,WAAW,CAAC;IACpB,YAAY,CAAC,EAAE,WAAW,CAAC;IAC3B,UAAU,EAAE,MAAM,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B,GACA,OAAO,CAaT;AAED,0EAA0E;AAC1E,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,GACd,iBAAiB,GAAG,SAAS,CAI/B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ollama.d.ts","sourceRoot":"","sources":["../../../src/shared/providers/ollama.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"ollama.d.ts","sourceRoot":"","sources":["../../../src/shared/providers/ollama.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAcH,OAAO,KAAK,EACV,cAAc,EACd,WAAW,EACX,SAAS,EACT,OAAO,EACP,UAAU,EACV,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,EACjB,uBAAuB,EACvB,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,cAAc,EACd,aAAa,EAEb,UAAU,EACV,WAAW,EACX,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EACrB,2BAA2B,EAC3B,KAAK,EACL,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,aAAU,CAAC;AA4TlB,qBAAa,cAAe,YAAW,WAAW;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAS;IACjD,OAAO,CAAC,gBAAgB,CAAC,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAG3B;IACJ,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAG/B;gBAEQ,OAAO,EAAE,aAAa;IASlC,OAAO,KAAK,aAAa,GAExB;IAED,OAAO,KAAK,oBAAoB,GAE/B;IAED,OAAO,CAAC,YAAY;YAaN,cAAc;IA+B5B,OAAO,CAAC,QAAQ;YAcF,WAAW;YAsBX,aAAa;YAmBZ,WAAW;YAiCZ,SAAS;YAeT,YAAY;YA4BZ,WAAW;IAyCzB,OAAO,CAAC,eAAe;YAQT,oBAAoB;YA0BpB,cAAc;IA0B5B,OAAO,CAAC,kBAAkB;YAaZ,mBAAmB;IA2DjC,OAAO,CAAC,QAAQ;IA6BhB,OAAO,CAAC,mBAAmB;IA8B3B,OAAO,CAAC,QAAQ;IAkBV,IAAI,CACR,QAAQ,EAAE,SAAS,EAAE,EACrB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,UAAU,CAAC;IA4FhB,QAAQ,CACZ,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,UAAU,CAAC;IAmFhB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,MAAM,CAAC;IA8BpE,KAAK,CACT,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,EACvB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,iBAAiB,CAAC;IA4CvB,UAAU,CACd,KAAK,EAAE,MAAM,GAAG,MAAM,EACtB,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,iBAAiB,CAAC;IAavB,aAAa,CACjB,KAAK,EAAE,MAAM,GAAG,MAAM,EACtB,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,MAAM,CAAC;IAqCZ,aAAa,CACjB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,uBAAuB,CAAC;IAgF5B,MAAM,CACX,QAAQ,EAAE,SAAS,EAAE,EACrB,OAAO,GAAE,WAAgB,GACxB,aAAa,CAAC,MAAM,CAAC;IAqGlB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAI1C,SAAS,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAkD/B,eAAe,IAAI,OAAO,CAAC,cAAc,CAAC;IAS1C,wBAAwB,CAC5B,QAAQ,EAAE,sBAAsB,GAC/B,OAAO,CAAC,kBAAkB,CAAC;IAQxB,qBAAqB,CACzB,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,2BAA2B,CAAC;IAQjC,0BAA0B,CAC9B,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,qBAAqB,CAAC;IAQ3B,wBAAwB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAQpE,6BAA6B,IAAI,OAAO,CAAC,OAAO,CAAC;IAQjD,gBAAgB,CACpB,KAAK,EAAE,MAAM,EACb,QAAQ,CAAC,EAAE,UAAU,GACpB,OAAO,CAAC,WAAW,CAAC;IAQvB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC;IAanE,UAAU,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,KAAK,CAAC;IAQvD,WAAW,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,KAAK,CAAC;IAQzD,SAAS,CAAC,QAAQ,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;CAO/D"}
|
|
@@ -82,6 +82,8 @@ export interface OpenAICompatibleOptions extends BaseAIOptions {
|
|
|
82
82
|
apiKey?: string;
|
|
83
83
|
baseUrl?: string;
|
|
84
84
|
organization?: string;
|
|
85
|
+
/** See {@link OpenAIOptions.retryConnectionErrors}. @default true */
|
|
86
|
+
retryConnectionErrors?: boolean;
|
|
85
87
|
}
|
|
86
88
|
/**
|
|
87
89
|
* OpenAI provider implementation that handles all interactions with OpenAI's API.
|
|
@@ -317,12 +319,30 @@ export declare class OpenAIProvider implements AIInterface {
|
|
|
317
319
|
*/
|
|
318
320
|
private mapUsage;
|
|
319
321
|
/**
|
|
320
|
-
*
|
|
322
|
+
* Reject `chatTemplateKwargs` on the hosted OpenAI API, which does not
|
|
323
|
+
* accept `chat_template_kwargs`. Throwing (rather than dropping the field)
|
|
324
|
+
* keeps a caller from silently losing a template switch it asked for, such
|
|
325
|
+
* as `enable_thinking: false`, and fails before the request is billed.
|
|
326
|
+
* The resolved client URL is checked, so `OPENAI_BASE_URL` pointing at a
|
|
327
|
+
* vLLM server still works when `baseUrl` is unset.
|
|
328
|
+
* @private
|
|
329
|
+
*/
|
|
330
|
+
private assertChatTemplateKwargsSupported;
|
|
331
|
+
/**
|
|
332
|
+
* Maps OpenAI finish reason to internal finish reason format. An absent
|
|
333
|
+
* reason is `'stop'`; a value outside the normalised set (e.g. vLLM
|
|
334
|
+
* `abort`, or legacy `function_call`, which carries no `tool_calls`) is
|
|
335
|
+
* `'other'` so a partial reply is not mistaken for a complete one.
|
|
321
336
|
* @param reason - OpenAI finish reason from API response
|
|
322
337
|
* @returns Internal finish reason
|
|
323
338
|
* @private
|
|
324
339
|
*/
|
|
325
340
|
private mapFinishReason;
|
|
341
|
+
/**
|
|
342
|
+
* Whether a failed chat/stream attempt gets its one transparent
|
|
343
|
+
* stale-connection retry (#1467). Records the retry for `attempts`.
|
|
344
|
+
*/
|
|
345
|
+
private retriesConnection;
|
|
326
346
|
/**
|
|
327
347
|
* Gets the context length for a given OpenAI model
|
|
328
348
|
* @param modelId - The OpenAI model identifier
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../../src/shared/providers/openai.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../../src/shared/providers/openai.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reasoning-text helpers shared by the chat adapters and continuation.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Reasoning text an OpenAI-compatible server returned beside the answer.
|
|
6
|
+
* vLLM's reasoning parsers emit `reasoning_content` (older releases) or
|
|
7
|
+
* `reasoning` (newer releases) on the message and on stream deltas; SGLang and
|
|
8
|
+
* several gateways use the same names. Only string values count, so a
|
|
9
|
+
* structured `reasoning` object from another gateway is ignored.
|
|
10
|
+
*/
|
|
11
|
+
export declare function readReasoningText(source: unknown): string | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Deliver accumulated stream reasoning to `ChatOptions.onReasoning`. Called
|
|
14
|
+
* from a stream's `finally`, so it also runs when the stream fails, is
|
|
15
|
+
* aborted, or the consumer stops early; a throwing callback is swallowed so it
|
|
16
|
+
* can neither break the stream nor mask the stream's own error.
|
|
17
|
+
*/
|
|
18
|
+
export declare function reportReasoning(callback: ((reasoning: string) => void) | undefined, reasoning: string): void;
|
|
19
|
+
//# sourceMappingURL=reasoning.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reasoning.d.ts","sourceRoot":"","sources":["../../src/shared/reasoning.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAQrE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,CAAC,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,EACnD,SAAS,EAAE,MAAM,GAChB,IAAI,CAON"}
|
package/dist/shared/safety.d.ts
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import type { AIGenerationLimits, AIInterface, AIReasoningOptions, AIRequestControls, AIRequestEvent, AIRequestOperation, AIRequestStatus, BaseAIOptions, ChatOptions, ImageGenerationOptions } from "./types.js";
|
|
2
2
|
export declare const DEFAULT_AI_TIMEOUT_MS = 120000;
|
|
3
3
|
export declare const DEFAULT_AI_MAX_RETRIES = 0;
|
|
4
|
+
/**
|
|
5
|
+
* Internal per-call channel from a provider back to the observed client: a
|
|
6
|
+
* provider that transparently resends a request (the OpenAI-compatible
|
|
7
|
+
* stale-connection retry, #1467) bumps `connectionRetries` so the request
|
|
8
|
+
* event's `attempts` reflects it. Enumerable so option spreads keep it.
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export declare const AI_ATTEMPT_RECORDER: unique symbol;
|
|
12
|
+
/** @internal */
|
|
13
|
+
export interface AIAttemptRecorder {
|
|
14
|
+
connectionRetries: number;
|
|
15
|
+
}
|
|
4
16
|
export declare const DEFAULT_AI_GENERATION_LIMITS: Readonly<AIGenerationLimits>;
|
|
5
17
|
export interface NormalizedBaseAIOptions extends BaseAIOptions {
|
|
6
18
|
timeout: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safety.d.ts","sourceRoot":"","sources":["../../src/shared/safety.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"safety.d.ts","sourceRoot":"","sources":["../../src/shared/safety.ts"],"names":[],"mappings":"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"}
|
package/dist/shared/types.d.ts
CHANGED
|
@@ -11,8 +11,13 @@ export type GeminiThinkingLevel = 'minimal' | 'low' | 'medium' | 'high';
|
|
|
11
11
|
*
|
|
12
12
|
* Provider instances merge partial overrides with the exported safe defaults.
|
|
13
13
|
*/
|
|
14
|
-
/**
|
|
15
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Why a generation stopped, normalised across providers. `'other'` means the
|
|
16
|
+
* server reported a reason outside this set (e.g. vLLM `abort`): treat the
|
|
17
|
+
* reply as possibly incomplete. Only the OpenAI-compatible providers report
|
|
18
|
+
* it today; see {@link AIResponse.rawFinishReason} for the server's value.
|
|
19
|
+
*/
|
|
20
|
+
export type AIFinishReason = 'stop' | 'length' | 'tool_calls' | 'content_filter' | 'other';
|
|
16
21
|
/**
|
|
17
22
|
* Automatic continuation when a reply stops on its output limit. `true`
|
|
18
23
|
* allows up to 3 extra requests; pass `{ maxContinuations }` to change that.
|
|
@@ -327,6 +332,30 @@ export interface ChatOptions extends AIRequestControls {
|
|
|
327
332
|
* finish reason. Used for continuation; also useful to detect truncation.
|
|
328
333
|
*/
|
|
329
334
|
onFinishReason?: (reason: AIFinishReason) => void;
|
|
335
|
+
/**
|
|
336
|
+
* Called by streaming adapters once when the stream ends, with the
|
|
337
|
+
* reasoning text accumulated from its reasoning deltas (vLLM
|
|
338
|
+
* `reasoning_content`/`reasoning`, Ollama `thinking`). It also runs when
|
|
339
|
+
* the stream fails, is aborted, or the consumer stops iterating early, with
|
|
340
|
+
* whatever arrived first, so it is a diagnostic, not a completion signal.
|
|
341
|
+
* Not called when no reasoning arrived. Errors it throws are swallowed.
|
|
342
|
+
* `chat()` returns the same text as {@link AIResponse.reasoning}.
|
|
343
|
+
*/
|
|
344
|
+
onReasoning?: (reasoning: string) => void;
|
|
345
|
+
/**
|
|
346
|
+
* Extra chat-template arguments sent as `chat_template_kwargs` by the
|
|
347
|
+
* OpenAI-compatible providers (`openai`, `litellm`, `bifrost`), for servers
|
|
348
|
+
* such as vLLM and SGLang that apply them to the model's chat template, e.g.
|
|
349
|
+
* `{ enable_thinking: false }` to switch thinking off for one request.
|
|
350
|
+
* Must be a plain JSON object (at most 8192 bytes serialized, 4 levels
|
|
351
|
+
* deep, 32 entries per object or array); invalid values throw
|
|
352
|
+
* `AI_INVALID_CHAT_TEMPLATE_KWARGS` before any request is sent (the error
|
|
353
|
+
* locates the entry by position, never by key name or value). An empty
|
|
354
|
+
* object is not sent. The `openai` provider throws `AI_UNSUPPORTED_OPTION`
|
|
355
|
+
* when its resolved base URL is the hosted `api.openai.com`, which does not
|
|
356
|
+
* accept the field. Other providers ignore it.
|
|
357
|
+
*/
|
|
358
|
+
chatTemplateKwargs?: Record<string, unknown>;
|
|
330
359
|
/**
|
|
331
360
|
* Continue a reply that stopped on its output limit and return the stitched
|
|
332
361
|
* text. Off by default; ignored for tools and JSON output. Each part is a
|
|
@@ -1193,9 +1222,25 @@ export interface AIResponse {
|
|
|
1193
1222
|
*/
|
|
1194
1223
|
model?: string;
|
|
1195
1224
|
/**
|
|
1196
|
-
*
|
|
1225
|
+
* Why generation stopped. The OpenAI-compatible providers always set it:
|
|
1226
|
+
* an absent server value is `'stop'`, an unrecognised one is `'other'`, and
|
|
1227
|
+
* a reply that carries tool calls but reports `'stop'` is `'tool_calls'`
|
|
1228
|
+
* (`'length'` and `'content_filter'` are kept as reported).
|
|
1197
1229
|
*/
|
|
1198
1230
|
finishReason?: AIFinishReason;
|
|
1231
|
+
/**
|
|
1232
|
+
* The server's own finish reason when `finishReason` is `'other'`, e.g.
|
|
1233
|
+
* `'abort'` from vLLM or legacy `'function_call'`.
|
|
1234
|
+
*/
|
|
1235
|
+
rawFinishReason?: string;
|
|
1236
|
+
/**
|
|
1237
|
+
* Reasoning ("thinking") text the server returned separately from
|
|
1238
|
+
* `content`: vLLM/SGLang `reasoning_content` or `reasoning` on
|
|
1239
|
+
* OpenAI-compatible providers, `thinking` on Ollama. Absent when the server
|
|
1240
|
+
* sent none. A reply whose `content` is empty but whose `reasoning` is not
|
|
1241
|
+
* usually means the answer was parsed into the reasoning channel.
|
|
1242
|
+
*/
|
|
1243
|
+
reasoning?: string;
|
|
1199
1244
|
/**
|
|
1200
1245
|
* Tool calls made by the model
|
|
1201
1246
|
*/
|
|
@@ -1736,6 +1781,17 @@ export interface OpenAIOptions extends BaseAIOptions {
|
|
|
1736
1781
|
apiKey?: string;
|
|
1737
1782
|
baseUrl?: string;
|
|
1738
1783
|
organization?: string;
|
|
1784
|
+
/**
|
|
1785
|
+
* Retry once, immediately, when a request fails on a stale keep-alive
|
|
1786
|
+
* connection (ECONNRESET, EPIPE, `UND_ERR_SOCKET`, "socket hang up", or the
|
|
1787
|
+
* OpenAI SDK's `APIConnectionError`): `chat()` only before response
|
|
1788
|
+
* headers arrive; `stream()` until the first chunk is yielded, which may
|
|
1789
|
+
* re-run a generation the server had started. Independent of `maxRetries`;
|
|
1790
|
+
* never retries after an HTTP status, a timeout, a caller abort, or a
|
|
1791
|
+
* streamed chunk.
|
|
1792
|
+
* @default true
|
|
1793
|
+
*/
|
|
1794
|
+
retryConnectionErrors?: boolean;
|
|
1739
1795
|
}
|
|
1740
1796
|
/**
|
|
1741
1797
|
* Protected local session surface consumed by the ChatGPT plan provider.
|
|
@@ -1774,6 +1830,17 @@ export interface LiteLLMOptions extends BaseAIOptions {
|
|
|
1774
1830
|
apiKey?: string;
|
|
1775
1831
|
baseUrl?: string;
|
|
1776
1832
|
organization?: string;
|
|
1833
|
+
/**
|
|
1834
|
+
* Retry once, immediately, when a request fails on a stale keep-alive
|
|
1835
|
+
* connection (ECONNRESET, EPIPE, `UND_ERR_SOCKET`, "socket hang up", or the
|
|
1836
|
+
* OpenAI SDK's `APIConnectionError`): `chat()` only before response
|
|
1837
|
+
* headers arrive; `stream()` until the first chunk is yielded, which may
|
|
1838
|
+
* re-run a generation the server had started. Independent of `maxRetries`;
|
|
1839
|
+
* never retries after an HTTP status, a timeout, a caller abort, or a
|
|
1840
|
+
* streamed chunk.
|
|
1841
|
+
* @default true
|
|
1842
|
+
*/
|
|
1843
|
+
retryConnectionErrors?: boolean;
|
|
1777
1844
|
adminApiKey?: string;
|
|
1778
1845
|
adminBaseUrl?: string;
|
|
1779
1846
|
adminUrl?: string;
|
|
@@ -1790,6 +1857,17 @@ export interface BifrostOptions extends BaseAIOptions {
|
|
|
1790
1857
|
apiKey?: string;
|
|
1791
1858
|
baseUrl?: string;
|
|
1792
1859
|
organization?: string;
|
|
1860
|
+
/**
|
|
1861
|
+
* Retry once, immediately, when a request fails on a stale keep-alive
|
|
1862
|
+
* connection (ECONNRESET, EPIPE, `UND_ERR_SOCKET`, "socket hang up", or the
|
|
1863
|
+
* OpenAI SDK's `APIConnectionError`): `chat()` only before response
|
|
1864
|
+
* headers arrive; `stream()` until the first chunk is yielded, which may
|
|
1865
|
+
* re-run a generation the server had started. Independent of `maxRetries`;
|
|
1866
|
+
* never retries after an HTTP status, a timeout, a caller abort, or a
|
|
1867
|
+
* streamed chunk.
|
|
1868
|
+
* @default true
|
|
1869
|
+
*/
|
|
1870
|
+
retryConnectionErrors?: boolean;
|
|
1793
1871
|
/**
|
|
1794
1872
|
* Optional virtual key for admin routes. Bifrost OSS admin APIs typically use
|
|
1795
1873
|
* username/password Basic auth instead; use `adminUser` / `adminPassword`
|