mlx-bun 0.2.0 → 0.4.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 (433) hide show
  1. package/README.md +71 -588
  2. package/docs/README.md +94 -0
  3. package/docs/{design → archive/investigations}/audio-input-plan.md +4 -4
  4. package/docs/{design → archive/investigations}/diffusion-gemma-port.md +3 -3
  5. package/docs/{design → archive/investigations}/faithful-l1-consolidation.md +4 -4
  6. package/docs/{design → archive/investigations}/minicpm5-decode-megakernel.md +11 -11
  7. package/docs/archive/investigations/openjarvis-fit.md +198 -0
  8. package/docs/{design → archive/investigations}/optimization_plan.md +1 -1
  9. package/docs/{design → archive/investigations}/pre-colibri-stabilization.md +5 -5
  10. package/docs/archive/investigations/qwen38-27b-campaign-log.md +1092 -0
  11. package/docs/{design → archive/investigations}/the-dreaming-handoff.md +2 -2
  12. package/docs/archive/planning/release-notes-v0.3.0.md +35 -0
  13. package/docs/design/batching.md +1841 -0
  14. package/docs/design/decode-speed-program.md +2346 -169
  15. package/docs/design/dreaming-nightly-pipeline.md +675 -282
  16. package/docs/design/generic-model-support.md +655 -334
  17. package/docs/design/kv-cache.md +824 -0
  18. package/docs/design/orpo-training.md +673 -1239
  19. package/docs/design/speculative-decoding.md +1990 -0
  20. package/docs/design/turboquant.md +2212 -0
  21. package/docs/design/unified-engine-frontier-plan.md +1833 -727
  22. package/docs/design/web-chat-redesign.md +666 -1083
  23. package/docs/planning/PRODUCT_ROADMAP.md +50 -1
  24. package/docs/planning/release-notes-v0.4.0.md +45 -0
  25. package/docs/planning/video-series.md +2 -2
  26. package/docs/reference/benchmarks.md +3613 -0
  27. package/docs/reference/cli.md +434 -160
  28. package/docs/reference/distribution.md +328 -182
  29. package/docs/reference/environment.md +398 -0
  30. package/docs/reference/glossary.md +39 -0
  31. package/docs/reference/library-api.md +566 -168
  32. package/docs/reference/memory.md +227 -64
  33. package/docs/reference/models.md +113 -6
  34. package/docs/reference/server-api.md +944 -429
  35. package/docs/reference/server-config.md +740 -338
  36. package/docs/reference/training.md +393 -254
  37. package/docs/reference/troubleshooting.md +158 -0
  38. package/package.json +9 -4
  39. package/src/audio/decode.ts +2 -2
  40. package/src/audio/features.ts +2 -2
  41. package/src/backends/mlx/assistant-target.ts +46 -0
  42. package/src/backends/mlx/autoregressive-draft-rows.ts +120 -0
  43. package/src/backends/mlx/autoregressive.ts +108 -0
  44. package/src/backends/mlx/batch-group.ts +1790 -0
  45. package/src/backends/mlx/cache-attachment.ts +67 -0
  46. package/src/backends/mlx/cache-layout.ts +31 -0
  47. package/src/backends/mlx/checkpoint-state.ts +53 -0
  48. package/src/backends/mlx/continuation-persistence.ts +106 -0
  49. package/src/backends/mlx/continuation-request.ts +43 -0
  50. package/src/backends/mlx/continuation.ts +77 -0
  51. package/src/backends/mlx/diffusion.ts +39 -0
  52. package/src/backends/mlx/draft-target.ts +32 -0
  53. package/src/backends/mlx/evaluation.ts +105 -0
  54. package/src/backends/mlx/fill-append.ts +45 -0
  55. package/src/backends/mlx/full-kv-row-append.ts +32 -0
  56. package/src/backends/mlx/full-kv-row-donor.ts +54 -0
  57. package/src/backends/mlx/full-transitioning-kv-rows.ts +65 -0
  58. package/src/backends/mlx/gateway-binding.ts +130 -0
  59. package/src/backends/mlx/graph.ts +38 -0
  60. package/src/backends/mlx/kv-codec.ts +9 -0
  61. package/src/backends/mlx/kv-maintenance.ts +133 -0
  62. package/src/backends/mlx/kv-tensor-rows.ts +212 -0
  63. package/src/backends/mlx/memory-client.ts +189 -0
  64. package/src/backends/mlx/methods.ts +90 -0
  65. package/src/backends/mlx/model-prompt.ts +164 -0
  66. package/src/backends/mlx/model-serving.ts +79 -0
  67. package/src/backends/mlx/prefill-cohort.ts +89 -0
  68. package/src/backends/mlx/prefill-rows.ts +200 -0
  69. package/src/backends/mlx/prefill.ts +33 -0
  70. package/src/backends/mlx/projected-context-rows.ts +72 -0
  71. package/src/backends/mlx/request-policy.ts +20 -0
  72. package/src/backends/mlx/request-state-policy.ts +41 -0
  73. package/src/backends/mlx/rollback.ts +89 -0
  74. package/src/backends/mlx/row-sampling.ts +49 -0
  75. package/src/backends/mlx/serial-executor.ts +242 -0
  76. package/src/backends/mlx/speculative-group.ts +359 -0
  77. package/src/backends/mlx/speculative-round.ts +161 -0
  78. package/src/backends/mlx/speculative.ts +114 -0
  79. package/src/backends/mlx/state-rows.ts +104 -0
  80. package/src/backends/mlx/state-views.ts +46 -0
  81. package/src/backends/mlx/target-layout-capability.ts +35 -0
  82. package/src/backends/mlx/text-engine.ts +73 -0
  83. package/src/backends/mlx/transitioning-kv-rows.ts +165 -0
  84. package/src/cli.ts +66 -58
  85. package/src/client.ts +66 -0
  86. package/src/config.ts +21 -4
  87. package/src/contracts/completion.ts +16 -0
  88. package/src/contracts/execution.ts +60 -0
  89. package/src/contracts/generation.ts +103 -0
  90. package/src/contracts/host.ts +7 -0
  91. package/src/contracts/jobs.ts +66 -0
  92. package/src/contracts/pi-provider.ts +30 -0
  93. package/src/contracts/pi.ts +259 -0
  94. package/src/contracts/prefix-cache.ts +23 -0
  95. package/src/contracts/resources.ts +25 -0
  96. package/src/contracts/sampling.ts +23 -0
  97. package/src/contracts/scheduling.ts +45 -0
  98. package/src/contracts/tsconfig.json +14 -0
  99. package/src/diffusion/diffusion-generate.ts +218 -153
  100. package/src/embed.ts +1 -1
  101. package/src/engine/admission.ts +59 -0
  102. package/src/engine/cancellation.ts +38 -0
  103. package/src/engine/engine.ts +56 -0
  104. package/src/engine/execution-coordinator.ts +70 -0
  105. package/src/engine/execution-plan.ts +53 -0
  106. package/src/engine/resources.ts +53 -0
  107. package/src/engine/scheduler.ts +72 -0
  108. package/src/engine/session.ts +247 -0
  109. package/src/eval/README.md +44 -1
  110. package/src/eval/kl.ts +236 -3
  111. package/src/eval/reference-logits.ts +207 -0
  112. package/src/eval/runner.ts +8 -96
  113. package/src/fill/echo-index.ts +188 -0
  114. package/src/fill/fill-session.ts +452 -0
  115. package/src/fill/proposal.ts +68 -0
  116. package/src/fill/schema-rows.ts +506 -0
  117. package/src/fill/tool-boundary.ts +103 -0
  118. package/src/fit.ts +30 -16
  119. package/src/generate.ts +709 -417
  120. package/src/grammar.ts +12 -7
  121. package/src/harness-pi.ts +14 -33
  122. package/src/hub-rest.ts +4 -4
  123. package/src/index.ts +7 -0
  124. package/src/inference/denoising.ts +17 -0
  125. package/src/inference/draft-acceptance.ts +41 -0
  126. package/src/inference/draft-output.ts +49 -0
  127. package/src/inference/graph.ts +33 -0
  128. package/src/inference/prefill.ts +39 -0
  129. package/src/inference/rollback.ts +7 -0
  130. package/src/jobs/db.ts +4 -0
  131. package/src/jobs/index.ts +2 -0
  132. package/src/jobs/job-entry.ts +12 -12
  133. package/src/jobs/runner.ts +98 -13
  134. package/src/jobs/task-client.ts +19 -0
  135. package/src/jobs/types.ts +2 -58
  136. package/src/kv-scheme.ts +70 -12
  137. package/src/kv-store.ts +177 -63
  138. package/src/lab/README.md +18 -0
  139. package/src/{assets → lab/curve}/curve-designer.html +2 -2
  140. package/src/{curve-sampler.ts → lab/curve/curve-sampler.ts} +2 -2
  141. package/src/{expert-trace.ts → lab/expert-trace/expert-trace.ts} +5 -5
  142. package/src/lab/paged-kv/paged-kv-rows.ts +83 -0
  143. package/src/{model → lab/paged-kv}/paged-kv.ts +32 -15
  144. package/src/library.ts +40 -0
  145. package/src/lora.ts +18 -0
  146. package/src/media-fetch.ts +1 -1
  147. package/src/memory/article.ts +1 -1
  148. package/src/memory/chunk.ts +1 -1
  149. package/src/memory/model.ts +30 -169
  150. package/src/memory/prompts.ts +1 -1
  151. package/src/memory/rest.ts +1 -1
  152. package/src/memory/schedule.ts +1 -1
  153. package/src/memory/stages.ts +4 -1
  154. package/src/memory/vault.ts +1 -3
  155. package/src/mlx/array.ts +11 -11
  156. package/src/mlx/compile.ts +12 -2
  157. package/src/mlx/ffi.ts +58 -11
  158. package/src/mlx/materialize.ts +23 -0
  159. package/src/mlx/metal-kernel.ts +10 -11
  160. package/src/mlx/ops.ts +33 -13
  161. package/src/mlx/quantized-rows.ts +36 -0
  162. package/src/mlx/token-bitmask.ts +52 -0
  163. package/src/mlx/turboquant-kv-decode.ts +82 -0
  164. package/src/mlx/turboquant-kv-inverse.ts +122 -0
  165. package/src/mlx/turboquant-ops.ts +33 -3
  166. package/src/mlx/turboquant-tables.ts +2 -2
  167. package/src/model/artifact-identity.ts +73 -0
  168. package/src/model/batched-kv.ts +235 -0
  169. package/src/model/batched-mask.ts +20 -6
  170. package/src/model/batched-quant.ts +9 -3
  171. package/src/model/batched-quantized-kv.ts +144 -0
  172. package/src/model/batched-rotating-quant.ts +78 -17
  173. package/src/model/batched-rotating-state.ts +76 -0
  174. package/src/model/batched-rotating.ts +65 -23
  175. package/src/model/batched-row-storage.ts +52 -0
  176. package/src/model/batched-ssm.ts +52 -0
  177. package/src/model/batched-turboquant-kv.ts +93 -0
  178. package/src/model/compiled-decode.ts +8 -2
  179. package/src/model/decoded-kv-donor.ts +12 -0
  180. package/src/model/delayed-quantized-kv.ts +72 -0
  181. package/src/model/delayed-rotating-quantized-kv.ts +93 -0
  182. package/src/model/delayed-turboquant-kv.ts +55 -0
  183. package/src/model/diffusion-gemma.ts +8 -8
  184. package/src/model/factory.ts +76 -33
  185. package/src/model/fingerprint.ts +1 -1
  186. package/src/model/flash-attention.ts +3 -3
  187. package/src/model/full-prefill-padding.ts +56 -0
  188. package/src/model/full-prefill-row.ts +105 -0
  189. package/src/model/gemma4-base.ts +179 -80
  190. package/src/model/gemma4.ts +40 -32
  191. package/src/model/generated/gemma4-12b.ts +6 -3
  192. package/src/model/generated/gemma4-26b.ts +6 -3
  193. package/src/model/generated/gemma4-e4b.ts +6 -3
  194. package/src/model/glm52-cache.ts +80 -4
  195. package/src/model/glm52-dsa.ts +13 -9
  196. package/src/model/glm52-memory.ts +1 -1
  197. package/src/model/glm52-mla.ts +12 -6
  198. package/src/model/glm52.ts +19 -40
  199. package/src/model/implementation.ts +69 -0
  200. package/src/model/kv-attention-view.ts +67 -0
  201. package/src/model/minicpm5.ts +17 -15
  202. package/src/model/profile.ts +12 -2
  203. package/src/model/qwen-append.ts +12 -0
  204. package/src/model/qwen-conv.ts +52 -0
  205. package/src/model/qwen3-delta-state.ts +74 -0
  206. package/src/model/qwen3-delta.ts +59 -36
  207. package/src/model/qwen3_5-checkpoint.ts +164 -0
  208. package/src/model/qwen3_5.ts +202 -78
  209. package/src/model/rotating-kv-donor.ts +35 -0
  210. package/src/model/rotating-kv-layout.ts +262 -0
  211. package/src/model/rotating-row-transaction.ts +35 -0
  212. package/src/model/speculative-rotating-kv.ts +101 -0
  213. package/src/model/ssm-prefill-padding.ts +39 -0
  214. package/src/model/support.ts +1 -1
  215. package/src/model/trellis-balanced-scatter.ts +51 -0
  216. package/src/model/trellis-linear.ts +672 -0
  217. package/src/model/trellis-shared-m.ts +151 -0
  218. package/src/model/trellis-shared-scatter.ts +144 -0
  219. package/src/model/trellis-splitk-prefill.ts +158 -0
  220. package/src/model/trellis-tiled-prefill.ts +136 -0
  221. package/src/model/trellis-vector-expand.ts +62 -0
  222. package/src/model/trellis-wide-prefill.ts +94 -0
  223. package/src/model/turboquant-codec.ts +83 -0
  224. package/src/model/universal/dense.ts +15 -14
  225. package/src/model/universal/modules.ts +8 -1
  226. package/src/native-pack.ts +6 -5
  227. package/src/pi-provider.ts +6 -64
  228. package/src/pi-web.ts +8 -315
  229. package/src/preflight.ts +31 -15
  230. package/src/prompt-cache.ts +110 -69
  231. package/src/quantize/allocator.ts +1 -1
  232. package/src/quantize/config-writer.ts +10 -3
  233. package/src/quantize/rotate.ts +4 -4
  234. package/src/quantize/trellis.ts +586 -0
  235. package/src/responses.ts +28 -1
  236. package/src/runtime-config.ts +18 -4
  237. package/src/sampler.ts +40 -29
  238. package/src/serve/batch-scheduler.ts +8 -1671
  239. package/src/serve/chat-request.ts +391 -0
  240. package/src/serve/chat-stage.ts +195 -0
  241. package/src/serve/checkpoint-identity.ts +64 -0
  242. package/src/serve/completion-executor.ts +15 -7
  243. package/src/serve/discovery-routes.ts +12 -13
  244. package/src/serve/generation-gateway.ts +183 -213
  245. package/src/serve/http.ts +159 -0
  246. package/src/serve/inference-request.ts +79 -0
  247. package/src/serve/isolate.ts +297 -105
  248. package/src/serve/lab-routes.ts +3 -0
  249. package/src/serve/lane-registry.ts +2 -1
  250. package/src/serve/model-admin-routes.ts +7 -5
  251. package/src/serve/model-binding.ts +43 -0
  252. package/src/serve/model-host.ts +511 -0
  253. package/src/serve/openai-wire.ts +103 -0
  254. package/src/serve/parent-application.ts +56 -0
  255. package/src/serve/pipeline.ts +33 -0
  256. package/src/serve/preparation.ts +33 -0
  257. package/src/serve/request-plan.ts +23 -18
  258. package/src/serve/request-prep.ts +344 -0
  259. package/src/serve/response-lease.ts +24 -0
  260. package/src/serve/responses-client.ts +69 -0
  261. package/src/serve/session-completion-engine.ts +110 -0
  262. package/src/serve/session-search.ts +1 -1
  263. package/src/serve/static-routes.ts +5 -5
  264. package/src/serve/text-completion-stage.ts +104 -0
  265. package/src/serve/token-streams.ts +519 -0
  266. package/src/server.ts +335 -2711
  267. package/src/spec/assistant-rows.ts +92 -0
  268. package/src/spec/assistant-source.ts +31 -55
  269. package/src/spec/cache-identity.ts +22 -0
  270. package/src/spec/deepspec-rows.ts +29 -0
  271. package/src/spec/deepspec-source.ts +16 -14
  272. package/src/spec/dflash-source.ts +36 -12
  273. package/src/spec/drafter.ts +153 -142
  274. package/src/spec/dspark/ab-stats.ts +3 -3
  275. package/src/spec/dspark/calibration.ts +2 -2
  276. package/src/spec/dspark/deepspec-module.ts +97 -122
  277. package/src/spec/dspark/generate-dflash.ts +2 -2
  278. package/src/spec/dspark/generate.ts +2 -2
  279. package/src/spec/dspark/loader.ts +1 -1
  280. package/src/spec/dspark/module-dflash.ts +129 -172
  281. package/src/spec/dspark/module.ts +3 -3
  282. package/src/spec/dspark/quantize-drafter.ts +1 -1
  283. package/src/spec/generate.ts +1 -1
  284. package/src/spec/glm52-mtp-graph.ts +29 -0
  285. package/src/spec/glm52-mtp-rows.ts +132 -0
  286. package/src/spec/glm52-mtp-source.ts +54 -137
  287. package/src/spec/glm52-mtp-state.ts +33 -0
  288. package/src/spec/ngram-source.ts +93 -21
  289. package/src/spec/projected-draft-rows.ts +73 -0
  290. package/src/spec/qwen-mtp-module.ts +171 -0
  291. package/src/spec/qwen-mtp-rows.ts +219 -0
  292. package/src/spec/qwen-mtp-source.ts +147 -195
  293. package/src/spec/qwen-mtp-state.ts +30 -0
  294. package/src/spec/serve-loop.ts +201 -201
  295. package/src/spec/source.ts +110 -13
  296. package/src/spec/two-model-rows.ts +61 -0
  297. package/src/spec/two-model.ts +44 -102
  298. package/src/ssd-cache.ts +99 -19
  299. package/src/ssd-durability.ts +36 -20
  300. package/src/tool-call.ts +51 -14
  301. package/src/train/flash-cce.ts +2 -2
  302. package/src/train/forward.ts +6 -0
  303. package/src/train/loss.ts +1 -1
  304. package/src/train/prefix-shared.ts +5 -1
  305. package/src/train/segmented.ts +5 -3
  306. package/src/train/trainer.ts +6 -6
  307. package/src/vision/prompt.ts +1 -1
  308. package/src/vision/qwen3vl-tower.ts +52 -10
  309. package/src/web/app.html +1 -1
  310. package/src/web/app.js +62 -60
  311. package/src/web/src/adapters-panel.ts +3 -3
  312. package/src/web/src/assistant.ts +2 -36
  313. package/src/web/src/chat.ts +4 -4
  314. package/src/web/src/composer.ts +4 -4
  315. package/src/web/src/hub.ts +1 -1
  316. package/src/web/src/markdown.ts +0 -0
  317. package/src/web/src/memory-panel.ts +1 -1
  318. package/src/web/src/model-picker.ts +1 -1
  319. package/src/web/src/palette.ts +1 -1
  320. package/src/web/src/protocol.ts +3 -39
  321. package/src/web/src/sessions.ts +1 -1
  322. package/src/web/src/ui-catalog.ts +4 -18
  323. package/src/web-assets.ts +47 -0
  324. package/src/weights.ts +55 -9
  325. package/docs/archive/investigations/curve-runs/bisector-route.json +0 -98
  326. package/docs/archive/investigations/curve-runs/bisector-trace.json +0 -1393
  327. package/docs/archive/investigations/curve-runs/curve-terrain.json +0 -1179
  328. package/docs/archive/investigations/curve-runs/curve-terrain.svg +0 -42
  329. package/docs/archive/investigations/hlg-ab.html +0 -34
  330. package/docs/archive/investigations/hlg-explorer.html +0 -238
  331. package/docs/archive/investigations/hlg-figs/cliff.svg +0 -1
  332. package/docs/archive/investigations/hlg-figs/cross.svg +0 -1
  333. package/docs/archive/investigations/hlg-figs/edges.svg +0 -1
  334. package/docs/archive/investigations/hlg-figs/k20-grids.svg +0 -1
  335. package/docs/archive/investigations/hlg-figs/k20-peaks.svg +0 -1
  336. package/docs/archive/investigations/hlg-figs/lw-curve.svg +0 -1
  337. package/docs/archive/investigations/hlg-figs/terrain.svg +0 -1
  338. package/docs/archive/investigations/hlg-report.html +0 -262
  339. package/docs/archive/investigations/hlg-runs/hlg-ab.json +0 -149
  340. package/docs/archive/investigations/hlg-runs/hlg-blind-prompts.md +0 -87
  341. package/docs/archive/investigations/hlg-runs/hlg-blind.json +0 -107
  342. package/docs/archive/investigations/hlg-runs/hlg-cliff.json +0 -197
  343. package/docs/archive/investigations/hlg-runs/hlg-cross.json +0 -505
  344. package/docs/archive/investigations/hlg-runs/hlg-edge.json +0 -388
  345. package/docs/archive/investigations/hlg-runs/hlg-eval1.json +0 -25
  346. package/docs/archive/investigations/hlg-runs/hlg-frontier.json +0 -86
  347. package/docs/archive/investigations/hlg-runs/hlg-grid.json +0 -242
  348. package/docs/archive/investigations/hlg-runs/hlg-grid2.json +0 -343
  349. package/docs/archive/investigations/hlg-runs/hlg-lw-coarse.json +0 -110
  350. package/docs/archive/investigations/hlg-runs/hlg-map.json +0 -383
  351. package/docs/archive/investigations/hlg-runs/run0-original.log +0 -159
  352. package/docs/archive/investigations/hlg-runs/runA-recommended.log +0 -131
  353. package/docs/archive/investigations/hlg-runs/runAA-cliff-cpm5.log +0 -26
  354. package/docs/archive/investigations/hlg-runs/runAB-grid2-e4b.log +0 -18
  355. package/docs/archive/investigations/hlg-runs/runAC-peak-e4b-partial.log +0 -25
  356. package/docs/archive/investigations/hlg-runs/runAD-ab-samples.log +0 -8
  357. package/docs/archive/investigations/hlg-runs/runAE-edge-e4b.log +0 -51
  358. package/docs/archive/investigations/hlg-runs/runAF-logit-calibration.log +0 -10
  359. package/docs/archive/investigations/hlg-runs/runAG-eval-config2.log +0 -16
  360. package/docs/archive/investigations/hlg-runs/runB-gain-variants.log +0 -192
  361. package/docs/archive/investigations/hlg-runs/runC-pivots.log +0 -162
  362. package/docs/archive/investigations/hlg-runs/runD-oetf.log +0 -132
  363. package/docs/archive/investigations/hlg-runs/runE-eotf.log +0 -162
  364. package/docs/archive/investigations/hlg-runs/runF-shaper-working.log +0 -86
  365. package/docs/archive/investigations/hlg-runs/runG-shaper-sweep.log +0 -101
  366. package/docs/archive/investigations/hlg-runs/runH-wsweep.log +0 -176
  367. package/docs/archive/investigations/hlg-runs/runI-asweep.log +0 -176
  368. package/docs/archive/investigations/hlg-runs/runJ-knobmap.log +0 -49
  369. package/docs/archive/investigations/hlg-runs/runK-frontier.log +0 -19
  370. package/docs/archive/investigations/hlg-runs/runL-widemap.log +0 -65
  371. package/docs/archive/investigations/hlg-runs/runM-frontier-emb.log +0 -15
  372. package/docs/archive/investigations/hlg-runs/runN-verify.log +0 -116
  373. package/docs/archive/investigations/hlg-runs/runO-frontier-seed5000.log +0 -15
  374. package/docs/archive/investigations/hlg-runs/runP-grid-AxSm.log +0 -15
  375. package/docs/archive/investigations/hlg-runs/runQ-grid-tgW.log +0 -15
  376. package/docs/archive/investigations/hlg-runs/runR-blind-transcript.log +0 -79
  377. package/docs/archive/investigations/hlg-runs/runS-cross-coherence.log +0 -33
  378. package/docs/archive/investigations/hlg-runs/runT-cross-cpm5.log +0 -33
  379. package/docs/archive/investigations/hlg-runs/runU-cross-12b.log +0 -33
  380. package/docs/archive/investigations/hlg-runs/runV-lw-e4b.log +0 -22
  381. package/docs/archive/investigations/hlg-runs/runW-lw-12b.log +0 -22
  382. package/docs/archive/investigations/hlg-runs/runX-lw-cpm5.log +0 -22
  383. package/docs/archive/investigations/hlg-runs/runY-cliff-e4b.log +0 -26
  384. package/docs/archive/investigations/hlg-runs/runZ-cliff-12b.log +0 -26
  385. package/docs/archive/mlx-bun-lab-report.html +0 -275
  386. package/docs/archive/wwdc-mlx-bun.html +0 -848
  387. package/docs/design/adapters-end-to-end.md +0 -205
  388. package/docs/design/batching-perf-path.md +0 -255
  389. package/docs/design/batching-v2-plan.md +0 -529
  390. package/docs/design/bucketing-stage.md +0 -197
  391. package/docs/design/compat-cli-surface-design.md +0 -230
  392. package/docs/design/docs-reorg-plan.md +0 -165
  393. package/docs/design/dspark-serving-program.md +0 -371
  394. package/docs/design/dspark-speculative-decoding.md +0 -318
  395. package/docs/design/grammar-spec-batching-integration.md +0 -301
  396. package/docs/design/memory-inference-path.md +0 -422
  397. package/docs/design/memory-synthesis.md +0 -287
  398. package/docs/design/memory-system.md +0 -237
  399. package/docs/design/mlx-lm-serving-execution-seam.md +0 -81
  400. package/docs/design/mlx-lm-tool-parity-plan.md +0 -545
  401. package/docs/design/omlx-adoption-map.md +0 -98
  402. package/docs/design/orpo-dynamic-lambda.md +0 -220
  403. package/docs/design/orpo-future-enhancements.md +0 -340
  404. package/docs/design/paged-kv-cache.md +0 -214
  405. package/docs/design/parallel-slots.md +0 -567
  406. package/docs/design/parity-tier-dag.md +0 -161
  407. package/docs/design/repo-cleanup-plan.md +0 -231
  408. package/docs/design/runtime-isolation.md +0 -263
  409. package/docs/design/segmented-backward-training.md +0 -543
  410. package/docs/design/spec-decode-larger-targets.md +0 -229
  411. package/docs/design/ssd-kv-cold-tier.md +0 -415
  412. package/docs/design/structured-output.md +0 -484
  413. package/docs/design/tauri-desktop-app.md +0 -127
  414. package/docs/design/the-dreaming-master-plan.md +0 -445
  415. package/docs/design/turboquant-kv.md +0 -235
  416. package/docs/design/turboquant-weights.md +0 -467
  417. package/docs/design/w4a16-compute-precision-spike.md +0 -232
  418. package/docs/design/web-chat-beat-matrix.md +0 -315
  419. package/docs/design/write-pipeline-entity.md +0 -468
  420. package/docs/planning/IDEAS.md +0 -69
  421. package/docs/reference/embedding.md +0 -197
  422. package/docs/reference/features-matrix.md +0 -101
  423. package/docs/reference/orpo-quickstart.md +0 -135
  424. package/src/flags.ts +0 -11
  425. /package/docs/{design → archive/investigations}/colibri-glm52-port.md +0 -0
  426. /package/docs/{planning → archive/planning}/chunk-task-roadmap.md +0 -0
  427. /package/docs/{planning → archive/planning}/curve-sampler-research-plan.md +0 -0
  428. /package/docs/{planning → archive/planning}/memory-docs-and-dag-plan.md +0 -0
  429. /package/docs/{planning → archive/planning}/pi-integration-review.md +0 -0
  430. /package/docs/{planning → archive/planning}/release-notes-v0.2.0.md +0 -0
  431. /package/src/{memory-plan.ts → admission-plan.ts} +0 -0
  432. /package/{docs/archive/investigations → src/serve/assets}/curve-terrain.html +0 -0
  433. /package/{docs/dag → src/serve/assets}/training-inference-map.html +0 -0
@@ -0,0 +1,200 @@
1
+ import type { BatchableCache, Cache } from "../../model/gemma4-base";
2
+ import type { MlxArray } from "../../mlx/array";
3
+ import * as ops from "../../mlx/ops";
4
+ import { clearCache } from "../../mlx/ffi";
5
+ import type { PrefillStep } from "../../inference/prefill";
6
+ import { cloneKvCaches, type CacheCodecProvider } from "../../kv-store";
7
+ import { disposeResources, cleanupFailure } from "../../engine/resources";
8
+ import type { MlxGroupPreparation, Row } from "./batch-group";
9
+ import { evalCacheState } from "./prefill";
10
+ import { prefillCacheLayout } from "./cache-layout";
11
+ import { MlxStateRows } from "./state-rows";
12
+ import type { KvMaintenance } from "./kv-maintenance";
13
+
14
+ export interface MlxPrefillStep extends PrefillStep {
15
+ /** Some methods maintain their final target chunk before sampling. */
16
+ readonly maintain?: boolean;
17
+ }
18
+
19
+ export interface MlxPrefillState {
20
+ row: Row;
21
+ solo: Cache[];
22
+ pos: number;
23
+ retain?: () => void;
24
+ planned?: MlxPrefillStep;
25
+ }
26
+
27
+ /** The method owns initialization, planning, companion state, snapshots and
28
+ * completion. This driver owns common target batching and work boundaries.
29
+ * Checkpoint factories return owned cache state; close/dispose are idempotent. */
30
+ export interface MlxPrefillRowsHost<State extends MlxPrefillState> {
31
+ stateCodecs?: CacheCodecProvider;
32
+ maintain?: KvMaintenance;
33
+ open(row: Row): State;
34
+ plan(state: State): MlxPrefillStep;
35
+ /** Already prepared state can complete without any target forward. */
36
+ ready?(state: State): boolean;
37
+ forward(ids: MlxArray, caches: Cache[], states: readonly State[]): Promise<MlxArray>;
38
+ project(hidden: MlxArray, caches: Cache[], completed: readonly State[]): MlxArray | null;
39
+ /** Consume method context after target maintenance, before snapshots. */
40
+ afterForward?(ids: MlxArray, caches: Cache[], states: readonly State[], hidden: MlxArray): void | Promise<void>;
41
+ checkpoint(state: State, capture: () => Cache[], row: number): void;
42
+ complete(state: State, logits: MlxArray | null, row: number): Promise<void>;
43
+ reject(row: Row, error: unknown): void;
44
+ close(state: State): void;
45
+ filterRows?(keep: readonly number[]): void;
46
+ dispose?(): void;
47
+ }
48
+
49
+ /** One target preparation lifecycle at B1/B>1. Late joins retain each row's
50
+ * planned chunk endpoint, precision transition and checkpoint boundary. */
51
+ export class MlxPrefillRows<State extends MlxPrefillState> implements MlxGroupPreparation {
52
+ #states: State[] = [];
53
+ #rows: Row[] = [];
54
+ #stateRows?: MlxStateRows;
55
+ constructor(readonly operations: MlxPrefillRowsHost<State>) {}
56
+ get rows(): readonly Row[] { return this.#rows; }
57
+ get canAdmit(): boolean { return this.#rows.length > 0; }
58
+ /** Keep a request's prefill weight until retirement so a nearly completed
59
+ * request does not repeatedly attract another long prefill into its tail. */
60
+ get tokenWeight(): number { return this.#states.reduce((sum, state) => sum + state.row.promptTokens - state.row.cachedTokens, 0); }
61
+
62
+ admit(row: Row): void {
63
+ this.#states.push(this.operations.open(row));
64
+ this.#rows.push(row);
65
+ }
66
+
67
+ #release(state: State): void {
68
+ const caches = state.solo; state.solo = [];
69
+ const retain = state.retain; state.retain = undefined;
70
+ disposeResources([...caches, { dispose: () => retain?.() }, { dispose: () => this.operations.close(state) }]);
71
+ }
72
+ #filter(keep: number[]): void {
73
+ if (keep.length) this.#stateRows?.filterRows(keep);
74
+ else { const rows = this.#stateRows; this.#stateRows = undefined; rows?.dispose(); }
75
+ this.operations.filterRows?.(keep);
76
+ this.#states = keep.map(row => this.#states[row]!);
77
+ this.#rows = keep.map(row => this.#rows[row]!);
78
+ }
79
+ /** Admission changes membership only between forwards. Existing planned
80
+ * endpoints survive a join, including partially consumed drain chunks. */
81
+ #synchronizeRows(): void {
82
+ if (!this.#stateRows && this.#states.length === 1) return;
83
+ if (!this.#stateRows) {
84
+ for (const state of this.#states) this.operations.maintain?.preparePrefill?.(state.solo);
85
+ const layouts: BatchableCache[] = [];
86
+ try { for (const cache of this.#states[0]!.solo) layouts.push(prefillCacheLayout(cache)); }
87
+ catch (error) { return cleanupFailure(error, () => disposeResources(layouts)); }
88
+ this.#stateRows = new MlxStateRows(layouts);
89
+ this.#stateRows.mergeRows(this.#states.map(state => state.solo));
90
+ } else {
91
+ for (const state of this.#states.slice(this.#stateRows.rowCount)) {
92
+ this.operations.maintain?.preparePrefill?.(state.solo);
93
+ this.#stateRows.append(state.solo);
94
+ }
95
+ }
96
+ // Resolve input-backed copies before releasing SSD restore leases.
97
+ if (this.#states.some(state => state.solo.length)) {
98
+ evalCacheState(this.#stateRows.caches);
99
+ for (const state of this.#states) {
100
+ const caches = state.solo; state.solo = [];
101
+ const retain = state.retain; state.retain = undefined;
102
+ disposeResources([...caches, { dispose: () => retain?.() }]);
103
+ }
104
+ }
105
+ for (const cache of this.#stateRows.caches) cache.prefillMaintenance?.beginPrefill();
106
+ }
107
+
108
+ async advance(): Promise<boolean> {
109
+ // Complete restored inputs before merging: their cache coverage must not
110
+ // introduce padding or a zero-width forward into unrelated cold rows.
111
+ if (this.operations.ready && this.#states.some(state => this.operations.ready!(state))) {
112
+ const remaining: State[] = [];
113
+ for (const state of this.#states) {
114
+ if (!this.operations.ready(state)) { remaining.push(state); continue; }
115
+ try {
116
+ state.row.req.signal?.throwIfAborted();
117
+ await this.operations.complete(state, null, -1);
118
+ state.solo = []; state.retain = undefined;
119
+ } catch (error) { this.operations.reject(state.row, error); this.#release(state); }
120
+ finally { this.operations.close(state); }
121
+ }
122
+ this.#states = remaining; this.#rows = remaining.map(state => state.row);
123
+ if (!remaining.length) { this.dispose(); return true; }
124
+ }
125
+ this.#synchronizeRows();
126
+ const keep: number[] = [];
127
+ for (const [index, state] of this.#states.entries()) {
128
+ if (!state.row.req.signal?.aborted) { keep.push(index); continue; }
129
+ this.#release(state); this.operations.reject(state.row, state.row.req.signal.reason);
130
+ }
131
+ if (keep.length !== this.#states.length) this.#filter(keep);
132
+ if (!this.#states.length) { this.dispose(); return true; }
133
+ while (this.#states.length) {
134
+ for (const state of this.#states) state.planned ??= this.operations.plan(state);
135
+ const count = Math.min(...this.#states.map(state => state.planned!.end - state.pos));
136
+ const closes = this.#states.map(state => state.row.req.trace?.begin("prefill.chunk", {
137
+ mechanism: "continuous", startToken: state.pos, batchSize: this.#states.length,
138
+ }));
139
+ const caches = this.#stateRows?.caches ?? this.#states[0]!.solo;
140
+ try {
141
+ using ids = count ? ops.fromInt32(this.#states.flatMap(state => state.row.req.promptIds.slice(state.pos, state.pos + count)),
142
+ [this.#states.length, count]) : null;
143
+ using hidden = ids ? await this.operations.forward(ids, caches, this.#states) : null;
144
+ const drains: number[] = [], finals: number[] = [];
145
+ let batchYield = false;
146
+ for (const [row, state] of this.#states.entries()) {
147
+ state.pos += count;
148
+ if (state.pos !== state.planned!.end) continue;
149
+ if (state.planned!.kind === "final") finals.push(row);
150
+ else drains.push(row);
151
+ batchYield ||= state.planned!.batchYield;
152
+ }
153
+ const maintained = [...drains, ...finals.filter(row => this.#states[row]!.planned!.maintain)];
154
+ if (count && (maintained.length || !finals.length)) {
155
+ evalCacheState(caches);
156
+ if (this.#stateRows) {
157
+ for (const cache of caches) cache.prefillMaintenance?.commitPrefill(maintained);
158
+ } else if (maintained.length) this.operations.maintain?.(this.#states[0]!.solo);
159
+ clearCache();
160
+ }
161
+ if (ids) {
162
+ const companion = this.operations.afterForward?.(ids, caches, this.#states, hidden!);
163
+ if (companion) await companion;
164
+ }
165
+ for (const row of [...drains, ...finals]) {
166
+ const state = this.#states[row]!;
167
+ if (state.planned!.snapshot) this.operations.checkpoint(state, () =>
168
+ this.#stateRows ? this.#stateRows.extractRow(row) : cloneKvCaches(state.solo, this.operations.stateCodecs), row);
169
+ if (!finals.includes(row)) state.planned = undefined;
170
+ }
171
+ using logits = hidden && finals.length ? this.operations.project(hidden, caches, finals.map(row => this.#states[row]!)) : null;
172
+ for (const row of finals) {
173
+ const state = this.#states[row]!;
174
+ if (this.#stateRows) state.solo = this.#stateRows.extractRow(row);
175
+ using part = logits ? logits.slice([row, logits.shape[1]! - 1, 0], [row + 1, logits.shape[1]!, logits.shape[2]!]) : null;
176
+ try {
177
+ state.row.req.signal?.throwIfAborted();
178
+ await this.operations.complete(state, part, row);
179
+ state.solo = []; state.retain = undefined;
180
+ } catch (error) {
181
+ this.operations.reject(state.row, error);
182
+ this.#release(state);
183
+ } finally { this.operations.close(state); }
184
+ }
185
+ for (const cache of caches) (cache as { releaseRopeArr?: () => void }).releaseRopeArr?.();
186
+ if (finals.length) this.#filter(this.#states.flatMap((_, row) => finals.includes(row) ? [] : [row]));
187
+ if (!this.#states.length) { this.dispose(); return true; }
188
+ if (batchYield || finals.length) return false;
189
+ } finally { for (const close of closes) close?.(); }
190
+ }
191
+ return true;
192
+ }
193
+
194
+ dispose(): void {
195
+ const states = this.#states; this.#states = []; this.#rows = [];
196
+ const rows = this.#stateRows; this.#stateRows = undefined;
197
+ disposeResources([...(rows ? [rows] : []), ...states.map(state => ({ dispose: () => this.#release(state) })),
198
+ { dispose: () => this.operations.dispose?.() }]);
199
+ }
200
+ }
@@ -0,0 +1,33 @@
1
+ import type { PrefillStep } from "../../inference/prefill";
2
+ import type { MlxArray } from "../../mlx/array";
3
+ import type { Cache } from "../../model/gemma4";
4
+ import * as ops from "../../mlx/ops";
5
+ import { clearCache } from "../../mlx/ffi";
6
+ import { leaseCacheStates } from "./state-views";
7
+ import { withResource } from "../../engine/resources";
8
+
9
+ /** State views with explicit ownership are released even on deferred errors.
10
+ * Owned views precede borrowed state, preserving the serial eval ordering. */
11
+ export function evalCacheState(cache: Cache[]): void {
12
+ withResource(leaseCacheStates(cache), (state) => { if (state.length) ops.evalAll([...state]); });
13
+ }
14
+
15
+ /** Forward once. Drains evaluate state, apply KV maintenance, then clear the
16
+ * allocator cache. Finals return owned hidden state without forcing eval. */
17
+ export async function executeMlxPrefillStep(
18
+ forward: (ids: MlxArray, cache: Cache[]) => MlxArray | Promise<MlxArray>,
19
+ cache: Cache[], prompt: readonly number[], step: PrefillStep,
20
+ maintain: () => void,
21
+ ): Promise<MlxArray | null> {
22
+ const chunk = prompt.slice(step.start, step.end);
23
+ const ids = ops.fromInt32(chunk, [1, chunk.length]);
24
+ let hidden: MlxArray;
25
+ try { hidden = await forward(ids, cache); }
26
+ finally { ids.dispose(); }
27
+ if (step.kind === "final") return hidden;
28
+ hidden.dispose();
29
+ evalCacheState(cache);
30
+ maintain();
31
+ clearCache();
32
+ return null;
33
+ }
@@ -0,0 +1,72 @@
1
+ import type { MlxArray } from "../../mlx/array";
2
+ import { Dtype } from "../../mlx/ffi";
3
+ import * as ops from "../../mlx/ops";
4
+ import { BatchedKVCache } from "../../model/batched-kv";
5
+ import type { Cache } from "../../model/gemma4-base";
6
+ import { MlxStateRows } from "./state-rows";
7
+ import { disposeResources } from "../../engine/resources";
8
+
9
+ export interface ProjectedContext { k: MlxArray; v: MlxArray; }
10
+ export interface ContextProjection {
11
+ project(hidden: MlxArray, positions: number | MlxArray): ProjectedContext[];
12
+ }
13
+
14
+ /** Incremental projected context reuses ordinary full-attention row storage.
15
+ * The projection graph owns numerics; this object owns positions and validity. */
16
+ export class MlxProjectedContextRows {
17
+ readonly state: MlxStateRows<BatchedKVCache>;
18
+ constructor(layers: number, readonly graph: ContextProjection) {
19
+ this.state = new MlxStateRows(Array.from({ length: layers }, () => new BatchedKVCache()));
20
+ }
21
+ get positions(): readonly number[] { return this.state.caches[0]!.rowOffsets; }
22
+ prepareAppend(rows: readonly (readonly Cache[])[]) { return this.state.prepareAppendMany(rows); }
23
+ append(hidden: MlxArray, lengths: readonly number[]): void {
24
+ const width = Math.max(...lengths), B = lengths.length, positions = this.positions;
25
+ using context = hidden.slice([0, 0, 0], [B, width, hidden.shape[2]!]);
26
+ using offsets = positions.every(position => position === positions[0]) ? null : ops.fromInt32([...positions], [B]);
27
+ const projected = this.graph.project(context, offsets ?? positions[0]!);
28
+ try {
29
+ for (const [layer, cache] of this.state.caches.entries()) {
30
+ cache.specRoundBegin();
31
+ for (const array of cache.updateAndFetch(projected[layer]!.k, projected[layer]!.v)) array.dispose();
32
+ if (lengths.every(length => length === width)) cache.specRoundCommit();
33
+ else cache.specRoundRollback(lengths);
34
+ }
35
+ } finally { disposeResources(projected.flatMap(pair => [pair.k, pair.v])); }
36
+ }
37
+ materialize(): void { ops.evalAll(this.state.caches.flatMap(cache => cache.state())); }
38
+ readAttention() {
39
+ const views: import("../../model/gemma4-base").KvDonorRows[] = [];
40
+ try { for (const cache of this.state.caches) views.push(cache.captureDonorRows()); }
41
+ catch (error) { disposeResources(views.flatMap(view => [view.keys, view.values])); throw error; }
42
+ const masks = new Map<string, MlxArray | null>();
43
+ return {
44
+ attend(layer: number, query: MlxArray, blockKeys: MlxArray, blockValues: MlxArray, scale = 1): MlxArray {
45
+ const view = views[layer]!, width = view.keys.shape[2]!, block = blockKeys.shape[2]!, B = view.offsets.length;
46
+ // Membership and coverage advance together in every context layer.
47
+ const key = `${width}:${block}:${view.keys.dtype}`;
48
+ if (!masks.has(key)) {
49
+ let mask: MlxArray | null = null;
50
+ if (view.starts.some(start => start !== 0) || view.ends.some(end => end !== width)) {
51
+ using columns = ops.arange(0, width, 1, Dtype.int32);
52
+ using lower = ops.fromInt32([...view.starts], [B, 1, 1, 1]);
53
+ using upper = ops.fromInt32([...view.ends], [B, 1, 1, 1]);
54
+ using before = ops.less(columns, lower), after = ops.greaterEqual(columns, upper);
55
+ using invalid = ops.logicalOr(before, after);
56
+ using floats = invalid.astype(view.keys.dtype);
57
+ using prefix = ops.mulScalar(floats, -1e9);
58
+ using suffix = ops.zeros([B, 1, 1, block], view.keys.dtype);
59
+ mask = ops.concatAxis([prefix, suffix], 3);
60
+ }
61
+ masks.set(key, mask);
62
+ }
63
+ using keys = ops.concatAxis([view.keys, blockKeys], 2);
64
+ using values = ops.concatAxis([view.values, blockValues], 2);
65
+ const mask = masks.get(key)!;
66
+ return ops.sdpa(query, keys, values, scale, mask ? "array" : "", mask);
67
+ },
68
+ dispose() { disposeResources([...views.flatMap(view => [view.keys, view.values]), ...[...masks.values()].filter(value => value !== null)]); },
69
+ };
70
+ }
71
+ dispose(): void { this.state.dispose(); }
72
+ }
@@ -0,0 +1,20 @@
1
+ import type { GenerateOptions } from "../../generate";
2
+
3
+ /** Copy policy data without cloning native caches, controllers or callbacks. */
4
+ export function snapshotGenerationPolicy<T extends GenerateOptions & { stopSequences?: readonly string[] }>(options: T): T {
5
+ const snapshot = { ...options };
6
+ const freeze = (value: unknown): void => {
7
+ if (!value || typeof value !== "object") return;
8
+ for (const item of Object.values(value)) freeze(item);
9
+ Object.freeze(value);
10
+ };
11
+ for (const key of ["stopSequences", "eosTokenIds", "adapters", "xtcSpecialTokens", "logitBias",
12
+ "kvConfig", "turboQuant", "pagedKv", "hlg", "curve", "decodePolicy"] as const) {
13
+ if (snapshot[key] === undefined) continue;
14
+ const value = structuredClone(snapshot[key]);
15
+ freeze(value);
16
+ Object.assign(snapshot, { [key]: value });
17
+ }
18
+ return Object.freeze(snapshot);
19
+ }
20
+
@@ -0,0 +1,41 @@
1
+ import type { GenerateOptions } from "../../generate";
2
+ import type { RuntimeModel } from "../../model/factory";
3
+ import { KVCache, type Cache } from "../../model/gemma4-base";
4
+ import { PagedKVCache } from "../../lab/paged-kv/paged-kv";
5
+ import type { RowPromptCache } from "./batch-group";
6
+ import { disposeResources } from "../../engine/resources";
7
+
8
+ /** Request state construction and reusable-prefix policy. Equal keys declare
9
+ * compatible state layouts; the executor need not inspect their settings. */
10
+ export interface MlxRequestStatePolicy {
11
+ readonly key: string;
12
+ readonly promptCache?: RowPromptCache;
13
+ create(): Cache[];
14
+ }
15
+
16
+ /** Replace fresh full-attention storage before prefill. Sliding layers retain
17
+ * their layout; pre-warmed library caches retain their existing storage. */
18
+ export function maybePageKv(
19
+ cache: Cache[], options: GenerateOptions, capacityTokens: number,
20
+ ): void {
21
+ if (!options.pagedKv) return;
22
+ if (cache.some((c) => c.offset > 0)) return;
23
+ const blockSize = options.pagedKv.blockSize ?? PagedKVCache.DEFAULT_BLOCK_SIZE;
24
+ for (let i = 0; i < cache.length; i++) {
25
+ if (cache[i] instanceof KVCache) {
26
+ cache[i]!.dispose(); // fresh (offset 0) — nothing stored yet
27
+ cache[i] = new PagedKVCache(capacityTokens, blockSize);
28
+ }
29
+ }
30
+ }
31
+
32
+ export function bindPagedRequestState(model: RuntimeModel, options: GenerateOptions,
33
+ capacityTokens: number): MlxRequestStatePolicy | undefined {
34
+ if (!options.pagedKv) return undefined;
35
+ const blockSize = options.pagedKv.blockSize ?? PagedKVCache.DEFAULT_BLOCK_SIZE;
36
+ return { key: `paged:${blockSize}`, create() {
37
+ const caches = model.makeCache();
38
+ try { maybePageKv(caches, { pagedKv: { blockSize } }, capacityTokens); return caches; }
39
+ catch (error) { disposeResources(caches); throw error; }
40
+ } };
41
+ }
@@ -0,0 +1,89 @@
1
+ import type { SpeculativeTransaction } from "../../inference/rollback";
2
+ import type { Cache } from "../../model/gemma4-base";
3
+
4
+ interface TransactionLayer<Acceptance> {
5
+ fits(drafts: number): boolean;
6
+ begin(): void;
7
+ resolve(accepted: Acceptance, drafts: number): void;
8
+ }
9
+
10
+ /** State storage that can retain a different verified prefix for each row.
11
+ * Both attention and recurrent layouts implement this same transaction. */
12
+ export interface RowSpeculativeState {
13
+ specRoundBegin(): void;
14
+ specRoundCommit(): void;
15
+ specRoundRollback(keep: number | readonly number[]): void;
16
+ }
17
+
18
+ export function bindRowCacheRollback(
19
+ caches: readonly RowSpeculativeState[], rows: number,
20
+ ): SpeculativeTransaction<readonly number[]> {
21
+ return bindTransaction(caches.map(cache => ({
22
+ fits: () => true,
23
+ begin: () => cache.specRoundBegin(),
24
+ resolve(accepted: readonly number[], drafts: number) {
25
+ if (accepted.every(count => count === drafts)) cache.specRoundCommit();
26
+ else cache.specRoundRollback(accepted.every(count => count === accepted[0])
27
+ ? accepted[0]! + 1 : accepted.map(count => count + 1));
28
+ },
29
+ })), (accepted, drafts) => accepted.length === rows &&
30
+ accepted.every(count => Number.isSafeInteger(count) && count >= 0 && count <= drafts));
31
+ }
32
+
33
+ /** Bind the recurrent transaction or the trim implementation once.
34
+ * Ring-capacity checks still happen at each safe boundary before any writes. */
35
+ export function bindCacheRollback(caches: readonly Cache[]): SpeculativeTransaction {
36
+ const layers = caches.map((cache) => {
37
+ const { specRoundBegin: begin, specRoundCommit: commit, specRoundRollback: rollback } = cache;
38
+ const hasRound = [begin, commit, rollback].some((method) => method !== undefined);
39
+ if (hasRound && !(typeof begin === "function" && typeof commit === "function" && typeof rollback === "function"))
40
+ throw new Error("cache exposes an incomplete speculative transaction");
41
+ return {
42
+ fits(drafts: number) {
43
+ if ("maxSize" in cache && typeof cache.maxSize === "number")
44
+ return cache.offset + drafts + 1 < cache.maxSize;
45
+ return hasRound || cache.isTrimmable();
46
+ },
47
+ begin: () => begin?.call(cache),
48
+ resolve(accepted: number, drafts: number) {
49
+ if (accepted < drafts) {
50
+ if (rollback) rollback.call(cache, accepted + 1);
51
+ else cache.trim(drafts - accepted);
52
+ } else commit?.call(cache);
53
+ },
54
+ };
55
+ });
56
+ return bindTransaction(layers, (accepted, drafts) =>
57
+ Number.isSafeInteger(accepted) && accepted >= 0 && accepted <= drafts);
58
+ }
59
+
60
+ /** One transaction lifecycle for scalar and row-wise state bindings. */
61
+ function bindTransaction<Acceptance>(
62
+ layers: readonly TransactionLayer<Acceptance>[],
63
+ accepts: (accepted: Acceptance, drafts: number) => boolean,
64
+ ): SpeculativeTransaction<Acceptance> {
65
+ let active: number | undefined;
66
+ let invalid = false;
67
+ const validate = (drafts: number) => {
68
+ if (invalid) throw new Error("speculative state is invalid and must be discarded");
69
+ if (!Number.isSafeInteger(drafts) || drafts < 0) throw new Error("invalid speculative draft count");
70
+ };
71
+ return {
72
+ canBegin(drafts) { validate(drafts); return active === undefined && layers.every((layer) => layer.fits(drafts)); },
73
+ begin(drafts) {
74
+ validate(drafts);
75
+ if (active !== undefined || !layers.every((layer) => layer.fits(drafts)))
76
+ throw new Error("speculative state cannot begin this round");
77
+ active = drafts;
78
+ try { for (const layer of layers) layer.begin(); }
79
+ catch (error) { invalid = true; throw error; }
80
+ },
81
+ resolve(accepted) {
82
+ if (invalid) throw new Error("speculative state is invalid and must be discarded");
83
+ if (active === undefined || !accepts(accepted, active)) throw new Error("invalid speculative acceptance count");
84
+ try { for (const layer of layers) layer.resolve(accepted, active); }
85
+ catch (error) { invalid = true; throw error; }
86
+ active = undefined;
87
+ },
88
+ };
89
+ }
@@ -0,0 +1,49 @@
1
+ import type { MlxArray } from "../../mlx/array";
2
+ import * as ops from "../../mlx/ops";
3
+ import type { TokenLogprobs } from "../../contracts/generation";
4
+ import { readStepExtras, stepExtrasArrays, disposeStepExtras,
5
+ type DeviceStepSampler, type StepExtras } from "../../sampler";
6
+ import { disposeResources, cleanupFailure } from "../../engine/resources";
7
+
8
+ type TokenSink = (token: number, logprobs?: TokenLogprobs) => void | boolean | Promise<void | boolean>;
9
+
10
+ /** Request-owned sampling and output metadata. Execution groups receive token
11
+ * tensors and an output callback; they need no logprob or retention policy. */
12
+ export function createRowSampling(
13
+ sampler: DeviceStepSampler, onToken: TokenSink,
14
+ ) {
15
+ if (!sampler.capturesLogprobs) return {
16
+ sample: (logits: MlxArray, step: number) => sampler.sample(logits, step).token,
17
+ plainGreedy: sampler.isPlainGreedy, onToken, dispose: () => sampler.dispose(),
18
+ };
19
+
20
+ // A pipelined group can sample the next token before emitting the previous
21
+ // one. Keep captures by request-local step, independently of row position.
22
+ const pending = new Map<number, StepExtras>();
23
+ let emitted = 0;
24
+ return {
25
+ sample(logits: MlxArray, step: number): MlxArray {
26
+ const result = sampler.sample(logits, step);
27
+ try {
28
+ ops.asyncEvalAll([result.token, ...stepExtrasArrays(result.extras)]);
29
+ if (result.extras) pending.set(step, result.extras);
30
+ return result.token;
31
+ } catch (error) {
32
+ return cleanupFailure(error, () => disposeResources([result.token,
33
+ { dispose: () => disposeStepExtras(result.extras) }]));
34
+ }
35
+ },
36
+ // The vectorized token-only shortcut bypasses the per-request sampler.
37
+ plainGreedy: false,
38
+ onToken(token: number) {
39
+ const extras = pending.get(emitted) ?? null;
40
+ pending.delete(emitted++);
41
+ return onToken(token, readStepExtras(extras));
42
+ },
43
+ dispose() {
44
+ const extras = [...pending.values()];
45
+ pending.clear();
46
+ disposeResources([sampler, ...extras.map(value => ({ dispose: () => disposeStepExtras(value) }))]);
47
+ },
48
+ };
49
+ }