@mlx-bun/inference 0.0.0-stage → 1.0.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 (467) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1475 -2
  3. package/THIRD_PARTY_NOTICES.md +3404 -0
  4. package/dist/native/libmlx_bun_ane.dylib +0 -0
  5. package/dist/native/libmlx_bun_expert_io.dylib +0 -0
  6. package/dist/native/mlx-bun-frame-extract +0 -0
  7. package/examples/fit-model.ts +25 -0
  8. package/examples/qwen3-forward.ts +42 -0
  9. package/examples/qwen3-generate.ts +28 -0
  10. package/examples/trellis-expand.ts +23 -0
  11. package/package.json +129 -4
  12. package/src/adapters/available.ts +110 -0
  13. package/src/adapters/index.ts +3 -0
  14. package/src/adapters/manager.ts +316 -0
  15. package/src/artifacts/auxiliary-files.ts +45 -0
  16. package/src/artifacts/config-dialects.ts +94 -0
  17. package/src/artifacts/config.ts +341 -0
  18. package/src/artifacts/draft-vocabulary.ts +30 -0
  19. package/src/artifacts/expert-offload-build.ts +75 -0
  20. package/src/artifacts/expert-offload.ts +89 -0
  21. package/src/artifacts/experts/index.ts +3 -0
  22. package/src/artifacts/experts/io.ts +386 -0
  23. package/src/artifacts/experts/residency.ts +1134 -0
  24. package/src/artifacts/experts/usage.ts +415 -0
  25. package/src/artifacts/fingerprint.ts +44 -0
  26. package/src/artifacts/glm52/container.ts +305 -0
  27. package/src/artifacts/glm52/expert-layout.ts +249 -0
  28. package/src/artifacts/glm52/index.ts +7 -0
  29. package/src/artifacts/glm52/kernel-layout.ts +124 -0
  30. package/src/artifacts/glm52/layout.ts +152 -0
  31. package/src/artifacts/glm52/memory.ts +500 -0
  32. package/src/artifacts/glm52/resident-weights.ts +135 -0
  33. package/src/artifacts/glm52/weights.ts +503 -0
  34. package/src/artifacts/glm52-config.ts +262 -0
  35. package/src/artifacts/identity.ts +94 -0
  36. package/src/artifacts/index.ts +15 -0
  37. package/src/artifacts/mmap.ts +90 -0
  38. package/src/artifacts/safetensors-writer.ts +249 -0
  39. package/src/artifacts/safetensors.ts +164 -0
  40. package/src/artifacts/turboquant-fold.ts +42 -0
  41. package/src/artifacts/weight-audit.ts +43 -0
  42. package/src/artifacts/weights.ts +255 -0
  43. package/src/contracts/index.ts +2 -0
  44. package/src/contracts/mlx/attention.ts +8 -0
  45. package/src/contracts/mlx/cache.ts +510 -0
  46. package/src/contracts/mlx/checkpoint.ts +10 -0
  47. package/src/contracts/mlx/draft-checkpoint.ts +14 -0
  48. package/src/contracts/mlx/draft-projection.ts +27 -0
  49. package/src/contracts/mlx/draft-target.ts +84 -0
  50. package/src/contracts/mlx/drafter.ts +176 -0
  51. package/src/contracts/mlx/forward-work.ts +23 -0
  52. package/src/contracts/mlx/glm52-weights.ts +25 -0
  53. package/src/contracts/mlx/graph.ts +309 -0
  54. package/src/contracts/mlx/head.ts +6 -0
  55. package/src/contracts/mlx/index.ts +15 -0
  56. package/src/contracts/mlx/kv-codec.ts +9 -0
  57. package/src/contracts/mlx/media.ts +113 -0
  58. package/src/contracts/mlx/positions.ts +16 -0
  59. package/src/contracts/mlx/row-table.ts +2 -0
  60. package/src/contracts/mlx/trainable.ts +103 -0
  61. package/src/contracts/mlx/whisper.ts +96 -0
  62. package/src/contracts/portable/composition.ts +106 -0
  63. package/src/contracts/portable/denoising.ts +17 -0
  64. package/src/contracts/portable/execution.ts +79 -0
  65. package/src/contracts/portable/generation.ts +103 -0
  66. package/src/contracts/portable/graph.ts +80 -0
  67. package/src/contracts/portable/index.ts +15 -0
  68. package/src/contracts/portable/memory-plan.ts +26 -0
  69. package/src/contracts/portable/object-cache.ts +8 -0
  70. package/src/contracts/portable/prefill.ts +63 -0
  71. package/src/contracts/portable/prefix-cache.ts +33 -0
  72. package/src/contracts/portable/prompt.ts +2 -0
  73. package/src/contracts/portable/resources.ts +25 -0
  74. package/src/contracts/portable/rollback.ts +7 -0
  75. package/src/contracts/portable/sampling.ts +44 -0
  76. package/src/contracts/portable/scheduling.ts +54 -0
  77. package/src/contracts/portable/token-delivery.ts +4 -0
  78. package/src/contracts/portable/tsconfig.json +14 -0
  79. package/src/embeddings/index.ts +1 -0
  80. package/src/embeddings/text.ts +85 -0
  81. package/src/execution/admission.ts +59 -0
  82. package/src/execution/batch-group.ts +1240 -0
  83. package/src/execution/batch-types.ts +225 -0
  84. package/src/execution/cancellation.ts +38 -0
  85. package/src/execution/continuation-request.ts +45 -0
  86. package/src/execution/continuation-types.ts +10 -0
  87. package/src/execution/coordinator.ts +70 -0
  88. package/src/execution/denoising-group.ts +180 -0
  89. package/src/execution/engine.ts +56 -0
  90. package/src/execution/fill-group.ts +505 -0
  91. package/src/execution/fit.ts +184 -0
  92. package/src/execution/gateway-binding.ts +178 -0
  93. package/src/execution/grammar-group.ts +224 -0
  94. package/src/execution/index.ts +18 -0
  95. package/src/execution/methods.ts +75 -0
  96. package/src/execution/mixed-iteration.ts +96 -0
  97. package/src/execution/plan.ts +65 -0
  98. package/src/execution/prefill-cohort.ts +100 -0
  99. package/src/execution/prefill-rows.ts +263 -0
  100. package/src/execution/request-policy.ts +19 -0
  101. package/src/execution/row-sampling.ts +49 -0
  102. package/src/execution/scheduler.ts +92 -0
  103. package/src/execution/session.ts +247 -0
  104. package/src/execution/speculative-group.ts +797 -0
  105. package/src/execution/tasks.ts +44 -0
  106. package/src/generation/autoregressive.ts +840 -0
  107. package/src/generation/bindings/autoregressive.ts +104 -0
  108. package/src/generation/bindings/denoising.ts +60 -0
  109. package/src/generation/bindings/prefill-policy.ts +36 -0
  110. package/src/generation/checkpoint-identity.ts +60 -0
  111. package/src/generation/denoising.ts +85 -0
  112. package/src/generation/diffusion.ts +583 -0
  113. package/src/generation/fill/echo-index.ts +188 -0
  114. package/src/generation/fill/index.ts +3 -0
  115. package/src/generation/fill/proposal.ts +69 -0
  116. package/src/generation/fill/schema-rows.ts +506 -0
  117. package/src/generation/fill/session.ts +464 -0
  118. package/src/generation/fill/tool-boundary.ts +103 -0
  119. package/src/generation/fill-append.ts +58 -0
  120. package/src/generation/generate.ts +44 -0
  121. package/src/generation/grammar-step.ts +39 -0
  122. package/src/generation/index.ts +14 -0
  123. package/src/generation/phase-dispatch.ts +115 -0
  124. package/src/generation/prefill.ts +33 -0
  125. package/src/generation/result.ts +49 -0
  126. package/src/generation/scopes.ts +157 -0
  127. package/src/generation/speculative/acceptance.ts +41 -0
  128. package/src/generation/speculative/adaptive-draft-gate.ts +166 -0
  129. package/src/generation/speculative/bindings/assistant-rows.ts +102 -0
  130. package/src/generation/speculative/bindings/autoregressive-rows.ts +124 -0
  131. package/src/generation/speculative/bindings/binding.ts +106 -0
  132. package/src/generation/speculative/bindings/deepspec-rows.ts +33 -0
  133. package/src/generation/speculative/bindings/draft-target.ts +10 -0
  134. package/src/generation/speculative/bindings/glm52-mtp-rows.ts +128 -0
  135. package/src/generation/speculative/bindings/projected-context-rows.ts +78 -0
  136. package/src/generation/speculative/bindings/projected-draft-rows.ts +95 -0
  137. package/src/generation/speculative/bindings/qwen-mtp-rows.ts +336 -0
  138. package/src/generation/speculative/bindings/two-model-rows.ts +63 -0
  139. package/src/generation/speculative/cache-identity.ts +16 -0
  140. package/src/generation/speculative/draft-kind.ts +149 -0
  141. package/src/generation/speculative/draft-policy.ts +41 -0
  142. package/src/generation/speculative/draft-registry.ts +118 -0
  143. package/src/generation/speculative/draft-vocab.ts +110 -0
  144. package/src/generation/speculative/index.ts +17 -0
  145. package/src/generation/speculative/output.ts +49 -0
  146. package/src/generation/speculative/round.ts +307 -0
  147. package/src/generation/speculative/source.ts +144 -0
  148. package/src/generation/speculative/sources/assistant-source.ts +64 -0
  149. package/src/generation/speculative/sources/deepspec-source.ts +70 -0
  150. package/src/generation/speculative/sources/dflash-source.ts +84 -0
  151. package/src/generation/speculative/sources/dflash2-source.ts +86 -0
  152. package/src/generation/speculative/sources/glm52-mtp-source.ts +66 -0
  153. package/src/generation/speculative/sources/ngram-source.ts +165 -0
  154. package/src/generation/speculative/sources/qwen-mtp-source.ts +154 -0
  155. package/src/generation/speculative/sources/two-model.ts +75 -0
  156. package/src/generation/types.ts +194 -0
  157. package/src/index.ts +20 -0
  158. package/src/input/audio/audiotoolbox.ts +112 -0
  159. package/src/input/audio/decode.ts +133 -0
  160. package/src/input/audio/features.ts +202 -0
  161. package/src/input/audio/index.ts +6 -0
  162. package/src/input/audio/transcode.ts +67 -0
  163. package/src/input/audio/whisper-mel.ts +185 -0
  164. package/src/input/audio/whisper-tokenizer.ts +238 -0
  165. package/src/input/chat-template.ts +389 -0
  166. package/src/input/index.ts +6 -0
  167. package/src/input/media-fetch.ts +439 -0
  168. package/src/input/packed-mixed.ts +43 -0
  169. package/src/input/special-tokens.ts +75 -0
  170. package/src/input/token-groups.ts +49 -0
  171. package/src/input/tokenizer.ts +336 -0
  172. package/src/input/tool-call.ts +689 -0
  173. package/src/input/vision/index.ts +3 -0
  174. package/src/input/vision/preprocess.ts +247 -0
  175. package/src/input/vision/prompt.ts +398 -0
  176. package/src/input/vision/qwen3vl-preprocess.ts +409 -0
  177. package/src/input/vision/qwen3vl-prompt.ts +237 -0
  178. package/src/input/vision/video-frames.ts +100 -0
  179. package/src/kernels/ane/fill.ts +101 -0
  180. package/src/kernels/ane/linear.ts +416 -0
  181. package/src/kernels/attention/flash.ts +694 -0
  182. package/src/kernels/attention/kvq4-decode.ts +155 -0
  183. package/src/kernels/attention/masks.ts +40 -0
  184. package/src/kernels/attention/multi-query.ts +193 -0
  185. package/src/kernels/attention/paged.ts +130 -0
  186. package/src/kernels/delta/gated.ts +306 -0
  187. package/src/kernels/delta/index.ts +3 -0
  188. package/src/kernels/delta/silu-rms-heads.ts +69 -0
  189. package/src/kernels/delta/state.ts +74 -0
  190. package/src/kernels/gated-rms-norm.ts +64 -0
  191. package/src/kernels/glm52/layout.ts +37 -0
  192. package/src/kernels/glm52/streamed-experts.ts +360 -0
  193. package/src/kernels/logits.ts +38 -0
  194. package/src/kernels/quantization/affine-row.ts +154 -0
  195. package/src/kernels/quantization/affine-rows.ts +36 -0
  196. package/src/kernels/quantization/affine-split-mma.ts +144 -0
  197. package/src/kernels/quantization/affine3-mma.ts +117 -0
  198. package/src/kernels/quantization/affine3-rows.ts +103 -0
  199. package/src/kernels/quantization/affine4-mma.ts +113 -0
  200. package/src/kernels/quantization/affine4-rows.ts +102 -0
  201. package/src/kernels/residual-rms-norm.ts +65 -0
  202. package/src/kernels/sampling/index.ts +2 -0
  203. package/src/kernels/sampling/normalized-argmax.ts +116 -0
  204. package/src/kernels/sampling/token-bitmask.ts +52 -0
  205. package/src/kernels/softcap.ts +35 -0
  206. package/src/kernels/trellis/codebook.ts +123 -0
  207. package/src/kernels/trellis/down-codebook.ts +184 -0
  208. package/src/kernels/trellis/down-factored.ts +180 -0
  209. package/src/kernels/trellis/down-k3-interleaved-factored.ts +146 -0
  210. package/src/kernels/trellis/down-mma-wide.ts +195 -0
  211. package/src/kernels/trellis/down-mma.ts +145 -0
  212. package/src/kernels/trellis/expand.ts +42 -0
  213. package/src/kernels/trellis/gate-up-codebook-mma.ts +141 -0
  214. package/src/kernels/trellis/gate-up-codebook.ts +137 -0
  215. package/src/kernels/trellis/gate-up-factored.ts +197 -0
  216. package/src/kernels/trellis/gate-up-mma-wide.ts +147 -0
  217. package/src/kernels/trellis/gate-up-mma.ts +148 -0
  218. package/src/kernels/trellis/gate-up.ts +248 -0
  219. package/src/kernels/trellis/geometry.ts +22 -0
  220. package/src/kernels/trellis/index.ts +103 -0
  221. package/src/kernels/trellis/launch.ts +12 -0
  222. package/src/kernels/trellis/mixed-gate-up-factored.ts +119 -0
  223. package/src/kernels/trellis/mixed-gate-up.ts +146 -0
  224. package/src/kernels/trellis/qualified.ts +34 -0
  225. package/src/kernels/trellis/reduce.ts +150 -0
  226. package/src/kernels/trellis/scatter.ts +407 -0
  227. package/src/kernels/trellis/splitk-prefill.ts +152 -0
  228. package/src/kernels/trellis/tiled-prefill.ts +131 -0
  229. package/src/kernels/trellis/vector-expand.ts +58 -0
  230. package/src/kernels/trellis/wide-prefill.ts +89 -0
  231. package/src/kernels/turboquant/decode.ts +82 -0
  232. package/src/kernels/turboquant/index.ts +5 -0
  233. package/src/kernels/turboquant/inverse.ts +122 -0
  234. package/src/kernels/turboquant/ops.ts +860 -0
  235. package/src/kernels/turboquant/signs.ts +130 -0
  236. package/src/kernels/turboquant/tables.ts +124 -0
  237. package/src/layers/affine-verify-linear.ts +75 -0
  238. package/src/layers/ane-prefill-split.ts +283 -0
  239. package/src/layers/compiled-normalization.ts +41 -0
  240. package/src/layers/delta-heads.ts +23 -0
  241. package/src/layers/dense-embedding.ts +29 -0
  242. package/src/layers/dense-linear.ts +32 -0
  243. package/src/layers/dequantized-linear.ts +72 -0
  244. package/src/layers/folded-attention.ts +42 -0
  245. package/src/layers/geglu.ts +130 -0
  246. package/src/layers/helpers.ts +7 -0
  247. package/src/layers/index.ts +36 -0
  248. package/src/layers/kv4-decode-attention.ts +15 -0
  249. package/src/layers/layer-norm.ts +24 -0
  250. package/src/layers/loading.ts +92 -0
  251. package/src/layers/lora.ts +150 -0
  252. package/src/layers/normalization.ts +9 -0
  253. package/src/layers/prefix-layout.ts +33 -0
  254. package/src/layers/quantized-append-attention.ts +32 -0
  255. package/src/layers/quantized-attention.ts +353 -0
  256. package/src/layers/quantized-embedding.ts +39 -0
  257. package/src/layers/quantized-linear.ts +137 -0
  258. package/src/layers/quantized-switch-linear.ts +37 -0
  259. package/src/layers/qwen-append.ts +12 -0
  260. package/src/layers/qwen-mrope.ts +238 -0
  261. package/src/layers/rope-2d.ts +110 -0
  262. package/src/layers/rope.ts +389 -0
  263. package/src/layers/swiglu.ts +23 -0
  264. package/src/layers/trellis-codebook-down.ts +52 -0
  265. package/src/layers/trellis-codebook-gate-up.ts +42 -0
  266. package/src/layers/trellis-down.ts +117 -0
  267. package/src/layers/trellis-gate-up.ts +71 -0
  268. package/src/layers/trellis-linear.ts +211 -0
  269. package/src/layers/trellis-prompt.ts +102 -0
  270. package/src/layers/trellis-reduce-gate-up.ts +73 -0
  271. package/src/layers/trellis-scatter-down.ts +98 -0
  272. package/src/models/ane-install.ts +74 -0
  273. package/src/models/audio/conformer.ts +656 -0
  274. package/src/models/cache-composition.ts +44 -0
  275. package/src/models/capabilities.ts +89 -0
  276. package/src/models/chat-template.ts +10 -0
  277. package/src/models/composition.ts +107 -0
  278. package/src/models/diffusion-gemma/experts.ts +59 -0
  279. package/src/models/diffusion-gemma/family.ts +21 -0
  280. package/src/models/diffusion-gemma/model.ts +900 -0
  281. package/src/models/diffusion-gemma/vision.ts +549 -0
  282. package/src/models/drafter-loaders.ts +49 -0
  283. package/src/models/drafters.ts +39 -0
  284. package/src/models/factory.ts +351 -0
  285. package/src/models/families.ts +70 -0
  286. package/src/models/family.ts +125 -0
  287. package/src/models/gemma4/assistant-target.ts +46 -0
  288. package/src/models/gemma4/assistant.ts +327 -0
  289. package/src/models/gemma4/blocks.ts +755 -0
  290. package/src/models/gemma4/compiled-decode.ts +452 -0
  291. package/src/models/gemma4/family.ts +39 -0
  292. package/src/models/gemma4/gemma4-12b.ts +677 -0
  293. package/src/models/gemma4/gemma4-26b.ts +544 -0
  294. package/src/models/gemma4/gemma4-e4b.ts +599 -0
  295. package/src/models/gemma4/graphs.ts +147 -0
  296. package/src/models/gemma4/media.ts +88 -0
  297. package/src/models/gemma4/model.ts +860 -0
  298. package/src/models/gemma4/serving-blocks.ts +72 -0
  299. package/src/models/gemma4/trainable.ts +186 -0
  300. package/src/models/gemma4/written-blocks.ts +232 -0
  301. package/src/models/gemma4/written-forward.ts +159 -0
  302. package/src/models/gemma4/written-input.ts +29 -0
  303. package/src/models/glm52/atlas.ts +507 -0
  304. package/src/models/glm52/coupling.ts +388 -0
  305. package/src/models/glm52/dsa.ts +601 -0
  306. package/src/models/glm52/family.ts +20 -0
  307. package/src/models/glm52/mla.ts +812 -0
  308. package/src/models/glm52/model.ts +1127 -0
  309. package/src/models/glm52/moe.ts +223 -0
  310. package/src/models/glm52/mtp.ts +60 -0
  311. package/src/models/glm52/pilot.ts +537 -0
  312. package/src/models/glm52/reference.ts +445 -0
  313. package/src/models/glm52/residency.ts +557 -0
  314. package/src/models/glm52/streamed-experts.ts +447 -0
  315. package/src/models/graph.ts +59 -0
  316. package/src/models/implementation.ts +230 -0
  317. package/src/models/index.ts +15 -0
  318. package/src/models/media-input.ts +15 -0
  319. package/src/models/memory-plan.ts +39 -0
  320. package/src/models/minicpm5/family.ts +29 -0
  321. package/src/models/minicpm5/model.ts +394 -0
  322. package/src/models/minicpm5/trainable.ts +90 -0
  323. package/src/models/profile.ts +337 -0
  324. package/src/models/qwen/blocks.ts +658 -0
  325. package/src/models/qwen/checkpoint.ts +190 -0
  326. package/src/models/qwen/families.ts +57 -0
  327. package/src/models/qwen/media-input.ts +161 -0
  328. package/src/models/qwen/mtp.ts +101 -0
  329. package/src/models/qwen/qwen3-moe.ts +355 -0
  330. package/src/models/qwen/qwen3.ts +323 -0
  331. package/src/models/qwen/qwen38-27b-trellis-m1max.ts +1532 -0
  332. package/src/models/qwen/qwen38-27b-trellis-m4pro.ts +1092 -0
  333. package/src/models/qwen/qwen3_5.ts +433 -0
  334. package/src/models/qwen/written-layers.ts +285 -0
  335. package/src/models/row-table.ts +1 -0
  336. package/src/models/runtime.ts +73 -0
  337. package/src/models/speculative/deepspec-artifact.ts +10 -0
  338. package/src/models/speculative/deepspec.ts +744 -0
  339. package/src/models/speculative/dflash.ts +553 -0
  340. package/src/models/speculative/dflash2-artifact.ts +9 -0
  341. package/src/models/speculative/dflash2-operations.ts +1 -0
  342. package/src/models/speculative/dflash2.ts +576 -0
  343. package/src/models/speculative/loader.ts +29 -0
  344. package/src/models/support.ts +79 -0
  345. package/src/models/universal/archs.ts +365 -0
  346. package/src/models/universal/blocks.ts +479 -0
  347. package/src/models/universal/dense.ts +255 -0
  348. package/src/models/universal/family.ts +17 -0
  349. package/src/models/vision/qwen3vl.ts +566 -0
  350. package/src/models/vision/siglip.ts +520 -0
  351. package/src/models/vision/unified.ts +176 -0
  352. package/src/models/whisper/family.ts +19 -0
  353. package/src/models/whisper/fast.ts +734 -0
  354. package/src/models/whisper/model.ts +430 -0
  355. package/src/runtime/compiled-trace.ts +16 -0
  356. package/src/runtime/config.ts +77 -0
  357. package/src/runtime/expert-trace.ts +71 -0
  358. package/src/runtime/graph-forward.ts +65 -0
  359. package/src/runtime/integers.ts +6 -0
  360. package/src/runtime/native.ts +16 -0
  361. package/src/runtime/resources.ts +53 -0
  362. package/src/runtime/row-operations.ts +42 -0
  363. package/src/runtime/trace.ts +161 -0
  364. package/src/sampling/curve.ts +122 -0
  365. package/src/sampling/draft.ts +55 -0
  366. package/src/sampling/extras.ts +45 -0
  367. package/src/sampling/filters.ts +134 -0
  368. package/src/sampling/grammar.ts +630 -0
  369. package/src/sampling/hlg.ts +290 -0
  370. package/src/sampling/index.ts +9 -0
  371. package/src/sampling/processors.ts +142 -0
  372. package/src/sampling/sampler.ts +120 -0
  373. package/src/sampling/step.ts +343 -0
  374. package/src/sampling/types.ts +161 -0
  375. package/src/sampling/window-filters.ts +46 -0
  376. package/src/scoring/decisions.ts +96 -0
  377. package/src/scoring/full-sequence.ts +103 -0
  378. package/src/scoring/index.ts +9 -0
  379. package/src/scoring/kl.ts +29 -0
  380. package/src/scoring/perplexity.ts +165 -0
  381. package/src/scoring/response-logps.ts +65 -0
  382. package/src/state/affine-attention.ts +180 -0
  383. package/src/state/attachment.ts +68 -0
  384. package/src/state/attention-read.ts +215 -0
  385. package/src/state/batched-kv.ts +294 -0
  386. package/src/state/batched-mask.ts +445 -0
  387. package/src/state/batched-quant.ts +389 -0
  388. package/src/state/batched-quantized-kv.ts +209 -0
  389. package/src/state/batched-rotating-quant.ts +457 -0
  390. package/src/state/batched-rotating-state.ts +149 -0
  391. package/src/state/batched-rotating.ts +430 -0
  392. package/src/state/batched-row-storage.ts +179 -0
  393. package/src/state/batched-ssm.ts +54 -0
  394. package/src/state/batched-turboquant-kv.ts +144 -0
  395. package/src/state/bf16-first-kv.ts +663 -0
  396. package/src/state/cache-service.ts +592 -0
  397. package/src/state/capabilities.ts +65 -0
  398. package/src/state/checkpoint.ts +46 -0
  399. package/src/state/continuation-persistence.ts +126 -0
  400. package/src/state/decode-step-inputs.ts +31 -0
  401. package/src/state/decoded-kv-donor.ts +12 -0
  402. package/src/state/delayed-quantized-kv.ts +141 -0
  403. package/src/state/delayed-rotating-quantized-kv.ts +178 -0
  404. package/src/state/delayed-turboquant-kv.ts +123 -0
  405. package/src/state/durability.ts +214 -0
  406. package/src/state/encoder-cache.ts +26 -0
  407. package/src/state/full-kv-row-append.ts +33 -0
  408. package/src/state/full-kv-row-donor.ts +54 -0
  409. package/src/state/full-prefill-padding.ts +56 -0
  410. package/src/state/full-prefill-row.ts +112 -0
  411. package/src/state/full-transitioning-kv-rows.ts +70 -0
  412. package/src/state/glm52-cache.ts +783 -0
  413. package/src/state/grouped-heads-kv4-cache.ts +26 -0
  414. package/src/state/index.ts +38 -0
  415. package/src/state/kv-attention-view.ts +77 -0
  416. package/src/state/kv-budget.ts +14 -0
  417. package/src/state/kv-scheme.ts +315 -0
  418. package/src/state/kv-storage.ts +57 -0
  419. package/src/state/kv-tensor-rows.ts +212 -0
  420. package/src/state/kv.ts +324 -0
  421. package/src/state/kv4-head256-cache.ts +46 -0
  422. package/src/state/latent-legos.ts +895 -0
  423. package/src/state/layout.ts +277 -0
  424. package/src/state/leases.ts +26 -0
  425. package/src/state/paged/cache.ts +689 -0
  426. package/src/state/paged/codec.ts +36 -0
  427. package/src/state/paged/rows.ts +223 -0
  428. package/src/state/persistence-types.ts +173 -0
  429. package/src/state/persistence-worker.ts +83 -0
  430. package/src/state/persistence.ts +1036 -0
  431. package/src/state/persistence.worker.d.ts +3 -0
  432. package/src/state/persistence.worker.js +264 -0
  433. package/src/state/prefix-cache.ts +685 -0
  434. package/src/state/quantized-kv.ts +369 -0
  435. package/src/state/quantized-tensor.ts +26 -0
  436. package/src/state/request-policy.ts +48 -0
  437. package/src/state/retention-policy.ts +37 -0
  438. package/src/state/rollback.ts +131 -0
  439. package/src/state/rotating-kv-donor.ts +35 -0
  440. package/src/state/rotating-kv-layout.ts +341 -0
  441. package/src/state/rotating-kv.ts +529 -0
  442. package/src/state/rotating-quantized-kv.ts +616 -0
  443. package/src/state/rotating-row-transaction.ts +35 -0
  444. package/src/state/rows.ts +104 -0
  445. package/src/state/softcap-attention.ts +118 -0
  446. package/src/state/speculative/glm52-mtp-state.ts +38 -0
  447. package/src/state/speculative/qwen-mtp-state.ts +34 -0
  448. package/src/state/speculative-rotating-kv.ts +113 -0
  449. package/src/state/ssd-cache.ts +434 -0
  450. package/src/state/ssm-prefill-padding.ts +39 -0
  451. package/src/state/ssm.ts +422 -0
  452. package/src/state/target-layout.ts +7 -0
  453. package/src/state/tiered-prefix-cache.ts +45 -0
  454. package/src/state/training-cache.ts +300 -0
  455. package/src/state/transitioning-kv-rows.ts +267 -0
  456. package/src/state/turboquant-attention.ts +97 -0
  457. package/src/state/turboquant-codec.ts +90 -0
  458. package/src/state/turboquant-kv.ts +442 -0
  459. package/src/state/views.ts +26 -0
  460. package/src/transcription/index.ts +3 -0
  461. package/src/transcription/silero-vad.ts +379 -0
  462. package/src/transcription/whisper/decode.ts +773 -0
  463. package/src/transcription/whisper/format.ts +74 -0
  464. package/src/transcription/whisper/index.ts +4 -0
  465. package/src/transcription/whisper/timing.ts +274 -0
  466. package/src/transcription/whisper/transcribe.ts +394 -0
  467. package/src/transcription/whisper/types.ts +22 -0
@@ -0,0 +1,104 @@
1
+ import type { BatchableCache, Cache } from "../contracts/mlx/cache";
2
+ import { applyStateChanges, cleanupFailure, disposeResources } from "../runtime/resources";
3
+ import type { PreparedStateChange } from "../contracts/portable/resources";
4
+
5
+ /** Preserve the graph's layout capabilities when an empty sibling is made. */
6
+ export interface MlxRowLayout<Layout extends BatchableCache> extends BatchableCache {
7
+ makeEmptyBatch(): Layout;
8
+ }
9
+
10
+ /** Layer layouts own tensor geometry. This collection only applies the same
11
+ * row membership operation to every layer. It has no scheduling, sampling,
12
+ * checkpoint-key or persistence policy. */
13
+ export class MlxStateRows<Layout extends MlxRowLayout<Layout> = BatchableCache> {
14
+ /** Borrowed by the bound target graph; collection ownership stays here. */
15
+ readonly caches: Layout[];
16
+ #rows = 0;
17
+
18
+ /** Takes ownership of empty, compatible layer layouts. */
19
+ constructor(layouts: readonly Layout[]) { this.caches = [...layouts]; }
20
+ get rowCount(): number { return this.#rows; }
21
+ /** Retain an immutable batch boundary without extracting or materializing
22
+ * individual rows. Layer layouts decide how to share their backing arrays. */
23
+ clone(): MlxStateRows<Layout> {
24
+ const layouts: Layout[] = [];
25
+ try {
26
+ for (const source of this.caches) {
27
+ const layout = source.makeEmptyBatch(); layouts.push(layout);
28
+ layout.mergeRows([source]);
29
+ }
30
+ const result = new MlxStateRows(layouts); result.#rows = this.#rows;
31
+ return result;
32
+ } catch (error) { return cleanupFailure(error, () => disposeResources(layouts)); }
33
+ }
34
+ /** Prepare an initial cohort with one merge per layer. */
35
+ mergeRows(rows: readonly (readonly Cache[])[]): void {
36
+ const next: Layout[] = [];
37
+ try {
38
+ for (let layer = 0; layer < this.caches.length; layer++) {
39
+ const layout = this.caches[layer]!.makeEmptyBatch(); next.push(layout);
40
+ layout.mergeRows(rows.map(row => row[layer]!));
41
+ }
42
+ } catch (error) { return cleanupFailure(error, () => disposeResources(next)); }
43
+ const previous = this.caches.splice(0, this.caches.length, ...next);
44
+ this.#rows = rows.length; disposeResources(previous);
45
+ }
46
+
47
+ /** Borrow a prepared request's state. Build every replacement before
48
+ * releasing the active group, so a failed admission leaves it intact. */
49
+ append(row: readonly Cache[]): void {
50
+ applyStateChanges([() => this.prepareAppend(row)]);
51
+ }
52
+
53
+ /** Stage membership so a method can compose it with companion-state admission. */
54
+ prepareAppend(row: readonly Cache[]): PreparedStateChange {
55
+ return this.prepareAppendMany([row]);
56
+ }
57
+
58
+ /** Stage several admissions with one membership operation per layer. */
59
+ prepareAppendMany(rows: readonly (readonly Cache[])[]): PreparedStateChange {
60
+ const next: Layout[] = [];
61
+ try {
62
+ for (let layer = 0; layer < this.caches.length; layer++) {
63
+ const layout = this.caches[layer]!;
64
+ const merged = layout.makeEmptyBatch();
65
+ next.push(merged);
66
+ merged.mergeRows([...(this.#rows ? [layout] : []), ...rows.map(row => row[layer]!)]);
67
+ }
68
+ } catch (error) { return cleanupFailure(error, () => disposeResources(next)); }
69
+ return {
70
+ commit: () => {
71
+ const previous = this.caches.splice(0, this.caches.length, ...next.splice(0));
72
+ this.#rows += rows.length;
73
+ next.push(...previous);
74
+ },
75
+ dispose: () => disposeResources(next.splice(0)),
76
+ };
77
+ }
78
+
79
+ /** The method calls this only between committed steps. A layer failure
80
+ * invalidates the group; its caller discards the state. */
81
+ filterRows(keep: readonly number[]): void {
82
+ if (!keep.length) { this.clear(); return; }
83
+ for (const layout of this.caches) layout.filterRows(keep);
84
+ this.#rows = keep.length;
85
+ }
86
+
87
+ /** Returns independent request state for a cache publisher or a new group. */
88
+ extractRow(row: number): Cache[] {
89
+ const state: Cache[] = [];
90
+ try { for (const layout of this.caches) state.push(layout.extractRow(row)); return state; }
91
+ catch (error) { return cleanupFailure(error, () => disposeResources(state)); }
92
+ }
93
+
94
+ clear(): void {
95
+ const next: Layout[] = [];
96
+ try { for (const layout of this.caches) next.push(layout.makeEmptyBatch()); }
97
+ catch (error) { return cleanupFailure(error, () => disposeResources(next)); }
98
+ const previous = this.caches.splice(0, this.caches.length, ...next);
99
+ this.#rows = 0;
100
+ disposeResources(previous);
101
+ }
102
+
103
+ dispose(): void { this.#rows = 0; disposeResources(this.caches); }
104
+ }
@@ -0,0 +1,118 @@
1
+ // The score-softcapped attention read (mlx-lm gemma2.py's manual attention):
2
+ // a graph whose layers softcap their attention scores composes it at
3
+ // construction in place of the cache's own read. The fused SDPA kernel cannot
4
+ // express the softcap, so this read fetches the window as plain keys and values
5
+ // and attends with the manual composition.
6
+ //
7
+ // It reads every KV storage through its dense fetch (`updateAndFetch`): plain
8
+ // and rotating storage and their row layouts hand their keys and values out as
9
+ // stored, TurboQuant storage decoded, affine storage dequantized (the delayed
10
+ // layouts per row, before and after a row's transition), paged storage
11
+ // gathered. Affine storage is dequantized and then read by the same manual
12
+ // attention, so a converted layer keeps the graph's own arithmetic over the
13
+ // values its storage holds. The read takes the storage's mask for the query
14
+ // count before the append, appends through `updateAndFetch`, then attends
15
+ // manually under that mask. The fetch and the mask are storage reads internal
16
+ // to `state/` (`KvStorage`); the cache contract carries neither.
17
+
18
+ import type { MlxArray } from "@mlx-bun/mlx/array";
19
+ import * as ops from "@mlx-bun/mlx/ops";
20
+ import type { AttentionRead, Cache, Mask } from "../contracts/mlx/cache";
21
+ import { createCausalMask } from "../kernels/attention/masks";
22
+ import { logitSoftcap } from "../kernels/logits";
23
+ import { disposing } from "../layers/helpers";
24
+ import { FINFO_MIN } from "../layers/quantized-attention";
25
+ import { disposeResources } from "../runtime/resources";
26
+ import { kvStorage, type KvStorage } from "./kv-storage";
27
+
28
+ /** The softcapped reads of one attention layer, each appending `k` and `v`
29
+ * (borrowed; positional encoding applied) to `cache` for the phase it names and
30
+ * returning the read the layer attends once and disposes. `attend(q, scale)`
31
+ * takes queries [B, Hq, L, D] (borrowed) and returns an owned [B, Hq, L, Dv]. */
32
+ export interface SoftcapAttentionReads {
33
+ /** One new position per row. */
34
+ appendDecode(cache: Cache, k: MlxArray, v: MlxArray): AttentionRead;
35
+ /** `L` new positions per row, causal within the window. */
36
+ appendWindow(cache: Cache, k: MlxArray, v: MlxArray): AttentionRead;
37
+ }
38
+
39
+ /** The softcapped reads of a layer whose attention scores are capped at
40
+ * `softcap` (`tanh(scores / softcap) * softcap`). `window` is the layer's
41
+ * sliding window (null for a full-attention layer), the window its cache masks
42
+ * with. `arrayMasks` materializes the ordinary causal mask as a boolean array
43
+ * (gemma2's `create_attention_mask(..., return_array=True)`); the manual
44
+ * attention applies only array masks. Decode and window make the same call:
45
+ * the cache's own mask for the query count, which is no mask for one unpadded
46
+ * position. */
47
+ export function softcapAttentionReads(softcap: number, window: number | null, arrayMasks: boolean): SoftcapAttentionReads {
48
+ const mask = (cache: KvStorage, L: number): Mask => {
49
+ const own = cache.makeMask(L, window);
50
+ return arrayMasks && own.mode === "causal" ? { mode: "array", arr: createCausalMask(L, cache.offset, window) } : own;
51
+ };
52
+ const read = (row: Cache, k: MlxArray, v: MlxArray): AttentionRead => {
53
+ const cache = kvStorage(row);
54
+ const held = mask(cache, k.shape[2]!);
55
+ let keys: MlxArray, values: MlxArray;
56
+ try { [keys, values] = cache.updateAndFetch(k, v); }
57
+ catch (error) { held.arr?.dispose(); throw error; }
58
+ return {
59
+ attend: (q, scale) => softcapAttention(q, keys, values, held, scale, softcap),
60
+ dispose() { disposeResources(held.arr ? [keys, values, held.arr] : [keys, values]); },
61
+ };
62
+ };
63
+ return Object.freeze({ appendDecode: read, appendWindow: read });
64
+ }
65
+
66
+ /** gemma2.py's manual attention: scale, the GQA 5-d reshape, q·kᵀ, the tanh
67
+ * softcap, a boolean mask through `where(mask, scores, finfo.min)`, the
68
+ * precise softmax, then ·v. `q` [B, Hq, L, D], `keys` [B, Hkv, S, D] and
69
+ * `values` [B, Hkv, S, Dv] are borrowed; only an array mask is applied. Returns
70
+ * an owned [B, Hq, L, Dv]. */
71
+ export function softcapAttention(q: MlxArray, keys: MlxArray, values: MlxArray, mask: Mask, scale: number,
72
+ softcap: number): MlxArray {
73
+ const [B, numHeads, L, headDim] = q.shape as [number, number, number, number];
74
+ const numKvHeads = keys.shape[1]!;
75
+ const repeats = Math.floor(numHeads / numKvHeads);
76
+ let queries = ops.mulScalar(q, scale); // queries * self.scale
77
+
78
+ let kk = keys;
79
+ let vv = values;
80
+ let kExp: MlxArray | null = null;
81
+ let vExp: MlxArray | null = null;
82
+ if (repeats > 1) {
83
+ queries = disposing(queries, ops.reshape(queries, [B, numKvHeads, repeats, L, headDim]));
84
+ kExp = ops.expandDims(keys, 2);
85
+ vExp = ops.expandDims(values, 2);
86
+ kk = kExp;
87
+ vv = vExp;
88
+ }
89
+
90
+ const kT = ops.transposeAxes(kk, repeats > 1 ? [0, 1, 2, 4, 3] : [0, 1, 3, 2]);
91
+ let scores = ops.matmul(queries, kT);
92
+ kT.dispose();
93
+ queries.dispose();
94
+
95
+ // tanh(scores / cap) * cap — same composition as logitSoftcap.
96
+ scores = disposing(scores, logitSoftcap(scores, softcap));
97
+
98
+ if (mask.mode === "array" && mask.arr) {
99
+ // bool mask: where(mask, scores, finfo(scores.dtype).min)
100
+ const minVal = FINFO_MIN[scores.dtype];
101
+ if (minVal === undefined) throw new Error(`no finfo.min for dtype ${scores.dtypeName}`);
102
+ const minArr = ops.scalarLike(minVal, scores);
103
+ // GQA scores are [B, Hkv, repeats, L, S]. Row masks carry B,
104
+ // unlike the ordinary [L, S] causal mask, so keep that axis aligned.
105
+ using rowMask = repeats > 1 && mask.arr.shape.length === 4
106
+ ? ops.expandDims(mask.arr, 2) : null;
107
+ scores = disposing(scores, ops.where(rowMask ?? mask.arr, scores, minArr));
108
+ minArr.dispose();
109
+ }
110
+
111
+ scores = disposing(scores, ops.softmaxAxis(scores, -1, true));
112
+ let out = ops.matmul(scores, vv);
113
+ scores.dispose();
114
+ kExp?.dispose();
115
+ vExp?.dispose();
116
+ if (repeats > 1) out = disposing(out, ops.reshape(out, [B, numHeads, L, values.shape[3]!]));
117
+ return out;
118
+ }
@@ -0,0 +1,38 @@
1
+ import type { MlxArray } from "@mlx-bun/mlx/array";
2
+ import type { MLACache } from "../glm52-cache";
3
+ import { cloneAttachments } from "../checkpoint";
4
+ import { disposeResources } from "../../runtime/resources";
5
+ import { DRAFT_CHECKPOINT_SCHEMA, type DraftRowCheckpoint } from "../../contracts/mlx/draft-checkpoint";
6
+
7
+ export function captureGlm52MtpState(state: Glm52MtpRowState): DraftRowCheckpoint {
8
+ const held: MlxArray[] = [];
9
+ try {
10
+ if (state.cache.offset) {
11
+ const cache = state.cache.fetch(); held.push(cache.latent, cache.rope);
12
+ }
13
+ held.push(state.hidden.slice([0, 0, 0], [...state.hidden.shape]));
14
+ return { processedTokens: state.processedTokens, attachment: {
15
+ schema: DRAFT_CHECKPOINT_SCHEMA.glm52Mtp, metadata: { processedTokens: state.processedTokens, draftOffset: state.cache.offset },
16
+ tensors: held.splice(0),
17
+ } };
18
+ } finally { disposeResources(held); }
19
+ }
20
+
21
+ export function restoreGlm52MtpState(checkpoint: DraftRowCheckpoint, makeCache: () => MLACache): Glm52MtpRowState {
22
+ const { attachment, processedTokens } = checkpoint;
23
+ if (attachment.schema !== DRAFT_CHECKPOINT_SCHEMA.glm52Mtp || attachment.metadata.processedTokens !== processedTokens)
24
+ throw new Error("invalid native GLM MTP checkpoint alignment");
25
+ const held = cloneAttachments([attachment])[0]!.tensors;
26
+ let cache: MLACache | null = makeCache();
27
+ try {
28
+ const offset = attachment.metadata.draftOffset as number;
29
+ if (offset) { cache.restoreCompressedState(held[0]!, held[1]!, null, offset); held.splice(0, 2); }
30
+ const state = { cache, hidden: held.pop()!, processedTokens }; cache = null; return state;
31
+ } finally { disposeResources([...held, ...(cache ? [cache] : [])]); }
32
+ }
33
+
34
+ export interface Glm52MtpRowState {
35
+ readonly cache: MLACache;
36
+ readonly hidden: MlxArray;
37
+ readonly processedTokens: number;
38
+ }
@@ -0,0 +1,34 @@
1
+ import type { MlxArray } from "@mlx-bun/mlx/array";
2
+ import { KVCache } from "../kv";
3
+ import { cloneAttachments } from "../checkpoint";
4
+ import { disposeResources } from "../../runtime/resources";
5
+ import { DRAFT_CHECKPOINT_SCHEMA, type DraftRowCheckpoint } from "../../contracts/mlx/draft-checkpoint";
6
+
7
+ /** The existing Qwen companion attachment is also the state interchange
8
+ * between prepared requests and a group. Storage-tier policy stays outside. */
9
+ export function restoreQwenMtpState(checkpoint: DraftRowCheckpoint): MtpRowState {
10
+ const { processedTokens: tokens, attachment } = checkpoint;
11
+ if (attachment.schema !== DRAFT_CHECKPOINT_SCHEMA.qwenMtp || attachment.metadata.draftOffset !== tokens - 1)
12
+ throw new Error("invalid paired Qwen MTP checkpoint alignment");
13
+ const held = cloneAttachments([attachment])[0]!.tensors;
14
+ let cache: KVCache | null = new KVCache();
15
+ try {
16
+ if (tokens > 1) { cache.restoreState(held[0]!, held[1]!, tokens - 1); held.splice(0, 2); }
17
+ const state = { cache, hidden: held.pop()! }; cache = null; return state;
18
+ } finally { disposeResources([...held, ...(cache ? [cache] : [])]); }
19
+ }
20
+
21
+ export function captureQwenMtpState(state: MtpRowState): DraftRowCheckpoint {
22
+ const held: MlxArray[] = [];
23
+ try {
24
+ if (state.cache.offset > 0) held.push(...state.cache.temporalView());
25
+ held.push(state.hidden.slice([0, 0, 0], [...state.hidden.shape]));
26
+ return { processedTokens: state.cache.offset + 1,
27
+ attachment: { schema: DRAFT_CHECKPOINT_SCHEMA.qwenMtp, metadata: { draftOffset: state.cache.offset }, tensors: held.splice(0) } };
28
+ } finally { disposeResources(held); }
29
+ }
30
+
31
+ export interface MtpRowState {
32
+ readonly cache: KVCache;
33
+ readonly hidden: MlxArray;
34
+ }
@@ -0,0 +1,113 @@
1
+ import { rotatingSourcePosition } from "./rotating-kv-layout";
2
+ import { MlxArray } from "@mlx-bun/mlx/array";
3
+ import * as ops from "@mlx-bun/mlx/ops";
4
+ import { type AttentionRead, type Cache, type CommittedAttentionCache, type Mask, type PrefillPadding, type SpeculativeRowLayout } from "../contracts/mlx/cache";
5
+ import { RotatingKVCache } from "./rotating-kv";
6
+ import { BatchedRotatingCache } from "./batched-rotating";
7
+ import { rollbackRotatingRing } from "./rotating-row-transaction";
8
+ import { BatchedRotatingState } from "./batched-rotating-state";
9
+ import { plainRowStorage, temporalStorageView } from "./batched-row-storage";
10
+ import { disposeResources } from "../runtime/resources";
11
+ import { AttentionMasks, decodeByPosition } from "./attention-read";
12
+
13
+ /** Ring transactions retain accepted KV columns, including rounds that cross
14
+ * the window boundary. The verify block already retains the complete history
15
+ * needed by its earliest query; no target recomputation or scheduler policy.
16
+ * Reads are the current ring's (`BatchedRotatingCache`); every ring this layout
17
+ * builds shares its `masks`. */
18
+ export class SpeculativeRotatingKVCache implements CommittedAttentionCache, SpeculativeRowLayout {
19
+ #inner: BatchedRotatingCache;
20
+ #before?: number[];
21
+ constructor(
22
+ readonly maxSize: number,
23
+ /** The per-forward masks of the model this layout serves. */
24
+ readonly masks = new AttentionMasks(),
25
+ ) { this.#inner = new BatchedRotatingCache(maxSize, [], masks); }
26
+ signature(): string { return "kv:rotating-plain"; }
27
+ get offset(): number { return this.#inner.offset; }
28
+ get rowOffsets(): readonly number[] { return this.#inner.offsetArr; }
29
+ get leftPad(): readonly number[] { return this.#inner.leftPad; }
30
+ get batchSize(): number { return this.#inner.batchSize; }
31
+ get ropeOffsetArr(): MlxArray { return this.#inner.ropeOffsetArr; }
32
+ makeEmptyBatch(): SpeculativeRotatingKVCache { return new SpeculativeRotatingKVCache(this.maxSize, this.masks); }
33
+ appendDecode(k: MlxArray, v: MlxArray): AttentionRead { return this.#inner.appendDecode(k, v); }
34
+ appendWindow(k: MlxArray, v: MlxArray): AttentionRead { return this.#inner.appendWindow(k, v); }
35
+ /** A committed span, one decode per position (`decodeByPosition`). */
36
+ appendCommitted(k: MlxArray, v: MlxArray): AttentionRead { return decodeByPosition(this, k, v); }
37
+ makeMask(tokens: number, window: number | null): Mask { return this.#inner.makeMask(tokens, window); }
38
+ updateAndFetch(k: MlxArray, v: MlxArray): [MlxArray, MlxArray] { return this.#inner.updateAndFetch(k, v); }
39
+ preparePrefill(padding: PrefillPadding): void { this.#inner.preparePrefill(padding); }
40
+ finalizePrefill(): void { this.#inner.finalizePrefill(); }
41
+ state(): MlxArray[] { return this.#inner.state(); }
42
+ isTrimmable(): boolean { return this.#inner.isTrimmable(); }
43
+ trim(count: number): void { this.#inner.trim(count); }
44
+ bytesPerToken(): number {
45
+ const state = this.state();
46
+ return state.length ? state.reduce((n, a) => n + a.nbytes, 0) / (this.batchSize * state[0]!.shape[2]!) : 0;
47
+ }
48
+ projectedBytes(tokens: number): number { return this.bytesPerToken() * Math.min(tokens, this.maxSize); }
49
+ extractRow(row: number): Cache {
50
+ const result = new RotatingKVCache(this.maxSize);
51
+ if (!this.rowOffsets[row] || !this.#inner.keys || !this.#inner.values) return result;
52
+ const position = new BatchedRotatingState(this.maxSize, []); position.restore(this.#inner.positionSnapshot);
53
+ const range = { row, from: Math.max(0, position.leftPad[row]!, position.activeLength - this.maxSize),
54
+ to: position.activeLength, copy: true };
55
+ const keys = temporalStorageView(plainRowStorage, this.#inner.keys, position, range);
56
+ let values: MlxArray;
57
+ try { values = temporalStorageView(plainRowStorage, this.#inner.values, position, range); }
58
+ catch (error) { keys.dispose(); throw error; }
59
+ result.restoreState(keys, values, this.rowOffsets[row]!, keys.shape[2]!); return result;
60
+ }
61
+ captureDonorRows(): import("../contracts/mlx/cache").KvDonorRows {
62
+ const position = new BatchedRotatingState(this.maxSize, []); position.restore(this.#inner.positionSnapshot);
63
+ const from = Math.max(0, position.activeLength - this.maxSize);
64
+ const range = { from, to: position.activeLength };
65
+ const keys = temporalStorageView(plainRowStorage, this.#inner.keys!, position, range); let values: MlxArray;
66
+ try { values = temporalStorageView(plainRowStorage, this.#inner.values!, position, range); }
67
+ catch (error) { keys.dispose(); throw error; }
68
+ return { keys, values, offsets: [...this.rowOffsets], starts: this.leftPad.map(pad => Math.max(0, pad - from)),
69
+ ends: this.rowOffsets.map(() => position.activeLength - from) };
70
+ }
71
+
72
+ filterRows(keep: readonly number[]): void { this.#inner.filterRows(keep); }
73
+ mergeRows(sources: readonly Cache[]): void {
74
+ const only = sources.length === 1 ? sources[0] : undefined;
75
+ if (only instanceof SpeculativeRotatingKVCache) {
76
+ const keys = only.#inner.keys ? ops.copyOf(only.#inner.keys) : null;
77
+ let values: MlxArray | null;
78
+ try { values = only.#inner.values ? ops.copyOf(only.#inner.values) : null; }
79
+ catch (error) { keys?.dispose(); throw error; }
80
+ const next = BatchedRotatingCache.adoptPhysical(keys, values, only.#inner.positionSnapshot, this.masks);
81
+ this.#inner.dispose(); this.#inner = next; return;
82
+ }
83
+ const held: Cache[] = [], planes: { keys: MlxArray; values: MlxArray }[] = [], offsets: number[] = [];
84
+ try {
85
+ const rows = sources.flatMap(source => source instanceof SpeculativeRotatingKVCache
86
+ ? Array.from({ length: source.batchSize }, (_, row) => { const cache = source.extractRow(row); held.push(cache); return cache; })
87
+ : [source]) as RotatingKVCache[];
88
+ const prototype = rows.find(row => row.keys !== null);
89
+ if (!prototype) {
90
+ this.#inner.dispose(); this.#inner = new BatchedRotatingCache(this.maxSize, rows.map(() => 0), this.masks); return;
91
+ }
92
+ for (const cache of rows) {
93
+ const state = rotatingSourcePosition(cache);
94
+ const range = { from: Math.max(0, state.activeLength - this.maxSize), to: state.activeLength };
95
+ const plane = (field: "keys" | "values") => cache[field]
96
+ ? temporalStorageView(plainRowStorage, cache[field]!, state, range)
97
+ : ops.zeros([1, prototype[field]!.shape[1]!, 0, prototype[field]!.shape[3]!], prototype[field]!.dtype);
98
+ const keys = plane("keys"); let values: MlxArray;
99
+ try { values = plane("values"); } catch (error) { keys.dispose(); throw error; }
100
+ planes.push({ keys, values }); offsets.push(cache.offset);
101
+ }
102
+ const next = BatchedRotatingCache.merge(planes, offsets, this.maxSize, this.masks);
103
+ this.#inner.dispose(); this.#inner = next;
104
+ } finally { disposeResources([...held, ...planes.flatMap(row => [row.keys, row.values])]); }
105
+ }
106
+ specRoundBegin(): void { this.#before = [...this.rowOffsets]; }
107
+ specRoundCommit(): void { this.#before = undefined; }
108
+ specRoundRollback(keep: number | readonly number[]): void {
109
+ this.#inner = rollbackRotatingRing(this.#inner, this.#before!, keep);
110
+ this.#before = undefined;
111
+ }
112
+ dispose(): void { this.#before = undefined; this.#inner.dispose(); }
113
+ }