@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
@@ -0,0 +1,448 @@
1
+ import { promises as fsPromises } from "bare-fs";
2
+ import path from "bare-path";
3
+ import { findMatchingCache, generateConfigHash, getCacheFilePath, getCurrentCacheInfo, renameCacheFile, deleteCache as deleteCacheUtil, } from "../../../ops/kv-cache-utils.js";
4
+ import { logCacheSaveError, logCacheStatus, } from "./cache-logger.js";
5
+ import { getServerLogger } from "../../../../../logging/index.js";
6
+ // Used by cross-model paths that have no `RequestContext` (e.g.
7
+ // `deleteKvCacheState`). Per-session call sites receive a logger from
8
+ // the caller — typically `withRequestContext(...)`.
9
+ const moduleLogger = getServerLogger();
10
+ /**
11
+ * Single owner of the three KV-cache bookkeeping layers.
12
+ *
13
+ * The llama.cpp completion handler has three independent layers it must
14
+ * keep consistent across every cancel/error branch:
15
+ *
16
+ * 1. `cachedMessageCounts: Map<path, count>` — the "n messages
17
+ * currently on disk" tracker.
18
+ * 2. `initializedCaches: Set<key>` — the "addon defers disk writes;
19
+ * we know this cache is primed" tracker.
20
+ * 3. On-disk `.bin` files written by the addon.
21
+ *
22
+ * Without a single owner, every cancel / zero-token / rename-failed /
23
+ * tool-call exit would need to touch all three; any branch that forgets
24
+ * a layer produces three-layer drift bugs.
25
+ *
26
+ * `KvCacheSession` collapses the three layers behind one object with
27
+ * three operations:
28
+ *
29
+ * - `beginTurn` — resolves the cache file path, primes the system
30
+ * prompt cache if missing (delegated to a caller-supplied closure
31
+ * so the session doesn't depend on the model addon), marks the
32
+ * cache initialized, and returns a `TurnHandle` carrying the
33
+ * resolved path + the snapshot of the on-disk saved count.
34
+ * - `commitTurn` — records the new saved count (for custom-key
35
+ * turns) or renames the addon's pre-response file to the
36
+ * post-response path and records the count there (for auto-cache
37
+ * turns). Flips the turn's internal `committed` flag so the
38
+ * deferred `rollback` becomes a no-op on the happy path.
39
+ * - `rollback` — atomically deletes the on-disk file, clears the
40
+ * in-memory init entry, and forgets the saved count. **All three
41
+ * layers, always, in one place.** Handlers call it once via
42
+ * `ctx.scope.defer(() => session.rollback(turn))`; `commitTurn`
43
+ * short-circuits it on success.
44
+ *
45
+ * The module-level `deleteKvCacheState(...)` function (below) provides
46
+ * an administrative cross-model delete API for the
47
+ * `handleDeleteCache` RPC handler.
48
+ *
49
+ * The module-scoped `cachedMessageCounts` and `initializedCaches` maps
50
+ * are *private* to this file — no other module reaches into them.
51
+ * Callers that need cache-status info do so through the session API.
52
+ */
53
+ // ----- module-scoped state. The session is the single mutation point
54
+ // for the in-memory KV-cache bookkeeping. -----
55
+ /**
56
+ * Number of chat messages the kv-cache file on disk is known to cover,
57
+ * keyed by cache path. Written by `commitTurn`, read by `getSavedCount`,
58
+ * deleted by `rollback` / `delete` / `dropStaleSavedCount`. The same
59
+ * INVARIANT that existed in `kv-cache-state.ts` still holds: an entry is
60
+ * present only when the corresponding `.bin` file is considered
61
+ * trustworthy. Cancelled or zero-token turns must remove the entry so
62
+ * the next-turn slice doesn't read a stale boundary.
63
+ */
64
+ const cachedMessageCounts = new Map();
65
+ /**
66
+ * In-memory registry of caches initialized this session. The addon
67
+ * defers disk writes, so the absence of a `.bin` file on disk isn't
68
+ * proof that the cache hasn't been primed in this worker process. Keyed
69
+ * by `${modelId}:${configHash}:${cacheKey}`, so on-disk caches from
70
+ * older worker runs still hit the lazy-load path in `beginTurn`.
71
+ */
72
+ const initializedCaches = new Set();
73
+ function initRegistryKey(modelId, configHash, cacheKey) {
74
+ return `${modelId}:${configHash}:${cacheKey}`;
75
+ }
76
+ // ----- factory -----
77
+ /**
78
+ * Construct a session bound to one `(modelId, turn-owning request)`
79
+ * scope. `options.logger` is the per-instance logger the session emits
80
+ * through (typically `withRequestContext(getServerLogger(), ctx)`);
81
+ * falls back to the module-scoped logger when omitted.
82
+ */
83
+ export function createKvCacheSession(modelId, options) {
84
+ const logger = options?.logger ?? moduleLogger;
85
+ // Per-session map: each `TurnHandle` carries an opaque entry here. A
86
+ // WeakMap so handles drop their state once the handler scope releases
87
+ // the reference; the module-scoped maps above survive.
88
+ const turnState = new WeakMap();
89
+ function makeHandle(cachePath, registryKey) {
90
+ const handle = {
91
+ cachePath,
92
+ savedCount: cachedMessageCounts.get(cachePath) ?? 0,
93
+ };
94
+ turnState.set(handle, {
95
+ cachePath,
96
+ registryKey,
97
+ committed: false,
98
+ rolledBack: false,
99
+ });
100
+ return handle;
101
+ }
102
+ async function beginCustom(input) {
103
+ const cachePath = await getCacheFilePath(modelId, input.configHash, input.customKey);
104
+ const registryKey = initRegistryKey(modelId, input.configHash, input.customKey);
105
+ // In-memory registry check first — the addon defers disk writes, so
106
+ // a freshly-primed cache may not yet exist on disk. If the
107
+ // in-memory flag isn't set, fall back to a filesystem probe so
108
+ // caches surviving across worker restarts still hit the reuse path.
109
+ let exists = initializedCaches.has(registryKey);
110
+ if (!exists) {
111
+ try {
112
+ await fsPromises.access(cachePath);
113
+ exists = true;
114
+ initializedCaches.add(registryKey);
115
+ }
116
+ catch {
117
+ exists = false;
118
+ }
119
+ }
120
+ logCacheStatus(input.customKey, exists);
121
+ if (!exists) {
122
+ await input.primeIfMissing(cachePath);
123
+ await verifyPrimedFile(cachePath, logger);
124
+ initializedCaches.add(registryKey);
125
+ }
126
+ return makeHandle(cachePath, registryKey);
127
+ }
128
+ async function beginAuto(input) {
129
+ // The pre-response cache key is derived from
130
+ // `history.slice(0, -1)` — `findMatchingCache` does that
131
+ // internally. The post-response key (used after a successful turn)
132
+ // is computed by the caller and passed to `commitTurn` as
133
+ // `targetCachePath`.
134
+ const existingCache = await findMatchingCache(modelId, input.configHash, input.history);
135
+ const preResponseCacheInfo = await getCurrentCacheInfo(modelId, input.configHash, input.history);
136
+ const cachePath = existingCache !== null
137
+ ? existingCache.cachePath
138
+ : preResponseCacheInfo.cachePath;
139
+ const cacheKeyForRegistry = existingCache !== null
140
+ ? existingCache.cacheKey
141
+ : preResponseCacheInfo.cacheKey;
142
+ const registryKey = initRegistryKey(modelId, input.configHash, cacheKeyForRegistry);
143
+ const cacheExists = existingCache !== null;
144
+ logCacheStatus("auto", cacheExists);
145
+ if (!cacheExists) {
146
+ await input.primeIfMissing(cachePath);
147
+ await verifyPrimedFile(cachePath, logger);
148
+ initializedCaches.add(registryKey);
149
+ }
150
+ return makeHandle(cachePath, registryKey);
151
+ }
152
+ async function beginTurn(input) {
153
+ if (input.kind === "custom")
154
+ return beginCustom(input);
155
+ return beginAuto(input);
156
+ }
157
+ async function commitTurn(turn, result) {
158
+ const state = turnState.get(turn);
159
+ if (!state) {
160
+ // Handle from a different session or already torn down. Treat as
161
+ // no-op — caller shouldn't be reaching into another session's
162
+ // state, but failing loudly here punishes the rollback-after-end
163
+ // path more than it helps.
164
+ return;
165
+ }
166
+ if (state.committed || state.rolledBack)
167
+ return;
168
+ if (result.kind === "static") {
169
+ // Custom-key path: the addon wrote the new cache state inline
170
+ // at the same path. Verify the file persisted (the addon
171
+ // currently swallows save errors — see TODO in
172
+ // `verifySaveAndRecord`) and record the new boundary.
173
+ const ok = await verifySaveAndRecord(state.cachePath, result.messageCount);
174
+ if (!ok) {
175
+ // The expected save didn't land — treat the turn as a rollback
176
+ // so the next turn re-primes cleanly.
177
+ await runRollback(state);
178
+ return;
179
+ }
180
+ state.committed = true;
181
+ return;
182
+ }
183
+ // Auto-rename path: the pre-response file is now stale (its key
184
+ // refers to history minus the last user turn). Rename it to the
185
+ // post-response key and record the new count there.
186
+ if (!(await renameCacheFile(state.cachePath, result.targetCachePath))) {
187
+ logger.warn(`[kv-cache] Auto cache rename failed; rolling back. from=${state.cachePath} to=${result.targetCachePath}`);
188
+ await runRollback(state);
189
+ return;
190
+ }
191
+ // The source path's entry is gone (the file moved). Drop it and
192
+ // record the new count at the rename target.
193
+ cachedMessageCounts.delete(state.cachePath);
194
+ const ok = await verifySaveAndRecord(result.targetCachePath, result.messageCount);
195
+ if (!ok) {
196
+ // Rename succeeded but the file isn't where we expected. Roll
197
+ // back via the target path instead of the (now-empty) source.
198
+ state.cachePath = result.targetCachePath;
199
+ await runRollback(state);
200
+ return;
201
+ }
202
+ // Successful auto-rename. The handle's `cachePath` field still
203
+ // points at the (now-gone) source path — that's fine, the handle
204
+ // is committed and won't roll back. Future turns compute fresh
205
+ // paths.
206
+ state.committed = true;
207
+ }
208
+ async function rollback(turn) {
209
+ const state = turnState.get(turn);
210
+ if (!state)
211
+ return;
212
+ if (state.committed || state.rolledBack)
213
+ return;
214
+ await runRollback(state);
215
+ }
216
+ async function runRollback(state) {
217
+ // Order matters only weakly: unlink first so a partial disk-state
218
+ // can't be re-loaded by a sibling turn between the file delete and
219
+ // the in-memory clear. In practice handlers serialise per model;
220
+ // the order is belt-and-suspenders.
221
+ try {
222
+ await fsPromises.unlink(state.cachePath);
223
+ }
224
+ catch (unlinkError) {
225
+ logger.warn(`[kv-cache] Failed to remove cache file during rollback; next turn may load stale KV state. path=${state.cachePath} error=${unlinkError instanceof Error ? unlinkError.message : String(unlinkError)}`);
226
+ }
227
+ initializedCaches.delete(state.registryKey);
228
+ cachedMessageCounts.delete(state.cachePath);
229
+ state.rolledBack = true;
230
+ }
231
+ function dropStaleSavedCount(turn) {
232
+ const state = turnState.get(turn);
233
+ if (!state)
234
+ return;
235
+ cachedMessageCounts.delete(state.cachePath);
236
+ }
237
+ return {
238
+ beginTurn,
239
+ commitTurn,
240
+ rollback,
241
+ dropStaleSavedCount,
242
+ };
243
+ }
244
+ // ----- module-level administrative API -----
245
+ /**
246
+ * Atomically delete every layer of KV-cache state for a
247
+ * `(kvCacheKey, modelId)` pair, or wipe everything. Single entry point
248
+ * — the only mutation point for cross-model state outside of
249
+ * turn-scoped `commitTurn`/`rollback`.
250
+ *
251
+ * Why this isn't a method on `KvCacheSession`: deletes are
252
+ * cross-model (`all: true` has no model; the keyed form has
253
+ * `modelId` optional on the wire). A session, by contrast, is
254
+ * created with a *fixed* `modelId` for the duration of a turn. Making
255
+ * delete a method would force callers to materialise an irrelevant
256
+ * session for cross-model administrative cleanups.
257
+ *
258
+ * Layers cleared, in order:
259
+ * 1. On-disk: `deleteCache(...)` removes the matching directory
260
+ * tree (or wipes and recreates the root for `all: true`).
261
+ * 2. `cachedMessageCounts`: prefix-cleanup by the removed directory
262
+ * so any per-cache count under the deleted tree is forgotten.
263
+ * 3. `initializedCaches`: scope clear by `(kvCacheKey[, modelId])`,
264
+ * matching the on-disk scope.
265
+ *
266
+ * Concurrency with in-flight turns: this delete is wire-async with
267
+ * respect to any turn currently holding a `TurnHandle` for the same
268
+ * cache key. Worst case the on-disk `.bin` is removed while a turn is
269
+ * mid-write; the turn's eventual `commitTurn(...)` then fails the
270
+ * `verifySaveAndRecord` probe (file gone) and rolls back idempotently.
271
+ * No coordination primitive is needed because every layer's mutation
272
+ * is idempotent (`unlink` no-ops if missing, `Map.delete` / `Set.delete`
273
+ * no-op on absent keys).
274
+ */
275
+ export async function deleteKvCacheState(target) {
276
+ if ("all" in target) {
277
+ const removed = await deleteCacheUtil({ all: true });
278
+ cachedMessageCounts.clear();
279
+ initializedCaches.clear();
280
+ // `removed` is the kv-cache root dir; surfaces it for ops
281
+ // visibility but isn't part of the contract.
282
+ moduleLogger.debug(`[kv-cache] Cleared all caches under ${removed}`);
283
+ return;
284
+ }
285
+ const removedPath = await deleteCacheUtil({
286
+ kvCacheKey: target.kvCacheKey,
287
+ ...(target.modelId !== undefined && { modelId: target.modelId }),
288
+ });
289
+ // Prefix-cleanup the in-memory counts. The on-disk directory tree
290
+ // is `{kvCacheRoot}/{kvCacheKey}[/{modelId}]/`, so every entry in
291
+ // `cachedMessageCounts` whose key is the removed directory itself
292
+ // or sits beneath it must go.
293
+ clearCachedMessageCountsByPrefix(removedPath, path.sep);
294
+ // The in-memory init-set keys are
295
+ // `${modelId}:${configHash}:${kvCacheKey}` — clear by the user-
296
+ // facing kvCacheKey (and optionally narrow by modelId).
297
+ clearInitializedCachesByScope({
298
+ cacheKey: target.kvCacheKey,
299
+ ...(target.modelId !== undefined && { modelId: target.modelId }),
300
+ });
301
+ }
302
+ // ----- private helpers -----
303
+ /**
304
+ * Verify that the addon actually persisted a usable cache file after a
305
+ * prime. Mirrors the `verifySaveAndRecord` access-probe used at commit
306
+ * time, applied at prime time so the session doesn't mark a cache
307
+ * `initializedCaches.add(...)` against a path that's missing or empty
308
+ * on disk.
309
+ *
310
+ * Failure modes this catches:
311
+ *
312
+ * - The addon's `model.run({ saveSessionPath })` was interrupted
313
+ * before the save call ran (e.g. signal abort during prefill); the
314
+ * prime closure resolves cleanly because addon save errors are not
315
+ * propagated, but no file is on disk.
316
+ * - The addon's `llama_state_save_file` was called but produced an
317
+ * empty file (out-of-space / fs error swallowed by the addon).
318
+ *
319
+ * Failure modes this does **NOT** catch:
320
+ *
321
+ * - A partial-but-nonzero file written by the addon (e.g. header +
322
+ * truncated KV state). Catching this requires either an
323
+ * addon-side change (have `CacheManager::writeCacheFile` check the
324
+ * return value of `llama_state_save_file` and throw on failure) or
325
+ * a structural hash check we can't currently compute from the
326
+ * SDK. Filed as a follow-up — see `cache-api.md` in the addon
327
+ * repo / tracking ticket.
328
+ *
329
+ * On failure we best-effort `unlink` an empty leftover file (so the
330
+ * next existence probe doesn't trust it) and throw — the handler in
331
+ * `completion-stream.ts` lets the error propagate up and no
332
+ * `initializedCaches` entry is recorded.
333
+ */
334
+ async function verifyPrimedFile(cachePath, logger) {
335
+ let stats;
336
+ try {
337
+ stats = await fsPromises.stat(cachePath);
338
+ }
339
+ catch (statError) {
340
+ // ENOENT is the common case here — addon prime returned without
341
+ // calling save (most often: signal abort during prefill).
342
+ throw new Error(`[kv-cache] prime closure resolved but no cache file was written. path=${cachePath} cause=${statError instanceof Error ? statError.message : String(statError)}`);
343
+ }
344
+ if (stats.size === 0) {
345
+ // Best-effort cleanup so a future probe doesn't trust the empty
346
+ // file. Unlink failure is non-fatal — we still throw on the
347
+ // primary "prime didn't persist" condition.
348
+ try {
349
+ await fsPromises.unlink(cachePath);
350
+ }
351
+ catch (unlinkError) {
352
+ logger.warn(`[kv-cache] Failed to remove empty primed cache file. path=${cachePath} error=${unlinkError instanceof Error ? unlinkError.message : String(unlinkError)}`);
353
+ }
354
+ throw new Error(`[kv-cache] prime closure resolved but cache file is empty. path=${cachePath}`);
355
+ }
356
+ }
357
+ /**
358
+ * Verify the addon actually persisted the cache file before recording
359
+ * its message count. The addon currently swallows write errors
360
+ * silently, so a missing file means the next turn must resend the full
361
+ * history rather than slicing against a stale `savedCount`.
362
+ *
363
+ * TODO: once the addon surfaces save failures (e.g. throws
364
+ * `UnableToSaveSessionFile` when `llama_state_save_file` returns
365
+ * false), drop the `access()` probe and wrap the `model.run()` call in
366
+ * a real try/catch that forwards the error.
367
+ */
368
+ async function verifySaveAndRecord(cachePath, messageCount) {
369
+ try {
370
+ await fsPromises.access(cachePath);
371
+ cachedMessageCounts.set(cachePath, messageCount);
372
+ return true;
373
+ }
374
+ catch (err) {
375
+ cachedMessageCounts.delete(cachePath);
376
+ logCacheSaveError(cachePath, err);
377
+ return false;
378
+ }
379
+ }
380
+ function clearCachedMessageCountsByPrefix(prefix, sep) {
381
+ if (!prefix) {
382
+ cachedMessageCounts.clear();
383
+ return;
384
+ }
385
+ for (const key of cachedMessageCounts.keys()) {
386
+ if (key === prefix) {
387
+ cachedMessageCounts.delete(key);
388
+ continue;
389
+ }
390
+ if (!key.startsWith(prefix + sep))
391
+ continue;
392
+ cachedMessageCounts.delete(key);
393
+ }
394
+ }
395
+ function clearInitializedCachesByScope(scope) {
396
+ if (scope.cacheKey === undefined && scope.modelId === undefined) {
397
+ initializedCaches.clear();
398
+ return;
399
+ }
400
+ for (const key of initializedCaches) {
401
+ const firstSep = key.indexOf(":");
402
+ const secondSep = key.indexOf(":", firstSep + 1);
403
+ if (firstSep === -1 || secondSep === -1)
404
+ continue;
405
+ const entryModelId = key.slice(0, firstSep);
406
+ const entryCacheKey = key.slice(secondSep + 1);
407
+ if (scope.cacheKey !== undefined && entryCacheKey !== scope.cacheKey) {
408
+ continue;
409
+ }
410
+ if (scope.modelId !== undefined && entryModelId !== scope.modelId) {
411
+ continue;
412
+ }
413
+ initializedCaches.delete(key);
414
+ }
415
+ }
416
+ // ----- test-only escape hatches -----
417
+ /**
418
+ * Test-only access to the module-scoped state. Production code reaches
419
+ * for cache state exclusively through the session API; the unit suite
420
+ * for `kv-cache-session.test.ts` needs to seed and inspect raw state
421
+ * to assert the rollback / commit invariants. Not part of the public
422
+ * SDK surface.
423
+ *
424
+ * @internal
425
+ */
426
+ export const __kvCacheSessionTestHooks = {
427
+ getSavedCount(cachePath) {
428
+ return cachedMessageCounts.get(cachePath);
429
+ },
430
+ setSavedCountForTest(cachePath, count) {
431
+ cachedMessageCounts.set(cachePath, count);
432
+ },
433
+ hasInitializedKey(modelId, configHash, cacheKey) {
434
+ return initializedCaches.has(initRegistryKey(modelId, configHash, cacheKey));
435
+ },
436
+ markInitializedForTest(modelId, configHash, cacheKey) {
437
+ initializedCaches.add(initRegistryKey(modelId, configHash, cacheKey));
438
+ },
439
+ resetForTest() {
440
+ cachedMessageCounts.clear();
441
+ initializedCaches.clear();
442
+ },
443
+ };
444
+ // Re-export `generateConfigHash` from the path utilities so callers of
445
+ // the session can compute the hash without separately importing
446
+ // `kv-cache-utils`. The function itself stays in `kv-cache-utils.ts`
447
+ // (pure, no state) — only the re-export lives here.
448
+ export { generateConfigHash };
@@ -1,73 +1,19 @@
1
1
  /**
2
- * Pure state + decision helpers for kv-cache bookkeeping used by
3
- * `completion-stream.ts`.
2
+ * Pure decision helper for kv-cache history slicing used by
3
+ * `completion-stream.ts` (via the slice computed from
4
+ * `TurnHandle.savedCount`).
4
5
  *
5
6
  * This module intentionally has **no** `bare-*` imports so it can be
6
- * exercised directly from unit tests running under `bun` without pulling
7
- * in the Bare runtime (which is not available in that environment).
8
- * The file-system-dependent pieces (e.g. `recordCacheSaveCount`) live in
9
- * `completion-stream.ts` and consume the state exported here.
10
- */
11
- /**
12
- * Number of chat messages the kv-cache file on disk is known to cover, keyed
13
- * by cache path. Written after a successful completion records a save, read
14
- * by `prepareMessagesForCache` to slice the history on the next turn so a
15
- * consumer can stage multiple messages between completions (e.g. an
16
- * `[assistant, user]` recovery sequence) without resending the whole history.
17
- *
18
- * INVARIANT: an entry is only present if the corresponding kv-cache file is
19
- * considered trustworthy. On any turn where the SDK cannot prove the saved
20
- * count reflects the on-disk state (cancellation mid-decode, zero-token
21
- * reply, cache file missing after a save attempt), the entry MUST be
22
- * deleted; a stale entry causes the next turn to slice its history down to
23
- * an empty payload and the model returns zero tokens.
24
- *
25
- * Mode notes:
26
- * - Static-mode turns are the only readers of this map. `clearStaleCount`
27
- * in `decideCachedHistorySlice` exists so a stale-but-non-zero entry
28
- * can be detected and dropped on the next read.
29
- * - Dynamic-mode turns do NOT consume this map — the addon trims tools
30
- * and the chain output from the kv-cache after each round, so the
31
- * SDK falls back to role-based dispatch in `prepareMessagesForCache`.
32
- * Writes still happen on dynamic-mode turns, but the recorded count
33
- * reflects the messages the SDK shipped, not the (possibly trimmed)
34
- * on-disk cache shape. The map is internally consistent within a
35
- * single mode; a `kvCache` key should not be reused across modes.
36
- */
37
- export declare const cachedMessageCounts: Map<string, number>;
38
- /**
39
- * Clear bookkeeping entries. With no argument, clears the whole map. With a
40
- * `prefix`, removes any entry whose path is equal to it OR sits beneath it
41
- * as a directory (i.e. `key.startsWith(prefix + sep)`).
7
+ * exercised directly from unit tests running under `bun` without
8
+ * pulling in the Bare runtime (which is not available in that
9
+ * environment).
42
10
  *
43
- * Runtime callers MUST pass the platform path separator (e.g. `path.sep`
44
- * from `bare-path`) so directory-prefix matches are correct on every
45
- * target. The "/" default exists only for unit tests under `bun`, where
46
- * cache paths are POSIX-shaped and importing `bare-path` would pull in
47
- * the Bare runtime. The exported wrapper in `completion-stream.ts`
48
- * injects the real separator for in-process use.
49
- */
50
- export declare function clearCachedMessageCounts(prefix?: string, sep?: string): void;
51
- /**
52
- * Called from `server/bare/ops/cancel.ts` right before `addon.cancel()` so
53
- * that the in-flight `completion()` for this model can detect that its
54
- * current turn is being cancelled and skip poisoning `cachedMessageCounts`
55
- * with a `history.length + 1` entry that does not correspond to a real
56
- * assistant reply.
57
- */
58
- export declare function noteCancelRequested(modelId: string): void;
59
- export declare function snapshotCancelCount(modelId: string): number;
60
- /** Test-only. */
61
- export declare function _resetCancelCountersForTest(): void;
62
- /**
63
- * A completion's `savedCount` should only be recorded when the turn ran to
64
- * completion AND produced at least one token. Any other outcome —
65
- * cancelled mid-decode, legitimate zero-token reply, or an early EOS — must
66
- * clear the entry instead, because there is no guarantee that the kv-cache
67
- * file on disk matches the `history.length + 1` boundary the SDK would
68
- * otherwise record.
11
+ * Cancel detection flows through the per-request `AbortSignal` from
12
+ * `RequestRegistry`; the `cachedMessageCounts` map lives in
13
+ * `kv-cache-session.ts`, which owns all three KV-cache bookkeeping
14
+ * layers (saved counts, init flags, on-disk files). Only the pure
15
+ * slice-decision helper remains here.
69
16
  */
70
- export declare function shouldRecordSavedCount(wasCancelled: boolean, producedTokens: boolean): boolean;
71
17
  export interface HistoryMessage {
72
18
  role: string;
73
19
  content: string;
@@ -80,8 +26,9 @@ export interface HistorySliceDecision {
80
26
  messages: HistoryMessage[];
81
27
  /**
82
28
  * True when the decision path proves the current `savedCount` is stale
83
- * and the caller should `cachedMessageCounts.delete(cachePath)` to avoid
84
- * propagating the bad count to the next turn.
29
+ * and the caller should drop the cached entry (via
30
+ * `KvCacheSession.dropStaleSavedCount(turn)`) to avoid propagating the
31
+ * bad count to the next turn.
85
32
  */
86
33
  clearStaleCount: boolean;
87
34
  }
@@ -89,13 +36,14 @@ export interface HistorySliceDecision {
89
36
  * Pure slice decision for `prepareMessagesForCache`.
90
37
  *
91
38
  * Mirrors the shape of the logic in `completion-stream.ts` but without
92
- * calling `transformMessages` (which depends on `bare-fs` for attachment
93
- * probing). Kept here so the decision can be unit-tested in isolation.
39
+ * calling `transformMessages` (which depends on `bare-fs` for
40
+ * attachment probing). Kept here so the decision can be unit-tested in
41
+ * isolation.
94
42
  *
95
- * The key regression guard: when a non-zero `savedCount` would slice the
96
- * history down to an empty array, it is treated as stale — the caller
97
- * falls back to sending the system-stripped full history rather than
98
- * handing the model an empty payload.
43
+ * The key regression guard: when a non-zero `savedCount` would slice
44
+ * the history down to an empty array, it is treated as stale — the
45
+ * caller falls back to sending the system-stripped full history rather
46
+ * than handing the model an empty payload.
99
47
  */
100
48
  export declare function decideCachedHistorySlice(savedCount: number, cacheExists: boolean, history: HistoryMessage[]): HistorySliceDecision;
101
49
  //# sourceMappingURL=kv-cache-state.d.ts.map