@mlx-bun/inference 0.0.0-stage → 1.0.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 (467) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1475 -2
  3. package/THIRD_PARTY_NOTICES.md +3404 -0
  4. package/dist/native/libmlx_bun_ane.dylib +0 -0
  5. package/dist/native/libmlx_bun_expert_io.dylib +0 -0
  6. package/dist/native/mlx-bun-frame-extract +0 -0
  7. package/examples/fit-model.ts +25 -0
  8. package/examples/qwen3-forward.ts +42 -0
  9. package/examples/qwen3-generate.ts +28 -0
  10. package/examples/trellis-expand.ts +23 -0
  11. package/package.json +129 -4
  12. package/src/adapters/available.ts +110 -0
  13. package/src/adapters/index.ts +3 -0
  14. package/src/adapters/manager.ts +316 -0
  15. package/src/artifacts/auxiliary-files.ts +45 -0
  16. package/src/artifacts/config-dialects.ts +94 -0
  17. package/src/artifacts/config.ts +341 -0
  18. package/src/artifacts/draft-vocabulary.ts +30 -0
  19. package/src/artifacts/expert-offload-build.ts +75 -0
  20. package/src/artifacts/expert-offload.ts +89 -0
  21. package/src/artifacts/experts/index.ts +3 -0
  22. package/src/artifacts/experts/io.ts +386 -0
  23. package/src/artifacts/experts/residency.ts +1134 -0
  24. package/src/artifacts/experts/usage.ts +415 -0
  25. package/src/artifacts/fingerprint.ts +44 -0
  26. package/src/artifacts/glm52/container.ts +305 -0
  27. package/src/artifacts/glm52/expert-layout.ts +249 -0
  28. package/src/artifacts/glm52/index.ts +7 -0
  29. package/src/artifacts/glm52/kernel-layout.ts +124 -0
  30. package/src/artifacts/glm52/layout.ts +152 -0
  31. package/src/artifacts/glm52/memory.ts +500 -0
  32. package/src/artifacts/glm52/resident-weights.ts +135 -0
  33. package/src/artifacts/glm52/weights.ts +503 -0
  34. package/src/artifacts/glm52-config.ts +262 -0
  35. package/src/artifacts/identity.ts +94 -0
  36. package/src/artifacts/index.ts +15 -0
  37. package/src/artifacts/mmap.ts +90 -0
  38. package/src/artifacts/safetensors-writer.ts +249 -0
  39. package/src/artifacts/safetensors.ts +164 -0
  40. package/src/artifacts/turboquant-fold.ts +42 -0
  41. package/src/artifacts/weight-audit.ts +43 -0
  42. package/src/artifacts/weights.ts +255 -0
  43. package/src/contracts/index.ts +2 -0
  44. package/src/contracts/mlx/attention.ts +8 -0
  45. package/src/contracts/mlx/cache.ts +510 -0
  46. package/src/contracts/mlx/checkpoint.ts +10 -0
  47. package/src/contracts/mlx/draft-checkpoint.ts +14 -0
  48. package/src/contracts/mlx/draft-projection.ts +27 -0
  49. package/src/contracts/mlx/draft-target.ts +84 -0
  50. package/src/contracts/mlx/drafter.ts +176 -0
  51. package/src/contracts/mlx/forward-work.ts +23 -0
  52. package/src/contracts/mlx/glm52-weights.ts +25 -0
  53. package/src/contracts/mlx/graph.ts +309 -0
  54. package/src/contracts/mlx/head.ts +6 -0
  55. package/src/contracts/mlx/index.ts +15 -0
  56. package/src/contracts/mlx/kv-codec.ts +9 -0
  57. package/src/contracts/mlx/media.ts +113 -0
  58. package/src/contracts/mlx/positions.ts +16 -0
  59. package/src/contracts/mlx/row-table.ts +2 -0
  60. package/src/contracts/mlx/trainable.ts +103 -0
  61. package/src/contracts/mlx/whisper.ts +96 -0
  62. package/src/contracts/portable/composition.ts +106 -0
  63. package/src/contracts/portable/denoising.ts +17 -0
  64. package/src/contracts/portable/execution.ts +79 -0
  65. package/src/contracts/portable/generation.ts +103 -0
  66. package/src/contracts/portable/graph.ts +80 -0
  67. package/src/contracts/portable/index.ts +15 -0
  68. package/src/contracts/portable/memory-plan.ts +26 -0
  69. package/src/contracts/portable/object-cache.ts +8 -0
  70. package/src/contracts/portable/prefill.ts +63 -0
  71. package/src/contracts/portable/prefix-cache.ts +33 -0
  72. package/src/contracts/portable/prompt.ts +2 -0
  73. package/src/contracts/portable/resources.ts +25 -0
  74. package/src/contracts/portable/rollback.ts +7 -0
  75. package/src/contracts/portable/sampling.ts +44 -0
  76. package/src/contracts/portable/scheduling.ts +54 -0
  77. package/src/contracts/portable/token-delivery.ts +4 -0
  78. package/src/contracts/portable/tsconfig.json +14 -0
  79. package/src/embeddings/index.ts +1 -0
  80. package/src/embeddings/text.ts +85 -0
  81. package/src/execution/admission.ts +59 -0
  82. package/src/execution/batch-group.ts +1240 -0
  83. package/src/execution/batch-types.ts +225 -0
  84. package/src/execution/cancellation.ts +38 -0
  85. package/src/execution/continuation-request.ts +45 -0
  86. package/src/execution/continuation-types.ts +10 -0
  87. package/src/execution/coordinator.ts +70 -0
  88. package/src/execution/denoising-group.ts +180 -0
  89. package/src/execution/engine.ts +56 -0
  90. package/src/execution/fill-group.ts +505 -0
  91. package/src/execution/fit.ts +184 -0
  92. package/src/execution/gateway-binding.ts +178 -0
  93. package/src/execution/grammar-group.ts +224 -0
  94. package/src/execution/index.ts +18 -0
  95. package/src/execution/methods.ts +75 -0
  96. package/src/execution/mixed-iteration.ts +96 -0
  97. package/src/execution/plan.ts +65 -0
  98. package/src/execution/prefill-cohort.ts +100 -0
  99. package/src/execution/prefill-rows.ts +263 -0
  100. package/src/execution/request-policy.ts +19 -0
  101. package/src/execution/row-sampling.ts +49 -0
  102. package/src/execution/scheduler.ts +92 -0
  103. package/src/execution/session.ts +247 -0
  104. package/src/execution/speculative-group.ts +797 -0
  105. package/src/execution/tasks.ts +44 -0
  106. package/src/generation/autoregressive.ts +840 -0
  107. package/src/generation/bindings/autoregressive.ts +104 -0
  108. package/src/generation/bindings/denoising.ts +60 -0
  109. package/src/generation/bindings/prefill-policy.ts +36 -0
  110. package/src/generation/checkpoint-identity.ts +60 -0
  111. package/src/generation/denoising.ts +85 -0
  112. package/src/generation/diffusion.ts +583 -0
  113. package/src/generation/fill/echo-index.ts +188 -0
  114. package/src/generation/fill/index.ts +3 -0
  115. package/src/generation/fill/proposal.ts +69 -0
  116. package/src/generation/fill/schema-rows.ts +506 -0
  117. package/src/generation/fill/session.ts +464 -0
  118. package/src/generation/fill/tool-boundary.ts +103 -0
  119. package/src/generation/fill-append.ts +58 -0
  120. package/src/generation/generate.ts +44 -0
  121. package/src/generation/grammar-step.ts +39 -0
  122. package/src/generation/index.ts +14 -0
  123. package/src/generation/phase-dispatch.ts +115 -0
  124. package/src/generation/prefill.ts +33 -0
  125. package/src/generation/result.ts +49 -0
  126. package/src/generation/scopes.ts +157 -0
  127. package/src/generation/speculative/acceptance.ts +41 -0
  128. package/src/generation/speculative/adaptive-draft-gate.ts +166 -0
  129. package/src/generation/speculative/bindings/assistant-rows.ts +102 -0
  130. package/src/generation/speculative/bindings/autoregressive-rows.ts +124 -0
  131. package/src/generation/speculative/bindings/binding.ts +106 -0
  132. package/src/generation/speculative/bindings/deepspec-rows.ts +33 -0
  133. package/src/generation/speculative/bindings/draft-target.ts +10 -0
  134. package/src/generation/speculative/bindings/glm52-mtp-rows.ts +128 -0
  135. package/src/generation/speculative/bindings/projected-context-rows.ts +78 -0
  136. package/src/generation/speculative/bindings/projected-draft-rows.ts +95 -0
  137. package/src/generation/speculative/bindings/qwen-mtp-rows.ts +336 -0
  138. package/src/generation/speculative/bindings/two-model-rows.ts +63 -0
  139. package/src/generation/speculative/cache-identity.ts +16 -0
  140. package/src/generation/speculative/draft-kind.ts +149 -0
  141. package/src/generation/speculative/draft-policy.ts +41 -0
  142. package/src/generation/speculative/draft-registry.ts +118 -0
  143. package/src/generation/speculative/draft-vocab.ts +110 -0
  144. package/src/generation/speculative/index.ts +17 -0
  145. package/src/generation/speculative/output.ts +49 -0
  146. package/src/generation/speculative/round.ts +307 -0
  147. package/src/generation/speculative/source.ts +144 -0
  148. package/src/generation/speculative/sources/assistant-source.ts +64 -0
  149. package/src/generation/speculative/sources/deepspec-source.ts +70 -0
  150. package/src/generation/speculative/sources/dflash-source.ts +84 -0
  151. package/src/generation/speculative/sources/dflash2-source.ts +86 -0
  152. package/src/generation/speculative/sources/glm52-mtp-source.ts +66 -0
  153. package/src/generation/speculative/sources/ngram-source.ts +165 -0
  154. package/src/generation/speculative/sources/qwen-mtp-source.ts +154 -0
  155. package/src/generation/speculative/sources/two-model.ts +75 -0
  156. package/src/generation/types.ts +194 -0
  157. package/src/index.ts +20 -0
  158. package/src/input/audio/audiotoolbox.ts +112 -0
  159. package/src/input/audio/decode.ts +133 -0
  160. package/src/input/audio/features.ts +202 -0
  161. package/src/input/audio/index.ts +6 -0
  162. package/src/input/audio/transcode.ts +67 -0
  163. package/src/input/audio/whisper-mel.ts +185 -0
  164. package/src/input/audio/whisper-tokenizer.ts +238 -0
  165. package/src/input/chat-template.ts +389 -0
  166. package/src/input/index.ts +6 -0
  167. package/src/input/media-fetch.ts +439 -0
  168. package/src/input/packed-mixed.ts +43 -0
  169. package/src/input/special-tokens.ts +75 -0
  170. package/src/input/token-groups.ts +49 -0
  171. package/src/input/tokenizer.ts +336 -0
  172. package/src/input/tool-call.ts +689 -0
  173. package/src/input/vision/index.ts +3 -0
  174. package/src/input/vision/preprocess.ts +247 -0
  175. package/src/input/vision/prompt.ts +398 -0
  176. package/src/input/vision/qwen3vl-preprocess.ts +409 -0
  177. package/src/input/vision/qwen3vl-prompt.ts +237 -0
  178. package/src/input/vision/video-frames.ts +100 -0
  179. package/src/kernels/ane/fill.ts +101 -0
  180. package/src/kernels/ane/linear.ts +416 -0
  181. package/src/kernels/attention/flash.ts +694 -0
  182. package/src/kernels/attention/kvq4-decode.ts +155 -0
  183. package/src/kernels/attention/masks.ts +40 -0
  184. package/src/kernels/attention/multi-query.ts +193 -0
  185. package/src/kernels/attention/paged.ts +130 -0
  186. package/src/kernels/delta/gated.ts +306 -0
  187. package/src/kernels/delta/index.ts +3 -0
  188. package/src/kernels/delta/silu-rms-heads.ts +69 -0
  189. package/src/kernels/delta/state.ts +74 -0
  190. package/src/kernels/gated-rms-norm.ts +64 -0
  191. package/src/kernels/glm52/layout.ts +37 -0
  192. package/src/kernels/glm52/streamed-experts.ts +360 -0
  193. package/src/kernels/logits.ts +38 -0
  194. package/src/kernels/quantization/affine-row.ts +154 -0
  195. package/src/kernels/quantization/affine-rows.ts +36 -0
  196. package/src/kernels/quantization/affine-split-mma.ts +144 -0
  197. package/src/kernels/quantization/affine3-mma.ts +117 -0
  198. package/src/kernels/quantization/affine3-rows.ts +103 -0
  199. package/src/kernels/quantization/affine4-mma.ts +113 -0
  200. package/src/kernels/quantization/affine4-rows.ts +102 -0
  201. package/src/kernels/residual-rms-norm.ts +65 -0
  202. package/src/kernels/sampling/index.ts +2 -0
  203. package/src/kernels/sampling/normalized-argmax.ts +116 -0
  204. package/src/kernels/sampling/token-bitmask.ts +52 -0
  205. package/src/kernels/softcap.ts +35 -0
  206. package/src/kernels/trellis/codebook.ts +123 -0
  207. package/src/kernels/trellis/down-codebook.ts +184 -0
  208. package/src/kernels/trellis/down-factored.ts +180 -0
  209. package/src/kernels/trellis/down-k3-interleaved-factored.ts +146 -0
  210. package/src/kernels/trellis/down-mma-wide.ts +195 -0
  211. package/src/kernels/trellis/down-mma.ts +145 -0
  212. package/src/kernels/trellis/expand.ts +42 -0
  213. package/src/kernels/trellis/gate-up-codebook-mma.ts +141 -0
  214. package/src/kernels/trellis/gate-up-codebook.ts +137 -0
  215. package/src/kernels/trellis/gate-up-factored.ts +197 -0
  216. package/src/kernels/trellis/gate-up-mma-wide.ts +147 -0
  217. package/src/kernels/trellis/gate-up-mma.ts +148 -0
  218. package/src/kernels/trellis/gate-up.ts +248 -0
  219. package/src/kernels/trellis/geometry.ts +22 -0
  220. package/src/kernels/trellis/index.ts +103 -0
  221. package/src/kernels/trellis/launch.ts +12 -0
  222. package/src/kernels/trellis/mixed-gate-up-factored.ts +119 -0
  223. package/src/kernels/trellis/mixed-gate-up.ts +146 -0
  224. package/src/kernels/trellis/qualified.ts +34 -0
  225. package/src/kernels/trellis/reduce.ts +150 -0
  226. package/src/kernels/trellis/scatter.ts +407 -0
  227. package/src/kernels/trellis/splitk-prefill.ts +152 -0
  228. package/src/kernels/trellis/tiled-prefill.ts +131 -0
  229. package/src/kernels/trellis/vector-expand.ts +58 -0
  230. package/src/kernels/trellis/wide-prefill.ts +89 -0
  231. package/src/kernels/turboquant/decode.ts +82 -0
  232. package/src/kernels/turboquant/index.ts +5 -0
  233. package/src/kernels/turboquant/inverse.ts +122 -0
  234. package/src/kernels/turboquant/ops.ts +860 -0
  235. package/src/kernels/turboquant/signs.ts +130 -0
  236. package/src/kernels/turboquant/tables.ts +124 -0
  237. package/src/layers/affine-verify-linear.ts +75 -0
  238. package/src/layers/ane-prefill-split.ts +283 -0
  239. package/src/layers/compiled-normalization.ts +41 -0
  240. package/src/layers/delta-heads.ts +23 -0
  241. package/src/layers/dense-embedding.ts +29 -0
  242. package/src/layers/dense-linear.ts +32 -0
  243. package/src/layers/dequantized-linear.ts +72 -0
  244. package/src/layers/folded-attention.ts +42 -0
  245. package/src/layers/geglu.ts +130 -0
  246. package/src/layers/helpers.ts +7 -0
  247. package/src/layers/index.ts +36 -0
  248. package/src/layers/kv4-decode-attention.ts +15 -0
  249. package/src/layers/layer-norm.ts +24 -0
  250. package/src/layers/loading.ts +92 -0
  251. package/src/layers/lora.ts +150 -0
  252. package/src/layers/normalization.ts +9 -0
  253. package/src/layers/prefix-layout.ts +33 -0
  254. package/src/layers/quantized-append-attention.ts +32 -0
  255. package/src/layers/quantized-attention.ts +353 -0
  256. package/src/layers/quantized-embedding.ts +39 -0
  257. package/src/layers/quantized-linear.ts +137 -0
  258. package/src/layers/quantized-switch-linear.ts +37 -0
  259. package/src/layers/qwen-append.ts +12 -0
  260. package/src/layers/qwen-mrope.ts +238 -0
  261. package/src/layers/rope-2d.ts +110 -0
  262. package/src/layers/rope.ts +389 -0
  263. package/src/layers/swiglu.ts +23 -0
  264. package/src/layers/trellis-codebook-down.ts +52 -0
  265. package/src/layers/trellis-codebook-gate-up.ts +42 -0
  266. package/src/layers/trellis-down.ts +117 -0
  267. package/src/layers/trellis-gate-up.ts +71 -0
  268. package/src/layers/trellis-linear.ts +211 -0
  269. package/src/layers/trellis-prompt.ts +102 -0
  270. package/src/layers/trellis-reduce-gate-up.ts +73 -0
  271. package/src/layers/trellis-scatter-down.ts +98 -0
  272. package/src/models/ane-install.ts +74 -0
  273. package/src/models/audio/conformer.ts +656 -0
  274. package/src/models/cache-composition.ts +44 -0
  275. package/src/models/capabilities.ts +89 -0
  276. package/src/models/chat-template.ts +10 -0
  277. package/src/models/composition.ts +107 -0
  278. package/src/models/diffusion-gemma/experts.ts +59 -0
  279. package/src/models/diffusion-gemma/family.ts +21 -0
  280. package/src/models/diffusion-gemma/model.ts +900 -0
  281. package/src/models/diffusion-gemma/vision.ts +549 -0
  282. package/src/models/drafter-loaders.ts +49 -0
  283. package/src/models/drafters.ts +39 -0
  284. package/src/models/factory.ts +351 -0
  285. package/src/models/families.ts +70 -0
  286. package/src/models/family.ts +125 -0
  287. package/src/models/gemma4/assistant-target.ts +46 -0
  288. package/src/models/gemma4/assistant.ts +327 -0
  289. package/src/models/gemma4/blocks.ts +755 -0
  290. package/src/models/gemma4/compiled-decode.ts +452 -0
  291. package/src/models/gemma4/family.ts +39 -0
  292. package/src/models/gemma4/gemma4-12b.ts +677 -0
  293. package/src/models/gemma4/gemma4-26b.ts +544 -0
  294. package/src/models/gemma4/gemma4-e4b.ts +599 -0
  295. package/src/models/gemma4/graphs.ts +147 -0
  296. package/src/models/gemma4/media.ts +88 -0
  297. package/src/models/gemma4/model.ts +860 -0
  298. package/src/models/gemma4/serving-blocks.ts +72 -0
  299. package/src/models/gemma4/trainable.ts +186 -0
  300. package/src/models/gemma4/written-blocks.ts +232 -0
  301. package/src/models/gemma4/written-forward.ts +159 -0
  302. package/src/models/gemma4/written-input.ts +29 -0
  303. package/src/models/glm52/atlas.ts +507 -0
  304. package/src/models/glm52/coupling.ts +388 -0
  305. package/src/models/glm52/dsa.ts +601 -0
  306. package/src/models/glm52/family.ts +20 -0
  307. package/src/models/glm52/mla.ts +812 -0
  308. package/src/models/glm52/model.ts +1127 -0
  309. package/src/models/glm52/moe.ts +223 -0
  310. package/src/models/glm52/mtp.ts +60 -0
  311. package/src/models/glm52/pilot.ts +537 -0
  312. package/src/models/glm52/reference.ts +445 -0
  313. package/src/models/glm52/residency.ts +557 -0
  314. package/src/models/glm52/streamed-experts.ts +447 -0
  315. package/src/models/graph.ts +59 -0
  316. package/src/models/implementation.ts +230 -0
  317. package/src/models/index.ts +15 -0
  318. package/src/models/media-input.ts +15 -0
  319. package/src/models/memory-plan.ts +39 -0
  320. package/src/models/minicpm5/family.ts +29 -0
  321. package/src/models/minicpm5/model.ts +394 -0
  322. package/src/models/minicpm5/trainable.ts +90 -0
  323. package/src/models/profile.ts +337 -0
  324. package/src/models/qwen/blocks.ts +658 -0
  325. package/src/models/qwen/checkpoint.ts +190 -0
  326. package/src/models/qwen/families.ts +57 -0
  327. package/src/models/qwen/media-input.ts +161 -0
  328. package/src/models/qwen/mtp.ts +101 -0
  329. package/src/models/qwen/qwen3-moe.ts +355 -0
  330. package/src/models/qwen/qwen3.ts +323 -0
  331. package/src/models/qwen/qwen38-27b-trellis-m1max.ts +1532 -0
  332. package/src/models/qwen/qwen38-27b-trellis-m4pro.ts +1092 -0
  333. package/src/models/qwen/qwen3_5.ts +433 -0
  334. package/src/models/qwen/written-layers.ts +285 -0
  335. package/src/models/row-table.ts +1 -0
  336. package/src/models/runtime.ts +73 -0
  337. package/src/models/speculative/deepspec-artifact.ts +10 -0
  338. package/src/models/speculative/deepspec.ts +744 -0
  339. package/src/models/speculative/dflash.ts +553 -0
  340. package/src/models/speculative/dflash2-artifact.ts +9 -0
  341. package/src/models/speculative/dflash2-operations.ts +1 -0
  342. package/src/models/speculative/dflash2.ts +576 -0
  343. package/src/models/speculative/loader.ts +29 -0
  344. package/src/models/support.ts +79 -0
  345. package/src/models/universal/archs.ts +365 -0
  346. package/src/models/universal/blocks.ts +479 -0
  347. package/src/models/universal/dense.ts +255 -0
  348. package/src/models/universal/family.ts +17 -0
  349. package/src/models/vision/qwen3vl.ts +566 -0
  350. package/src/models/vision/siglip.ts +520 -0
  351. package/src/models/vision/unified.ts +176 -0
  352. package/src/models/whisper/family.ts +19 -0
  353. package/src/models/whisper/fast.ts +734 -0
  354. package/src/models/whisper/model.ts +430 -0
  355. package/src/runtime/compiled-trace.ts +16 -0
  356. package/src/runtime/config.ts +77 -0
  357. package/src/runtime/expert-trace.ts +71 -0
  358. package/src/runtime/graph-forward.ts +65 -0
  359. package/src/runtime/integers.ts +6 -0
  360. package/src/runtime/native.ts +16 -0
  361. package/src/runtime/resources.ts +53 -0
  362. package/src/runtime/row-operations.ts +42 -0
  363. package/src/runtime/trace.ts +161 -0
  364. package/src/sampling/curve.ts +122 -0
  365. package/src/sampling/draft.ts +55 -0
  366. package/src/sampling/extras.ts +45 -0
  367. package/src/sampling/filters.ts +134 -0
  368. package/src/sampling/grammar.ts +630 -0
  369. package/src/sampling/hlg.ts +290 -0
  370. package/src/sampling/index.ts +9 -0
  371. package/src/sampling/processors.ts +142 -0
  372. package/src/sampling/sampler.ts +120 -0
  373. package/src/sampling/step.ts +343 -0
  374. package/src/sampling/types.ts +161 -0
  375. package/src/sampling/window-filters.ts +46 -0
  376. package/src/scoring/decisions.ts +96 -0
  377. package/src/scoring/full-sequence.ts +103 -0
  378. package/src/scoring/index.ts +9 -0
  379. package/src/scoring/kl.ts +29 -0
  380. package/src/scoring/perplexity.ts +165 -0
  381. package/src/scoring/response-logps.ts +65 -0
  382. package/src/state/affine-attention.ts +180 -0
  383. package/src/state/attachment.ts +68 -0
  384. package/src/state/attention-read.ts +215 -0
  385. package/src/state/batched-kv.ts +294 -0
  386. package/src/state/batched-mask.ts +445 -0
  387. package/src/state/batched-quant.ts +389 -0
  388. package/src/state/batched-quantized-kv.ts +209 -0
  389. package/src/state/batched-rotating-quant.ts +457 -0
  390. package/src/state/batched-rotating-state.ts +149 -0
  391. package/src/state/batched-rotating.ts +430 -0
  392. package/src/state/batched-row-storage.ts +179 -0
  393. package/src/state/batched-ssm.ts +54 -0
  394. package/src/state/batched-turboquant-kv.ts +144 -0
  395. package/src/state/bf16-first-kv.ts +663 -0
  396. package/src/state/cache-service.ts +592 -0
  397. package/src/state/capabilities.ts +65 -0
  398. package/src/state/checkpoint.ts +46 -0
  399. package/src/state/continuation-persistence.ts +126 -0
  400. package/src/state/decode-step-inputs.ts +31 -0
  401. package/src/state/decoded-kv-donor.ts +12 -0
  402. package/src/state/delayed-quantized-kv.ts +141 -0
  403. package/src/state/delayed-rotating-quantized-kv.ts +178 -0
  404. package/src/state/delayed-turboquant-kv.ts +123 -0
  405. package/src/state/durability.ts +214 -0
  406. package/src/state/encoder-cache.ts +26 -0
  407. package/src/state/full-kv-row-append.ts +33 -0
  408. package/src/state/full-kv-row-donor.ts +54 -0
  409. package/src/state/full-prefill-padding.ts +56 -0
  410. package/src/state/full-prefill-row.ts +112 -0
  411. package/src/state/full-transitioning-kv-rows.ts +70 -0
  412. package/src/state/glm52-cache.ts +783 -0
  413. package/src/state/grouped-heads-kv4-cache.ts +26 -0
  414. package/src/state/index.ts +38 -0
  415. package/src/state/kv-attention-view.ts +77 -0
  416. package/src/state/kv-budget.ts +14 -0
  417. package/src/state/kv-scheme.ts +315 -0
  418. package/src/state/kv-storage.ts +57 -0
  419. package/src/state/kv-tensor-rows.ts +212 -0
  420. package/src/state/kv.ts +324 -0
  421. package/src/state/kv4-head256-cache.ts +46 -0
  422. package/src/state/latent-legos.ts +895 -0
  423. package/src/state/layout.ts +277 -0
  424. package/src/state/leases.ts +26 -0
  425. package/src/state/paged/cache.ts +689 -0
  426. package/src/state/paged/codec.ts +36 -0
  427. package/src/state/paged/rows.ts +223 -0
  428. package/src/state/persistence-types.ts +173 -0
  429. package/src/state/persistence-worker.ts +83 -0
  430. package/src/state/persistence.ts +1036 -0
  431. package/src/state/persistence.worker.d.ts +3 -0
  432. package/src/state/persistence.worker.js +264 -0
  433. package/src/state/prefix-cache.ts +685 -0
  434. package/src/state/quantized-kv.ts +369 -0
  435. package/src/state/quantized-tensor.ts +26 -0
  436. package/src/state/request-policy.ts +48 -0
  437. package/src/state/retention-policy.ts +37 -0
  438. package/src/state/rollback.ts +131 -0
  439. package/src/state/rotating-kv-donor.ts +35 -0
  440. package/src/state/rotating-kv-layout.ts +341 -0
  441. package/src/state/rotating-kv.ts +529 -0
  442. package/src/state/rotating-quantized-kv.ts +616 -0
  443. package/src/state/rotating-row-transaction.ts +35 -0
  444. package/src/state/rows.ts +104 -0
  445. package/src/state/softcap-attention.ts +118 -0
  446. package/src/state/speculative/glm52-mtp-state.ts +38 -0
  447. package/src/state/speculative/qwen-mtp-state.ts +34 -0
  448. package/src/state/speculative-rotating-kv.ts +113 -0
  449. package/src/state/ssd-cache.ts +434 -0
  450. package/src/state/ssm-prefill-padding.ts +39 -0
  451. package/src/state/ssm.ts +422 -0
  452. package/src/state/target-layout.ts +7 -0
  453. package/src/state/tiered-prefix-cache.ts +45 -0
  454. package/src/state/training-cache.ts +300 -0
  455. package/src/state/transitioning-kv-rows.ts +267 -0
  456. package/src/state/turboquant-attention.ts +97 -0
  457. package/src/state/turboquant-codec.ts +90 -0
  458. package/src/state/turboquant-kv.ts +442 -0
  459. package/src/state/views.ts +26 -0
  460. package/src/transcription/index.ts +3 -0
  461. package/src/transcription/silero-vad.ts +379 -0
  462. package/src/transcription/whisper/decode.ts +773 -0
  463. package/src/transcription/whisper/format.ts +74 -0
  464. package/src/transcription/whisper/index.ts +4 -0
  465. package/src/transcription/whisper/timing.ts +274 -0
  466. package/src/transcription/whisper/transcribe.ts +394 -0
  467. package/src/transcription/whisper/types.ts +22 -0
@@ -0,0 +1,190 @@
1
+ // Qwen3.5 checkpoint-generation normalization — the load-seam port of
2
+ // mlx_lm.models.qwen3_5's `Model.sanitize` + `TextModel.sanitize`.
3
+ //
4
+ // Two checkpoint generations ship the same graph under different conventions:
5
+ //
6
+ // pre-5.8 (mlx-lm-converted) 5.8-family (transformers 5.8.0 export)
7
+ // ────────────────────────── ───────────────────────────────────────
8
+ // language_model.model.* model.language_model.*
9
+ // language_model.lm_head.* lm_head.* (top level)
10
+ // vision_tower.* model.visual.*
11
+ // (no mtp tensors in-repo) mtp.* (in-repo)
12
+ // conv1d.weight [C, K, 1] conv1d.weight [C, 1, K] (HF layout)
13
+ // RMSNorm gains stored as γ RMSNorm gains stored as γ−1
14
+ //
15
+ // Our graph speaks the FIRST column (`PREFIX = "language_model"` in
16
+ // qwen3_5.ts) — which is exactly mlx-lm's post-sanitize name space — so this
17
+ // module maps the artifact onto it instead of teaching every consumer two
18
+ // namings. The rules below are a line-for-line copy of the oracle; see
19
+ // mlx_lm/models/qwen3_5.py `Model.sanitize` (naming/drop) and
20
+ // `TextModel.sanitize` (γ shift, conv layout).
21
+ //
22
+ // The γ shift is the dangerous one: a spurious +1.0 silently corrupts an old
23
+ // artifact. The oracle's discriminator is NOT the naming — it is
24
+ // should_shift = any("mtp." in k) or any conv1d.weight with shape[-1] != 1
25
+ // evaluated over the whole (post-rename, pre-drop) weight map. Reproduced
26
+ // verbatim. Measured on the two artifacts in play (2026-09-01, M1 Max):
27
+ // • ~/.cache/…/models--mjriii--Qwen3.8-27B/snapshots/staged — no mtp.*,
28
+ // conv1d [10240,4,1] → no shift; layer-0 input_layernorm ≡ 1.0.
29
+ // • /Volumes/MLX-Models/models/mjriii/Qwen3.8-27B-{tqalloc-norot,rtn4-g64}
30
+ // — 31 mtp.* tensors, conv1d [10240,1,4] → shift; layer-0
31
+ // input_layernorm mean −0.0334 (= γ−1), byte-identical to the raw
32
+ // Qwen/Qwen3.8-27B 5.8 checkpoint (the quantizer copies norms verbatim).
33
+
34
+ import type { MlxArray } from "@mlx-bun/mlx/array";
35
+ import * as ops from "@mlx-bun/mlx/ops";
36
+ import { quantFor, type ModelConfig } from "../../artifacts/config";
37
+ import type { Weights, WeightsView } from "../../artifacts/weights";
38
+
39
+ /** Header-level facts about one stored tensor (no bytes are read). */
40
+ export interface CheckpointTensor {
41
+ readonly name: string;
42
+ readonly shape: readonly number[];
43
+ }
44
+
45
+ export interface Qwen35Sanitized {
46
+ /** canonical (graph) name → the name the artifact actually stores. */
47
+ readonly names: Map<string, string>;
48
+ /** Canonical names stored as γ−1: a +1.0 is due at load. */
49
+ readonly normShift: Set<string>;
50
+ /** Canonical names in HF conv layout: a moveaxis(2, 1) is due at load. */
51
+ readonly convMoveaxis: Set<string>;
52
+ /** True when the artifact already IS our canonical layout — no view needed
53
+ * and the pre-existing load path runs untouched. */
54
+ readonly identity: boolean;
55
+ }
56
+
57
+ /** mlx-lm `TextModel.sanitize` norm_keys, verbatim and in order. */
58
+ const NORM_KEYS = [
59
+ ".input_layernorm.weight",
60
+ ".post_attention_layernorm.weight",
61
+ "model.norm.weight",
62
+ ".q_norm.weight",
63
+ ".k_norm.weight",
64
+ ] as const;
65
+
66
+ /** mlx-lm `Model.sanitize`: drop vision, fold every naming onto
67
+ * `language_model.…`. Returns null for a dropped tensor. */
68
+ function canonicalName(key: string): string | null {
69
+ if (key.startsWith("vision_tower") || key.startsWith("model.visual")) return null;
70
+ if (key.startsWith("model.language_model"))
71
+ return "language_model.model" + key.slice("model.language_model".length);
72
+ if (key.startsWith("language_model.")) return key;
73
+ return "language_model." + key;
74
+ }
75
+
76
+ /**
77
+ * Port of mlx_lm.models.qwen3_5 `Model.sanitize` ∘ `TextModel.sanitize`,
78
+ * name/shape half. Pure: takes header facts, returns the load plan.
79
+ */
80
+ export function sanitizeQwen35Checkpoint(
81
+ tensors: Iterable<CheckpointTensor>,
82
+ ): Qwen35Sanitized {
83
+ // Pass 1 — rename (vision dropped), exactly as Model.sanitize.
84
+ const renamed: { canonical: string; source: string; shape: readonly number[] }[] = [];
85
+ let sawForeignName = false;
86
+ for (const t of tensors) {
87
+ const canonical = canonicalName(t.name);
88
+ if (canonical === null) {
89
+ sawForeignName ||= t.name.startsWith("model.visual");
90
+ continue;
91
+ }
92
+ if (canonical !== t.name) sawForeignName = true;
93
+ renamed.push({ canonical, source: t.name, shape: t.shape });
94
+ }
95
+
96
+ // Pass 2 — TextModel.sanitize's two flags, over the renamed map BEFORE the
97
+ // mtp drop (the oracle computes them first, then filters).
98
+ const hasMtpWeights = renamed.some((t) => t.canonical.includes("mtp."));
99
+ const hasUnsanitizedConv1d = renamed.some(
100
+ (t) => t.canonical.includes("conv1d.weight") && t.shape[t.shape.length - 1] !== 1,
101
+ );
102
+ const shouldShiftNormWeights = hasMtpWeights || hasUnsanitizedConv1d;
103
+
104
+ const names = new Map<string, string>();
105
+ const normShift = new Set<string>();
106
+ const convMoveaxis = new Set<string>();
107
+ for (const t of renamed) {
108
+ if (t.canonical.includes("mtp.")) continue; // oracle drops these outright
109
+ names.set(t.canonical, t.source);
110
+ if (t.canonical.includes("conv1d.weight") && t.shape[t.shape.length - 1] !== 1)
111
+ convMoveaxis.add(t.canonical);
112
+ if (
113
+ shouldShiftNormWeights &&
114
+ NORM_KEYS.some((sfx) => t.canonical.endsWith(sfx)) &&
115
+ t.shape.length === 1
116
+ )
117
+ normShift.add(t.canonical);
118
+ }
119
+
120
+ return {
121
+ names,
122
+ normShift,
123
+ convMoveaxis,
124
+ identity: !sawForeignName && !hasMtpWeights && !shouldShiftNormWeights &&
125
+ convMoveaxis.size === 0,
126
+ };
127
+ }
128
+
129
+ /**
130
+ * The {@link WeightsView} for a qwen3.5 artifact, or null when the artifact is
131
+ * already canonical (then nothing is installed and the load path is bit-for-bit
132
+ * what it was before this seam existed).
133
+ */
134
+ export function qwen35WeightsView(weights: Weights): WeightsView | null {
135
+ const plan = sanitizeQwen35Checkpoint(
136
+ weights.tensorNames.map((name) => ({ name, shape: weights.info(name).shape })),
137
+ );
138
+ if (plan.identity) return null;
139
+ return {
140
+ names: plan.names,
141
+ fixup(canonical: string, arr: MlxArray): MlxArray | null {
142
+ // Oracle order: moveaxis first, then the γ shift (disjoint sets — a
143
+ // conv1d weight is 3-D and never a norm gain).
144
+ if (plan.convMoveaxis.has(canonical)) {
145
+ // `v.moveaxis(2, 1)` on [C, 1, K] → [C, K, 1]. Materialized: the
146
+ // conv1d kernel consumes it every forward, and the transposed view
147
+ // would otherwise pin the source shard buffer.
148
+ const moved = ops.transposeAxes(arr, [0, 2, 1]);
149
+ const out = ops.contiguous(moved);
150
+ moved.dispose();
151
+ return out;
152
+ }
153
+ if (plan.normShift.has(canonical)) {
154
+ // `v + 1.0` — a weak python scalar, so the add happens at the gain's
155
+ // own dtype (bf16 here); scalarLike builds the constant host-side at
156
+ // that dtype for the same single-kernel add the reference dispatches.
157
+ const one = ops.scalarLike(1, arr);
158
+ const out = ops.add(arr, one);
159
+ one.dispose();
160
+ return out;
161
+ }
162
+ return null;
163
+ },
164
+ };
165
+ }
166
+
167
+ /** The graph fingerprint the `qwen3.5` graph table keys its written graphs on: architecture plus the complete
168
+ * language-model quantization table (every layer's projections, the head and the embedding). Two artifacts share
169
+ * a fingerprint only if every tensor has the same codec. Reads the config only. */
170
+ export function qwen35GraphFingerprint(config: ModelConfig): string {
171
+ const t = config.text;
172
+ const q = config.quantization as unknown as { bits?: number; groupSize?: number; mode?: string; overrides?: Record<string, unknown> } | null;
173
+ const roles = ["linear_attn.in_proj_qkv", "linear_attn.in_proj_z", "linear_attn.in_proj_a", "linear_attn.in_proj_b",
174
+ "linear_attn.out_proj", "self_attn.q_proj", "self_attn.k_proj", "self_attn.v_proj", "self_attn.o_proj",
175
+ "mlp.gate_proj", "mlp.up_proj", "mlp.down_proj"];
176
+ const table: unknown[] = [];
177
+ for (let layer = 0; layer < t.numHiddenLayers; layer++)
178
+ for (const role of roles) table.push(quantFor(config.quantization, `language_model.model.layers.${layer}.${role}`));
179
+ table.push(quantFor(config.quantization, "language_model.lm_head"), quantFor(config.quantization, "language_model.model.embed_tokens"));
180
+ const payload = JSON.stringify({
181
+ modelType: config.modelType, hiddenSize: t.hiddenSize, intermediateSize: t.intermediateSize,
182
+ layers: t.numHiddenLayers, fullAttentionInterval: t.fullAttentionInterval,
183
+ heads: t.numAttentionHeads, kvHeads: t.numKeyValueHeads, headDim: t.headDim,
184
+ linear: [t.linearNumKeyHeads, t.linearNumValueHeads, t.linearKeyHeadDim, t.linearValueHeadDim, t.linearConvKernelDim],
185
+ vocabSize: t.vocabSize, tied: t.tieWordEmbeddings, defaults: q ? [q.bits, q.groupSize, q.mode] : null, table,
186
+ });
187
+ const hash = new Bun.CryptoHasher("sha256");
188
+ hash.update(payload);
189
+ return hash.digest("hex").slice(0, 16);
190
+ }
@@ -0,0 +1,57 @@
1
+ import { L1, defineFamily } from "../family";
2
+
3
+ /** Qwen3.5 hybrid gated-DeltaNet family (model_type qwen3_5 / qwen3_5_text).
4
+ * Dense MLP only for now: the MoE variant (qwen3_5_moe) is deferred. */
5
+ export const QWEN35_FAMILY = defineFamily({
6
+ graph: "qwen3.5",
7
+ accepts: config => (config.modelType === "qwen3_5" || config.modelType === "qwen3_5_text") &&
8
+ !config.text.enableMoeBlock &&
9
+ config.text.numExperts === 0 &&
10
+ config.text.linearNumValueHeads > 0 &&
11
+ config.text.fullAttentionInterval > 0,
12
+ hasModelType: modelType => modelType === "qwen3_5" || modelType === "qwen3_5_text",
13
+ tier: "targeted",
14
+ label: "qwen3_5",
15
+ loader: "safetensors",
16
+ loop: "autoregressive",
17
+ fidelity: L1,
18
+ specialization: "dedicated",
19
+ profileId: "qwen3.5-dedicated",
20
+ capabilities: ["qwen3.5-graph", "recurrent-state"],
21
+ });
22
+
23
+ /** Plain Qwen3 (model_type `qwen3`, Qwen3ForCausalLM): a standard dense decoder
24
+ * with per-head q/k norm and tied embeddings. Also the text-embedding backbone
25
+ * (mlx-community Qwen3-Embedding-*). Distinct from the qwen3_5 hybrid. */
26
+ export const QWEN3_FAMILY = defineFamily({
27
+ graph: "qwen3",
28
+ accepts: config => config.modelType === "qwen3",
29
+ hasModelType: modelType => modelType === "qwen3",
30
+ tier: "targeted",
31
+ label: "qwen3",
32
+ loader: "safetensors",
33
+ loop: "autoregressive",
34
+ fidelity: L1,
35
+ specialization: "dedicated",
36
+ profileId: "qwen3-dedicated",
37
+ capabilities: ["qwen3-graph"],
38
+ embedding: { terminator: "<|endoftext|>" },
39
+ });
40
+
41
+ /** Qwen3-MoE (model_type `qwen3_moe`): plain-qwen3 attention with a sparse MoE
42
+ * FFN (gate Linear, precise softmax, top-k, renormalize, SwitchGLU experts with
43
+ * compiled swiglu). Distinct from the qwen3 embedding backbone and the
44
+ * qwen3_5 gated-DeltaNet hybrid. */
45
+ export const QWEN3_MOE_FAMILY = defineFamily({
46
+ graph: "qwen3-moe",
47
+ accepts: config => config.modelType === "qwen3_moe",
48
+ hasModelType: modelType => modelType === "qwen3_moe",
49
+ tier: "targeted",
50
+ label: "qwen3_moe",
51
+ loader: "safetensors",
52
+ loop: "autoregressive",
53
+ fidelity: L1,
54
+ specialization: "dedicated",
55
+ profileId: "qwen3-moe-dedicated",
56
+ capabilities: ["qwen3-moe-graph"],
57
+ });
@@ -0,0 +1,161 @@
1
+ import { rowOperationFor } from "../../runtime/row-operations";
2
+ import type { ModelConfig } from "../../artifacts/config";
3
+ import { TURBOQUANT_FOLD_FILE, readTurboQuantFold } from "../../artifacts/turboquant-fold";
4
+ import type { QuantizedEmbedding } from "../../layers/quantized-embedding";
5
+ import { QuantizedLinear } from "../../layers/quantized-linear";
6
+ import { readDraftVocabulary } from "../../artifacts/draft-vocabulary";
7
+ import type { DraftProjection } from "../../contracts/mlx/draft-projection";
8
+ import { mropePositionIds } from "../../layers/qwen-mrope";
9
+ import { type MropeRequestState } from "../../contracts/mlx/positions";
10
+ import type { MlxArray } from "@mlx-bun/mlx/array";
11
+ import type { Cache } from "../../contracts/mlx/cache";
12
+ import type { MediaEncoders, MlxDecodeState, MlxPromptInput, VisionEncoder, MlxPositionedEmbeddingsRange, MlxPositionedRange, MlxPositionedForward } from "../../contracts/mlx/media";
13
+ import type { MlxHeadForward, MlxRowTable } from "../../contracts/mlx/graph";
14
+ import type { DraftProjectionKernels, ResidualBasis, TargetView } from "../../contracts/mlx/draft-target";
15
+ import type { DraftHeadOperations } from "../../contracts/mlx/draft-projection";
16
+ import { existsSync } from "node:fs";
17
+ import { join } from "node:path";
18
+ import * as ops from "@mlx-bun/mlx/ops";
19
+ import { Dtype } from "@mlx-bun/mlx/ffi";
20
+ import { bindEmbeddingsInput } from "../media-input";
21
+
22
+ /** What the Qwen graph's media and draft ports read from it. */
23
+ export interface QwenMediaGraph {
24
+ readonly config: ModelConfig;
25
+ readonly embed: QuantizedEmbedding;
26
+ readonly lmHead: QuantizedLinear | null;
27
+ /** The full-attention layer whose cache supplies logical positions. */
28
+ readonly faIdx: number;
29
+ /** The vision prefill phase: a prompt's prepared embeddings (borrowed) at request positions. */
30
+ prefillEmbeddingsAtPositions?(embeddings: MlxArray, caches: Cache[], positions: MlxArray, width: number): MlxArray;
31
+ /** A prompt's token ids after a reused prefix, at request positions. */
32
+ prefillAtPositions?(ids: MlxArray, caches: Cache[], positions: MlxArray, width: number): MlxArray;
33
+ /** One new token per row at request positions. */
34
+ decodeAtPositions?(ids: MlxArray, caches: Cache[], positions: MlxArray, width: number): MlxArray;
35
+ readonly mediaPrefill?: readonly MlxPositionedEmbeddingsRange[];
36
+ readonly mediaPrompt?: readonly MlxPositionedRange[];
37
+ readonly mediaDecode?: MlxRowTable<MlxPositionedForward>;
38
+ readonly logits: MlxRowTable<MlxHeadForward>;
39
+ }
40
+
41
+ class QwenMediaDecodeState implements MlxDecodeState {
42
+ readonly key = "qwen-interleaved-mrope";
43
+ constructor(readonly model: QwenMediaGraph, readonly delta: number) {}
44
+
45
+ decode(ids: MlxArray, caches: Cache[], rows: readonly MlxDecodeState[], width: number): MlxArray {
46
+ const B = rows.length, L = ids.shape[1]!;
47
+ const cache = caches[this.model.faIdx]!;
48
+ // The cache supplies logical positions, including left padding, on device.
49
+ // No offset readback or request-global position mutation is needed.
50
+ const offsets = (cache as Cache & { ropeOffsetArr?: MlxArray }).ropeOffsetArr;
51
+ using deltas = ops.fromInt32(rows.map(row => (row as QwenMediaDecodeState).delta), [B]);
52
+ using scalar = offsets ? null : ops.fromInt32([cache.offset], []);
53
+ using starts = ops.add(offsets ?? scalar!, deltas);
54
+ using startRows = ops.reshape(starts, [B, 1]);
55
+ using indices = ops.arange(0, L, 1, Dtype.int32);
56
+ using positions = ops.add(startRows, indices);
57
+ using axis = ops.reshape(positions, [1, B, L]);
58
+ using grid = ops.concatAxis([axis, axis, axis], 0);
59
+ return this.model.mediaDecode ? rowOperationFor(this.model.mediaDecode, width)(ids, caches, grid)
60
+ : this.model.decodeAtPositions!(ids, caches, grid, width);
61
+ }
62
+ }
63
+
64
+ /** The prompt owns its grid; only its continuation delta survives into decode. */
65
+ export function bindQwenMediaInput(model: QwenMediaGraph, embeddings: MlxArray,
66
+ state: MropeRequestState): MlxPromptInput {
67
+ const input = bindEmbeddingsInput((ids, caches, start, phase, width) => {
68
+ using positions = mropePositionIds(state, start, ids.shape[1]!);
69
+ if (start === 0) return model.mediaPrefill
70
+ ? model.mediaPrefill.find(range => width >= range.from && width <= range.to)!.operation(embeddings, caches, positions)
71
+ : model.prefillEmbeddingsAtPositions!(embeddings, caches, positions, width);
72
+ if (phase === "decode") return model.mediaDecode ? rowOperationFor(model.mediaDecode, width)(ids, caches, positions)
73
+ : model.decodeAtPositions!(ids, caches, positions, width);
74
+ return model.mediaPrompt
75
+ ? model.mediaPrompt.find(range => width >= range.from && width <= range.to)!.operation(ids, caches, positions)
76
+ : model.prefillAtPositions!(ids, caches, positions, width);
77
+ });
78
+ return { ...input, decodeState: new QwenMediaDecodeState(model, state.delta) };
79
+ }
80
+
81
+ /** Tower weights arrive either as the OptiQ-convention sidecar or in the main
82
+ * shards (mlx-vlm convention); the tower loader handles both. The encoder is a
83
+ * Qwen3VLVisionTower riding the shared lazy slot; the Qwen media route is its
84
+ * only consumer and reads it through the structural contract it defines. */
85
+ export async function qwenMediaEncoders(model: QwenMediaGraph, modelDir: string): Promise<MediaEncoders> {
86
+ const hasSidecar = existsSync(`${modelDir}/optiq/optiq_vision.safetensors`);
87
+ if (!hasSidecar && model.config.raw.vision_config === undefined) return { vision: null, audio: null };
88
+ const { Qwen3VLVisionTower } = await import("../vision/qwen3vl");
89
+ return { vision: () => Qwen3VLVisionTower.load(modelDir) as unknown as VisionEncoder, audio: null };
90
+ }
91
+
92
+ /** The residual basis a rotated Qwen artifact declares in its fold record
93
+ * (`turboquant_fold.json`), for its graph's constructor to read once. A record
94
+ * whose stream carries no R1 rotation declares none. A missing record, or one
95
+ * without `final_gain`, declares none either: DFlash 2 then drafts in its
96
+ * trained basis (output exact, acceptance collapsed), and one line names the
97
+ * file to update. */
98
+ export function qwenResidualBasis(graph: string, modelDir: string): ResidualBasis | undefined {
99
+ const fold = readTurboQuantFold(modelDir);
100
+ if (fold && !fold.r1) return undefined;
101
+ if (fold?.finalGain) return Object.freeze({ r1Seed: fold.seed, finalGain: fold.finalGain });
102
+ console.error(`[graph] ${graph}: ${join(modelDir, TURBOQUANT_FOLD_FILE)} ${fold ? "records no final_gain" : "is missing"}; ` +
103
+ "DFlash 2 drafts unrotated (output exact, acceptance collapses) until it records the final-norm gain the fold moved into lm_head");
104
+ return undefined;
105
+ }
106
+
107
+ /** Ports draft sources read from this graph: its embedding, head, layer taps,
108
+ * the MTP geometry a checkpoint-native draft head needs, from a graph whose
109
+ * residual stream carries a rotation fold that basis, and from a graph whose
110
+ * composition measured them the kernels of a drafter's own projections (each the
111
+ * same object on every view) and the head over its draft vocabulary (`vocabulary`,
112
+ * read when a drafter first reads the projection's). */
113
+ export function qwenDraftTarget(model: QwenMediaGraph, residualBasis?: ResidualBasis,
114
+ draftProjections?: DraftProjectionKernels, vocabulary?: () => DraftProjection["vocabulary"]): TargetView {
115
+ const projection: DraftProjection = { embed: model.embed, logits: model.logits };
116
+ // The vocabulary's rows are gathered when a drafter first reads them, not for drafters that never do.
117
+ if (vocabulary) Object.defineProperty(projection, "vocabulary", { get: vocabulary, enumerable: true });
118
+ return Object.freeze({ identity: model, ...(residualBasis ? { residualBasis } : {}), ...(draftProjections ? { draftProjections } : {}),
119
+ hiddenLayerTaps: Object.freeze({
120
+ layerCount: model.config.text.numHiddenLayers,
121
+ projection: Object.freeze(projection),
122
+ }), recurrentMtp: Object.freeze({
123
+ hiddenSize: model.config.text.hiddenSize, layerCount: model.config.text.numHiddenLayers,
124
+ embed: model.embed.encode.bind(model.embed), logits: model.logits,
125
+ vocabularyHead: model.lmHead ? Object.freeze({ w: model.lmHead.w, scales: model.lmHead.scales,
126
+ biases: model.lmHead.biases, spec: model.lmHead.spec, vocabSize: model.config.text.vocabSize }) : undefined,
127
+ }) });
128
+ }
129
+
130
+ /** The head's rows of the artifact's frequency-ranked draft vocabulary (`file`, a path inside the artifact) and their
131
+ * projection operations on `kernels` (the head's own layers over those rows), for a graph whose composition
132
+ * measured a drafter selecting over them. A row gather of an affine head is exact: the rows' logits are the full
133
+ * head's arithmetic per row. The gathered arrays go to `owned`, which the graph frees. */
134
+ export function qwenDraftVocabulary(head: QuantizedLinear, modelDir: string, file: string, vocabSize: number,
135
+ kernels: (rows: QuantizedLinear) => DraftHeadOperations,
136
+ owned: { dispose(): void }[]): NonNullable<DraftProjection["vocabulary"]> {
137
+ const listed = readDraftVocabulary(join(modelDir, file), vocabSize);
138
+ using index = ops.fromInt32([...listed], [listed.length]);
139
+ const ids = index.astype(Dtype.uint32);
140
+ owned.push(ids);
141
+ const gather = (array: MlxArray) => {
142
+ using rows = ops.takeAxis(array, index, 0);
143
+ const copy = ops.contiguous(rows);
144
+ owned.push(copy);
145
+ return copy;
146
+ };
147
+ const rows = new QuantizedLinear(gather(head.w), gather(head.scales), head.biases ? gather(head.biases) : null, head.spec);
148
+ ops.evalAll([ids, rows.w, rows.scales, ...(rows.biases ? [rows.biases] : [])]);
149
+ return Object.freeze({ ids, logits: kernels(rows) });
150
+ }
151
+
152
+
153
+ /** Gather a draft vocabulary only when a source first reads it, then retain
154
+ * the same port and owned weights for every target view. The graph supplies
155
+ * the concrete projection operations over the gathered rows. */
156
+ export function qwenDraftVocabularyMemo(head: QuantizedLinear, modelDir: string, file: string, vocabSize: number,
157
+ kernels: (rows: QuantizedLinear) => DraftHeadOperations,
158
+ owned: { dispose(): void }[]): () => NonNullable<DraftProjection["vocabulary"]> {
159
+ let vocabulary: NonNullable<DraftProjection["vocabulary"]> | undefined;
160
+ return () => vocabulary ??= qwenDraftVocabulary(head, modelDir, file, vocabSize, kernels, owned);
161
+ }
@@ -0,0 +1,101 @@
1
+ // Qwen MTP numerical graph. Request state, sampling and checkpoint retention
2
+ // belong to its callers; the cache supplies positions and attention storage.
3
+ import type { MlxArray } from "@mlx-bun/mlx/array";
4
+ import * as ops from "@mlx-bun/mlx/ops";
5
+ import type { ModelConfig } from "../../artifacts/config";
6
+ import type { Weights } from "../../artifacts/weights";
7
+ import { disposing } from "../../layers/helpers";
8
+ import { QuantizedLinear } from "../../layers/quantized-linear";
9
+ import { RMSNorm } from "../../layers/normalization";
10
+ import { type Cache } from "../../contracts/mlx/cache";
11
+ import type { RecurrentMtpForward, RecurrentMtpModule } from "../../contracts/mlx/drafter";
12
+ import type { MlxRowTable } from "../../contracts/mlx/graph";
13
+ import { DenseLinear } from "../../layers/dense-linear";
14
+ import { compiledSwiglu } from "../../layers/swiglu";
15
+ import { Qwen3Attention } from "./blocks";
16
+ import { rowTable } from "../graph";
17
+
18
+ type MtpLinear = DenseLinear | QuantizedLinear;
19
+
20
+ /** Projection tensors belong to Weights; dense transpose views belong to
21
+ * the provider's resource stack. Quantized heads keep no dense copy. */
22
+ function loadMtpLinear(
23
+ weights: Weights, path: string, config: ModelConfig, resources: DisposableStack,
24
+ ): MtpLinear {
25
+ if (weights.has(`${path}.scales`)) return QuantizedLinear.load(weights, path, config);
26
+ const layer = new DenseLinear(weights.tensor(`${path}.weight`), null);
27
+ resources.use(layer.wT);
28
+ return layer;
29
+ }
30
+
31
+ /** The one MTP decoder block: fc-merge → attention → swiglu MLP → norm. */
32
+ export class MtpModule implements RecurrentMtpModule {
33
+ readonly fc: MtpLinear;
34
+ readonly preFcNormEmbedding: RMSNorm;
35
+ readonly preFcNormHidden: RMSNorm;
36
+ readonly attn: Qwen3Attention<MtpLinear>;
37
+ readonly mlpGate: MtpLinear;
38
+ readonly mlpUp: MtpLinear;
39
+ readonly mlpDown: MtpLinear;
40
+ readonly inputNorm: RMSNorm;
41
+ readonly postAttnNorm: RMSNorm;
42
+ readonly finalNorm: RMSNorm;
43
+
44
+ constructor(weights: Weights, config: ModelConfig, resources: DisposableStack) {
45
+ const eps = config.text.rmsNormEps;
46
+ this.fc = loadMtpLinear(weights, "fc", config, resources);
47
+ this.preFcNormEmbedding = new RMSNorm(weights.tensor("pre_fc_norm_embedding.weight"), eps);
48
+ this.preFcNormHidden = new RMSNorm(weights.tensor("pre_fc_norm_hidden.weight"), eps);
49
+ // The target's attention block (blocks.ts) with the companion's dense or quantized heads.
50
+ this.attn = new Qwen3Attention<MtpLinear>(weights, config, "layers.0.self_attn",
51
+ (w, path, c) => loadMtpLinear(w, path, c, resources));
52
+ this.mlpGate = loadMtpLinear(weights, "layers.0.mlp.gate_proj", config, resources);
53
+ this.mlpUp = loadMtpLinear(weights, "layers.0.mlp.up_proj", config, resources);
54
+ this.mlpDown = loadMtpLinear(weights, "layers.0.mlp.down_proj", config, resources);
55
+ this.inputNorm = new RMSNorm(weights.tensor("layers.0.input_layernorm.weight"), eps);
56
+ this.postAttnNorm = new RMSNorm(weights.tensor("layers.0.post_attention_layernorm.weight"), eps);
57
+ this.finalNorm = new RMSNorm(weights.tensor("norm.weight"), eps);
58
+ }
59
+
60
+ /** One position per row; the module has one draft kernel set, at every width. */
61
+ readonly decode: MlxRowTable<RecurrentMtpForward> = rowTable<RecurrentMtpForward>(
62
+ (tokenEmbeds, hiddens, cache) => this.#block(tokenEmbeds, hiddens, cache, "decode"));
63
+ /** Several positions per row. */
64
+ readonly window: RecurrentMtpForward = (tokenEmbeds, hiddens, cache) => this.#block(tokenEmbeds, hiddens, cache, "window");
65
+
66
+ /** One block forward over [B,S,·]: token embeddings ([B,S,H], target
67
+ * embed_tokens output) paired with hiddens ([B,S,H], target pre-final-norm
68
+ * or the module's own chained output), the attention reading its cache for
69
+ * `phase`. Appends S rows to `cache`; returns the module output [B,S,H]
70
+ * (post final norm — what the target lm_head consumes AND what chains into
71
+ * the next step's `hidden`). */
72
+ #block(tokenEmbeds: MlxArray, hiddens: MlxArray, cache: Cache, phase: "decode" | "window"): MlxArray {
73
+ const embNorm = this.preFcNormEmbedding.forward(tokenEmbeds);
74
+ const hidNorm = this.preFcNormHidden.forward(hiddens);
75
+ const joined = ops.concatAxis([embNorm, hidNorm], 2);
76
+ embNorm.dispose();
77
+ hidNorm.dispose();
78
+ const x = this.fc.forward(joined);
79
+ joined.dispose();
80
+
81
+ // Decoder layer (Qwen3Layer.forward shape).
82
+ const xn = this.inputNorm.forward(x);
83
+ const r = this.attn.forward(xn, cache, phase);
84
+ xn.dispose();
85
+ const h = ops.add(x, r);
86
+ x.dispose();
87
+ r.dispose();
88
+ const hn = this.postAttnNorm.forward(h);
89
+ const g = this.mlpGate.forward(hn);
90
+ const u = this.mlpUp.forward(hn);
91
+ hn.dispose();
92
+ const act = compiledSwiglu(g, u);
93
+ g.dispose(); u.dispose();
94
+ const m = this.mlpDown.forward(act);
95
+ act.dispose();
96
+ const out = ops.add(h, m);
97
+ h.dispose();
98
+ m.dispose();
99
+ return disposing(out, this.finalNorm.forward(out));
100
+ }
101
+ }