From 2e3ea8b9ddd0b55524890bf85c50271c972b3794 Mon Sep 17 00:00:00 2001 From: grjte Date: Fri, 11 Sep 2026 15:08:31 +0100 Subject: [PATCH 1/2] feat: update llm library to enable use with patchwork-worker --- libraries/llm/index.js | 170 +++++++++++++++++++---------------- libraries/llm/pnpm-lock.yaml | 24 ++--- 2 files changed, 105 insertions(+), 89 deletions(-) diff --git a/libraries/llm/index.js b/libraries/llm/index.js index 1fd091d9..bbbb1d31 100644 --- a/libraries/llm/index.js +++ b/libraries/llm/index.js @@ -21,92 +21,108 @@ */ export { - // config (account doc + patchwork:llm-config provider) - readConfig, - writeConfig, - callConfig, - normalizeConfig, - subscribeConfig, - resolveConfig, - ensureSettingsDoc, - ensureConfig, - // per-tool / per-doc whole-config overrides - scopedRaw, - hasScopeOverride, - readScopedConfig, - writeScopeOverride, - clearScopeOverride, - settingsDocHandle, - applyPrompts, - effectiveSystem, - DEFAULTS, - PARAM_KEYS, - PROVIDER_CAPS, - TOOL_STORAGE_ID, - CONFIG_SELECTOR, - // catalogues / labels - LOCAL_MODELS, - WEBLLM_MODELS, - fetchOpenRouterModels, - fetchOllamaModels, - describeConfig, -} from "./config.js" + // config (account doc + patchwork:llm-config provider) + readConfig, + writeConfig, + callConfig, + normalizeConfig, + subscribeConfig, + resolveConfig, + ensureSettingsDoc, + ensureConfig, + // per-tool / per-doc whole-config overrides + scopedRaw, + hasScopeOverride, + readScopedConfig, + writeScopeOverride, + clearScopeOverride, + settingsDocHandle, + applyPrompts, + effectiveSystem, + DEFAULTS, + PARAM_KEYS, + PROVIDER_CAPS, + TOOL_STORAGE_ID, + CONFIG_SELECTOR, + // catalogues / labels + LOCAL_MODELS, + WEBLLM_MODELS, + fetchOpenRouterModels, + fetchOllamaModels, + describeConfig, +} from "./config.js"; export { - generate, - generateWithTools, - stream, - predict, - scoreTokens, - preload, - abort, - resume, - onStatus, - registerLocalModel, - computeImportance, - computeAttentionWeights, - extractFeatures, - extractCutFeatures, - decodeTokens, - probeAttention, -} from "./client.js" + generate, + generateWithTools, + stream, + predict, + scoreTokens, + preload, + abort, + resume, + onStatus, + registerLocalModel, + computeImportance, + computeAttentionWeights, + extractFeatures, + extractCutFeatures, + decodeTokens, + probeAttention, +} from "./client.js"; -export {dom, popup} from "./picker.js" +export { dom, popup } from "./picker.js"; -export {builtinSupported, builtinAvailability} from "./builtin.js" +export { + builtinSupported, + builtinAvailability, + builtinGenerate, +} from "./builtin.js"; + +// Construct this library's compute worker. This has to live in the library: +// `new URL("./worker.js", import.meta.url)` resolves against this module's own +// URL, so it finds the sibling worker.js wherever the library is served from, +// and bundlers only emit the worker chunk when they see this exact literal. +// +// import { createWorker } from "@chee/patchwork-llm"; +// const worker = createWorker(); +// worker.onmessage = (e) => console.log(e.data.models); +// worker.postMessage({ type: "list-local-models" }); +export const createWorker = () => + new Worker(new URL("./worker.js", import.meta.url), { type: "module" }); // LLM tools (user-defined tools the model can be given) export { - createLLMTool, - createToolFile, - LLMToolDatatype, - sanitizeToolName, - resolveTools, - toToolSchemas, - buildToolsSystem, - parseToolCalls, - loadHandler, - runTool, - runHandlerSandboxed, - // saved prompts (system + pre), same doc shape as tools - createPromptDoc, - resolvePromptDocs, - resolvePromptText, - resolveCfgPrompts, - LLMSystemPromptDatatype, - LLMPrePromptDatatype, - // folders + one-time migration - ensureFolderUrl, - addToFolder, - removeFromFolder, - migrateConfig, -} from "./tools.js" + createLLMTool, + createToolFile, + LLMToolDatatype, + sanitizeToolName, + resolveTools, + toToolSchemas, + buildToolsSystem, + parseToolCalls, + loadHandler, + runTool, + runHandlerSandboxed, + // saved prompts (system + pre), same doc shape as tools + createPromptDoc, + resolvePromptDocs, + resolvePromptText, + resolveCfgPrompts, + LLMSystemPromptDatatype, + LLMPrePromptDatatype, + // folders + one-time migration + ensureFolderUrl, + addToFolder, + removeFromFolder, + migrateConfig, +} from "./tools.js"; // Registers on import. export { - PatchworkLLMConfigProvider, - definePatchworkLLMConfigProvider, -} from "./provider.js" + PatchworkLLMConfigProvider, + definePatchworkLLMConfigProvider, +} from "./provider.js"; // Built-in prompt templates -export {PROMPT_TEMPLATES} from "./templates.js" +export { PROMPT_TEMPLATES } from "./templates.js"; diff --git a/libraries/llm/pnpm-lock.yaml b/libraries/llm/pnpm-lock.yaml index dc251f69..fa0a70c3 100644 --- a/libraries/llm/pnpm-lock.yaml +++ b/libraries/llm/pnpm-lock.yaml @@ -24,8 +24,8 @@ packages: '@automerge/automerge-repo@2.5.6': resolution: {integrity: sha512-ZXM6TOAwm192g3+zIxYvlB+Z3O00NP+psErOwvbSype8fFO+dhc8tB/jPwfZJqmn1ULUz5w7gssKEynwcYFRSA==} - '@automerge/automerge@3.4.0': - resolution: {integrity: sha512-THmghtTNGGt2xsI0pM3o1i3PM8oZKcYFgOj25FOzW7l6e94SQOivNtCwy6xc0I8hVJsQSSotoBNs+yk/9hM2dg==} + '@automerge/automerge@3.4.1': + resolution: {integrity: sha512-zsZpbs/iDPvp+ZojIYd+gxmbcPVz2Xbkcx778G8zrt3E0zS+6saHJOm666lOuZyNRlTV4wHw9qzGTKueedeCsQ==} '@cbor-extract/cbor-extract-darwin-arm64@2.2.2': resolution: {integrity: sha512-ZKZ/F8US7JR92J4DMct6cLW/Y66o2K576+zjlEN/MevH70bFIsB10wkZEQPLzl2oNh2SMGy55xpJ9JoBRl5DOA==} @@ -79,8 +79,8 @@ packages: resolution: {integrity: sha512-hlSxxI9XO2yQfe9g6msd3g4xCfDqK5T5P0fRMLuaLHhxn4ViPrm+a+MUfhrvH2W962RGxcBwEGzLQyjbDG1gng==} hasBin: true - cbor-x@1.6.5: - resolution: {integrity: sha512-yO64CxnSh6kp+pHNRK9IfwnMvCB+c8HvmUjQY/9l9YRF0/cAPka/tUHLwS64QqUpFCq3/OtbKziVJYXH2EaRig==} + cbor-x@1.6.6: + resolution: {integrity: sha512-8QiD9PGOxyQHo7s2pzwTBH6lTjqekxPdl9Aq6fXvZgCuCJHOht1puDEA/fTr6mciB76c+M+Gi0qT2i1a4pm4Wg==} debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} @@ -118,25 +118,25 @@ packages: deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true - xstate@5.32.5: - resolution: {integrity: sha512-ULazi1oe6wGrXl0Frb6otSlkm5HLifbbVTkMk5kkSKqz4TkxJaVpnl6jOJwKeid3ORPxYyZQgNLUSYX9q65SIA==} + xstate@5.32.6: + resolution: {integrity: sha512-WfA8WNrh6r9osuGwVm+aIPM4jmMW2LKHV1Yv9thYpOtL4HVF/kobh95K/O8v2jDCpDmP2EoY+6uvuqHXCZ6ZLw==} snapshots: '@automerge/automerge-repo@2.5.6': dependencies: - '@automerge/automerge': 3.4.0 + '@automerge/automerge': 3.4.1 bs58check: 3.0.1 - cbor-x: 1.6.5 + cbor-x: 1.6.6 debug: 4.4.3 eventemitter3: 5.0.4 fast-sha256: 1.3.0 uuid: 9.0.1 - xstate: 5.32.5 + xstate: 5.32.6 transitivePeerDependencies: - supports-color - '@automerge/automerge@3.4.0': {} + '@automerge/automerge@3.4.1': {} '@cbor-extract/cbor-extract-darwin-arm64@2.2.2': optional: true @@ -185,7 +185,7 @@ snapshots: '@cbor-extract/cbor-extract-win32-x64': 2.2.2 optional: true - cbor-x@1.6.5: + cbor-x@1.6.6: optionalDependencies: cbor-extract: 2.2.2 @@ -211,4 +211,4 @@ snapshots: uuid@9.0.1: {} - xstate@5.32.5: {} + xstate@5.32.6: {} From 8f4dc736f0effa5918486c69e43e478b0cebaa6b Mon Sep 17 00:00:00 2001 From: grjte Date: Wed, 16 Sep 2026 11:25:19 +0100 Subject: [PATCH 2/2] refactor: llm library for use with patchwork-worker without dup --- libraries/llm/.gitignore | 1 + libraries/llm/README.md | 26 ++++++++ libraries/llm/client.js | 72 +++++--------------- libraries/llm/index.js | 9 +++ libraries/llm/package.json | 6 +- libraries/llm/request.js | 128 ++++++++++++++++++++++++++++++++++++ libraries/llm/tsconfig.json | 1 + 7 files changed, 186 insertions(+), 57 deletions(-) create mode 100644 libraries/llm/request.js diff --git a/libraries/llm/.gitignore b/libraries/llm/.gitignore index a7c47537..f372293c 100644 --- a/libraries/llm/.gitignore +++ b/libraries/llm/.gitignore @@ -1 +1,2 @@ types/ +.pushwork diff --git a/libraries/llm/README.md b/libraries/llm/README.md index 0e7a68cd..481aa0fb 100644 --- a/libraries/llm/README.md +++ b/libraries/llm/README.md @@ -102,6 +102,32 @@ Pass a stable `sessionKey` (e.g. a doc URL) to `generate`/`stream`; after a reload, `resume(sessionKey, { onToken, onDone })` re-attaches to the still-running stream in the worker. +### Request preparation (`request.js`) + +`generate()` is two halves: preparing the request and posting it to the worker. +The first half is exported so a host-side worker spec (one that serves this +library over a stream to sandboxed tools) prepares requests exactly the way +`generate()` does: + +```js +import { prepareGenerate, buildGeneratePayload } from "@patchwork/llm" + +const { cfg, config, extraSystem, builtin, input } = await prepareGenerate(cfg0, { + messages, // chat messages or a string + system, // extra system prompt, already provider-resolved + tools, // tool descriptors, already filtered + continuation, // treat a string as a raw continuation + overrides, // passed to callConfig verbatim +}) +if (builtin) { /* run builtinGenerate(input, { system: effectiveSystem(cfg, extraSystem), … }) */ } +else worker.postMessage(buildGeneratePayload(config, input, { id, sessionKey })) +``` + +Resolving a provider-conditional `system` map, filtering tools by the user's +`toolToggles`, and choosing which `overrides` to forward are the caller's job: +`callConfig` honours provider / apiKey / model / url overrides, so a host serving +untrusted tools passes only sampling knobs. + ## Events reference | event | fields | local | openrouter | ollama | diff --git a/libraries/llm/client.js b/libraries/llm/client.js index 879ff1ac..6914109c 100644 --- a/libraries/llm/client.js +++ b/libraries/llm/client.js @@ -13,7 +13,8 @@ import {readConfig, ensureConfig, callConfig, applyPrompts, effectiveSystem} from "./config.js" import {builtinGenerate} from "./builtin.js" -import {resolveTools, toToolSchemas, buildToolsSystem, parseToolCalls, runTool, resolveCfgPrompts, sanitizeToolName} from "./tools.js" +import {resolveTools, buildToolsSystem, parseToolCalls, runTool, resolveCfgPrompts, sanitizeToolName} from "./tools.js" +import {prepareGenerate, buildGeneratePayload, NATIVE_TOOL_PROVIDERS, TEMPLATE_TOOL_PROVIDERS} from "./request.js" /** * Per-call options. A superset of every option any exported function accepts; @@ -66,16 +67,7 @@ import {resolveTools, toToolSchemas, buildToolsSystem, parseToolCalls, runTool, /** @typedef {{post: (m:any)=>void}} Connection */ -/** CallConfig plus the extra mutable fields the client tacks on per-call. - * @typedef {import("./config.js").CallConfig & {tools?:any, toolSystem?:string, continuation?:boolean}} CallConfigExt */ - -/** @typedef {{type:string, id:string, sessionKey:string, provider:import("./config.js").ProviderId, config:import("./config.js").CallConfig, text?:string, messages?:any}} GeneratePayload */ - -// Providers with real function-calling APIs (the worker passes tool schemas and -// parses structured tool_calls). Everything else (local transformers, Chrome -// built-in) uses the XML prompt convention, parsed from the text. -const NATIVE_TOOL_PROVIDERS = new Set(["openrouter", "ollama", "webllm"]) -const TEMPLATE_TOOL_PROVIDERS = new Set(["local"]) +/** @typedef {import("./request.js").CallConfigExt} CallConfigExt */ /** @type {Connection|null} */ let connection = null @@ -196,34 +188,21 @@ function getConnection() { */ export async function generate(messages, opts = {}) { const cfg0 = opts.config ?? (await ensureConfig(opts.scope)) - // Resolve the selected system/pre prompt docs → their text. repo.find is - // cached, so this is cheap after first load. - const cfg = await resolveCfgPrompts(cfg0) - /** @type {CallConfigExt} */ - const config = callConfig(/** @type {any} */ (cfg), /** @type {any} */ (opts)) - - // Tools: native providers get JSON schemas on `config.tools`; the rest get the - // XML convention prepended to the system prompt (parsed from text). - const hasTools = Array.isArray(opts.tools) && opts.tools.length > 0 - const native = hasTools && NATIVE_TOOL_PROVIDERS.has(config.provider) - const templated = hasTools && TEMPLATE_TOOL_PROVIDERS.has(config.provider) - if (native || templated) config.tools = toToolSchemas(opts.tools) - if (templated) config.toolSystem = buildToolsSystem(opts.tools) - const extraSystem = - hasTools && !native && !templated - ? [buildToolsSystem(opts.tools), opts.system].filter(Boolean).join("\n\n") - : opts.system + // Prompt resolution, CallConfig, the tools decision, the builtin detour and + // the chat-vs-continuation input shape all live in request.js, shared with + // host-side worker specs. The whole opts is passed as overrides: a same-realm + // caller legitimately owns provider/model/apiKey overrides. + const {cfg, config, extraSystem, builtin, input} = await prepareGenerate(cfg0, { + messages, + system: opts.system, + tools: opts.tools, + continuation: opts.continuation, + overrides: opts, + }) // Built-in (Chrome Prompt API) runs on the main thread, not the worker. - if (config.provider === "builtin") { - const pre = cfg.resolved?.pre || "" - const text = - typeof messages === "string" - ? pre - ? pre + "\n\n" + messages - : messages - : messages - return builtinGenerate(text, { + if (builtin) { + return builtinGenerate(input, { temperature: config.temperature, topK: config.topK, system: effectiveSystem(/** @type {any} */ (cfg), extraSystem), @@ -233,19 +212,6 @@ export async function generate(messages, opts = {}) { }).then((t) => ({text: t, toolCalls: null, stats: null})) } - // A string input is CHAT by default — wrapped as a user turn, so instruct/chat - // models respond normally and the system prompt applies. It's a raw - // CONTINUATION only when opts.continuation is set: raw-fed for - // local/webllm/ollama, and CONTINUE_SYS-framed for chat-only OpenRouter (see - // the worker). Loom passes continuation:true; other callers get plain chat. - const asContinuation = !!opts.continuation && typeof messages === "string" - const prepared = asContinuation - ? messages - : typeof messages === "string" - ? [{role: "user", content: messages}] - : messages - // Prepend the configured system + pre-prompt (and any tool-supplied system). - const input = applyPrompts(prepared, /** @type {any} */ (cfg), extraSystem) const conn = getConnection() const id = nextId() const sessionKey = opts.sessionKey || id @@ -296,11 +262,7 @@ export async function generate(messages, opts = {}) { opts.signal.addEventListener("abort", onAbort) } // A string is a raw continuation prompt; an array is chat messages. - /** @type {GeneratePayload} */ - const payload = {type: "generate", id, sessionKey, provider: config.provider, config} - if (typeof input === "string") payload.text = input - else payload.messages = input - conn.post(payload) + conn.post(buildGeneratePayload(config, input, {id, sessionKey})) }) } diff --git a/libraries/llm/index.js b/libraries/llm/index.js index bbbb1d31..4cead657 100644 --- a/libraries/llm/index.js +++ b/libraries/llm/index.js @@ -91,6 +91,15 @@ export { export const createWorker = () => new Worker(new URL("./worker.js", import.meta.url), { type: "module" }); +// Transport-neutral request preparation, shared by generate() and by +// host-side worker specs that serve this library over a stream. +export { + prepareGenerate, + buildGeneratePayload, + NATIVE_TOOL_PROVIDERS, + TEMPLATE_TOOL_PROVIDERS, +} from "./request.js"; + // LLM tools (user-defined tools the model can be given) export { createLLMTool, diff --git a/libraries/llm/package.json b/libraries/llm/package.json index 9b2a9e08..84776ea7 100644 --- a/libraries/llm/package.json +++ b/libraries/llm/package.json @@ -1,6 +1,6 @@ { "name": "@chee/patchwork-llm", - "version": "0.2.1", + "version": "0.3.0", "description": "LLM toolkit for Patchwork tools: a model picker, a refresh-surviving SharedWorker that runs local (transformers.js) / OpenRouter / Ollama generation, and a streaming API that carries rich telemetry — next-token predictions, temperature, tokens/sec — alongside the text so you can build UIs that show how the model thinks.", "type": "module", "main": "index.js", @@ -17,13 +17,15 @@ }, "scripts": { "build": "pnpm build:types", - "build:types": "tsc" + "build:types": "tsc", + "push": "pnpm build && pushwork sync" }, "files": [ "types", "index.js", "config.js", "client.js", + "request.js", "worker.js", "picker.js", "tools.js", diff --git a/libraries/llm/request.js b/libraries/llm/request.js new file mode 100644 index 00000000..5343843b --- /dev/null +++ b/libraries/llm/request.js @@ -0,0 +1,128 @@ +/** + * Request preparation — the transport-neutral half of a `generate` call. + * + * Everything between "here is a resolved config and what the caller wants" and + * "here is the exact payload the worker understands" lives here, once: prompt + * resolution, the flat CallConfig, the native-vs-templated tool decision, the + * built-in (Chrome Prompt API) detour, and the chat-vs-continuation input shape. + * + * Two callers share it and must stay in step: + * - client.js `generate()` — same realm, posts straight to this library's worker. + * - a host-side worker spec (e.g. llm-host's worker-spec.js) — receives request + * frames over a stream and posts to the worker it runs. + * + * What is deliberately NOT here, because it is caller policy rather than + * preparation: resolving a provider-conditional `system` map, filtering tools by + * the user's `toolToggles`, and deciding which `overrides` reach `callConfig` + * (client.js passes the whole opts; a host must pass only sampling knobs, since + * callConfig also honours provider/apiKey/model/url). + */ + +import {callConfig, applyPrompts} from "./config.js" +import {toToolSchemas, buildToolsSystem, resolveCfgPrompts} from "./tools.js" + +/** + * CallConfig plus the extra mutable fields tacked on per call. + * @typedef {import("./config.js").CallConfig & {tools?:any, toolSystem?:string, continuation?:boolean}} CallConfigExt + */ + +/** + * The `generate` message the worker accepts. A string `text` is a raw + * continuation prompt; `messages` is chat. + * @typedef {{type:string, id:string, sessionKey:string, provider:import("./config.js").ProviderId, config:import("./config.js").CallConfig, text?:string, messages?:any}} GeneratePayload + */ + +// Providers with real function-calling APIs (the worker passes tool schemas and +// parses structured tool_calls). Everything else (local transformers, Chrome +// built-in) uses the XML prompt convention, parsed from the text. +export const NATIVE_TOOL_PROVIDERS = new Set(["openrouter", "ollama", "webllm"]) +export const TEMPLATE_TOOL_PROVIDERS = new Set(["local"]) + +/** + * @typedef {Object} PrepareOpts + * @property {any[]|string} messages chat messages, or a string + * @property {string} [system] extra system prompt, already provider-resolved + * @property {any[]} [tools] tool descriptors, already filtered + * @property {boolean} [continuation] treat a string input as a raw continuation + * @property {any} [overrides] passed to callConfig verbatim (see header) + * + * @typedef {Object} PreparedGenerate + * @property {any} cfg config with prompt docs resolved (`cfg.resolved`) + * @property {CallConfigExt} config the flat per-call config the worker receives + * @property {string|undefined} extraSystem + * @property {boolean} builtin provider is "builtin": run builtinGenerate(input, …) + * in-realm instead of posting to the worker + * @property {any} input builtin: the pre-joined text/messages; + * otherwise applyPrompts()'d text or messages + */ + +/** + * Prepare a generate request from an unresolved config and the caller's intent. + * + * @param {any} cfg0 an LLMConfig (e.g. from ensureConfig), prompts not yet resolved + * @param {PrepareOpts} opts + * @returns {Promise} + */ +export async function prepareGenerate(cfg0, {messages, system, tools, continuation, overrides = {}}) { + // Resolve the selected system/pre prompt docs → their text. repo.find is + // cached, so this is cheap after first load. + const cfg = await resolveCfgPrompts(cfg0) + /** @type {CallConfigExt} */ + const config = callConfig(/** @type {any} */ (cfg), /** @type {any} */ (overrides)) + + // Tools: native providers get JSON schemas on `config.tools`; the rest get the + // XML convention prepended to the system prompt (parsed from text). + const hasTools = Array.isArray(tools) && tools.length > 0 + const native = hasTools && NATIVE_TOOL_PROVIDERS.has(config.provider) + const templated = hasTools && TEMPLATE_TOOL_PROVIDERS.has(config.provider) + if (native || templated) config.tools = toToolSchemas(tools) + if (templated) config.toolSystem = buildToolsSystem(tools) + const extraSystem = + hasTools && !native && !templated + ? [buildToolsSystem(tools), system].filter(Boolean).join("\n\n") + : system + + // Built-in (Chrome Prompt API) runs in the caller's realm, not the worker. + // The caller runs builtinGenerate(input, {system: effectiveSystem(cfg, + // extraSystem), …}) with its own callbacks. + if (config.provider === "builtin") { + const pre = cfg.resolved?.pre || "" + const input = + typeof messages === "string" + ? pre + ? pre + "\n\n" + messages + : messages + : messages + return {cfg, config, extraSystem, builtin: true, input} + } + + // A string input is CHAT by default — wrapped as a user turn, so instruct/chat + // models respond normally and the system prompt applies. It's a raw + // CONTINUATION only when asked: raw-fed for local/webllm/ollama, and + // CONTINUE_SYS-framed for chat-only OpenRouter (see the worker). + const asContinuation = !!continuation && typeof messages === "string" + const prepared = asContinuation + ? messages + : typeof messages === "string" + ? [{role: "user", content: messages}] + : messages + // Prepend the configured system + pre-prompt (and any tool-supplied system). + const input = applyPrompts(prepared, /** @type {any} */ (cfg), extraSystem) + return {cfg, config, extraSystem, builtin: false, input} +} + +/** + * The `generate` message for the worker, from a prepared request. + * + * @param {CallConfigExt} config + * @param {any} input string (raw continuation) or chat messages + * @param {{id: string, sessionKey: string}} ids + * @returns {GeneratePayload} + */ +export function buildGeneratePayload(config, input, {id, sessionKey}) { + /** @type {GeneratePayload} */ + const payload = {type: "generate", id, sessionKey, provider: config.provider, config} + if (typeof input === "string") payload.text = input + else payload.messages = input + return payload +} diff --git a/libraries/llm/tsconfig.json b/libraries/llm/tsconfig.json index 5dc1f2d0..1f5e752a 100644 --- a/libraries/llm/tsconfig.json +++ b/libraries/llm/tsconfig.json @@ -15,6 +15,7 @@ "index.js", "config.js", "client.js", + "request.js", "worker.js", "picker.js", "tools.js",