llama-cpp-pro 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. package/CHANGELOG.md +295 -0
  2. package/LICENSE +21 -0
  3. package/LlamaCpp.podspec +33 -0
  4. package/LlamaCppCapacitor.podspec +33 -0
  5. package/Package.swift +29 -0
  6. package/README.md +93 -0
  7. package/android/build.gradle +88 -0
  8. package/android/src/main/AndroidManifest.xml +4 -0
  9. package/android/src/main/CMakeLists-arm64.txt +138 -0
  10. package/android/src/main/CMakeLists-x86_64.txt +141 -0
  11. package/android/src/main/CMakeLists.txt +138 -0
  12. package/android/src/main/java/ai/annadata/plugin/capacitor/LlamaCpp.java +1340 -0
  13. package/android/src/main/java/ai/annadata/plugin/capacitor/LlamaCppPlugin.java +814 -0
  14. package/android/src/main/java/ai/annadata/plugin/capacitor/ModelAdmissionController.java +214 -0
  15. package/android/src/main/jni-chat-session.cpp +261 -0
  16. package/android/src/main/jni-lora.cpp +197 -0
  17. package/android/src/main/jni-multimodal.cpp +167 -0
  18. package/android/src/main/jni-tts.cpp +290 -0
  19. package/android/src/main/jni-utils.h +148 -0
  20. package/android/src/main/jni.cpp +1808 -0
  21. package/android/src/main/jniLibs/arm64-v8a/libllama-cpp-arm64.so +0 -0
  22. package/android/src/main/res/.gitkeep +0 -0
  23. package/build-native.sh +280 -0
  24. package/cmake/desktop-metal-embed.cmake +30 -0
  25. package/cmake/desktop-sources.cmake +100 -0
  26. package/cmake/ggml-backends.cmake +44 -0
  27. package/cpp/LICENSE +21 -0
  28. package/cpp/README.md +15 -0
  29. package/cpp/anyascii.c +22223 -0
  30. package/cpp/anyascii.h +42 -0
  31. package/cpp/cap-completion.cpp +942 -0
  32. package/cpp/cap-completion.h +127 -0
  33. package/cpp/cap-embedding.cpp +193 -0
  34. package/cpp/cap-embedding.h +35 -0
  35. package/cpp/cap-ios-bridge.cpp +1810 -0
  36. package/cpp/cap-ios-bridge.h +61 -0
  37. package/cpp/cap-llama.cpp +412 -0
  38. package/cpp/cap-llama.h +161 -0
  39. package/cpp/cap-mtmd.hpp +602 -0
  40. package/cpp/cap-native-server.cpp +1095 -0
  41. package/cpp/cap-native-server.h +40 -0
  42. package/cpp/cap-tts.cpp +591 -0
  43. package/cpp/cap-tts.h +59 -0
  44. package/cpp/cap-wasm-fs.cpp +156 -0
  45. package/cpp/cap-wasm-jspi.cpp +19 -0
  46. package/cpp/cap-wasm-jspi.h +30 -0
  47. package/cpp/cap-wasm-vfs.cpp +22 -0
  48. package/cpp/chat-parser.cpp +393 -0
  49. package/cpp/chat-parser.h +120 -0
  50. package/cpp/chat.cpp +2315 -0
  51. package/cpp/chat.h +221 -0
  52. package/cpp/common.cpp +1664 -0
  53. package/cpp/common.h +744 -0
  54. package/cpp/ggml-alloc.c +1028 -0
  55. package/cpp/ggml-alloc.h +76 -0
  56. package/cpp/ggml-backend-impl.h +255 -0
  57. package/cpp/ggml-backend-reg.cpp +600 -0
  58. package/cpp/ggml-backend.cpp +2121 -0
  59. package/cpp/ggml-backend.h +354 -0
  60. package/cpp/ggml-common.h +1878 -0
  61. package/cpp/ggml-cpp.h +39 -0
  62. package/cpp/ggml-cpu/amx/amx.cpp +221 -0
  63. package/cpp/ggml-cpu/amx/amx.h +8 -0
  64. package/cpp/ggml-cpu/amx/common.h +91 -0
  65. package/cpp/ggml-cpu/amx/mmq.cpp +2512 -0
  66. package/cpp/ggml-cpu/amx/mmq.h +10 -0
  67. package/cpp/ggml-cpu/arch/arm/cpu-feats.cpp +94 -0
  68. package/cpp/ggml-cpu/arch/arm/quants.c +3650 -0
  69. package/cpp/ggml-cpu/arch/arm/repack.cpp +1891 -0
  70. package/cpp/ggml-cpu/arch/x86/cpu-feats.cpp +327 -0
  71. package/cpp/ggml-cpu/arch/x86/quants.c +3820 -0
  72. package/cpp/ggml-cpu/arch/x86/repack.cpp +6307 -0
  73. package/cpp/ggml-cpu/arch-fallback.h +215 -0
  74. package/cpp/ggml-cpu/binary-ops.cpp +158 -0
  75. package/cpp/ggml-cpu/binary-ops.h +16 -0
  76. package/cpp/ggml-cpu/common.h +73 -0
  77. package/cpp/ggml-cpu/ggml-cpu-impl.h +559 -0
  78. package/cpp/ggml-cpu/ggml-cpu.c +3578 -0
  79. package/cpp/ggml-cpu/ggml-cpu.cpp +672 -0
  80. package/cpp/ggml-cpu/ops.cpp +10587 -0
  81. package/cpp/ggml-cpu/ops.h +114 -0
  82. package/cpp/ggml-cpu/quants.c +1193 -0
  83. package/cpp/ggml-cpu/quants.h +97 -0
  84. package/cpp/ggml-cpu/repack.cpp +1982 -0
  85. package/cpp/ggml-cpu/repack.h +120 -0
  86. package/cpp/ggml-cpu/simd-mappings.h +1184 -0
  87. package/cpp/ggml-cpu/traits.cpp +36 -0
  88. package/cpp/ggml-cpu/traits.h +38 -0
  89. package/cpp/ggml-cpu/unary-ops.cpp +186 -0
  90. package/cpp/ggml-cpu/unary-ops.h +28 -0
  91. package/cpp/ggml-cpu/vec.cpp +348 -0
  92. package/cpp/ggml-cpu/vec.h +1121 -0
  93. package/cpp/ggml-cpu.h +145 -0
  94. package/cpp/ggml-impl.h +622 -0
  95. package/cpp/ggml-metal-impl.h +688 -0
  96. package/cpp/ggml-metal.h +66 -0
  97. package/cpp/ggml-metal.m +6833 -0
  98. package/cpp/ggml-metal.metal +10754 -0
  99. package/cpp/ggml-opt.cpp +1093 -0
  100. package/cpp/ggml-opt.h +256 -0
  101. package/cpp/ggml-quants.c +5324 -0
  102. package/cpp/ggml-quants.h +106 -0
  103. package/cpp/ggml-threading.cpp +12 -0
  104. package/cpp/ggml-threading.h +14 -0
  105. package/cpp/ggml.c +7108 -0
  106. package/cpp/ggml.h +2492 -0
  107. package/cpp/gguf.cpp +1358 -0
  108. package/cpp/gguf.h +202 -0
  109. package/cpp/json-partial.cpp +256 -0
  110. package/cpp/json-partial.h +38 -0
  111. package/cpp/json-schema-to-grammar.cpp +985 -0
  112. package/cpp/json-schema-to-grammar.h +21 -0
  113. package/cpp/llama-adapter.cpp +388 -0
  114. package/cpp/llama-adapter.h +76 -0
  115. package/cpp/llama-arch.cpp +2355 -0
  116. package/cpp/llama-arch.h +499 -0
  117. package/cpp/llama-batch.cpp +875 -0
  118. package/cpp/llama-batch.h +160 -0
  119. package/cpp/llama-chat.cpp +783 -0
  120. package/cpp/llama-chat.h +65 -0
  121. package/cpp/llama-context.cpp +2788 -0
  122. package/cpp/llama-context.h +306 -0
  123. package/cpp/llama-cparams.cpp +5 -0
  124. package/cpp/llama-cparams.h +41 -0
  125. package/cpp/llama-cpp.h +30 -0
  126. package/cpp/llama-grammar.cpp +1229 -0
  127. package/cpp/llama-grammar.h +173 -0
  128. package/cpp/llama-graph.cpp +1891 -0
  129. package/cpp/llama-graph.h +810 -0
  130. package/cpp/llama-hparams.cpp +180 -0
  131. package/cpp/llama-hparams.h +233 -0
  132. package/cpp/llama-impl.cpp +167 -0
  133. package/cpp/llama-impl.h +61 -0
  134. package/cpp/llama-io.cpp +15 -0
  135. package/cpp/llama-io.h +35 -0
  136. package/cpp/llama-kv-cache-iswa.cpp +318 -0
  137. package/cpp/llama-kv-cache-iswa.h +135 -0
  138. package/cpp/llama-kv-cache.cpp +2059 -0
  139. package/cpp/llama-kv-cache.h +374 -0
  140. package/cpp/llama-kv-cells.h +491 -0
  141. package/cpp/llama-memory-hybrid.cpp +258 -0
  142. package/cpp/llama-memory-hybrid.h +137 -0
  143. package/cpp/llama-memory-recurrent.cpp +1146 -0
  144. package/cpp/llama-memory-recurrent.h +179 -0
  145. package/cpp/llama-memory.cpp +59 -0
  146. package/cpp/llama-memory.h +119 -0
  147. package/cpp/llama-mmap.cpp +609 -0
  148. package/cpp/llama-mmap.h +68 -0
  149. package/cpp/llama-model-loader.cpp +1166 -0
  150. package/cpp/llama-model-loader.h +170 -0
  151. package/cpp/llama-model-saver.cpp +282 -0
  152. package/cpp/llama-model-saver.h +37 -0
  153. package/cpp/llama-model.cpp +19061 -0
  154. package/cpp/llama-model.h +491 -0
  155. package/cpp/llama-sampling.cpp +2575 -0
  156. package/cpp/llama-sampling.h +32 -0
  157. package/cpp/llama-vocab.cpp +3792 -0
  158. package/cpp/llama-vocab.h +176 -0
  159. package/cpp/llama.cpp +358 -0
  160. package/cpp/llama.h +1373 -0
  161. package/cpp/log.cpp +428 -0
  162. package/cpp/log.h +103 -0
  163. package/cpp/minja/chat-template.hpp +550 -0
  164. package/cpp/minja/minja.hpp +3009 -0
  165. package/cpp/nlohmann/json.hpp +25526 -0
  166. package/cpp/nlohmann/json_fwd.hpp +187 -0
  167. package/cpp/regex-partial.cpp +204 -0
  168. package/cpp/regex-partial.h +56 -0
  169. package/cpp/sampling.cpp +579 -0
  170. package/cpp/sampling.h +107 -0
  171. package/cpp/tools/mtmd/clip-impl.h +473 -0
  172. package/cpp/tools/mtmd/clip.cpp +4322 -0
  173. package/cpp/tools/mtmd/clip.h +106 -0
  174. package/cpp/tools/mtmd/miniaudio/miniaudio.h +93468 -0
  175. package/cpp/tools/mtmd/mtmd-audio.cpp +769 -0
  176. package/cpp/tools/mtmd/mtmd-audio.h +47 -0
  177. package/cpp/tools/mtmd/mtmd-helper.cpp +460 -0
  178. package/cpp/tools/mtmd/mtmd-helper.h +95 -0
  179. package/cpp/tools/mtmd/mtmd.cpp +1066 -0
  180. package/cpp/tools/mtmd/mtmd.h +302 -0
  181. package/cpp/tools/mtmd/stb/stb_image.h +7988 -0
  182. package/cpp/unicode-data.cpp +7034 -0
  183. package/cpp/unicode-data.h +20 -0
  184. package/cpp/unicode.cpp +1061 -0
  185. package/cpp/unicode.h +68 -0
  186. package/cpp/vendor/cpp-httplib/httplib.cpp +16509 -0
  187. package/cpp/vendor/cpp-httplib/httplib.h +3883 -0
  188. package/desktop/electron-builder.config.cjs +157 -0
  189. package/desktop/entitlements.mac.plist +12 -0
  190. package/desktop/package.json +11 -0
  191. package/desktop/resolve-package-root.cjs +88 -0
  192. package/desktop/src/main/backend-selector.cjs +148 -0
  193. package/desktop/src/main/gpu-probe.cjs +142 -0
  194. package/desktop/src/main/index.cjs +58 -0
  195. package/desktop/src/main/ipc-handlers.cjs +212 -0
  196. package/desktop/src/main/model-store.cjs +50 -0
  197. package/desktop/src/main/preload.cjs +39 -0
  198. package/desktop/src/main/sidecar-client.cjs +76 -0
  199. package/desktop/src/main/sidecar-manager.cjs +364 -0
  200. package/dist/docs.json +14357 -0
  201. package/dist/esm/definitions.d.ts +731 -0
  202. package/dist/esm/definitions.js +2 -0
  203. package/dist/esm/definitions.js.map +1 -0
  204. package/dist/esm/desktop.d.ts +37 -0
  205. package/dist/esm/desktop.js +133 -0
  206. package/dist/esm/desktop.js.map +1 -0
  207. package/dist/esm/index.d.ts +200 -0
  208. package/dist/esm/index.js +612 -0
  209. package/dist/esm/index.js.map +1 -0
  210. package/dist/esm/isomorphic/desktop.runtime.d.ts +37 -0
  211. package/dist/esm/isomorphic/desktop.runtime.js +36 -0
  212. package/dist/esm/isomorphic/desktop.runtime.js.map +1 -0
  213. package/dist/esm/isomorphic/errors.d.ts +6 -0
  214. package/dist/esm/isomorphic/errors.js +9 -0
  215. package/dist/esm/isomorphic/errors.js.map +1 -0
  216. package/dist/esm/isomorphic/model.admission.d.ts +17 -0
  217. package/dist/esm/isomorphic/model.admission.js +27 -0
  218. package/dist/esm/isomorphic/model.admission.js.map +1 -0
  219. package/dist/esm/isomorphic/model.scheduler.d.ts +31 -0
  220. package/dist/esm/isomorphic/model.scheduler.js +95 -0
  221. package/dist/esm/isomorphic/model.scheduler.js.map +1 -0
  222. package/dist/esm/isomorphic/provider.desktop.d.ts +40 -0
  223. package/dist/esm/isomorphic/provider.desktop.js +411 -0
  224. package/dist/esm/isomorphic/provider.desktop.js.map +1 -0
  225. package/dist/esm/isomorphic/provider.factory.d.ts +2 -0
  226. package/dist/esm/isomorphic/provider.factory.js +16 -0
  227. package/dist/esm/isomorphic/provider.factory.js.map +1 -0
  228. package/dist/esm/isomorphic/provider.interface.d.ts +76 -0
  229. package/dist/esm/isomorphic/provider.interface.js +2 -0
  230. package/dist/esm/isomorphic/provider.interface.js.map +1 -0
  231. package/dist/esm/isomorphic/provider.native.d.ts +18 -0
  232. package/dist/esm/isomorphic/provider.native.js +173 -0
  233. package/dist/esm/isomorphic/provider.native.js.map +1 -0
  234. package/dist/esm/isomorphic/provider.web.d.ts +88 -0
  235. package/dist/esm/isomorphic/provider.web.js +573 -0
  236. package/dist/esm/isomorphic/provider.web.js.map +1 -0
  237. package/dist/esm/isomorphic/sidecar-sse.d.ts +14 -0
  238. package/dist/esm/isomorphic/sidecar-sse.js +76 -0
  239. package/dist/esm/isomorphic/sidecar-sse.js.map +1 -0
  240. package/dist/esm/isomorphic/wasmMemoryCalibration.d.ts +26 -0
  241. package/dist/esm/isomorphic/wasmMemoryCalibration.js +60 -0
  242. package/dist/esm/isomorphic/wasmMemoryCalibration.js.map +1 -0
  243. package/dist/esm/isomorphic/wasmMemoryPolicy.d.ts +55 -0
  244. package/dist/esm/isomorphic/wasmMemoryPolicy.js +93 -0
  245. package/dist/esm/isomorphic/wasmMemoryPolicy.js.map +1 -0
  246. package/dist/esm/storage/manifest.d.ts +13 -0
  247. package/dist/esm/storage/manifest.js +87 -0
  248. package/dist/esm/storage/manifest.js.map +1 -0
  249. package/dist/esm/storage/opfs.store.d.ts +31 -0
  250. package/dist/esm/storage/opfs.store.js +241 -0
  251. package/dist/esm/storage/opfs.store.js.map +1 -0
  252. package/dist/esm/web.d.ts +206 -0
  253. package/dist/esm/web.js +521 -0
  254. package/dist/esm/web.js.map +1 -0
  255. package/dist/esm/workers/async-file.d.ts +13 -0
  256. package/dist/esm/workers/async-file.js +12 -0
  257. package/dist/esm/workers/async-file.js.map +1 -0
  258. package/dist/esm/workers/heapfs.d.ts +55 -0
  259. package/dist/esm/workers/heapfs.js +115 -0
  260. package/dist/esm/workers/heapfs.js.map +1 -0
  261. package/dist/esm/workers/wasm.engine.d.ts +86 -0
  262. package/dist/esm/workers/wasm.engine.js +504 -0
  263. package/dist/esm/workers/wasm.engine.js.map +1 -0
  264. package/dist/esm/workers/worker.protocol.d.ts +160 -0
  265. package/dist/esm/workers/worker.protocol.js +2 -0
  266. package/dist/esm/workers/worker.protocol.js.map +1 -0
  267. package/dist/plugin.cjs +3179 -0
  268. package/dist/plugin.cjs.map +1 -0
  269. package/dist/plugin.js +3181 -0
  270. package/dist/plugin.js.map +1 -0
  271. package/dist/wasm/llama_engine.d.ts +74 -0
  272. package/dist/wasm/llama_engine.js +1829 -0
  273. package/dist/wasm/llama_engine.wasm +0 -0
  274. package/dist/wasm/llama_engine_emscripten.mjs +2 -0
  275. package/dist/wasm/package.json +16 -0
  276. package/dist/workers/llm.worker.js +1226 -0
  277. package/dist/workers/llm.worker.js.map +7 -0
  278. package/extraResources/llama-wasm/llama_engine.d.ts +74 -0
  279. package/extraResources/llama-wasm/llama_engine.js +1829 -0
  280. package/extraResources/llama-wasm/llama_engine.wasm +0 -0
  281. package/extraResources/llama-wasm/llama_engine_emscripten.mjs +2 -0
  282. package/extraResources/llama-wasm/package.json +16 -0
  283. package/extraResources/sidecar/README.md +11 -0
  284. package/extraResources/sidecar/darwin-arm64 +0 -0
  285. package/extraResources/sidecar/darwin-x64 +0 -0
  286. package/ios/CMakeLists-arm64.txt +161 -0
  287. package/ios/CMakeLists-x86_64.txt +188 -0
  288. package/ios/CMakeLists.txt +161 -0
  289. package/ios/Frameworks/llama-cpp.framework/Info.plist +28 -0
  290. package/ios/Frameworks/llama-cpp.framework/llama-cpp +0 -0
  291. package/ios/Sources/LlamaCppCapacitor/LlamaCpp.swift +1365 -0
  292. package/ios/Sources/LlamaCppCapacitor/LlamaCppPlugin.swift +694 -0
  293. package/ios/Sources/LlamaCppCapacitor/LlamaNativeBridge.swift +349 -0
  294. package/ios/Sources/LlamaCppCapacitor/ModelAdmissionController.swift +177 -0
  295. package/ios/embed-metal-shaders.sh +24 -0
  296. package/ios/metal-embed.cmake +29 -0
  297. package/package.json +281 -0
  298. package/scripts/build-js-preserve-wasm.cjs +53 -0
  299. package/scripts/build-sidecar-linux.sh +6 -0
  300. package/scripts/build-sidecar-win.bat +19 -0
  301. package/scripts/build-sidecar.sh +184 -0
  302. package/scripts/embed-llama-ios-app-framework.sh +63 -0
  303. package/scripts/ensure-desktop-sidecar-bundle.cjs +103 -0
  304. package/scripts/ensure-llama-ios-xcframework.sh +108 -0
  305. package/scripts/fix-esm-extensions.cjs +45 -0
  306. package/scripts/prepare-js-dist.cjs +28 -0
  307. package/scripts/stage-desktop-resources.cjs +116 -0
  308. package/sidecar/CMakeLists.txt +192 -0
  309. package/sidecar/cap-sidecar-main.cpp +68 -0
  310. package/types/llama-cpp-pro.d.ts +441 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.web.js","sourceRoot":"","sources":["../../../src/isomorphic/provider.web.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n EmbedRequest,\n EmbedResult,\n GenerateRequest,\n GenerateResult,\n InitializeOptions,\n LlmProvider,\n MemorySnapshot,\n PlatformKind,\n TokenEvent,\n} from './provider.interface';\nimport type { DetokenizeResult, TokenizeResult } from '../workers/wasm.engine';\nimport { LlmError } from './errors';\nimport { DefaultModelScheduler } from './model.scheduler';\nimport {\n WASM_MAX_CONCURRENT_MODELS,\n WASM_POOL_CEILING_BYTES,\n wasmMemoryPressure,\n} from './wasmMemoryPolicy';\nimport {\n ensureModelInOpfs,\n getOpfsUsage,\n} from '../storage/opfs.store';\nimport { getManifestEntry } from '../storage/manifest';\nimport type { WorkerEvent, WorkerRequest } from '../workers/worker.protocol';\n\n// ---------------------------------------------------------------------------\n// Fix #10: Pre-flight capability checks\n// ---------------------------------------------------------------------------\n\n/** Verify that the browser supports everything the web WASM path needs. */\nexport function checkWasmCapabilities(): {\n supported: boolean;\n missing: string[];\n} {\n const missing: string[] = [];\n\n if (typeof WebAssembly !== 'object' || typeof WebAssembly.instantiate !== 'function') {\n missing.push('WebAssembly');\n }\n if (typeof (globalThis as any)?.Worker === 'undefined') {\n missing.push('Worker');\n }\n if (\n typeof (globalThis as any)?.navigator?.storage?.getDirectory !== 'function'\n ) {\n missing.push('OPFS (navigator.storage.getDirectory)');\n }\n\n // WASM threads (needed for multi-threaded inference) require cross-origin\n // isolation. Warn but don't block — single-threaded inference still works.\n const coi = (globalThis as any)?.crossOriginIsolated === true;\n const hasShared = typeof SharedArrayBuffer !== 'undefined';\n if (!coi || !hasShared) {\n // Not a hard failure — single-threaded WASM still functions.\n // Callers can check this separately via checkCrossOriginIsolation().\n }\n\n return { supported: missing.length === 0, missing };\n}\n\n/** Returns true only when COOP/COEP headers are set for WASM threads. */\nexport function checkCrossOriginIsolation(): boolean {\n return (\n (globalThis as any)?.crossOriginIsolated === true &&\n typeof SharedArrayBuffer !== 'undefined'\n );\n}\n\n// ---------------------------------------------------------------------------\n// Worker factory helpers\n// ---------------------------------------------------------------------------\ntype WithoutId<T> = T extends { id: string } ? Omit<T, 'id'> : never;\ntype WorkerRequestWithoutId = WithoutId<WorkerRequest>;\ntype WorkerFactory = () => Worker;\n\ntype PendingRequest = {\n resolve: (value: any) => void;\n reject: (reason?: unknown) => void;\n onToken?: (event: TokenEvent) => void;\n onProgress?: (downloaded: number, total: number) => void;\n};\n\nconst toError = (code: string, message: string, meta?: Record<string, unknown>): LlmError => {\n const knownCodes = [\n 'MODEL_NOT_LOADED',\n 'MODEL_LIMIT_REACHED',\n 'INSUFFICIENT_MEMORY',\n 'MODEL_DOWNLOAD_FAILED',\n 'STORAGE_UNAVAILABLE',\n 'STORAGE_IO_FAILED',\n 'UNSUPPORTED_PLATFORM',\n 'WASM_INIT_FAILED',\n 'NATIVE_PLUGIN_UNAVAILABLE',\n 'INFERENCE_FAILED',\n 'INVALID_REQUEST',\n ];\n const normalizedCode = knownCodes.includes(code) ? (code as any) : 'INFERENCE_FAILED';\n const text =\n message == null || message === ''\n ? 'Unknown inference error'\n : typeof message === 'string'\n ? message\n : String(message);\n return new LlmError(normalizedCode, text, meta);\n};\n\n// ---------------------------------------------------------------------------\n// Fix #11: Cross-browser memory snapshot using storage.estimate() fallback\n// ---------------------------------------------------------------------------\nasync function getMemorySnapshotCrossBrowser(): Promise<MemorySnapshot> {\n // performance.memory is Chromium-only and non-standard. Use it when present,\n // otherwise fall back to storage.estimate() which is universally available.\n const perfMem = (globalThis as any)?.performance?.memory;\n if (perfMem && typeof perfMem.jsHeapSizeLimit === 'number' && perfMem.jsHeapSizeLimit > 0) {\n const totalBytes = Number(perfMem.jsHeapSizeLimit);\n const usedBytes = Number(perfMem.usedJSHeapSize);\n const freeBytes = totalBytes - usedBytes;\n const usedRatio = usedBytes / totalBytes;\n const pressure = usedRatio >= 0.85 ? 'high' : usedRatio >= 0.7 ? 'medium' : 'low';\n return { totalBytes, usedBytes, freeBytes, pressure };\n }\n\n // Fallback: use OPFS storage quota as a coarse proxy for available memory.\n // Not perfect but gives the admission controller a real number to work with\n // on Safari/Firefox instead of always returning undefined (which caused the\n // memory guard to be silently bypassed — fix #11).\n try {\n const est = await (globalThis as any)?.navigator?.storage?.estimate?.();\n if (est && typeof est.quota === 'number' && typeof est.usage === 'number') {\n const totalBytes = est.quota;\n const usedBytes = est.usage;\n const freeBytes = totalBytes - usedBytes;\n const usedRatio = totalBytes > 0 ? usedBytes / totalBytes : 0;\n const pressure = usedRatio >= 0.85 ? 'high' : usedRatio >= 0.7 ? 'medium' : 'low';\n return { totalBytes, usedBytes, freeBytes, pressure };\n }\n } catch {\n // ignore\n }\n\n return { pressure: 'unknown' };\n}\n\n// ---------------------------------------------------------------------------\n// WebProvider\n// ---------------------------------------------------------------------------\nexport class WebProvider implements LlmProvider {\n private static globalWorkerFactory?: WorkerFactory;\n readonly platform: PlatformKind = 'web';\n private loadedModelIds = new Set<string>();\n private worker: Worker | null = null;\n private reqCounter = 0;\n private pending = new Map<string, PendingRequest>();\n // Fix #5: wire the scheduler so admission control is enforced on the web path.\n private scheduler = new DefaultModelScheduler(WASM_MAX_CONCURRENT_MODELS);\n\n constructor(private workerFactoryOverride?: WorkerFactory) {}\n\n static setWorkerFactory(factory?: WorkerFactory): void {\n WebProvider.globalWorkerFactory = factory;\n }\n\n // Fix #15: resolve compiled worker .js first; fall back to .ts for dev.\n private resolveWorkerUrl(): string | URL {\n const customUrl = (globalThis as any)?.__LLAMA_WORKER_URL__;\n if (typeof customUrl === 'string' && customUrl.length > 0) {\n return customUrl;\n }\n try {\n const metaUrl = new Function('return import.meta.url')() as string;\n return new URL('../../dist/workers/llm.worker.js', metaUrl);\n } catch {\n return '/dist/workers/llm.worker.js';\n }\n }\n\n private defaultWorkerFactory(): Worker {\n return new Worker(this.resolveWorkerUrl(), { type: 'module' });\n }\n\n private ensureWorker(): Worker {\n if (this.worker) return this.worker;\n const factory =\n this.workerFactoryOverride ??\n WebProvider.globalWorkerFactory ??\n (() => this.defaultWorkerFactory());\n const worker = factory();\n worker.onmessage = (evt: MessageEvent<WorkerEvent>) => {\n const message = evt.data;\n const request = this.pending.get(message.id);\n if (!request) return;\n\n if (message.type === 'TOKEN') {\n request.onToken?.({\n modelId: message.modelId,\n token: message.token,\n index: message.index,\n });\n return;\n }\n\n if (message.type === 'PROGRESS') {\n request.onProgress?.(message.downloaded, message.total);\n return;\n }\n\n if (message.type === 'RESULT') {\n this.pending.delete(message.id);\n request.resolve(message.payload);\n return;\n }\n\n this.pending.delete(message.id);\n request.reject(toError(message.code, message.message, message.meta));\n };\n worker.onerror = (evt) => {\n const err = toError(\n 'INFERENCE_FAILED',\n `Web worker error: ${evt.message || 'unknown worker error'}`,\n );\n for (const [id, req] of this.pending.entries()) {\n this.pending.delete(id);\n req.reject(err);\n }\n };\n this.worker = worker;\n return worker;\n }\n\n private sendRequest<T>(\n request: WorkerRequestWithoutId,\n onToken?: (event: TokenEvent) => void,\n onProgress?: (downloaded: number, total: number) => void,\n ): Promise<T> {\n const worker = this.ensureWorker();\n const id = `req_${Date.now()}_${this.reqCounter++}`;\n const message = { ...request, id } as WorkerRequest;\n return new Promise<T>((resolve, reject) => {\n this.pending.set(id, { resolve, reject, onToken, onProgress });\n try {\n // Fix #9: no Transferable[] needed — the ArrayBuffer lives in the worker\n worker.postMessage(message);\n } catch (error) {\n this.pending.delete(id);\n reject(\n toError('INFERENCE_FAILED', 'Failed to post request to wasm worker.', {\n cause: String(error),\n requestType: request.type,\n }),\n );\n }\n });\n }\n\n async initialize(opts: InitializeOptions): Promise<void> {\n // Fix #10: gate on capability check before touching the worker.\n // Skip when a custom worker factory is injected (tests / custom hosts).\n const usingCustomWorker =\n !!this.workerFactoryOverride || !!WebProvider.globalWorkerFactory;\n if (!usingCustomWorker) {\n const caps = checkWasmCapabilities();\n if (!caps.supported) {\n throw new LlmError(\n 'UNSUPPORTED_PLATFORM',\n `Missing browser capabilities for WASM inference: ${caps.missing.join(', ')}`,\n { missing: caps.missing },\n );\n }\n }\n await this.sendRequest<{ ok: boolean }>({ type: 'INIT' });\n await this.loadModel(opts);\n }\n\n async loadModel(opts: InitializeOptions): Promise<void> {\n if (!opts.modelId) {\n throw new LlmError('INVALID_REQUEST', 'modelId is required');\n }\n if (this.loadedModelIds.has(opts.modelId)) {\n return;\n }\n\n const existing = await getManifestEntry(opts.modelId);\n if (!existing && !opts.modelUrl) {\n throw new LlmError(\n 'INVALID_REQUEST',\n 'modelUrl is required for first-time web load when model is not cached in OPFS.',\n );\n }\n\n // Download and persist to OPFS if needed (#6: with progress events).\n if (!existing && opts.modelUrl) {\n await ensureModelInOpfs(opts.modelId, opts.modelUrl, opts.onProgress);\n }\n\n // Fix #5: enforce admission control (memory guard + slot limit) BEFORE\n // asking the worker to load, using a real memory snapshot (#11).\n const memory = await getMemorySnapshotCrossBrowser();\n const wasmMemory = await this.fetchWorkerMemory().catch(\n (): Record<string, unknown> => ({}),\n );\n const wasmLinearBytes =\n typeof wasmMemory.wasmLinearBytes === 'number' ? wasmMemory.wasmLinearBytes : undefined;\n const manifestEntry = existing ?? (await getManifestEntry(opts.modelId));\n const modelBytes = manifestEntry?.sizeBytes ?? 0;\n this.scheduler.ensureCapacity(\n opts.modelId,\n modelBytes,\n memory,\n undefined,\n {\n wasmLinearBytes,\n wasmPoolCeilingBytes: WASM_POOL_CEILING_BYTES,\n loadOpts: {\n n_ctx: opts.n_ctx,\n n_batch: opts.n_batch,\n embedding: opts.embedding,\n },\n },\n );\n\n // Fix #9: send modelId only — the worker reads from OPFS internally.\n const loadResult = await this.sendRequest<{\n ok: boolean;\n alreadyLoaded?: boolean;\n measuredFootprintBytes?: number;\n wasmLinearBytes?: number;\n }>(\n {\n type: 'LOAD_MODEL',\n modelId: opts.modelId,\n opts: {\n modelPath: (opts as any).modelPath ?? (opts as any).model_path ?? manifestEntry?.path,\n modelBytes,\n n_ctx: opts.n_ctx,\n n_batch: opts.n_batch,\n n_gpu_layers: opts.n_gpu_layers,\n n_threads: opts.n_threads,\n embedding: opts.embedding,\n use_mmap: opts.use_mmap,\n preferVfsStreaming: opts.preferVfsStreaming,\n },\n },\n undefined,\n opts.onProgress,\n );\n\n let measuredFootprint = loadResult.measuredFootprintBytes;\n if (!(typeof measuredFootprint === 'number' && measuredFootprint > 0)) {\n const workerMem = await this.fetchWorkerMemory().catch((): Record<string, unknown> => ({}));\n measuredFootprint = this.readMeasuredFootprintFromWorker(workerMem, opts.modelId);\n }\n\n this.loadedModelIds.add(opts.modelId);\n this.scheduler.markLoaded(\n opts.modelId,\n modelBytes,\n {\n n_ctx: opts.n_ctx,\n n_batch: opts.n_batch,\n embedding: opts.embedding,\n },\n measuredFootprint,\n );\n if (typeof measuredFootprint === 'number' && measuredFootprint > 0) {\n this.scheduler.calibrateFootprint(opts.modelId, measuredFootprint);\n }\n }\n\n private readMeasuredFootprintFromWorker(\n workerMem: Record<string, unknown>,\n modelId: string,\n ): number | undefined {\n const models = workerMem.loadedModels;\n if (!Array.isArray(models)) return undefined;\n for (const row of models) {\n if (!row || typeof row !== 'object') continue;\n const entry = row as Record<string, unknown>;\n if (entry.modelId !== modelId) continue;\n if (typeof entry.measuredFootprintBytes === 'number' && entry.measuredFootprintBytes > 0) {\n return entry.measuredFootprintBytes;\n }\n }\n return undefined;\n }\n\n async unloadModel(modelId: string): Promise<void> {\n if (!this.loadedModelIds.has(modelId)) {\n return;\n }\n await this.sendRequest<{ ok: boolean }>({ type: 'UNLOAD_MODEL', modelId });\n this.loadedModelIds.delete(modelId);\n this.scheduler.markUnloaded(modelId);\n }\n\n async generate(req: GenerateRequest): Promise<GenerateResult> {\n if (!this.loadedModelIds.has(req.modelId)) {\n throw new LlmError('MODEL_NOT_LOADED', `Model '${req.modelId}' is not loaded`);\n }\n return this.sendRequest<GenerateResult>({\n type: 'GENERATE',\n modelId: req.modelId,\n req: {\n prompt: req.prompt,\n messages: req.messages,\n max_tokens: req.max_tokens,\n temperature: req.temperature,\n stream: false,\n },\n });\n }\n\n async generateStream(req: GenerateRequest, onToken: (event: TokenEvent) => void): Promise<GenerateResult> {\n if (!this.loadedModelIds.has(req.modelId)) {\n throw new LlmError('MODEL_NOT_LOADED', `Model '${req.modelId}' is not loaded`);\n }\n return this.sendRequest<GenerateResult>(\n {\n type: 'GENERATE',\n modelId: req.modelId,\n req: {\n prompt: req.prompt,\n messages: req.messages,\n max_tokens: req.max_tokens,\n temperature: req.temperature,\n stream: true,\n },\n },\n onToken,\n );\n }\n\n async embed(req: EmbedRequest): Promise<EmbedResult> {\n if (!this.loadedModelIds.has(req.modelId)) {\n throw new LlmError('MODEL_NOT_LOADED', `Model '${req.modelId}' is not loaded`);\n }\n return this.sendRequest<EmbedResult>({\n type: 'EMBED',\n modelId: req.modelId,\n input: req.input,\n });\n }\n\n // Fix #11: use cross-browser memory snapshot instead of performance.memory only.\n async getMemorySnapshot(): Promise<MemorySnapshot> {\n return getMemorySnapshotCrossBrowser();\n }\n\n /** Worker WASM linear memory + loaded-model registry (for scheduling UI). */\n async fetchWorkerMemory(): Promise<Record<string, unknown>> {\n return this.sendRequest<Record<string, unknown>>({ type: 'MEMORY' });\n }\n\n async getWasmMemoryStatus(): Promise<Record<string, unknown>> {\n const [browser, workerRaw] = await Promise.all([\n getMemorySnapshotCrossBrowser(),\n this.fetchWorkerMemory().catch((): Record<string, unknown> => ({})),\n ]);\n const worker = workerRaw;\n const wasmLinearBytes =\n typeof worker.wasmLinearBytes === 'number' ? worker.wasmLinearBytes : undefined;\n return {\n browser,\n worker,\n wasmLinearBytes,\n wasmPoolCeilingBytes: WASM_POOL_CEILING_BYTES,\n wasmHeadroomBytes:\n typeof wasmLinearBytes === 'number'\n ? Math.max(0, WASM_POOL_CEILING_BYTES - wasmLinearBytes)\n : undefined,\n pressure:\n typeof wasmLinearBytes === 'number'\n ? wasmMemoryPressure(wasmLinearBytes, WASM_POOL_CEILING_BYTES)\n : browser.pressure,\n loadedModels: this.loadedModelIds.size,\n maxModels: WASM_MAX_CONCURRENT_MODELS,\n schedulerFootprintBytes: this.scheduler.totalFootprintBytes(),\n };\n }\n\n async tokenize(modelId: string, text: string): Promise<TokenizeResult> {\n if (!this.loadedModelIds.has(modelId)) {\n throw new LlmError('MODEL_NOT_LOADED', `Model '${modelId}' is not loaded`);\n }\n return this.sendRequest<TokenizeResult>({ type: 'TOKENIZE', modelId, text });\n }\n\n async detokenize(modelId: string, tokens: number[]): Promise<DetokenizeResult> {\n if (!this.loadedModelIds.has(modelId)) {\n throw new LlmError('MODEL_NOT_LOADED', `Model '${modelId}' is not loaded`);\n }\n return this.sendRequest<DetokenizeResult>({ type: 'DETOKENIZE', modelId, tokens });\n }\n\n async convertJsonSchemaToGrammar(schemaJson: string): Promise<string> {\n // CONVERT_GRAMMAR is context-free — no model needs to be loaded.\n // The worker must be initialised (INIT sent), but that happens on first use.\n const result = await this.sendRequest<{ grammar: string }>({\n type: 'CONVERT_GRAMMAR',\n schemaJson,\n });\n return result.grammar;\n }\n\n private requireLoaded(modelId: string): void {\n if (!this.loadedModelIds.has(modelId)) {\n throw new LlmError('MODEL_NOT_LOADED', `Model '${modelId}' is not loaded`);\n }\n }\n\n async rerank(modelId: string, query: string, documents: string[]): Promise<Array<{ index: number; score: number }>> {\n this.requireLoaded(modelId);\n const result = await this.sendRequest<{ results: Array<{ index: number; score: number }> }>({\n type: 'RERANK',\n modelId,\n query,\n documents,\n });\n return result.results;\n }\n\n async bench(modelId: string, pp: number, tg: number, pl: number, nr: number): Promise<string> {\n this.requireLoaded(modelId);\n const result = await this.sendRequest<{ result: string }>({\n type: 'BENCH',\n modelId,\n pp,\n tg,\n pl,\n nr,\n });\n return result.result;\n }\n\n async saveSession(modelId: string, filepath: string, tokenSize: number): Promise<number> {\n this.requireLoaded(modelId);\n const result = await this.sendRequest<{ tokens_saved: number }>({\n type: 'SAVE_SESSION',\n modelId,\n filepath,\n tokenSize,\n });\n return result.tokens_saved;\n }\n\n async loadSession(\n modelId: string,\n filepath: string,\n ): Promise<{ tokens_loaded: number; prompt: string }> {\n this.requireLoaded(modelId);\n return this.sendRequest<{ tokens_loaded: number; prompt: string }>({\n type: 'LOAD_SESSION',\n modelId,\n filepath,\n });\n }\n\n async applyLoraAdapters(\n modelId: string,\n loraAdapters: Array<{ path: string; scaled?: number }>,\n ): Promise<void> {\n this.requireLoaded(modelId);\n await this.sendRequest<{ ok: boolean }>({\n type: 'APPLY_LORA',\n modelId,\n loraAdapters,\n });\n }\n\n async removeLoraAdapters(modelId: string): Promise<void> {\n this.requireLoaded(modelId);\n await this.sendRequest<{ ok: boolean }>({ type: 'REMOVE_LORA', modelId });\n }\n\n async getLoadedLoraAdapters(\n modelId: string,\n ): Promise<Array<{ path: string; scaled?: number }>> {\n this.requireLoaded(modelId);\n const result = await this.sendRequest<{ adapters: Array<{ path: string; scaled?: number }> }>({\n type: 'GET_LORA',\n modelId,\n });\n return result.adapters;\n }\n\n async initMultimodal(modelId: string, path: string, useGpu = false): Promise<boolean> {\n this.requireLoaded(modelId);\n const result = await this.sendRequest<{ ok: boolean }>({\n type: 'INIT_MULTIMODAL',\n modelId,\n path,\n useGpu,\n });\n return !!result.ok;\n }\n\n async isMultimodalEnabled(modelId: string): Promise<boolean> {\n this.requireLoaded(modelId);\n const result = await this.sendRequest<{ enabled: boolean }>({\n type: 'MULTIMODAL_STATUS',\n modelId,\n });\n return !!result.enabled;\n }\n\n async getMultimodalSupport(\n modelId: string,\n ): Promise<{ vision: boolean; audio: boolean }> {\n this.requireLoaded(modelId);\n const result = await this.sendRequest<{ vision: boolean; audio: boolean }>({\n type: 'MULTIMODAL_STATUS',\n modelId,\n });\n return { vision: !!result.vision, audio: !!result.audio };\n }\n\n async releaseMultimodal(modelId: string): Promise<void> {\n await this.sendRequest<{ ok: boolean }>({ type: 'RELEASE_MULTIMODAL', modelId });\n }\n\n async initVocoder(modelId: string, path: string, nBatch = 512): Promise<boolean> {\n this.requireLoaded(modelId);\n const result = await this.sendRequest<{ ok: boolean }>({\n type: 'INIT_VOCODER',\n modelId,\n path,\n nBatch,\n });\n return !!result.ok;\n }\n\n async isVocoderEnabled(modelId: string): Promise<boolean> {\n this.requireLoaded(modelId);\n const result = await this.sendRequest<{ enabled: boolean }>({\n type: 'VOCODER_ENABLED',\n modelId,\n });\n return !!result.enabled;\n }\n\n async releaseVocoder(modelId: string): Promise<void> {\n await this.sendRequest<{ ok: boolean }>({ type: 'RELEASE_VOCODER', modelId });\n }\n\n async getFormattedAudioCompletion(\n modelId: string,\n speaker: object | null,\n textToSpeak: string,\n ): Promise<{ prompt: string; grammar?: string }> {\n this.requireLoaded(modelId);\n return this.sendRequest<{ prompt: string; grammar?: string }>({\n type: 'FORMATTED_AUDIO',\n modelId,\n speakerJson: speaker ? JSON.stringify(speaker) : '',\n textToSpeak,\n });\n }\n\n async getAudioCompletionGuideTokens(modelId: string, textToSpeak: string): Promise<number[]> {\n this.requireLoaded(modelId);\n const result = await this.sendRequest<{ tokens: number[] }>({\n type: 'AUDIO_GUIDE_TOKENS',\n modelId,\n textToSpeak,\n });\n return result.tokens;\n }\n\n async decodeAudioTokens(modelId: string, tokens: number[]): Promise<number[]> {\n this.requireLoaded(modelId);\n const result = await this.sendRequest<{ audio: number[] }>({\n type: 'DECODE_AUDIO_TOKENS',\n modelId,\n tokens,\n });\n return result.audio;\n }\n\n /**\n * Terminate the worker mid-inference. WASM is single-threaded, so posting\n * an abort message cannot be received while generate() is running. Worker\n * termination is the only reliable interrupt. The model will need to be\n * reloaded on the next generate() call.\n */\n stopGeneration(): void {\n if (!this.worker) return;\n this.worker.terminate();\n this.worker = null;\n const interrupted = toError('INFERENCE_FAILED', 'Generation stopped by caller.');\n for (const [id, req] of this.pending.entries()) {\n this.pending.delete(id);\n req.reject(interrupted);\n }\n // Worker is gone, so all previously tracked model IDs are invalid.\n this.loadedModelIds.clear();\n for (const id of this.scheduler.listLoaded()) {\n this.scheduler.markUnloaded(id);\n }\n }\n\n async health(): Promise<{ ok: boolean; details?: Record<string, unknown> }> {\n const usage = await getOpfsUsage().catch(() => ({\n usedBytes: 0 as number,\n quotaBytes: undefined as number | undefined,\n }));\n const workerHealth = await this.sendRequest<Record<string, unknown>>({ type: 'HEALTH' }).catch(\n (error: unknown) => ({\n ok: false,\n message: error instanceof Error ? error.message : String(error),\n }),\n );\n const workerRecord = workerHealth as Record<string, unknown>;\n const workerDetails = workerRecord.details as Record<string, unknown> | undefined;\n return {\n ok: !!workerHealth?.ok,\n details: {\n loadedModels: this.loadedModelIds.size,\n opfsUsedBytes: usage.usedBytes,\n opfsQuotaBytes: usage.quotaBytes,\n worker: workerHealth,\n crossOriginIsolated: checkCrossOriginIsolation(),\n wasmJspi: workerDetails?.wasmJspi,\n wasmPthread: workerDetails?.wasmPthread,\n },\n };\n }\n}\n"]}
@@ -0,0 +1,14 @@
1
+ /** OpenAI-style SSE lines emitted by the native desktop sidecar. */
2
+ export type SidecarSseKind = 'chat' | 'completion';
3
+ /** Extract a token string from one SSE `data:` JSON payload (empty if none). */
4
+ export declare function extractSidecarSseToken(payload: string, kind: SidecarSseKind): string;
5
+ /** Parse a single SSE line; returns a token when present. */
6
+ export declare function parseSidecarSseLine(line: string, kind: SidecarSseKind): string | null;
7
+ /** Buffers decoded stream bytes into complete newline-delimited lines. */
8
+ export declare class SidecarSseLineParser {
9
+ private buffer;
10
+ feed(chunk: string): string[];
11
+ flush(): string[];
12
+ }
13
+ /** Read token chunks from a fetch `ReadableStream` body. */
14
+ export declare function readSidecarSseTokens(body: ReadableStream<Uint8Array>, kind: SidecarSseKind, onToken: (token: string) => void): Promise<void>;
@@ -0,0 +1,76 @@
1
+ /** Extract a token string from one SSE `data:` JSON payload (empty if none). */
2
+ export function extractSidecarSseToken(payload, kind) {
3
+ var _a, _b, _c, _d, _e, _f, _g;
4
+ if (payload === '[DONE]') {
5
+ return '';
6
+ }
7
+ try {
8
+ const chunk = JSON.parse(payload);
9
+ if (kind === 'chat') {
10
+ return (_d = (_c = (_b = (_a = chunk.choices) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.delta) === null || _c === void 0 ? void 0 : _c.content) !== null && _d !== void 0 ? _d : '';
11
+ }
12
+ return (_g = (_f = (_e = chunk.choices) === null || _e === void 0 ? void 0 : _e[0]) === null || _f === void 0 ? void 0 : _f.text) !== null && _g !== void 0 ? _g : '';
13
+ }
14
+ catch (_h) {
15
+ return '';
16
+ }
17
+ }
18
+ /** Parse a single SSE line; returns a token when present. */
19
+ export function parseSidecarSseLine(line, kind) {
20
+ if (!line.startsWith('data: ')) {
21
+ return null;
22
+ }
23
+ const payload = line.slice(6).trim();
24
+ if (payload === '[DONE]') {
25
+ return null;
26
+ }
27
+ const token = extractSidecarSseToken(payload, kind);
28
+ return token ? token : null;
29
+ }
30
+ /** Buffers decoded stream bytes into complete newline-delimited lines. */
31
+ export class SidecarSseLineParser {
32
+ constructor() {
33
+ this.buffer = '';
34
+ }
35
+ feed(chunk) {
36
+ var _a;
37
+ this.buffer += chunk;
38
+ const lines = this.buffer.split('\n');
39
+ this.buffer = (_a = lines.pop()) !== null && _a !== void 0 ? _a : '';
40
+ return lines;
41
+ }
42
+ flush() {
43
+ if (!this.buffer) {
44
+ return [];
45
+ }
46
+ const line = this.buffer;
47
+ this.buffer = '';
48
+ return [line];
49
+ }
50
+ }
51
+ /** Read token chunks from a fetch `ReadableStream` body. */
52
+ export async function readSidecarSseTokens(body, kind, onToken) {
53
+ const reader = body.getReader();
54
+ const decoder = new TextDecoder();
55
+ const parser = new SidecarSseLineParser();
56
+ while (true) {
57
+ const { done, value } = await reader.read();
58
+ if (done) {
59
+ break;
60
+ }
61
+ const lines = parser.feed(decoder.decode(value, { stream: true }));
62
+ for (const line of lines) {
63
+ const token = parseSidecarSseLine(line, kind);
64
+ if (token) {
65
+ onToken(token);
66
+ }
67
+ }
68
+ }
69
+ for (const line of parser.flush()) {
70
+ const token = parseSidecarSseLine(line, kind);
71
+ if (token) {
72
+ onToken(token);
73
+ }
74
+ }
75
+ }
76
+ //# sourceMappingURL=sidecar-sse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sidecar-sse.js","sourceRoot":"","sources":["../../../src/isomorphic/sidecar-sse.ts"],"names":[],"mappings":"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","sourcesContent":["/** OpenAI-style SSE lines emitted by the native desktop sidecar. */\nexport type SidecarSseKind = 'chat' | 'completion';\n\n/** Extract a token string from one SSE `data:` JSON payload (empty if none). */\nexport function extractSidecarSseToken(payload: string, kind: SidecarSseKind): string {\n if (payload === '[DONE]') {\n return '';\n }\n try {\n const chunk = JSON.parse(payload) as {\n choices?: Array<{ delta?: { content?: string }; text?: string }>;\n };\n if (kind === 'chat') {\n return chunk.choices?.[0]?.delta?.content ?? '';\n }\n return chunk.choices?.[0]?.text ?? '';\n } catch {\n return '';\n }\n}\n\n/** Parse a single SSE line; returns a token when present. */\nexport function parseSidecarSseLine(line: string, kind: SidecarSseKind): string | null {\n if (!line.startsWith('data: ')) {\n return null;\n }\n const payload = line.slice(6).trim();\n if (payload === '[DONE]') {\n return null;\n }\n const token = extractSidecarSseToken(payload, kind);\n return token ? token : null;\n}\n\n/** Buffers decoded stream bytes into complete newline-delimited lines. */\nexport class SidecarSseLineParser {\n private buffer = '';\n\n feed(chunk: string): string[] {\n this.buffer += chunk;\n const lines = this.buffer.split('\\n');\n this.buffer = lines.pop() ?? '';\n return lines;\n }\n\n flush(): string[] {\n if (!this.buffer) {\n return [];\n }\n const line = this.buffer;\n this.buffer = '';\n return [line];\n }\n}\n\n/** Read token chunks from a fetch `ReadableStream` body. */\nexport async function readSidecarSseTokens(\n body: ReadableStream<Uint8Array>,\n kind: SidecarSseKind,\n onToken: (token: string) => void,\n): Promise<void> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n const parser = new SidecarSseLineParser();\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n const lines = parser.feed(decoder.decode(value, { stream: true }));\n for (const line of lines) {\n const token = parseSidecarSseLine(line, kind);\n if (token) {\n onToken(token);\n }\n }\n }\n for (const line of parser.flush()) {\n const token = parseSidecarSseLine(line, kind);\n if (token) {\n onToken(token);\n }\n }\n}\n"]}
@@ -0,0 +1,26 @@
1
+ export type ModelFootprintEntry = {
2
+ fileBytes: number;
3
+ estimatedBytes: number;
4
+ measuredBytes?: number;
5
+ linearBefore?: number;
6
+ linearAfter?: number;
7
+ calibratedAt?: number;
8
+ };
9
+ export type WasmProjectionInput = {
10
+ wasmLinearBytes: number;
11
+ residentModelCount: number;
12
+ residentFootprintBytes: number;
13
+ candidateEstimateBytes: number;
14
+ candidateMeasuredBytes?: number;
15
+ };
16
+ /** Bytes used for scheduling — measured when calibrated, else estimate. */
17
+ export declare function resolveFootprintBytes(entry: ModelFootprintEntry | number | undefined, fallbackEstimate: number): number;
18
+ /** Attribute heap growth to one model load (delta from linear before → after). */
19
+ export declare function calibrateFootprintFromLinearDelta(linearBefore: number, linearAfter: number, estimatedBytes: number, options?: {
20
+ firstModelInHeap?: boolean;
21
+ }): number;
22
+ export declare function createFootprintEntry(fileBytes: number, estimatedBytes: number): ModelFootprintEntry;
23
+ export declare function applyCalibration(entry: ModelFootprintEntry, linearBefore: number, linearAfter: number, firstModelInHeap: boolean): ModelFootprintEntry;
24
+ export declare function sumResidentFootprintBytes(footprints: Map<string, ModelFootprintEntry | number>, excludeModelId?: string): number;
25
+ /** Project WASM pool usage after admitting one more model (footprint-based). */
26
+ export declare function projectWasmAfterLoad(input: WasmProjectionInput): number;
@@ -0,0 +1,60 @@
1
+ const WARM_HEAP_BYTES = 64 * 1024 * 1024;
2
+ /** Bytes used for scheduling — measured when calibrated, else estimate. */
3
+ export function resolveFootprintBytes(entry, fallbackEstimate) {
4
+ if (typeof entry === 'number' && entry > 0)
5
+ return entry;
6
+ if (entry && typeof entry === 'object') {
7
+ if (typeof entry.measuredBytes === 'number' && entry.measuredBytes > 0) {
8
+ return entry.measuredBytes;
9
+ }
10
+ if (entry.estimatedBytes > 0)
11
+ return entry.estimatedBytes;
12
+ }
13
+ return fallbackEstimate;
14
+ }
15
+ /** Attribute heap growth to one model load (delta from linear before → after). */
16
+ export function calibrateFootprintFromLinearDelta(linearBefore, linearAfter, estimatedBytes, options) {
17
+ const delta = Math.max(0, linearAfter - linearBefore);
18
+ if ((options === null || options === void 0 ? void 0 : options.firstModelInHeap) && linearAfter > WARM_HEAP_BYTES) {
19
+ return linearAfter;
20
+ }
21
+ if (delta > 0) {
22
+ return delta;
23
+ }
24
+ return estimatedBytes;
25
+ }
26
+ export function createFootprintEntry(fileBytes, estimatedBytes) {
27
+ return { fileBytes, estimatedBytes };
28
+ }
29
+ export function applyCalibration(entry, linearBefore, linearAfter, firstModelInHeap) {
30
+ const measuredBytes = calibrateFootprintFromLinearDelta(linearBefore, linearAfter, entry.estimatedBytes, { firstModelInHeap });
31
+ return Object.assign(Object.assign({}, entry), { measuredBytes,
32
+ linearBefore,
33
+ linearAfter, calibratedAt: Date.now() });
34
+ }
35
+ export function sumResidentFootprintBytes(footprints, excludeModelId) {
36
+ let sum = 0;
37
+ for (const [id, entry] of footprints) {
38
+ if (excludeModelId && id === excludeModelId)
39
+ continue;
40
+ const fallback = typeof entry === 'object' ? entry.estimatedBytes : 0;
41
+ sum += resolveFootprintBytes(entry, fallback);
42
+ }
43
+ return sum;
44
+ }
45
+ /** Project WASM pool usage after admitting one more model (footprint-based). */
46
+ export function projectWasmAfterLoad(input) {
47
+ var _a;
48
+ const linear = input.wasmLinearBytes;
49
+ const nextBytes = (_a = input.candidateMeasuredBytes) !== null && _a !== void 0 ? _a : input.candidateEstimateBytes;
50
+ // Prefer calibrated footprints over linear heap size. Linear may include unused
51
+ // pre-grown headroom (or a prior failed grow to MAXIMUM_MEMORY).
52
+ if (input.residentModelCount > 0) {
53
+ return input.residentFootprintBytes + nextBytes;
54
+ }
55
+ if (linear > WARM_HEAP_BYTES) {
56
+ return nextBytes;
57
+ }
58
+ return Math.max(linear, nextBytes);
59
+ }
60
+ //# sourceMappingURL=wasmMemoryCalibration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wasmMemoryCalibration.js","sourceRoot":"","sources":["../../../src/isomorphic/wasmMemoryCalibration.ts"],"names":[],"mappings":"AAiBA,MAAM,eAAe,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAEzC,2EAA2E;AAC3E,MAAM,UAAU,qBAAqB,CACnC,KAA+C,EAC/C,gBAAwB;IAExB,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACzD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvC,IAAI,OAAO,KAAK,CAAC,aAAa,KAAK,QAAQ,IAAI,KAAK,CAAC,aAAa,GAAG,CAAC,EAAE,CAAC;YACvE,OAAO,KAAK,CAAC,aAAa,CAAC;QAC7B,CAAC;QACD,IAAI,KAAK,CAAC,cAAc,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC,cAAc,CAAC;IAC5D,CAAC;IACD,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,iCAAiC,CAC/C,YAAoB,EACpB,WAAmB,EACnB,cAAsB,EACtB,OAAwC;IAExC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,GAAG,YAAY,CAAC,CAAC;IACtD,IAAI,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,gBAAgB,KAAI,WAAW,GAAG,eAAe,EAAE,CAAC;QAC/D,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACd,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,cAAc,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,SAAiB,EACjB,cAAsB;IAEtB,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,KAA0B,EAC1B,YAAoB,EACpB,WAAmB,EACnB,gBAAyB;IAEzB,MAAM,aAAa,GAAG,iCAAiC,CACrD,YAAY,EACZ,WAAW,EACX,KAAK,CAAC,cAAc,EACpB,EAAE,gBAAgB,EAAE,CACrB,CAAC;IACF,uCACK,KAAK,KACR,aAAa;QACb,YAAY;QACZ,WAAW,EACX,YAAY,EAAE,IAAI,CAAC,GAAG,EAAE,IACxB;AACJ,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,UAAqD,EACrD,cAAuB;IAEvB,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,UAAU,EAAE,CAAC;QACrC,IAAI,cAAc,IAAI,EAAE,KAAK,cAAc;YAAE,SAAS;QACtD,MAAM,QAAQ,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;QACtE,GAAG,IAAI,qBAAqB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,oBAAoB,CAAC,KAA0B;;IAC7D,MAAM,MAAM,GAAG,KAAK,CAAC,eAAe,CAAC;IACrC,MAAM,SAAS,GAAG,MAAA,KAAK,CAAC,sBAAsB,mCAAI,KAAK,CAAC,sBAAsB,CAAC;IAE/E,gFAAgF;IAChF,iEAAiE;IACjE,IAAI,KAAK,CAAC,kBAAkB,GAAG,CAAC,EAAE,CAAC;QACjC,OAAO,KAAK,CAAC,sBAAsB,GAAG,SAAS,CAAC;IAClD,CAAC;IACD,IAAI,MAAM,GAAG,eAAe,EAAE,CAAC;QAC7B,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AACrC,CAAC","sourcesContent":["export type ModelFootprintEntry = {\n fileBytes: number;\n estimatedBytes: number;\n measuredBytes?: number;\n linearBefore?: number;\n linearAfter?: number;\n calibratedAt?: number;\n};\n\nexport type WasmProjectionInput = {\n wasmLinearBytes: number;\n residentModelCount: number;\n residentFootprintBytes: number;\n candidateEstimateBytes: number;\n candidateMeasuredBytes?: number;\n};\n\nconst WARM_HEAP_BYTES = 64 * 1024 * 1024;\n\n/** Bytes used for scheduling — measured when calibrated, else estimate. */\nexport function resolveFootprintBytes(\n entry: ModelFootprintEntry | number | undefined,\n fallbackEstimate: number,\n): number {\n if (typeof entry === 'number' && entry > 0) return entry;\n if (entry && typeof entry === 'object') {\n if (typeof entry.measuredBytes === 'number' && entry.measuredBytes > 0) {\n return entry.measuredBytes;\n }\n if (entry.estimatedBytes > 0) return entry.estimatedBytes;\n }\n return fallbackEstimate;\n}\n\n/** Attribute heap growth to one model load (delta from linear before → after). */\nexport function calibrateFootprintFromLinearDelta(\n linearBefore: number,\n linearAfter: number,\n estimatedBytes: number,\n options?: { firstModelInHeap?: boolean },\n): number {\n const delta = Math.max(0, linearAfter - linearBefore);\n if (options?.firstModelInHeap && linearAfter > WARM_HEAP_BYTES) {\n return linearAfter;\n }\n if (delta > 0) {\n return delta;\n }\n return estimatedBytes;\n}\n\nexport function createFootprintEntry(\n fileBytes: number,\n estimatedBytes: number,\n): ModelFootprintEntry {\n return { fileBytes, estimatedBytes };\n}\n\nexport function applyCalibration(\n entry: ModelFootprintEntry,\n linearBefore: number,\n linearAfter: number,\n firstModelInHeap: boolean,\n): ModelFootprintEntry {\n const measuredBytes = calibrateFootprintFromLinearDelta(\n linearBefore,\n linearAfter,\n entry.estimatedBytes,\n { firstModelInHeap },\n );\n return {\n ...entry,\n measuredBytes,\n linearBefore,\n linearAfter,\n calibratedAt: Date.now(),\n };\n}\n\nexport function sumResidentFootprintBytes(\n footprints: Map<string, ModelFootprintEntry | number>,\n excludeModelId?: string,\n): number {\n let sum = 0;\n for (const [id, entry] of footprints) {\n if (excludeModelId && id === excludeModelId) continue;\n const fallback = typeof entry === 'object' ? entry.estimatedBytes : 0;\n sum += resolveFootprintBytes(entry, fallback);\n }\n return sum;\n}\n\n/** Project WASM pool usage after admitting one more model (footprint-based). */\nexport function projectWasmAfterLoad(input: WasmProjectionInput): number {\n const linear = input.wasmLinearBytes;\n const nextBytes = input.candidateMeasuredBytes ?? input.candidateEstimateBytes;\n\n // Prefer calibrated footprints over linear heap size. Linear may include unused\n // pre-grown headroom (or a prior failed grow to MAXIMUM_MEMORY).\n if (input.residentModelCount > 0) {\n return input.residentFootprintBytes + nextBytes;\n }\n if (linear > WARM_HEAP_BYTES) {\n return nextBytes;\n }\n return Math.max(linear, nextBytes);\n}\n"]}
@@ -0,0 +1,55 @@
1
+ import type { MemorySnapshot } from './provider.interface';
2
+ /** Max concurrent GGUF contexts in one WASM worker (matches n_threads slot policy). */
3
+ export declare const WASM_MAX_CONCURRENT_MODELS = 5;
4
+ /** Emscripten MAXIMUM_MEMORY — absolute hard limit from build (2 GiB). */
5
+ export declare const WASM_EMSCRIPTEN_MAX_BYTES = 2147483648;
6
+ /** WASM pool planning cap — aligned with Emscripten max (was 1536 MB). */
7
+ export declare const WASM_POOL_CEILING_BYTES = 2147483648;
8
+ /** Keep this much headroom free inside the WASM pool after a load. */
9
+ export declare const WASM_POOL_RESERVE_BYTES: number;
10
+ export type ModelLoadMemoryOpts = {
11
+ n_ctx?: number;
12
+ n_batch?: number;
13
+ embedding?: boolean;
14
+ };
15
+ export type WasmMemoryStatus = MemorySnapshot & {
16
+ wasmLinearBytes?: number;
17
+ wasmPoolCeilingBytes?: number;
18
+ wasmHeadroomBytes?: number;
19
+ loadedModelCount?: number;
20
+ maxModels?: number;
21
+ loadedModels?: Array<{
22
+ modelId: string;
23
+ fileBytes?: number;
24
+ estimatedFootprintBytes?: number;
25
+ }>;
26
+ };
27
+ export type WasmLoadAdmissionInput = {
28
+ modelId: string;
29
+ fileBytes: number;
30
+ loadOpts?: ModelLoadMemoryOpts;
31
+ currentlyLoaded: number;
32
+ maxModels?: number;
33
+ wasmLinearBytes?: number;
34
+ wasmPoolCeilingBytes?: number;
35
+ loadedFootprintBytes?: number;
36
+ /** Prior measured footprint for this model id (if re-loading after unload). */
37
+ candidateMeasuredBytes?: number;
38
+ reserveBytes?: number;
39
+ browserMemory?: MemorySnapshot;
40
+ };
41
+ export type WasmLoadAdmissionResult = {
42
+ allow: boolean;
43
+ deniedBy?: 'limit' | 'wasm_pool' | 'browser_memory';
44
+ reason?: string;
45
+ estimatedFootprintBytes: number;
46
+ projectedWasmBytes?: number;
47
+ };
48
+ /**
49
+ * Estimate WASM linear memory for one model (weights + context/KV headroom).
50
+ * PWA loads via async OPFS — weights are not fully duplicated in heap (not 2× file).
51
+ * Observed: LFM2 ~697 MB GGUF → ~940 MB WASM; BGE ~17 MB → ~150–200 MB.
52
+ */
53
+ export declare function estimateModelWasmFootprint(fileBytes: number, opts?: ModelLoadMemoryOpts): number;
54
+ export declare function canAdmitWasmModelLoad(input: WasmLoadAdmissionInput): WasmLoadAdmissionResult;
55
+ export declare function wasmMemoryPressure(wasmLinearBytes: number, ceilingBytes?: number): MemorySnapshot['pressure'];
@@ -0,0 +1,93 @@
1
+ import { projectWasmAfterLoad } from './wasmMemoryCalibration';
2
+ /** Max concurrent GGUF contexts in one WASM worker (matches n_threads slot policy). */
3
+ export const WASM_MAX_CONCURRENT_MODELS = 5;
4
+ /** Emscripten MAXIMUM_MEMORY — absolute hard limit from build (2 GiB). */
5
+ export const WASM_EMSCRIPTEN_MAX_BYTES = 2147483648;
6
+ /** WASM pool planning cap — aligned with Emscripten max (was 1536 MB). */
7
+ export const WASM_POOL_CEILING_BYTES = WASM_EMSCRIPTEN_MAX_BYTES;
8
+ /** Keep this much headroom free inside the WASM pool after a load. */
9
+ export const WASM_POOL_RESERVE_BYTES = 64 * 1024 * 1024;
10
+ /**
11
+ * Estimate WASM linear memory for one model (weights + context/KV headroom).
12
+ * PWA loads via async OPFS — weights are not fully duplicated in heap (not 2× file).
13
+ * Observed: LFM2 ~697 MB GGUF → ~940 MB WASM; BGE ~17 MB → ~150–200 MB.
14
+ */
15
+ export function estimateModelWasmFootprint(fileBytes, opts = {}) {
16
+ if (!(fileBytes > 0))
17
+ return 20 * 1024 * 1024;
18
+ const embedding = opts.embedding === true;
19
+ const n_ctx = typeof opts.n_ctx === 'number' && opts.n_ctx > 0 ? opts.n_ctx : embedding ? 256 : 512;
20
+ const n_batch = typeof opts.n_batch === 'number' && opts.n_batch > 0 ? opts.n_batch : embedding ? 32 : 16;
21
+ // Async OPFS: ~1.3× file for large chat; embed models are lighter.
22
+ const weightMultiplier = embedding ? 1.25 : fileBytes > 200 * 1024 * 1024 ? 1.32 : 1.2;
23
+ const ctxBytes = n_ctx * n_batch * 4096;
24
+ const proportional = Math.ceil(fileBytes * 0.12);
25
+ const minHeadroom = embedding ? 48 * 1024 * 1024 : 96 * 1024 * 1024;
26
+ const headroom = Math.max(minHeadroom, proportional, ctxBytes);
27
+ return Math.ceil(fileBytes * weightMultiplier + headroom);
28
+ }
29
+ export function canAdmitWasmModelLoad(input) {
30
+ var _a, _b, _c, _d, _e, _f, _g;
31
+ const maxModels = (_a = input.maxModels) !== null && _a !== void 0 ? _a : WASM_MAX_CONCURRENT_MODELS;
32
+ const ceiling = (_b = input.wasmPoolCeilingBytes) !== null && _b !== void 0 ? _b : WASM_POOL_CEILING_BYTES;
33
+ const reserve = (_c = input.reserveBytes) !== null && _c !== void 0 ? _c : WASM_POOL_RESERVE_BYTES;
34
+ const estimated = estimateModelWasmFootprint(input.fileBytes, (_d = input.loadOpts) !== null && _d !== void 0 ? _d : {});
35
+ if (input.currentlyLoaded >= maxModels) {
36
+ return {
37
+ allow: false,
38
+ deniedBy: 'limit',
39
+ reason: `Model slot limit reached (${maxModels} concurrent WASM contexts)`,
40
+ estimatedFootprintBytes: estimated,
41
+ };
42
+ }
43
+ const linear = (_e = input.wasmLinearBytes) !== null && _e !== void 0 ? _e : 0;
44
+ const loadedFootprint = (_f = input.loadedFootprintBytes) !== null && _f !== void 0 ? _f : 0;
45
+ const projectedWasm = projectWasmAfterLoad({
46
+ wasmLinearBytes: linear,
47
+ residentModelCount: input.currentlyLoaded,
48
+ residentFootprintBytes: loadedFootprint,
49
+ candidateEstimateBytes: estimated,
50
+ candidateMeasuredBytes: input.candidateMeasuredBytes,
51
+ });
52
+ const admitLimit = Math.min(ceiling, WASM_EMSCRIPTEN_MAX_BYTES) - reserve;
53
+ if (projectedWasm > admitLimit) {
54
+ return {
55
+ allow: false,
56
+ deniedBy: 'wasm_pool',
57
+ reason: `WASM pool would exceed ${(ceiling / 1024 / 1024).toFixed(0)} MB ` +
58
+ `(projected ${(projectedWasm / 1024 / 1024).toFixed(0)} MB, ` +
59
+ `GGUF ${(input.fileBytes / 1024 / 1024).toFixed(0)} MB → est. WASM ~${(estimated / 1024 / 1024).toFixed(0)} MB)`,
60
+ estimatedFootprintBytes: estimated,
61
+ projectedWasmBytes: projectedWasm,
62
+ };
63
+ }
64
+ if (typeof ((_g = input.browserMemory) === null || _g === void 0 ? void 0 : _g.freeBytes) === 'number') {
65
+ const browserReserve = 256 * 1024 * 1024;
66
+ const postFree = input.browserMemory.freeBytes - estimated;
67
+ if (postFree < browserReserve) {
68
+ return {
69
+ allow: false,
70
+ deniedBy: 'browser_memory',
71
+ reason: 'Insufficient browser JS heap after model load reserve',
72
+ estimatedFootprintBytes: estimated,
73
+ projectedWasmBytes: projectedWasm,
74
+ };
75
+ }
76
+ }
77
+ return {
78
+ allow: true,
79
+ estimatedFootprintBytes: estimated,
80
+ projectedWasmBytes: projectedWasm,
81
+ };
82
+ }
83
+ export function wasmMemoryPressure(wasmLinearBytes, ceilingBytes = WASM_POOL_CEILING_BYTES) {
84
+ if (!(wasmLinearBytes > 0) || !(ceilingBytes > 0))
85
+ return 'unknown';
86
+ const ratio = wasmLinearBytes / ceilingBytes;
87
+ if (ratio >= 0.85)
88
+ return 'high';
89
+ if (ratio >= 0.7)
90
+ return 'medium';
91
+ return 'low';
92
+ }
93
+ //# sourceMappingURL=wasmMemoryPolicy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wasmMemoryPolicy.js","sourceRoot":"","sources":["../../../src/isomorphic/wasmMemoryPolicy.ts"],"names":[],"mappings":"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","sourcesContent":["import type { MemorySnapshot } from './provider.interface';\nimport { projectWasmAfterLoad } from './wasmMemoryCalibration';\n\n/** Max concurrent GGUF contexts in one WASM worker (matches n_threads slot policy). */\nexport const WASM_MAX_CONCURRENT_MODELS = 5;\n\n/** Emscripten MAXIMUM_MEMORY — absolute hard limit from build (2 GiB). */\nexport const WASM_EMSCRIPTEN_MAX_BYTES = 2147483648;\n\n/** WASM pool planning cap — aligned with Emscripten max (was 1536 MB). */\nexport const WASM_POOL_CEILING_BYTES = WASM_EMSCRIPTEN_MAX_BYTES;\n\n/** Keep this much headroom free inside the WASM pool after a load. */\nexport const WASM_POOL_RESERVE_BYTES = 64 * 1024 * 1024;\n\nexport type ModelLoadMemoryOpts = {\n n_ctx?: number;\n n_batch?: number;\n embedding?: boolean;\n};\n\nexport type WasmMemoryStatus = MemorySnapshot & {\n wasmLinearBytes?: number;\n wasmPoolCeilingBytes?: number;\n wasmHeadroomBytes?: number;\n loadedModelCount?: number;\n maxModels?: number;\n loadedModels?: Array<{ modelId: string; fileBytes?: number; estimatedFootprintBytes?: number }>;\n};\n\nexport type WasmLoadAdmissionInput = {\n modelId: string;\n fileBytes: number;\n loadOpts?: ModelLoadMemoryOpts;\n currentlyLoaded: number;\n maxModels?: number;\n wasmLinearBytes?: number;\n wasmPoolCeilingBytes?: number;\n loadedFootprintBytes?: number;\n /** Prior measured footprint for this model id (if re-loading after unload). */\n candidateMeasuredBytes?: number;\n reserveBytes?: number;\n browserMemory?: MemorySnapshot;\n};\n\nexport type WasmLoadAdmissionResult = {\n allow: boolean;\n deniedBy?: 'limit' | 'wasm_pool' | 'browser_memory';\n reason?: string;\n estimatedFootprintBytes: number;\n projectedWasmBytes?: number;\n};\n\n/**\n * Estimate WASM linear memory for one model (weights + context/KV headroom).\n * PWA loads via async OPFS — weights are not fully duplicated in heap (not 2× file).\n * Observed: LFM2 ~697 MB GGUF → ~940 MB WASM; BGE ~17 MB → ~150–200 MB.\n */\nexport function estimateModelWasmFootprint(\n fileBytes: number,\n opts: ModelLoadMemoryOpts = {},\n): number {\n if (!(fileBytes > 0)) return 20 * 1024 * 1024;\n\n const embedding = opts.embedding === true;\n const n_ctx = typeof opts.n_ctx === 'number' && opts.n_ctx > 0 ? opts.n_ctx : embedding ? 256 : 512;\n const n_batch = typeof opts.n_batch === 'number' && opts.n_batch > 0 ? opts.n_batch : embedding ? 32 : 16;\n\n // Async OPFS: ~1.3× file for large chat; embed models are lighter.\n const weightMultiplier = embedding ? 1.25 : fileBytes > 200 * 1024 * 1024 ? 1.32 : 1.2;\n const ctxBytes = n_ctx * n_batch * 4096;\n const proportional = Math.ceil(fileBytes * 0.12);\n const minHeadroom = embedding ? 48 * 1024 * 1024 : 96 * 1024 * 1024;\n const headroom = Math.max(minHeadroom, proportional, ctxBytes);\n\n return Math.ceil(fileBytes * weightMultiplier + headroom);\n}\n\nexport function canAdmitWasmModelLoad(input: WasmLoadAdmissionInput): WasmLoadAdmissionResult {\n const maxModels = input.maxModels ?? WASM_MAX_CONCURRENT_MODELS;\n const ceiling = input.wasmPoolCeilingBytes ?? WASM_POOL_CEILING_BYTES;\n const reserve = input.reserveBytes ?? WASM_POOL_RESERVE_BYTES;\n const estimated = estimateModelWasmFootprint(input.fileBytes, input.loadOpts ?? {});\n\n if (input.currentlyLoaded >= maxModels) {\n return {\n allow: false,\n deniedBy: 'limit',\n reason: `Model slot limit reached (${maxModels} concurrent WASM contexts)`,\n estimatedFootprintBytes: estimated,\n };\n }\n\n const linear = input.wasmLinearBytes ?? 0;\n const loadedFootprint = input.loadedFootprintBytes ?? 0;\n const projectedWasm = projectWasmAfterLoad({\n wasmLinearBytes: linear,\n residentModelCount: input.currentlyLoaded,\n residentFootprintBytes: loadedFootprint,\n candidateEstimateBytes: estimated,\n candidateMeasuredBytes: input.candidateMeasuredBytes,\n });\n const admitLimit = Math.min(ceiling, WASM_EMSCRIPTEN_MAX_BYTES) - reserve;\n\n if (projectedWasm > admitLimit) {\n return {\n allow: false,\n deniedBy: 'wasm_pool',\n reason:\n `WASM pool would exceed ${(ceiling / 1024 / 1024).toFixed(0)} MB ` +\n `(projected ${(projectedWasm / 1024 / 1024).toFixed(0)} MB, ` +\n `GGUF ${(input.fileBytes / 1024 / 1024).toFixed(0)} MB → est. WASM ~${(estimated / 1024 / 1024).toFixed(0)} MB)`,\n estimatedFootprintBytes: estimated,\n projectedWasmBytes: projectedWasm,\n };\n }\n\n if (typeof input.browserMemory?.freeBytes === 'number') {\n const browserReserve = 256 * 1024 * 1024;\n const postFree = input.browserMemory.freeBytes - estimated;\n if (postFree < browserReserve) {\n return {\n allow: false,\n deniedBy: 'browser_memory',\n reason: 'Insufficient browser JS heap after model load reserve',\n estimatedFootprintBytes: estimated,\n projectedWasmBytes: projectedWasm,\n };\n }\n }\n\n return {\n allow: true,\n estimatedFootprintBytes: estimated,\n projectedWasmBytes: projectedWasm,\n };\n}\n\nexport function wasmMemoryPressure(\n wasmLinearBytes: number,\n ceilingBytes: number = WASM_POOL_CEILING_BYTES,\n): MemorySnapshot['pressure'] {\n if (!(wasmLinearBytes > 0) || !(ceilingBytes > 0)) return 'unknown';\n const ratio = wasmLinearBytes / ceilingBytes;\n if (ratio >= 0.85) return 'high';\n if (ratio >= 0.7) return 'medium';\n return 'low';\n}\n"]}
@@ -0,0 +1,13 @@
1
+ export interface ModelManifestEntry {
2
+ modelId: string;
3
+ path: string;
4
+ sizeBytes: number;
5
+ sha256?: string;
6
+ sourceUrl?: string;
7
+ createdAt: number;
8
+ lastUsedAt: number;
9
+ }
10
+ export declare function listManifestEntries(): Promise<ModelManifestEntry[]>;
11
+ export declare function getManifestEntry(modelId: string): Promise<ModelManifestEntry | undefined>;
12
+ export declare function upsertManifestEntry(entry: ModelManifestEntry): Promise<void>;
13
+ export declare function removeManifestEntry(modelId: string): Promise<void>;
@@ -0,0 +1,87 @@
1
+ import { LlmError } from '../isomorphic/errors';
2
+ const MANIFEST_FILE = '.llm-manifest.json';
3
+ const getStorageApi = () => {
4
+ var _a;
5
+ const storageApi = (_a = globalThis === null || globalThis === void 0 ? void 0 : globalThis.navigator) === null || _a === void 0 ? void 0 : _a.storage;
6
+ if (!storageApi || typeof storageApi.getDirectory !== 'function') {
7
+ throw new LlmError('STORAGE_UNAVAILABLE', 'OPFS is not available in this runtime. navigator.storage.getDirectory is missing.');
8
+ }
9
+ return storageApi;
10
+ };
11
+ const getRootDirectory = async () => {
12
+ const storageApi = getStorageApi();
13
+ try {
14
+ return await storageApi.getDirectory();
15
+ }
16
+ catch (error) {
17
+ throw new LlmError('STORAGE_IO_FAILED', 'Failed to access OPFS root directory.', {
18
+ cause: String(error),
19
+ });
20
+ }
21
+ };
22
+ const readTextFile = async (fileHandle) => {
23
+ const file = await fileHandle.getFile();
24
+ return file.text();
25
+ };
26
+ const writeTextFile = async (fileHandle, content) => {
27
+ const writable = await fileHandle.createWritable();
28
+ try {
29
+ await writable.write(content);
30
+ }
31
+ finally {
32
+ await writable.close();
33
+ }
34
+ };
35
+ async function loadManifestInternal() {
36
+ const root = await getRootDirectory();
37
+ try {
38
+ const handle = await root.getFileHandle(MANIFEST_FILE, { create: true });
39
+ const content = await readTextFile(handle);
40
+ if (!content.trim()) {
41
+ return {};
42
+ }
43
+ const parsed = JSON.parse(content);
44
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
45
+ return {};
46
+ }
47
+ return parsed;
48
+ }
49
+ catch (error) {
50
+ throw new LlmError('STORAGE_IO_FAILED', 'Failed to read OPFS manifest.', {
51
+ cause: String(error),
52
+ });
53
+ }
54
+ }
55
+ async function saveManifestInternal(manifest) {
56
+ const root = await getRootDirectory();
57
+ try {
58
+ const handle = await root.getFileHandle(MANIFEST_FILE, { create: true });
59
+ await writeTextFile(handle, JSON.stringify(manifest, null, 2));
60
+ }
61
+ catch (error) {
62
+ throw new LlmError('STORAGE_IO_FAILED', 'Failed to write OPFS manifest.', {
63
+ cause: String(error),
64
+ });
65
+ }
66
+ }
67
+ export async function listManifestEntries() {
68
+ const manifest = await loadManifestInternal();
69
+ return Object.values(manifest);
70
+ }
71
+ export async function getManifestEntry(modelId) {
72
+ const manifest = await loadManifestInternal();
73
+ return manifest[modelId];
74
+ }
75
+ export async function upsertManifestEntry(entry) {
76
+ const manifest = await loadManifestInternal();
77
+ manifest[entry.modelId] = entry;
78
+ await saveManifestInternal(manifest);
79
+ }
80
+ export async function removeManifestEntry(modelId) {
81
+ const manifest = await loadManifestInternal();
82
+ if (manifest[modelId]) {
83
+ delete manifest[modelId];
84
+ await saveManifestInternal(manifest);
85
+ }
86
+ }
87
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../src/storage/manifest.ts"],"names":[],"mappings":"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","sourcesContent":["import { LlmError } from '../isomorphic/errors';\n\nexport interface ModelManifestEntry {\n modelId: string;\n path: string;\n sizeBytes: number;\n sha256?: string;\n sourceUrl?: string;\n createdAt: number;\n lastUsedAt: number;\n}\n\ntype ManifestMap = Record<string, ModelManifestEntry>;\n\nconst MANIFEST_FILE = '.llm-manifest.json';\n\nconst getStorageApi = (): any => {\n const storageApi = (globalThis as any)?.navigator?.storage;\n if (!storageApi || typeof storageApi.getDirectory !== 'function') {\n throw new LlmError(\n 'STORAGE_UNAVAILABLE',\n 'OPFS is not available in this runtime. navigator.storage.getDirectory is missing.',\n );\n }\n return storageApi;\n};\n\nconst getRootDirectory = async (): Promise<any> => {\n const storageApi = getStorageApi();\n try {\n return await storageApi.getDirectory();\n } catch (error) {\n throw new LlmError('STORAGE_IO_FAILED', 'Failed to access OPFS root directory.', {\n cause: String(error),\n });\n }\n};\n\nconst readTextFile = async (fileHandle: any): Promise<string> => {\n const file = await fileHandle.getFile();\n return file.text();\n};\n\nconst writeTextFile = async (fileHandle: any, content: string): Promise<void> => {\n const writable = await fileHandle.createWritable();\n try {\n await writable.write(content);\n } finally {\n await writable.close();\n }\n};\n\nasync function loadManifestInternal(): Promise<ManifestMap> {\n const root = await getRootDirectory();\n try {\n const handle = await root.getFileHandle(MANIFEST_FILE, { create: true });\n const content = await readTextFile(handle);\n if (!content.trim()) {\n return {};\n }\n const parsed = JSON.parse(content) as unknown;\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n return {};\n }\n return parsed as ManifestMap;\n } catch (error) {\n throw new LlmError('STORAGE_IO_FAILED', 'Failed to read OPFS manifest.', {\n cause: String(error),\n });\n }\n}\n\nasync function saveManifestInternal(manifest: ManifestMap): Promise<void> {\n const root = await getRootDirectory();\n try {\n const handle = await root.getFileHandle(MANIFEST_FILE, { create: true });\n await writeTextFile(handle, JSON.stringify(manifest, null, 2));\n } catch (error) {\n throw new LlmError('STORAGE_IO_FAILED', 'Failed to write OPFS manifest.', {\n cause: String(error),\n });\n }\n}\n\nexport async function listManifestEntries(): Promise<ModelManifestEntry[]> {\n const manifest = await loadManifestInternal();\n return Object.values(manifest);\n}\n\nexport async function getManifestEntry(modelId: string): Promise<ModelManifestEntry | undefined> {\n const manifest = await loadManifestInternal();\n return manifest[modelId];\n}\n\nexport async function upsertManifestEntry(entry: ModelManifestEntry): Promise<void> {\n const manifest = await loadManifestInternal();\n manifest[entry.modelId] = entry;\n await saveManifestInternal(manifest);\n}\n\nexport async function removeManifestEntry(modelId: string): Promise<void> {\n const manifest = await loadManifestInternal();\n if (manifest[modelId]) {\n delete manifest[modelId];\n await saveManifestInternal(manifest);\n }\n}\n\n"]}
@@ -0,0 +1,31 @@
1
+ import { type ModelManifestEntry } from './manifest';
2
+ export declare function ensureModelInOpfs(modelId: string, modelUrl: string, onProgress?: (downloaded: number, total: number) => void, signal?: AbortSignal): Promise<ModelManifestEntry>;
3
+ /**
4
+ * Choice 3 — primary web model load path.
5
+ * Opens an OPFS FileSystemSyncAccessHandle in the worker and reads the
6
+ * model in fixed-size chunks (default 4MB). Chunks are streamed into WASM
7
+ * MEMFS; the full GGUF is never materialised as a single JS ArrayBuffer.
8
+ *
9
+ * Worker-only: createSyncAccessHandle is not available on the main thread.
10
+ */
11
+ export declare const OPFS_MODEL_CHUNK_BYTES: number;
12
+ export interface OpfsModelSyncReader {
13
+ readonly sizeBytes: number;
14
+ readChunk(offset: number, length?: number): Uint8Array;
15
+ close(): void;
16
+ }
17
+ export declare function openOpfsModelSyncReader(modelId: string): Promise<OpfsModelSyncReader>;
18
+ /**
19
+ * Read the model from OPFS as an ArrayBuffer (fallback when sync handles
20
+ * are unavailable). Prefer openOpfsModelSyncReader in workers.
21
+ */
22
+ export declare function readModelBufferFromOpfs(modelId: string): Promise<{
23
+ buffer: ArrayBuffer;
24
+ sizeBytes: number;
25
+ }>;
26
+ export declare function readModelFromOpfs(modelId: string): Promise<File>;
27
+ export declare function removeModelFromOpfs(modelId: string): Promise<void>;
28
+ export declare function getOpfsUsage(): Promise<{
29
+ usedBytes: number;
30
+ quotaBytes?: number;
31
+ }>;