mlx-bun 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (433) hide show
  1. package/README.md +71 -588
  2. package/docs/README.md +94 -0
  3. package/docs/{design → archive/investigations}/audio-input-plan.md +4 -4
  4. package/docs/{design → archive/investigations}/diffusion-gemma-port.md +3 -3
  5. package/docs/{design → archive/investigations}/faithful-l1-consolidation.md +4 -4
  6. package/docs/{design → archive/investigations}/minicpm5-decode-megakernel.md +11 -11
  7. package/docs/archive/investigations/openjarvis-fit.md +198 -0
  8. package/docs/{design → archive/investigations}/optimization_plan.md +1 -1
  9. package/docs/{design → archive/investigations}/pre-colibri-stabilization.md +5 -5
  10. package/docs/archive/investigations/qwen38-27b-campaign-log.md +1092 -0
  11. package/docs/{design → archive/investigations}/the-dreaming-handoff.md +2 -2
  12. package/docs/archive/planning/release-notes-v0.3.0.md +35 -0
  13. package/docs/design/batching.md +1841 -0
  14. package/docs/design/decode-speed-program.md +2346 -169
  15. package/docs/design/dreaming-nightly-pipeline.md +675 -282
  16. package/docs/design/generic-model-support.md +655 -334
  17. package/docs/design/kv-cache.md +824 -0
  18. package/docs/design/orpo-training.md +673 -1239
  19. package/docs/design/speculative-decoding.md +1990 -0
  20. package/docs/design/turboquant.md +2212 -0
  21. package/docs/design/unified-engine-frontier-plan.md +1833 -727
  22. package/docs/design/web-chat-redesign.md +666 -1083
  23. package/docs/planning/PRODUCT_ROADMAP.md +50 -1
  24. package/docs/planning/release-notes-v0.4.0.md +45 -0
  25. package/docs/planning/video-series.md +2 -2
  26. package/docs/reference/benchmarks.md +3613 -0
  27. package/docs/reference/cli.md +434 -160
  28. package/docs/reference/distribution.md +328 -182
  29. package/docs/reference/environment.md +398 -0
  30. package/docs/reference/glossary.md +39 -0
  31. package/docs/reference/library-api.md +566 -168
  32. package/docs/reference/memory.md +227 -64
  33. package/docs/reference/models.md +113 -6
  34. package/docs/reference/server-api.md +944 -429
  35. package/docs/reference/server-config.md +740 -338
  36. package/docs/reference/training.md +393 -254
  37. package/docs/reference/troubleshooting.md +158 -0
  38. package/package.json +9 -4
  39. package/src/audio/decode.ts +2 -2
  40. package/src/audio/features.ts +2 -2
  41. package/src/backends/mlx/assistant-target.ts +46 -0
  42. package/src/backends/mlx/autoregressive-draft-rows.ts +120 -0
  43. package/src/backends/mlx/autoregressive.ts +108 -0
  44. package/src/backends/mlx/batch-group.ts +1790 -0
  45. package/src/backends/mlx/cache-attachment.ts +67 -0
  46. package/src/backends/mlx/cache-layout.ts +31 -0
  47. package/src/backends/mlx/checkpoint-state.ts +53 -0
  48. package/src/backends/mlx/continuation-persistence.ts +106 -0
  49. package/src/backends/mlx/continuation-request.ts +43 -0
  50. package/src/backends/mlx/continuation.ts +77 -0
  51. package/src/backends/mlx/diffusion.ts +39 -0
  52. package/src/backends/mlx/draft-target.ts +32 -0
  53. package/src/backends/mlx/evaluation.ts +105 -0
  54. package/src/backends/mlx/fill-append.ts +45 -0
  55. package/src/backends/mlx/full-kv-row-append.ts +32 -0
  56. package/src/backends/mlx/full-kv-row-donor.ts +54 -0
  57. package/src/backends/mlx/full-transitioning-kv-rows.ts +65 -0
  58. package/src/backends/mlx/gateway-binding.ts +130 -0
  59. package/src/backends/mlx/graph.ts +38 -0
  60. package/src/backends/mlx/kv-codec.ts +9 -0
  61. package/src/backends/mlx/kv-maintenance.ts +133 -0
  62. package/src/backends/mlx/kv-tensor-rows.ts +212 -0
  63. package/src/backends/mlx/memory-client.ts +189 -0
  64. package/src/backends/mlx/methods.ts +90 -0
  65. package/src/backends/mlx/model-prompt.ts +164 -0
  66. package/src/backends/mlx/model-serving.ts +79 -0
  67. package/src/backends/mlx/prefill-cohort.ts +89 -0
  68. package/src/backends/mlx/prefill-rows.ts +200 -0
  69. package/src/backends/mlx/prefill.ts +33 -0
  70. package/src/backends/mlx/projected-context-rows.ts +72 -0
  71. package/src/backends/mlx/request-policy.ts +20 -0
  72. package/src/backends/mlx/request-state-policy.ts +41 -0
  73. package/src/backends/mlx/rollback.ts +89 -0
  74. package/src/backends/mlx/row-sampling.ts +49 -0
  75. package/src/backends/mlx/serial-executor.ts +242 -0
  76. package/src/backends/mlx/speculative-group.ts +359 -0
  77. package/src/backends/mlx/speculative-round.ts +161 -0
  78. package/src/backends/mlx/speculative.ts +114 -0
  79. package/src/backends/mlx/state-rows.ts +104 -0
  80. package/src/backends/mlx/state-views.ts +46 -0
  81. package/src/backends/mlx/target-layout-capability.ts +35 -0
  82. package/src/backends/mlx/text-engine.ts +73 -0
  83. package/src/backends/mlx/transitioning-kv-rows.ts +165 -0
  84. package/src/cli.ts +66 -58
  85. package/src/client.ts +66 -0
  86. package/src/config.ts +21 -4
  87. package/src/contracts/completion.ts +16 -0
  88. package/src/contracts/execution.ts +60 -0
  89. package/src/contracts/generation.ts +103 -0
  90. package/src/contracts/host.ts +7 -0
  91. package/src/contracts/jobs.ts +66 -0
  92. package/src/contracts/pi-provider.ts +30 -0
  93. package/src/contracts/pi.ts +259 -0
  94. package/src/contracts/prefix-cache.ts +23 -0
  95. package/src/contracts/resources.ts +25 -0
  96. package/src/contracts/sampling.ts +23 -0
  97. package/src/contracts/scheduling.ts +45 -0
  98. package/src/contracts/tsconfig.json +14 -0
  99. package/src/diffusion/diffusion-generate.ts +218 -153
  100. package/src/embed.ts +1 -1
  101. package/src/engine/admission.ts +59 -0
  102. package/src/engine/cancellation.ts +38 -0
  103. package/src/engine/engine.ts +56 -0
  104. package/src/engine/execution-coordinator.ts +70 -0
  105. package/src/engine/execution-plan.ts +53 -0
  106. package/src/engine/resources.ts +53 -0
  107. package/src/engine/scheduler.ts +72 -0
  108. package/src/engine/session.ts +247 -0
  109. package/src/eval/README.md +44 -1
  110. package/src/eval/kl.ts +236 -3
  111. package/src/eval/reference-logits.ts +207 -0
  112. package/src/eval/runner.ts +8 -96
  113. package/src/fill/echo-index.ts +188 -0
  114. package/src/fill/fill-session.ts +452 -0
  115. package/src/fill/proposal.ts +68 -0
  116. package/src/fill/schema-rows.ts +506 -0
  117. package/src/fill/tool-boundary.ts +103 -0
  118. package/src/fit.ts +30 -16
  119. package/src/generate.ts +709 -417
  120. package/src/grammar.ts +12 -7
  121. package/src/harness-pi.ts +14 -33
  122. package/src/hub-rest.ts +4 -4
  123. package/src/index.ts +7 -0
  124. package/src/inference/denoising.ts +17 -0
  125. package/src/inference/draft-acceptance.ts +41 -0
  126. package/src/inference/draft-output.ts +49 -0
  127. package/src/inference/graph.ts +33 -0
  128. package/src/inference/prefill.ts +39 -0
  129. package/src/inference/rollback.ts +7 -0
  130. package/src/jobs/db.ts +4 -0
  131. package/src/jobs/index.ts +2 -0
  132. package/src/jobs/job-entry.ts +12 -12
  133. package/src/jobs/runner.ts +98 -13
  134. package/src/jobs/task-client.ts +19 -0
  135. package/src/jobs/types.ts +2 -58
  136. package/src/kv-scheme.ts +70 -12
  137. package/src/kv-store.ts +177 -63
  138. package/src/lab/README.md +18 -0
  139. package/src/{assets → lab/curve}/curve-designer.html +2 -2
  140. package/src/{curve-sampler.ts → lab/curve/curve-sampler.ts} +2 -2
  141. package/src/{expert-trace.ts → lab/expert-trace/expert-trace.ts} +5 -5
  142. package/src/lab/paged-kv/paged-kv-rows.ts +83 -0
  143. package/src/{model → lab/paged-kv}/paged-kv.ts +32 -15
  144. package/src/library.ts +40 -0
  145. package/src/lora.ts +18 -0
  146. package/src/media-fetch.ts +1 -1
  147. package/src/memory/article.ts +1 -1
  148. package/src/memory/chunk.ts +1 -1
  149. package/src/memory/model.ts +30 -169
  150. package/src/memory/prompts.ts +1 -1
  151. package/src/memory/rest.ts +1 -1
  152. package/src/memory/schedule.ts +1 -1
  153. package/src/memory/stages.ts +4 -1
  154. package/src/memory/vault.ts +1 -3
  155. package/src/mlx/array.ts +11 -11
  156. package/src/mlx/compile.ts +12 -2
  157. package/src/mlx/ffi.ts +58 -11
  158. package/src/mlx/materialize.ts +23 -0
  159. package/src/mlx/metal-kernel.ts +10 -11
  160. package/src/mlx/ops.ts +33 -13
  161. package/src/mlx/quantized-rows.ts +36 -0
  162. package/src/mlx/token-bitmask.ts +52 -0
  163. package/src/mlx/turboquant-kv-decode.ts +82 -0
  164. package/src/mlx/turboquant-kv-inverse.ts +122 -0
  165. package/src/mlx/turboquant-ops.ts +33 -3
  166. package/src/mlx/turboquant-tables.ts +2 -2
  167. package/src/model/artifact-identity.ts +73 -0
  168. package/src/model/batched-kv.ts +235 -0
  169. package/src/model/batched-mask.ts +20 -6
  170. package/src/model/batched-quant.ts +9 -3
  171. package/src/model/batched-quantized-kv.ts +144 -0
  172. package/src/model/batched-rotating-quant.ts +78 -17
  173. package/src/model/batched-rotating-state.ts +76 -0
  174. package/src/model/batched-rotating.ts +65 -23
  175. package/src/model/batched-row-storage.ts +52 -0
  176. package/src/model/batched-ssm.ts +52 -0
  177. package/src/model/batched-turboquant-kv.ts +93 -0
  178. package/src/model/compiled-decode.ts +8 -2
  179. package/src/model/decoded-kv-donor.ts +12 -0
  180. package/src/model/delayed-quantized-kv.ts +72 -0
  181. package/src/model/delayed-rotating-quantized-kv.ts +93 -0
  182. package/src/model/delayed-turboquant-kv.ts +55 -0
  183. package/src/model/diffusion-gemma.ts +8 -8
  184. package/src/model/factory.ts +76 -33
  185. package/src/model/fingerprint.ts +1 -1
  186. package/src/model/flash-attention.ts +3 -3
  187. package/src/model/full-prefill-padding.ts +56 -0
  188. package/src/model/full-prefill-row.ts +105 -0
  189. package/src/model/gemma4-base.ts +179 -80
  190. package/src/model/gemma4.ts +40 -32
  191. package/src/model/generated/gemma4-12b.ts +6 -3
  192. package/src/model/generated/gemma4-26b.ts +6 -3
  193. package/src/model/generated/gemma4-e4b.ts +6 -3
  194. package/src/model/glm52-cache.ts +80 -4
  195. package/src/model/glm52-dsa.ts +13 -9
  196. package/src/model/glm52-memory.ts +1 -1
  197. package/src/model/glm52-mla.ts +12 -6
  198. package/src/model/glm52.ts +19 -40
  199. package/src/model/implementation.ts +69 -0
  200. package/src/model/kv-attention-view.ts +67 -0
  201. package/src/model/minicpm5.ts +17 -15
  202. package/src/model/profile.ts +12 -2
  203. package/src/model/qwen-append.ts +12 -0
  204. package/src/model/qwen-conv.ts +52 -0
  205. package/src/model/qwen3-delta-state.ts +74 -0
  206. package/src/model/qwen3-delta.ts +59 -36
  207. package/src/model/qwen3_5-checkpoint.ts +164 -0
  208. package/src/model/qwen3_5.ts +202 -78
  209. package/src/model/rotating-kv-donor.ts +35 -0
  210. package/src/model/rotating-kv-layout.ts +262 -0
  211. package/src/model/rotating-row-transaction.ts +35 -0
  212. package/src/model/speculative-rotating-kv.ts +101 -0
  213. package/src/model/ssm-prefill-padding.ts +39 -0
  214. package/src/model/support.ts +1 -1
  215. package/src/model/trellis-balanced-scatter.ts +51 -0
  216. package/src/model/trellis-linear.ts +672 -0
  217. package/src/model/trellis-shared-m.ts +151 -0
  218. package/src/model/trellis-shared-scatter.ts +144 -0
  219. package/src/model/trellis-splitk-prefill.ts +158 -0
  220. package/src/model/trellis-tiled-prefill.ts +136 -0
  221. package/src/model/trellis-vector-expand.ts +62 -0
  222. package/src/model/trellis-wide-prefill.ts +94 -0
  223. package/src/model/turboquant-codec.ts +83 -0
  224. package/src/model/universal/dense.ts +15 -14
  225. package/src/model/universal/modules.ts +8 -1
  226. package/src/native-pack.ts +6 -5
  227. package/src/pi-provider.ts +6 -64
  228. package/src/pi-web.ts +8 -315
  229. package/src/preflight.ts +31 -15
  230. package/src/prompt-cache.ts +110 -69
  231. package/src/quantize/allocator.ts +1 -1
  232. package/src/quantize/config-writer.ts +10 -3
  233. package/src/quantize/rotate.ts +4 -4
  234. package/src/quantize/trellis.ts +586 -0
  235. package/src/responses.ts +28 -1
  236. package/src/runtime-config.ts +18 -4
  237. package/src/sampler.ts +40 -29
  238. package/src/serve/batch-scheduler.ts +8 -1671
  239. package/src/serve/chat-request.ts +391 -0
  240. package/src/serve/chat-stage.ts +195 -0
  241. package/src/serve/checkpoint-identity.ts +64 -0
  242. package/src/serve/completion-executor.ts +15 -7
  243. package/src/serve/discovery-routes.ts +12 -13
  244. package/src/serve/generation-gateway.ts +183 -213
  245. package/src/serve/http.ts +159 -0
  246. package/src/serve/inference-request.ts +79 -0
  247. package/src/serve/isolate.ts +297 -105
  248. package/src/serve/lab-routes.ts +3 -0
  249. package/src/serve/lane-registry.ts +2 -1
  250. package/src/serve/model-admin-routes.ts +7 -5
  251. package/src/serve/model-binding.ts +43 -0
  252. package/src/serve/model-host.ts +511 -0
  253. package/src/serve/openai-wire.ts +103 -0
  254. package/src/serve/parent-application.ts +56 -0
  255. package/src/serve/pipeline.ts +33 -0
  256. package/src/serve/preparation.ts +33 -0
  257. package/src/serve/request-plan.ts +23 -18
  258. package/src/serve/request-prep.ts +344 -0
  259. package/src/serve/response-lease.ts +24 -0
  260. package/src/serve/responses-client.ts +69 -0
  261. package/src/serve/session-completion-engine.ts +110 -0
  262. package/src/serve/session-search.ts +1 -1
  263. package/src/serve/static-routes.ts +5 -5
  264. package/src/serve/text-completion-stage.ts +104 -0
  265. package/src/serve/token-streams.ts +519 -0
  266. package/src/server.ts +335 -2711
  267. package/src/spec/assistant-rows.ts +92 -0
  268. package/src/spec/assistant-source.ts +31 -55
  269. package/src/spec/cache-identity.ts +22 -0
  270. package/src/spec/deepspec-rows.ts +29 -0
  271. package/src/spec/deepspec-source.ts +16 -14
  272. package/src/spec/dflash-source.ts +36 -12
  273. package/src/spec/drafter.ts +153 -142
  274. package/src/spec/dspark/ab-stats.ts +3 -3
  275. package/src/spec/dspark/calibration.ts +2 -2
  276. package/src/spec/dspark/deepspec-module.ts +97 -122
  277. package/src/spec/dspark/generate-dflash.ts +2 -2
  278. package/src/spec/dspark/generate.ts +2 -2
  279. package/src/spec/dspark/loader.ts +1 -1
  280. package/src/spec/dspark/module-dflash.ts +129 -172
  281. package/src/spec/dspark/module.ts +3 -3
  282. package/src/spec/dspark/quantize-drafter.ts +1 -1
  283. package/src/spec/generate.ts +1 -1
  284. package/src/spec/glm52-mtp-graph.ts +29 -0
  285. package/src/spec/glm52-mtp-rows.ts +132 -0
  286. package/src/spec/glm52-mtp-source.ts +54 -137
  287. package/src/spec/glm52-mtp-state.ts +33 -0
  288. package/src/spec/ngram-source.ts +93 -21
  289. package/src/spec/projected-draft-rows.ts +73 -0
  290. package/src/spec/qwen-mtp-module.ts +171 -0
  291. package/src/spec/qwen-mtp-rows.ts +219 -0
  292. package/src/spec/qwen-mtp-source.ts +147 -195
  293. package/src/spec/qwen-mtp-state.ts +30 -0
  294. package/src/spec/serve-loop.ts +201 -201
  295. package/src/spec/source.ts +110 -13
  296. package/src/spec/two-model-rows.ts +61 -0
  297. package/src/spec/two-model.ts +44 -102
  298. package/src/ssd-cache.ts +99 -19
  299. package/src/ssd-durability.ts +36 -20
  300. package/src/tool-call.ts +51 -14
  301. package/src/train/flash-cce.ts +2 -2
  302. package/src/train/forward.ts +6 -0
  303. package/src/train/loss.ts +1 -1
  304. package/src/train/prefix-shared.ts +5 -1
  305. package/src/train/segmented.ts +5 -3
  306. package/src/train/trainer.ts +6 -6
  307. package/src/vision/prompt.ts +1 -1
  308. package/src/vision/qwen3vl-tower.ts +52 -10
  309. package/src/web/app.html +1 -1
  310. package/src/web/app.js +62 -60
  311. package/src/web/src/adapters-panel.ts +3 -3
  312. package/src/web/src/assistant.ts +2 -36
  313. package/src/web/src/chat.ts +4 -4
  314. package/src/web/src/composer.ts +4 -4
  315. package/src/web/src/hub.ts +1 -1
  316. package/src/web/src/markdown.ts +0 -0
  317. package/src/web/src/memory-panel.ts +1 -1
  318. package/src/web/src/model-picker.ts +1 -1
  319. package/src/web/src/palette.ts +1 -1
  320. package/src/web/src/protocol.ts +3 -39
  321. package/src/web/src/sessions.ts +1 -1
  322. package/src/web/src/ui-catalog.ts +4 -18
  323. package/src/web-assets.ts +47 -0
  324. package/src/weights.ts +55 -9
  325. package/docs/archive/investigations/curve-runs/bisector-route.json +0 -98
  326. package/docs/archive/investigations/curve-runs/bisector-trace.json +0 -1393
  327. package/docs/archive/investigations/curve-runs/curve-terrain.json +0 -1179
  328. package/docs/archive/investigations/curve-runs/curve-terrain.svg +0 -42
  329. package/docs/archive/investigations/hlg-ab.html +0 -34
  330. package/docs/archive/investigations/hlg-explorer.html +0 -238
  331. package/docs/archive/investigations/hlg-figs/cliff.svg +0 -1
  332. package/docs/archive/investigations/hlg-figs/cross.svg +0 -1
  333. package/docs/archive/investigations/hlg-figs/edges.svg +0 -1
  334. package/docs/archive/investigations/hlg-figs/k20-grids.svg +0 -1
  335. package/docs/archive/investigations/hlg-figs/k20-peaks.svg +0 -1
  336. package/docs/archive/investigations/hlg-figs/lw-curve.svg +0 -1
  337. package/docs/archive/investigations/hlg-figs/terrain.svg +0 -1
  338. package/docs/archive/investigations/hlg-report.html +0 -262
  339. package/docs/archive/investigations/hlg-runs/hlg-ab.json +0 -149
  340. package/docs/archive/investigations/hlg-runs/hlg-blind-prompts.md +0 -87
  341. package/docs/archive/investigations/hlg-runs/hlg-blind.json +0 -107
  342. package/docs/archive/investigations/hlg-runs/hlg-cliff.json +0 -197
  343. package/docs/archive/investigations/hlg-runs/hlg-cross.json +0 -505
  344. package/docs/archive/investigations/hlg-runs/hlg-edge.json +0 -388
  345. package/docs/archive/investigations/hlg-runs/hlg-eval1.json +0 -25
  346. package/docs/archive/investigations/hlg-runs/hlg-frontier.json +0 -86
  347. package/docs/archive/investigations/hlg-runs/hlg-grid.json +0 -242
  348. package/docs/archive/investigations/hlg-runs/hlg-grid2.json +0 -343
  349. package/docs/archive/investigations/hlg-runs/hlg-lw-coarse.json +0 -110
  350. package/docs/archive/investigations/hlg-runs/hlg-map.json +0 -383
  351. package/docs/archive/investigations/hlg-runs/run0-original.log +0 -159
  352. package/docs/archive/investigations/hlg-runs/runA-recommended.log +0 -131
  353. package/docs/archive/investigations/hlg-runs/runAA-cliff-cpm5.log +0 -26
  354. package/docs/archive/investigations/hlg-runs/runAB-grid2-e4b.log +0 -18
  355. package/docs/archive/investigations/hlg-runs/runAC-peak-e4b-partial.log +0 -25
  356. package/docs/archive/investigations/hlg-runs/runAD-ab-samples.log +0 -8
  357. package/docs/archive/investigations/hlg-runs/runAE-edge-e4b.log +0 -51
  358. package/docs/archive/investigations/hlg-runs/runAF-logit-calibration.log +0 -10
  359. package/docs/archive/investigations/hlg-runs/runAG-eval-config2.log +0 -16
  360. package/docs/archive/investigations/hlg-runs/runB-gain-variants.log +0 -192
  361. package/docs/archive/investigations/hlg-runs/runC-pivots.log +0 -162
  362. package/docs/archive/investigations/hlg-runs/runD-oetf.log +0 -132
  363. package/docs/archive/investigations/hlg-runs/runE-eotf.log +0 -162
  364. package/docs/archive/investigations/hlg-runs/runF-shaper-working.log +0 -86
  365. package/docs/archive/investigations/hlg-runs/runG-shaper-sweep.log +0 -101
  366. package/docs/archive/investigations/hlg-runs/runH-wsweep.log +0 -176
  367. package/docs/archive/investigations/hlg-runs/runI-asweep.log +0 -176
  368. package/docs/archive/investigations/hlg-runs/runJ-knobmap.log +0 -49
  369. package/docs/archive/investigations/hlg-runs/runK-frontier.log +0 -19
  370. package/docs/archive/investigations/hlg-runs/runL-widemap.log +0 -65
  371. package/docs/archive/investigations/hlg-runs/runM-frontier-emb.log +0 -15
  372. package/docs/archive/investigations/hlg-runs/runN-verify.log +0 -116
  373. package/docs/archive/investigations/hlg-runs/runO-frontier-seed5000.log +0 -15
  374. package/docs/archive/investigations/hlg-runs/runP-grid-AxSm.log +0 -15
  375. package/docs/archive/investigations/hlg-runs/runQ-grid-tgW.log +0 -15
  376. package/docs/archive/investigations/hlg-runs/runR-blind-transcript.log +0 -79
  377. package/docs/archive/investigations/hlg-runs/runS-cross-coherence.log +0 -33
  378. package/docs/archive/investigations/hlg-runs/runT-cross-cpm5.log +0 -33
  379. package/docs/archive/investigations/hlg-runs/runU-cross-12b.log +0 -33
  380. package/docs/archive/investigations/hlg-runs/runV-lw-e4b.log +0 -22
  381. package/docs/archive/investigations/hlg-runs/runW-lw-12b.log +0 -22
  382. package/docs/archive/investigations/hlg-runs/runX-lw-cpm5.log +0 -22
  383. package/docs/archive/investigations/hlg-runs/runY-cliff-e4b.log +0 -26
  384. package/docs/archive/investigations/hlg-runs/runZ-cliff-12b.log +0 -26
  385. package/docs/archive/mlx-bun-lab-report.html +0 -275
  386. package/docs/archive/wwdc-mlx-bun.html +0 -848
  387. package/docs/design/adapters-end-to-end.md +0 -205
  388. package/docs/design/batching-perf-path.md +0 -255
  389. package/docs/design/batching-v2-plan.md +0 -529
  390. package/docs/design/bucketing-stage.md +0 -197
  391. package/docs/design/compat-cli-surface-design.md +0 -230
  392. package/docs/design/docs-reorg-plan.md +0 -165
  393. package/docs/design/dspark-serving-program.md +0 -371
  394. package/docs/design/dspark-speculative-decoding.md +0 -318
  395. package/docs/design/grammar-spec-batching-integration.md +0 -301
  396. package/docs/design/memory-inference-path.md +0 -422
  397. package/docs/design/memory-synthesis.md +0 -287
  398. package/docs/design/memory-system.md +0 -237
  399. package/docs/design/mlx-lm-serving-execution-seam.md +0 -81
  400. package/docs/design/mlx-lm-tool-parity-plan.md +0 -545
  401. package/docs/design/omlx-adoption-map.md +0 -98
  402. package/docs/design/orpo-dynamic-lambda.md +0 -220
  403. package/docs/design/orpo-future-enhancements.md +0 -340
  404. package/docs/design/paged-kv-cache.md +0 -214
  405. package/docs/design/parallel-slots.md +0 -567
  406. package/docs/design/parity-tier-dag.md +0 -161
  407. package/docs/design/repo-cleanup-plan.md +0 -231
  408. package/docs/design/runtime-isolation.md +0 -263
  409. package/docs/design/segmented-backward-training.md +0 -543
  410. package/docs/design/spec-decode-larger-targets.md +0 -229
  411. package/docs/design/ssd-kv-cold-tier.md +0 -415
  412. package/docs/design/structured-output.md +0 -484
  413. package/docs/design/tauri-desktop-app.md +0 -127
  414. package/docs/design/the-dreaming-master-plan.md +0 -445
  415. package/docs/design/turboquant-kv.md +0 -235
  416. package/docs/design/turboquant-weights.md +0 -467
  417. package/docs/design/w4a16-compute-precision-spike.md +0 -232
  418. package/docs/design/web-chat-beat-matrix.md +0 -315
  419. package/docs/design/write-pipeline-entity.md +0 -468
  420. package/docs/planning/IDEAS.md +0 -69
  421. package/docs/reference/embedding.md +0 -197
  422. package/docs/reference/features-matrix.md +0 -101
  423. package/docs/reference/orpo-quickstart.md +0 -135
  424. package/src/flags.ts +0 -11
  425. /package/docs/{design → archive/investigations}/colibri-glm52-port.md +0 -0
  426. /package/docs/{planning → archive/planning}/chunk-task-roadmap.md +0 -0
  427. /package/docs/{planning → archive/planning}/curve-sampler-research-plan.md +0 -0
  428. /package/docs/{planning → archive/planning}/memory-docs-and-dag-plan.md +0 -0
  429. /package/docs/{planning → archive/planning}/pi-integration-review.md +0 -0
  430. /package/docs/{planning → archive/planning}/release-notes-v0.2.0.md +0 -0
  431. /package/src/{memory-plan.ts → admission-plan.ts} +0 -0
  432. /package/{docs/archive/investigations → src/serve/assets}/curve-terrain.html +0 -0
  433. /package/{docs/dag → src/serve/assets}/training-inference-map.html +0 -0
@@ -0,0 +1,158 @@
1
+ # Troubleshooting
2
+
3
+ Symptom → cause → fix, for the problems users actually hit. Every path and
4
+ flag below is taken from the code (`src/`) or the linked reference doc; when a
5
+ sentence here disagrees with the code, the code wins — fix the doc.
6
+
7
+ Related: [cli.md](./cli.md) (commands), [server-config.md](./server-config.md)
8
+ (serve flags, admission), [distribution.md](./distribution.md) (install paths,
9
+ signing), [docs/reference/distribution.md](./distribution.md) (sidecar layout, self-signing),
10
+ [environment.md](./environment.md) (contributor/agent platform facts).
11
+
12
+ ## Runtime and install
13
+
14
+ ### `dlopen` fails / `libmlxc.dylib` not found
15
+
16
+ **Cause.** The `mlx-bun` executable ships without the MLX native runtime
17
+ (`libmlxc.dylib`, `libmlx.dylib`, `libjaccl.dylib`, `mlx.metallib`, plus the
18
+ expert-IO dylib and frame-extract helper — the list is `NATIVE_PACK_FILES` in
19
+ `src/native-pack.ts`). The runtime is a versioned tarball downloaded on first
20
+ run into `~/Library/Caches/mlx-bun/native-v<ver>-<arch>/`. The download is
21
+ resumable and sha256-verified through the same machinery as model downloads
22
+ (`src/download.ts`), so an interrupted first run leaves a partial file, not a
23
+ broken install.
24
+
25
+ **Fix.** Rerun `mlx-bun serve` (or any command that loads the runtime); it
26
+ resumes and verifies. The library is resolved in this order
27
+ (`resolveLibmlxc()` in `src/mlx/ffi.ts`, mirrored by `nativeRuntimeDir()` in
28
+ `src/native-pack.ts`):
29
+
30
+ 1. `MLX_BUN_LIBMLXC=/path/to/libmlxc.dylib` — explicit override; the other
31
+ libs are expected in the same directory.
32
+ 2. Beside the executable (the sidecar layout from `docs/reference/distribution.md`).
33
+ 3. The native-pack cache dir above.
34
+ 4. Homebrew: `/opt/homebrew/lib`, then `/usr/local/lib`.
35
+
36
+ To use your own build, set `MLX_BUN_LIBMLXC`. If you see
37
+ `no native pack published for <arch> — set MLX_BUN_LIBMLXC or install mlx via
38
+ homebrew`, there is no published pack for that CPU architecture (only `arm64`
39
+ has a baked checksum in `src/native-pack.ts`); use one of the two escapes in
40
+ the message. `MLX_BUN_NATIVE_PACK_URL` overrides the download URL.
41
+
42
+ ### Gatekeeper: "unidentified developer" / app can't be opened
43
+
44
+ **Cause.** Released binaries are Developer-ID signed and notarized. macOS only
45
+ checks the notarization ticket when a file carries the `com.apple.quarantine`
46
+ xattr, which browser downloads and `curl -O`-style saves get. Homebrew installs
47
+ and the documented `curl ... | tar -xz` one-liner never write a quarantined
48
+ file, so they never prompt (`distribution.md`, "Direct download").
49
+
50
+ **Fix.**
51
+ - Online: the notarization ticket resolves the check; allow it once.
52
+ - Offline: `xattr -d com.apple.quarantine mlx-bun` (the manual escape hatch
53
+ from `distribution.md`).
54
+ - Self-built binary: the bundle's dylibs must be (re)signed with the hardened
55
+ runtime and entitlements — see "Signing & notarization" in
56
+ [docs/reference/distribution.md](./distribution.md).
57
+
58
+ ### Wrong Bun version / `Bun.Image` missing / FFI crashes in a source checkout
59
+
60
+ **Cause.** `package.json` pins `"bun": ">=1.4.0"`. Two things depend on it:
61
+ `Bun.Image` is the vision decode path (`src/vision/preprocess.ts`), and Bun
62
+ 1.4 fixed a `bun:ffi` stack-argument ABI bug on macOS arm64 that made
63
+ multi-argument mlx-c bindings hand the callee shifted garbage
64
+ (`lab/repro/bun-ffi-stack-args/ISSUE.md`; the code now uses natural mlx-c
65
+ signatures with no workaround).
66
+
67
+ **Fix.** `bun upgrade`, then `bun --version` ≥ 1.4.0. The compiled release
68
+ binary embeds its own Bun, so this only affects running from source.
69
+
70
+ ### `port 8080 is already serving …`
71
+
72
+ **Cause.** `serve` probes the port before loading weights and refuses to start
73
+ a second server on a port that already answers `/v1` (`src/cli.ts`, serve
74
+ branch; `--port` row in `server-config.md`).
75
+
76
+ **Fix.** Reuse the running server (`mlx-bun pi` attaches automatically), stop
77
+ it, or pass `--port <other>`. A second server is a second model in memory;
78
+ check `mlx-bun fit` first.
79
+
80
+ ## Models and downloads
81
+
82
+ ### `no models match (try \`mlx-bun scan\`)`
83
+
84
+ **Cause.** `ls`/`serve`/`fit` resolve models from a registry built by scanning
85
+ the Hugging Face hub cache. The registry is stale or empty, or the model is
86
+ not in the cache directory the registry reads.
87
+
88
+ **Fix.** Run `mlx-bun scan` after downloading. The cache path is resolved
89
+ exactly as `huggingface_hub` does (`DEFAULT_HUB` in `src/registry.ts`):
90
+ `HF_HUB_CACHE`, else `HF_HOME/hub`, else `~/.cache/huggingface/hub`. If you
91
+ downloaded to a custom location, set the same env var for `mlx-bun`. The
92
+ registry database lives at `~/.cache/mlx-bun/registry.sqlite`.
93
+
94
+ ### Hugging Face download stalls at 0%
95
+
96
+ **Cause.** The Python `hf` downloader uses the Xet transfer path, which stalls
97
+ on some networks.
98
+
99
+ **Fix.** Use `mlx-bun get <org/repo>` — it speaks plain HTTPS resolve/CDN with
100
+ no Xet, Range-resumes partial blobs, and verifies every file (sha256 for LFS
101
+ blobs, git-blob sha1 for small files) into the standard hub cache layout
102
+ (`src/download.ts`). Rerunning the same command resumes verified
103
+ `.incomplete` prefixes. If you must use the Python CLI, set
104
+ `HF_HUB_DISABLE_XET=1` before the download command.
105
+
106
+ ### `get` refuses for lack of disk space
107
+
108
+ **Cause.** Before transferring, `get` credits complete blobs and partial
109
+ prefixes, then requires free space for the exact remainder plus a fixed 1 GiB
110
+ reserve (`cli.md`, `get`).
111
+
112
+ **Fix.** Free space, or point `HF_HUB_CACHE` at a larger volume before
113
+ starting.
114
+
115
+ ### Gated repo: 401/403 from Hugging Face
116
+
117
+ **Cause.** No token. `get` reads `HF_TOKEN`, else
118
+ `~/.cache/huggingface/token` (`hfToken()` in `src/download.ts`).
119
+
120
+ **Fix.** `hf auth login`, or export `HF_TOKEN`.
121
+
122
+ ## Memory and performance
123
+
124
+ ### Will it fit? / decode is very slow on a model near the RAM ceiling
125
+
126
+ Memory pressure can reduce speed or cause allocation failures. The default
127
+ `fit` estimate uses machine RAM × 0.75 (`WIRED_FRACTION` in `src/fit.ts`).
128
+ Serving treats that estimate as advisory; `--memory-budget` opts into a limit.
129
+
130
+ **Fix.** Check first:
131
+
132
+ ```sh
133
+ mlx-bun fit <model> --ctx 8192 # this machine
134
+ mlx-bun fit <model> --ctx 8192 --skus # across the Apple Silicon lineup
135
+ mlx-bun fit <model> --kv-quant 4 # window with a 4-bit KV cache
136
+ ```
137
+
138
+ `fit` reports weights bytes (from safetensors headers), KV bytes/token, the
139
+ calibrated prefill transient, and the wired ceiling. Then close memory-heavy
140
+ apps, pick a smaller quantization, or serve with `--kv-quant 4|8` for a larger
141
+ context window in the same budget. GLM-5.2 uses its own streamed-runtime plan
142
+ (`fit GLM-5.2`; `--context-length`), not the resident-weights estimator.
143
+
144
+ ### Completion stops before my `max_tokens` (no error)
145
+
146
+ Check `finish_reason`: `stop` means EOS or a stop condition; `length` means
147
+ an output/context cap was reached. Default memory estimates do not shorten
148
+ requests. Explicit `--memory-budget`, context settings and GLM-5.2's fixed
149
+ layout can cap a completion. `/stats.admission.enforced_context_tokens` shows
150
+ that cap, or null when none applies. `max_safe_context` is only an estimate.
151
+
152
+ ### `400` with `"type": "memory_admission"`, `"code": "context_over_budget"`
153
+
154
+ This error applies to an explicitly configured budget/context cap or a fixed
155
+ runtime layout. The prompt leaves no room to generate under that limit.
156
+ Remove the optional budget/context cap to attempt the request without an
157
+ estimated restriction, or adjust the limit you selected. See
158
+ [server configuration](server-config.md#memory-admission-and-caches).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mlx-bun",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Native MLX inference for Bun on Apple Silicon — local LLM server (OpenAI/Anthropic-compatible) and TypeScript library. No Python.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -26,7 +26,9 @@
26
26
  },
27
27
  "exports": {
28
28
  ".": "./src/index.ts",
29
- "./package.json": "./package.json"
29
+ "./package.json": "./package.json",
30
+ "./engine": "./src/library.ts",
31
+ "./client": "./src/client.ts"
30
32
  },
31
33
  "files": [
32
34
  "bin",
@@ -47,16 +49,19 @@
47
49
  ],
48
50
  "scripts": {
49
51
  "test": "bash scripts/test.sh",
52
+ "typecheck": "tsc --noEmit && tsc -p tsconfig.web.json --noEmit && tsc -p src/contracts/tsconfig.json --noEmit",
50
53
  "link-cli": "chmod +x src/cli.ts && ln -sf $PWD/src/cli.ts $HOME/.bun/bin/mlx-bun && mlx-bun --version",
51
54
  "build:binary": "sh scripts/build-binary.sh",
52
55
  "release": "PUBLISH=1 sh scripts/release-binary.sh",
53
- "publish:npm": "bun publish"
56
+ "publish:npm": "bun publish",
57
+ "clean": "bun scripts/clean.ts"
54
58
  },
55
59
  "devDependencies": {
56
60
  "@anthropic-ai/sdk": "^0.104.1",
57
61
  "@types/bun": "^1.3.14",
58
62
  "happy-dom": "^20.10.6",
59
- "openai": "^6.42.0"
63
+ "openai": "^6.42.0",
64
+ "typescript": "6.0.3"
60
65
  },
61
66
  "dependencies": {
62
67
  "@earendil-works/pi-ai": "0.80.3",
@@ -1,9 +1,9 @@
1
- // WAV decode for audio input (A1 of docs/design/audio-input-plan.md).
1
+ // WAV decode for audio input (A1 of docs/design/generic-model-support.md).
2
2
  //
3
3
  // Scope: RIFF/WAVE containers — PCM 16/24/32-bit and IEEE float32, any
4
4
  // channel count (mean mixdown), any sample rate (linear resample to 16 kHz).
5
5
  // PCM16 scales by 1/32768 to match the oracle golden generator
6
- // (scripts/gen-e4b-audio-golden.py) exactly. Non-WAV containers (mp3/m4a/
6
+ // (scripts/oracle/gen-e4b-audio-golden.py) exactly. Non-WAV containers (mp3/m4a/
7
7
  // flac/ogg) are transcoded to WAV by the serve layer via macOS `afconvert`
8
8
  // before reaching this parser.
9
9
  //
@@ -1,9 +1,9 @@
1
1
  // USM log-mel feature extraction for gemma-4 audio — a verbatim-semantics
2
2
  // port of the oracle's Gemma4AudioFeatureExtractor (optiq/vlm/_mlxvlm/
3
3
  // models/gemma4/audio_feature_extractor.py, constructor DEFAULTS — §3.3 Q3
4
- // of docs/design/audio-input-plan.md: no per-bin normalization, params are
4
+ // of docs/design/generic-model-support.md: no per-bin normalization, params are
5
5
  // fixed for all gemma-4 models). Gated bit-close against the T0 mel goldens
6
- // (goldens/e4b-audio-*-mel.bin) in tests/audio-features.test.ts.
6
+ // (goldens/e4b-audio-*-mel.bin) in tests/parity/audio-features.test.ts.
7
7
  //
8
8
  // Pipeline (single waveform, 16 kHz mono float32):
9
9
  // pad to a multiple of 128 samples (validity mask over the original part)
@@ -0,0 +1,46 @@
1
+ import type { MlxArray } from "../../mlx/array";
2
+ import { Dtype } from "../../mlx/ffi";
3
+ import * as ops from "../../mlx/ops";
4
+ import type { Cache, KvDonorAttention } from "../../model/gemma4-base";
5
+ import { captureKvDonorAttention } from "../../model/kv-attention-view";
6
+ import type { AssistantAttention } from "../../spec/drafter";
7
+ import { disposeResources } from "../../engine/resources";
8
+
9
+ /** Bind captured cache validity to Q-only attention. Encoded layouts can
10
+ * supply this same numerical port without changing the draft graph. */
11
+ export function readAssistantDonors(sliding: Cache, full: Cache) {
12
+ const views: KvDonorAttention[] = [], masks: MlxArray[] = [];
13
+ const dispose = () => disposeResources([...masks, ...views]);
14
+ try {
15
+ for (const cache of [sliding, full]) views.push(captureKvDonorAttention(cache));
16
+ const bind = (view: KvDonorAttention): AssistantAttention => {
17
+ // All draft steps borrow the same target snapshot. Build each validity
18
+ // mask once, then reuse it across matching layers and the entire chain.
19
+ const byWindow = new Map<number | null, MlxArray | null>();
20
+ return { attend(query, scale, window) {
21
+ if (!byWindow.has(window)) {
22
+ const width = view.width, B = view.offsets.length;
23
+ const starts = view.starts.map((start, row) => Math.max(start,
24
+ window === null ? start : view.ends[row]! - window));
25
+ let mask: MlxArray | null = null;
26
+ if (starts.some(start => start !== 0) || view.ends.some(end => end !== width)) {
27
+ using columns = ops.arange(0, width, 1, Dtype.int32);
28
+ using lower = ops.fromInt32(starts, [B, 1, 1, 1]);
29
+ using upper = ops.fromInt32([...view.ends], [B, 1, 1, 1]);
30
+ using before = ops.less(columns, lower);
31
+ using after = ops.greaterEqual(columns, upper);
32
+ using invalid = ops.logicalOr(before, after);
33
+ using floats = invalid.astype(view.dtype);
34
+ mask = ops.mulScalar(floats, -1e9);
35
+ masks.push(mask);
36
+ }
37
+ byWindow.set(window, mask);
38
+ }
39
+ const mask = byWindow.get(window)!;
40
+ return view.attend(query, scale, { mode: mask ? "array" : "", arr: mask });
41
+ } };
42
+ };
43
+ return { positions: views[0]!.offsets.map(offset => offset - 1),
44
+ sliding: bind(views[0]!), full: bind(views[1]!), dispose };
45
+ } catch (error) { dispose(); throw error; }
46
+ }
@@ -0,0 +1,120 @@
1
+ import type { MlxArray } from "../../mlx/array";
2
+ import * as ops from "../../mlx/ops";
3
+ import type { AutoregressiveGraph } from "../../inference/graph";
4
+ import type { Cache, BatchableCache, PaddedPrefillCache } from "../../model/gemma4-base";
5
+ import type { DraftRowSampling } from "../../spec/source";
6
+ import { toLogprobs } from "../../sampler";
7
+ import { disposeResources } from "../../engine/resources";
8
+ import { MlxStateRows } from "./state-rows";
9
+ import type { PreparedStateChange } from "../../contracts/resources";
10
+ import { evalCacheState } from "./prefill";
11
+
12
+ export interface MlxDraftLayout extends BatchableCache, PaddedPrefillCache {
13
+ makeEmptyBatch(): MlxDraftLayout;
14
+ }
15
+
16
+ /** The draft graph and sampler operate at B. State snapshots own rewind and
17
+ * membership independently of the graph, target verifier and scheduler. */
18
+ export class MlxAutoregressiveDraftRows {
19
+ #history: MlxStateRows[] = [];
20
+ #drafts: number[][] = [];
21
+ #depth = 0;
22
+ #pendingLast: Array<number | null>;
23
+ constructor(readonly graph: AutoregressiveGraph<MlxArray, Cache[], MlxArray>,
24
+ readonly state: MlxStateRows<MlxDraftLayout>, readonly sampling: DraftRowSampling | null) {
25
+ this.#pendingLast = Array.from({ length: state.rowCount }, () => null);
26
+ }
27
+ get pendingLast(): readonly (number | null)[] { return this.#pendingLast; }
28
+ prepareAppend(rows: readonly (readonly Cache[])[], pending: readonly (number | null)[]): PreparedStateChange {
29
+ const state = this.state.prepareAppendMany(rows), next = [...this.#pendingLast, ...pending];
30
+ return { commit: () => { state.commit(); this.#pendingLast = next; }, dispose: () => state.dispose() };
31
+ }
32
+ filterRows(keep: readonly number[]): void {
33
+ this.state.filterRows(keep); this.#pendingLast = keep.map(row => this.#pendingLast[row]!);
34
+ }
35
+
36
+ async #forward(ids: MlxArray, lengths?: readonly number[]): Promise<MlxArray> {
37
+ const width = ids.shape[1]!, padded = lengths?.some(length => length !== width);
38
+ if (padded) for (const cache of this.state.caches) cache.preparePrefill({
39
+ lengths: [...lengths!], rightPadding: lengths!.map(length => width - length),
40
+ });
41
+ const hidden = await this.graph.forwardHidden(ids, this.state.caches);
42
+ try {
43
+ if (padded) for (const cache of this.state.caches) cache.finalizePrefill();
44
+ return hidden;
45
+ } catch (error) { hidden.dispose(); throw error; }
46
+ }
47
+
48
+ /** A restored full-accept boundary may have one unprocessed draft token.
49
+ * Combine it with the incoming block on device, retaining per-row lengths. */
50
+ async prefill(tokens: MlxArray): Promise<void> {
51
+ const [B, N] = tokens.shape as [number, number];
52
+ if (this.#pendingLast.some(token => token !== null)) {
53
+ using previous = ops.fromInt32(this.#pendingLast.map(token => token ?? 0), [B, 1]);
54
+ using joined = ops.concatAxis([previous, tokens], 1);
55
+ const lengths = this.#pendingLast.map(token => N + Number(token !== null));
56
+ using indices = ops.fromInt32(lengths.flatMap(length => Array.from({ length: N + 1 },
57
+ (_, position) => length === N + 1 ? position : Math.min(position + 1, N))), [B, N + 1]);
58
+ using inputs = ops.takeAlongAxis(joined, indices, 1);
59
+ (await this.#forward(inputs, lengths)).dispose();
60
+ } else (await this.#forward(tokens)).dispose();
61
+ this.#pendingLast.fill(null); this.materialize();
62
+ }
63
+ materialize(): void { evalCacheState(this.state.caches); }
64
+
65
+ async draft(pending: readonly number[], depth: number, steps: readonly number[]): Promise<number[][]> {
66
+ this.#releaseHistory();
67
+ this.#depth = depth;
68
+ const tokens: MlxArray[] = [];
69
+ const feeds = pending.map((token, row) => this.#pendingLast[row] == null ? [token] : [this.#pendingLast[row]!, token]);
70
+ const lengths = feeds.map(feed => feed.length), width = Math.max(...lengths);
71
+ let ids = ops.fromInt32(feeds.flatMap(feed => [...feed, ...Array(width - feed.length).fill(0)]), [pending.length, width]);
72
+ try {
73
+ // With zero proposals, consume the pending input to keep companion
74
+ // coverage aligned with the target's one-token verification.
75
+ for (let position = 0; position < Math.max(1, depth); position++) {
76
+ const padded = position === 0 && lengths.some(length => length !== width);
77
+ using hidden = await this.#forward(ids, position === 0 ? lengths : undefined);
78
+ this.#history.push(this.state.clone());
79
+ if (depth === 0) break;
80
+ using selection = padded ? ops.fromInt32(lengths.map(length => length - 1), [pending.length, 1, 1]) : null;
81
+ using selected = selection ? ops.takeAlongAxis(hidden, selection, 1) : null;
82
+ using logits = this.graph.projectLogits(selected ?? hidden, { type: "last" });
83
+ using flat = ops.reshape(logits, [pending.length, logits.shape.at(-1)!]);
84
+ using logprobs = toLogprobs(flat);
85
+ const token = this.sampling!.sample(logprobs, steps.map(step => step + position));
86
+ tokens.push(token);
87
+ ids.dispose(); ids = ops.reshape(token, [pending.length, 1]);
88
+ }
89
+ if (depth === 0) this.#drafts = pending.map(() => []);
90
+ else {
91
+ using packed = ops.concatAxis(tokens, 0);
92
+ const values = packed.toIntTokens();
93
+ this.#drafts = pending.map((_, row) => Array.from({ length: depth },
94
+ (_, position) => values[position * pending.length + row]!));
95
+ }
96
+ return this.#drafts;
97
+ } catch (error) { this.#releaseHistory(); throw error; }
98
+ finally { ids.dispose(); disposeResources(tokens); }
99
+ }
100
+
101
+ /** Preserve mlx-lm's full-accept re-feed shape: the final draft remains
102
+ * pending and joins the next target token in one forward. Recurrent state
103
+ * uses saved boundaries, never trimming. The lag is companion state. */
104
+ async commit(accepted: readonly number[]): Promise<void> {
105
+ const selected: Cache[][] = [];
106
+ try {
107
+ if (!accepted.every(count => count >= this.#depth - 1)) {
108
+ for (const [row, count] of accepted.entries())
109
+ selected.push(this.#history[Math.min(count, Math.max(0, this.#depth - 1))]!.extractRow(row));
110
+ this.state.mergeRows(selected);
111
+ }
112
+ } finally { disposeResources(selected.flat()); this.#releaseHistory(); }
113
+
114
+ this.#pendingLast = accepted.map((count, row) => this.#depth > 0 && count === this.#depth ? this.#drafts[row]!.at(-1)! : null);
115
+ this.#drafts = []; this.#depth = 0;
116
+ }
117
+
118
+ #releaseHistory(): void { disposeResources(this.#history.splice(0)); }
119
+ dispose(): void { this.#releaseHistory(); this.#drafts = []; this.state.dispose(); }
120
+ }
@@ -0,0 +1,108 @@
1
+ import type { AutoregressiveGraph } from "../../inference/graph";
2
+ import type { MlxArray } from "../../mlx/array";
3
+ import type { Cache, Gemma4Model } from "../../model/gemma4";
4
+ import type { RuntimeModel } from "../../model/factory";
5
+ import { CompiledDecode } from "../../model/compiled-decode";
6
+ import { runtimeConfig, type RuntimeConfig } from "../../runtime-config";
7
+ import { bindMlxGraph } from "./graph";
8
+
9
+ /** One declaration shared by planning and both native execution lanes. */
10
+ export function legacyCompiledDecodeAvailable(model: RuntimeModel): boolean {
11
+ return model.config?.modelType?.startsWith("gemma4") === true && !model.config.text.enableMoeBlock;
12
+ }
13
+
14
+ export interface MlxModelMemory {
15
+ readonly weightsBytes: number;
16
+ readonly expertRuntime?: {
17
+ readonly plan: { readonly plannedBytes: number };
18
+ flushUsage?: () => void;
19
+ finishUsage?: () => Promise<void>;
20
+ } | null;
21
+ }
22
+
23
+ export interface MlxDecodeStep {
24
+ /** Consume one pending token and advance state once. Returned arrays belong
25
+ * to the caller. null permits ordinary graph execution and MUST leave state
26
+ * unchanged. Errors propagate unless this implementation can roll back. */
27
+ tryStep(token: MlxArray, state: Cache[]): { logits: MlxArray; evalWith: MlxArray[] } | null;
28
+ /** Release per-run workspaces after pending outputs are dropped and before
29
+ * cache disposal. Wait for native work if releasing requires completion. */
30
+ close(): void | Promise<void>;
31
+ }
32
+
33
+ /** Model-owned execution for committed tokens. Recheck the chunk limit after
34
+ * each forward: native arithmetic can change at a cache-length boundary. */
35
+ export interface MlxTokenAppend {
36
+ maxChunkSize(state: readonly Cache[]): number;
37
+ forwardHidden(ids: MlxArray, state: Cache[]): MlxArray | Promise<MlxArray>;
38
+ }
39
+
40
+ /** One replaceable binding owns all graph-specific operations used by the AR
41
+ * loop. The current method requires MLX tensors and the legacy Cache[] ABI.
42
+ * Weights are borrowed for the binding's lifetime; generated caches are owned
43
+ * by the run. Caller-provided caches and media remain borrowed. */
44
+ export interface MlxAutoregressiveBinding {
45
+ readonly runtime?: RuntimeConfig;
46
+ readonly graph: AutoregressiveGraph<MlxArray, Cache[], MlxArray>;
47
+ readonly eosTokenIds: readonly number[];
48
+ readonly memory: MlxModelMemory;
49
+ readonly adapters?: { active: string[] };
50
+ makeCache(): Cache[];
51
+ forwardEmbeddings?(
52
+ embeddings: MlxArray, state: Cache[], imageMask: MlxArray | null,
53
+ ids: MlxArray, multimodalMask: MlxArray | null,
54
+ ): MlxArray;
55
+ /** Called once after prefill. A compiled/fused decoder belongs to THIS graph,
56
+ * never to a model inferred from a name or inherited by a replacement. */
57
+ createDecode?(policy: { hasAdapters: boolean; pagedKv: boolean }): MlxDecodeStep | null;
58
+ createAppend?(policy: { hasAdapters: boolean; pagedKv: boolean }): MlxTokenAppend | null;
59
+ }
60
+
61
+ /** Keep concrete model and compiled-decode decisions at the legacy boundary. */
62
+ export function bindLegacyAutoregressiveModel(model: RuntimeModel): MlxAutoregressiveBinding {
63
+ const runtime = runtimeConfig();
64
+ return {
65
+ runtime,
66
+ graph: bindMlxGraph<Cache[]>(model, {
67
+ id: `legacy:${model.config.modelType}`, artifact: "legacy-resident-model",
68
+ stateAbi: "legacy-cache-array-v1", // not a persistence identity
69
+ }),
70
+ eosTokenIds: model.config.eosTokenIds,
71
+ memory: model,
72
+ adapters: model.loraState,
73
+ makeCache: model.makeCache.bind(model),
74
+ forwardEmbeddings: model.forwardEmbeddings?.bind(model),
75
+ createAppend: "createAppend" in model ? model.createAppend.bind(model) : undefined,
76
+ createDecode(policy) {
77
+ // Preserve the existing Gemma path and exclusions. MoE shapeless replay
78
+ // retraces growing windows; adapters would bake residuals into the tape.
79
+ if (!runtime.flag("MLX_BUN_COMPILED_DECODE", true) || policy.hasAdapters || policy.pagedKv ||
80
+ !legacyCompiledDecodeAvailable(model))
81
+ return null;
82
+ let compiled: CompiledDecode | null = CompiledDecode.for(model as Gemma4Model);
83
+ return {
84
+ tryStep(token, state) {
85
+ if (!compiled || !CompiledDecode.supports(state)) return null;
86
+ try { return compiled.step(token, state); }
87
+ catch (error) {
88
+ // CompiledDecode restores committed writes on failure, so retrying
89
+ // this token through the ordinary graph is safe. Other decoders
90
+ // must establish that guarantee themselves before returning null.
91
+ compiled = null;
92
+ console.warn(`compiled decode disabled for this generation: ${error}`);
93
+ return null;
94
+ }
95
+ },
96
+ // Compiled closures belong to the model's existing unload lifecycle.
97
+ close() { compiled = null; },
98
+ };
99
+ },
100
+ };
101
+ }
102
+
103
+ export function assertMlxAutoregressiveBinding(binding: MlxAutoregressiveBinding): void {
104
+ const descriptor = binding.graph.descriptor;
105
+ if (descriptor.backend !== "mlx" || descriptor.graphAbi !== "mlx-hidden-bsh-v1" ||
106
+ descriptor.stateAbi !== "legacy-cache-array-v1")
107
+ throw new Error(`AR binding ${descriptor.id} has an incompatible backend, graph, or state ABI`);
108
+ }