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
@@ -1,384 +1,705 @@
1
- # Generic model support — run anything mlx-lm runs
1
+ ---
2
+ status: active
3
+ axis: ON
4
+ canonical-for: model-support
5
+ plan-anchor: "Serving architecture consolidation `[~]` (opened 2026-08-21)"
6
+ last-verified: 2026-08-23
7
+ ---
8
+
9
+ # Model support — run anything mlx-lm runs, and the ports we target
2
10
 
3
- **Status: Phase 1 + 1.5 BUILT (2026-07-01, commit 9bd9f1b)** — `src/model/universal/`
4
- (UniversalDense + descriptor table for 11 archs, rope factory bit-exact vs oracle
5
- fixtures, DenseLinear/bf16 checkpoints, weight audit, dispatch ladder in
6
- factory/support, manifest-driven parity harness). Parity gates light per-model
7
- once the small checkpoints are downloaded (`scripts/regen-universal-goldens.ts` →
8
- `MLX_BUN_TEST_UNIVERSAL=1`). Phases 2 (UniversalMoE), 3 (SSM/MLA one-offs),
9
- 4 (`mlx-bun port` scaffold) remain design.
11
+ **This is the one design doc for model support.** New model ports become
12
+ SECTIONS under §6 (Ports) of this file, not new files in `docs/design/`.
13
+ Per-port phase logs, gate results, and dates belong in PLAN.md (anchors are
14
+ named per section); this doc keeps the design and the oracle each port is
15
+ held to.
10
16
 
11
17
  Direction (Josh): *"we should be able to run any model that mlx-lm can run.
12
18
  Run any model generically; for the specific models we target, optimize them
13
19
  further — push the quality/performance border outwards. Like the gemma
14
20
  generator methodology."*
15
21
 
16
- The architecture already embodies the two-tier idea for one family:
17
- `src/model/gemma4-base.ts` (shared machinery) + `gemma4.ts` (config-driven
18
- monolith) + `src/model/generated/*.ts` (codegen'd specializations via
19
- `scripts/gen-model.ts`, gated bit-exact by `tests/generated-parity.test.ts`).
20
- This doc generalizes that shape to the whole mlx-lm zoo:
22
+ Two tiers, one contract:
21
23
 
22
24
  - **Tier-0 GENERIC** — one config-driven "universal" module per architecture
23
- *family* (dense llama-family first, MoE second). Runs any covered checkpoint
24
- at **L1 parity** (bit-exact vs mlx-lm on this machine's GPU). Monolith path
25
- only: no compiled decode, no kv-quant. Slow, never broken.
26
- - **Tier-1 TARGETED** — a model *graduates*: dedicated/generated forward,
27
- optiq-quant **L2** parity, Lab experiments where warranted, benchmark
28
- entries. Exactly what gemma4 / minicpm5 / qwen3_5 already are.
29
-
30
- The fidelity contract is unchanged (three-level tree): **L1 = mlx-lm
31
- bit-exact is the gate for ANY new model**, generic or targeted. A model the
32
- generic tier cannot hold to L1 parity is not "supported with caveats" — it is
33
- unsupported until fixed.
25
+ *family*. Runs any covered checkpoint at **L1 parity** (bit-exact vs mlx-lm
26
+ on this machine's GPU). Monolith path only, without compiled decode.
27
+ Standard attention now uses the shared plain/affine KV port; the softcap
28
+ branch retains plain KV. Qualified full-attention targets compose delayed
29
+ affine conversion with standalone and lookup drafting through the same
30
+ cache transaction interface; rotating layouts use that interface for
31
+ per-layer conversion and assistant donors. Built: `src/model/universal/` (dense
32
+ llama-family). Design only: UniversalMoE.
33
+ - **Tier-1 TARGETED** — a model *graduates*: dedicated or generated forward,
34
+ L2 (mlx-optiq) composition where an optiq artifact exists, Lab experiments
35
+ where warranted, benchmark entries. The ports in §6.
36
+
37
+ **L1 = mlx-lm bit-exact is the gate for ANY new model**, generic or targeted.
38
+ Where no mlx-lm arm exists (audio, vision towers, DiffusionGemma, GLM-5.2's
39
+ Colibri container) the oracle is whoever ships the capability — optiq's
40
+ internal machinery, mlx-vlm, or the pinned Colibri engine — and the profile
41
+ declares that fidelity honestly (§3). A model the generic tier cannot hold to
42
+ L1 parity is not "supported with caveats"; it is unsupported until fixed.
34
43
 
35
44
  ---
36
45
 
37
- ## 1. The mlx-lm model zoo, inventoried
46
+ ## 1. The mlx-lm zoo, inventoried (mlx-lm 0.31.3, the oracle venv)
38
47
 
39
- Source: `mlx-lm 0.31.3` (the oracle venv),
40
- `site-packages/mlx_lm/models/*.py`. **108 model files** after excluding
48
+ 108 model files in `site-packages/mlx_lm/models/` after excluding
41
49
  infrastructure (`base`, `cache`, `rope_utils`, `activations`,
42
50
  `switch_layers`, `ssm`, `gated_delta`, `mla`, `bitlinear_layers`,
43
- `pipeline`). `utils.py MODEL_REMAPPING` adds free aliases on top
44
- (`mistral→llama`, `kimi_k2→deepseek_v3`, `qwen2_5_vl→qwen2_vl`,
45
- `minimax_m2→minimax`, `iquestcoder→llama`, `falcon_mamba→mamba`, …).
46
-
47
- ### Buckets (by reading llama.py in full + feature-grep + sampling ~20 files)
48
-
49
- **A. Dense llama-family — ~36 files, one parameterized module covers them.**
50
- All are: embed → N × (norm → GQA-attention(+rope) → residual → norm →
51
- MLP → residual) → norm → head. Every file is a ~170–240-line permutation of
52
- the same dozen knobs (verified deltas listed in §3.1):
53
-
54
- > llama (+mistral, iquestcoder via remap), qwen2, qwen3, gemma, gemma2,
55
- > helium, olmo2, olmo3, smollm3, starcoder2, stablelm, phi3, internlm2,
56
- > internlm3, granite, exaone, exaone4, glm, glm4, nemotron, minicpm, mimo,
57
- > ministral3, seed_oss, hunyuan_v1_dense, ernie4_5, cohere, cohere2,
58
- > apertus, nanochat, lille-130m, telechat3, solar_open, olmo, phi, plamo
59
-
60
- (`smollm3` is literally a 75-line subclass of `llama` that swaps some
61
- layers' rope for a no-op; `solar_open` is 38 lines. mlx-lm itself treats
62
- this family as one module with per-file ModelArgs.)
63
-
64
- **B. MoE llama-family (SwitchGLU experts) — ~17 files, a second module.**
65
- Same block, MLP replaced by router + `SwitchGLU` (+ optional shared expert):
66
-
67
- > mixtral, qwen2_moe, qwen3_moe, olmoe, phimoe, dots1, granitemoe,
68
- > ernie4_5_moe, glm4_moe, hunyuan, Klear, bailing_moe, exaone_moe, deepseek
69
- > (v1: MoE without MLA), step3p5, mimo_v2_flash, afmoe
70
- > (llama4_text / gpt_oss are near-family but carry extra deltas —
71
- > chunked-attention/NoPE, attention sinks.)
72
-
73
- **C. MLA lineage (DeepSeek latent attention, usually + MoE + yarn) — ~11:**
74
- > deepseek_v2, deepseek_v3 (+kimi_k2 remap), deepseek_v32, glm4_moe_lite,
75
- > glm_moe_dsa, kimi_k25, kimi_vl, longcat_flash(+ngram), minicpm3, youtu_llm
76
-
77
- **D. SSM / hybrid / linear-attention — ~17, individually shaped:**
78
- > mamba, mamba2 (+falcon_mamba remap), falcon_h1, jamba, granitemoehybrid,
79
- > nemotron_h, plamo2, lfm2, lfm2_moe, qwen3_next, kimi_linear, minimax,
80
- > recurrent_gemma, rwkv7, baichuan_m1, **qwen3_5 (already ported)**,
81
- > qwen3_5_moe
82
-
83
- **E. Legacy / exotic one-offs — ~13, deprioritized:**
84
- > gpt2, gpt_bigcode, gpt_neox, qwen (v1), openelm (per-layer varying dims),
85
- > phi3small (blocksparse attn), phixtral, dbrx, nemotron-nas (variable
86
- > blocks), bitnet (bitlinear), afm7, baichuan_m1 (also in D), lille-130m-ish
87
- > oddities
88
-
89
- **F. Vision/text wrappers — ~10, ~free once the text base exists:**
90
- > gemma3, gemma4 (ours already), qwen2_vl (+qwen2_5_vl), qwen3_vl,
91
- > qwen3_vl_moe, kimi_vl, lfm2-vl, mistral3 (+llava remap), pixtral, llama4
92
- > — mlx-lm runs only their *text* stack; each wrapper is ~50–120 lines of
93
- > config unwrapping + weight-prefix stripping.
94
-
95
- ### Coverage math
96
-
97
- | Bucket | Files | Unlocked by |
98
- |---|---|---|
99
- | A. dense llama-family | ~36 (33%) | **one** UniversalDense module (Phase 1) |
100
- | B. MoE llama-family | ~17 (16%) | **one** UniversalMoE module (Phase 2) |
101
- | F. vision wrappers | ~10 (9%) | thin config/prefix shims over A/B (Phase 1–2) |
102
- | C. MLA lineage | ~11 (10%) | one MLA attention module (Phase 3, demand-driven — most are >24 GB even at 4-bit) |
103
- | D. SSM/hybrid | ~17 (16%) | individual ports, qwen3_5 pattern (Phase 3) |
104
- | E. legacy/exotic | ~13 (12%) | individual ports, likely never |
105
- | already in mlx-bun | 5 | gemma4(+text), qwen3, qwen3_5, minicpm5(llama-typed), diffusion_gemma |
106
-
107
- **Two generic modules + the wrapper shims ≈ 60% of the zoo by file count,
108
- and >90% of what actually gets downloaded** (Llama 3.x, Mistral/Ministral,
109
- Qwen 2.5/3 dense+MoE, Gemma 1–3, Phi-3/4, SmolLM3, OLMo-2/3, GLM-4,
110
- Granite, Mixtral, OLMoE are all in A/B/F).
51
+ `pipeline`). `utils.py MODEL_REMAPPING` adds free aliases (`mistral→llama`,
52
+ `kimi_k2→deepseek_v3`, `qwen2_5_vl→qwen2_vl`, `falcon_mamba→mamba`, …).
53
+
54
+ | Bucket | ~Files | Shape | Unlocked by |
55
+ |---|---|---|---|
56
+ | A. dense llama-family | ~36 | embed → N × (norm → GQA attn(+rope) → residual → norm → MLP → residual) → norm → head; every file a permutation of a dozen knobs | **UniversalDense** (built) |
57
+ | B. MoE llama-family | ~17 | same block, MLP → router + SwitchGLU (+ shared expert) | **UniversalMoE** (design) |
58
+ | F. vision/text wrappers | ~10 | mlx-lm runs only the text stack; ~50–120 lines of config unwrapping + prefix stripping | thin shims over A/B |
59
+ | C. MLA lineage | ~11 | DeepSeek latent attention, usually + MoE + yarn | one MLA module, demand-driven (most exceed local RAM at 4-bit) |
60
+ | D. SSM / hybrid / linear-attention | ~17 | individually shaped (mamba, jamba, lfm2, qwen3_next, rwkv7, qwen3_5 …) | individual ports, the qwen3_5 pattern |
61
+ | E. legacy / exotic | ~13 | gpt2, openelm, phi3small, dbrx, bitnet … | individual ports, likely never |
62
+
63
+ Two generic modules + the wrapper shims cover roughly 60% of the zoo by
64
+ file count and the large majority of what actually gets downloaded (Llama
65
+ 3.x, Mistral/Ministral, Qwen 2.5/3 dense+MoE, Gemma 1–3, Phi-3/4, SmolLM3,
66
+ OLMo-2/3, GLM-4, Granite, Mixtral, OLMoE are all in A/B/F).
111
67
 
112
68
  ---
113
69
 
114
- ## 2. What mlx-bun already has to build on
115
-
116
- Audited 2026-07-01; file references are load-bearing.
70
+ ## 2. Building blocks (what every tier is made of)
117
71
 
118
- - **Config parsing** — `src/config.ts loadModelConfig`: already a *normalized*
119
- config (`TextConfig`) with per-model_type quirk handling inline (gemma
120
- nested `text_config`, qwen3_5 flat rope dict, llama defaults, diffusion
121
- backfill). Already carries: layerTypes/slidingWindow, headDim fallback,
122
- tie, softcap, partialRotaryFactor, `ropeParameters` map, per-layer quant
123
- map (`quantFor`), kv_config. **This is 70% of the normalization layer;**
124
- it needs the delta fields from §3.1 and a table-driven (not if-chain)
125
- quirk mechanism before it drowns.
72
+ - **Config parsing** — `src/config.ts loadModelConfig` produces a normalized
73
+ `TextConfig` (layerTypes/slidingWindow, headDim fallback, tie, softcap,
74
+ partialRotaryFactor, `ropeParameters`, per-layer quant map via `quantFor`,
75
+ kv_config, sidecar detection). Per-arch quirks for the generic tier live in
76
+ the descriptor table (§4.1), not in this if-chain.
126
77
  - **Primitives** — `src/model/gemma4-base.ts`: `QuantizedLinear` (+LoRA
127
78
  residual), `QuantizedEmbedding` (+tied `asLinear`), `RMSNorm`,
128
- `QuantizedSwitchLinear` (MoE experts — already used by 26B),
129
- `KVCache`/`RotatingKVCache`(+quantized variants), mask machinery,
130
- `logitSoftcap`, `disposing`. `src/model/qwen3.ts` (276 lines) is the
131
- proof-of-shape: a complete dense port using only these primitives.
132
- `minicpm5.ts`/`qwen3_5.ts` show the "dedicated module conforming to
133
- RuntimeModel" pattern.
134
- - **Gating/dispatch** — `src/model/support.ts` (allowlist by model_type +
135
- config predicates), `src/model/factory.ts` (specific classes →
136
- fingerprint-matched generated class → monolith; *rejects* unknown types),
137
- `src/model/fingerprint.ts` (structural hash for generated dispatch).
138
- - **Generator** — `scripts/gen-model.ts`: emits unrolled, branch-resolved
139
- `forwardLayers` overrides *of Gemma4Model specifically* (reads the shard
140
- index for layout facts, folds kv-quant constants, guards cache signature,
141
- falls back to monolith). Gated by `tests/generated-parity.test.ts`
142
- (bit-exact vs monolith, fingerprint asserted, fast-path-use asserted).
143
- - **Parity harness** — the `scripts/regen-*-goldens.ts` +
144
- `tests/*-parity.test.ts` pattern (e.g. `regen-qwen-parity-goldens.ts`):
145
- oracle venv emits `<prefix>-parity.json` (explicit prompt ids + greedy
146
- ids) + per-step raw logit `.bin`s; the test replays ids (no cross-stack
147
- tokenizer dependency) and compares bit-exact on the same GPU. Plus
148
- `scripts/check-minicpm5-port.ts` (hard, no-skip port check) and
149
- `scripts/inspect-model.ts` (tensor name/shape/dtype dump — the seed of
150
- the weight audit).
151
- - **Tokenizer** — `src/tokenizer.ts`: `@huggingface/tokenizers` (pure JS)
152
- reads stock `tokenizer.json` + `tokenizer_config.json`; already
153
- generic across BPE/SentencePiece-as-tokenizer.json. Known landmine class:
154
- BOS conventions (the double-BOS bug cost a debug session — see memory);
155
- chat-template rendering rides Pi, with `/v1` as the boundary.
156
-
157
- ### Gaps the generic tier must close (found in this audit)
158
-
159
- 1. **No unquantized Linear.** `QuantizedLinear.load` throws without a
160
- `.scales` tensor (`gemma4-base.ts:94`). Tier-0 v1 can inherit this
161
- constraint (target mlx-community 4/8-bit checkpoints — what users pull
162
- anyway), but a plain `DenseLinear` (bf16/fp16 `ops.matmul`) is a required
163
- fast-follow: many small models ship only fp16.
164
- 2. **No additive linear bias.** `QuantizedLinear`'s `biases` are quant
165
- zero-points, not a bias *term*. qwen2 (attention qkv bias), stablelm,
166
- starcoder2, phi et al. need an optional post-matmul `+ bias` in the
167
- linear primitive.
168
- 3. **Rope variants.** Only default/proportional exist in the runtime.
169
- mlx-lm `rope_utils.py` also ships: `linear`, `llama3` (Llama3RoPE),
170
- `yarn` (3 spellings), `longrope`/`su` (SuScaledRoPE), `mrope`. llama3 +
171
- yarn + longrope are hard requirements for bucket A (Llama 3.x, Phi-3,
172
- DeepSeek-lineage, various long-context finetunes).
173
- 4. **Attention-score softcap** (gemma2): needs the manual
174
- (q·kᵀ → tanh-cap → softmax) path — `ops.sdpa` can't express it.
175
- 5. **factory.ts rejects unknown types** rather than attempting a generic
176
- fallback (by design today; changes in §3.3).
79
+ `QuantizedSwitchLinear` (MoE experts), `KVCache`/`RotatingKVCache` (+
80
+ quantized and TurboQuant variants), mask machinery, `logitSoftcap`,
81
+ `disposing`. `src/model/universal/modules.ts` adds the dense
82
+ (unquantized) `nn.Linear`/`nn.Embedding` ports and the load-time
83
+ `WeightAudit`.
84
+ - **Generator** — `scripts/gen-model.ts` emits unrolled, branch-resolved
85
+ `forwardLayers` overrides of `Gemma4Model` into `src/model/generated/`
86
+ (e4b, 12B, 26B), dispatched by config fingerprint, gated bit-exact vs the
87
+ monolith by `tests/generated-parity.test.ts`.
88
+ - **Parity harness** — `scripts/regen.ts <job>` (jobs: `parity`,
89
+ `parity-26b`, `kvq`, `rotating-kvq`, `mixed-kv`, `lora`, `fused-sdpa`,
90
+ `universal`, `qwen-parity`, `minicpm5`, `minicpm5-kv`, `turboquant`,
91
+ `audio-fixtures`) drives the oracle venv
92
+ (`/Users/joshrossi/Code/mlx-lm/.venv/bin/python`) to emit
93
+ `<prefix>-parity.json` (explicit prompt ids + greedy ids) plus per-step raw
94
+ logit `.bin`s; `tests/*-parity.test.ts` replay the ids (no cross-stack
95
+ tokenizer dependency) and compare bit-exact on the same GPU. Manifests are
96
+ tracked; `.bin` blobs are machine-specific and untracked
97
+ (goldens/README.md).
98
+ - **Tokenizer** — `src/tokenizer.ts` (`@huggingface/tokenizers`, pure JS)
99
+ reads stock `tokenizer.json` + `tokenizer_config.json`. Known landmine:
100
+ BOS conventions (the double-BOS bug). Chat-template rendering rides Pi;
101
+ `/v1` is the boundary.
177
102
 
178
103
  ---
179
104
 
180
- ## 3. Design
181
-
182
- ### 3.1 Tier-0: `UniversalDense` (src/model/universal/)
105
+ ## 3. Model profiles — capability declaration (`src/model/profile.ts`)
183
106
 
184
- One module, shaped exactly like `qwen3.ts` but every delta a config field.
185
- **The normalized config is the union of mlx-lm's per-arch ModelArgs**, and a
186
- declarative **arch descriptor table** supplies per-model_type defaults +
187
- config-key aliases — mirroring mlx-lm's structure (shared base module,
188
- per-arch args) without one file per arch:
107
+ Model loading resolves ONE immutable profile before weights are opened.
108
+ A profile declares **construction only**: request-level methods (MTP, KV
109
+ schemes, adapters, grammar, sampling) are resolved elsewhere and cannot be
110
+ rewritten by profile selection.
189
111
 
190
112
  ```ts
191
- // src/model/universal/archs.ts — ~15–25 lines per arch vs mlx-lm's ~200
192
- export interface ArchDescriptor {
193
- // block structure
194
- block: "sequential" | "sandwich" | "parallel"; // llama | gemma2/glm4 | cohere/phi
195
- norm: { kind: "rmsnorm" | "layernorm"; plusOne?: boolean; bias?: boolean };
196
- qkNorm: "none" | "head-rms" | "layernorm-2d"; // qwen3/olmo2 | cohere
197
- mlp: { kind: "gated" | "plain"; act: "silu" | "gelu" | "gelu_tanh" | "relu2" };
198
- fusedQkv?: boolean; fusedGateUp?: boolean; // phi3 — split in sanitize
199
- // scalars (all read from config.json when present; descriptor = default)
200
- attnLogitSoftcap?: number; // gemma2
201
- logitScale?: ConfigPath; // cohere (multiply), granite logits_scaling (divide)
202
- embedScale?: "sqrt-hidden" | "mup" | null; // gemma family, minicpm
203
- residualMultiplier?: ConfigPath; // granite
204
- bias: { qkv?: boolean; o?: boolean; mlp?: boolean };
205
- nope?: "interval" | "list"; // smollm3, llama4-style no-rope layers
206
- // weights
207
- weightMap?: Partial<Record<CanonicalName, string>>; // starcoder2 c_fc/c_proj, gpt2 h.N.*
208
- sanitize?: (names: string[]) => Rename[]; // fused-proj splits, inv_freq drops
209
- configAliases?: Record<string, string>; // norm_epsilon→rms_norm_eps etc.
113
+ interface ModelProfile {
114
+ id: string;
115
+ artifactFingerprint?: string; // exact external identity (hf:<repo>@<rev>); family profiles omit
116
+ configFingerprint?: string; // structural guard for an exact artifact declaration
117
+ fidelity: FidelityTarget; // {l1, mlx-lm, bit-exact} | {l2, mlx-optiq, bit-exact} | {l3, null, measured}
118
+ requiredCapabilities: EngineCapability[];
119
+ execution: { loader: "safetensors" | "colibri";
120
+ graph: "gemma4" | "minicpm5" | "qwen3.5" | "qwen3" | "qwen3-moe"
121
+ | "diffusion-gemma" | "glm5.2" | "universal-dense";
122
+ loop: "autoregressive" | "diffusion";
123
+ specialization: "artifact" | "dedicated" | "generated" | "generic" };
210
124
  }
211
- export const ARCHS: Record<string /* model_type */, ArchDescriptor> = { ... };
212
125
  ```
213
126
 
127
+ Engine capabilities (`ENGINE_CAPABILITIES`): `autoregressive`,
128
+ `colibri-container`, `diffusion`, `diffusion-gemma-graph`, `gemma4-graph`,
129
+ `generated-graph`, `glm5.2-graph`, `minicpm5-graph`, `mixed-precision-kv`,
130
+ `native-mtp`, `qwen3-graph`, `qwen3-moe-graph`, `qwen3.5-graph`,
131
+ `recurrent-state`, `safetensors`, `streamed-experts`,
132
+ `universal-dense-graph`, `vision-sidecar`.
133
+
134
+ Resolution (`resolveModelProfile`):
135
+
136
+ 1. **Exact artifact profiles outrank family profiles.** The external
137
+ fingerprint is derived only from an immutable HF snapshot path
138
+ (`models--<org>--<repo>/snapshots/<40–64 hex>`); relocation keeps the
139
+ identity, mutable aliases and arbitrary local dirs return null. A matched
140
+ exact profile whose config fingerprint or graph acceptance mismatches
141
+ REFUSES — it never falls back. Built-in exact declarations today:
142
+ `qwen3.8-27b-optiq-4bit` (L1) and `glm5.2-colibri-int4-int8-mtp` (L3).
143
+ 2. **Family profile** by config predicate (`src/model/support.ts`), in this
144
+ order: `glm_moe_dsa` → `diffusion_gemma` → MiniCPM5 (exact-shape `llama`
145
+ predicate) → `qwen3_5`/`qwen3_5_text` (dense hybrid only; the MoE variant
146
+ is excluded) → `qwen3_moe` → `qwen3` → `gemma4*` (generated class if
147
+ `GENERATED.has(fingerprint)`, else monolith) → universal-dense if
148
+ `genericArgsFor(config)` resolves → throw naming the targeted list and
149
+ the generic descriptor keys.
150
+ 3. `validateProfile` enforces the fidelity/oracle pairing, loader↔graph
151
+ (`glm5.2` ⇒ colibri), loop↔graph (`diffusion-gemma` ⇒ diffusion), and that
152
+ every capability the execution composition implies is declared. Missing
153
+ engine capabilities refuse; nothing downgrades.
154
+
155
+ **Factory** (`src/model/factory.ts`): `openModel(dir)` resolves the profile,
156
+ routes `loader: "colibri"` through `openGlm52RuntimeModel` (header-only
157
+ memory plan first, then `Glm52Model.openStreamed`; the Colibri snapshot has no
158
+ `model.safetensors.index.json` so it bypasses `Weights.open`), and otherwise
159
+ `createModel(weights, config, profile)` switches on `execution.graph`.
160
+ `RuntimeModel` = `Gemma4Model | MiniCPM5Model | Qwen35Model | Qwen3Model |
161
+ Qwen3MoeModel | DiffusionGemmaModel | Glm52Model | UniversalDenseModel`.
162
+
163
+ **Support tiers in UX** (`supportTier(modelType, repoId)` →
164
+ `"targeted" | "generic" | null`): consumed by `mlx-bun ls`
165
+ (src/cli.ts), `src/hub-rest.ts`, and the serve discovery routes. Drafters
166
+ (`*_assistant`) are never selectable on their own. Note the MiniCPM5
167
+ *record*-level check keys on the repo id containing
168
+ `minicpm5-1b-optiq-4bit`; the config-level check is the exact-shape predicate.
169
+
170
+ Reference mirror of this section: docs/reference/models.md "Declared model
171
+ profiles" (keep in sync).
172
+
173
+ ---
174
+
175
+ ## 4. Tier-0 design
176
+
177
+ ### 4.1 `UniversalDense` (`src/model/universal/`)
178
+
179
+ One module (`dense.ts`), shaped like `qwen3.ts`, with every arch delta
180
+ selected by a `UniversalArgs` descriptor. `archs.ts` holds an explicit
181
+ table keyed by `model_type` (mlx-lm's `MODEL_REMAPPING` vendored in) — no
182
+ config sniffing to *identify* an arch; fingerprints remain a generated-
183
+ dispatch guard only. Descriptors in the table today (11):
184
+ **llama, smollm3, qwen2, qwen3, gemma, gemma2, phi3, olmo2, glm4, granite,
185
+ starcoder2**. `GENERIC_MODEL_TYPES` = the table's keys.
186
+
214
187
  Key choices:
215
188
 
216
- - **Descriptor keyed by `model_type` + mlx-lm's MODEL_REMAPPING table
217
- vendored in.** No config sniffing/fingerprinting to *identify* an arch —
218
- fingerprints stay what they are today: a dispatch guard for generated
219
- specializations. Explicit table = explicit support surface = honest
220
- `mlx-bun models` output.
221
- - **Transcribe mlx-lm op-for-op** inside the universal forward, per
222
- descriptor branch — same discipline as every existing port (q/k-norm
223
- before vs after transpose, rope order, cast points). The descriptor
224
- selects branches; it never approximates.
225
- - **Rope factory** `src/model/universal/rope.ts` ports
226
- `rope_utils.initialize_rope` verbatim: default/linear (native
227
- `ops.rope` with scale), llama3 (precomputed freqs), yarn, longrope/su.
228
- This is the single riskiest chunk of Phase 1 — rope bugs are
229
- off-by-a-little and only caught by logit goldens, which is why the parity
230
- gate feeds explicit ids and compares raw logits per step.
231
- - **KV cache**: reuse `KVCache`/`RotatingKVCache` unchanged;
232
- `layer_types`/`sliding_window` already normalized. No kv-quant at Tier-0
233
- (that's an L2/graduation concern).
234
- - **Quantization**: v1 requires MLX-quantized checkpoints (`.scales`
235
- present), same as the rest of the runtime; `DenseLinear` for
236
- fp16/bf16 checkpoints is Phase 1.5. Add the additive-bias term to both.
237
- - **RuntimeModel surface**: implement the same minimal contract
238
- `Qwen3Model` does (config, weightsBytes, loraState, makeCache,
239
- forwardHidden, logitsFromHidden, forward, generate, loraTargets) so
240
- serving/eval/LoRA hot-swap work day one. `forwardEmbeddings` throws
241
- (vision is per-arch work).
242
-
243
- ### 3.2 Tier-0.5: `UniversalMoE`
189
+ - **Transcribe mlx-lm op-for-op** inside each descriptor branch (q/k-norm
190
+ before vs after reshape, rope order, scale points, softcap, mask kinds).
191
+ The descriptor selects branches; it never approximates.
192
+ - **Rope factory** (`rope.ts`) — faithful port of `rope_utils.initialize_rope`:
193
+ default / linear / llama3 / yarn / longrope (SuScaledRoPE) / proportional.
194
+ Frequency tables are computed with the same mlx float32 ops the oracle uses
195
+ at module init so the bytes match; host double math only where the oracle
196
+ uses python floats. Gated by `tests/universal-rope.test.ts` against
197
+ machine-keyed oracle fixtures (`tests/fixtures/universal-rope/`).
198
+ - **Dense checkpoints** (`modules.ts`) — verbatim `mlx.nn.Linear`
199
+ (`addmm(bias, x, W.T)` / `x @ W.T`) and `nn.Embedding`; quantized paths
200
+ delegate to gemma4-base. Additive bias is a first-class field (qwen2 qkv,
201
+ starcoder2 all-bias).
202
+ - **Weight audit at load** — `WeightAudit.finish` diffs consumed tensors
203
+ against the shard index minus the arch's sanitize-drop rules; unconsumed
204
+ or missing tensors are a LOAD ERROR naming them, never a silently-wrong
205
+ model.
206
+ - **KV cache** — `KVCache`/`RotatingKVCache` unchanged; `layer_types` /
207
+ `sliding_window` already normalized. Standard attention consumes the shared
208
+ cache-attention interface; qualified Llama uniform KV4/KV8 serving and
209
+ generated-cache coverage are described in batching.md.
210
+ - **RuntimeModel surface** — the minimal contract `Qwen3Model` implements
211
+ (config, weightsBytes, loraState, makeCache, forwardHidden,
212
+ logitsFromHidden, forward, generate, loraTargets) so serving/eval/LoRA
213
+ hot-swap work day one. `forwardEmbeddings` is a stub (vision is per-arch).
214
+
215
+ ### 4.2 The parity gate for a new generic arch
216
+
217
+ `tests/universal-manifest.ts` — one entry per launch arch pointing at the
218
+ SMALLEST mlx-community 4-bit checkpoint of that arch, skip-if-absent, with
219
+ `expectClass: "universal" | "dedicated"` (the `qwen3` entry expects
220
+ `Qwen3Model` — generic never shadows targeted, the gate still runs the
221
+ oracle bar). Flow: user downloads → `bun scripts/regen.ts universal [<prefix>|all]`
222
+ → `MLX_BUN_TEST_UNIVERSAL=1 bun test tests/universal-parity.test.ts`.
223
+ Asserts: fingerprint-free construction, weight audit clean, greedy
224
+ trajectory match, per-step logits bit-exact.
225
+
226
+ **Definition of supported-generic = manifest entry green on the current
227
+ machine.** Adding a descriptor without its manifest goldens is the one
228
+ anti-pattern this design forbids.
229
+
230
+ ### 4.3 `UniversalMoE` (design only)
244
231
 
245
232
  Same block with the MLP swapped for router + `QuantizedSwitchLinear`
246
- (already exists and is serving 26B-A4B). Deltas to parameterize: top-k,
233
+ (already serving 26B-A4B and Qwen3-MoE). Deltas to parameterize: top-k,
247
234
  `norm_topk_probs`, routing score fn (softmax/sigmoid), routing scale,
248
235
  shared-expert branch (+ optional shared-expert gate — qwen2_moe),
249
236
  first-k-dense-replace (deepseek/glm4_moe layouts), grouped routing
250
237
  (deepseek_v3-style, defer). gpt_oss (attention sinks) and llama4 (chunked
251
- attention) are *not* claimed by the generic MoE — they graduate to
252
- one-offs if wanted.
253
-
254
- Memory reality check on the reference machines (24–32 GB): Mixtral-8x7B
255
- 4-bit ≈ 25 GB — no. OLMoE-1B-7B, Qwen3-30B-A3B (≈17 GB @4bit),
256
- GLM-4 lite variants, granitemoe small — yes. The generic MoE tier is
257
- worth building, but expectations belong in `mlx-bun models` output
258
- (weightsBytes vs RAM), not in marketing.
259
-
260
- ### 3.3 Dispatch changes (support.ts / factory.ts)
261
-
262
- Order matters — **generic never shadows a dedicated port**:
238
+ attention) are not claimed by the generic MoE. RAM honesty belongs in the
239
+ `ls`/fit output (weightsBytes vs RAM), not in marketing.
240
+
241
+ ### 4.4 Graduation to Tier-1
242
+
243
+ Criteria (all three): (a) L1 generic parity green and stable across real
244
+ use; (b) it is a daily driver / benchmark / product target; (c) a measured
245
+ perf or memory gap vs a dedicated path worth the maintenance (number in
246
+ docs/reference/benchmarks.md).
247
+
248
+ Process, in order, stop at any step: (1) L2 — optiq goldens
249
+ (`mixed-kv` pattern) if an optiq artifact/kv_config exists; (2) dedicated
250
+ or generated forward — extend `gen-model.ts` if gemma4-base-shaped,
251
+ otherwise a hand port (`qwen3_5.ts` pattern; hand ports are proven and
252
+ cheap); (3) perf levers behind their existing flags (compiled decode,
253
+ kv-quant, fused sdpa) — output-changing experiments are Lab items
254
+ (unified-engine-frontier-plan.md §6); (4) benchmark + docs entries, tier
255
+ label flips to `targeted`. Graduation never deletes the generic path — it
256
+ stays the permanent correctness fallback, as the monolith does for generated
257
+ gemma classes.
258
+
259
+ ### 4.5 Remaining phases
260
+
261
+ | Phase | Scope | State |
262
+ |---|---|---|
263
+ | 1 | UniversalDense + descriptor table + rope factory + bias + manifest harness | built |
264
+ | 1.5 | dense (bf16/fp16) checkpoints, no `.scales` | built (`modules.ts`) |
265
+ | 2 | UniversalMoE: mixtral, qwen2_moe, olmoe, glm4_moe, dots1, granitemoe, ernie4_5_moe, phimoe (qwen3_moe is already a dedicated port) | design |
266
+ | 3 | demand-driven one-offs (SSM/hybrid: lfm2, qwen3_next, mamba2, nemotron_h; MLA if a runnable target appears) — each a real port with its own goldens and cache types | design |
267
+ | 4 | `mlx-bun port <hf-repo>`: download smallest snapshot → descriptor coverage check (config keys + weight-audit dry run) → auto-regen goldens vs the oracle venv → run the gate → print verdict + manifest entry. Optionally generalize `gen-model.ts` to emit from UniversalDense | design (no CLI command exists) |
263
268
 
264
- ```
265
- createModel(weights, config):
266
- 1. dedicated classes (diffusion, minicpm5, qwen3_5, qwen3) — unchanged
267
- 2. gemma4*: GENERATED.get(fingerprint) ?? Gemma4Model — unchanged
268
- 3. ARCHS[remap(config.modelType)] → new UniversalDense/MoE(...) — NEW
269
- 4. throw "unsupported model_type X (nearest: …)" — unchanged shape
270
- ```
269
+ ---
271
270
 
272
- - `support.ts isSupportedModelRecord`: add `GENERIC_MODEL_TYPES` (the
273
- descriptor table's keys, post-remap). Keep the drafter exclusion.
274
- `mlx-bun models` labels the tier: `supported (targeted)` vs
275
- `supported (generic)` — sets perf expectations and doubles as the
276
- graduation worklist.
277
- - The current hard throw for non-MiniCPM5 `llama` configs is *replaced* by
278
- the generic path (that throw exists only because nothing generic existed).
279
- `isMiniCPM5Config`'s exact-shape predicate keeps MiniCPM5 on its
280
- dedicated class ahead of the generic.
281
-
282
- ### 3.4 Weight-name mapping + load audit
283
-
284
- Bucket A is already ~uniform in HF land
285
- (`model.layers.N.self_attn.{q,k,v,o}_proj`, `mlp.{gate,up,down}_proj`,
286
- `input_layernorm`, `post_attention_layernorm`, `model.norm`,
287
- `model.embed_tokens`, optional `lm_head`). The descriptor handles the
288
- exceptions: rename maps (starcoder2 `c_fc/c_proj`), fused-proj split rules
289
- (phi3 `qkv_proj`, `gate_up_proj` — split at load into views/copies),
290
- prefix strips (vision wrappers `language_model.model.*` — gemma4 already
291
- does this via `prefixBase`), and drop rules (`rotary_emb.inv_freq`,
292
- mlx-lm `sanitize`).
293
-
294
- **Every generic load runs a weight audit** (grow `scripts/inspect-model.ts`
295
- into `src/model/universal/audit.ts`): after module construction, diff
296
- {tensors in shard index} vs {tensors consumed}. Unconsumed or missing
297
- tensors ⇒ load error naming them, not a silent wrong-answer model. This is
298
- the cheap tripwire that catches descriptor mistakes before parity does
299
- (the "verify the foundation" rule, mechanized).
300
-
301
- ### 3.5 The parity gate for a NEW arch (cost: ~2–4 h/arch, mostly waiting)
302
-
303
- Pattern already proven three times (gemma/minicpm5/qwen). Parameterize it
304
- once:
305
-
306
- 1. `scripts/regen-generic-goldens.ts <snapshot> <prefix>` — oracle venv
307
- (`/Users/joshrossi/Code/mlx-lm/.venv/bin/python`, mlx-lm `load()` +
308
- `make_prompt_cache`) emits `<prefix>-parity.json` (explicit prompt ids,
309
- greedy ids) + 12 step-logit `.bin`s. Same-machine rule applies (logit
310
- goldens are GPU-specific — label goldens with host).
311
- 2. `tests/generic-parity.test.ts` — iterates a manifest
312
- (`tests/generic-manifest.ts`: prefix → snapshot path → model_type),
313
- skipIf-gated on snapshot presence like every parity test. Asserts:
314
- fingerprint-free construction, weight audit clean, greedy trajectory
315
- match, per-step logits bit-exact.
316
- 3. Checkpoint choice: **smallest mlx-community 4-bit of the arch**
317
- (0.5B–3B exists for nearly all of bucket A) — keeps the gate runnable
318
- and the download small. Downloads stay a user action (ground rules).
319
-
320
- Definition of supported-generic = manifest entry green on the current
321
- machine. No entry, no support claim.
322
-
323
- ### 3.6 Graduation to Tier-1 (targeted)
324
-
325
- **Criteria** (all three): (a) L1 generic parity green and stable across a
326
- few sessions of real use; (b) it's a daily driver / benchmark / product
327
- target (e.g. the Lucien pipeline models); (c) measured perf or memory gap
328
- vs a dedicated path that's worth the maintenance (number in
329
- `benchmarks/RESULTS.md`, per the every-perf-claim-gets-a-number rule).
330
-
331
- **Process** (the gemma methodology, in order — stop at any step):
332
- 1. **L2**: optiq-quant goldens (`regen-*-kv-goldens` pattern, mixed-KV vs
333
- the optiq oracle) if an optiq checkpoint/kv_config exists for it.
334
- 2. **Dedicated or generated forward**: if the arch is gemma4-base-shaped,
335
- extend `gen-model.ts`; otherwise hand-port a dedicated module
336
- (`qwen3_5.ts` pattern). Note: today's `gen-model.ts` subclasses
337
- `Gemma4Model` specifically — generalizing it to emit from
338
- `UniversalDense` is Phase 4 work, and *optional*: hand ports are proven
339
- and cheap ("faithful port took ~1 hr, not the huge effort claimed").
340
- 3. **Perf levers**: compiled decode / kv-quant / fused-sdpa, each behind its
341
- existing flag. (The former "L3 kernels" step — fused decode / flash paths
342
- with frozen-oracle gates — was deleted 2026-07-05; output-changing
343
- experiments are now Lab items, see
344
- [unified-engine-frontier-plan.md §6](unified-engine-frontier-plan.md).)
345
- 4. RESULTS.md + docs entries; `mlx-bun models` label flips to `targeted`.
346
-
347
- Nothing about graduation removes the generic path — it stays as the
348
- always-correct fallback, exactly like the monolith does for generated
349
- gemma classes today.
271
+ ## 5. Multimodal seams shared by the ports
272
+
273
+ Every tower (vision or audio) returns language-space soft tokens
274
+ `[1, soft, textHidden]` pre-divided by `embed_scale` (the language model
275
+ re-multiplies), splices into the prompt through
276
+ `src/vision/prompt.ts buildMultimodalPrompt` (images + audio in document
277
+ order; `buildVisionPrompt` is a byte-identical wrapper), and enters the model
278
+ through `forwardEmbeddings` (merged embeddings; per-layer-input models take
279
+ a `multimodal` zeroing mask decoupled from the `bidir` attention overlay).
280
+ Media requests route to the **serial lane**, skip the prompt cache and spec
281
+ decode, and capability flags (`visionCapable`, `audioCapable` in
282
+ `src/registry.ts`) check TENSORS, not just config. Non-WAV audio transcodes
283
+ via macOS `afconvert`; video decodes via the AVFoundation sidecar
284
+ `mlx-bun-frame-extract` — zero vendored codecs.
350
285
 
351
286
  ---
352
287
 
353
- ## 4. Phased rollout
288
+ ## 6. Ports
289
+
290
+ One subsection per family. Each states the graph, its oracle, and the
291
+ design-relevant facts; phase logs live in PLAN.md at the named anchor.
292
+
293
+ ### 6.1 Gemma-4 (e4b / 12B / 26B-A4B) — `src/model/gemma4.ts`, `gemma4-base.ts`, `generated/`
294
+
295
+ - **Graph**: line-for-line port of mlx-lm `gemma4_text.py` covering 12B
296
+ (dense), e4b (per-layer-input embeddings + KV-shared layers), 26B-A4B
297
+ (MoE: router + gather_qmm experts). SDPA scale 1.0 (q/k normalized);
298
+ full-attention layers use global_head_dim 512, one global KV head,
299
+ `attention_k_eq_v`; ProportionalRoPE rotates only
300
+ `partial_rotary_factor` dims; python-float scalars promote weakly; mlx
301
+ helper implementations replicated exactly (`x**3` is `mx.power`).
302
+ Sliding layers use a plain cache + window masks (numerically identical to
303
+ mlx-lm's RotatingKVCache).
304
+ - **Specialization**: `scripts/gen-model.ts` → `generated/gemma4-{e4b,12b,26b}.ts`,
305
+ fingerprint-dispatched, bit-exact vs the monolith
306
+ (`tests/generated-parity.test.ts`).
307
+ - **Oracle**: L1 mlx-lm (`goldens/parity.json` on the 12B snapshot,
308
+ `tests/parity.test.ts`; 26B `tests/parity-26b.test.ts`); L2 mlx-optiq for
309
+ the mixed-KV composition (26B `logits-26b-kvmix.bin`, `mixed-kv` job).
310
+ Profile: `gemma4-generated` / `gemma4-dedicated`, L1.
311
+ - **Vision**: two towers behind one merge contract — `src/vision/siglip.ts`
312
+ (full SigLIP encoder shipped by e2b/e4b/26B/31B; port of optiq's vendored
313
+ mlx-vlm gemma4 encoder from the bf16 `optiq_vision.safetensors` sidecar)
314
+ and `src/vision/embedder.ts` (12B `gemma4_unified` encoder-free patch
315
+ embedder). Oracle = optiq internals (`goldens/e4b-vision.json`,
316
+ `tests/e4b-vision.test.ts`, `tests/vision.test.ts`): spliced ids and
317
+ soft-token count EXACT, greedy PREFIX match; full bit-exact greedy is not
318
+ asserted because the 16-layer bf16 encoder composition drifts sub-bf16 and
319
+ the scale-1.0 softmax amplifies it (siglip.ts header).
320
+ - **Audio**: §6.6.
321
+ - PLAN anchors: Phase 12 (SigLIP), Phase 2 findings (parity notes).
322
+
323
+ ### 6.2 MiniCPM5-1B — `src/model/minicpm5.ts`
324
+
325
+ - **Graph**: `model_type: llama` (plain Llama block — no MiniCPM residual
326
+ scaling), 24 layers, hidden 1536, 16/2 heads @128, vocab 130560, untied,
327
+ `rope_theta` from `ropeParameters.full_attention`. Port target mlx-lm
328
+ `models/llama.py`; the expert swiglu is mx.compile-compiled like the
329
+ oracle's `activations.py` (`compiledSwiglu`, kill-switch
330
+ `MLX_BUN_COMPILED_SWIGLU=0`) — the one fusion that matched the oracle's
331
+ kernel set and brought CPM5 decode to parity with mlx-lm
332
+ (decode-speed-program.md).
333
+ - **Dispatch**: the exact-shape `isMiniCPM5Config` predicate keeps it on
334
+ the dedicated class ahead of the generic `llama` descriptor.
335
+ - **Oracle**: L1 mlx-lm (`goldens/minicpm5-parity.json`,
336
+ `tests/minicpm5-parity.test.ts`); L2 mlx-optiq for per-layer quantized KV
337
+ (`goldens/minicpm5-kv-parity.json`, `tests/minicpm5-kv-parity.test.ts`,
338
+ bit-exact via `QuantizedKVCache` + `quantizedSdpaUnfused`). Also the
339
+ TurboQuant KV testbed (`TurboQuantKVCache`). Profile
340
+ `minicpm5-dedicated`, L1 (the L2 composition is a request-level KV scheme,
341
+ not a profile property).
342
+ - Training reference model for segmented backward and ORPO
343
+ (docs/design/orpo-training.md, orpo-training.md).
344
+
345
+ #### 6.2.1 MiniCPM5-2B investigation
346
+
347
+ Metadata and template inspection completed 2026-09-10. No weights were
348
+ downloaded and no GPU inference was run. This checkpoint is a candidate,
349
+ not an artifact with established parity or local performance results.
350
+
351
+ Start with the official [OpenBMB MLX artifact](https://huggingface.co/openbmb/MiniCPM5-2B-MLX),
352
+ revision `3d00c3da500debfe345e60e25a87ed2669f5b1ee`. Its config uses standard
353
+ Llama blocks, 42 layers, hidden size 2048, intermediate size 6144, 16 query
354
+ and 2 KV heads of dimension 128, untied embeddings, vocab 130560 and
355
+ RoPE theta 5000000. Quantization is affine 4-bit with group size 64.
356
+ Preserve both EOS IDs, `1` and `130073`, and the separate
357
+ `chat_template.jinja`. The release is text-only and Apache-2.0.
358
+
359
+ Current integration findings:
360
+
361
+ - `isMiniCPM5Config` in `src/model/support.ts` matches the older 24-layer,
362
+ hidden-1536 artifact. The 2B config fails that predicate and qualifies for
363
+ generic Llama through `genericArgsFor`; `familyProfile` therefore selects
364
+ the universal graph. Do not widen the predicate before auditing dedicated
365
+ execution, training and cache assumptions against this shape.
366
+ - A CPU-only smoke using the pinned config and template passed
367
+ `loadModelConfig`, `genericArgsFor`, `ChatTemplate.load` and rendering a
368
+ user → assistant tool call → tool result → user conversation. Explicit
369
+ thinking true/false both render correctly; the XML function call survives.
370
+ This checks rendering, not generated tool-call parsing or tokenizer parity.
371
+ - `resolveEnableThinking` applies the MiniCPM no-thinking default through
372
+ the same exact-shape predicate. It does not apply to 2B. With no explicit
373
+ option, this artifact's prompt ends at the assistant header; true appends
374
+ an open think tag, false appends a closed empty think block. Set this
375
+ explicitly in comparisons. Template support for disabling thinking does
376
+ not establish no-thinking quality.
377
+
378
+ Evaluation sequence:
379
+
380
+ 1. Pin an 8-bit or BF16 control alongside the official 4-bit candidate.
381
+ Establish tokenizer/prompt identity and same-machine logits against the
382
+ pinned mlx-lm oracle, then test multi-turn tool calls, reasoning splits,
383
+ EOS, cache reuse and batched continuation. Keep quantization quality
384
+ comparisons separate from same-artifact runtime parity.
385
+ 2. Compare with MiniCPM5-1B and Gemma e4b on held-out Dreaming segmentation,
386
+ extraction and source-grounded synthesis, plus bounded repository/tool
387
+ tasks. Score boundary/label accuracy and completed tasks, not just valid
388
+ JSON or XML. Use explicit thinking modes and equal token/time budgets.
389
+ 3. Record first-answer latency, complete task time, output/reasoning tokens,
390
+ repetition and truncation rates, memory and context scaling. Local
391
+ measurements belong only in `docs/reference/benchmarks.md`, with a named
392
+ quiet machine and the required serving benchmark procedure.
393
+ 4. Investigate the [released DSpark draft](https://huggingface.co/openbmb/MiniCPM5-2B-DSpark)
394
+ after ordinary inference passes. Its config declares `Qwen3DSparkModel`,
395
+ five draft layers, block size seven, and target taps `[1,10,20,30,39]`.
396
+ Existing Gemma DSpark support does not establish compatibility. Audit
397
+ the draft's architecture, target taps, weights and verifier before a
398
+ paired task-time comparison.
399
+
400
+ Evidence to use when designing the quality checks:
401
+ [OpenBMB's model card](https://huggingface.co/openbmb/MiniCPM5-2B) distinguishes
402
+ internally reproduced scores from Artificial Analysis results. The
403
+ [independent September 7 evaluation](https://artificialanalysis.ai/articles/openbmb-releases-minicpm5-2b)
404
+ supports strong capability for its size but reports substantial reasoning
405
+ token use and weak absolute terminal-task success. These evaluations do not
406
+ validate MLX 4-bit quality. [Upstream issue 374](https://github.com/OpenBMB/MiniCPM/issues/374)
407
+ reports repetition sensitivity in GGUF coding runs. That is an unreproduced
408
+ cross-runtime hypothesis for our sweep, not evidence of the same MLX failure
409
+ or a reason to change repetition defaults.
410
+
411
+ ### 6.3 Qwen3 / Qwen3-MoE / Qwen3.5-family (3.6, 3.8) — `qwen3.ts`, `qwen3-moe.ts`, `qwen3_5.ts`
412
+
413
+ - **Qwen3** (`model_type: qwen3`): dense GQA with per-head q/k RMSNorm
414
+ before RoPE, theta 1e6, tied embeddings. Primary use is the
415
+ text-embedding backbone (`embedPooled`: last-token hidden, L2-normalized).
416
+ Oracle L1 mlx-lm (`tests/qwen3-embed-parity.test.ts`). Shadows the
417
+ generic `qwen3` descriptor.
418
+ - **Qwen3-MoE** (`qwen3_moe`): straight op-for-op transcription of
419
+ mlx-lm `qwen3_moe.py` + `switch_layers.py` — gate Linear → precise
420
+ softmax over all experts → argpartition top-k → renormalize → SwitchGLU
421
+ with compiled swiglu; `decoder_sparse_step` / `mlp_only_layers` dense
422
+ layers handled. Oracle L1 mlx-lm on the 30B-A3B
423
+ (`tests/qwen3-moe-parity.test.ts`; the cached checkpoint has no
424
+ kv_config, so no L2 bar).
425
+ - **Qwen3.5 hybrid** (`qwen3_5` / `qwen3_5_text`; the `qwen3_5_moe` variant
426
+ is excluded by `isQwen35Config`): 64 layers, every
427
+ `full_attention_interval`-th (4) a gated softmax-attention layer (q-gate
428
+ split, per-head q/k norm, partial RoPE 0.25 @ base 1e7, GQA 24/4 @256,
429
+ `o_proj(out·σ(gate))`), the rest **gated DeltaNet** linear attention
430
+ (`in_proj_qkv/z/b/a`, depthwise causal conv1d k=4, `A_log`/`dt_bias`
431
+ float, `RMSNormGated`). The recurrence is the reference's custom Metal
432
+ kernel `gated_delta_step` ported VERBATIM (`src/model/qwen3-delta.ts`) —
433
+ bit-exact parity requires it; the ops fallback reduces in a different
434
+ order. `SSMCache` (conv + recurrent state) implements `Cache` and the
435
+ spec-round contract (`specRoundBegin/Commit/Rollback`: free snapshot,
436
+ replay of the kept window on partial reject — bit-exact by construction
437
+ because the kernel's per-thread loop is serial). Weights under
438
+ `language_model.`; `output_gate_type` other than `"swish"`/absent throws.
439
+ **Qwen3.8-27B is byte-for-byte the 3.6-27B text geometry** — zero new
440
+ graph work; the exact profile `qwen3.8-27b-optiq-4bit` pins the validated
441
+ revision.
442
+ - **Oracles**: L1 mlx-lm `qwen3_5.py` with bf16 KV
443
+ (`goldens/qwen38-parity.json`, `tests/qwen-parity.test.ts`; earlier 4B/3.6
444
+ goldens via `regen.ts qwen-parity`); L2 mlx-optiq mixed-KV on the 3.5/3.6
445
+ OptiQ artifacts (`install_mixed_kv` per-layer bits keyed by cache index ≡
446
+ our `maybeQuantizeKv`). Qwen3.8's OptiQ repo ships no mixed-KV config →
447
+ no L2 bar; mixed-KV serving there is Lab-tier.
448
+ - **Vision + video** (`src/vision/qwen3vl-{preprocess,tower,prompt}.ts`,
449
+ `video-frames.ts`, `src/model/qwen3-mrope.ts`): mlx-vlm `qwen3_vl`
450
+ vision tower at the qwen3_5 configuration (depth 27, hidden 1152, heads
451
+ 16 @72, patch 16, temporal 2, merge 2, deepstack empty) from the bf16
452
+ sidecar `optiq/optiq_vision.safetensors`; PIL-exact fixed-point bicubic
453
+ smart_resize; conv3d patch embed (new `mlx_conv3d` binding);
454
+ `ensure_fused_sdpa`'s 72→80 head-dim pad replicated; **interleaved
455
+ mRoPE** via the reference's verbatim Metal apply kernel with
456
+ `get_rope_index` positions + delta exact, installed per request on the
457
+ serial lane (text-only keeps the untouched fast-rope path — equal
458
+ position streams degenerate mRoPE to plain RoPE). Video: AVFoundation
459
+ sidecar samples at 2 fps (max 768 frames), temporal-pair patchify, gridT>1
460
+ tower, transformers' `<t seconds>` per-frame-group prompt format with a
461
+ python-`%.1f` port. Oracle = **mlx-vlm 0.6.14 pinned to mlx 0.31.2**
462
+ (independent of mlx-lm, so no composite bit-match target exists): tower
463
+ bit-exact at small grids, calibrated envelope at 2304 patches; e2e greedy
464
+ token-exact on 2/3 image fixtures, step-0 argmax exact on all
465
+ (`tests/qwen38-vision*.test.ts`).
466
+ - **Native MTP** (`src/spec/qwen-mtp-source.ts`, `--draft-kind mtp`): the
467
+ separately published `Qwen3.8-27B-MTP-*` head (`fc` over
468
+ concat(rms(embed(next)), rms(target_hidden)) → one full-attention layer
469
+ with its own KVCache → target lm_head, block_size 3, DeepSeek-V3 shape)
470
+ reads the target's PRE-final-norm hidden via `captureLayer`. Gate:
471
+ greedy speculation token-identical to non-spec greedy
472
+ (`tests/qwen38-mtp.test.ts`). Durable negative perf verdict on the quiet
473
+ M1 Max (MTP-on slower than off at γ=2 despite 61% acceptance) — stays
474
+ opt-in. Drafter logits verified against the mlx-vlm reference fed the
475
+ oracle's captured hidden grid.
476
+ - Training: `loraTargets()` wired; the DeltaNet kernel is inference-only —
477
+ training needs mlx-lm's pure-mlx `gated_delta_ops` scan under training
478
+ (open).
479
+ - PLAN anchors: Phase 14 (bring-up, 14g MTP, 14v vision, 14w video, 14y
480
+ YaRN open, 14z TurboQuant weights).
481
+
482
+ ### 6.4 GLM-5.2 (`glm_moe_dsa`) — the Colibri hierarchy, `src/model/glm52*.ts`
483
+
484
+ Summary of docs/archive/investigations/colibri-glm52-port.md (frozen);
485
+ full phase record G0–G8 in git (`git show 3199c75:PLAN-archive.md`,
486
+ Phase 21, closed 2026-08-17). GLM-5.3+ would extend THIS section.
487
+
488
+ - **Decision**: a native `Glm52Model` over the PUBLIC Colibri container in
489
+ place (no second copy, no Colibri child process, no `--backend`); the
490
+ pinned Colibri build (`JustVugg/colibri` @ `44e489b`) is an external
491
+ executable oracle for formats, logits/tokens, routing traces, memory and
492
+ speed. Its policy code is studied and reproduced, not shipped.
493
+ - **Model**: 78 main layers (3 dense FFN + 75 sparse MoE, 256 routed
494
+ experts, top-8) + an MTP row with its own 256 experts (19,456 expert
495
+ instances). The dense spine (embeddings, lm-head, attention, norms, first
496
+ dense FFNs, routers, shared experts) stays resident at int4 (~9.9 GB); the
497
+ ~370 GB routed-expert pool stays on disk.
498
+ - **Graph** (`glm52.ts`, `glm52-mla.ts`, `glm52-dsa.ts`, `glm52-moe.ts`):
499
+ MLA — q-a → norm → q-b; kv-a → latent norm; **compressed cache** of the
500
+ 512-wide latent + 64 RoPE values per token (`MLACache`, ~57× smaller than
501
+ reconstructed K/V at this geometry), weight-absorption decode,
502
+ reconstructed-prefill fallback, partial interleaved RoPE. **DSA indexer**
503
+ — q/k/projection/norm, per-layer full/shared schedule, exact dense
504
+ fallback when the selected set covers the prefix (`DSAIndexCache` only on
505
+ layers that own it). MoE — sigmoid scores + correction bias for
506
+ selection, un-biased gate weights, true top-8, routed scale, shared expert
507
+ in parallel. Colibri arithmetic (offset-binary int4, per-row int8 scale
508
+ applied once, RMSNorm with multiplicative weight and double-accumulated
509
+ reduction) is mirrored in `glm52-reference.ts`. G2 favors an auditable
510
+ dequantize→f32 path; the Metal streamed kernel (`glm52-streamed-metal.ts`)
511
+ replaces the expert resolver without changing the graph.
512
+ - **Expert residency / streaming** (`glm52-residency.ts`,
513
+ `glm52-streamed-experts.ts`, `glm52-expert-layout.ts`, `glm52-pilot.ts`,
514
+ `glm52-coupling.ts`, `glm52-atlas.ts`): per-layer bounded LRU slots
515
+ derived from the whole-process memory equation, pinned hot-store seeded
516
+ from persistent usage, LFRU repinning with hysteresis, batch-union of
517
+ unique (layer, expert) across rows so each expert is read once per
518
+ layer/step, `pread` worker pool with slot generations and completion
519
+ fences (no reuse while a lazy MLX command can retain the buffer), PILOT
520
+ (next-layer router on the current state) and COUPLE (cross-layer route
521
+ pairs) prefetch, RSS feedback shrinking only the evictable tier. Unified
522
+ memory removes a copy, not the 370 GB: the meaningful states are disk /
523
+ resident / pinned / loading / in-flight / evictable.
524
+ - **Fixed-context admission** (`glm52-memory.ts`, `factory.ts
525
+ openGlm52RuntimeModel`): a header-only resource plan runs BEFORE any
526
+ resident tensor or expert slab is opened — process limit (default 25 GiB
527
+ preset or physical RAM, whichever is smaller), fixed context
528
+ (default 4096 tokens, 128 generation), allocator/Bun/safety reserves — and
529
+ refuses an impossible placement; the opened runtime's planned bytes must
530
+ equal the preflight equation or load fails. Serving clamps `max_tokens`
531
+ to the room under the fixed context (STATUS: "GLM fixed-context admission
532
+ correction", generalized to every model in v0.2.0).
533
+ - **Native MTP** (`src/spec/glm52-mtp-source.ts`): the checkpoint's int8 MTP
534
+ row as an in-process draft source sharing the target; serial only —
535
+ batched rows decode single tokens (Colibri keeps MTP out of its mux path
536
+ too). Batched caches land via `makeEmptyBatch/mergeRows/extractRow/
537
+ filterRows/projectedBytes` on right-justified latent/RoPE/DSA tensors —
538
+ no full K/V at merge, admission, extraction or cancellation.
539
+ - **Oracle / fidelity**: profile `glm5.2-colibri` / exact
540
+ `glm5.2-colibri-int4-int8-mtp`, **L3 (measured)** — Colibri is neither
541
+ mlx-lm nor mlx-optiq, so the tier system cannot call it bit-exact even
542
+ though the G2 gate is a teacher-forced trajectory from the pinned engine
543
+ on a tiny converted artifact (`tests/glm52-teacher-forcing.test.ts`,
544
+ `fixtures/colibri-glm52/`). Curated numbers live in code as operator
545
+ guidance (`GLM52_G5_MEASURED_WARM_DECODE_TPS`,
546
+ `GLM52_G5_DIRECT_ORACLE_WARM_DECODE_TPS`, M1 Max 32 GB, MTP on) and in
547
+ docs/reference/models.md "GLM-5.2 on a 32 GB Mac". The 24 GB M4 Pro is
548
+ below the one-slot-per-layer floor and out of scope.
549
+ - **Not claimed**: embeddings, image/audio input, LoRA, training, adapters
550
+ — advertised false, never faked (archive N8).
551
+ - PLAN anchor: Phase 21 (closed 2026-08-17); probes, gate tests, and
552
+ lab spikes for the port surface retired afterwards (commit fbafe44).
553
+
554
+ ### 6.5 DiffusionGemma-26B-A4B — `src/model/diffusion-gemma.ts`, `src/diffusion/`, `src/vision/diffusion-vision.ts`
555
+
556
+ Summary of docs/design/generic-model-support.md (the D0 reference dossier
557
+ there stays the porting contract; do not extend it).
558
+
559
+ - **What it is**: the first non-autoregressive model — an encoder prefill
560
+ over the prompt builds a KV cache, then a decoder pass over a fixed
561
+ 256-token canvas (initialized to uniform-random ids, NOT a mask token) is
562
+ denoised over up to 48 steps. 30 layers, hidden 2816, 16 heads; each
563
+ layer runs a parallel dense MLP + 128-expert top-8 MoE summed through 7
564
+ RMSNorms and a `layer_scalar`; attention scale 1.0, no attention softcap
565
+ (final-logit softcap 30 in fp32), QK/V-norm post-proj/pre-RoPE, full
566
+ layers (5,11,17,23,29) reuse k as v at hd 512 / kv 2 with partial rotary
567
+ 0.25; tied 4-bit head via `QuantizedEmbedding.asLinear`; a
568
+ `SelfConditioning` MLP feeds soft embeddings from the previous step.
569
+ Bidirectional decoder masks (`_make_decoder_masks`) are the crux.
570
+ - **Engine** (`diffusion-generate.ts`): linear temperature schedule
571
+ (`t_min 0.4 → t_max 0.8`, DIVIDES logits), both samplers
572
+ (confidence-threshold = optiq public default, entropy-bound = engine
573
+ default), self-conditioning feedback, stability/EOS, block loop. RNG
574
+ parity via bound `mlx_random_randint`/`mlx_random_seed` threading the
575
+ global key in the reference's draw order. Parity traps recorded in the
576
+ source doc: division not reciprocal-multiply; independent history copies;
577
+ the as-loaded oracle has `generation_config = None` (stable-stop OFF,
578
+ eos {1, 106}).
579
+ - **Vision**: a DEDICATED tower (`diffusion-vision.ts`), not the e4b SigLIP
580
+ — inline-quantized `input_proj` truncates `2*(x-0.5)` patches to integers
581
+ (a trained-in quirk), head_dim 72 padded to 80 like the reference, plain
582
+ bf16 `down_proj`.
583
+ - **Oracle**: **mlx-optiq IS the oracle** (stock mlx-lm cannot load it);
584
+ the mixed-precision quant is the native weight format, so matching optiq
585
+ = L2 = the floor. Profile `diffusion-gemma-dedicated`, L2. Gates:
586
+ single forward bit-exact (`tests/diffusion-parity.test.ts`), generation
587
+ token-for-token for both samplers (`diffusion-gen-parity`), image
588
+ token-for-token (`diffusion-vision`), serving (`diffusion-serving`), LoRA
589
+ with the denoising objective (`diffusion-lora`,
590
+ `src/train/diffusion-lora.ts`; MoE backward by stop-gradient on router
591
+ indices). All `MLX_BUN_TEST_DIFFUSION=1`.
592
+ - **Entry points — honest state**: `src/generate.ts` routes by
593
+ `instanceof DiffusionGemmaModel` to `generateDiffusionInner`, and
594
+ `src/server.ts` has a diffusion vision lane; **`src/cli.ts` contains no
595
+ diffusion reference** (`grep -c diffusion src/cli.ts` = 0). There is no
596
+ diffusion-specific CLI surface; the model is reachable only through the
597
+ generic `serve` / `generate` path by profile + instanceof dispatch, and
598
+ streaming yields tokens after the engine completes. D4 (performance,
599
+ measured) is open.
600
+
601
+ ### 6.6 Audio input (gemma-4 audio tower) — `src/audio/`
602
+
603
+ Summary of docs/design/generic-model-support.md. Scope: audio-in, text-out
604
+ through the chat API; TTS/STT endpoints, streaming audio, >30 s, batched
605
+ audio prefill, and 26B-A4B/DiffusionGemma audio (no `audio_config`) are
606
+ non-goals.
607
+
608
+ - **Oracle**: mlx-lm strips `audio_tower`/`embed_audio` at load and rejects
609
+ non-text content; optiq's internal gemma4 machinery is complete but its
610
+ serve frontend never exposes audio → the oracle is the optiq internal
611
+ model driven directly (`scripts/oracle/gen-e4b-audio-golden.py`,
612
+ `goldens/e4b-audio.json`). The e4b OptiQ-4bit sidecar already holds all
613
+ 752 audio tensors (bf16, incl. clipped-linear min/max stats) plus
614
+ `audio_config` and token ids (`boa 256000`, `audio 258881`,
615
+ `eoa 258883`) — no download.
616
+ - **Pipeline**: `decode.ts` (RIFF/WAVE PCM16/24/32/f32, mean mixdown, linear
617
+ resample to 16 kHz, PCM16/32768 like the oracle; >30 s truncates at
618
+ 480 000 samples BEFORE features, the oracle extractor's default) →
619
+ `transcode.ts` (`afconvert` for non-WAV, content-sniffed) →
620
+ `features.ts` (USM log-mel, frame 320 / hop 160 / rfft 512 in f64, 128 HTK
621
+ bins, `log(x+1e-3)`, the oracle's exact f32 Hann values baked in because
622
+ numpy's vectorized f32 cos differs by 1 ulp and log-amplifies) →
623
+ `conformer.ts` (SSCP two Conv2d stride-2 stages (128, 32) → Linear 1024 →
624
+ 12 Conformer blocks with chunked local attention (chunk 12, left 13,
625
+ softcap 50), depthwise Conv1d k=5, clipped linears → output_proj 1536 →
626
+ `embed_audio` RMSNormNoScale → Linear → /embed_scale). **Dtype contract
627
+ differs from siglip**: the oracle feeds f32 mel into bf16 weights and mlx
628
+ promotes, so activations stay f32 end-to-end — do not cast to weight
629
+ dtype. Clipped-linear stats are load-bearing (off diverges 90%).
630
+ - **LM semantics (resolved against the oracle)**: audio tokens are strictly
631
+ CAUSAL; any audio in the prompt disables the vision bidir overlay
632
+ entirely; per-layer-input zeroing uses the union multimodal mask; USM
633
+ parameters are fixed constructor defaults (no per-bin normalization);
634
+ `<|audio|>` → `boa + audio×n + eoa` with `n = min(ceil(ms/40), 750)` is
635
+ splice-side. The merge divides by embed_scale AFTER the bf16 cast (weak
636
+ scalar) — `features(preDivide=false)` + astype + div mirrors it.
637
+ - **Serve**: OpenAI `input_audio` plus optiq `audio`/`audio_url` parts;
638
+ lazy `getAudioTower` from the same sidecar, zero new flags; a request
639
+ with audio on a towerless model is an explicit 400; Anthropic
640
+ `/v1/messages` rejects audio blocks with a pointer to the OpenAI
641
+ endpoint; `audio` capability flag on `/v1/models`, `/library`, and the pi
642
+ `ready` frame (requires `audio_config` AND tower tensors — the 12B stub
643
+ sidecar reads false).
644
+ - **Gates**: T0 mel model-free (`tests/audio-features.test.ts`, 1e-5),
645
+ T1 tower rel-RMSE (`e4b-audio-tower`, bit-exact result), T2 e2e greedy +
646
+ decoded text EXACT for both fixtures (`e4b-audio`), T3 HTTP
647
+ (`e4b-audio-serve`, `MLX_BUN_TEST_AUDIO_SERVE=1`).
648
+ - **Open (A5)**: bench cells (tower ms, TTFT delta, RSS delta) into
649
+ docs/reference/benchmarks.md; 12B audio cell needs a sidecar rebuild via
650
+ optiq `build_vision_sidecar` (local 12B sidecar holds 1 audio tensor);
651
+ features-matrix note audio×batching = serial.
652
+ - PLAN anchor: "Phase: audio input — gemma-4 audio tower, e4b first".
354
653
 
355
- | Phase | Scope | Unlocks | Effort | Key risks |
356
- |---|---|---|---|---|
357
- | **1** | `UniversalDense` + descriptor table + rope factory (llama3/yarn/longrope) + bias term + goldens harness. Launch archs: **llama (⇒ Llama 3.x + Mistral + Ministral), qwen2, qwen3(fold-in), gemma, gemma2, smollm3, olmo2, olmo3, phi3, glm4, granite, starcoder2** | ~20 files at launch; the rest of bucket A (~36 total) as S-sized descriptor+golden follow-ons; F-wrappers for covered bases | **L** (module M, rope M, harness S, 12×goldens S-each) | rope variants (llama3/yarn/longrope math), gemma2 softcap manual-attn path, phi3 fused-proj split, BOS/tokenizer conventions per family (the double-BOS class of bug), qwen2 qkv bias |
358
- | **1.5** | `DenseLinear` (bf16/fp16 checkpoints, no `.scales`) | fp16-only small models; removes the "MLX-quantized only" constraint | **S–M** | dtype/cast points vs mlx-lm (bf16 matmul accumulation — see e4b length-sensitivity memory) |
359
- | **2** | `UniversalMoE` (router + SwitchGLU + shared experts + first-k-dense) : **mixtral, qwen2_moe, qwen3_moe, olmoe, glm4_moe, dots1, granitemoe, ernie4_5_moe, phimoe** | ~12–15 of bucket B (gpt_oss/llama4 excluded) | **M** (SwitchGLU exists; routing variants are config) | routing-score parity (softmax vs sigmoid + norm_topk), RAM honesty on 24 GB |
360
- | **3** | Demand-driven one-offs, qwen3_5 pattern: SSM/hybrid (**lfm2, qwen3_next, mamba2, nemotron_h**…), MLA module if a runnable target appears (**minicpm3**; deepseek-lineage mostly exceeds local RAM) | bucket C/D picks, ~1 model per effort unit | **M–L each** (cumulatively XL; never a blocker for A/B) | new cache types (conv/ssm state) touch the Cache interface + serving slots; each is a real port with its own goldens |
361
- | **4** | Tooling: **`mlx-bun port <hf-repo>`** — download smallest snapshot → descriptor coverage check (config keys + weight-audit dry run) → auto-regen goldens vs oracle venv → run parity gate → print verdict + manifest entry. Optionally: generalize `gen-model.ts` to emit from UniversalDense for graduation | turns "new arch" into a ~1-command, ~1-hour operation; makes the coverage claim self-verifying | **M** (scaffold) + **L** (generator generalization, optional) | oracle-venv coupling (mlx-lm version drift changes goldens — pin + record versions in parity.json, already the pattern) |
362
-
363
- Sequencing note: Phase 1's descriptor table should be *born* with only the
364
- 12 launch archs actually gated green — adding an arch without its manifest
365
- goldens is the one anti-pattern this design forbids.
654
+ ---
366
655
 
367
- ## 5. Top design decisions (summary)
656
+ ## 7. Top design decisions
368
657
 
369
658
  1. **Explicit descriptor table keyed by model_type (+ vendored
370
659
  MODEL_REMAPPING), not config sniffing** — support is a declared,
371
660
  testable surface; fingerprints remain a generated-dispatch guard only.
372
- 2. **One normalized config** — extend the existing `TextConfig` (it's
373
- already 70% there) with the bucket-A delta union; move per-arch quirks
374
- out of `loadModelConfig`'s if-chain into descriptor `configAliases`.
661
+ 2. **One profile per load, resolved before weights open** — exact artifact
662
+ > family > generic; mismatches refuse, never downgrade; profiles declare
663
+ construction only.
375
664
  3. **L1 bit-exact is the gate for generic too** — manifest-driven golden
376
- harness (explicit ids, raw per-step logits, same-GPU), one regen script
377
- + one test file for all generic archs.
378
- 4. **Weight audit at load** — unconsumed/missing tensors are a load error,
379
- never a silently-wrong model.
380
- 5. **Generic never shadows targeted; graduation never deletes generic** —
381
- the dispatch ladder is dedicated → generated → generic → reject, and the
382
- generic path is the permanent correctness fallback.
383
- 6. **Honest tiering in UX** — `mlx-bun models` shows `targeted` vs
384
- `generic` (and RAM fit), which doubles as the graduation worklist.
665
+ harness (explicit ids, raw per-step logits, same GPU).
666
+ 4. **Weight audit at load** — unconsumed/missing tensors are a load error.
667
+ 5. **Generic never shadows targeted; graduation never deletes generic.**
668
+ 6. **The oracle for any capability is whoever ships it** — mlx-lm (L1),
669
+ mlx-optiq (L2), mlx-vlm / optiq internals / Colibri where those are the
670
+ only implementations — and the profile's fidelity label says which.
671
+ 7. **Honest tiering in UX** — `mlx-bun ls`, hub REST, and discovery routes
672
+ show `targeted` vs `generic`; media capability flags check tensors.
673
+ 8. **New ports are sections of this doc**, with their durable phase record
674
+ in PLAN.md.
675
+
676
+ ## History
677
+
678
+ - 2026-06-24 — MiniCPM5 decode megakernel shelved (persistent single-dispatch
679
+ decode kernel, ~0.94× baseline at best; L2 ceiling 93/100 from quant
680
+ discontinuity amplifying 1-ULP GEMV drift). Premise removed by the
681
+ bandwidth-wall finding (decode-speed-program.md: the baseline decode path
682
+ sits at the memory-bandwidth wall; the real CPM5 waste was the unfused
683
+ swiglu, fixed by `compiledSwiglu`). Code shelved to scripts/experiments
684
+ 2026-07-01 and deleted with that directory 2026-08-23 (git history); no
685
+ megakernel code remains in `src/`. The doc
686
+ `docs/design/generic-model-support.md` is superseded by this line.
687
+ - 2026-06-24 — DiffusionGemma D0–D3 + D5 landed (bit-exact forward,
688
+ token-for-token generation, image, LoRA); D4 open.
689
+ - 2026-06-15 → 2026-08-18 — Qwen3.5-family: 3.6 text parity both bars;
690
+ 3.8 retarget (identical geometry), native MTP, vision, video landed.
691
+ - 2026-07-01 — Generic Phase 1 + 1.5 built (commit 9bd9f1b):
692
+ UniversalDense, 11 descriptors, rope factory, dense checkpoints, weight
693
+ audit, manifest harness.
694
+ - 2026-07-07 — Audio A0–A4 landed (e4b, oracle-exact); A5 open.
695
+ - 2026-08-17 — GLM-5.2 Colibri port closed (Phase 21); surface retired,
696
+ design archived.
697
+ - 2026-08-21 — Model profiles (`src/model/profile.ts`) introduced; exact
698
+ artifact declarations for Qwen3.8 OptiQ and GLM-5.2 Colibri.
699
+ - 2026-08-23 — This doc consolidated: audio-input-plan,
700
+ diffusion-gemma-port, minicpm5-decode-megakernel, and the Colibri archive
701
+ summarized here; ports become sections.
702
+
703
+
704
+ Non-Qwen grouped TurboQuant drafting, including assistant donor attention, uses
705
+ the shared cache interfaces. See [composition coverage](batching.md#turboquant-donor-attention-and-grouped-draft-composition).