@qvac/sdk 0.10.2 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (326) hide show
  1. package/NOTICE +1455 -29
  2. package/README.md +2 -0
  3. package/dist/client/api/cancel.d.ts +24 -32
  4. package/dist/client/api/cancel.js +58 -31
  5. package/dist/client/api/classify.d.ts +23 -0
  6. package/dist/client/api/classify.js +43 -0
  7. package/dist/client/api/client-request-id.d.ts +17 -0
  8. package/dist/client/api/client-request-id.js +27 -0
  9. package/dist/client/api/completion-stream.d.ts +1 -1
  10. package/dist/client/api/completion-stream.js +34 -3
  11. package/dist/client/api/diffusion.d.ts +46 -0
  12. package/dist/client/api/diffusion.js +50 -1
  13. package/dist/client/api/download-asset.d.ts +12 -2
  14. package/dist/client/api/download-asset.js +21 -3
  15. package/dist/client/api/embed.d.ts +8 -4
  16. package/dist/client/api/embed.js +14 -1
  17. package/dist/client/api/get-model-info.d.ts +1 -1
  18. package/dist/client/api/index.d.ts +5 -0
  19. package/dist/client/api/index.js +5 -0
  20. package/dist/client/api/load-model.d.ts +12 -4
  21. package/dist/client/api/load-model.js +49 -2
  22. package/dist/client/api/rag.d.ts +9 -3
  23. package/dist/client/api/rag.js +23 -3
  24. package/dist/client/api/transcribe.d.ts +23 -8
  25. package/dist/client/api/transcribe.js +69 -4
  26. package/dist/client/api/unload-model.d.ts +5 -2
  27. package/dist/client/api/unload-model.js +9 -4
  28. package/dist/client/api/upscale.d.ts +45 -0
  29. package/dist/client/api/upscale.js +99 -0
  30. package/dist/client/api/video.d.ts +64 -0
  31. package/dist/client/api/video.js +147 -0
  32. package/dist/client/api/vla-helpers.d.ts +45 -0
  33. package/dist/client/api/vla-helpers.js +130 -0
  34. package/dist/client/api/vla.d.ts +65 -0
  35. package/dist/client/api/vla.js +109 -0
  36. package/dist/client/config-loader/resolve-config.node.d.ts +16 -0
  37. package/dist/client/config-loader/resolve-config.node.js +77 -23
  38. package/dist/client/plugins-factory.d.ts +8 -0
  39. package/dist/client/plugins-factory.js +10 -0
  40. package/dist/client/rpc/bare-client.js +62 -66
  41. package/dist/client/rpc/ensure-worker-ready.d.ts +9 -0
  42. package/dist/client/rpc/ensure-worker-ready.js +17 -0
  43. package/dist/client/rpc/expo-rpc-client.js +2 -1
  44. package/dist/client/rpc/node-rpc-client.js +22 -8
  45. package/dist/client/rpc/rpc-client.d.ts +2 -2
  46. package/dist/client/rpc/rpc-client.js +10 -4
  47. package/dist/client/rpc/rpc-error.d.ts +9 -0
  48. package/dist/client/rpc/rpc-error.js +105 -0
  49. package/dist/commands/bundle/bare-pack.d.ts +13 -0
  50. package/dist/commands/bundle/bare-pack.js +54 -0
  51. package/dist/commands/bundle/constants.d.ts +7 -0
  52. package/dist/commands/bundle/constants.js +23 -0
  53. package/dist/commands/bundle/entry-gen.d.ts +2 -0
  54. package/dist/commands/bundle/entry-gen.js +48 -0
  55. package/dist/commands/bundle/index.d.ts +20 -0
  56. package/dist/commands/bundle/index.js +141 -0
  57. package/dist/commands/bundle/manifest.d.ts +21 -0
  58. package/dist/commands/bundle/manifest.js +193 -0
  59. package/dist/commands/bundle/plugins.d.ts +9 -0
  60. package/dist/commands/bundle/plugins.js +51 -0
  61. package/dist/commands/index.d.ts +5 -0
  62. package/dist/commands/index.js +2 -0
  63. package/dist/commands/verify/abi.d.ts +52 -0
  64. package/dist/commands/verify/abi.js +125 -0
  65. package/dist/commands/verify/addon-source.d.ts +43 -0
  66. package/dist/commands/verify/addon-source.js +75 -0
  67. package/dist/commands/verify/bundle-source.d.ts +12 -0
  68. package/dist/commands/verify/bundle-source.js +53 -0
  69. package/dist/commands/verify/index.d.ts +59 -0
  70. package/dist/commands/verify/index.js +371 -0
  71. package/dist/commands/verify/node-modules-source.d.ts +11 -0
  72. package/dist/commands/verify/node-modules-source.js +76 -0
  73. package/dist/commands/verify/prebuilds.d.ts +15 -0
  74. package/dist/commands/verify/prebuilds.js +39 -0
  75. package/dist/examples/cancel-by-request-id.d.ts +38 -0
  76. package/dist/examples/cancel-by-request-id.js +103 -0
  77. package/dist/examples/classification/classify-image.d.ts +2 -0
  78. package/dist/examples/classification/classify-image.js +23 -0
  79. package/dist/examples/diffusion-esrgan-upscale.d.ts +2 -0
  80. package/dist/examples/diffusion-esrgan-upscale.js +78 -0
  81. package/dist/examples/diffusion-txt2vid.d.ts +2 -0
  82. package/dist/examples/diffusion-txt2vid.js +81 -0
  83. package/dist/examples/download-with-cancel.js +10 -10
  84. package/dist/examples/embed-multi-gpu.d.ts +2 -0
  85. package/dist/examples/embed-multi-gpu.js +46 -0
  86. package/dist/examples/llamacpp-multi-gpu.d.ts +2 -0
  87. package/dist/examples/llamacpp-multi-gpu.js +57 -0
  88. package/dist/examples/plugins.js +3 -7
  89. package/dist/examples/rag/rag-hyperdb/cancellation.js +20 -17
  90. package/dist/examples/tools/llamacpp-tools-gemma4.d.ts +2 -0
  91. package/dist/examples/tools/llamacpp-tools-gemma4.js +73 -0
  92. package/dist/examples/tools/llamacpp-tools-qwen35.d.ts +2 -0
  93. package/dist/examples/tools/llamacpp-tools-qwen35.js +69 -0
  94. package/dist/examples/transcription/parakeet-ctc-filesystem.js +18 -12
  95. package/dist/examples/transcription/parakeet-microphone-record.js +7 -12
  96. package/dist/examples/transcription/parakeet-microphone-stream.d.ts +2 -0
  97. package/dist/examples/transcription/parakeet-microphone-stream.js +79 -0
  98. package/dist/examples/transcription/parakeet-sortformer-streaming.d.ts +2 -0
  99. package/dist/examples/transcription/parakeet-sortformer-streaming.js +121 -0
  100. package/dist/examples/transcription/parakeet-sortformer.js +58 -55
  101. package/dist/examples/transcription/parakeet-tdt-filesystem.js +18 -15
  102. package/dist/examples/transcription/whispercpp-microphone-conversation.d.ts +2 -0
  103. package/dist/examples/transcription/whispercpp-microphone-conversation.js +107 -0
  104. package/dist/examples/tts/chatterbox.js +7 -16
  105. package/dist/examples/tts/llm-to-tts-streaming.js +3 -10
  106. package/dist/examples/tts/supertonic-multilingual.js +4 -12
  107. package/dist/examples/tts/supertonic.js +5 -12
  108. package/dist/examples/vla-smolvla.d.ts +2 -0
  109. package/dist/examples/vla-smolvla.js +75 -0
  110. package/dist/examples/voice-assistant/voice-assistant.js +3 -10
  111. package/dist/expo/plugins/find-in-ancestor-node-modules.d.ts +14 -0
  112. package/dist/expo/plugins/find-in-ancestor-node-modules.js +24 -0
  113. package/dist/expo/plugins/get-project-root.d.ts +22 -0
  114. package/dist/expo/plugins/get-project-root.js +23 -0
  115. package/dist/expo/plugins/index.d.ts +4 -0
  116. package/dist/expo/plugins/index.js +4 -0
  117. package/dist/expo/plugins/resolve-sdk-package-dir.d.ts +9 -2
  118. package/dist/expo/plugins/resolve-sdk-package-dir.js +38 -11
  119. package/dist/expo/plugins/withDeviceInfo.js +2 -1
  120. package/dist/expo/plugins/withMobileBundle.d.ts +5 -4
  121. package/dist/expo/plugins/withMobileBundle.js +42 -58
  122. package/dist/index.d.ts +6 -2
  123. package/dist/index.js +23 -2
  124. package/dist/models/registry/models.d.ts +3725 -514
  125. package/dist/models/registry/models.js +7269 -3910
  126. package/dist/models/update-models/naming.js +22 -8
  127. package/dist/pear/pre.d.ts +3 -0
  128. package/dist/pear/pre.js +9 -2
  129. package/dist/schemas/cancel.d.ts +172 -28
  130. package/dist/schemas/cancel.js +120 -19
  131. package/dist/schemas/classification.d.ts +53 -0
  132. package/dist/schemas/classification.js +33 -0
  133. package/dist/schemas/common.d.ts +860 -1379
  134. package/dist/schemas/common.js +8 -1
  135. package/dist/schemas/completion-event.d.ts +17 -0
  136. package/dist/schemas/completion-event.js +12 -1
  137. package/dist/schemas/completion-stream.d.ts +16 -1
  138. package/dist/schemas/completion-stream.js +25 -7
  139. package/dist/schemas/download-asset.d.ts +25 -9
  140. package/dist/schemas/download-asset.js +17 -6
  141. package/dist/schemas/embed.d.ts +1 -0
  142. package/dist/schemas/embed.js +5 -0
  143. package/dist/schemas/engine-addon-map.d.ts +3 -0
  144. package/dist/schemas/engine-addon-map.js +18 -5
  145. package/dist/schemas/error.d.ts +31 -0
  146. package/dist/schemas/error.js +29 -1
  147. package/dist/schemas/finetune.d.ts +2 -0
  148. package/dist/schemas/finetune.js +5 -0
  149. package/dist/schemas/get-model-info.d.ts +10 -6
  150. package/dist/schemas/get-model-info.js +2 -0
  151. package/dist/schemas/index.d.ts +3 -0
  152. package/dist/schemas/index.js +3 -0
  153. package/dist/schemas/llamacpp-config.d.ts +64 -8
  154. package/dist/schemas/llamacpp-config.js +12 -0
  155. package/dist/schemas/load-model.d.ts +4644 -8605
  156. package/dist/schemas/load-model.js +90 -7
  157. package/dist/schemas/model-src-utils.d.ts +34 -14
  158. package/dist/schemas/model-types.d.ts +54 -14
  159. package/dist/schemas/model-types.js +28 -5
  160. package/dist/schemas/ocr.d.ts +8 -3
  161. package/dist/schemas/plugin.d.ts +60 -6
  162. package/dist/schemas/plugin.js +31 -5
  163. package/dist/schemas/rag.d.ts +9 -0
  164. package/dist/schemas/rag.js +17 -9
  165. package/dist/schemas/registry.d.ts +74 -30
  166. package/dist/schemas/registry.js +5 -0
  167. package/dist/schemas/reload-config.d.ts +34 -14
  168. package/dist/schemas/sdcpp-config.d.ts +445 -16
  169. package/dist/schemas/sdcpp-config.js +387 -26
  170. package/dist/schemas/sdk-config.d.ts +2431 -2723
  171. package/dist/schemas/sdk-config.js +16 -1
  172. package/dist/schemas/sdk-errors-client.d.ts +6 -0
  173. package/dist/schemas/sdk-errors-client.js +31 -1
  174. package/dist/schemas/sdk-errors-server.d.ts +8 -1
  175. package/dist/schemas/sdk-errors-server.js +45 -5
  176. package/dist/schemas/text-to-speech.d.ts +81 -698
  177. package/dist/schemas/text-to-speech.js +46 -19
  178. package/dist/schemas/transcription-config.d.ts +40 -229
  179. package/dist/schemas/transcription-config.js +76 -15
  180. package/dist/schemas/transcription.d.ts +108 -2
  181. package/dist/schemas/transcription.js +81 -0
  182. package/dist/schemas/translate.d.ts +2 -0
  183. package/dist/schemas/translate.js +13 -2
  184. package/dist/schemas/translation-config.d.ts +90 -40
  185. package/dist/schemas/unload-model.d.ts +2 -1
  186. package/dist/schemas/unload-model.js +4 -1
  187. package/dist/schemas/vla.d.ts +87 -0
  188. package/dist/schemas/vla.js +108 -0
  189. package/dist/scripts/run-unit-tests.js +22 -3
  190. package/dist/server/bare/ops/cancel.d.ts +27 -1
  191. package/dist/server/bare/ops/cancel.js +36 -10
  192. package/dist/server/bare/ops/embed.d.ts +3 -3
  193. package/dist/server/bare/ops/embed.js +144 -28
  194. package/dist/server/bare/ops/kv-cache-utils.d.ts +0 -7
  195. package/dist/server/bare/ops/kv-cache-utils.js +8 -47
  196. package/dist/server/bare/ops/transcribe.d.ts +11 -5
  197. package/dist/server/bare/ops/transcribe.js +230 -50
  198. package/dist/server/bare/ops/translate.d.ts +1 -1
  199. package/dist/server/bare/ops/translate.js +197 -88
  200. package/dist/server/bare/plugins/ggml-classification/ops/classify.d.ts +6 -0
  201. package/dist/server/bare/plugins/ggml-classification/ops/classify.js +30 -0
  202. package/dist/server/bare/plugins/ggml-classification/plugin.d.ts +32 -0
  203. package/dist/server/bare/plugins/ggml-classification/plugin.js +55 -0
  204. package/dist/server/bare/plugins/ggml-vla/ops/vla-hparams.d.ts +3 -0
  205. package/dist/server/bare/plugins/ggml-vla/ops/vla-hparams.js +12 -0
  206. package/dist/server/bare/plugins/ggml-vla/ops/vla-run.d.ts +3 -0
  207. package/dist/server/bare/plugins/ggml-vla/ops/vla-run.js +75 -0
  208. package/dist/server/bare/plugins/ggml-vla/plugin.d.ts +54 -0
  209. package/dist/server/bare/plugins/ggml-vla/plugin.js +57 -0
  210. package/dist/server/bare/plugins/index.d.ts +3 -1
  211. package/dist/server/bare/plugins/index.js +3 -1
  212. package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stream.d.ts +12 -3
  213. package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stream.js +173 -172
  214. package/dist/server/bare/plugins/llamacpp-completion/ops/context-overflow.d.ts +29 -0
  215. package/dist/server/bare/plugins/llamacpp-completion/ops/context-overflow.js +65 -0
  216. package/dist/server/bare/plugins/llamacpp-completion/ops/finetune.js +125 -21
  217. package/dist/server/bare/plugins/llamacpp-completion/ops/kv-cache-session.d.ts +154 -0
  218. package/dist/server/bare/plugins/llamacpp-completion/ops/kv-cache-session.js +448 -0
  219. package/dist/server/bare/plugins/llamacpp-completion/ops/kv-cache-state.d.ts +21 -73
  220. package/dist/server/bare/plugins/llamacpp-completion/ops/kv-cache-state.js +18 -101
  221. package/dist/server/bare/plugins/llamacpp-completion/plugin.d.ts +36 -3
  222. package/dist/server/bare/plugins/llamacpp-completion/plugin.js +183 -85
  223. package/dist/server/bare/plugins/llamacpp-completion/transform.d.ts +10 -0
  224. package/dist/server/bare/plugins/llamacpp-completion/transform.js +34 -0
  225. package/dist/server/bare/plugins/llamacpp-embedding/plugin.d.ts +7 -0
  226. package/dist/server/bare/plugins/llamacpp-embedding/plugin.js +10 -1
  227. package/dist/server/bare/plugins/nmtcpp-translation/plugin.d.ts +42 -15
  228. package/dist/server/bare/plugins/nmtcpp-translation/plugin.js +5 -1
  229. package/dist/server/bare/plugins/onnx-ocr/plugin.d.ts +8 -3
  230. package/dist/server/bare/plugins/onnx-ocr/plugin.js +3 -0
  231. package/dist/server/bare/plugins/parakeet-transcription/plugin.d.ts +73 -244
  232. package/dist/server/bare/plugins/parakeet-transcription/plugin.js +68 -96
  233. package/dist/server/bare/plugins/sdcpp-generation/ops/diffusion.js +8 -0
  234. package/dist/server/bare/plugins/sdcpp-generation/ops/upscale.d.ts +3 -0
  235. package/dist/server/bare/plugins/sdcpp-generation/ops/upscale.js +40 -0
  236. package/dist/server/bare/plugins/sdcpp-generation/ops/video.d.ts +3 -0
  237. package/dist/server/bare/plugins/sdcpp-generation/ops/video.js +199 -0
  238. package/dist/server/bare/plugins/sdcpp-generation/plugin.d.ts +288 -15
  239. package/dist/server/bare/plugins/sdcpp-generation/plugin.js +150 -7
  240. package/dist/server/bare/plugins/{onnx-tts → tts-ggml}/ops/text-to-speech-stream.js +2 -15
  241. package/dist/server/bare/plugins/{onnx-tts → tts-ggml}/ops/text-to-speech.js +2 -1
  242. package/dist/server/bare/plugins/tts-ggml/plugin.d.ts +75 -0
  243. package/dist/server/bare/plugins/tts-ggml/plugin.js +189 -0
  244. package/dist/server/bare/plugins/whispercpp-transcription/plugin.d.ts +47 -3
  245. package/dist/server/bare/plugins/whispercpp-transcription/plugin.js +61 -14
  246. package/dist/server/bare/rag-hyperdb/index.d.ts +1 -1
  247. package/dist/server/bare/rag-hyperdb/index.js +1 -1
  248. package/dist/server/bare/rag-hyperdb/rag-operation-manager.d.ts +26 -4
  249. package/dist/server/bare/rag-hyperdb/rag-operation-manager.js +65 -28
  250. package/dist/server/bare/registry/model-config-utils.js +7 -0
  251. package/dist/server/bare/runtime/disposable-scope.d.ts +36 -0
  252. package/dist/server/bare/runtime/disposable-scope.js +69 -0
  253. package/dist/server/bare/runtime/index.d.ts +8 -0
  254. package/dist/server/bare/runtime/index.js +3 -0
  255. package/dist/server/bare/runtime/request-context.d.ts +49 -0
  256. package/dist/server/bare/runtime/request-context.js +1 -0
  257. package/dist/server/bare/runtime/request-id.d.ts +12 -0
  258. package/dist/server/bare/runtime/request-id.js +14 -0
  259. package/dist/server/bare/runtime/request-registry-singleton.d.ts +4 -0
  260. package/dist/server/bare/runtime/request-registry-singleton.js +27 -0
  261. package/dist/server/bare/runtime/request-registry.d.ts +136 -0
  262. package/dist/server/bare/runtime/request-registry.js +297 -0
  263. package/dist/server/bare/runtime/with-request-context.d.ts +22 -0
  264. package/dist/server/bare/runtime/with-request-context.js +53 -0
  265. package/dist/server/bare/runtime-lifecycle.js +9 -9
  266. package/dist/server/bare/types/addon-responses.d.ts +12 -1
  267. package/dist/server/env.js +4 -1
  268. package/dist/server/plugins/index.d.ts +1 -1
  269. package/dist/server/plugins/index.js +1 -1
  270. package/dist/server/plugins/registry.d.ts +1 -0
  271. package/dist/server/plugins/registry.js +5 -0
  272. package/dist/server/rpc/handler-registry.js +30 -7
  273. package/dist/server/rpc/handler-selection.d.ts +9 -0
  274. package/dist/server/rpc/handler-selection.js +14 -0
  275. package/dist/server/rpc/handler-utils.js +5 -13
  276. package/dist/server/rpc/handlers/cancel-delegated.js +28 -31
  277. package/dist/server/rpc/handlers/cancelHandler.d.ts +30 -1
  278. package/dist/server/rpc/handlers/cancelHandler.js +54 -22
  279. package/dist/server/rpc/handlers/classify.d.ts +3 -0
  280. package/dist/server/rpc/handlers/classify.js +4 -0
  281. package/dist/server/rpc/handlers/delete-cache.d.ts +9 -0
  282. package/dist/server/rpc/handlers/delete-cache.js +13 -15
  283. package/dist/server/rpc/handlers/download-asset.js +133 -40
  284. package/dist/server/rpc/handlers/index.d.ts +4 -0
  285. package/dist/server/rpc/handlers/index.js +4 -0
  286. package/dist/server/rpc/handlers/load-model/download-manager.d.ts +60 -2
  287. package/dist/server/rpc/handlers/load-model/download-manager.js +141 -8
  288. package/dist/server/rpc/handlers/load-model/handler.js +216 -98
  289. package/dist/server/rpc/handlers/load-model/http.js +3 -3
  290. package/dist/server/rpc/handlers/load-model/hyperdrive.js +1 -1
  291. package/dist/server/rpc/handlers/load-model/registry.js +1 -1
  292. package/dist/server/rpc/handlers/load-model/resolve-session.d.ts +20 -1
  293. package/dist/server/rpc/handlers/load-model/resolve-session.js +6 -5
  294. package/dist/server/rpc/handlers/load-model/resolve.d.ts +3 -2
  295. package/dist/server/rpc/handlers/load-model/resolve.js +18 -6
  296. package/dist/server/rpc/handlers/load-model/types.d.ts +24 -0
  297. package/dist/server/rpc/handlers/rag.js +133 -15
  298. package/dist/server/rpc/handlers/upscale-stream.d.ts +3 -0
  299. package/dist/server/rpc/handlers/upscale-stream.js +4 -0
  300. package/dist/server/rpc/handlers/video-stream.d.ts +3 -0
  301. package/dist/server/rpc/handlers/video-stream.js +4 -0
  302. package/dist/server/rpc/profiling/operation-metrics.js +23 -0
  303. package/dist/server/utils/completion-normalizer.js +8 -0
  304. package/dist/server/utils/config-transform.js +1 -1
  305. package/dist/server/utils/tools/dialect.js +4 -0
  306. package/dist/server/utils/tools/parser.js +16 -1
  307. package/dist/server/utils/tools/parsers/gemma4native.d.ts +4 -0
  308. package/dist/server/utils/tools/parsers/gemma4native.js +60 -0
  309. package/dist/server/utils/tools/parsers/qwen35.d.ts +4 -0
  310. package/dist/server/utils/tools/parsers/qwen35.js +120 -0
  311. package/dist/server/worker.js +14 -11
  312. package/dist/utils/aggregate-events.d.ts +9 -0
  313. package/dist/utils/aggregate-events.js +18 -3
  314. package/dist/utils/decorate-promise.d.ts +34 -0
  315. package/dist/utils/decorate-promise.js +35 -0
  316. package/dist/utils/errors-client.d.ts +18 -0
  317. package/dist/utils/errors-client.js +31 -0
  318. package/dist/utils/errors-server.d.ts +115 -2
  319. package/dist/utils/errors-server.js +148 -3
  320. package/package.json +68 -77
  321. package/dist/server/bare/plugins/onnx-tts/plugin.d.ts +0 -490
  322. package/dist/server/bare/plugins/onnx-tts/plugin.js +0 -266
  323. package/dist/server/bare/plugins/onnx-tts/wav-helper.d.ts +0 -14
  324. package/dist/server/bare/plugins/onnx-tts/wav-helper.js +0 -107
  325. /package/dist/server/bare/plugins/{onnx-tts → tts-ggml}/ops/text-to-speech-stream.d.ts +0 -0
  326. /package/dist/server/bare/plugins/{onnx-tts → tts-ggml}/ops/text-to-speech.d.ts +0 -0
@@ -1,8 +1,9 @@
1
1
  import { TOOLS_MODE } from "../../../../../schemas/tools.js";
2
- import { logCacheDisabled, logCacheInit, logCacheSave, logCacheSaveError, logCacheStatus, logMessagesToAddon, } from "./cache-logger.js";
3
- import { clearCacheRegistry, customCacheExists, extractSystemPrompt, findMatchingCache, generateConfigHash, getCacheFilePath, getCurrentCacheInfo, markCacheInitialized, renameCacheFile, } from "../../../ops/kv-cache-utils.js";
2
+ import { logCacheDisabled, logCacheInit, logCacheSave, logMessagesToAddon, } from "./cache-logger.js";
3
+ import { extractSystemPrompt, getCurrentCacheInfo, } from "../../../ops/kv-cache-utils.js";
4
4
  import { getModel, getModelConfig, } from "../../../registry/model-registry.js";
5
- import { cachedMessageCounts, clearCachedMessageCounts as clearCachedMessageCountsFromState, decideCachedHistorySlice, noteCancelRequested as noteCancelRequestedFromState, shouldRecordSavedCount, snapshotCancelCount, } from "./kv-cache-state.js";
5
+ import { decideCachedHistorySlice } from "./kv-cache-state.js";
6
+ import { createKvCacheSession, generateConfigHash, } from "./kv-cache-session.js";
6
7
  import { appendToolsToHistory, detectToolDialect, prependToolsToHistory, } from "../../../../utils/tool-integration.js";
7
8
  import { parseToolCalls } from "../../../../utils/tools/index.js";
8
9
  import { getResponseFormatJsonSchema } from "../../../../utils/response-format.js";
@@ -11,37 +12,23 @@ import { getServerLogger } from "../../../../../logging/index.js";
11
12
  import { AttachmentNotFoundError } from "../../../../../utils/errors-server.js";
12
13
  import { nowMs } from "../../../../../profiling/index.js";
13
14
  import { buildStreamResult, hasDefinedValues, } from "../../../../../profiling/model-execution.js";
14
- import fs, { promises as fsPromises } from "bare-fs";
15
- import path from "bare-path";
15
+ import fs from "bare-fs";
16
16
  const logger = getServerLogger();
17
- // Re-export so existing callers keep their import surface intact. The pure
18
- // state module has no `bare-*` imports, so we inject the platform path
19
- // separator here — without this, prefix-based clears would miss entries
20
- // under directory keys on Windows.
21
- export function clearCachedMessageCounts(prefix) {
22
- clearCachedMessageCountsFromState(prefix, path.sep);
23
- }
24
- export const noteCancelRequested = noteCancelRequestedFromState;
25
- // Verify the addon actually persisted the cache file before recording its
26
- // message count. The addon currently swallows write errors silently, so a
27
- // missing file means the next turn must resend the full history rather than
28
- // slicing against a stale `savedCount`.
29
- //
30
- // TODO: once the addon surfaces save failures (e.g. throws
31
- // `UnableToSaveSessionFile` when `llama_state_save_file` returns false),
32
- // drop the `access()` probe and wrap the `model.run()` call in a real
33
- // try/catch that forwards the error to `logCacheSaveError`.
34
- async function recordCacheSaveCount(cachePath, messageCount) {
35
- try {
36
- await fsPromises.access(cachePath);
37
- cachedMessageCounts.set(cachePath, messageCount);
38
- return true;
39
- }
40
- catch (err) {
41
- cachedMessageCounts.delete(cachePath);
42
- logCacheSaveError(cachePath, err);
43
- return false;
44
- }
17
+ /**
18
+ * Decide whether a completed turn earned the right to record its kv-cache
19
+ * boundary. A `savedCount` is only safe to write when the turn ran to
20
+ * completion AND produced at least one token — anything else (cancelled
21
+ * mid-decode, zero-token reply, early EOS) leaves the on-disk cache file
22
+ * in an unknown state relative to `history.length + 1`, and a stale entry
23
+ * would slice the next turn's history down to an empty payload.
24
+ *
25
+ * Replaces the pre-0.11.0 `shouldRecordSavedCount(wasCancelled, ...)` with
26
+ * a signal-driven check that reads directly from the request's
27
+ * `AbortSignal`. The local helper keeps the call sites in
28
+ * `completion-stream.ts` honest without importing the registry every time.
29
+ */
30
+ function shouldCommitTurn(signal, producedTokens) {
31
+ return !signal.aborted && producedTokens;
45
32
  }
46
33
  function transformMessage(message) {
47
34
  const transformed = [];
@@ -100,9 +87,7 @@ async function initSystemPromptCache(model, cachePathToUse, systemPromptToUse, c
100
87
  const primeResponse = await runModel(model, primeMessages, {
101
88
  cacheKey: cachePathToUse,
102
89
  saveCacheToDisk: true,
103
- });
104
- primeResponse.once("output", () => {
105
- void primeResponse.cancel();
90
+ prefill: true,
106
91
  });
107
92
  await primeResponse.await();
108
93
  }
@@ -117,7 +102,8 @@ async function initSystemPromptCache(model, cachePathToUse, systemPromptToUse, c
117
102
  * consumer pushing both an assistant transcript and a follow-up user
118
103
  * message between completions) all reaches the model.
119
104
  * - Cache hit with a stale/missing `savedCount`: fall back to the full
120
- * non-system history.
105
+ * non-system history. The session is told (`dropStaleSavedCount`) so
106
+ * the bad boundary doesn't propagate into the next turn.
121
107
  *
122
108
  * Dynamic mode (`tools` argument set):
123
109
  * - The addon anchors the tool block after the last user message and
@@ -133,7 +119,7 @@ async function initSystemPromptCache(model, cachePathToUse, systemPromptToUse, c
133
119
  * the new prompt, then re-anchor the tool block.
134
120
  * * otherwise: send just the last message + tool block.
135
121
  */
136
- function prepareMessagesForCache(cachePathToUse, cacheExists, history, tools) {
122
+ function prepareMessagesForCache(session, turn, cacheExists, history, tools) {
137
123
  const addTools = tools?.length ? transformMessages(tools) : [];
138
124
  const dynamic = addTools.length > 0;
139
125
  if (!(cacheExists && history.length > 0)) {
@@ -141,16 +127,18 @@ function prepareMessagesForCache(cachePathToUse, cacheExists, history, tools) {
141
127
  return [...transformMessages(historyWithoutSystem), ...addTools];
142
128
  }
143
129
  if (!dynamic) {
144
- // Static path — slice from the recorded `savedCount` so callers can
130
+ // Static path — slice from the turn's `savedCount` so callers can
145
131
  // stage multiple messages between completions. `decideCachedHistorySlice`
146
132
  // also guards against the QVAC-17780 stale-count regression: if the
147
133
  // saved boundary would slice the history down to an empty payload
148
134
  // (e.g. after a cancelled mid-decode), it falls back to the full
149
135
  // non-system history and signals the caller to drop the bad entry.
150
- const savedCount = cachedMessageCounts.get(cachePathToUse) ?? 0;
151
- const { messages, clearStaleCount } = decideCachedHistorySlice(savedCount, cacheExists, history);
136
+ // The session owns the entry; `dropStaleSavedCount` clears it
137
+ // without touching the on-disk file (the file is still trustworthy
138
+ // — only the boundary count is wrong).
139
+ const { messages, clearStaleCount } = decideCachedHistorySlice(turn.savedCount, cacheExists, history);
152
140
  if (clearStaleCount) {
153
- cachedMessageCounts.delete(cachePathToUse);
141
+ session.dropStaleSavedCount(turn);
154
142
  }
155
143
  return transformMessages(messages);
156
144
  }
@@ -217,6 +205,9 @@ async function* processModelResponse(model, messagesToSend, tools, generationPar
217
205
  ...(responseWithStats.stats?.CacheTokens !== undefined && {
218
206
  cacheTokens: responseWithStats.stats.CacheTokens,
219
207
  }),
208
+ ...(responseWithStats.stats?.promptTokens !== undefined && {
209
+ promptTokens: responseWithStats.stats.promptTokens,
210
+ }),
220
211
  ...(responseWithStats.stats?.generatedTokens !== undefined && {
221
212
  generatedTokens: responseWithStats.stats.generatedTokens,
222
213
  }),
@@ -231,8 +222,10 @@ async function* processModelResponse(model, messagesToSend, tools, generationPar
231
222
  producedTokens,
232
223
  };
233
224
  }
234
- export async function* completion(params) {
225
+ export async function* completion(params, opts) {
235
226
  const { history, modelId, kvCache, tools, generationParams, responseFormat } = params;
227
+ const { signal, scope } = opts;
228
+ const requestLogger = opts.logger ?? logger;
236
229
  const modelConfig = getModelConfig(modelId);
237
230
  const toolsEnabled = modelConfig.tools === true;
238
231
  const toolsMode = modelConfig.toolsMode;
@@ -259,136 +252,45 @@ export async function* completion(params) {
259
252
  }
260
253
  }
261
254
  const model = getModel(modelId);
262
- if (kvCache) {
263
- const systemPromptFromHistory = extractSystemPrompt(history);
264
- // Dynamic mode lets each turn carry its own tool set, so the cache
265
- // hash must not depend on the tool list — otherwise a tool change
266
- // would force a fresh cache file and defeat the whole optimisation.
267
- const configHash = generateConfigHash(systemPromptFromHistory, dynamicTools ? undefined : tools);
268
- const systemPromptToUse = systemPromptFromHistory ||
269
- modelConfig.system_prompt ||
270
- "You are a helpful assistant.";
271
- let cachePathToUse;
272
- if (typeof kvCache === "string") {
273
- cachePathToUse = await getCacheFilePath(modelId, configHash, kvCache);
274
- let cacheExists = await customCacheExists(modelId, configHash, kvCache);
275
- logCacheStatus(kvCache, cacheExists);
276
- if (!cacheExists) {
277
- await initSystemPromptCache(model, cachePathToUse, systemPromptToUse, kvCache,
278
- // Static-mode tools are baked into the system-prompt cache so
279
- // they're shared across the session. Dynamic-mode tools belong
280
- // to a per-turn anchor and must not enter the system cache.
281
- staticTools ? tools : undefined);
282
- markCacheInitialized(modelId, configHash, kvCache);
283
- cacheExists = true;
284
- }
285
- const messagesToSend = prepareMessagesForCache(cachePathToUse, cacheExists, history, dynamicTools ? tools : undefined);
286
- logMessagesToAddon(messagesToSend, "PROMPT_SEND");
287
- const cancelCountBefore = snapshotCancelCount(modelId);
288
- const result = yield* processModelResponse(model, messagesToSend, tools, mergedGenerationParams, { cacheKey: cachePathToUse, saveCacheToDisk: true }, dialect);
289
- const wasCancelled = snapshotCancelCount(modelId) > cancelCountBefore;
290
- if (shouldRecordSavedCount(wasCancelled, result.producedTokens)) {
291
- // Turn ran to completion and produced content — record the new
292
- // boundary so the next turn can slice its history.
293
- await recordCacheSaveCount(cachePathToUse, history.length + 1);
294
- }
295
- else {
296
- // The addon writes the cache file unconditionally on
297
- // `saveCacheToDisk` turns, including cancellations and zero-token
298
- // exits, so what's left on disk holds partial decode state that
299
- // does not correspond to a clean turn boundary. Mirror the
300
- // auto-key handling: drop the file, clear the in-memory init
301
- // flag (otherwise `customCacheExists` would still report true),
302
- // and forget the saved count. Next turn re-primes the system
303
- // prompt cleanly — a one-turn perf hit, but no risk of the
304
- // addon loading the stale KV state.
305
- try {
306
- await fsPromises.unlink(cachePathToUse);
307
- }
308
- catch (unlinkError) {
309
- logger.warn(`[kv-cache] Failed to remove cache file after cancelled or empty custom-key turn; next turn may load stale KV state. path=${cachePathToUse} error=${unlinkError instanceof Error ? unlinkError.message : String(unlinkError)}`);
310
- }
311
- clearCacheRegistry({ cacheKey: kvCache, modelId });
312
- cachedMessageCounts.delete(cachePathToUse);
313
- }
314
- return result;
315
- }
316
- else {
317
- // Auto-generate cache key based on conversation history
318
- const cacheMessages = history.map((msg) => ({
319
- role: msg.role,
320
- content: msg.content,
321
- attachments: msg.attachments ?? undefined,
322
- }));
323
- const existingCache = await findMatchingCache(modelId, configHash, cacheMessages);
324
- const preResponseCacheInfo = await getCurrentCacheInfo(modelId, configHash, cacheMessages);
325
- cachePathToUse =
326
- existingCache !== null
327
- ? existingCache.cachePath
328
- : preResponseCacheInfo.cachePath;
329
- let cacheExists = existingCache !== null;
330
- logCacheStatus("auto", cacheExists);
331
- if (!cacheExists) {
332
- await initSystemPromptCache(model, cachePathToUse, systemPromptToUse, "auto", staticTools ? tools : undefined);
333
- markCacheInitialized(modelId, configHash, preResponseCacheInfo.cacheKey);
334
- cacheExists = true;
335
- }
336
- const messagesToSend = prepareMessagesForCache(cachePathToUse, cacheExists, history, dynamicTools ? tools : undefined);
337
- logMessagesToAddon(messagesToSend, "PROMPT_SEND");
338
- const cancelCountBefore = snapshotCancelCount(modelId);
339
- const result = yield* processModelResponse(model, messagesToSend, tools, mergedGenerationParams, { cacheKey: cachePathToUse, saveCacheToDisk: true }, dialect);
340
- const wasCancelled = snapshotCancelCount(modelId) > cancelCountBefore;
341
- // TODO: support auto-cache for tool-call turns by keying off the
342
- // structured assistant/tool messages callers push into history,
343
- // not result.responseText (which is raw tool-call markup here).
344
- // Until then, remove any cache file the addon wrote so it doesn't
345
- // leak on disk (the next turn would compute a different key and
346
- // never reach it).
347
- if (result.toolCalls.length > 0) {
348
- logger.warn(`[kv-cache] Auto cache tool-call turn; removing orphaned cache to avoid disk leak. path=${cachePathToUse}`);
349
- try {
350
- await fsPromises.unlink(cachePathToUse);
351
- }
352
- catch (unlinkError) {
353
- logger.warn(`[kv-cache] Failed to remove orphaned tool-turn cache file; disk leak likely. path=${cachePathToUse} error=${unlinkError instanceof Error ? unlinkError.message : String(unlinkError)}`);
354
- }
355
- cachedMessageCounts.delete(cachePathToUse);
356
- return result;
357
- }
358
- // A cancelled or zero-token turn cannot be promoted to a post-response
359
- // cache: the post-response key is derived from `result.responseText`,
360
- // which is empty/partial in those cases, and the on-disk cache the
361
- // addon wrote is not aligned with the current-history hash. Treat it
362
- // like the tool-call branch — drop the cache file and clear the count.
363
- if (!shouldRecordSavedCount(wasCancelled, result.producedTokens)) {
364
- try {
365
- await fsPromises.unlink(cachePathToUse);
366
- }
367
- catch (unlinkError) {
368
- logger.warn(`[kv-cache] Failed to remove cache file after cancelled or empty turn; disk leak possible. path=${cachePathToUse} error=${unlinkError instanceof Error ? unlinkError.message : String(unlinkError)}`);
369
- }
370
- cachedMessageCounts.delete(cachePathToUse);
371
- return result;
372
- }
373
- const savedHistory = buildAutoCacheSaveHistory(cacheMessages, result.responseText);
374
- const postResponseCacheInfo = await getCurrentCacheInfo(modelId, configHash, savedHistory);
375
- if (!(await renameCacheFile(cachePathToUse, postResponseCacheInfo.cachePath))) {
376
- logger.warn(`[kv-cache] Auto cache rename failed; removing stale cache to avoid disk leak. from=${cachePathToUse} to=${postResponseCacheInfo.cachePath}`);
377
- try {
378
- await fsPromises.unlink(cachePathToUse);
379
- }
380
- catch (unlinkError) {
381
- logger.warn(`[kv-cache] Failed to remove stale cache file; disk leak likely. path=${cachePathToUse} error=${unlinkError instanceof Error ? unlinkError.message : String(unlinkError)}`);
382
- }
383
- cachedMessageCounts.delete(cachePathToUse);
384
- return result;
385
- }
386
- cachedMessageCounts.delete(cachePathToUse);
387
- await recordCacheSaveCount(postResponseCacheInfo.cachePath, savedHistory.length);
388
- return result;
255
+ // Hard-cancel wiring: when the registry aborts the request's signal,
256
+ // forward to the addon so the C++ work stops as soon as it can. The
257
+ // SDK still treats `signal.aborted` as the truth for cancel detection
258
+ // (post-completion bookkeeping below) — this listener only shortens
259
+ // the latency between "user clicked stop" and "addon stops decoding".
260
+ //
261
+ // Fire-and-forget by construction (event listeners can't `await`), but
262
+ // `addon.cancel()` returns a Promise — if it ever rejects the bare
263
+ // `void` would leak it as an unhandledRejection. Attach `.catch(...)`
264
+ // so a rejection is logged and the process stays clean; the iterator
265
+ // below still sees EOF/empty tokens via the addon's normal cancel path
266
+ // so callers aren't affected.
267
+ const onAbort = () => {
268
+ const addon = model.addon;
269
+ if (addon?.cancel) {
270
+ addon.cancel.call(addon).catch((err) => {
271
+ requestLogger.warn(`[cancel] addon.cancel() rejected during abort for modelId=${modelId}: ${err instanceof Error ? err.message : String(err)}`);
272
+ });
389
273
  }
390
- }
391
- else {
274
+ };
275
+ signal.addEventListener("abort", onAbort, { once: true });
276
+ // `addEventListener("abort", ..., { once: true })` does *not* fire if
277
+ // the signal is already aborted at register time — but the registry
278
+ // synchronously aborts a fresh controller when `parentSignal` was
279
+ // already aborted at `begin(...)`. Without this fall-through, the
280
+ // addon would keep decoding until the post-loop check notices.
281
+ // Re-using `onAbort` here keeps the listener body as the single
282
+ // source of truth for "what cancel does."
283
+ if (signal.aborted)
284
+ onAbort();
285
+ // Detach the abort listener on every exit path (happy, throw, generator
286
+ // `return()` from upstream). `{ once: true }` already removes the
287
+ // listener if the signal fires, so the `removeEventListener` here is
288
+ // the cleanup hook for the signal-never-fired path.
289
+ scope.defer(() => {
290
+ signal.removeEventListener("abort", onAbort);
291
+ });
292
+ if (!kvCache) {
293
+ // KV-cache disabled — straight passthrough, no session involvement.
392
294
  let historyWithTools = history;
393
295
  if (staticTools && tools) {
394
296
  historyWithTools = prependToolsToHistory(history, tools);
@@ -401,4 +303,103 @@ export async function* completion(params) {
401
303
  logMessagesToAddon(transformedHistory, "NO_CACHE");
402
304
  return yield* processModelResponse(model, transformedHistory, tools, mergedGenerationParams, undefined, dialect);
403
305
  }
306
+ // ---- KV-cache path. The session owns all three bookkeeping layers
307
+ // (on-disk `.bin`, `initializedCaches`, `cachedMessageCounts`). The
308
+ // handler asks for a turn, registers rollback on the scope, and on
309
+ // the happy path calls `commitTurn` which short-circuits the deferred
310
+ // rollback. Cancellations / zero-token replies / rename failures all
311
+ // unwind through the same `scope.defer` hook. ----
312
+ const session = createKvCacheSession(modelId, { logger: requestLogger });
313
+ const systemPromptFromHistory = extractSystemPrompt(history);
314
+ // Dynamic mode lets each turn carry its own tool set, so the cache
315
+ // hash must not depend on the tool list — otherwise a tool change
316
+ // would force a fresh cache file and defeat the whole optimisation.
317
+ const configHash = generateConfigHash(systemPromptFromHistory, dynamicTools ? undefined : tools);
318
+ const systemPromptToUse = systemPromptFromHistory ||
319
+ modelConfig.system_prompt ||
320
+ "You are a helpful assistant.";
321
+ const primeIfMissing = async (cachePath) => {
322
+ await initSystemPromptCache(model, cachePath, systemPromptToUse, typeof kvCache === "string" ? kvCache : "auto",
323
+ // Static-mode tools are baked into the system-prompt cache so
324
+ // they're shared across the session. Dynamic-mode tools belong
325
+ // to a per-turn anchor and must not enter the system cache.
326
+ staticTools ? tools : undefined);
327
+ };
328
+ let turn;
329
+ if (typeof kvCache === "string") {
330
+ turn = await session.beginTurn({
331
+ kind: "custom",
332
+ customKey: kvCache,
333
+ configHash,
334
+ primeIfMissing,
335
+ });
336
+ }
337
+ else {
338
+ const cacheMessages = history.map((msg) => ({
339
+ role: msg.role,
340
+ content: msg.content,
341
+ attachments: msg.attachments ?? undefined,
342
+ }));
343
+ turn = await session.beginTurn({
344
+ kind: "auto",
345
+ configHash,
346
+ history: cacheMessages,
347
+ primeIfMissing,
348
+ });
349
+ }
350
+ // Single cleanup hook for every non-success exit path. `commitTurn`
351
+ // flips the turn's internal `committed` flag so this becomes a no-op
352
+ // on the happy path. Scope unwinding is LIFO — registered after the
353
+ // `removeEventListener` defer above so rollback runs before the
354
+ // listener detach.
355
+ scope.defer(() => session.rollback(turn));
356
+ // `cacheExists` is implied by `beginTurn` — the session either found
357
+ // an existing cache or just primed one. Pass `true` to the message
358
+ // selector so the slicing branches engage.
359
+ const messagesToSend = prepareMessagesForCache(session, turn,
360
+ /* cacheExists */ true, history, dynamicTools ? tools : undefined);
361
+ logMessagesToAddon(messagesToSend, "PROMPT_SEND");
362
+ const result = yield* processModelResponse(model, messagesToSend, tools, mergedGenerationParams, { cacheKey: turn.cachePath, saveCacheToDisk: true }, dialect);
363
+ if (typeof kvCache === "string") {
364
+ // Custom-key path: the addon wrote the new cache state inline at
365
+ // the same path. Either commit (records the boundary, suppresses
366
+ // rollback) or fall through to the deferred rollback.
367
+ if (shouldCommitTurn(signal, result.producedTokens)) {
368
+ await session.commitTurn(turn, {
369
+ kind: "static",
370
+ messageCount: history.length + 1,
371
+ });
372
+ }
373
+ return result;
374
+ }
375
+ // Auto-cache path.
376
+ //
377
+ // Tool-call turns: the auto-cache key is derived from
378
+ // `result.responseText`, which here is raw tool-call markup rather
379
+ // than a clean assistant message. There's no safe post-response key
380
+ // to rename to, so we let the deferred rollback drop the file. Once
381
+ // the SDK supports auto-cache for structured assistant/tool turns,
382
+ // this becomes a normal commit path.
383
+ if (result.toolCalls.length > 0) {
384
+ logger.warn(`[kv-cache] Auto cache tool-call turn; rolling back to avoid disk leak. path=${turn.cachePath}`);
385
+ return result;
386
+ }
387
+ if (!shouldCommitTurn(signal, result.producedTokens)) {
388
+ // Cancelled or zero-token turn — the addon wrote the file but its
389
+ // contents don't correspond to a clean turn boundary. Let the
390
+ // deferred rollback unlink it.
391
+ return result;
392
+ }
393
+ const savedHistory = buildAutoCacheSaveHistory(history.map((msg) => ({
394
+ role: msg.role,
395
+ content: msg.content,
396
+ attachments: msg.attachments ?? undefined,
397
+ })), result.responseText);
398
+ const postResponseCacheInfo = await getCurrentCacheInfo(modelId, configHash, savedHistory);
399
+ await session.commitTurn(turn, {
400
+ kind: "autoRename",
401
+ targetCachePath: postResponseCacheInfo.cachePath,
402
+ messageCount: savedHistory.length,
403
+ });
404
+ return result;
404
405
  }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Helpers for detecting and parsing the llama.cpp addon's
3
+ * `ContextOverflow` status error (`LlmErrors.hpp::ContextOverflow = 14`).
4
+ *
5
+ * The addon's JS-facing throw goes through `js_throw_error(env, code,
6
+ * msg)` (see `JsUtils.hpp::JSCATCH`) where `code` comes from
7
+ * `qvac_errors::StatusError::codeString()` and formats as
8
+ * `"[ <addonId> :: ContextOverflow ]"`. The message carries the
9
+ * C++-formatted detail (which may include the prompt/ctx sizes).
10
+ *
11
+ * These helpers let the plugin handler convert that addon error into a
12
+ * typed `ContextOverflowError` and let unit tests assert the detection
13
+ * + extraction logic without a real model load.
14
+ */
15
+ export declare function isAddonContextOverflowError(err: unknown): boolean;
16
+ /**
17
+ * Best-effort extraction of `promptTokens` / `ctxSize` from the addon
18
+ * error message. The C++ paths in `TextLlmContext.cpp` and
19
+ * `MtmdLlmContext.cpp` format both numbers into the message; the
20
+ * `LlamaModel::processPromptImpl` fallback path emits a bare
21
+ * `"<func>: context overflow\n"` with neither number. Returning
22
+ * `undefined` for either field is fine — `ContextOverflowError` holds
23
+ * them as optional and the message factory degrades gracefully.
24
+ */
25
+ export declare function parseContextOverflowMessage(message: string): {
26
+ promptTokens?: number;
27
+ ctxSize?: number;
28
+ };
29
+ //# sourceMappingURL=context-overflow.d.ts.map
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Helpers for detecting and parsing the llama.cpp addon's
3
+ * `ContextOverflow` status error (`LlmErrors.hpp::ContextOverflow = 14`).
4
+ *
5
+ * The addon's JS-facing throw goes through `js_throw_error(env, code,
6
+ * msg)` (see `JsUtils.hpp::JSCATCH`) where `code` comes from
7
+ * `qvac_errors::StatusError::codeString()` and formats as
8
+ * `"[ <addonId> :: ContextOverflow ]"`. The message carries the
9
+ * C++-formatted detail (which may include the prompt/ctx sizes).
10
+ *
11
+ * These helpers let the plugin handler convert that addon error into a
12
+ * typed `ContextOverflowError` and let unit tests assert the detection
13
+ * + extraction logic without a real model load.
14
+ */
15
+ export function isAddonContextOverflowError(err) {
16
+ if (typeof err !== "object" || err === null)
17
+ return false;
18
+ const code = err.code;
19
+ // Anchor to the codeString tail (`[ <addonId> :: ContextOverflow ]`)
20
+ // so we don't false-positive on a hypothetical sibling like
21
+ // `ContextOverflowRecovered` or `PostContextOverflow` after an
22
+ // addon-side rename.
23
+ if (typeof code === "string" && /::\s*ContextOverflow\s*\]/.test(code)) {
24
+ return true;
25
+ }
26
+ // Message-substring fallback for the bare `LlamaModel::processPromptImpl`
27
+ // path, which doesn't go through `StatusError::codeString()`. Match the
28
+ // two known C++-emitted formats only — broader substring would catch
29
+ // wrapper / cause-chain text that mentions overflow without being one.
30
+ const message = err.message;
31
+ return (typeof message === "string" &&
32
+ /(?:context overflow at prefill step|processPromptImpl: context overflow)/i.test(message));
33
+ }
34
+ /**
35
+ * Best-effort extraction of `promptTokens` / `ctxSize` from the addon
36
+ * error message. The C++ paths in `TextLlmContext.cpp` and
37
+ * `MtmdLlmContext.cpp` format both numbers into the message; the
38
+ * `LlamaModel::processPromptImpl` fallback path emits a bare
39
+ * `"<func>: context overflow\n"` with neither number. Returning
40
+ * `undefined` for either field is fine — `ContextOverflowError` holds
41
+ * them as optional and the message factory degrades gracefully.
42
+ */
43
+ export function parseContextOverflowMessage(message) {
44
+ // "[TextLlm] context overflow at prefill step: prompt tokens N, max context tokens M\n"
45
+ // Same-clause separator (no `[^]*?` cross-newline walk) so a future
46
+ // wrapper that pastes overflow text alongside unrelated numbers can't
47
+ // produce a mismatched pair.
48
+ const longForm = message.match(/prompt tokens (\d+)[,\s]+max context tokens (\d+)/i);
49
+ if (longForm?.[1] && longForm[2]) {
50
+ return {
51
+ promptTokens: Number(longForm[1]),
52
+ ctxSize: Number(longForm[2]),
53
+ };
54
+ }
55
+ // "[TextLlm] context overflow at prefill step (N tokens, max M)\n"
56
+ // "[MtmdLlm] context overflow at prefill step (N tokens, max M)\n"
57
+ const shortForm = message.match(/\((\d+)\s+tokens,\s*max\s+(\d+)\)/i);
58
+ if (shortForm?.[1] && shortForm[2]) {
59
+ return {
60
+ promptTokens: Number(shortForm[1]),
61
+ ctxSize: Number(shortForm[2]),
62
+ };
63
+ }
64
+ return {};
65
+ }