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,573 @@
1
+ import { LlmError } from './errors';
2
+ import { DefaultModelScheduler } from './model.scheduler';
3
+ import { WASM_MAX_CONCURRENT_MODELS, WASM_POOL_CEILING_BYTES, wasmMemoryPressure, } from './wasmMemoryPolicy';
4
+ import { ensureModelInOpfs, getOpfsUsage, } from '../storage/opfs.store';
5
+ import { getManifestEntry } from '../storage/manifest';
6
+ // ---------------------------------------------------------------------------
7
+ // Fix #10: Pre-flight capability checks
8
+ // ---------------------------------------------------------------------------
9
+ /** Verify that the browser supports everything the web WASM path needs. */
10
+ export function checkWasmCapabilities() {
11
+ var _a, _b;
12
+ const missing = [];
13
+ if (typeof WebAssembly !== 'object' || typeof WebAssembly.instantiate !== 'function') {
14
+ missing.push('WebAssembly');
15
+ }
16
+ if (typeof (globalThis === null || globalThis === void 0 ? void 0 : globalThis.Worker) === 'undefined') {
17
+ missing.push('Worker');
18
+ }
19
+ if (typeof ((_b = (_a = globalThis === null || globalThis === void 0 ? void 0 : globalThis.navigator) === null || _a === void 0 ? void 0 : _a.storage) === null || _b === void 0 ? void 0 : _b.getDirectory) !== 'function') {
20
+ missing.push('OPFS (navigator.storage.getDirectory)');
21
+ }
22
+ // WASM threads (needed for multi-threaded inference) require cross-origin
23
+ // isolation. Warn but don't block — single-threaded inference still works.
24
+ const coi = (globalThis === null || globalThis === void 0 ? void 0 : globalThis.crossOriginIsolated) === true;
25
+ const hasShared = typeof SharedArrayBuffer !== 'undefined';
26
+ if (!coi || !hasShared) {
27
+ // Not a hard failure — single-threaded WASM still functions.
28
+ // Callers can check this separately via checkCrossOriginIsolation().
29
+ }
30
+ return { supported: missing.length === 0, missing };
31
+ }
32
+ /** Returns true only when COOP/COEP headers are set for WASM threads. */
33
+ export function checkCrossOriginIsolation() {
34
+ return ((globalThis === null || globalThis === void 0 ? void 0 : globalThis.crossOriginIsolated) === true &&
35
+ typeof SharedArrayBuffer !== 'undefined');
36
+ }
37
+ const toError = (code, message, meta) => {
38
+ const knownCodes = [
39
+ 'MODEL_NOT_LOADED',
40
+ 'MODEL_LIMIT_REACHED',
41
+ 'INSUFFICIENT_MEMORY',
42
+ 'MODEL_DOWNLOAD_FAILED',
43
+ 'STORAGE_UNAVAILABLE',
44
+ 'STORAGE_IO_FAILED',
45
+ 'UNSUPPORTED_PLATFORM',
46
+ 'WASM_INIT_FAILED',
47
+ 'NATIVE_PLUGIN_UNAVAILABLE',
48
+ 'INFERENCE_FAILED',
49
+ 'INVALID_REQUEST',
50
+ ];
51
+ const normalizedCode = knownCodes.includes(code) ? code : 'INFERENCE_FAILED';
52
+ const text = message == null || message === ''
53
+ ? 'Unknown inference error'
54
+ : typeof message === 'string'
55
+ ? message
56
+ : String(message);
57
+ return new LlmError(normalizedCode, text, meta);
58
+ };
59
+ // ---------------------------------------------------------------------------
60
+ // Fix #11: Cross-browser memory snapshot using storage.estimate() fallback
61
+ // ---------------------------------------------------------------------------
62
+ async function getMemorySnapshotCrossBrowser() {
63
+ var _a, _b, _c, _d;
64
+ // performance.memory is Chromium-only and non-standard. Use it when present,
65
+ // otherwise fall back to storage.estimate() which is universally available.
66
+ const perfMem = (_a = globalThis === null || globalThis === void 0 ? void 0 : globalThis.performance) === null || _a === void 0 ? void 0 : _a.memory;
67
+ if (perfMem && typeof perfMem.jsHeapSizeLimit === 'number' && perfMem.jsHeapSizeLimit > 0) {
68
+ const totalBytes = Number(perfMem.jsHeapSizeLimit);
69
+ const usedBytes = Number(perfMem.usedJSHeapSize);
70
+ const freeBytes = totalBytes - usedBytes;
71
+ const usedRatio = usedBytes / totalBytes;
72
+ const pressure = usedRatio >= 0.85 ? 'high' : usedRatio >= 0.7 ? 'medium' : 'low';
73
+ return { totalBytes, usedBytes, freeBytes, pressure };
74
+ }
75
+ // Fallback: use OPFS storage quota as a coarse proxy for available memory.
76
+ // Not perfect but gives the admission controller a real number to work with
77
+ // on Safari/Firefox instead of always returning undefined (which caused the
78
+ // memory guard to be silently bypassed — fix #11).
79
+ try {
80
+ const est = await ((_d = (_c = (_b = globalThis === null || globalThis === void 0 ? void 0 : globalThis.navigator) === null || _b === void 0 ? void 0 : _b.storage) === null || _c === void 0 ? void 0 : _c.estimate) === null || _d === void 0 ? void 0 : _d.call(_c));
81
+ if (est && typeof est.quota === 'number' && typeof est.usage === 'number') {
82
+ const totalBytes = est.quota;
83
+ const usedBytes = est.usage;
84
+ const freeBytes = totalBytes - usedBytes;
85
+ const usedRatio = totalBytes > 0 ? usedBytes / totalBytes : 0;
86
+ const pressure = usedRatio >= 0.85 ? 'high' : usedRatio >= 0.7 ? 'medium' : 'low';
87
+ return { totalBytes, usedBytes, freeBytes, pressure };
88
+ }
89
+ }
90
+ catch (_e) {
91
+ // ignore
92
+ }
93
+ return { pressure: 'unknown' };
94
+ }
95
+ // ---------------------------------------------------------------------------
96
+ // WebProvider
97
+ // ---------------------------------------------------------------------------
98
+ export class WebProvider {
99
+ constructor(workerFactoryOverride) {
100
+ this.workerFactoryOverride = workerFactoryOverride;
101
+ this.platform = 'web';
102
+ this.loadedModelIds = new Set();
103
+ this.worker = null;
104
+ this.reqCounter = 0;
105
+ this.pending = new Map();
106
+ // Fix #5: wire the scheduler so admission control is enforced on the web path.
107
+ this.scheduler = new DefaultModelScheduler(WASM_MAX_CONCURRENT_MODELS);
108
+ }
109
+ static setWorkerFactory(factory) {
110
+ WebProvider.globalWorkerFactory = factory;
111
+ }
112
+ // Fix #15: resolve compiled worker .js first; fall back to .ts for dev.
113
+ resolveWorkerUrl() {
114
+ const customUrl = globalThis === null || globalThis === void 0 ? void 0 : globalThis.__LLAMA_WORKER_URL__;
115
+ if (typeof customUrl === 'string' && customUrl.length > 0) {
116
+ return customUrl;
117
+ }
118
+ try {
119
+ const metaUrl = new Function('return import.meta.url')();
120
+ return new URL('../../dist/workers/llm.worker.js', metaUrl);
121
+ }
122
+ catch (_a) {
123
+ return '/dist/workers/llm.worker.js';
124
+ }
125
+ }
126
+ defaultWorkerFactory() {
127
+ return new Worker(this.resolveWorkerUrl(), { type: 'module' });
128
+ }
129
+ ensureWorker() {
130
+ var _a, _b;
131
+ if (this.worker)
132
+ return this.worker;
133
+ const factory = (_b = (_a = this.workerFactoryOverride) !== null && _a !== void 0 ? _a : WebProvider.globalWorkerFactory) !== null && _b !== void 0 ? _b : (() => this.defaultWorkerFactory());
134
+ const worker = factory();
135
+ worker.onmessage = (evt) => {
136
+ var _a, _b;
137
+ const message = evt.data;
138
+ const request = this.pending.get(message.id);
139
+ if (!request)
140
+ return;
141
+ if (message.type === 'TOKEN') {
142
+ (_a = request.onToken) === null || _a === void 0 ? void 0 : _a.call(request, {
143
+ modelId: message.modelId,
144
+ token: message.token,
145
+ index: message.index,
146
+ });
147
+ return;
148
+ }
149
+ if (message.type === 'PROGRESS') {
150
+ (_b = request.onProgress) === null || _b === void 0 ? void 0 : _b.call(request, message.downloaded, message.total);
151
+ return;
152
+ }
153
+ if (message.type === 'RESULT') {
154
+ this.pending.delete(message.id);
155
+ request.resolve(message.payload);
156
+ return;
157
+ }
158
+ this.pending.delete(message.id);
159
+ request.reject(toError(message.code, message.message, message.meta));
160
+ };
161
+ worker.onerror = (evt) => {
162
+ const err = toError('INFERENCE_FAILED', `Web worker error: ${evt.message || 'unknown worker error'}`);
163
+ for (const [id, req] of this.pending.entries()) {
164
+ this.pending.delete(id);
165
+ req.reject(err);
166
+ }
167
+ };
168
+ this.worker = worker;
169
+ return worker;
170
+ }
171
+ sendRequest(request, onToken, onProgress) {
172
+ const worker = this.ensureWorker();
173
+ const id = `req_${Date.now()}_${this.reqCounter++}`;
174
+ const message = Object.assign(Object.assign({}, request), { id });
175
+ return new Promise((resolve, reject) => {
176
+ this.pending.set(id, { resolve, reject, onToken, onProgress });
177
+ try {
178
+ // Fix #9: no Transferable[] needed — the ArrayBuffer lives in the worker
179
+ worker.postMessage(message);
180
+ }
181
+ catch (error) {
182
+ this.pending.delete(id);
183
+ reject(toError('INFERENCE_FAILED', 'Failed to post request to wasm worker.', {
184
+ cause: String(error),
185
+ requestType: request.type,
186
+ }));
187
+ }
188
+ });
189
+ }
190
+ async initialize(opts) {
191
+ // Fix #10: gate on capability check before touching the worker.
192
+ // Skip when a custom worker factory is injected (tests / custom hosts).
193
+ const usingCustomWorker = !!this.workerFactoryOverride || !!WebProvider.globalWorkerFactory;
194
+ if (!usingCustomWorker) {
195
+ const caps = checkWasmCapabilities();
196
+ if (!caps.supported) {
197
+ throw new LlmError('UNSUPPORTED_PLATFORM', `Missing browser capabilities for WASM inference: ${caps.missing.join(', ')}`, { missing: caps.missing });
198
+ }
199
+ }
200
+ await this.sendRequest({ type: 'INIT' });
201
+ await this.loadModel(opts);
202
+ }
203
+ async loadModel(opts) {
204
+ var _a, _b, _c;
205
+ if (!opts.modelId) {
206
+ throw new LlmError('INVALID_REQUEST', 'modelId is required');
207
+ }
208
+ if (this.loadedModelIds.has(opts.modelId)) {
209
+ return;
210
+ }
211
+ const existing = await getManifestEntry(opts.modelId);
212
+ if (!existing && !opts.modelUrl) {
213
+ throw new LlmError('INVALID_REQUEST', 'modelUrl is required for first-time web load when model is not cached in OPFS.');
214
+ }
215
+ // Download and persist to OPFS if needed (#6: with progress events).
216
+ if (!existing && opts.modelUrl) {
217
+ await ensureModelInOpfs(opts.modelId, opts.modelUrl, opts.onProgress);
218
+ }
219
+ // Fix #5: enforce admission control (memory guard + slot limit) BEFORE
220
+ // asking the worker to load, using a real memory snapshot (#11).
221
+ const memory = await getMemorySnapshotCrossBrowser();
222
+ const wasmMemory = await this.fetchWorkerMemory().catch(() => ({}));
223
+ const wasmLinearBytes = typeof wasmMemory.wasmLinearBytes === 'number' ? wasmMemory.wasmLinearBytes : undefined;
224
+ const manifestEntry = existing !== null && existing !== void 0 ? existing : (await getManifestEntry(opts.modelId));
225
+ const modelBytes = (_a = manifestEntry === null || manifestEntry === void 0 ? void 0 : manifestEntry.sizeBytes) !== null && _a !== void 0 ? _a : 0;
226
+ this.scheduler.ensureCapacity(opts.modelId, modelBytes, memory, undefined, {
227
+ wasmLinearBytes,
228
+ wasmPoolCeilingBytes: WASM_POOL_CEILING_BYTES,
229
+ loadOpts: {
230
+ n_ctx: opts.n_ctx,
231
+ n_batch: opts.n_batch,
232
+ embedding: opts.embedding,
233
+ },
234
+ });
235
+ // Fix #9: send modelId only — the worker reads from OPFS internally.
236
+ const loadResult = await this.sendRequest({
237
+ type: 'LOAD_MODEL',
238
+ modelId: opts.modelId,
239
+ opts: {
240
+ modelPath: (_c = (_b = opts.modelPath) !== null && _b !== void 0 ? _b : opts.model_path) !== null && _c !== void 0 ? _c : manifestEntry === null || manifestEntry === void 0 ? void 0 : manifestEntry.path,
241
+ modelBytes,
242
+ n_ctx: opts.n_ctx,
243
+ n_batch: opts.n_batch,
244
+ n_gpu_layers: opts.n_gpu_layers,
245
+ n_threads: opts.n_threads,
246
+ embedding: opts.embedding,
247
+ use_mmap: opts.use_mmap,
248
+ preferVfsStreaming: opts.preferVfsStreaming,
249
+ },
250
+ }, undefined, opts.onProgress);
251
+ let measuredFootprint = loadResult.measuredFootprintBytes;
252
+ if (!(typeof measuredFootprint === 'number' && measuredFootprint > 0)) {
253
+ const workerMem = await this.fetchWorkerMemory().catch(() => ({}));
254
+ measuredFootprint = this.readMeasuredFootprintFromWorker(workerMem, opts.modelId);
255
+ }
256
+ this.loadedModelIds.add(opts.modelId);
257
+ this.scheduler.markLoaded(opts.modelId, modelBytes, {
258
+ n_ctx: opts.n_ctx,
259
+ n_batch: opts.n_batch,
260
+ embedding: opts.embedding,
261
+ }, measuredFootprint);
262
+ if (typeof measuredFootprint === 'number' && measuredFootprint > 0) {
263
+ this.scheduler.calibrateFootprint(opts.modelId, measuredFootprint);
264
+ }
265
+ }
266
+ readMeasuredFootprintFromWorker(workerMem, modelId) {
267
+ const models = workerMem.loadedModels;
268
+ if (!Array.isArray(models))
269
+ return undefined;
270
+ for (const row of models) {
271
+ if (!row || typeof row !== 'object')
272
+ continue;
273
+ const entry = row;
274
+ if (entry.modelId !== modelId)
275
+ continue;
276
+ if (typeof entry.measuredFootprintBytes === 'number' && entry.measuredFootprintBytes > 0) {
277
+ return entry.measuredFootprintBytes;
278
+ }
279
+ }
280
+ return undefined;
281
+ }
282
+ async unloadModel(modelId) {
283
+ if (!this.loadedModelIds.has(modelId)) {
284
+ return;
285
+ }
286
+ await this.sendRequest({ type: 'UNLOAD_MODEL', modelId });
287
+ this.loadedModelIds.delete(modelId);
288
+ this.scheduler.markUnloaded(modelId);
289
+ }
290
+ async generate(req) {
291
+ if (!this.loadedModelIds.has(req.modelId)) {
292
+ throw new LlmError('MODEL_NOT_LOADED', `Model '${req.modelId}' is not loaded`);
293
+ }
294
+ return this.sendRequest({
295
+ type: 'GENERATE',
296
+ modelId: req.modelId,
297
+ req: {
298
+ prompt: req.prompt,
299
+ messages: req.messages,
300
+ max_tokens: req.max_tokens,
301
+ temperature: req.temperature,
302
+ stream: false,
303
+ },
304
+ });
305
+ }
306
+ async generateStream(req, onToken) {
307
+ if (!this.loadedModelIds.has(req.modelId)) {
308
+ throw new LlmError('MODEL_NOT_LOADED', `Model '${req.modelId}' is not loaded`);
309
+ }
310
+ return this.sendRequest({
311
+ type: 'GENERATE',
312
+ modelId: req.modelId,
313
+ req: {
314
+ prompt: req.prompt,
315
+ messages: req.messages,
316
+ max_tokens: req.max_tokens,
317
+ temperature: req.temperature,
318
+ stream: true,
319
+ },
320
+ }, onToken);
321
+ }
322
+ async embed(req) {
323
+ if (!this.loadedModelIds.has(req.modelId)) {
324
+ throw new LlmError('MODEL_NOT_LOADED', `Model '${req.modelId}' is not loaded`);
325
+ }
326
+ return this.sendRequest({
327
+ type: 'EMBED',
328
+ modelId: req.modelId,
329
+ input: req.input,
330
+ });
331
+ }
332
+ // Fix #11: use cross-browser memory snapshot instead of performance.memory only.
333
+ async getMemorySnapshot() {
334
+ return getMemorySnapshotCrossBrowser();
335
+ }
336
+ /** Worker WASM linear memory + loaded-model registry (for scheduling UI). */
337
+ async fetchWorkerMemory() {
338
+ return this.sendRequest({ type: 'MEMORY' });
339
+ }
340
+ async getWasmMemoryStatus() {
341
+ const [browser, workerRaw] = await Promise.all([
342
+ getMemorySnapshotCrossBrowser(),
343
+ this.fetchWorkerMemory().catch(() => ({})),
344
+ ]);
345
+ const worker = workerRaw;
346
+ const wasmLinearBytes = typeof worker.wasmLinearBytes === 'number' ? worker.wasmLinearBytes : undefined;
347
+ return {
348
+ browser,
349
+ worker,
350
+ wasmLinearBytes,
351
+ wasmPoolCeilingBytes: WASM_POOL_CEILING_BYTES,
352
+ wasmHeadroomBytes: typeof wasmLinearBytes === 'number'
353
+ ? Math.max(0, WASM_POOL_CEILING_BYTES - wasmLinearBytes)
354
+ : undefined,
355
+ pressure: typeof wasmLinearBytes === 'number'
356
+ ? wasmMemoryPressure(wasmLinearBytes, WASM_POOL_CEILING_BYTES)
357
+ : browser.pressure,
358
+ loadedModels: this.loadedModelIds.size,
359
+ maxModels: WASM_MAX_CONCURRENT_MODELS,
360
+ schedulerFootprintBytes: this.scheduler.totalFootprintBytes(),
361
+ };
362
+ }
363
+ async tokenize(modelId, text) {
364
+ if (!this.loadedModelIds.has(modelId)) {
365
+ throw new LlmError('MODEL_NOT_LOADED', `Model '${modelId}' is not loaded`);
366
+ }
367
+ return this.sendRequest({ type: 'TOKENIZE', modelId, text });
368
+ }
369
+ async detokenize(modelId, tokens) {
370
+ if (!this.loadedModelIds.has(modelId)) {
371
+ throw new LlmError('MODEL_NOT_LOADED', `Model '${modelId}' is not loaded`);
372
+ }
373
+ return this.sendRequest({ type: 'DETOKENIZE', modelId, tokens });
374
+ }
375
+ async convertJsonSchemaToGrammar(schemaJson) {
376
+ // CONVERT_GRAMMAR is context-free — no model needs to be loaded.
377
+ // The worker must be initialised (INIT sent), but that happens on first use.
378
+ const result = await this.sendRequest({
379
+ type: 'CONVERT_GRAMMAR',
380
+ schemaJson,
381
+ });
382
+ return result.grammar;
383
+ }
384
+ requireLoaded(modelId) {
385
+ if (!this.loadedModelIds.has(modelId)) {
386
+ throw new LlmError('MODEL_NOT_LOADED', `Model '${modelId}' is not loaded`);
387
+ }
388
+ }
389
+ async rerank(modelId, query, documents) {
390
+ this.requireLoaded(modelId);
391
+ const result = await this.sendRequest({
392
+ type: 'RERANK',
393
+ modelId,
394
+ query,
395
+ documents,
396
+ });
397
+ return result.results;
398
+ }
399
+ async bench(modelId, pp, tg, pl, nr) {
400
+ this.requireLoaded(modelId);
401
+ const result = await this.sendRequest({
402
+ type: 'BENCH',
403
+ modelId,
404
+ pp,
405
+ tg,
406
+ pl,
407
+ nr,
408
+ });
409
+ return result.result;
410
+ }
411
+ async saveSession(modelId, filepath, tokenSize) {
412
+ this.requireLoaded(modelId);
413
+ const result = await this.sendRequest({
414
+ type: 'SAVE_SESSION',
415
+ modelId,
416
+ filepath,
417
+ tokenSize,
418
+ });
419
+ return result.tokens_saved;
420
+ }
421
+ async loadSession(modelId, filepath) {
422
+ this.requireLoaded(modelId);
423
+ return this.sendRequest({
424
+ type: 'LOAD_SESSION',
425
+ modelId,
426
+ filepath,
427
+ });
428
+ }
429
+ async applyLoraAdapters(modelId, loraAdapters) {
430
+ this.requireLoaded(modelId);
431
+ await this.sendRequest({
432
+ type: 'APPLY_LORA',
433
+ modelId,
434
+ loraAdapters,
435
+ });
436
+ }
437
+ async removeLoraAdapters(modelId) {
438
+ this.requireLoaded(modelId);
439
+ await this.sendRequest({ type: 'REMOVE_LORA', modelId });
440
+ }
441
+ async getLoadedLoraAdapters(modelId) {
442
+ this.requireLoaded(modelId);
443
+ const result = await this.sendRequest({
444
+ type: 'GET_LORA',
445
+ modelId,
446
+ });
447
+ return result.adapters;
448
+ }
449
+ async initMultimodal(modelId, path, useGpu = false) {
450
+ this.requireLoaded(modelId);
451
+ const result = await this.sendRequest({
452
+ type: 'INIT_MULTIMODAL',
453
+ modelId,
454
+ path,
455
+ useGpu,
456
+ });
457
+ return !!result.ok;
458
+ }
459
+ async isMultimodalEnabled(modelId) {
460
+ this.requireLoaded(modelId);
461
+ const result = await this.sendRequest({
462
+ type: 'MULTIMODAL_STATUS',
463
+ modelId,
464
+ });
465
+ return !!result.enabled;
466
+ }
467
+ async getMultimodalSupport(modelId) {
468
+ this.requireLoaded(modelId);
469
+ const result = await this.sendRequest({
470
+ type: 'MULTIMODAL_STATUS',
471
+ modelId,
472
+ });
473
+ return { vision: !!result.vision, audio: !!result.audio };
474
+ }
475
+ async releaseMultimodal(modelId) {
476
+ await this.sendRequest({ type: 'RELEASE_MULTIMODAL', modelId });
477
+ }
478
+ async initVocoder(modelId, path, nBatch = 512) {
479
+ this.requireLoaded(modelId);
480
+ const result = await this.sendRequest({
481
+ type: 'INIT_VOCODER',
482
+ modelId,
483
+ path,
484
+ nBatch,
485
+ });
486
+ return !!result.ok;
487
+ }
488
+ async isVocoderEnabled(modelId) {
489
+ this.requireLoaded(modelId);
490
+ const result = await this.sendRequest({
491
+ type: 'VOCODER_ENABLED',
492
+ modelId,
493
+ });
494
+ return !!result.enabled;
495
+ }
496
+ async releaseVocoder(modelId) {
497
+ await this.sendRequest({ type: 'RELEASE_VOCODER', modelId });
498
+ }
499
+ async getFormattedAudioCompletion(modelId, speaker, textToSpeak) {
500
+ this.requireLoaded(modelId);
501
+ return this.sendRequest({
502
+ type: 'FORMATTED_AUDIO',
503
+ modelId,
504
+ speakerJson: speaker ? JSON.stringify(speaker) : '',
505
+ textToSpeak,
506
+ });
507
+ }
508
+ async getAudioCompletionGuideTokens(modelId, textToSpeak) {
509
+ this.requireLoaded(modelId);
510
+ const result = await this.sendRequest({
511
+ type: 'AUDIO_GUIDE_TOKENS',
512
+ modelId,
513
+ textToSpeak,
514
+ });
515
+ return result.tokens;
516
+ }
517
+ async decodeAudioTokens(modelId, tokens) {
518
+ this.requireLoaded(modelId);
519
+ const result = await this.sendRequest({
520
+ type: 'DECODE_AUDIO_TOKENS',
521
+ modelId,
522
+ tokens,
523
+ });
524
+ return result.audio;
525
+ }
526
+ /**
527
+ * Terminate the worker mid-inference. WASM is single-threaded, so posting
528
+ * an abort message cannot be received while generate() is running. Worker
529
+ * termination is the only reliable interrupt. The model will need to be
530
+ * reloaded on the next generate() call.
531
+ */
532
+ stopGeneration() {
533
+ if (!this.worker)
534
+ return;
535
+ this.worker.terminate();
536
+ this.worker = null;
537
+ const interrupted = toError('INFERENCE_FAILED', 'Generation stopped by caller.');
538
+ for (const [id, req] of this.pending.entries()) {
539
+ this.pending.delete(id);
540
+ req.reject(interrupted);
541
+ }
542
+ // Worker is gone, so all previously tracked model IDs are invalid.
543
+ this.loadedModelIds.clear();
544
+ for (const id of this.scheduler.listLoaded()) {
545
+ this.scheduler.markUnloaded(id);
546
+ }
547
+ }
548
+ async health() {
549
+ const usage = await getOpfsUsage().catch(() => ({
550
+ usedBytes: 0,
551
+ quotaBytes: undefined,
552
+ }));
553
+ const workerHealth = await this.sendRequest({ type: 'HEALTH' }).catch((error) => ({
554
+ ok: false,
555
+ message: error instanceof Error ? error.message : String(error),
556
+ }));
557
+ const workerRecord = workerHealth;
558
+ const workerDetails = workerRecord.details;
559
+ return {
560
+ ok: !!(workerHealth === null || workerHealth === void 0 ? void 0 : workerHealth.ok),
561
+ details: {
562
+ loadedModels: this.loadedModelIds.size,
563
+ opfsUsedBytes: usage.usedBytes,
564
+ opfsQuotaBytes: usage.quotaBytes,
565
+ worker: workerHealth,
566
+ crossOriginIsolated: checkCrossOriginIsolation(),
567
+ wasmJspi: workerDetails === null || workerDetails === void 0 ? void 0 : workerDetails.wasmJspi,
568
+ wasmPthread: workerDetails === null || workerDetails === void 0 ? void 0 : workerDetails.wasmPthread,
569
+ },
570
+ };
571
+ }
572
+ }
573
+ //# sourceMappingURL=provider.web.js.map