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
@@ -21,187 +21,49 @@
21
21
  // (held over from the verify tap). Computationally identical to mlx-vlm's
22
22
  // commit-time "seed" append, just performed at the top of the next round.
23
23
  //
24
- // Weights are plain bf16 (DenseLinear); the published drafter snapshots are
25
- // already sanitized (norms in runtime layout — no +1.0 shift here).
24
+ // Companion projections may be dense or quantized according to their metadata.
25
+ // Published drafter norms are already sanitized to runtime layout; no +1.0 shift.
26
26
 
27
27
  import { MlxArray } from "../mlx/array";
28
28
  import * as ops from "../mlx/ops";
29
+ import { materializeCopy } from "../mlx/materialize";
29
30
  import { toLogprobs } from "../sampler";
30
31
  import { loadModelConfig, type ModelConfig } from "../config";
31
32
  import { Weights } from "../weights";
32
- import { disposing, KVCache, RMSNorm, type Mask } from "../model/gemma4-base";
33
- import { DenseLinear } from "../model/universal/modules";
34
- import { Qwen35Model } from "../model/qwen3_5";
35
- import type { DraftProvider, DraftSource, TargetView } from "./source";
33
+ import { KVCache } from "../model/gemma4-base";
34
+ import { MtpModule } from "./qwen-mtp-module";
35
+ import type { DraftProvider, DraftSource, DraftRowCheckpoint, DraftRowGroup, DraftPrefillGroup, DraftRowSampling, GroupedDraftProvider, QwenMtpTarget, TargetView } from "./source";
36
+ import { QwenMtpRows, type MtpRowState } from "./qwen-mtp-rows";
37
+ import { captureQwenMtpState, restoreQwenMtpState } from "./qwen-mtp-state";
38
+ import type { Cache } from "../model/gemma4";
39
+ import { applyStateChanges, cleanupFailure, disposeResources } from "../engine/resources";
40
+ import { artifactIdentity } from "../model/artifact-identity";
41
+ import { configFingerprint } from "../model/fingerprint";
42
+ import type { PreparedStateChange } from "../contracts/resources";
36
43
 
37
44
  type Sampler = (logprobs: MlxArray, step: number) => MlxArray;
38
45
 
39
46
  const DRAFT_PREFILL_CHUNK = 2048;
40
47
 
41
- /** Dense-weight clone of Qwen3Attention.forward (src/model/qwen3_5.ts —
42
- * ops copied verbatim; only the projection flavor differs: the drafter is
43
- * bf16, the target's class hardwires QuantizedLinear). */
44
- class MtpAttention {
45
- readonly qProj: DenseLinear;
46
- readonly kProj: DenseLinear;
47
- readonly vProj: DenseLinear;
48
- readonly oProj: DenseLinear;
49
- readonly qNorm: RMSNorm;
50
- readonly kNorm: RMSNorm;
51
- readonly nHeads: number;
52
- readonly nKvHeads: number;
53
- readonly headDim: number;
54
- readonly scale: number;
55
- readonly ropeDims: number;
56
- readonly ropeBase: number;
57
-
58
- constructor(weights: Weights, config: ModelConfig, prefix: string) {
59
- const t = config.text;
60
- this.nHeads = t.numAttentionHeads;
61
- this.nKvHeads = t.numKeyValueHeads;
62
- this.headDim = t.headDim;
63
- this.scale = Math.pow(this.headDim, -0.5);
64
- this.ropeDims = Math.trunc(this.headDim * t.partialRotaryFactor);
65
- this.ropeBase = t.ropeParameters.full_attention?.ropeTheta ?? 10000;
66
- const dense = (path: string): DenseLinear =>
67
- new DenseLinear(weights.tensor(`${path}.weight`), null);
68
- this.qProj = dense(`${prefix}.q_proj`);
69
- this.kProj = dense(`${prefix}.k_proj`);
70
- this.vProj = dense(`${prefix}.v_proj`);
71
- this.oProj = dense(`${prefix}.o_proj`);
72
- this.qNorm = new RMSNorm(weights.tensor(`${prefix}.q_norm.weight`), t.rmsNormEps);
73
- this.kNorm = new RMSNorm(weights.tensor(`${prefix}.k_norm.weight`), t.rmsNormEps);
74
- }
75
-
76
- forward(x: MlxArray, mask: Mask, cache: KVCache): MlxArray {
77
- const [B, L] = x.shape as [number, number, number];
78
- const qp = this.qProj.forward(x);
79
- const qpr = disposing(qp, ops.reshape(qp, [B, L, this.nHeads, this.headDim * 2]));
80
- const [qHeads, gateHeads] = ops.split(qpr, [this.headDim], -1) as [MlxArray, MlxArray];
81
- qpr.dispose();
82
- const gate = disposing(gateHeads, ops.reshape(gateHeads, [B, L, this.nHeads * this.headDim]));
83
-
84
- let k = this.kProj.forward(x);
85
- let v = this.vProj.forward(x);
86
-
87
- let q = this.qNorm.forward(qHeads);
88
- qHeads.dispose();
89
- q = disposing(q, ops.transposeAxes(q, [0, 2, 1, 3]));
90
- k = disposing(k, ops.reshape(k, [B, L, this.nKvHeads, this.headDim]));
91
- k = disposing(k, this.kNorm.forward(k));
92
- k = disposing(k, ops.transposeAxes(k, [0, 2, 1, 3]));
93
- v = disposing(v, ops.reshape(v, [B, L, this.nKvHeads, this.headDim]));
94
- v = disposing(v, ops.transposeAxes(v, [0, 2, 1, 3]));
95
-
96
- q = disposing(q, ops.rope(q, this.ropeDims, this.ropeBase, cache.offset, null));
97
- k = disposing(k, ops.rope(k, this.ropeDims, this.ropeBase, cache.offset, null));
98
-
99
- const [keys, values] = cache.updateAndFetch(k, v);
100
- k.dispose();
101
- v.dispose();
102
- const attn = ops.sdpa(q, keys, values, this.scale, mask.mode, mask.arr);
103
- keys.dispose();
104
- values.dispose();
105
- q.dispose();
106
-
107
- const attnT = ops.transposeAxes(attn, [0, 2, 1, 3]);
108
- attn.dispose();
109
- const merged = ops.reshape(attnT, [B, L, -1]);
110
- attnT.dispose();
111
- const sig = ops.sigmoid(gate);
112
- gate.dispose();
113
- const gated = ops.mul(merged, sig);
114
- merged.dispose();
115
- sig.dispose();
116
- const out = this.oProj.forward(gated);
117
- gated.dispose();
118
- return out;
119
- }
120
- }
121
-
122
- /** The one MTP decoder block: fc-merge → attention → swiglu MLP → norm. */
123
- class MtpModule {
124
- readonly fc: DenseLinear;
125
- readonly preFcNormEmbedding: RMSNorm;
126
- readonly preFcNormHidden: RMSNorm;
127
- readonly attn: MtpAttention;
128
- readonly mlpGate: DenseLinear;
129
- readonly mlpUp: DenseLinear;
130
- readonly mlpDown: DenseLinear;
131
- readonly inputNorm: RMSNorm;
132
- readonly postAttnNorm: RMSNorm;
133
- readonly finalNorm: RMSNorm;
134
-
135
- constructor(weights: Weights, config: ModelConfig) {
136
- const eps = config.text.rmsNormEps;
137
- const dense = (path: string): DenseLinear =>
138
- new DenseLinear(weights.tensor(`${path}.weight`), null);
139
- this.fc = dense("fc");
140
- this.preFcNormEmbedding = new RMSNorm(weights.tensor("pre_fc_norm_embedding.weight"), eps);
141
- this.preFcNormHidden = new RMSNorm(weights.tensor("pre_fc_norm_hidden.weight"), eps);
142
- this.attn = new MtpAttention(weights, config, "layers.0.self_attn");
143
- this.mlpGate = dense("layers.0.mlp.gate_proj");
144
- this.mlpUp = dense("layers.0.mlp.up_proj");
145
- this.mlpDown = dense("layers.0.mlp.down_proj");
146
- this.inputNorm = new RMSNorm(weights.tensor("layers.0.input_layernorm.weight"), eps);
147
- this.postAttnNorm = new RMSNorm(weights.tensor("layers.0.post_attention_layernorm.weight"), eps);
148
- this.finalNorm = new RMSNorm(weights.tensor("norm.weight"), eps);
149
- }
150
-
151
- /** One block forward over [1,S,·]: token embeddings ([1,S,H], target
152
- * embed_tokens output) paired with hiddens ([1,S,H], target pre-final-norm
153
- * or the module's own chained output). Appends S rows to `cache`; returns
154
- * the module output [1,S,H] (post final norm — what the target lm_head
155
- * consumes AND what chains into the next step's `hidden`). */
156
- forward(tokenEmbeds: MlxArray, hiddens: MlxArray, cache: KVCache): MlxArray {
157
- const embNorm = this.preFcNormEmbedding.forward(tokenEmbeds);
158
- const hidNorm = this.preFcNormHidden.forward(hiddens);
159
- const joined = ops.concatAxis([embNorm, hidNorm], 2);
160
- embNorm.dispose();
161
- hidNorm.dispose();
162
- const x = this.fc.forward(joined);
163
- joined.dispose();
164
-
165
- // Decoder layer (Qwen3Layer.forward shape, dense weights).
166
- const L = x.shape[1]!;
167
- const mask = cache.makeMask(L, null);
168
- const xn = this.inputNorm.forward(x);
169
- const r = this.attn.forward(xn, mask, cache);
170
- xn.dispose();
171
- mask.arr?.dispose();
172
- const h = ops.add(x, r);
173
- x.dispose();
174
- r.dispose();
175
- const hn = this.postAttnNorm.forward(h);
176
- const g = this.mlpGate.forward(hn);
177
- const u = this.mlpUp.forward(hn);
178
- hn.dispose();
179
- const silu = ops.silu(g);
180
- g.dispose();
181
- const act = ops.mul(silu, u);
182
- silu.dispose();
183
- u.dispose();
184
- const m = this.mlpDown.forward(act);
185
- act.dispose();
186
- const out = ops.add(h, m);
187
- h.dispose();
188
- m.dispose();
189
- return disposing(out, this.finalNorm.forward(out));
190
- }
191
- }
192
-
193
48
  export class QwenMtpProvider implements DraftProvider {
49
+ readonly grouped: GroupedDraftProvider = {
50
+ open: options => this.#openRows(options.target, options.sampling, options.checkpoints),
51
+ openPrefill: options => this.#openRows(options.target, null, options.checkpoints),
52
+ };
194
53
  readonly id: string;
195
54
  readonly weightsBytes: number;
196
55
  readonly #module: MtpModule;
197
56
  readonly #config: ModelConfig;
57
+ readonly #resources: DisposableStack;
58
+ readonly #checkpointNamespace: string;
198
59
 
199
- private constructor(id: string, config: ModelConfig, weights: Weights, module: MtpModule) {
60
+ private constructor(id: string, config: ModelConfig, weightsBytes: number, module: MtpModule, resources: DisposableStack, checkpointNamespace: string) {
200
61
  this.id = id;
201
62
  this.#config = config;
202
63
  this.#module = module;
203
- this.weightsBytes = [...weights.shards.files.values()]
204
- .reduce((a, f) => a + f.mmap.size, 0);
64
+ this.weightsBytes = weightsBytes;
65
+ this.#resources = resources;
66
+ this.#checkpointNamespace = checkpointNamespace;
205
67
  }
206
68
 
207
69
  static async load(dir: string): Promise<QwenMtpProvider> {
@@ -209,28 +71,81 @@ export class QwenMtpProvider implements DraftProvider {
209
71
  if (config.modelType !== "qwen3_5_mtp")
210
72
  throw new Error(`${dir}: not a qwen3_5_mtp drafter (model_type ${config.modelType})`);
211
73
  const weights = await Weights.open(dir);
74
+ using resources = new DisposableStack();
75
+ resources.defer(() => weights.dispose());
76
+ const weightsBytes = [...weights.shards.files.values()]
77
+ .reduce((a, f) => a + f.mmap.size, 0);
78
+ const module = new MtpModule(weights, config, resources);
79
+ // Stable across restarts and distinct for differently folded/quantized
80
+ // companions. Hash once at provider load, outside inference execution.
81
+ const identity = await artifactIdentity(configFingerprint(config),
82
+ [...weights.shards.files].map(([name, shard]) => ({ name, path: shard.path })));
212
83
  return new QwenMtpProvider(
213
84
  dir.split("/").filter(Boolean).at(-1) ?? "qwen-mtp",
214
- config, weights, new MtpModule(weights, config),
85
+ config, weightsBytes, module, resources.move(), `qwen-mtp-v1:${identity}`,
215
86
  );
216
87
  }
217
88
 
218
89
  open(opts: Parameters<DraftProvider["open"]>[0]): DraftSource {
219
- const target = opts.target.model;
220
- if (!(target instanceof Qwen35Model))
90
+ return new QwenMtpSource(this.#target(opts.target), this.#module, opts.sampler, this.#checkpointNamespace);
91
+ }
92
+
93
+ #target(view: TargetView): QwenMtpTarget {
94
+ if (this.#resources.disposed)
95
+ throw new Error("qwen MTP provider is disposed");
96
+ const target = view.qwenMtp;
97
+ if (!target)
221
98
  throw new Error("qwen MTP drafting requires a qwen3_5-family target");
222
- if (target.config.text.hiddenSize !== this.#config.text.hiddenSize) {
99
+ if (target.hiddenSize !== this.#config.text.hiddenSize) {
223
100
  throw new Error(
224
101
  `qwen MTP drafter hidden ${this.#config.text.hiddenSize} != target ` +
225
- `${target.config.text.hiddenSize} — split from a different checkpoint?`,
102
+ `${target.hiddenSize} — split from a different checkpoint?`,
226
103
  );
227
104
  }
228
- return new QwenMtpSource(target, this.#module, opts.sampler);
105
+ return target;
229
106
  }
230
107
 
108
+ #openRows(view: TargetView, sampling: DraftRowSampling | null,
109
+ checkpoints: readonly (DraftRowCheckpoint | null)[]): DraftRowGroup & DraftPrefillGroup {
110
+ const target = this.#target(view);
111
+ const rows = new QwenMtpRows(target, this.#module, sampling, []);
112
+ const prepareAppend = (checkpoints: readonly (DraftRowCheckpoint | null)[]) => {
113
+ const states: Array<MtpRowState | null> = [];
114
+ let change: PreparedStateChange | undefined;
115
+ try {
116
+ for (const checkpoint of checkpoints) states.push(checkpoint ? restoreQwenMtpState(checkpoint) : null);
117
+ change = rows.prepareAppend(states);
118
+ disposeResources(states.splice(0).flatMap(state => state ? [state.cache, state.hidden] : []));
119
+ return change;
120
+ } catch (error) {
121
+ return cleanupFailure(error, () => disposeResources([
122
+ ...states.flatMap(state => state ? [state.cache, state.hidden] : []), ...(change ? [change] : []),
123
+ ]));
124
+ }
125
+ };
126
+ const append = (checkpoints: readonly (DraftRowCheckpoint | null)[]) => applyStateChanges([() => prepareAppend(checkpoints)]);
127
+ try { append(checkpoints); }
128
+ catch (error) { return cleanupFailure(error, () => rows.dispose()); }
129
+ return {
130
+ namespace: this.#checkpointNamespace, prefillMode: "full", tapLayers: [target.layerCount - 1],
131
+ get rowCount() { return rows.rowCount; },
132
+ append, prepareAppend, prefill: (tokens, context) => rows.prefill(tokens, context!), materialize: rows.materialize.bind(rows),
133
+ filterRows: rows.filterRows.bind(rows),
134
+ draft: rows.draft.bind(rows), commit: rows.commit.bind(rows),
135
+ capture(row) {
136
+ const state = rows.extractRow(row);
137
+ try { return captureQwenMtpState(state); }
138
+ finally { disposeResources([state.cache, state.hidden]); }
139
+ },
140
+ dispose: rows.dispose.bind(rows),
141
+ };
142
+ }
143
+
144
+
231
145
  dispose(): void {
232
- // Weights are mmap-backed and pinned for the process (house rule: no JS
233
- // dtors into mlx); the provider owns no other native state.
146
+ // Release cached transpose views before their native weight maps. MLX
147
+ // retains buffers needed by outstanding GPU commands until completion.
148
+ this.#resources.dispose();
234
149
  }
235
150
  }
236
151
 
@@ -243,10 +158,13 @@ export class QwenMtpSource implements DraftSource {
243
158
  * The seam's anchorHidden is post-final-norm and is deliberately unused. */
244
159
  readonly tapLayers: number[];
245
160
 
246
- readonly #target: Qwen35Model;
161
+ readonly #target: QwenMtpTarget;
247
162
  readonly #module: MtpModule;
248
163
  readonly #sampler: Sampler;
249
- readonly #cache = new KVCache();
164
+ #cache = new KVCache();
165
+ readonly checkpoint: NonNullable<DraftSource["checkpoint"]>;
166
+ #prefilledTokens = 0;
167
+ #hasDrafted = false;
250
168
  /** Target pre-norm hidden at the position preceding the next pending
251
169
  * token: prefill's last tapped row, then each commit's vCtx row at the
252
170
  * emitted position. draft() consumes it to build the pending row. [1,1,H] */
@@ -254,11 +172,32 @@ export class QwenMtpSource implements DraftSource {
254
172
  #roundAppended = 0;
255
173
  #closed = false;
256
174
 
257
- constructor(target: Qwen35Model, module: MtpModule, sampler: Sampler) {
175
+ constructor(target: QwenMtpTarget, module: MtpModule, sampler: Sampler,
176
+ namespace = "qwen-mtp-v1") {
258
177
  this.#target = target;
259
178
  this.#module = module;
260
179
  this.#sampler = sampler;
261
- this.tapLayers = [target.config.text.numHiddenLayers - 1];
180
+ this.tapLayers = [target.layerCount - 1];
181
+ this.checkpoint = {
182
+ namespace,
183
+ restore: (tokens, attachment) => {
184
+ this.#checkOpen();
185
+ if (this.#prefilledTokens !== 0 || this.#hasDrafted)
186
+ throw new Error("Qwen MTP checkpoint restore requires a fresh source");
187
+ const state = restoreQwenMtpState({ processedTokens: tokens, attachment });
188
+ try { disposeResources([this.#cache, ...(this.#pendingTrueHidden ? [this.#pendingTrueHidden] : [])]); }
189
+ catch (error) { return cleanupFailure(error, () => disposeResources([state.cache, state.hidden])); }
190
+ this.#cache = state.cache;
191
+ this.#pendingTrueHidden = state.hidden;
192
+ this.#prefilledTokens = tokens;
193
+ },
194
+ capture: (tokens) => {
195
+ this.#checkOpen();
196
+ if (!this.#pendingTrueHidden || this.#cache.offset !== tokens - 1 || this.#roundAppended !== 0)
197
+ throw new Error("Qwen MTP snapshot requires an aligned committed boundary");
198
+ return captureQwenMtpState({ cache: this.#cache, hidden: this.#pendingTrueHidden }).attachment;
199
+ },
200
+ };
262
201
  }
263
202
 
264
203
  /** Drafter prefill: rows for positions 0..L-2, keyed (token_{p+1}, h_p) —
@@ -269,27 +208,43 @@ export class QwenMtpSource implements DraftSource {
269
208
  if (!ctxML)
270
209
  throw new Error("qwen MTP prefill requires the tapped pre-final-norm context");
271
210
  try {
272
- if (this.#cache.offset !== 0)
273
- throw new Error("qwen MTP source cannot be prefilled twice");
211
+ if (this.#hasDrafted)
212
+ throw new Error("qwen MTP prefill cannot follow drafting");
274
213
  const L = promptIds.length;
214
+ const start = this.#prefilledTokens;
275
215
  const H = ctxML.shape[2]!;
276
- if (ctxML.shape[1]! !== L)
277
- throw new Error(`qwen MTP tap covered ${ctxML.shape[1]} of ${L} prompt positions`);
278
- this.#pendingTrueHidden = ctxML.slice([0, L - 1, 0], [1, L, H]);
279
- for (let pos = 0; pos + 1 < L; pos += DRAFT_PREFILL_CHUNK) {
216
+ if (L <= start || ctxML.shape[1]! !== L - start)
217
+ throw new Error(`qwen MTP tap covered ${ctxML.shape[1]} of ${L - start} new prompt positions`);
218
+ if (start > 0) {
219
+ if (!this.#pendingTrueHidden || this.#cache.offset !== start - 1)
220
+ throw new Error("qwen MTP prefix state is not aligned");
221
+ this.#stepOne(promptIds[start]!, this.#pendingTrueHidden).dispose();
222
+ }
223
+ this.#pendingTrueHidden?.dispose();
224
+ // A slice would retain the complete prompt buffer in the saved prefix.
225
+ // Materialize this one row before handing off the prefill state.
226
+ using tail = ctxML.slice([0, L - start - 1, 0], [1, L - start, H]);
227
+ this.#pendingTrueHidden = materializeCopy(tail);
228
+ for (let pos = start; pos + 1 < L; pos += DRAFT_PREFILL_CHUNK) {
280
229
  const n = Math.min(DRAFT_PREFILL_CHUNK, L - 1 - pos);
281
230
  const shifted = promptIds.slice(pos + 1, pos + 1 + n);
282
231
  const ids = ops.fromInt32(shifted, [1, n]);
283
- const embeds = this.#target.embed.encode(ids);
232
+ const embeds = this.#target.embed(ids);
284
233
  ids.dispose();
285
- const hiddens = ctxML.slice([0, pos, 0], [1, pos + n, H]);
234
+ const hiddens = ctxML.slice([0, pos - start, 0], [1, pos + n - start, H]);
286
235
  const out = this.#module.forward(embeds, hiddens, this.#cache);
287
236
  embeds.dispose();
288
237
  hiddens.dispose();
289
238
  out.dispose(); // prefill outputs are not seeds; only KV matters here
239
+ // Bound the lazy KV graph at each chunk. Evaluating the unused output
240
+ // would also execute attention and the MLP, which prefill does not need.
241
+ ops.evalAll(this.#cache.state());
290
242
  }
291
243
  if (this.#cache.offset !== L - 1)
292
244
  throw new Error(`qwen MTP prefill offset ${this.#cache.offset}, expected ${L - 1}`);
245
+ // Also covers a restored-prefix bridge with no subsequent full chunk.
246
+ ops.evalAll([this.#pendingTrueHidden, ...this.#cache.state()]);
247
+ this.#prefilledTokens = L;
293
248
  } finally {
294
249
  ctxML?.dispose(); // ownership per the seam contract
295
250
  }
@@ -297,6 +252,7 @@ export class QwenMtpSource implements DraftSource {
297
252
 
298
253
  async draft(feed: number[], n: number, stepBase: number): Promise<number[]> {
299
254
  this.#checkOpen();
255
+ this.#hasDrafted = true;
300
256
  if (this.#roundAppended !== 0)
301
257
  throw new Error("qwen MTP draft called before the prior round committed");
302
258
  if (n <= 0) return [];
@@ -316,8 +272,8 @@ export class QwenMtpSource implements DraftSource {
316
272
  this.#pendingTrueHidden.dispose();
317
273
  this.#pendingTrueHidden = null;
318
274
  this.#roundAppended++;
319
- drafts.push(this.#sample(out, stepBase));
320
275
  chained = out;
276
+ drafts.push(this.#sample(out, stepBase));
321
277
  while (drafts.length < n) {
322
278
  const out = this.#stepOne(drafts.at(-1)!, chained!);
323
279
  chained!.dispose();
@@ -369,7 +325,7 @@ export class QwenMtpSource implements DraftSource {
369
325
  const H = vCtxML.shape[2]!;
370
326
  if (kAccept === d && d > 0) {
371
327
  const ids = ops.fromInt32([acceptedTokens[kAccept - 1]!], [1, 1]);
372
- const embeds = this.#target.embed.encode(ids);
328
+ const embeds = this.#target.embed(ids);
373
329
  ids.dispose();
374
330
  const hidden = vCtxML.slice([0, d - 1, 0], [1, d, H]);
375
331
  const out = this.#module.forward(embeds, hidden, this.#cache);
@@ -396,33 +352,29 @@ export class QwenMtpSource implements DraftSource {
396
352
 
397
353
  /** One module forward for (token, hidden) — appends one KV row. */
398
354
  #stepOne(token: number, hidden: MlxArray): MlxArray {
399
- const ids = ops.fromInt32([token], [1, 1]);
400
- const embed = this.#target.embed.encode(ids);
355
+ using ids = ops.fromInt32([token], [1, 1]);
356
+ using embed = this.#target.embed(ids);
401
357
  ids.dispose();
402
- const out = this.#module.forward(embed, hidden, this.#cache);
403
- embed.dispose();
404
- return out;
358
+ return this.#module.forward(embed, hidden, this.#cache);
405
359
  }
406
360
 
407
361
  /** Sample a draft token from the module output via the TARGET's lm head
408
362
  * and the request sampler (per-step RNG stream discipline). */
409
363
  #sample(moduleOut: MlxArray, step: number): number {
410
- const logits = this.#target.logitsFromHidden(moduleOut);
364
+ using logits = this.#target.logitsFromHidden(moduleOut);
411
365
  // Sampler contract is [1, V] (the main decode loop's shape). moduleOut
412
366
  // is [1, 1, H] → logits [1, 1, V]; without this reshape any sampler
413
367
  // that slices 2-D (top-k) throws "[slice] Invalid number of indices…
414
368
  // dimension 3" — the serve-lane MTP 500 (chat defaults carry the
415
369
  // model's top_k=20; the greedy bench harness never hit it).
416
370
  const V = logits.shape[logits.shape.length - 1]!;
417
- const flat = ops.reshape(logits, [1, V]);
371
+ using flat = ops.reshape(logits, [1, V]);
418
372
  logits.dispose();
419
- const logprobs = toLogprobs(flat);
373
+ using logprobs = toLogprobs(flat);
420
374
  flat.dispose();
421
- const tok = this.#sampler(logprobs, step);
375
+ using tok = this.#sampler(logprobs, step);
422
376
  logprobs.dispose();
423
- const id = ops.itemUint32(tok);
424
- tok.dispose();
425
- return id;
377
+ return ops.itemUint32(tok);
426
378
  }
427
379
 
428
380
  #checkOpen(): void {
@@ -0,0 +1,30 @@
1
+ import type { MlxArray } from "../mlx/array";
2
+ import { KVCache } from "../model/gemma4-base";
3
+ import { cloneAttachments } from "../backends/mlx/checkpoint-state";
4
+ import { disposeResources } from "../engine/resources";
5
+ import type { MtpRowState } from "./qwen-mtp-rows";
6
+ import type { DraftRowCheckpoint } from "./source";
7
+
8
+ /** The existing Qwen companion attachment is also the state interchange
9
+ * between prepared requests and a group. Storage-tier policy stays outside. */
10
+ export function restoreQwenMtpState(checkpoint: DraftRowCheckpoint): MtpRowState {
11
+ const { processedTokens: tokens, attachment } = checkpoint;
12
+ if (attachment.schema !== "qwen-mtp-v1" || attachment.metadata.draftOffset !== tokens - 1)
13
+ throw new Error("invalid paired Qwen MTP checkpoint alignment");
14
+ const held = cloneAttachments([attachment])[0]!.tensors;
15
+ let cache: KVCache | null = new KVCache();
16
+ try {
17
+ if (tokens > 1) { cache.restoreState(held[0]!, held[1]!, tokens - 1); held.splice(0, 2); }
18
+ const state = { cache, hidden: held.pop()! }; cache = null; return state;
19
+ } finally { disposeResources([...held, ...(cache ? [cache] : [])]); }
20
+ }
21
+
22
+ export function captureQwenMtpState(state: MtpRowState): DraftRowCheckpoint {
23
+ const held: MlxArray[] = [];
24
+ try {
25
+ if (state.cache.offset > 0) held.push(...state.cache.temporalView());
26
+ held.push(state.hidden.slice([0, 0, 0], [...state.hidden.shape]));
27
+ return { processedTokens: state.cache.offset + 1,
28
+ attachment: { schema: "qwen-mtp-v1", metadata: { draftOffset: state.cache.offset }, tensors: held.splice(0) } };
29
+ } finally { disposeResources(held); }
30
+ }