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
@@ -13,8 +13,11 @@ import * as ops from "../mlx/ops";
13
13
  import { toLogprobs } from "../sampler";
14
14
  import { Glm52DecoderLayer, Glm52Model } from "../model/glm52";
15
15
  import { MLACache } from "../model/glm52-cache";
16
- import { rmsNormF32Mlx } from "../model/glm52-mla";
17
- import type { DraftProvider, DraftSource } from "./source";
16
+ import { Glm52MtpGraph } from "./glm52-mtp-graph";
17
+ import type { DraftProvider, DraftSource, GroupedDraftProvider, TargetView, DraftRowSampling, DraftRowCheckpoint, DraftRowGroup, DraftPrefillGroup } from "./source";
18
+ import { Glm52MtpRows, type Glm52MtpRowState } from "./glm52-mtp-rows";
19
+ import { captureGlm52MtpState, restoreGlm52MtpState } from "./glm52-mtp-state";
20
+ import { applyStateChanges, disposeResources } from "../engine/resources";
18
21
 
19
22
  type Sampler = (logprobs: MlxArray, step: number) => MlxArray;
20
23
 
@@ -26,6 +29,10 @@ function lastToken(feed: readonly number[]): number {
26
29
  }
27
30
 
28
31
  export class Glm52NativeMtpProvider implements DraftProvider {
32
+ readonly grouped: GroupedDraftProvider = {
33
+ open: options => this.#openRows(options.target, options.sampling, options.checkpoints),
34
+ openPrefill: options => this.#openRows(options.target, null, options.checkpoints),
35
+ };
29
36
  readonly id = "glm52-native-mtp";
30
37
  readonly weightsBytes = 0;
31
38
  readonly #layer: Glm52DecoderLayer;
@@ -57,11 +64,39 @@ export class Glm52NativeMtpProvider implements DraftProvider {
57
64
  }
58
65
 
59
66
  open(opts: Parameters<DraftProvider["open"]>[0]): DraftSource {
60
- if (opts.target.model !== this.model)
67
+ if (opts.target.identity !== this.model)
61
68
  throw new Error("native MTP provider was opened for a different target");
62
69
  return new Glm52NativeMtpSource(this.model, this.#layer, opts.sampler);
63
70
  }
64
71
 
72
+ #openRows(target: TargetView, sampling: DraftRowSampling | null,
73
+ checkpoints: readonly (DraftRowCheckpoint | null)[]): DraftRowGroup & DraftPrefillGroup {
74
+ if (target.identity !== this.model) throw new Error("native MTP provider was opened for a different target");
75
+ const rows = new Glm52MtpRows(new Glm52MtpGraph(this.model, this.#layer), sampling);
76
+ const prepareAppend = (checkpoints: readonly (DraftRowCheckpoint | null)[]) => {
77
+ const states: (Glm52MtpRowState | null)[] = [];
78
+ try {
79
+ for (const checkpoint of checkpoints) states.push(checkpoint ? restoreGlm52MtpState(checkpoint, () => rows.makeCache()) : null);
80
+ return rows.prepareAppend(states);
81
+ } finally { disposeResources(states.flatMap(state => state ? [state.cache, state.hidden] : [])); }
82
+ };
83
+ const append = (states: readonly (DraftRowCheckpoint | null)[]) => applyStateChanges([() => prepareAppend(states)]);
84
+ try { append(checkpoints); } catch (error) { rows.dispose(); throw error; }
85
+ return {
86
+ namespace: "glm52-native-mtp-v1", prefillMode: "full", tapLayers: [],
87
+ get rowCount() { return rows.rowCount; },
88
+ append, prepareAppend, prefill: (tokens, context) => rows.prefill(tokens, context!),
89
+ materialize: rows.materialize.bind(rows), filterRows: rows.filterRows.bind(rows),
90
+ draft: rows.draft.bind(rows), commit: rows.commit.bind(rows),
91
+ capture(row) {
92
+ const state = rows.extractRow(row);
93
+ try { return captureGlm52MtpState(state); }
94
+ finally { state.cache.dispose(); state.hidden.dispose(); }
95
+ },
96
+ dispose: rows.dispose.bind(rows),
97
+ };
98
+ }
99
+
65
100
  dispose(): void {
66
101
  // The target model owns every shared/MTP weight and the expert tier.
67
102
  }
@@ -72,6 +107,7 @@ export class Glm52NativeMtpSource implements DraftSource {
72
107
  readonly pinTargetKernelFamily = true;
73
108
  readonly weightsBytes = 0;
74
109
  #cache: MLACache;
110
+ readonly #graph: Glm52MtpGraph;
75
111
  #roundStart = 0;
76
112
  #lastDraftCount = 0;
77
113
  #closed = false;
@@ -81,6 +117,7 @@ export class Glm52NativeMtpSource implements DraftSource {
81
117
  readonly layer: Glm52DecoderLayer,
82
118
  readonly sampler: Sampler,
83
119
  ) {
120
+ this.#graph = new Glm52MtpGraph(model, layer);
84
121
  this.#cache = new MLACache({
85
122
  kvLoraRank: model.glmConfig.kvLoraRank,
86
123
  ropeHeadDim: model.glmConfig.qkRopeHeadDim,
@@ -256,142 +293,22 @@ export class Glm52NativeMtpSource implements DraftSource {
256
293
  hidden: MlxArray,
257
294
  sampleStep: number,
258
295
  ): Promise<{ hidden: MlxArray; token: number }> {
259
- const config = this.model.glmConfig;
260
- const ids = ops.fromInt32([token], [1, 1]);
261
- let embedded: MlxArray | null = null;
262
- let embeddedNorm: MlxArray | null = null;
263
- let hiddenNorm: MlxArray | null = null;
264
- let joined: MlxArray | null = null;
265
- let projected: MlxArray | null = null;
266
- let output: MlxArray | null = null;
267
- let headInput: MlxArray | null = null;
268
- let logits: MlxArray | null = null;
269
- let logprobs: MlxArray | null = null;
270
- let sampled: MlxArray | null = null;
271
- try {
272
- embedded = this.model.weights.embedding(
273
- ids,
274
- "model.embed_tokens.weight",
275
- config.vocabSize,
276
- config.hiddenSize,
277
- );
278
- embeddedNorm = rmsNormF32Mlx(
279
- embedded,
280
- this.model.weights.tensor(
281
- `model.layers.${config.numHiddenLayers}.enorm.weight`,
282
- ),
283
- config.rmsNormEps,
284
- );
285
- hiddenNorm = rmsNormF32Mlx(
286
- hidden,
287
- this.model.weights.tensor(
288
- `model.layers.${config.numHiddenLayers}.hnorm.weight`,
289
- ),
290
- config.rmsNormEps,
291
- );
292
- joined = ops.concatAxis([embeddedNorm, hiddenNorm], 2);
293
- projected = this.model.weights.linear(
294
- joined,
295
- `model.layers.${config.numHiddenLayers}.eh_proj.weight`,
296
- config.hiddenSize,
297
- 2 * config.hiddenSize,
298
- );
299
- output = await this.layer.forwardAsync(projected, this.#cache, null);
300
- headInput = rmsNormF32Mlx(
301
- output,
302
- this.model.weights.tensor(
303
- `model.layers.${config.numHiddenLayers}.shared_head.norm.weight`,
304
- ),
305
- config.rmsNormEps,
306
- );
307
- logits = this.model.logitsFromHidden(headInput);
308
- // Sampler contract is [1, V] — same 3-D top-k hazard as
309
- // qwen-mtp-source #sample (2026-08-20); see the comment there.
310
- {
311
- const V = logits.shape[logits.shape.length - 1]!;
312
- const flat = ops.reshape(logits, [1, V]);
313
- logits.dispose();
314
- logits = flat;
315
- }
316
- logprobs = toLogprobs(logits);
317
- sampled = this.sampler(logprobs, sampleStep);
318
- return {
319
- hidden: ops.contiguous(output),
320
- token: ops.itemUint32(sampled),
321
- };
322
- } finally {
323
- ids.dispose();
324
- embedded?.dispose();
325
- embeddedNorm?.dispose();
326
- hiddenNorm?.dispose();
327
- joined?.dispose();
328
- projected?.dispose();
329
- output?.dispose();
330
- headInput?.dispose();
331
- logits?.dispose();
332
- logprobs?.dispose();
333
- sampled?.dispose();
334
- }
296
+ using ids = ops.fromInt32([token], [1, 1]);
297
+ using output = await this.#graph.forward(ids, hidden, this.#cache);
298
+ using logits = this.#graph.project(output);
299
+ // Sampling consumes [B,V], independently of the graph's token dimension.
300
+ using flat = ops.reshape(logits, [1, logits.shape.at(-1)!]);
301
+ using logprobs = toLogprobs(flat);
302
+ using sampled = this.sampler(logprobs, sampleStep);
303
+ return { hidden: ops.contiguous(output), token: ops.itemUint32(sampled) };
335
304
  }
336
305
 
337
- async #absorb(
338
- acceptedTokens: readonly number[],
339
- verifiedHidden: MlxArray,
340
- ): Promise<void> {
341
- const config = this.model.glmConfig;
342
- const k = acceptedTokens.length;
343
- const ids = ops.fromInt32([...acceptedTokens], [1, k]);
344
- let embedded: MlxArray | null = null;
345
- let embeddedNorm: MlxArray | null = null;
346
- let trueRows: MlxArray | null = null;
347
- let hiddenNorm: MlxArray | null = null;
348
- let joined: MlxArray | null = null;
349
- let projected: MlxArray | null = null;
350
- let output: MlxArray | null = null;
351
- try {
352
- embedded = this.model.weights.embedding(
353
- ids,
354
- "model.embed_tokens.weight",
355
- config.vocabSize,
356
- config.hiddenSize,
357
- );
358
- embeddedNorm = rmsNormF32Mlx(
359
- embedded,
360
- this.model.weights.tensor(
361
- `model.layers.${config.numHiddenLayers}.enorm.weight`,
362
- ),
363
- config.rmsNormEps,
364
- );
365
- trueRows = verifiedHidden.slice(
366
- [0, 0, 0],
367
- [1, k, config.hiddenSize],
368
- );
369
- hiddenNorm = rmsNormF32Mlx(
370
- trueRows,
371
- this.model.weights.tensor(
372
- `model.layers.${config.numHiddenLayers}.hnorm.weight`,
373
- ),
374
- config.rmsNormEps,
375
- );
376
- joined = ops.concatAxis([embeddedNorm, hiddenNorm], 2);
377
- projected = this.model.weights.linear(
378
- joined,
379
- `model.layers.${config.numHiddenLayers}.eh_proj.weight`,
380
- config.hiddenSize,
381
- 2 * config.hiddenSize,
382
- );
383
- output = await this.layer.forwardAsync(projected, this.#cache, null);
384
- output.eval();
385
- } finally {
386
- ids.dispose();
387
- embedded?.dispose();
388
- embeddedNorm?.dispose();
389
- trueRows?.dispose();
390
- hiddenNorm?.dispose();
391
- joined?.dispose();
392
- projected?.dispose();
393
- output?.dispose();
394
- }
306
+ async #absorb(acceptedTokens: readonly number[], verifiedHidden: MlxArray): Promise<void> {
307
+ const count = acceptedTokens.length;
308
+ using ids = ops.fromInt32([...acceptedTokens], [1, count]);
309
+ using trueRows = verifiedHidden.slice([0, 0, 0], [1, count, this.model.glmConfig.hiddenSize]);
310
+ using output = await this.#graph.forward(ids, trueRows, this.#cache);
311
+ output.eval();
395
312
  }
396
313
 
397
314
  #checkOpen(): void {
@@ -0,0 +1,33 @@
1
+ import type { MlxArray } from "../mlx/array";
2
+ import type { MLACache } from "../model/glm52-cache";
3
+ import { cloneAttachments } from "../backends/mlx/checkpoint-state";
4
+ import { disposeResources } from "../engine/resources";
5
+ import type { DraftRowCheckpoint } from "./source";
6
+ import type { Glm52MtpRowState } from "./glm52-mtp-rows";
7
+
8
+ export function captureGlm52MtpState(state: Glm52MtpRowState): DraftRowCheckpoint {
9
+ const held: MlxArray[] = [];
10
+ try {
11
+ if (state.cache.offset) {
12
+ const cache = state.cache.fetch(); held.push(cache.latent, cache.rope);
13
+ }
14
+ held.push(state.hidden.slice([0, 0, 0], [...state.hidden.shape]));
15
+ return { processedTokens: state.processedTokens, attachment: {
16
+ schema: "glm52-native-mtp-v1", metadata: { processedTokens: state.processedTokens, draftOffset: state.cache.offset },
17
+ tensors: held.splice(0),
18
+ } };
19
+ } finally { disposeResources(held); }
20
+ }
21
+
22
+ export function restoreGlm52MtpState(checkpoint: DraftRowCheckpoint, makeCache: () => MLACache): Glm52MtpRowState {
23
+ const { attachment, processedTokens } = checkpoint;
24
+ if (attachment.schema !== "glm52-native-mtp-v1" || attachment.metadata.processedTokens !== processedTokens)
25
+ throw new Error("invalid native GLM MTP checkpoint alignment");
26
+ const held = cloneAttachments([attachment])[0]!.tensors;
27
+ let cache: MLACache | null = makeCache();
28
+ try {
29
+ const offset = attachment.metadata.draftOffset as number;
30
+ if (offset) { cache.restoreCompressedState(held[0]!, held[1]!, null, offset); held.splice(0, 2); }
31
+ const state = { cache, hidden: held.pop()!, processedTokens }; cache = null; return state;
32
+ } finally { disposeResources([...held, ...(cache ? [cache] : [])]); }
33
+ }
@@ -38,8 +38,80 @@
38
38
  // speculation is structurally never worse than plain decode by more than the
39
39
  // JS scan (~µs against 30k-token histories).
40
40
 
41
- import { flagOn } from "../flags";
42
- import type { DraftProvider, DraftSource } from "./source";
41
+ import { flagOn } from "../runtime-config";
42
+ import type { MlxArray } from "../mlx/array";
43
+ import * as ops from "../mlx/ops";
44
+ import type { CheckpointAttachment } from "../backends/mlx/checkpoint-state";
45
+ import type { DraftProvider, DraftSource, DraftRowCheckpoint, DraftRowGroup, DraftPrefillGroup, GroupedDraftProvider } from "./source";
46
+ import { applyStateChanges } from "../engine/resources";
47
+
48
+ /** The matching policy is independent of the executor's feed convention. */
49
+ function proposeNgram(h: readonly number[], max: number, min: number, n: number): number[] {
50
+ const L = h.length;
51
+ for (let k = Math.min(max, L - 1); k >= min; k--) {
52
+ const tailAt = L - k;
53
+ search: for (let i = 0; i + k < L; i++) {
54
+ for (let j = 0; j < k; j++) if (h[i + j] !== h[tailAt + j]) continue search;
55
+ return h.slice(i + k, i + k + n);
56
+ }
57
+ }
58
+ return [];
59
+ }
60
+
61
+ const namespace = (max: number, min: number) => `ngram-history-v1:${max}:${min}`;
62
+ const captureHistory = (history: readonly number[], max: number, min: number): CheckpointAttachment => ({
63
+ schema: "ngram-history-v1", metadata: { max, min }, tensors: [ops.fromInt32([...history], [history.length])],
64
+ });
65
+ function restoreHistory(state: DraftRowCheckpoint, max: number, min: number): number[] {
66
+ const { attachment, processedTokens } = state;
67
+ if (attachment.schema !== "ngram-history-v1" || attachment.metadata.max !== max || attachment.metadata.min !== min ||
68
+ attachment.tensors.length !== 1 || attachment.tensors[0]!.shape.length !== 1 || attachment.tensors[0]!.shape[0] !== processedTokens)
69
+ throw new Error("ngram checkpoint does not match its token coverage or lookup policy");
70
+ return attachment.tensors[0]!.toIntTokens();
71
+ }
72
+
73
+ /** Each row owns only its committed token history. Verification and sampling
74
+ * remain in the shared method; target storage and scheduling are not needed. */
75
+ class NgramRows implements DraftRowGroup, DraftPrefillGroup {
76
+ readonly prefillMode = "tail-split" as const;
77
+ readonly tapLayers: readonly number[] = [];
78
+ readonly namespace: string;
79
+ #histories: number[][] = [];
80
+ #drafts: number[][] = [];
81
+ constructor(readonly max: number, readonly min: number, checkpoints: readonly (DraftRowCheckpoint | null)[]) {
82
+ this.namespace = namespace(max, min);
83
+ this.append(checkpoints);
84
+ }
85
+ get rowCount() { return this.#histories.length; }
86
+ prepareAppend(checkpoints: readonly (DraftRowCheckpoint | null)[]) {
87
+ let next = [...this.#histories, ...checkpoints.map(state => state ? restoreHistory(state, this.max, this.min) : [])];
88
+ return { commit: () => { const old = this.#histories; this.#histories = next; next = old; }, dispose: () => { next = []; } };
89
+ }
90
+ append(checkpoints: readonly (DraftRowCheckpoint | null)[]) { applyStateChanges([() => this.prepareAppend(checkpoints)]); }
91
+ filterRows(keep: readonly number[]) { this.#histories = keep.map(row => this.#histories[row]!); this.#drafts = []; }
92
+ prefill(tokens: MlxArray): void {
93
+ using packed = ops.contiguous(tokens);
94
+ const ids = packed.toIntTokens(), length = tokens.shape[1]!;
95
+ for (let row = 0; row < this.rowCount; row++) this.#histories[row]!.push(...ids.slice(row * length, (row + 1) * length));
96
+ }
97
+ materialize(): void {}
98
+ draft(pending: readonly number[], depth: number): number[][] {
99
+ this.#drafts = this.#histories.map((history, row) => {
100
+ history.push(pending[row]!);
101
+ return proposeNgram(history, this.max, this.min, depth);
102
+ });
103
+ return this.#drafts;
104
+ }
105
+ commit(accepted: readonly number[]) {
106
+ for (let row = 0; row < this.rowCount; row++) this.#histories[row]!.push(...this.#drafts[row]!.slice(0, accepted[row]!));
107
+ this.#drafts = [];
108
+ }
109
+ capture(row: number): DraftRowCheckpoint {
110
+ const history = this.#histories[row]!;
111
+ return { processedTokens: history.length, attachment: captureHistory(history, this.max, this.min) };
112
+ }
113
+ dispose() { this.#histories = []; this.#drafts = []; }
114
+ }
43
115
 
44
116
  export interface NgramOptions {
45
117
  /** Longest suffix k-gram tried first (Saxena max_ngram_size). */
@@ -53,6 +125,11 @@ export class NgramProvider implements DraftProvider {
53
125
  readonly weightsBytes = 0;
54
126
  readonly max: number;
55
127
  readonly min: number;
128
+ readonly grouped: GroupedDraftProvider = {
129
+ supportsTargetAdapters: true,
130
+ open: options => new NgramRows(this.max, this.min, options.checkpoints),
131
+ openPrefill: options => new NgramRows(this.max, this.min, options.checkpoints),
132
+ };
56
133
 
57
134
  constructor(opts: NgramOptions = {}) {
58
135
  this.max = Math.max(1, opts.max ?? 3);
@@ -73,24 +150,33 @@ class NgramSource implements DraftSource {
73
150
  readonly weightsBytes = 0;
74
151
  #hist: number[] = [];
75
152
  #lastDrafts: number[] = [];
153
+ readonly #tailSplit = flagOn("MLX_BUN_PREFILL_TAIL_SPLIT", true);
154
+ readonly checkpoint: NonNullable<DraftSource["checkpoint"]>;
76
155
 
77
156
  constructor(
78
157
  private readonly max: number,
79
158
  private readonly min: number,
80
- ) {}
159
+ ) {
160
+ this.checkpoint = {
161
+ namespace: namespace(max, min),
162
+ capture: () => captureHistory(this.#hist, this.max, this.min),
163
+ restore: (processedTokens, attachment) => {
164
+ this.#hist = restoreHistory({ processedTokens, attachment }, this.max, this.min);
165
+ },
166
+ };
167
+ }
81
168
 
82
169
  /** Test hook — the reconstructed prompt+emitted stream (see header). */
83
170
  get history(): readonly number[] {
84
171
  return this.#hist;
85
172
  }
86
173
 
87
- prefill(promptIds: number[]): void {
174
+ prefill(promptIds: number[], _context?: Parameters<DraftSource["prefill"]>[1], processedTokens?: number): void {
88
175
  // Mirror the serve loop's prefill shape (two-model.ts does the same): under
89
176
  // the oracle tail split the last prompt token is never prefilled — it IS
90
177
  // the first feed. Legacy shape (kill switch / 1-token prompt): full prompt,
91
178
  // and the sampled token0 arrives as the first feed.
92
- const tailSplit = flagOn("MLX_BUN_PREFILL_TAIL_SPLIT", true);
93
- const upTo = tailSplit && promptIds.length > 1 ? promptIds.length - 1 : promptIds.length;
179
+ const upTo = processedTokens ?? (this.#tailSplit && promptIds.length > 1 ? promptIds.length - 1 : promptIds.length);
94
180
  this.#hist = promptIds.slice(0, upTo);
95
181
  }
96
182
 
@@ -111,21 +197,7 @@ class NgramSource implements DraftSource {
111
197
  /** Longest-k-first, first-occurrence prompt lookup (Saxena/vLLM order):
112
198
  * find the trailing k-gram earlier in history, propose what followed it. */
113
199
  #propose(n: number): number[] {
114
- const h = this.#hist;
115
- const L = h.length;
116
- const kTop = Math.min(this.max, L - 1);
117
- for (let k = kTop; k >= this.min; k--) {
118
- const tailAt = L - k;
119
- // First occurrence, left to right; i + k < L both excludes the trailing
120
- // self-match and guarantees at least one continuation token.
121
- search: for (let i = 0; i + k < L; i++) {
122
- for (let j = 0; j < k; j++) {
123
- if (h[i + j] !== h[tailAt + j]) continue search;
124
- }
125
- return h.slice(i + k, i + k + n);
126
- }
127
- }
128
- return [];
200
+ return proposeNgram(this.#hist, this.max, this.min, n);
129
201
  }
130
202
 
131
203
  dispose(): void {}
@@ -0,0 +1,73 @@
1
+ import type { MlxArray } from "../mlx/array";
2
+ import * as ops from "../mlx/ops";
3
+ import { KVCache, type Cache } from "../model/gemma4-base";
4
+ import { MlxProjectedContextRows } from "../backends/mlx/projected-context-rows";
5
+ import { captureCacheAttachment, restoreCacheAttachment } from "../backends/mlx/cache-attachment";
6
+ import { applyStateChanges, disposeResources } from "../engine/resources";
7
+ import type { PreparedStateChange } from "../contracts/resources";
8
+ import type { DraftPrefillGroup, DraftRowGroup, DraftRowCheckpoint, GroupedDraftProvider, TargetView } from "./source";
9
+
10
+ export interface ProjectedDraftMethod {
11
+ namespace: string;
12
+ schema: string;
13
+ layers: number;
14
+ tapLayers: readonly number[];
15
+ project(hidden: MlxArray, positions: number | MlxArray): { k: MlxArray; v: MlxArray }[];
16
+ draft(context: ReturnType<MlxProjectedContextRows["readAttention"]>, pending: readonly number[], positions: number | MlxArray, depth: number): number[][];
17
+ }
18
+
19
+ /** Provider numerics compose with shared context membership and persistence. */
20
+ class ProjectedDraftRows implements DraftPrefillGroup, DraftRowGroup {
21
+ readonly prefillMode = "tail-split" as const;
22
+ readonly tapLayers: readonly number[];
23
+ readonly context: MlxProjectedContextRows;
24
+ constructor(readonly method: ProjectedDraftMethod,
25
+ checkpoints: readonly (DraftRowCheckpoint | null)[]) {
26
+ this.tapLayers = method.tapLayers;
27
+ this.context = new MlxProjectedContextRows(method.layers, { project: method.project });
28
+ try { this.append(checkpoints); } catch (error) { this.dispose(); throw error; }
29
+ }
30
+ get namespace(): string { return this.method.namespace; }
31
+ get rowCount(): number { return this.context.state.rowCount; }
32
+ prepareAppend(checkpoints: readonly (DraftRowCheckpoint | null)[]): PreparedStateChange {
33
+ const restored: Cache[][] = [];
34
+ const empty = () => Array.from({ length: this.method.layers }, () => new KVCache());
35
+ try {
36
+ for (const checkpoint of checkpoints) restored.push(checkpoint ? restoreCacheAttachment(checkpoint.attachment, empty) : empty());
37
+ return this.context.prepareAppend(restored);
38
+ } finally { disposeResources(restored.flat()); }
39
+ }
40
+ append(checkpoints: readonly (DraftRowCheckpoint | null)[]): void {
41
+ if (checkpoints.length) applyStateChanges([() => this.prepareAppend(checkpoints)]);
42
+ }
43
+ prefill(tokens: MlxArray, hidden?: MlxArray): void {
44
+ this.context.append(hidden!, Array(this.rowCount).fill(tokens.shape[1]!)); this.materialize();
45
+ }
46
+ materialize(): void { this.context.materialize(); }
47
+ filterRows(keep: readonly number[]): void { this.context.state.filterRows(keep); }
48
+ capture(row: number): DraftRowCheckpoint {
49
+ const caches = this.context.state.extractRow(row);
50
+ try {
51
+ const processedTokens = caches[0]!.offset;
52
+ return { processedTokens, attachment: captureCacheAttachment(this.method.schema, caches, { processedTokens }) };
53
+ } finally { disposeResources(caches); }
54
+ }
55
+ draft(pending: readonly number[], depth: number): number[][] {
56
+ if (!depth) return pending.map(() => []);
57
+ const positions = this.context.positions, donors = this.context.readAttention();
58
+ using offsets = positions.every(position => position === positions[0]) ? null : ops.fromInt32([...positions], [pending.length]);
59
+ try { return this.method.draft(donors, pending, offsets ?? positions[0]!, depth); }
60
+ finally { donors.dispose(); }
61
+ }
62
+ commit(accepted: readonly number[], hidden: MlxArray): void {
63
+ this.context.append(hidden, accepted.map(count => count + 1));
64
+ }
65
+ dispose(): void { this.context.dispose(); }
66
+ }
67
+
68
+ export function projectedDraftGroups(bind: (target: TargetView) => ProjectedDraftMethod): GroupedDraftProvider {
69
+ const open = ({ target, checkpoints }: {
70
+ target: TargetView; checkpoints: readonly (DraftRowCheckpoint | null)[];
71
+ }) => new ProjectedDraftRows(bind(target), checkpoints);
72
+ return { open, openPrefill: open };
73
+ }
@@ -0,0 +1,171 @@
1
+ // Qwen MTP numerical graph. Request state, sampling and checkpoint retention
2
+ // belong to its callers; the cache supplies positions and attention storage.
3
+ import type { MlxArray } from "../mlx/array";
4
+ import * as ops from "../mlx/ops";
5
+ import type { ModelConfig } from "../config";
6
+ import type { Weights } from "../weights";
7
+ import { disposing, QuantizedLinear, RMSNorm, type Cache, type Mask } from "../model/gemma4-base";
8
+ import { DenseLinear } from "../model/universal/modules";
9
+ import { compiledSwiglu } from "../model/qwen3_5";
10
+
11
+ type MtpLinear = DenseLinear | QuantizedLinear;
12
+
13
+ /** Projection tensors belong to Weights; dense transpose views belong to
14
+ * the provider's resource stack. Quantized heads keep no dense copy. */
15
+ function loadMtpLinear(
16
+ weights: Weights, path: string, config: ModelConfig, resources: DisposableStack,
17
+ ): MtpLinear {
18
+ if (weights.has(`${path}.scales`)) return QuantizedLinear.load(weights, path, config);
19
+ const layer = new DenseLinear(weights.tensor(`${path}.weight`), null);
20
+ resources.use(layer.wT);
21
+ return layer;
22
+ }
23
+
24
+ /** Qwen3Attention.forward with the companion's dense or quantized projections.
25
+ * Attention operations follow src/model/qwen3_5.ts verbatim. */
26
+ class MtpAttention {
27
+ readonly qProj: MtpLinear;
28
+ readonly kProj: MtpLinear;
29
+ readonly vProj: MtpLinear;
30
+ readonly oProj: MtpLinear;
31
+ readonly qNorm: RMSNorm;
32
+ readonly kNorm: RMSNorm;
33
+ readonly nHeads: number;
34
+ readonly nKvHeads: number;
35
+ readonly headDim: number;
36
+ readonly scale: number;
37
+ readonly ropeDims: number;
38
+ readonly ropeBase: number;
39
+
40
+ constructor(weights: Weights, config: ModelConfig, prefix: string, resources: DisposableStack) {
41
+ const t = config.text;
42
+ this.nHeads = t.numAttentionHeads;
43
+ this.nKvHeads = t.numKeyValueHeads;
44
+ this.headDim = t.headDim;
45
+ this.scale = Math.pow(this.headDim, -0.5);
46
+ this.ropeDims = Math.trunc(this.headDim * t.partialRotaryFactor);
47
+ this.ropeBase = t.ropeParameters.full_attention?.ropeTheta ?? 10000;
48
+ this.qProj = loadMtpLinear(weights, `${prefix}.q_proj`, config, resources);
49
+ this.kProj = loadMtpLinear(weights, `${prefix}.k_proj`, config, resources);
50
+ this.vProj = loadMtpLinear(weights, `${prefix}.v_proj`, config, resources);
51
+ this.oProj = loadMtpLinear(weights, `${prefix}.o_proj`, config, resources);
52
+ this.qNorm = new RMSNorm(weights.tensor(`${prefix}.q_norm.weight`), t.rmsNormEps);
53
+ this.kNorm = new RMSNorm(weights.tensor(`${prefix}.k_norm.weight`), t.rmsNormEps);
54
+ }
55
+
56
+ forward(x: MlxArray, mask: Mask, cache: Cache): MlxArray {
57
+ const [B, L] = x.shape as [number, number, number];
58
+ const qp = this.qProj.forward(x);
59
+ const qpr = disposing(qp, ops.reshape(qp, [B, L, this.nHeads, this.headDim * 2]));
60
+ const [qHeads, gateHeads] = ops.split(qpr, [this.headDim], -1) as [MlxArray, MlxArray];
61
+ qpr.dispose();
62
+ const gate = disposing(gateHeads, ops.reshape(gateHeads, [B, L, this.nHeads * this.headDim]));
63
+
64
+ let k = this.kProj.forward(x);
65
+ let v = this.vProj.forward(x);
66
+
67
+ let q = this.qNorm.forward(qHeads);
68
+ qHeads.dispose();
69
+ q = disposing(q, ops.transposeAxes(q, [0, 2, 1, 3]));
70
+ k = disposing(k, ops.reshape(k, [B, L, this.nKvHeads, this.headDim]));
71
+ k = disposing(k, this.kNorm.forward(k));
72
+ k = disposing(k, ops.transposeAxes(k, [0, 2, 1, 3]));
73
+ v = disposing(v, ops.reshape(v, [B, L, this.nKvHeads, this.headDim]));
74
+ v = disposing(v, ops.transposeAxes(v, [0, 2, 1, 3]));
75
+
76
+ const offsets = cache.ropeOffsetArr;
77
+ q = disposing(q, offsets
78
+ ? ops.ropeDynamic(q, this.ropeDims, this.ropeBase, offsets, null)
79
+ : ops.rope(q, this.ropeDims, this.ropeBase, cache.offset, null));
80
+ k = disposing(k, offsets
81
+ ? ops.ropeDynamic(k, this.ropeDims, this.ropeBase, offsets, null)
82
+ : ops.rope(k, this.ropeDims, this.ropeBase, cache.offset, null));
83
+
84
+ const [keys, values] = cache.updateAndFetch(k, v);
85
+ k.dispose();
86
+ v.dispose();
87
+ const attn = ops.sdpa(q, keys, values, this.scale, mask.mode, mask.arr);
88
+ keys.dispose();
89
+ values.dispose();
90
+ q.dispose();
91
+
92
+ const attnT = ops.transposeAxes(attn, [0, 2, 1, 3]);
93
+ attn.dispose();
94
+ const merged = ops.reshape(attnT, [B, L, -1]);
95
+ attnT.dispose();
96
+ const sig = ops.sigmoid(gate);
97
+ gate.dispose();
98
+ const gated = ops.mul(merged, sig);
99
+ merged.dispose();
100
+ sig.dispose();
101
+ const out = this.oProj.forward(gated);
102
+ gated.dispose();
103
+ return out;
104
+ }
105
+ }
106
+
107
+ /** The one MTP decoder block: fc-merge → attention → swiglu MLP → norm. */
108
+ export class MtpModule {
109
+ readonly fc: MtpLinear;
110
+ readonly preFcNormEmbedding: RMSNorm;
111
+ readonly preFcNormHidden: RMSNorm;
112
+ readonly attn: MtpAttention;
113
+ readonly mlpGate: MtpLinear;
114
+ readonly mlpUp: MtpLinear;
115
+ readonly mlpDown: MtpLinear;
116
+ readonly inputNorm: RMSNorm;
117
+ readonly postAttnNorm: RMSNorm;
118
+ readonly finalNorm: RMSNorm;
119
+
120
+ constructor(weights: Weights, config: ModelConfig, resources: DisposableStack) {
121
+ const eps = config.text.rmsNormEps;
122
+ this.fc = loadMtpLinear(weights, "fc", config, resources);
123
+ this.preFcNormEmbedding = new RMSNorm(weights.tensor("pre_fc_norm_embedding.weight"), eps);
124
+ this.preFcNormHidden = new RMSNorm(weights.tensor("pre_fc_norm_hidden.weight"), eps);
125
+ this.attn = new MtpAttention(weights, config, "layers.0.self_attn", resources);
126
+ this.mlpGate = loadMtpLinear(weights, "layers.0.mlp.gate_proj", config, resources);
127
+ this.mlpUp = loadMtpLinear(weights, "layers.0.mlp.up_proj", config, resources);
128
+ this.mlpDown = loadMtpLinear(weights, "layers.0.mlp.down_proj", config, resources);
129
+ this.inputNorm = new RMSNorm(weights.tensor("layers.0.input_layernorm.weight"), eps);
130
+ this.postAttnNorm = new RMSNorm(weights.tensor("layers.0.post_attention_layernorm.weight"), eps);
131
+ this.finalNorm = new RMSNorm(weights.tensor("norm.weight"), eps);
132
+ }
133
+
134
+ /** One block forward over [B,S,·]: token embeddings ([B,S,H], target
135
+ * embed_tokens output) paired with hiddens ([B,S,H], target pre-final-norm
136
+ * or the module's own chained output). Appends S rows to `cache`; returns
137
+ * the module output [B,S,H] (post final norm — what the target lm_head
138
+ * consumes AND what chains into the next step's `hidden`). */
139
+ forward(tokenEmbeds: MlxArray, hiddens: MlxArray, cache: Cache): MlxArray {
140
+ const embNorm = this.preFcNormEmbedding.forward(tokenEmbeds);
141
+ const hidNorm = this.preFcNormHidden.forward(hiddens);
142
+ const joined = ops.concatAxis([embNorm, hidNorm], 2);
143
+ embNorm.dispose();
144
+ hidNorm.dispose();
145
+ const x = this.fc.forward(joined);
146
+ joined.dispose();
147
+
148
+ // Decoder layer (Qwen3Layer.forward shape).
149
+ const L = x.shape[1]!;
150
+ const mask = cache.makeMask(L, null);
151
+ const xn = this.inputNorm.forward(x);
152
+ const r = this.attn.forward(xn, mask, cache);
153
+ xn.dispose();
154
+ mask.arr?.dispose();
155
+ const h = ops.add(x, r);
156
+ x.dispose();
157
+ r.dispose();
158
+ const hn = this.postAttnNorm.forward(h);
159
+ const g = this.mlpGate.forward(hn);
160
+ const u = this.mlpUp.forward(hn);
161
+ hn.dispose();
162
+ const act = compiledSwiglu(g, u);
163
+ g.dispose(); u.dispose();
164
+ const m = this.mlpDown.forward(act);
165
+ act.dispose();
166
+ const out = ops.add(h, m);
167
+ h.dispose();
168
+ m.dispose();
169
+ return disposing(out, this.finalNorm.forward(out));
170
+ }
171
+ }