mlx-bun 0.0.13 → 0.3.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 (427) hide show
  1. package/README.md +71 -578
  2. package/bin/mlx-bun.mjs +1 -1
  3. package/docs/README.md +91 -0
  4. package/docs/{design → archive}/hlg-sampling.md +3 -3
  5. package/docs/{design → archive/investigations}/audio-input-plan.md +4 -4
  6. package/docs/{design → archive/investigations}/colibri-glm52-port.md +1 -1
  7. package/docs/{design → archive/investigations}/diffusion-gemma-port.md +3 -3
  8. package/docs/{design → archive/investigations}/faithful-l1-consolidation.md +4 -4
  9. package/docs/{investigations → archive/investigations}/hlg-sampling-investigation.md +1 -1
  10. package/docs/{design → archive/investigations}/minicpm5-decode-megakernel.md +11 -11
  11. package/docs/{design → archive/investigations}/optimization_plan.md +1 -1
  12. package/docs/archive/investigations/pareto-specialized-runtime-findings.md +92 -0
  13. package/docs/{design → archive/investigations}/pre-colibri-stabilization.md +5 -5
  14. package/docs/{design → archive/investigations}/the-dreaming-handoff.md +2 -2
  15. package/docs/{planning → archive/planning}/chat-ui-vision.md +1 -1
  16. package/docs/{planning → archive/planning}/chunk-task-roadmap.md +1 -1
  17. package/docs/{planning → archive/planning}/curve-sampler-research-plan.md +4 -4
  18. package/docs/{planning → archive/planning}/memory-docs-and-dag-plan.md +1 -1
  19. package/docs/{planning → archive/planning}/release-notes-v0.0.9.md +1 -1
  20. package/docs/archive/planning/release-notes-v0.2.0.md +49 -0
  21. package/docs/{planning → archive/planning}/website-readme-pass-plan.md +1 -1
  22. package/docs/design/batching.md +569 -0
  23. package/docs/design/decode-speed-program.md +3178 -169
  24. package/docs/design/dreaming-nightly-pipeline.md +675 -282
  25. package/docs/design/generic-model-support.md +579 -334
  26. package/docs/design/kv-cache.md +680 -0
  27. package/docs/design/orpo-training.md +673 -1239
  28. package/docs/design/speculative-decoding.md +1627 -0
  29. package/docs/design/turboquant.md +2102 -0
  30. package/docs/design/unified-engine-frontier-plan.md +1831 -727
  31. package/docs/design/web-chat-redesign.md +666 -1083
  32. package/docs/planning/PRODUCT_ROADMAP.md +34 -1
  33. package/docs/planning/release-notes-v0.3.0.md +35 -0
  34. package/docs/planning/video-series.md +421 -0
  35. package/docs/reference/benchmarks.md +1162 -0
  36. package/docs/reference/cli.md +395 -149
  37. package/docs/reference/distribution.md +321 -181
  38. package/docs/reference/environment.md +348 -0
  39. package/docs/reference/glossary.md +39 -0
  40. package/docs/reference/library-api.md +580 -142
  41. package/docs/reference/memory.md +227 -64
  42. package/docs/reference/models.md +137 -6
  43. package/docs/reference/server-api.md +938 -422
  44. package/docs/reference/server-config.md +652 -320
  45. package/docs/reference/training.md +393 -254
  46. package/docs/reference/troubleshooting.md +166 -0
  47. package/package.json +10 -5
  48. package/src/admission-plan.ts +18 -0
  49. package/src/anthropic.ts +92 -3
  50. package/src/audio/decode.ts +2 -2
  51. package/src/audio/features.ts +2 -2
  52. package/src/backends/mlx/autoregressive.ts +108 -0
  53. package/src/backends/mlx/batch-group.ts +1646 -0
  54. package/src/backends/mlx/diffusion.ts +39 -0
  55. package/src/backends/mlx/draft-target.ts +47 -0
  56. package/src/backends/mlx/evaluation.ts +105 -0
  57. package/src/backends/mlx/fill-append.ts +45 -0
  58. package/src/backends/mlx/gateway-binding.ts +71 -0
  59. package/src/backends/mlx/graph.ts +38 -0
  60. package/src/backends/mlx/memory-client.ts +189 -0
  61. package/src/backends/mlx/memory-guard.ts +40 -0
  62. package/src/backends/mlx/methods.ts +90 -0
  63. package/src/backends/mlx/model-prompt.ts +164 -0
  64. package/src/backends/mlx/model-serving.ts +79 -0
  65. package/src/backends/mlx/prefill.ts +33 -0
  66. package/src/backends/mlx/request-policy.ts +20 -0
  67. package/src/backends/mlx/rollback.ts +51 -0
  68. package/src/backends/mlx/serial-executor.ts +273 -0
  69. package/src/backends/mlx/speculative.ts +114 -0
  70. package/src/backends/mlx/state-views.ts +26 -0
  71. package/src/backends/mlx/text-engine.ts +73 -0
  72. package/src/cli.ts +189 -61
  73. package/src/client.ts +66 -0
  74. package/src/config.ts +21 -4
  75. package/src/contracts/completion.ts +16 -0
  76. package/src/contracts/execution.ts +49 -0
  77. package/src/contracts/generation.ts +103 -0
  78. package/src/contracts/host.ts +7 -0
  79. package/src/contracts/jobs.ts +66 -0
  80. package/src/contracts/pi-provider.ts +30 -0
  81. package/src/contracts/pi.ts +259 -0
  82. package/src/contracts/resources.ts +18 -0
  83. package/src/contracts/scheduling.ts +27 -0
  84. package/src/contracts/tsconfig.json +14 -0
  85. package/src/diffusion/diffusion-generate.ts +218 -153
  86. package/src/embed.ts +1 -1
  87. package/src/engine/admission.ts +59 -0
  88. package/src/engine/cancellation.ts +38 -0
  89. package/src/engine/engine.ts +56 -0
  90. package/src/engine/execution-coordinator.ts +70 -0
  91. package/src/engine/execution-plan.ts +51 -0
  92. package/src/engine/resources.ts +42 -0
  93. package/src/engine/scheduler.ts +67 -0
  94. package/src/engine/session.ts +247 -0
  95. package/src/eval/README.md +44 -1
  96. package/src/eval/kl.ts +263 -23
  97. package/src/eval/reference-logits.ts +207 -0
  98. package/src/eval/runner.ts +10 -79
  99. package/src/eval/tasks/bfcl.ts +2 -1
  100. package/src/eval/tasks/gsm8k.ts +2 -1
  101. package/src/eval/tasks/hashhop.ts +2 -1
  102. package/src/eval/tasks/humaneval.ts +5 -4
  103. package/src/eval/tasks/ifeval.ts +2 -1
  104. package/src/eval/tasks/mmlu.ts +2 -1
  105. package/src/expert-io.ts +3 -1
  106. package/src/expert-offload.ts +3 -1
  107. package/src/fill/echo-index.ts +188 -0
  108. package/src/fill/fill-session.ts +452 -0
  109. package/src/fill/proposal.ts +68 -0
  110. package/src/fill/schema-rows.ts +506 -0
  111. package/src/fill/tool-boundary.ts +103 -0
  112. package/src/fit.ts +24 -43
  113. package/src/generate.ts +740 -337
  114. package/src/grammar.ts +14 -8
  115. package/src/harness-pi.ts +15 -34
  116. package/src/hub-rest.ts +4 -4
  117. package/src/index.ts +27 -0
  118. package/src/inference/denoising.ts +17 -0
  119. package/src/inference/graph.ts +33 -0
  120. package/src/inference/prefill.ts +39 -0
  121. package/src/inference/rollback.ts +7 -0
  122. package/src/jobs/db.ts +4 -0
  123. package/src/jobs/index.ts +2 -0
  124. package/src/jobs/job-entry.ts +15 -14
  125. package/src/jobs/runner.ts +98 -13
  126. package/src/jobs/task-client.ts +19 -0
  127. package/src/jobs/types.ts +2 -58
  128. package/src/kv-scheme.ts +199 -0
  129. package/src/kv-store.ts +459 -234
  130. package/src/lab/README.md +18 -0
  131. package/src/{assets → lab/curve}/curve-designer.html +2 -2
  132. package/src/{curve-sampler.ts → lab/curve/curve-sampler.ts} +2 -2
  133. package/src/{expert-trace.ts → lab/expert-trace/expert-trace.ts} +7 -5
  134. package/src/{model → lab/paged-kv}/paged-kv.ts +9 -6
  135. package/src/library.ts +40 -0
  136. package/src/lora.ts +18 -0
  137. package/src/media-fetch.ts +20 -4
  138. package/src/memory/article.ts +1 -1
  139. package/src/memory/chunk.ts +1 -1
  140. package/src/memory/model.ts +32 -170
  141. package/src/memory/prompts.ts +1 -1
  142. package/src/memory/rest.ts +1 -1
  143. package/src/memory/schedule.ts +1 -1
  144. package/src/memory/stages.ts +4 -1
  145. package/src/memory/vault.ts +3 -4
  146. package/src/mlx/array.ts +9 -10
  147. package/src/mlx/compile.ts +12 -2
  148. package/src/mlx/ffi.ts +66 -22
  149. package/src/mlx/materialize.ts +23 -0
  150. package/src/mlx/metal-kernel.ts +10 -11
  151. package/src/mlx/ops.ts +64 -19
  152. package/src/mlx/quantized-rows.ts +36 -0
  153. package/src/mlx/token-bitmask.ts +52 -0
  154. package/src/mlx/turboquant-kv-decode.ts +82 -0
  155. package/src/mlx/turboquant-kv-inverse.ts +122 -0
  156. package/src/mlx/turboquant-ops.ts +33 -3
  157. package/src/mlx/turboquant-tables.ts +2 -2
  158. package/src/model/batched-mask.ts +9 -3
  159. package/src/model/batched-quant.ts +2 -2
  160. package/src/model/batched-rotating-quant.ts +45 -99
  161. package/src/model/batched-rotating-state.ts +73 -0
  162. package/src/model/batched-rotating.ts +57 -106
  163. package/src/model/batched-row-storage.ts +127 -0
  164. package/src/model/compiled-decode.ts +4 -3
  165. package/src/model/diffusion-gemma.ts +8 -8
  166. package/src/model/factory.ts +87 -49
  167. package/src/model/fingerprint.ts +1 -1
  168. package/src/model/flash-attention.ts +3 -3
  169. package/src/model/gemma4-base.ts +187 -17
  170. package/src/model/gemma4.ts +6 -6
  171. package/src/model/generated/gemma4-12b.ts +52 -148
  172. package/src/model/generated/gemma4-26b.ts +34 -94
  173. package/src/model/generated/gemma4-e4b.ts +28 -76
  174. package/src/model/glm52-cache.ts +19 -9
  175. package/src/model/glm52-dsa.ts +13 -9
  176. package/src/model/glm52-memory.ts +28 -1
  177. package/src/model/implementation.ts +69 -0
  178. package/src/model/minicpm5.ts +7 -8
  179. package/src/model/profile.ts +443 -0
  180. package/src/model/qwen-append.ts +12 -0
  181. package/src/model/qwen-conv.ts +52 -0
  182. package/src/model/qwen3-delta.ts +98 -2
  183. package/src/model/qwen3-mrope.ts +252 -0
  184. package/src/model/qwen3_5-checkpoint.ts +164 -0
  185. package/src/model/qwen3_5.ts +336 -60
  186. package/src/model/support.ts +1 -1
  187. package/src/model/trellis-balanced-scatter.ts +51 -0
  188. package/src/model/trellis-linear.ts +672 -0
  189. package/src/model/trellis-shared-m.ts +151 -0
  190. package/src/model/trellis-shared-scatter.ts +144 -0
  191. package/src/model/trellis-splitk-prefill.ts +158 -0
  192. package/src/model/trellis-tiled-prefill.ts +136 -0
  193. package/src/model/trellis-vector-expand.ts +62 -0
  194. package/src/model/trellis-wide-prefill.ts +94 -0
  195. package/src/model/universal/dense.ts +1 -1
  196. package/src/model/universal/modules.ts +8 -1
  197. package/src/native/frame_extract.swift +140 -0
  198. package/src/native-pack.ts +15 -7
  199. package/src/pi-provider.ts +6 -64
  200. package/src/pi-web.ts +14 -320
  201. package/src/prompt-cache.ts +97 -54
  202. package/src/quantize/allocator.ts +1 -1
  203. package/src/quantize/atomic-output.ts +38 -0
  204. package/src/quantize/calibration.ts +2 -1
  205. package/src/quantize/config-writer.ts +16 -3
  206. package/src/quantize/index.ts +28 -1
  207. package/src/quantize/job.ts +11 -0
  208. package/src/quantize/quantizer.ts +265 -100
  209. package/src/quantize/rotate.ts +603 -0
  210. package/src/quantize/safetensors-writer.ts +79 -1
  211. package/src/quantize/sensitivity.ts +41 -59
  212. package/src/quantize/trellis.ts +586 -0
  213. package/src/quantize/weight-transform.ts +292 -0
  214. package/src/responses.ts +130 -3
  215. package/src/runtime-config.ts +81 -0
  216. package/src/sampler.ts +276 -4
  217. package/src/serve/admin-routes.ts +184 -0
  218. package/src/serve/aux-routes.ts +132 -0
  219. package/src/serve/batch-scheduler.ts +8 -1558
  220. package/src/serve/chat-request.ts +391 -0
  221. package/src/serve/chat-stage.ts +195 -0
  222. package/src/serve/checkpoint-identity.ts +64 -0
  223. package/src/serve/completion-executor.ts +354 -0
  224. package/src/serve/completion-sink.ts +157 -0
  225. package/src/serve/discovery-routes.ts +204 -0
  226. package/src/serve/generation-gateway.ts +211 -243
  227. package/src/serve/http.ts +159 -0
  228. package/src/serve/inference-request.ts +79 -0
  229. package/src/serve/isolate.ts +297 -105
  230. package/src/serve/kv-budget.ts +14 -0
  231. package/src/serve/lab-routes.ts +341 -0
  232. package/src/serve/lane-registry.ts +2 -1
  233. package/src/serve/model-admin-routes.ts +155 -0
  234. package/src/serve/model-binding.ts +43 -0
  235. package/src/serve/model-host.ts +512 -0
  236. package/src/serve/openai-wire.ts +103 -0
  237. package/src/serve/parent-application.ts +56 -0
  238. package/src/serve/pipeline.ts +33 -0
  239. package/src/serve/preparation.ts +33 -0
  240. package/src/serve/prompt-response-trace.ts +147 -0
  241. package/src/serve/request-plan.ts +162 -0
  242. package/src/serve/request-prep.ts +346 -0
  243. package/src/serve/response-lease.ts +24 -0
  244. package/src/serve/responses-client.ts +69 -0
  245. package/src/serve/session-completion-engine.ts +110 -0
  246. package/src/serve/session-search.ts +1 -1
  247. package/src/serve/static-routes.ts +101 -0
  248. package/src/serve/text-completion-stage.ts +104 -0
  249. package/src/serve/token-streams.ts +519 -0
  250. package/src/server.ts +523 -3551
  251. package/src/spec/assistant-source.ts +10 -44
  252. package/src/spec/deepspec-source.ts +6 -6
  253. package/src/spec/dflash-source.ts +9 -8
  254. package/src/spec/dspark/ab-stats.ts +3 -3
  255. package/src/spec/dspark/calibration.ts +2 -2
  256. package/src/spec/dspark/deepspec-module.ts +2 -2
  257. package/src/spec/dspark/generate-dflash.ts +2 -2
  258. package/src/spec/dspark/generate.ts +2 -2
  259. package/src/spec/dspark/loader.ts +1 -1
  260. package/src/spec/dspark/module-dflash.ts +5 -4
  261. package/src/spec/dspark/module.ts +3 -3
  262. package/src/spec/dspark/quantize-drafter.ts +1 -1
  263. package/src/spec/generate.ts +1 -1
  264. package/src/spec/glm52-mtp-source.ts +9 -1
  265. package/src/spec/ngram-source.ts +1 -1
  266. package/src/spec/prefix-state.ts +45 -0
  267. package/src/spec/qwen-mtp-source.ts +528 -0
  268. package/src/spec/serve-loop.ts +179 -213
  269. package/src/spec/source.ts +42 -10
  270. package/src/spec/two-model.ts +1 -1
  271. package/src/ssd-cache.ts +95 -24
  272. package/src/ssd-durability.ts +207 -0
  273. package/src/tool-call.ts +51 -14
  274. package/src/train/flash-cce.ts +14 -13
  275. package/src/train/forward.ts +38 -1
  276. package/src/train/loss.ts +3 -2
  277. package/src/train/prefix-shared.ts +5 -1
  278. package/src/train/segmented.ts +9 -6
  279. package/src/train/trainer.ts +9 -8
  280. package/src/vision/preprocess.ts +1 -1
  281. package/src/vision/prompt.ts +48 -2
  282. package/src/vision/qwen3vl-preprocess.ts +409 -0
  283. package/src/vision/qwen3vl-prompt.ts +196 -0
  284. package/src/vision/qwen3vl-tower.ts +555 -0
  285. package/src/vision/video-frames.ts +148 -0
  286. package/src/web/app.html +1 -1
  287. package/src/web/app.js +15 -6
  288. package/src/web/src/adapters-panel.ts +3 -3
  289. package/src/web/src/assistant.ts +2 -36
  290. package/src/web/src/chat.ts +16 -9
  291. package/src/web/src/composer.ts +4 -4
  292. package/src/web/src/hub.ts +1 -1
  293. package/src/web/src/markdown.ts +0 -0
  294. package/src/web/src/memory-panel.ts +1 -1
  295. package/src/web/src/model-picker.ts +1 -1
  296. package/src/web/src/palette.ts +1 -1
  297. package/src/web/src/protocol.ts +3 -39
  298. package/src/web/src/sessions.ts +1 -1
  299. package/src/web/src/ui-catalog.ts +4 -18
  300. package/src/web-assets.ts +47 -0
  301. package/src/weights.ts +134 -33
  302. package/docs/archive/mlx-bun-lab-report.html +0 -275
  303. package/docs/archive/wwdc-mlx-bun.html +0 -848
  304. package/docs/design/adapters-end-to-end.md +0 -205
  305. package/docs/design/batching-perf-path.md +0 -255
  306. package/docs/design/batching-v2-plan.md +0 -529
  307. package/docs/design/bucketing-stage.md +0 -197
  308. package/docs/design/compat-cli-surface-design.md +0 -230
  309. package/docs/design/docs-reorg-plan.md +0 -165
  310. package/docs/design/dspark-serving-program.md +0 -371
  311. package/docs/design/dspark-speculative-decoding.md +0 -268
  312. package/docs/design/grammar-spec-batching-integration.md +0 -301
  313. package/docs/design/memory-inference-path.md +0 -422
  314. package/docs/design/memory-synthesis.md +0 -287
  315. package/docs/design/memory-system.md +0 -237
  316. package/docs/design/mlx-lm-tool-parity-plan.md +0 -545
  317. package/docs/design/omlx-adoption-map.md +0 -98
  318. package/docs/design/orpo-dynamic-lambda.md +0 -220
  319. package/docs/design/orpo-future-enhancements.md +0 -340
  320. package/docs/design/paged-kv-cache.md +0 -214
  321. package/docs/design/parallel-slots.md +0 -567
  322. package/docs/design/parity-tier-dag.md +0 -161
  323. package/docs/design/repo-cleanup-plan.md +0 -189
  324. package/docs/design/runtime-isolation.md +0 -263
  325. package/docs/design/segmented-backward-training.md +0 -543
  326. package/docs/design/spec-decode-larger-targets.md +0 -229
  327. package/docs/design/ssd-kv-cold-tier.md +0 -288
  328. package/docs/design/structured-output.md +0 -484
  329. package/docs/design/tauri-desktop-app.md +0 -127
  330. package/docs/design/the-dreaming-master-plan.md +0 -445
  331. package/docs/design/turboquant-kv.md +0 -235
  332. package/docs/design/w4a16-compute-precision-spike.md +0 -232
  333. package/docs/design/web-chat-beat-matrix.md +0 -315
  334. package/docs/design/write-pipeline-entity.md +0 -468
  335. package/docs/investigations/curve-runs/bisector-route.json +0 -98
  336. package/docs/investigations/curve-runs/bisector-trace.json +0 -1393
  337. package/docs/investigations/curve-runs/curve-terrain.json +0 -1179
  338. package/docs/investigations/curve-runs/curve-terrain.svg +0 -42
  339. package/docs/investigations/hlg-ab.html +0 -34
  340. package/docs/investigations/hlg-explorer.html +0 -238
  341. package/docs/investigations/hlg-figs/cliff.svg +0 -1
  342. package/docs/investigations/hlg-figs/cross.svg +0 -1
  343. package/docs/investigations/hlg-figs/edges.svg +0 -1
  344. package/docs/investigations/hlg-figs/k20-grids.svg +0 -1
  345. package/docs/investigations/hlg-figs/k20-peaks.svg +0 -1
  346. package/docs/investigations/hlg-figs/lw-curve.svg +0 -1
  347. package/docs/investigations/hlg-figs/terrain.svg +0 -1
  348. package/docs/investigations/hlg-report.html +0 -262
  349. package/docs/investigations/hlg-runs/hlg-ab.json +0 -149
  350. package/docs/investigations/hlg-runs/hlg-blind-prompts.md +0 -87
  351. package/docs/investigations/hlg-runs/hlg-blind.json +0 -107
  352. package/docs/investigations/hlg-runs/hlg-cliff.json +0 -197
  353. package/docs/investigations/hlg-runs/hlg-cross.json +0 -505
  354. package/docs/investigations/hlg-runs/hlg-edge.json +0 -388
  355. package/docs/investigations/hlg-runs/hlg-eval1.json +0 -25
  356. package/docs/investigations/hlg-runs/hlg-frontier.json +0 -86
  357. package/docs/investigations/hlg-runs/hlg-grid.json +0 -242
  358. package/docs/investigations/hlg-runs/hlg-grid2.json +0 -343
  359. package/docs/investigations/hlg-runs/hlg-lw-coarse.json +0 -110
  360. package/docs/investigations/hlg-runs/hlg-map.json +0 -383
  361. package/docs/investigations/hlg-runs/run0-original.log +0 -159
  362. package/docs/investigations/hlg-runs/runA-recommended.log +0 -131
  363. package/docs/investigations/hlg-runs/runAA-cliff-cpm5.log +0 -26
  364. package/docs/investigations/hlg-runs/runAB-grid2-e4b.log +0 -18
  365. package/docs/investigations/hlg-runs/runAC-peak-e4b-partial.log +0 -25
  366. package/docs/investigations/hlg-runs/runAD-ab-samples.log +0 -8
  367. package/docs/investigations/hlg-runs/runAE-edge-e4b.log +0 -51
  368. package/docs/investigations/hlg-runs/runAF-logit-calibration.log +0 -10
  369. package/docs/investigations/hlg-runs/runAG-eval-config2.log +0 -16
  370. package/docs/investigations/hlg-runs/runB-gain-variants.log +0 -192
  371. package/docs/investigations/hlg-runs/runC-pivots.log +0 -162
  372. package/docs/investigations/hlg-runs/runD-oetf.log +0 -132
  373. package/docs/investigations/hlg-runs/runE-eotf.log +0 -162
  374. package/docs/investigations/hlg-runs/runF-shaper-working.log +0 -86
  375. package/docs/investigations/hlg-runs/runG-shaper-sweep.log +0 -101
  376. package/docs/investigations/hlg-runs/runH-wsweep.log +0 -176
  377. package/docs/investigations/hlg-runs/runI-asweep.log +0 -176
  378. package/docs/investigations/hlg-runs/runJ-knobmap.log +0 -49
  379. package/docs/investigations/hlg-runs/runK-frontier.log +0 -19
  380. package/docs/investigations/hlg-runs/runL-widemap.log +0 -65
  381. package/docs/investigations/hlg-runs/runM-frontier-emb.log +0 -15
  382. package/docs/investigations/hlg-runs/runN-verify.log +0 -116
  383. package/docs/investigations/hlg-runs/runO-frontier-seed5000.log +0 -15
  384. package/docs/investigations/hlg-runs/runP-grid-AxSm.log +0 -15
  385. package/docs/investigations/hlg-runs/runQ-grid-tgW.log +0 -15
  386. package/docs/investigations/hlg-runs/runR-blind-transcript.log +0 -79
  387. package/docs/investigations/hlg-runs/runS-cross-coherence.log +0 -33
  388. package/docs/investigations/hlg-runs/runT-cross-cpm5.log +0 -33
  389. package/docs/investigations/hlg-runs/runU-cross-12b.log +0 -33
  390. package/docs/investigations/hlg-runs/runV-lw-e4b.log +0 -22
  391. package/docs/investigations/hlg-runs/runW-lw-12b.log +0 -22
  392. package/docs/investigations/hlg-runs/runX-lw-cpm5.log +0 -22
  393. package/docs/investigations/hlg-runs/runY-cliff-e4b.log +0 -26
  394. package/docs/investigations/hlg-runs/runZ-cliff-12b.log +0 -26
  395. package/docs/planning/IDEAS.md +0 -69
  396. package/docs/reference/embedding.md +0 -197
  397. package/docs/reference/features-matrix.md +0 -100
  398. package/docs/reference/orpo-quickstart.md +0 -135
  399. package/src/flags.ts +0 -13
  400. /package/docs/{investigations → archive/investigations}/chunk-finetune-experiment.md +0 -0
  401. /package/docs/{investigations → archive/investigations}/colibri-oracle-pin.md +0 -0
  402. /package/docs/{investigations → archive/investigations}/curve-bisector-routing.md +0 -0
  403. /package/docs/{investigations → archive/investigations}/decode-roofline-lookagain.md +0 -0
  404. /package/docs/{investigations → archive/investigations}/dspark-handoff.md +0 -0
  405. /package/docs/{investigations → archive/investigations}/expert-offload-single-user-moe.md +0 -0
  406. /package/docs/{investigations → archive/investigations}/indexshare-performance-spike.md +0 -0
  407. /package/docs/{investigations → archive/investigations}/kernel-perf-review-2026-07.md +0 -0
  408. /package/docs/{investigations → archive/investigations}/lab-build-journal.md +0 -0
  409. /package/docs/{investigations → archive/investigations}/openwiki-evaluation.md +0 -0
  410. /package/docs/{investigations → archive/investigations}/orpo-base-uf-experiment-and-directions.md +0 -0
  411. /package/docs/{investigations → archive/investigations}/orpo-flash-cce-pin-leak.md +0 -0
  412. /package/docs/{investigations → archive/investigations}/orpo-uf-testing-handoff.md +0 -0
  413. /package/docs/{investigations → archive/investigations}/pi-builtin-investigation.md +0 -0
  414. /package/docs/{investigations → archive/investigations}/segmented-backward-handoff.md +0 -0
  415. /package/docs/{investigations → archive/investigations}/starter-model-port-handoff.md +0 -0
  416. /package/docs/{investigations → archive/investigations}/steel-flash-cce-handoff.md +0 -0
  417. /package/docs/{investigations → archive/investigations}/trainer-validation-experiment.md +0 -0
  418. /package/docs/{planning → archive/planning}/chat-ui-vision-memory-first.md +0 -0
  419. /package/docs/{planning → archive/planning}/journal.md +0 -0
  420. /package/docs/{planning → archive/planning}/pi-integration-review.md +0 -0
  421. /package/docs/{planning → archive/planning}/release-notes-v0.0.10.md +0 -0
  422. /package/docs/{planning → archive/planning}/release-notes-v0.0.11.md +0 -0
  423. /package/docs/{planning → archive/planning}/release-notes-v0.0.12.md +0 -0
  424. /package/docs/{planning → archive/planning}/release-notes-v0.0.13.md +0 -0
  425. /package/docs/{planning → archive/planning}/web-ui-pass-plan.md +0 -0
  426. /package/{docs/investigations → src/serve/assets}/curve-terrain.html +0 -0
  427. /package/{docs/dag → src/serve/assets}/training-inference-map.html +0 -0
@@ -0,0 +1,443 @@
1
+ import type { ModelConfig } from "../config";
2
+ import { configFingerprint } from "./fingerprint";
3
+ import {
4
+ isDiffusionGemmaConfig,
5
+ isGlm52Config,
6
+ isMiniCPM5Config,
7
+ isQwen35Config,
8
+ isQwen3Config,
9
+ isQwen3MoeConfig,
10
+ } from "./support";
11
+ import { GENERATED } from "./generated";
12
+ import { GENERIC_MODEL_TYPES, genericArgsFor, remapModelType } from "./universal/archs";
13
+
14
+ export const ENGINE_CAPABILITIES = Object.freeze([
15
+ "autoregressive",
16
+ "colibri-container",
17
+ "diffusion",
18
+ "diffusion-gemma-graph",
19
+ "gemma4-graph",
20
+ "generated-graph",
21
+ "glm5.2-graph",
22
+ "minicpm5-graph",
23
+ "mixed-precision-kv",
24
+ "native-mtp",
25
+ "qwen3-graph",
26
+ "qwen3-moe-graph",
27
+ "qwen3.5-graph",
28
+ "recurrent-state",
29
+ "safetensors",
30
+ "streamed-experts",
31
+ "universal-dense-graph",
32
+ "vision-sidecar",
33
+ ] as const);
34
+
35
+ export type EngineCapability = typeof ENGINE_CAPABILITIES[number];
36
+ export type FidelityTier = "l1" | "l2" | "l3";
37
+
38
+ export type FidelityTarget =
39
+ | Readonly<{ tier: "l1"; oracle: "mlx-lm"; claim: "bit-exact" }>
40
+ | Readonly<{ tier: "l2"; oracle: "mlx-optiq"; claim: "bit-exact" }>
41
+ | Readonly<{ tier: "l3"; oracle: null; claim: "measured" }>;
42
+
43
+ export type ModelLoader = "safetensors" | "colibri";
44
+ export type ModelGraph =
45
+ | "gemma4"
46
+ | "minicpm5"
47
+ | "qwen3.5"
48
+ | "qwen3"
49
+ | "qwen3-moe"
50
+ | "diffusion-gemma"
51
+ | "glm5.2"
52
+ | "universal-dense";
53
+ export type GenerationLoop = "autoregressive" | "diffusion";
54
+ export type ModelSpecialization = "artifact" | "dedicated" | "generated" | "generic";
55
+
56
+ export interface ModelExecutionComposition {
57
+ readonly loader: ModelLoader;
58
+ readonly graph: ModelGraph;
59
+ readonly loop: GenerationLoop;
60
+ readonly specialization: ModelSpecialization;
61
+ /** Engine-owned code registration. Model files never supply executable code.
62
+ * Omit to retain the existing graph implementation. */
63
+ readonly implementation?: string;
64
+ }
65
+
66
+ /** A profile declares construction only. Request methods such as MTP, KV
67
+ * schemes, adapters, grammar, and sampling are resolved independently and
68
+ * cannot be rewritten by profile selection. */
69
+ export interface ModelProfile {
70
+ readonly id: string;
71
+ /** Exact external identity. Family profiles omit this field. */
72
+ readonly artifactFingerprint?: string;
73
+ /** Structural guard for an exact artifact declaration. */
74
+ readonly configFingerprint?: string;
75
+ readonly fidelity: FidelityTarget;
76
+ readonly requiredCapabilities: readonly EngineCapability[];
77
+ readonly execution: ModelExecutionComposition;
78
+ }
79
+
80
+ export interface ArtifactModelProfile extends ModelProfile {
81
+ readonly artifactFingerprint: string;
82
+ readonly configFingerprint: string;
83
+ }
84
+
85
+ export interface ModelArtifactIdentity {
86
+ readonly fingerprint: string | null;
87
+ readonly configFingerprint: string;
88
+ }
89
+
90
+ export interface ResolvedModelProfile {
91
+ readonly profile: ModelProfile;
92
+ readonly artifact: ModelArtifactIdentity;
93
+ readonly exactArtifact: boolean;
94
+ }
95
+
96
+ export interface ResolveModelProfileOptions {
97
+ /** Explicit identity for a non-Hugging-Face artifact. The caller owns its
98
+ * provenance; mlx-bun never mistakes a local path for a content identity. */
99
+ readonly artifactFingerprint?: string | null;
100
+ /** Additional exact declarations composed with the shipped profiles. */
101
+ readonly artifactProfiles?: readonly ArtifactModelProfile[];
102
+ readonly engineCapabilities?: readonly EngineCapability[];
103
+ }
104
+
105
+ const L1: FidelityTarget = Object.freeze({
106
+ tier: "l1", oracle: "mlx-lm", claim: "bit-exact",
107
+ });
108
+ const L2: FidelityTarget = Object.freeze({
109
+ tier: "l2", oracle: "mlx-optiq", claim: "bit-exact",
110
+ });
111
+ const L3: FidelityTarget = Object.freeze({
112
+ tier: "l3", oracle: null, claim: "measured",
113
+ });
114
+
115
+ function freezeProfile<T extends ModelProfile>(profile: T): T {
116
+ Object.freeze(profile.fidelity);
117
+ Object.freeze(profile.requiredCapabilities);
118
+ Object.freeze(profile.execution);
119
+ return Object.freeze(profile);
120
+ }
121
+
122
+ function snapshotProfile(profile: ModelProfile): ModelProfile {
123
+ return freezeProfile({
124
+ ...profile,
125
+ fidelity: { ...profile.fidelity },
126
+ requiredCapabilities: [...profile.requiredCapabilities],
127
+ execution: { ...profile.execution },
128
+ });
129
+ }
130
+
131
+ /** Exact artifact declarations already backed by this repository's parity or
132
+ * measured evidence. A new revision gets the family profile until it earns a
133
+ * declaration of its own. */
134
+ export const BUILTIN_ARTIFACT_PROFILES: readonly ArtifactModelProfile[] = Object.freeze([
135
+ freezeProfile({
136
+ id: "qwen3.8-27b-optiq-4bit",
137
+ artifactFingerprint:
138
+ "hf:mlx-community/Qwen3.8-27B-OptiQ-4bit@b04599de95d7a9bfbd7f208d347c0f10d9432a42",
139
+ configFingerprint: "50117975cb405944",
140
+ fidelity: L1,
141
+ requiredCapabilities: Object.freeze([
142
+ "safetensors", "autoregressive", "qwen3.5-graph", "recurrent-state", "vision-sidecar",
143
+ ]),
144
+ execution: Object.freeze({
145
+ loader: "safetensors",
146
+ graph: "qwen3.5",
147
+ loop: "autoregressive",
148
+ specialization: "artifact",
149
+ }),
150
+ }),
151
+ freezeProfile({
152
+ id: "glm5.2-colibri-int4-int8-mtp",
153
+ artifactFingerprint:
154
+ "hf:mateogrgic/GLM-5.2-colibri-int4-with-int8-mtp@3cc8db99b1b13fc79325d987ba3c1c430766b3b8",
155
+ configFingerprint: "8b49d0941e18f1b9",
156
+ fidelity: L3,
157
+ requiredCapabilities: Object.freeze([
158
+ "colibri-container", "autoregressive", "glm5.2-graph", "streamed-experts",
159
+ ]),
160
+ execution: Object.freeze({
161
+ loader: "colibri",
162
+ graph: "glm5.2",
163
+ loop: "autoregressive",
164
+ specialization: "artifact",
165
+ }),
166
+ }),
167
+ ]);
168
+
169
+ const FAMILY_PROFILES = {
170
+ gemma4Generated: freezeProfile({
171
+ id: "gemma4-generated",
172
+ fidelity: L1,
173
+ requiredCapabilities: ["safetensors", "autoregressive", "gemma4-graph", "generated-graph"],
174
+ execution: {
175
+ loader: "safetensors", graph: "gemma4", loop: "autoregressive", specialization: "generated",
176
+ },
177
+ }),
178
+ gemma4: freezeProfile({
179
+ id: "gemma4-dedicated",
180
+ fidelity: L1,
181
+ requiredCapabilities: ["safetensors", "autoregressive", "gemma4-graph"],
182
+ execution: {
183
+ loader: "safetensors", graph: "gemma4", loop: "autoregressive", specialization: "dedicated",
184
+ },
185
+ }),
186
+ minicpm5: freezeProfile({
187
+ id: "minicpm5-dedicated",
188
+ fidelity: L1,
189
+ requiredCapabilities: ["safetensors", "autoregressive", "minicpm5-graph"],
190
+ execution: {
191
+ loader: "safetensors", graph: "minicpm5", loop: "autoregressive", specialization: "dedicated",
192
+ },
193
+ }),
194
+ qwen35: freezeProfile({
195
+ id: "qwen3.5-dedicated",
196
+ fidelity: L1,
197
+ requiredCapabilities: ["safetensors", "autoregressive", "qwen3.5-graph", "recurrent-state"],
198
+ execution: {
199
+ loader: "safetensors", graph: "qwen3.5", loop: "autoregressive", specialization: "dedicated",
200
+ },
201
+ }),
202
+ qwen3: freezeProfile({
203
+ id: "qwen3-dedicated",
204
+ fidelity: L1,
205
+ requiredCapabilities: ["safetensors", "autoregressive", "qwen3-graph"],
206
+ execution: {
207
+ loader: "safetensors", graph: "qwen3", loop: "autoregressive", specialization: "dedicated",
208
+ },
209
+ }),
210
+ qwen3Moe: freezeProfile({
211
+ id: "qwen3-moe-dedicated",
212
+ fidelity: L1,
213
+ requiredCapabilities: ["safetensors", "autoregressive", "qwen3-moe-graph"],
214
+ execution: {
215
+ loader: "safetensors", graph: "qwen3-moe", loop: "autoregressive", specialization: "dedicated",
216
+ },
217
+ }),
218
+ diffusionGemma: freezeProfile({
219
+ id: "diffusion-gemma-dedicated",
220
+ fidelity: L2,
221
+ requiredCapabilities: ["safetensors", "diffusion", "diffusion-gemma-graph"],
222
+ execution: {
223
+ loader: "safetensors", graph: "diffusion-gemma", loop: "diffusion", specialization: "dedicated",
224
+ },
225
+ }),
226
+ glm52: freezeProfile({
227
+ id: "glm5.2-colibri",
228
+ fidelity: L3,
229
+ requiredCapabilities: ["colibri-container", "autoregressive", "glm5.2-graph", "streamed-experts"],
230
+ execution: {
231
+ loader: "colibri", graph: "glm5.2", loop: "autoregressive", specialization: "dedicated",
232
+ },
233
+ }),
234
+ universal: freezeProfile({
235
+ id: "universal-dense",
236
+ fidelity: L1,
237
+ requiredCapabilities: ["safetensors", "autoregressive", "universal-dense-graph"],
238
+ execution: {
239
+ loader: "safetensors", graph: "universal-dense", loop: "autoregressive", specialization: "generic",
240
+ },
241
+ }),
242
+ } satisfies Record<string, ModelProfile>;
243
+
244
+ /** Return a stable external fingerprint only when the directory is an exact HF
245
+ * snapshot revision. Relocation does not change the identity. Arbitrary local
246
+ * directories and mutable aliases intentionally return null. */
247
+ export function externalArtifactFingerprint(modelDir: string): string | null {
248
+ const match = modelDir.replaceAll("\\", "/").match(
249
+ /(?:^|\/)models--([^/]+)\/snapshots\/([0-9a-f]{40,64})(?:\/|$)/i,
250
+ );
251
+ if (!match) return null;
252
+ const encodedRepo = match[1]!;
253
+ const separator = encodedRepo.indexOf("--");
254
+ if (separator <= 0 || separator === encodedRepo.length - 2) return null;
255
+ const repo = `${encodedRepo.slice(0, separator)}/${encodedRepo.slice(separator + 2)}`;
256
+ return `hf:${repo}@${match[2]!.toLowerCase()}`;
257
+ }
258
+
259
+ function familyProfile(config: ModelConfig, fingerprint: string): ModelProfile {
260
+ if (isGlm52Config(config)) return FAMILY_PROFILES.glm52;
261
+ if (isDiffusionGemmaConfig(config)) return FAMILY_PROFILES.diffusionGemma;
262
+ if (isMiniCPM5Config(config)) return FAMILY_PROFILES.minicpm5;
263
+ if (isQwen35Config(config)) return FAMILY_PROFILES.qwen35;
264
+ if (isQwen3MoeConfig(config)) return FAMILY_PROFILES.qwen3Moe;
265
+ if (isQwen3Config(config)) return FAMILY_PROFILES.qwen3;
266
+ if (config.modelType.startsWith("gemma4"))
267
+ return GENERATED.has(fingerprint) ? FAMILY_PROFILES.gemma4Generated : FAMILY_PROFILES.gemma4;
268
+ if (genericArgsFor(config)) return FAMILY_PROFILES.universal;
269
+
270
+ const arch = remapModelType(config.modelType);
271
+ throw new Error(
272
+ `unsupported model_type "${config.modelType}"` +
273
+ (arch !== config.modelType ? ` (mlx-lm remaps it to "${arch}")` : "") +
274
+ ` — targeted: gemma4*, diffusion_gemma, glm_moe_dsa, qwen3_5, qwen3, qwen3_moe, MiniCPM5;` +
275
+ ` generic (Tier-0): ${[...GENERIC_MODEL_TYPES].sort().join(", ")}`,
276
+ );
277
+ }
278
+
279
+ interface GraphMetadata {
280
+ readonly accepts: (config: ModelConfig) => boolean;
281
+ readonly capabilities: readonly EngineCapability[];
282
+ }
283
+
284
+ const GRAPH_METADATA: Readonly<Record<ModelGraph, GraphMetadata>> = Object.freeze({
285
+ "gemma4": {
286
+ accepts: (config) => config.modelType.startsWith("gemma4"),
287
+ capabilities: ["gemma4-graph"],
288
+ },
289
+ "minicpm5": { accepts: isMiniCPM5Config, capabilities: ["minicpm5-graph"] },
290
+ "qwen3.5": {
291
+ accepts: isQwen35Config,
292
+ capabilities: ["qwen3.5-graph", "recurrent-state"],
293
+ },
294
+ "qwen3": { accepts: isQwen3Config, capabilities: ["qwen3-graph"] },
295
+ "qwen3-moe": { accepts: isQwen3MoeConfig, capabilities: ["qwen3-moe-graph"] },
296
+ "diffusion-gemma": {
297
+ accepts: isDiffusionGemmaConfig,
298
+ capabilities: ["diffusion-gemma-graph"],
299
+ },
300
+ "glm5.2": {
301
+ accepts: isGlm52Config,
302
+ capabilities: ["glm5.2-graph", "streamed-experts"],
303
+ },
304
+ "universal-dense": {
305
+ accepts: (config) => {
306
+ try { return genericArgsFor(config) !== null; } catch { return false; }
307
+ },
308
+ capabilities: ["universal-dense-graph"],
309
+ },
310
+ });
311
+
312
+ function graphAccepts(profile: ModelProfile, config: ModelConfig): boolean {
313
+ return GRAPH_METADATA[profile.execution.graph].accepts(config);
314
+ }
315
+
316
+ function executionCapabilities(profile: ModelProfile): EngineCapability[] {
317
+ const required: EngineCapability[] = [profile.execution.loader === "colibri"
318
+ ? "colibri-container"
319
+ : "safetensors"];
320
+ if (profile.execution.loop === "diffusion") required.push("diffusion");
321
+ else required.push("autoregressive");
322
+ required.push(...GRAPH_METADATA[profile.execution.graph].capabilities);
323
+ if (profile.execution.specialization === "generated") required.push("generated-graph");
324
+ return required;
325
+ }
326
+
327
+ function validateProfile(profile: ModelProfile): void {
328
+ if (!profile.id) throw new Error("model profile id must not be empty");
329
+ if (profile.execution.implementation !== undefined &&
330
+ (!profile.execution.implementation.trim() || !profile.artifactFingerprint ||
331
+ profile.execution.specialization !== "artifact"))
332
+ throw new Error(`model profile ${profile.id} must bind a named implementation to an exact artifact`);
333
+ if ((profile.artifactFingerprint === undefined) !== (profile.configFingerprint === undefined))
334
+ throw new Error(
335
+ `model profile ${profile.id} must declare artifactFingerprint and configFingerprint together`,
336
+ );
337
+ const fidelityOk =
338
+ (profile.fidelity.tier === "l1" && profile.fidelity.oracle === "mlx-lm" &&
339
+ profile.fidelity.claim === "bit-exact") ||
340
+ (profile.fidelity.tier === "l2" && profile.fidelity.oracle === "mlx-optiq" &&
341
+ profile.fidelity.claim === "bit-exact") ||
342
+ (profile.fidelity.tier === "l3" && profile.fidelity.oracle === null &&
343
+ profile.fidelity.claim === "measured");
344
+ if (!fidelityOk) throw new Error(`model profile ${profile.id} has an invalid fidelity contract`);
345
+ const expectedLoader = profile.execution.graph === "glm5.2" ? "colibri" : "safetensors";
346
+ const expectedLoop = profile.execution.graph === "diffusion-gemma"
347
+ ? "diffusion"
348
+ : "autoregressive";
349
+ if (profile.execution.loader !== expectedLoader || profile.execution.loop !== expectedLoop)
350
+ throw new Error(
351
+ `model profile ${profile.id} has an invalid execution composition for ` +
352
+ `${profile.execution.graph}`,
353
+ );
354
+ const declared = new Set(profile.requiredCapabilities);
355
+ const underdeclared = executionCapabilities(profile).filter((capability) => !declared.has(capability));
356
+ if (underdeclared.length)
357
+ throw new Error(
358
+ `model profile ${profile.id} does not declare execution capabilities: ` +
359
+ `${underdeclared.join(", ")}`,
360
+ );
361
+ }
362
+
363
+ export function resolveModelProfile(
364
+ config: ModelConfig,
365
+ options: ResolveModelProfileOptions = {},
366
+ ): ResolvedModelProfile {
367
+ const fingerprint = configFingerprint(config);
368
+ const artifactFingerprint = options.artifactFingerprint === undefined
369
+ ? externalArtifactFingerprint(config.modelDir)
370
+ : options.artifactFingerprint;
371
+ const artifactProfiles = options.artifactProfiles
372
+ ? [...BUILTIN_ARTIFACT_PROFILES, ...options.artifactProfiles]
373
+ : BUILTIN_ARTIFACT_PROFILES;
374
+ const capabilities = new Set(options.engineCapabilities ?? ENGINE_CAPABILITIES);
375
+
376
+ let profile: ModelProfile | undefined;
377
+ let exactArtifact = false;
378
+ if (artifactFingerprint) {
379
+ const matches = artifactProfiles.filter((entry) => {
380
+ validateProfile(entry);
381
+ return entry.artifactFingerprint === artifactFingerprint;
382
+ });
383
+ if (matches.length > 1)
384
+ throw new Error(`multiple model profiles declare artifact ${artifactFingerprint}`);
385
+ profile = matches[0];
386
+ if (profile) {
387
+ exactArtifact = true;
388
+ if (profile.configFingerprint !== fingerprint)
389
+ throw new Error(
390
+ `model profile ${profile.id} matched artifact ${artifactFingerprint}, but config fingerprint ` +
391
+ `${fingerprint} != declared ${profile.configFingerprint}; refusing to fall back`,
392
+ );
393
+ if (!graphAccepts(profile, config))
394
+ throw new Error(
395
+ `model profile ${profile.id} selects ${profile.execution.graph}, which is incompatible with ` +
396
+ `${config.modelType}; refusing to fall back`,
397
+ );
398
+ }
399
+ }
400
+ profile ??= familyProfile(config, fingerprint);
401
+ validateProfile(profile);
402
+ profile = snapshotProfile(profile);
403
+
404
+ const missing = profile.requiredCapabilities.filter((capability) => !capabilities.has(capability));
405
+ if (missing.length)
406
+ throw new Error(
407
+ `model profile ${profile.id} requires missing engine capabilities: ${missing.join(", ")}; ` +
408
+ `refusing to fall back`,
409
+ );
410
+
411
+ return Object.freeze({
412
+ profile,
413
+ artifact: Object.freeze({ fingerprint: artifactFingerprint, configFingerprint: fingerprint }),
414
+ exactArtifact,
415
+ });
416
+ }
417
+
418
+ /** Guard the factory seam when a caller passes a previously resolved profile. */
419
+ export function assertResolvedModelProfile(
420
+ config: ModelConfig,
421
+ resolved: ResolvedModelProfile,
422
+ ): void {
423
+ validateProfile(resolved.profile);
424
+ const fingerprint = configFingerprint(config);
425
+ if (resolved.artifact.configFingerprint !== fingerprint)
426
+ throw new Error(
427
+ `model profile ${resolved.profile.id} was resolved for config ` +
428
+ `${resolved.artifact.configFingerprint}, not ${fingerprint}`,
429
+ );
430
+ if (!graphAccepts(resolved.profile, config))
431
+ throw new Error(
432
+ `model profile ${resolved.profile.id} selects ${resolved.profile.execution.graph}, ` +
433
+ `which is incompatible with ${config.modelType}`,
434
+ );
435
+ if (resolved.exactArtifact !== (resolved.profile.artifactFingerprint !== undefined) ||
436
+ (resolved.exactArtifact &&
437
+ (resolved.profile.artifactFingerprint !== resolved.artifact.fingerprint ||
438
+ resolved.profile.configFingerprint !== fingerprint)))
439
+ throw new Error(
440
+ `model profile ${resolved.profile.id} does not match artifact ` +
441
+ `${resolved.artifact.fingerprint ?? "<unidentified>"}`,
442
+ );
443
+ }
@@ -0,0 +1,12 @@
1
+ // MLX 0.32.2, mlx/backend/metal/scaled_dot_product_attention.cpp (MIT):
2
+ // https://github.com/ml-explore/mlx/blob/v0.32.2/mlx/backend/metal/scaled_dot_product_attention.cpp
3
+ // For the qualified Qwen GQA-6/D256 graph on applegpu_g16s, one-pass/vector
4
+ // selection and two-pass block counts change after these inclusive KV lengths.
5
+ // A committed span must stay within one arithmetic regime to match M=1.
6
+ const ATTENTION_BOUNDARIES = [1023, 1024, 8192, 32768, 65536];
7
+
8
+ export function qwenAppendChunkSize(cacheTokens: number): number {
9
+ for (const end of ATTENTION_BOUNDARIES)
10
+ if (cacheTokens < end) return Math.min(4, end - cacheTokens);
11
+ return 4;
12
+ }
@@ -0,0 +1,52 @@
1
+ // Experimental Qwen GDN convolution. Its two outputs are evaluated together:
2
+ // consuming the activation also materializes the small, independently owned
3
+ // state tail, without keeping a concatenated prefill buffer alive for it.
4
+ // Arithmetic follows MLX 0.31.2 depthwise_conv_1d and unary sigmoid (MIT,
5
+ // Copyright Apple Inc.), preserving the bf16 intermediate rounding.
6
+ import type { MlxArray } from "../mlx/array";
7
+ import { Dtype } from "../mlx/ffi";
8
+ import { MetalKernel } from "../mlx/metal-kernel";
9
+
10
+ /** Borrow all inputs; return owned activation and an independent state tail. */
11
+ export type QwenConvolution = (x: MlxArray, state: MlxArray, weight: MlxArray) => [MlxArray, MlxArray];
12
+
13
+ let kernel: MetalKernel | null = null;
14
+ export const fusedQwenConvolution: QwenConvolution = (x, state, weight) => {
15
+ const [B, M, D] = x.shape as [number, number, number];
16
+ const K = weight.shape[1]!;
17
+ if (x.shape.length !== 3 || weight.shape.length !== 3 || weight.shape[0] !== D ||
18
+ weight.shape[2] !== 1 || K !== 4 || state.shape.join() !== [B, K - 1, D].join() ||
19
+ ![Dtype.bfloat16, Dtype.float32].includes(x.dtype) || state.dtype !== x.dtype || weight.dtype !== x.dtype)
20
+ throw new Error("fused Qwen convolution requires matching bf16/f32 inputs, [B,M,D], [B,3,D], [D,4,1]");
21
+ kernel ??= new MetalKernel({ name: "qwen_causal_conv_silu_tail",
22
+ inputNames: ["state", "x", "w"], outputNames: ["out", "tail"],
23
+ source: String.raw`
24
+ const uint c = thread_position_in_grid.x;
25
+ const uint t = thread_position_in_grid.y;
26
+ const uint b = thread_position_in_grid.z;
27
+ if (c >= D) return;
28
+ if (t < M) {
29
+ float acc = 0.0f;
30
+ for (uint i = 0; i < K; ++i) {
31
+ const uint row = t + i;
32
+ const T value = row < K-1 ? state[(b*(K-1)+row)*D+c] : x[(b*M+row-(K-1))*D+c];
33
+ acc += float(value) * float(w[c*K+i]);
34
+ }
35
+ const T conv = T(acc);
36
+ // Preserve the pinned MLX sigmoid's typed operations and bf16
37
+ // intermediate rounding. Promoting this expression to f32 differs.
38
+ const auto y = 1 / (1 + metal::exp(metal::abs(conv)));
39
+ const T sig = conv < 0 ? y : 1-y;
40
+ out[(b*M+t)*D+c] = conv * sig;
41
+ }
42
+ if (t < K-1) {
43
+ const uint row = M + t;
44
+ tail[(b*(K-1)+t)*D+c] = row < K-1 ? state[(b*(K-1)+row)*D+c] : x[(b*M+row-(K-1))*D+c];
45
+ }
46
+ ` });
47
+ return kernel.apply([state, x, weight], {
48
+ outputs: [{ shape: [B, M, D], dtype: x.dtype }, { shape: [B, K - 1, D], dtype: x.dtype }],
49
+ grid: [D, Math.max(M, K - 1), B], threadGroup: [256, 1, 1],
50
+ templateDtypes: { T: x.dtype }, templateInts: { D, M, K },
51
+ }) as [MlxArray, MlxArray];
52
+ };
@@ -194,10 +194,37 @@ export function gatedDeltaUpdate(
194
194
  * and writes these slots directly; `advance(N)` only tracks token count for
195
195
  * B=1 single-stream (lengths / left_padding are batched-decode concerns).
196
196
  * Not a KVCache, so maybeQuantizeKv skips it. */
197
+ /** One armed speculative verify round on an SSMCache: the pre-round state
198
+ * snapshot (retained refs — MLX arrays are immutable, so this is free) plus
199
+ * the layer's recorded position-local kernel inputs, which make a partial
200
+ * reject bit-exactly replayable: state after the first `keep` window tokens
201
+ * is the same arithmetic prefix whether or not the rejected tail was ever
202
+ * processed. The replay is installed by the OWNING layer (it needs the conv
203
+ * weight / A_log / dt_bias); the cache only stores and frees. */
204
+ export interface SsmSpecRound {
205
+ /** True from specRoundBegin() until the layer's forward records. */
206
+ armed: boolean;
207
+ prevConv: MlxArray | null;
208
+ prevRecurrent: MlxArray | null;
209
+ prevOffset: number;
210
+ /** Pre-conv in_proj output [B,S,convDim] — position-local. */
211
+ qkv: MlxArray | null;
212
+ /** Gate/beta projections [B,S,Hv] — position-local. */
213
+ a: MlxArray | null;
214
+ b: MlxArray | null;
215
+ /** Window length S of the recorded verify forward. */
216
+ S: number;
217
+ /** Layer-bound prefix replay: called AFTER the snapshot is restored onto
218
+ * the cache; advances conv/recurrent/offset by `keep` tokens. */
219
+ replay: ((cache: SSMCache, keep: number) => void) | null;
220
+ }
221
+
197
222
  export class SSMCache implements Cache {
198
223
  conv: MlxArray | null = null;
199
224
  recurrent: MlxArray | null = null;
200
225
  offset = 0;
226
+ /** Live speculative verify round (serial spec lane only; null otherwise). */
227
+ specRound: SsmSpecRound | null = null;
201
228
  /** Per-row token coverage (batch lane only; null on serial B=1 caches,
202
229
  * where `offset` IS the row's count). mlx-lm's ArraysCache tracks no
203
230
  * offset at all (cache.py:594-722) — per-sequence coverage is the
@@ -207,6 +234,10 @@ export class SSMCache implements Cache {
207
234
  * lockstep by advance(), row-filtered by filter(). */
208
235
  offsets: number[] | null = null;
209
236
 
237
+ signature(): string { return "ssm"; }
238
+ bytesPerToken(): number { return 0; }
239
+ get batchSize(): number { return this.offsets?.length ?? 1; }
240
+
210
241
  /** Row `i`'s own token coverage (per-row when batched, `offset` serial). */
211
242
  rowOffset(i: number): number {
212
243
  return this.offsets ? this.offsets[i]! : this.offset;
@@ -241,14 +272,77 @@ export class SSMCache implements Cache {
241
272
  }
242
273
 
243
274
  isTrimmable(): boolean {
244
- return false; // recurrent state can't be rolled back per token
275
+ return false; // recurrent state can't be trimmed per token — see specRound*
245
276
  }
246
277
 
247
278
  trim(_n: number): void {
248
279
  throw new Error("SSMCache is not trimmable");
249
280
  }
250
281
 
282
+ // --- speculative verify-round support (serial spec lane, B=1) ------------
283
+ // The serve loop arms a round before the verify forward and resolves it
284
+ // after the accept walk. The layer's forward, seeing an armed round, hands
285
+ // its replaced state slots to the round instead of disposing them, records
286
+ // qkv/a/b, and installs the replay. Cache/interface contract:
287
+ // rollback(keep) restores the snapshot then replays `keep` window tokens
288
+ // bit-exactly; commit frees the snapshot + recordings.
289
+
290
+ specRoundBegin(): void {
291
+ this.#dropSpecRound(); // defensive: a mid-round throw left a stale round
292
+ this.specRound = {
293
+ armed: true,
294
+ prevConv: null,
295
+ prevRecurrent: null,
296
+ prevOffset: this.offset,
297
+ qkv: null,
298
+ a: null,
299
+ b: null,
300
+ S: 0,
301
+ replay: null,
302
+ };
303
+ }
304
+
305
+ specRoundCommit(): void {
306
+ this.#dropSpecRound();
307
+ }
308
+
309
+ specRoundRollback(keep: number): void {
310
+ const r = this.specRound;
311
+ if (!r) throw new Error("SSMCache.specRoundRollback without an armed round");
312
+ if (r.armed)
313
+ throw new Error("SSMCache.specRoundRollback before the verify forward recorded");
314
+ if (keep < 0 || keep > r.S)
315
+ throw new Error(`SSMCache.specRoundRollback keep=${keep} outside window S=${r.S}`);
316
+ // Restore the pre-round snapshot (ownership moves back to the cache).
317
+ this.conv?.dispose();
318
+ this.recurrent?.dispose();
319
+ this.conv = r.prevConv;
320
+ this.recurrent = r.prevRecurrent;
321
+ r.prevConv = null;
322
+ r.prevRecurrent = null;
323
+ this.offset = r.prevOffset;
324
+ if (this.offsets)
325
+ throw new Error("SSMCache.specRoundRollback on a batched cache (serial lane only)");
326
+ if (keep > 0) {
327
+ if (!r.replay) throw new Error("SSMCache.specRoundRollback with no recorded replay");
328
+ r.replay(this, keep); // advances conv/recurrent/offset by `keep`
329
+ }
330
+ this.#dropSpecRound();
331
+ }
332
+
333
+ #dropSpecRound(): void {
334
+ const r = this.specRound;
335
+ if (!r) return;
336
+ r.prevConv?.dispose();
337
+ r.prevRecurrent?.dispose();
338
+ r.qkv?.dispose();
339
+ r.a?.dispose();
340
+ r.b?.dispose();
341
+ this.specRound = null;
342
+ }
343
+
251
344
  dispose(): void {
345
+ this.#dropSpecRound();
252
346
  this.conv?.dispose();
253
347
  this.recurrent?.dispose();
254
348
  this.conv = null;
@@ -304,6 +398,8 @@ export class SSMCache implements Cache {
304
398
  if (this.offsets) this.offsets = keep.map((i) => this.offsets![i]!);
305
399
  }
306
400
 
401
+ filterRows(keep: readonly number[]): void { this.filter([...keep]); }
402
+
307
403
  /** Row `i` as a fresh SERIAL cache — port of mlx-lm ArraysCache.extract
308
404
  * (cache.py:673-676: `cache.cache = [c[idx : idx + 1] for c in self.cache]`,
309
405
  * a B-axis slice of every state slot). Ours are OWNED contiguous copies
@@ -319,7 +415,7 @@ export class SSMCache implements Cache {
319
415
  const hi = [...a.shape];
320
416
  hi[0] = i + 1;
321
417
  const view = a.slice(lo, hi);
322
- const own = ops.contiguous(view);
418
+ const own = ops.copyOf(view); // TRUE copy: contiguous(view) is a no-op VIEW when already contiguous — pins the source buffer (2026-08-20 DeltaNet conv leak class)
323
419
  view.dispose();
324
420
  return own;
325
421
  };