@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,576 @@
1
+ import type { MlxRowTable } from "../../contracts/mlx/row-table";
2
+ // DFlash 2 drafter for Qwen3.8-27B (incoai/Qwen3.8-27B-DFlash2, Apache-2.0).
3
+ // Port of z-lab/dflash@07ebd93 `dflash/model_mlx.py` (DFlash2DraftModel),
4
+ // cross-checked against Splash `runtime/model/DFlashDraft.cpp`, SGLang PR
5
+ // #35371 and vLLM PR #52816. Five Qwen3-style layers draft one block
6
+ // [anchor, MASK×(G−1)] in a single pass:
7
+ // context c = hidden_norm(fc(concat(target layers 5,19,33,47,61)))
8
+ // — each layer projects c with its own k/v (k_norm, RoPE at the
9
+ // row's absolute position) into a K/V prefix the block attends to.
10
+ // layer n = rms(x); D = kernel_projection(n) → [stage, tap, group]
11
+ // x += Conv₁(Attn(Conv₀(n))); m = rms(x); D' from m
12
+ // x += Conv₁(MLP(Conv₀(m)))
13
+ // Conv(y)[t,c] = Σ_τ (base[τ,c] + D[t,τ,c/16])·y[t−τ,c], y[−1] = 0
14
+ // output rows 1..G−1 → norm → the TARGET's lm_head (the drafter has no
15
+ // embedding or head of its own), or the head's rows of the draft
16
+ // vocabulary a target's composition declares
17
+ // (`DraftProjection.vocabulary`): the walk then selects among them.
18
+ // selector top-16 per position; greedy left-to-right walk scoring
19
+ // logit + Σ_r pred[prev,r]·z[r]·succ[cand,r], z = hidden_projection(h).
20
+ // Attention is bidirectional within the block. The 2048-row sliding window
21
+ // over context is not applied: context longer than 2047 rows attends to all
22
+ // of it (verification keeps outputs exact; acceptance can drop).
23
+ //
24
+ // Target basis: a TurboQuant R1 fold stores the residual stream as h·R1,
25
+ // R1 = diag(s)·M with M = MLX's hadamard_transform/√n (x ↦ x·M), and folds the
26
+ // final-norm gain γ into the head. The drafter was trained on the unrotated
27
+ // model and loads in that basis; the target declares its own
28
+ // (`TargetView.residualBasis`) and the drafter applies it once, when a draft
29
+ // group binds: taps reach fc as tap·R1ᵀ (folded into fc as fc·diag(s)·M),
30
+ // embedding rows are rotated back as (x·Mᵀ)⊙s, and draft hiddens enter the
31
+ // folded head as ((v/γ)⊙s)·M. For n = 5120 = 20·256, M is orthogonal but NOT
32
+ // symmetric, so x·Mᵀ needs the dense transpose, not a second transform.
33
+ //
34
+ // Kernels: each 4-bit projection runs, per row count or range of its rows, the kernel
35
+ // the target's composition declares for its device (`TargetView.draftProjections`)
36
+ // or, without a declaration, the drafter's own rule: five to eight rows (the
37
+ // 5..8 rows, one block of 8) on the simdgroup matrix unit, every other
38
+ // width on MLX's quantized matmul. The rule's kernels are built at load (fc when
39
+ // the first draft group binds) and the declared ones when it binds. The context
40
+ // projection (fc, then each layer's k and v, over the B × L rows a prefill or a
41
+ // commit appends) and the draft block (B anchors × G columns) are row declarations;
42
+ // the caller indexes them by the rows it projects or drafts.
43
+
44
+ import { MlxArray } from "@mlx-bun/mlx/array";
45
+ import { Dtype } from "@mlx-bun/mlx/ffi";
46
+ import * as ops from "@mlx-bun/mlx/ops";
47
+ import { Weights } from "../../artifacts/weights";
48
+ import type { DraftProjection } from "../../contracts/mlx/draft-projection";
49
+ import type { DraftProjectionKernels, ResidualBasis } from "../../contracts/mlx/draft-target";
50
+ import type {
51
+ ContextKV, Dflash2ContextAttention, Dflash2DraftBlock, Dflash2DrafterModel, DrafterContextKV, DrafterContextProjection, DrafterOperations,
52
+ } from "../../contracts/mlx/drafter";
53
+ import { rowOperationFor } from "../graph";
54
+ import { mapOperations } from "./dflash2-operations";
55
+ import { isDflash2Architecture } from "./dflash2-artifact";
56
+ import { QuantizedLinear, QuantizedLinearPlain } from "../../layers/quantized-linear";
57
+ import { Affine4MmaLinear } from "../../layers/affine-verify-linear";
58
+
59
+ export interface Dflash2Config {
60
+ hidden: number;
61
+ layers: number;
62
+ heads: number;
63
+ kvHeads: number;
64
+ headDim: number;
65
+ eps: number;
66
+ ropeTheta: number;
67
+ blockSize: number;
68
+ maskTokenId: number;
69
+ convGroupSize: number;
70
+ topK: number;
71
+ targetLayerIds: number[];
72
+ numTargetLayers: number;
73
+ }
74
+
75
+ /** One projection on one kernel. */
76
+ interface Projection { forward(x: MlxArray): MlxArray }
77
+
78
+ /** A BF16 projection over its stored transpose. */
79
+ class Bf16Projection implements Projection {
80
+ constructor(readonly t: MlxArray) {}
81
+ forward(x: MlxArray): MlxArray { return ops.matmul(x, this.t); }
82
+ }
83
+
84
+ /** A projection's kernel at each width class of its rows. Built at load on the drafter's own rule (fc when
85
+ * the target binds): a BF16 projection one matmul at every class; a 4-bit one the simdgroup matrix unit at
86
+ * five to eight rows where the weight's shape takes it (N a multiple of 8, K of 256) and MLX's quantized matmul
87
+ * at every other class. A target that declares its composition's kernels rebuilds `at` over `affine4` when it
88
+ * binds. */
89
+ interface Weight {
90
+ at: DrafterOperations<Projection>;
91
+ /** The fixed default of the checkpoint's original range-backed projection. */
92
+ readonly defaultProjection?: Projection;
93
+ /** The 4-bit, group-64 weight a declared kernel builds over; null for any other width. */
94
+ readonly affine4: { readonly w: MlxArray; readonly scales: MlxArray; readonly biases: MlxArray } | null;
95
+ dispose(): void;
96
+ }
97
+
98
+ function bf16Weight(projection: Bf16Projection): Weight {
99
+ return { at: [{from:1,to:Infinity,operation:projection}], defaultProjection: projection, affine4: null, dispose: () => projection.t.dispose() };
100
+ }
101
+ function quantizedWeight(source: MlxArray, bits: number): Weight {
102
+ const q = ops.quantize(source, 64, bits);
103
+ ops.evalAll([q.packed, q.scales, q.biases]);
104
+ const linear = new QuantizedLinear(q.packed, q.scales, q.biases, { bits, groupSize: 64, mode: "affine" });
105
+ const plain = new QuantizedLinearPlain(linear);
106
+ const mma = bits === 4 && q.scales.shape[0]! % 8 === 0 && (q.scales.shape[1]! * 64) % 256 === 0 ? new Affine4MmaLinear(linear) : null;
107
+ return {
108
+ at: [{from:1,to:4,operation:plain},{from:5,to:8,operation:mma ?? plain},{from:9,to:Infinity,operation:plain}],
109
+ defaultProjection: plain,
110
+ affine4: bits === 4 ? { w: q.packed, scales: q.scales, biases: q.biases } : null,
111
+ dispose() { linear.w.dispose(); linear.scales.dispose(); linear.biases!.dispose(); },
112
+ };
113
+ }
114
+
115
+ const DEFAULT_PROJECTION_ROWS=[{from:1,to:4,operation:true},{from:5,to:8,operation:true},{from:9,to:Infinity,operation:true}];
116
+ type LayerProjections=Record<"q"|"k"|"v"|"o"|"gate"|"up"|"down",Projection>;
117
+
118
+ /** R1 sign lane 0 of the rotation fold (packages/quantize/src/rotate.ts signVector). */
119
+ function r1Signs(seed: number, n: number): Float32Array {
120
+ let state = (seed ^ Math.imul(1, 0x9e3779b9)) >>> 0;
121
+ const out = new Float32Array(n);
122
+ for (let i = 0; i < n; i++) {
123
+ state = (state + 0x9e3779b9) >>> 0;
124
+ let z = state;
125
+ z = Math.imul(z ^ (z >>> 16), 0x21f0aaad);
126
+ z = Math.imul(z ^ (z >>> 15), 0x735a2d97);
127
+ z ^= z >>> 15;
128
+ out[i] = (z & 1) === 0 ? 1 : -1;
129
+ }
130
+ return out;
131
+ }
132
+
133
+ interface Layer {
134
+ inNorm: MlxArray; postNorm: MlxArray;
135
+ q: Weight; k: Weight; v: Weight; o: Weight; qNorm: MlxArray; kNorm: MlxArray;
136
+ gate: Weight; up: Weight; down: Weight;
137
+ attnBase: MlxArray; attnProj: Bf16Projection; mlpBase: MlxArray; mlpProj: Bf16Projection;
138
+ }
139
+
140
+ function readConfig(raw: Record<string, any>): Dflash2Config {
141
+ if (!isDflash2Architecture(raw.architectures))
142
+ throw new Error(`Dflash2Drafter: expected architectures[0]==="DFlash2DraftModel", got ${JSON.stringify(raw.architectures)}`);
143
+ const d = raw.dflash_config ?? {};
144
+ if (d.conv_kernel_size !== 2) throw new Error(`Dflash2Drafter: conv_kernel_size ${d.conv_kernel_size} not implemented (two-tap only)`);
145
+ if ((raw.rope_parameters?.rope_type ?? "default") !== "default") throw new Error("Dflash2Drafter: only default RoPE is implemented");
146
+ return {
147
+ hidden: raw.hidden_size, layers: raw.num_hidden_layers, heads: raw.num_attention_heads,
148
+ kvHeads: raw.num_key_value_heads, headDim: raw.head_dim, eps: raw.rms_norm_eps,
149
+ ropeTheta: raw.rope_parameters?.rope_theta ?? raw.rope_theta,
150
+ blockSize: d.block_size, maskTokenId: d.mask_token_id, convGroupSize: d.conv_group_size,
151
+ topK: d.selector_top_k, targetLayerIds: d.target_layer_ids, numTargetLayers: raw.num_target_layers,
152
+ };
153
+ }
154
+
155
+ export class Dflash2Drafter implements Dflash2DrafterModel {
156
+ readonly cfg: Dflash2Config;
157
+ readonly tapLayers: number[];
158
+ /** Draft tokens per block (block size minus the anchor). */
159
+ readonly gamma: number;
160
+ readonly #bits: number;
161
+ #w: Weights | null;
162
+ /** fc in the trained basis, owned until the target binds and fc is built from it. */
163
+ #fcSource: MlxArray | null;
164
+ #fc: Weight | null = null;
165
+ #hiddenNorm: MlxArray;
166
+ #norm: MlxArray;
167
+ #selProj: Bf16Projection;
168
+ #pred: MlxArray;
169
+ #succ: MlxArray;
170
+ #layers: Layer[] = [];
171
+ /** The target declarations bound by the first draft group: undefined until then. */
172
+ #bound: { basis: ResidualBasis | null; projections: DraftProjectionKernels | null } | undefined = undefined;
173
+ /** R1's signs, the folded gain and dense Mᵀ [H, H] (bf16; every entry is ±1/√H) of a bound fold. */
174
+ #rotation: { signs: MlxArray; finalGain: MlxArray; hadamardT: MlxArray } | null = null;
175
+ /** Target-basis rows → drafter basis; identity until a fold binds. */
176
+ #fromTarget: (x: MlxArray) => MlxArray = x => ops.contiguous(x);
177
+ /** Drafter's normed hidden → input of the target's head; identity until a fold binds. */
178
+ #toTargetHead: (v: MlxArray) => MlxArray = v => ops.contiguous(v);
179
+
180
+ private constructor(w: Weights, cfg: Dflash2Config, bits: number) {
181
+ this.#w = w;
182
+ this.cfg = cfg;
183
+ this.#bits = bits;
184
+ this.tapLayers = cfg.targetLayerIds;
185
+ this.gamma = cfg.blockSize - 1;
186
+ const T = (name: string) => w.tensor(name);
187
+ const bf16 = (name: string) => new Bf16Projection(ops.transposeAxes(T(name), [1, 0]));
188
+ // Splash quantizes projections only; convs, norms and codebooks stay BF16.
189
+ const weight = (name: string): Weight => {
190
+ if (!bits) return bf16Weight(bf16(name));
191
+ using source = T(name);
192
+ return quantizedWeight(source, bits);
193
+ };
194
+ this.#fcSource = T("fc.weight");
195
+ this.#hiddenNorm = T("hidden_norm.weight");
196
+ this.#norm = T("norm.weight");
197
+ this.#selProj = bf16("candidate_selector.hidden_projection.weight");
198
+ this.#pred = T("candidate_selector.predecessor_codebook");
199
+ this.#succ = T("candidate_selector.successor_codebook");
200
+ for (let i = 0; i < cfg.layers; i++) {
201
+ const p = `layers.${i}`;
202
+ this.#layers.push({
203
+ inNorm: T(`${p}.input_layernorm.weight`), postNorm: T(`${p}.post_attention_layernorm.weight`),
204
+ q: weight(`${p}.self_attn.q_proj.weight`), k: weight(`${p}.self_attn.k_proj.weight`),
205
+ v: weight(`${p}.self_attn.v_proj.weight`), o: weight(`${p}.self_attn.o_proj.weight`),
206
+ qNorm: T(`${p}.self_attn.q_norm.weight`), kNorm: T(`${p}.self_attn.k_norm.weight`),
207
+ gate: weight(`${p}.mlp.gate_proj.weight`), up: weight(`${p}.mlp.up_proj.weight`),
208
+ down: weight(`${p}.mlp.down_proj.weight`),
209
+ attnBase: this.#baseKernel(T(`${p}.attention_conv.base_kernel`)),
210
+ attnProj: bf16(`${p}.attention_conv.kernel_projection.weight`),
211
+ mlpBase: this.#baseKernel(T(`${p}.mlp_conv.base_kernel`)),
212
+ mlpProj: bf16(`${p}.mlp_conv.kernel_projection.weight`),
213
+ });
214
+ }
215
+ if (bits) this.#releaseCheckpoint();
216
+ }
217
+
218
+ /** Quantized projections own their storage; copy the remaining BF16 tensors
219
+ * (fc's source among them) out of the checkpoint map so its 3.85 GB mapping
220
+ * can be released. */
221
+ #releaseCheckpoint(): void {
222
+ const own = (a: MlxArray): MlxArray => {
223
+ const copy = a.dtype === Dtype.float32 ? ops.contiguous(a) : ops.mulScalar(a, 1);
224
+ copy.eval(); a.dispose(); return copy;
225
+ };
226
+ const ownBf16 = (m: Bf16Projection): Bf16Projection => {
227
+ const t = ops.contiguous(m.t); // materializes the transposed view
228
+ t.eval(); m.t.dispose(); return new Bf16Projection(t);
229
+ };
230
+ this.#fcSource = own(this.#fcSource!);
231
+ this.#hiddenNorm = own(this.#hiddenNorm); this.#norm = own(this.#norm);
232
+ this.#pred = own(this.#pred); this.#succ = own(this.#succ); this.#selProj = ownBf16(this.#selProj);
233
+ for (const l of this.#layers) {
234
+ l.inNorm = own(l.inNorm); l.postNorm = own(l.postNorm); l.qNorm = own(l.qNorm); l.kNorm = own(l.kNorm);
235
+ l.attnBase = own(l.attnBase); l.mlpBase = own(l.mlpBase);
236
+ l.attnProj = ownBf16(l.attnProj); l.mlpProj = ownBf16(l.mlpProj);
237
+ }
238
+ const w = this.#w!;
239
+ w.dispose();
240
+ for (const file of w.shards.files.values()) file.mmap.unmap();
241
+ this.#w = null;
242
+ }
243
+
244
+ /** fc acting on target-basis taps: per tap block, fc_k·diag(s)·M (f32 fold). Consumes `source`. */
245
+ #foldedFc(source: MlxArray, signs: Float32Array, bits: number): Weight {
246
+ const H = this.cfg.hidden, m = this.cfg.targetLayerIds.length;
247
+ using s = MlxArray.fromFloat32(signs, [H]);
248
+ using f = source.astype(Dtype.float32);
249
+ source.dispose();
250
+ using blocks = ops.reshape(f, [H, m, H]);
251
+ using signed = ops.mul(blocks, s);
252
+ using rotated = ops.hadamardTransform(signed, 1 / Math.sqrt(H));
253
+ using flat = ops.reshape(rotated, [H, m * H]);
254
+ using folded = flat.astype(Dtype.bfloat16);
255
+ if (!bits) {
256
+ const t = ops.transposeAxes(folded, [1, 0]);
257
+ t.eval();
258
+ return bf16Weight(new Bf16Projection(t));
259
+ }
260
+ return quantizedWeight(folded, bits);
261
+ }
262
+
263
+ /** `dir`: the drafter checkpoint, loaded in the basis it was trained on.
264
+ * `bits`: the projections' quantized width; 0 keeps BF16 projections. */
265
+ static async load(dir: string, opts: { bits: number }): Promise<Dflash2Drafter> {
266
+ const raw = (await Bun.file(`${dir}/config.json`).json()) as Record<string, any>;
267
+ const cfg = readConfig(raw);
268
+ const w = await Weights.open(dir);
269
+ try { return new Dflash2Drafter(w, cfg, opts.bits); }
270
+ catch (error) { w.dispose(); throw error; }
271
+ }
272
+
273
+ /** Build fc for the target's basis and, for a fold, the rotations at the
274
+ * embedding and the head; then, where the target declares its composition's
275
+ * kernels, every 4-bit projection's kernel per row count or range from them. The
276
+ * first call applies; later calls (every draft group binds) must pass the
277
+ * same declarations. */
278
+ bindTarget(basis: ResidualBasis | null, projections: DraftProjectionKernels | null): void {
279
+ if (this.#bound !== undefined) {
280
+ if (this.#bound.basis !== basis) throw new Error("this DFlash 2 drafter is bound to a target with a different residual basis");
281
+ if (this.#bound.projections !== projections) throw new Error("this DFlash 2 drafter is bound to a target with different projection kernels");
282
+ return;
283
+ }
284
+ this.#bindBasis(basis);
285
+ if (projections) for (const weight of [this.#fc!, ...this.#layers.flatMap(l => [l.q, l.k, l.v, l.o, l.gate, l.up, l.down])]) {
286
+ if (!weight.affine4) continue;
287
+ const { w, scales, biases } = weight.affine4;
288
+ weight.at = mapOperations(projections, kernel=>({forward:kernel(w,scales,biases)}));
289
+ }
290
+ this.#bindOperations(projections ?? DEFAULT_PROJECTION_ROWS);
291
+ this.#bound = { basis, projections };
292
+ }
293
+
294
+ #bindBasis(basis: ResidualBasis | null): void {
295
+ const source = this.#fcSource!;
296
+ this.#fcSource = null;
297
+ if (!basis) {
298
+ if (this.#bits) {
299
+ using unrotated = source;
300
+ this.#fc = quantizedWeight(unrotated, this.#bits);
301
+ } else {
302
+ this.#fc = bf16Weight(new Bf16Projection(ops.transposeAxes(source, [1, 0])));
303
+ source.dispose();
304
+ }
305
+ return;
306
+ }
307
+ const H = this.cfg.hidden;
308
+ const signs = r1Signs(basis.r1Seed, H);
309
+ this.#fc = this.#foldedFc(source, signs, this.#bits);
310
+ const eye = new Float32Array(H * H);
311
+ for (let i = 0; i < H; i++) eye[i * H + i] = 1;
312
+ using identity = MlxArray.fromFloat32(eye, [H, H]);
313
+ using dense = ops.hadamardTransform(identity, 1 / Math.sqrt(H)); // rows e_i·M
314
+ using transposed = ops.transposeAxes(dense, [1, 0]);
315
+ using contiguous = ops.contiguous(transposed);
316
+ const hadamardT = contiguous.astype(Dtype.bfloat16);
317
+ hadamardT.eval();
318
+ const rotation = this.#rotation = {
319
+ signs: MlxArray.fromFloat32(signs, [H]), finalGain: MlxArray.fromFloat32(basis.finalGain, [H]), hadamardT,
320
+ };
321
+ // x·R1ᵀ = (x·Mᵀ)⊙s over the last axis (target basis → drafter basis).
322
+ this.#fromTarget = x => {
323
+ using h = ops.matmul(x.dtype === Dtype.bfloat16 ? x : x.astype(Dtype.bfloat16), rotation.hadamardT);
324
+ using back = ops.mul(h, rotation.signs);
325
+ return back.astype(x.dtype);
326
+ };
327
+ // (v/γ)·R1 (drafter's normed hidden → input of the target's folded head).
328
+ this.#toTargetHead = v => {
329
+ const n = v.shape[v.shape.length - 1]!;
330
+ using f = v.astype(Dtype.float32);
331
+ using unscaled = ops.div(f, rotation.finalGain);
332
+ using signed = ops.mul(unscaled, rotation.signs);
333
+ using h = ops.hadamardTransform(signed, 1 / Math.sqrt(n));
334
+ return h.astype(v.dtype);
335
+ };
336
+ }
337
+
338
+ /** [stage, tap, H] base kernel as f32 [1, 1, stage, tap, H] for broadcasting. */
339
+ #baseKernel(source: MlxArray): MlxArray {
340
+ using f = source.astype(Dtype.float32);
341
+ source.dispose();
342
+ return ops.reshape(f, [1, 1, 2, 2, this.cfg.hidden]);
343
+ }
344
+
345
+ #rms(x: MlxArray, weight: MlxArray): MlxArray { return ops.rmsNorm(x, weight, this.cfg.eps); }
346
+
347
+ /** Per-row dynamic coefficients [B,G,stage,tap,H] (f32) for one conv site. */
348
+ #coefficients(n: MlxArray, proj: Bf16Projection, base: MlxArray): MlxArray {
349
+ const B = n.shape[0]!, G = n.shape[1]!, H = this.cfg.hidden, groups = H / this.cfg.convGroupSize;
350
+ using d = proj.forward(n);
351
+ using d32 = d.astype(Dtype.float32);
352
+ using grouped = ops.reshape(d32, [B, G, 2, 2, groups, 1]);
353
+ using wide = ops.broadcastTo(grouped, [B, G, 2, 2, groups, this.cfg.convGroupSize]);
354
+ using perChannel = ops.reshape(wide, [B, G, 2, 2, H]);
355
+ return ops.add(perChannel, base);
356
+ }
357
+
358
+ /** Two-tap conv of y [B,G,H] with stage `stage` of coef; f32 result. */
359
+ #conv(y: MlxArray, coef: MlxArray, stage: number): MlxArray {
360
+ const B = y.shape[0]!, G = y.shape[1]!, H = this.cfg.hidden;
361
+ using c0 = coef.slice([0, 0, stage, 0, 0], [B, G, stage + 1, 1, H]);
362
+ using c1 = coef.slice([0, 0, stage, 1, 0], [B, G, stage + 1, 2, H]);
363
+ using t0 = ops.reshape(c0, [B, G, H]);
364
+ using t1 = ops.reshape(c1, [B, G, H]);
365
+ using y32 = y.astype(Dtype.float32);
366
+ using head = ops.zeros([B, 1, H], Dtype.float32);
367
+ using body = y32.slice([0, 0, 0], [B, G - 1, H]);
368
+ using prev = ops.concatAxis([head, body], 1);
369
+ using a = ops.mul(t0, y32);
370
+ using b = ops.mul(t1, prev);
371
+ return ops.add(a, b);
372
+ }
373
+
374
+ #rope(x: MlxArray, position: number | MlxArray): MlxArray {
375
+ return typeof position === "number"
376
+ ? ops.rope(x, this.cfg.headDim, this.cfg.ropeTheta, position, null)
377
+ : ops.ropeDynamic(x, this.cfg.headDim, this.cfg.ropeTheta, position, null);
378
+ }
379
+
380
+ /** Each context operation is fixed when the target's declarations bind. */
381
+ projectContext!: DrafterOperations<DrafterContextProjection>;
382
+ projectContextKVRows!: DrafterOperations<DrafterContextKV>;
383
+ draft!: DrafterOperations<Dflash2DraftBlock>;
384
+
385
+ #bindOperations(rows: DrafterOperations<unknown>): void {
386
+ type Binding = { fc: Projection; layers: LayerProjections[] };
387
+ const bind = (projection: (weight: Weight) => Projection): Binding => ({
388
+ fc: projection(this.#fc!),
389
+ layers: this.#layers.map(layer => ({
390
+ q: projection(layer.q), k: projection(layer.k), v: projection(layer.v), o: projection(layer.o),
391
+ gate: projection(layer.gate), up: projection(layer.up), down: projection(layer.down),
392
+ })),
393
+ });
394
+ const at = (row: number) => bind(weight => rowOperationFor(weight.at, row));
395
+ const defaults = () => bind(weight => {
396
+ const operation = Array.isArray(weight.at) ? Object.hasOwn(weight, "defaultProjection") ? weight.defaultProjection : undefined
397
+ : Object.hasOwn(weight.at, "default") ? (weight.at as MlxRowTable<Projection>).default : undefined;
398
+ if (operation === undefined) throw new Error("DFlash2 projection has no declared default operation");
399
+ return operation;
400
+ });
401
+ let bindings: DrafterOperations<Binding>;
402
+ if (Array.isArray(rows)) {
403
+ bindings = Object.freeze(rows.map(range => Object.freeze({
404
+ from: range.from, to: range.to, operation: at(range.from),
405
+ })));
406
+ } else {
407
+ const source = rows as MlxRowTable<unknown>, exact: Partial<Record<number, Binding>> & { default?: Binding } = {};
408
+ for (const [key, operation] of Object.entries(source)) {
409
+ const row = Number(key);
410
+ if (operation !== undefined && Number.isSafeInteger(row) && row > 0 && String(row) === key) exact[row] = at(row);
411
+ }
412
+ if (Object.hasOwn(source, "default") && source.default !== undefined) exact.default = defaults();
413
+ bindings = Object.freeze(exact);
414
+ }
415
+ this.projectContext = mapOperations(bindings, fixed => (taps: MlxArray) => {
416
+ using projected = fixed.fc.forward(taps);
417
+ return this.#rms(projected, this.#hiddenNorm);
418
+ });
419
+ this.projectContextKVRows = mapOperations(bindings, fixed =>
420
+ (context: MlxArray, position: number | MlxArray) => this.#contextKV(context, position, fixed.layers));
421
+ this.draft = mapOperations(bindings, fixed =>
422
+ (context: Dflash2ContextAttention, projection: DraftProjection, anchors: readonly number[], position: number | MlxArray, columns: number) =>
423
+ this.#block(context, projection, anchors, position, columns, fixed.layers));
424
+ }
425
+
426
+ #contextKV(context: MlxArray, position: number | MlxArray, fixed: readonly LayerProjections[]): ContextKV[] {
427
+ const B = context.shape[0]!, L = context.shape[1]!, { kvHeads, headDim } = this.cfg;
428
+ return this.#layers.map((layer,index) => {
429
+ using kFlat = fixed[index]!.k.forward(context);
430
+ using k4 = ops.reshape(kFlat, [B, L, kvHeads, headDim]);
431
+ using kn = this.#rms(k4, layer.kNorm);
432
+ using kT = ops.transposeAxes(kn, [0, 2, 1, 3]);
433
+ using vFlat = fixed[index]!.v.forward(context);
434
+ using v4 = ops.reshape(vFlat, [B, L, kvHeads, headDim]);
435
+ return { k: this.#rope(kT, position), v: ops.transposeAxes(v4, [0, 2, 1, 3]) };
436
+ });
437
+ }
438
+
439
+ /** The columns of a block drafting `depth` tokens: the anchor and up to `depth` (≤ gamma) mask positions. */
440
+ blockColumns(depth: number): number { return Math.min(this.cfg.blockSize, Math.max(1, depth) + 1); }
441
+
442
+ /** One block per anchor over `columns` positions, every projection on its kernel for `width`: the proposals left on the
443
+ * device, [B, columns - 1] uint32, row-major. */
444
+ #block(context: Dflash2ContextAttention, projection: DraftProjection, anchors: readonly number[],
445
+ position: number | MlxArray, columns: number, fixed: readonly LayerProjections[]): MlxArray {
446
+ const B = anchors.length, G = columns;
447
+ const { hidden: H, heads, kvHeads, headDim } = this.cfg;
448
+ using ids = ops.fromInt32(anchors.flatMap(anchor => [anchor, ...Array(G - 1).fill(this.cfg.maskTokenId)]), [B, G]);
449
+ using embedded = projection.embed.encode(ids);
450
+ let x = this.#fromTarget(embedded);
451
+ try {
452
+ for (const [li, layer] of this.#layers.entries()) {
453
+ {
454
+ using n = this.#rms(x, layer.inNorm);
455
+ using coef = this.#coefficients(n, layer.attnProj, layer.attnBase);
456
+ using a32 = this.#conv(n, coef, 0);
457
+ using a = a32.astype(x.dtype);
458
+ using qFlat = fixed[li]!.q.forward(a);
459
+ using q4 = ops.reshape(qFlat, [B, G, heads, headDim]);
460
+ using qn = this.#rms(q4, layer.qNorm);
461
+ using qT = ops.transposeAxes(qn, [0, 2, 1, 3]);
462
+ using q = this.#rope(qT, position);
463
+ using kFlat = fixed[li]!.k.forward(a);
464
+ using k4 = ops.reshape(kFlat, [B, G, kvHeads, headDim]);
465
+ using kn = this.#rms(k4, layer.kNorm);
466
+ using kT = ops.transposeAxes(kn, [0, 2, 1, 3]);
467
+ using k = this.#rope(kT, position);
468
+ using vFlat = fixed[li]!.v.forward(a);
469
+ using v4 = ops.reshape(vFlat, [B, G, kvHeads, headDim]);
470
+ using v = ops.transposeAxes(v4, [0, 2, 1, 3]);
471
+ using attn = context.attend(li, q, k, v, 1 / Math.sqrt(headDim));
472
+ using attnT = ops.transposeAxes(attn, [0, 2, 1, 3]);
473
+ using attnFlat = ops.reshape(attnT, [B, G, heads * headDim]);
474
+ using out = fixed[li]!.o.forward(attnFlat);
475
+ using finished = this.#conv(out, coef, 1);
476
+ using x32 = x.astype(Dtype.float32);
477
+ using sum = ops.add(x32, finished);
478
+ x.dispose();
479
+ x = sum.astype(embedded.dtype);
480
+ }
481
+ {
482
+ using m = this.#rms(x, layer.postNorm);
483
+ using coef = this.#coefficients(m, layer.mlpProj, layer.mlpBase);
484
+ using inner32 = this.#conv(m, coef, 0);
485
+ using inner = inner32.astype(x.dtype);
486
+ using g = fixed[li]!.gate.forward(inner);
487
+ using u = fixed[li]!.up.forward(inner);
488
+ using act = ops.silu(g);
489
+ using prod = ops.mul(act, u);
490
+ using mlp = fixed[li]!.down.forward(prod);
491
+ using finished = this.#conv(mlp, coef, 1);
492
+ using x32 = x.astype(Dtype.float32);
493
+ using sum = ops.add(x32, finished);
494
+ x.dispose();
495
+ x = sum.astype(embedded.dtype);
496
+ }
497
+ }
498
+ using rows = x.slice([0, 1, 0], [B, G, H]);
499
+ using h = this.#rms(rows, this.#norm);
500
+ using headInput = this.#toTargetHead(h);
501
+ // A target that declares its draft vocabulary is projected onto those rows only (its candidates their ids).
502
+ const listed = projection.vocabulary;
503
+ using logits = rowOperationFor(listed?.logits ?? projection.logits,B * (G - 1))(headInput);
504
+ using z = this.#selProj.forward(h);
505
+ using columns = this.#select(logits, z, anchors, G - 1, listed?.ids ?? null); // [steps, B]
506
+ using rowsMajor = ops.transposeAxes(columns, [1, 0]);
507
+ return ops.contiguous(rowsMajor);
508
+ } finally { x.dispose(); }
509
+ }
510
+
511
+ /** Greedy candidate-path walk (fp32 scores, as vLLM requires). Every position's top-K candidates and their
512
+ * scores come from one partition over all positions (each row partitions alone, as one position's would);
513
+ * only the path term walks position by position. `ids` (uint32 [N]) maps the columns of logits over a draft
514
+ * vocabulary to token ids; null: the columns are the token ids. */
515
+ #select(logits: MlxArray, z: MlxArray, anchors: readonly number[], steps: number, ids: MlxArray | null): MlxArray {
516
+ const B = anchors.length, R = z.shape[2]!, K = this.cfg.topK;
517
+ const tokens: MlxArray[] = [];
518
+ using scoresAll = logits.astype(Dtype.float32);
519
+ using negatedAll = ops.mulScalar(scoresAll, -1);
520
+ using orderAll = ops.argpartitionAxis(negatedAll, K - 1, -1);
521
+ using localAll = orderAll.slice([0, 0, 0], [B, steps, K]);
522
+ using unaryAll = ops.takeAlongAxis(scoresAll, localAll, -1); // [B, steps, K]
523
+ using listedAll = ids ? ops.takeAxis(ids, localAll, 0) : null; // their token ids over a draft vocabulary
524
+ const candidateAll = listedAll ?? localAll;
525
+ using anchorIds = ops.fromInt32([...anchors], [B]);
526
+ let previous = anchorIds.astype(Dtype.uint32);
527
+ try {
528
+ for (let p = 0; p < steps; p++) {
529
+ using localRow = candidateAll.slice([0, p, 0], [B, p + 1, K]);
530
+ using local = ops.reshape(localRow, [B, K]);
531
+ using unaryRow = unaryAll.slice([0, p, 0], [B, p + 1, K]);
532
+ using unary = ops.reshape(unaryRow, [B, K]);
533
+ const candidates = local;
534
+ using zRow = z.slice([0, p, 0], [B, p + 1, R]);
535
+ using zFlat = ops.reshape(zRow, [B, R]);
536
+ using z32 = zFlat.astype(Dtype.float32);
537
+ using predRows = ops.takeAxis(this.#pred, previous, 0);
538
+ using pred32 = predRows.astype(Dtype.float32);
539
+ using weighted = ops.mul(pred32, z32);
540
+ using column = ops.reshape(weighted, [B, R, 1]);
541
+ using candidateFlat = ops.reshape(candidates, [B * K]);
542
+ using succRows = ops.takeAxis(this.#succ, candidateFlat, 0);
543
+ using succ32 = succRows.astype(Dtype.float32);
544
+ using succ3 = ops.reshape(succ32, [B, K, R]);
545
+ using edge3 = ops.matmul(succ3, column);
546
+ using edge = ops.reshape(edge3, [B, K]);
547
+ using total = ops.add(unary, edge);
548
+ using best = ops.argmaxAxis(total, -1);
549
+ using bestCol = ops.reshape(best, [B, 1]);
550
+ using chosen = ops.takeAlongAxis(candidates, bestCol, -1);
551
+ const token = ops.reshape(chosen, [1, B]);
552
+ tokens.push(token);
553
+ previous.dispose();
554
+ using flatToken = ops.reshape(token, [B]);
555
+ previous = flatToken.astype(Dtype.uint32);
556
+ }
557
+ return ops.concatAxis(tokens, 0);
558
+ } finally {
559
+ previous.dispose();
560
+ for (const token of tokens) token.dispose();
561
+ }
562
+ }
563
+
564
+ dispose(): void {
565
+ this.#fc?.dispose(); this.#fcSource?.dispose(); this.#selProj.t.dispose();
566
+ this.#hiddenNorm.dispose(); this.#norm.dispose(); this.#pred.dispose(); this.#succ.dispose();
567
+ for (const l of this.#layers) {
568
+ l.inNorm.dispose(); l.postNorm.dispose(); l.qNorm.dispose(); l.kNorm.dispose();
569
+ for (const m of [l.q, l.k, l.v, l.o, l.gate, l.up, l.down]) m.dispose();
570
+ l.attnProj.t.dispose(); l.mlpProj.t.dispose();
571
+ l.attnBase.dispose(); l.mlpBase.dispose();
572
+ }
573
+ if (this.#rotation) { this.#rotation.signs.dispose(); this.#rotation.finalGain.dispose(); this.#rotation.hadamardT.dispose(); }
574
+ this.#w?.dispose();
575
+ }
576
+ }
@@ -0,0 +1,29 @@
1
+ // Central DSpark checkpoint loader — the variant dispatch the modules never
2
+ // had (scripts imported their class directly; the serve path needs one entry
3
+ // point). Reads dspark.json and returns the matching drafter:
4
+ // variant "dspark" — the faithful KV-injection module (canonical)
5
+ // variant "dflash" (legacy) — same module, pre-rename stamp
6
+ // variant absent — a v1 single-vector checkpoint (its module is
7
+ // deleted; superseded research baseline) — refused.
8
+
9
+ import { readFileSync, existsSync } from "node:fs";
10
+ import { join } from "node:path";
11
+ import { DflashDrafter } from "./dflash";
12
+
13
+ // The drafter's producer (`@mlx-bun/training/dspark`) builds, trains and saves
14
+ // this module through this file, published as `@mlx-bun/inference/generation/speculative/loader`.
15
+ // It is the drafter-producer contract (listed with the graph contracts in the
16
+ // architecture test); serving reaches the drafter through `models/drafters`.
17
+ export { DflashDrafter, DEFAULT_DFLASH_CONFIG } from "./dflash";
18
+ export type { DflashConfig, DflashTrainOut, StsCalibration, TargetDims } from "./dflash";
19
+
20
+ export function loadDsparkDrafter(dir: string): DflashDrafter {
21
+ const metaPath = join(dir, "dspark.json");
22
+ if (!existsSync(metaPath)) throw new Error(`no dspark.json in ${dir} — not a DSpark checkpoint`);
23
+ const meta = JSON.parse(readFileSync(metaPath, "utf8")) as { variant?: string };
24
+ if (meta.variant === "dspark" || meta.variant === "dflash") return DflashDrafter.load(dir);
25
+ throw new Error(
26
+ `${dir} is a v1 single-vector DSpark checkpoint (variant=${meta.variant ?? "none"}) — ` +
27
+ `superseded, not serveable; retrain it as a v2 (KV-injection) checkpoint`,
28
+ );
29
+ }