@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,165 @@
1
+ // NgramProvider — MODEL-FREE prompt-lookup speculative drafting behind the
2
+ // grouped draft rows (packages/inference/src/generation/speculative/source.ts).
3
+ // No weights, no caches, no tokenizer:
4
+ // drafts are copied from the request's own token stream. When the trailing
5
+ // k-gram of (prompt + emitted-so-far) has occurred earlier in that stream,
6
+ // the tokens that followed the earlier occurrence are proposed as the draft;
7
+ // the shared speculative group makes the result LOSSLESS by construction
8
+ // (drafts are only proposals — the target's own samples decide every emitted
9
+ // token, at any temperature; only the acceptance rate moves). Best case:
10
+ // agentic/RAG/code-edit traffic that re-emits spans already present in context.
11
+ //
12
+ // Prior art (ported, not invented): "Prompt Lookup Decoding" (Apoorv Saxena,
13
+ // github.com/apoorvumang/prompt-lookup-decoding) and vLLM's `ngram` proposer
14
+ // (vllm/v1 spec_decode ngram_proposer) — both match the LONGEST k-gram first
15
+ // (k = max..min) and take the FIRST occurrence scanning left-to-right; we
16
+ // follow that exactly. Defaults mirror Saxena (max_ngram_size=3,
17
+ // num_pred_tokens=10 → our --num-draft-tokens default for this kind).
18
+ //
19
+ // Token history: each row keeps the committed stream it has seen. Prefill
20
+ // appends the target's prompt chunks (to len-1 under the tail-split shape, the
21
+ // last prompt token being the first round's pending token); draft appends the
22
+ // row's pending token, then looks up; commit appends the accepted drafts.
23
+ // Invariant at matching time: history == prompt + every emitted token, ending
24
+ // at the pending token. A round with no match drafts nothing, which the group
25
+ // verifies as one plain target step, so ngram speculation is structurally never
26
+ // worse than plain decode by more than the host lookup and verification overhead.
27
+
28
+ import type { MlxArray } from "@mlx-bun/mlx/array";
29
+ import * as ops from "@mlx-bun/mlx/ops";
30
+ import type { CheckpointAttachment } from "../../../contracts/mlx/checkpoint";
31
+ import type { DraftProvider, DraftRowGroup, DraftPrefillGroup, GroupedDraftProvider, DraftRowConstraints } from "../source";
32
+ import type { DraftRowCheckpoint } from "../../../contracts/mlx/draft-checkpoint";
33
+ import { applyStateChanges } from "../../../runtime/resources";
34
+
35
+ // Histories are append-only between prefill/restore replacements. Weak keys
36
+ // release derived indexes with retired rows; checkpoints still contain tokens
37
+ // only. Ordered positions preserve the original first-occurrence policy.
38
+ const ngramPositions = new WeakMap<readonly number[], { length: number; positions: Map<number, number[]> }>();
39
+ function proposeNgram(h: readonly number[], max: number, min: number, n: number): number[] {
40
+ let index = ngramPositions.get(h);
41
+ if (!index || h.length < index.length) {
42
+ index = { length: 0, positions: new Map() };
43
+ ngramPositions.set(h, index);
44
+ }
45
+ for (let i = index.length; i < h.length; i++) {
46
+ const token = h[i]!;
47
+ const positions = index.positions.get(token);
48
+ if (positions) positions.push(i); else index.positions.set(token, [i]);
49
+ }
50
+ index.length = h.length;
51
+ const L = h.length;
52
+ for (let k = Math.min(max, L - 1); k >= min; k--) {
53
+ const tailAt = L - k;
54
+ const positions = index.positions.get(h[tailAt]!) ?? [];
55
+ search: for (const i of positions) {
56
+ if (i + k >= L) break;
57
+ for (let j = 0; j < k; j++) if (h[i + j] !== h[tailAt + j]) continue search;
58
+ return h.slice(i + k, i + k + n);
59
+ }
60
+ }
61
+ return [];
62
+ }
63
+
64
+ const namespace = (max: number, min: number) => `ngram-history-v1:${max}:${min}`;
65
+ const captureHistory = (history: readonly number[], max: number, min: number): CheckpointAttachment => ({
66
+ schema: "ngram-history-v1", metadata: { max, min }, tensors: [ops.fromInt32([...history], [history.length])],
67
+ });
68
+ function restoreHistory(state: DraftRowCheckpoint, max: number, min: number): number[] {
69
+ const { attachment, processedTokens } = state;
70
+ if (attachment.schema !== "ngram-history-v1" || attachment.metadata.max !== max || attachment.metadata.min !== min ||
71
+ attachment.tensors.length !== 1 || attachment.tensors[0]!.shape.length !== 1 || attachment.tensors[0]!.shape[0] !== processedTokens)
72
+ throw new Error("ngram checkpoint does not match its token coverage or lookup policy");
73
+ return attachment.tensors[0]!.toIntTokens();
74
+ }
75
+
76
+ /** Each row owns only its committed token history. Verification and sampling
77
+ * remain in the shared method; target storage and scheduling are not needed. */
78
+ class NgramRows implements DraftRowGroup, DraftPrefillGroup {
79
+ readonly prefillMode = "tail-split" as const;
80
+ readonly tapLayers: readonly number[] = [];
81
+ readonly namespace: string;
82
+ #histories: number[][] = [];
83
+ #drafts: number[][] = [];
84
+ constructor(readonly max: number, readonly min: number, checkpoints: readonly (DraftRowCheckpoint | null)[],
85
+ readonly constraints?: DraftRowConstraints) {
86
+ this.namespace = namespace(max, min);
87
+ this.append(checkpoints);
88
+ }
89
+ get rowCount() { return this.#histories.length; }
90
+ prepareAppend(checkpoints: readonly (DraftRowCheckpoint | null)[]) {
91
+ let next = [...this.#histories, ...checkpoints.map(state => state ? restoreHistory(state, this.max, this.min) : [])];
92
+ return { commit: () => { const old = this.#histories; this.#histories = next; next = old; }, dispose: () => { next = []; } };
93
+ }
94
+ append(checkpoints: readonly (DraftRowCheckpoint | null)[]) { applyStateChanges([() => this.prepareAppend(checkpoints)]); }
95
+ filterRows(keep: readonly number[]) { this.#histories = keep.map(row => this.#histories[row]!); this.#drafts = []; }
96
+ prefill(tokens: MlxArray): void {
97
+ using packed = ops.contiguous(tokens);
98
+ const ids = packed.toIntTokens(), length = tokens.shape[1]!;
99
+ for (let row = 0; row < this.rowCount; row++) this.#histories[row]!.push(...ids.slice(row * length, (row + 1) * length));
100
+ }
101
+ materialize(): void {}
102
+ draft(pending: readonly number[], depth: number): number[][] | Promise<number[][]> {
103
+ if (this.constraints) {
104
+ for (const [row, history] of this.#histories.entries()) history.push(pending[row]!);
105
+ return Promise.all(this.#histories.map((_, row) => this.constraints!.propose(row, depth)))
106
+ .then(proposals => this.#drafts = proposals);
107
+ }
108
+ this.#drafts = this.#histories.map((history, row) => {
109
+ history.push(pending[row]!);
110
+ return proposeNgram(history, this.max, this.min, depth);
111
+ });
112
+ return this.#drafts;
113
+ }
114
+ commit(accepted: readonly number[]) {
115
+ for (let row = 0; row < this.rowCount; row++) this.#histories[row]!.push(...this.#drafts[row]!.slice(0, accepted[row]!));
116
+ this.#drafts = [];
117
+ }
118
+ capture(row: number): DraftRowCheckpoint {
119
+ const history = this.#histories[row]!;
120
+ return { processedTokens: history.length, attachment: captureHistory(history, this.max, this.min) };
121
+ }
122
+ dispose() { this.#histories = []; this.#drafts = []; }
123
+ }
124
+
125
+ export interface NgramOptions {
126
+ /** Longest suffix k-gram tried first (Saxena max_ngram_size). */
127
+ max?: number;
128
+ /** Shortest k-gram tried before giving up (vLLM prompt_lookup_min). */
129
+ min?: number;
130
+ }
131
+
132
+ export class NgramProvider implements DraftProvider {
133
+ readonly id = "ngram";
134
+ readonly weightsBytes = 0;
135
+ readonly max: number;
136
+ readonly min: number;
137
+ readonly grouped: GroupedDraftProvider = {
138
+ checkpointNamespace: () => namespace(this.max, this.min),
139
+ supportsTargetAdapters: true,
140
+ open: options => new NgramRows(this.max, this.min, options.checkpoints),
141
+ openPrefill: options => new NgramRows(this.max, this.min, options.checkpoints),
142
+ };
143
+
144
+ constructor(opts: NgramOptions = {}) {
145
+ this.max = Math.max(1, opts.max ?? 3);
146
+ this.min = Math.max(1, Math.min(opts.min ?? 1, this.max));
147
+ }
148
+
149
+ dispose(): void {}
150
+ }
151
+
152
+ /** Constraint candidates share committed-history ownership with prompt lookup.
153
+ * They never perform ngram lookup. */
154
+ export function constraintDraftProvider(): { id: string; grouped: GroupedDraftProvider } {
155
+ return {
156
+ id: "grammar",
157
+ grouped: {
158
+ checkpointNamespace: () => namespace(3, 1),
159
+ supportsTargetAdapters: true,
160
+ openPrefill: options => new NgramRows(3, 1, options.checkpoints),
161
+ open: options => new NgramRows(3, 1, options.checkpoints,
162
+ options.constraints ?? { propose: async () => [] }),
163
+ },
164
+ };
165
+ }
@@ -0,0 +1,154 @@
1
+ // Native Qwen3.8 MTP draft provider — the Qwen-TRAINED multi-step prediction
2
+ // head, split from the raw release's last shard and published as
3
+ // mlx-community/Qwen3.8-27B-MTP-* (model_type "qwen3_5_mtp", block_size 3).
4
+ //
5
+ // Reference implementation (locate + port + gate, don't design):
6
+ // mlx_vlm/speculative/drafters/qwen3_5_mtp/qwen3_5_mtp.py. Mechanism, per
7
+ // step: h = fc(concat(rms_emb(embed(token)), rms_hidden(hidden))) → ONE
8
+ // full-attention decoder layer (own KVCache, positions continue the target
9
+ // sequence) → norm → the TARGET's lm_head → next draft token; recursive for
10
+ // the block ("trained with multiple steps"). The drafter is NOT standalone:
11
+ // it binds the target's embed_tokens + lm_head (mtp_use_dedicated_embeddings
12
+ // false) and consumes the target's PRE-final-norm last-layer hidden (mlx-vlm
13
+ // captures it with skip_final_norm=True) — carried here by the provider's tap
14
+ // layer, NOT the target's post-norm output.
15
+ //
16
+ // Row convention (predict-2-ahead): drafter KV row at position p is built
17
+ // from (embed(token at position p+1), hidden at position p). Invariant
18
+ // across rounds: after commit, the drafter offset equals the next pending
19
+ // token's position minus zero — i.e. a draft always opens by building the
20
+ // pending token's row from the TARGET's TRUE hidden at the emitted position
21
+ // (held over from the verify tap). Computationally identical to mlx-vlm's
22
+ // commit-time "seed" append, just performed at the top of the next round.
23
+ //
24
+ // Companion projections may be dense or quantized according to their metadata.
25
+ // Published drafter norms are already sanitized to runtime layout; no +1.0 shift.
26
+
27
+ import { loadModelConfig, type ModelConfig } from "../../../artifacts/config";
28
+ import { Weights } from "../../../artifacts/weights";
29
+ import type { RecurrentMtpModule } from "../../../contracts/mlx/drafter";
30
+ import { DRAFT_CHECKPOINT_SCHEMA } from "../../../contracts/mlx/draft-checkpoint";
31
+ import { loadQwenMtpModule } from "../../../models/drafter-loaders";
32
+ import type { DraftProvider, DraftRowGroup, DraftPrefillGroup, DraftRowSampling, GroupedDraftProvider, RecurrentMtpTarget, TargetView } from "../source";
33
+ import { targetLacks } from "../source";
34
+ import type { DraftRowCheckpoint } from "../../../contracts/mlx/draft-checkpoint";
35
+ import { QwenMtpRows } from "../bindings/qwen-mtp-rows";
36
+ import { configuredDraftVocabulary } from "../draft-vocab";
37
+ import { type MtpRowState } from "../../../state/speculative/qwen-mtp-state";
38
+ import { captureQwenMtpState, restoreQwenMtpState } from "../../../state/speculative/qwen-mtp-state";
39
+ import { applyStateChanges, cleanupFailure, disposeResources } from "../../../runtime/resources";
40
+ import { artifactIdentity } from "../../../artifacts/identity";
41
+ import { configFingerprint } from "../../../artifacts/fingerprint";
42
+ import type { PreparedStateChange } from "../../../contracts/portable/resources";
43
+
44
+ /** MTP drafts from the target's last hidden layer, before its final norm. */
45
+ const mtpTapLayers = (target: RecurrentMtpTarget): readonly number[] => Object.freeze([target.layerCount - 1]);
46
+
47
+ export class QwenMtpProvider implements DraftProvider {
48
+ readonly grouped: GroupedDraftProvider = {
49
+ supportsExternalTokens: true,
50
+ targetTapLayers: view => mtpTapLayers(this.#target(view)),
51
+ // A list shipped beside the companion (or named by MLX_BUN_SPEC_DRAFT_VOCAB),
52
+ // for a target whose quantized head the rows can project a row subset of.
53
+ draftVocabulary: view => {
54
+ const head = this.#target(view).vocabularyHead;
55
+ return head ? configuredDraftVocabulary(head.vocabSize, this.#dir) : null;
56
+ },
57
+ checkpointNamespace: () => this.#checkpointNamespace,
58
+ open: options => this.#openRows(options.target, options.sampling, options.checkpoints),
59
+ openPrefill: options => this.#openRows(options.target, null, options.checkpoints),
60
+ };
61
+ readonly id: string;
62
+ readonly weightsBytes: number;
63
+ readonly #module: RecurrentMtpModule;
64
+ readonly #config: ModelConfig;
65
+ readonly #resources: DisposableStack;
66
+ readonly #checkpointNamespace: string;
67
+ /** The companion's directory, where its optional draft vocabulary ships. */
68
+ readonly #dir: string;
69
+
70
+ private constructor(id: string, dir: string, config: ModelConfig, weightsBytes: number, module: RecurrentMtpModule, resources: DisposableStack, checkpointNamespace: string) {
71
+ this.id = id;
72
+ this.#dir = dir;
73
+ this.#config = config;
74
+ this.#module = module;
75
+ this.weightsBytes = weightsBytes;
76
+ this.#resources = resources;
77
+ this.#checkpointNamespace = checkpointNamespace;
78
+ }
79
+
80
+ static async load(dir: string): Promise<QwenMtpProvider> {
81
+ const config = await loadModelConfig(dir);
82
+ const weights = await Weights.open(dir);
83
+ using resources = new DisposableStack();
84
+ resources.defer(() => weights.dispose());
85
+ const weightsBytes = [...weights.shards.files.values()]
86
+ .reduce((a, f) => a + f.mmap.size, 0);
87
+ const module = await loadQwenMtpModule(weights, config, resources);
88
+ // Stable across restarts and distinct for differently folded/quantized
89
+ // companions. Hash once at provider load, outside inference execution.
90
+ const identity = await artifactIdentity(configFingerprint(config),
91
+ [...weights.shards.files].map(([name, shard]) => ({ name, path: shard.path })));
92
+ return new QwenMtpProvider(
93
+ dir.split("/").filter(Boolean).at(-1) ?? "qwen-mtp", dir,
94
+ config, weightsBytes, module, resources.move(), `${DRAFT_CHECKPOINT_SCHEMA.qwenMtp}:${identity}`,
95
+ );
96
+ }
97
+
98
+ #target(view: TargetView): RecurrentMtpTarget {
99
+ if (this.#resources.disposed)
100
+ throw new Error("qwen MTP provider is disposed");
101
+ const target = view.recurrentMtp;
102
+ if (!target) throw targetLacks("recurrentMtp");
103
+ if (target.hiddenSize !== this.#config.text.hiddenSize) {
104
+ throw new Error(
105
+ `qwen MTP drafter hidden ${this.#config.text.hiddenSize} != target ` +
106
+ `${target.hiddenSize} — split from a different checkpoint?`,
107
+ );
108
+ }
109
+ return target;
110
+ }
111
+
112
+ #openRows(view: TargetView, sampling: DraftRowSampling | null,
113
+ checkpoints: readonly (DraftRowCheckpoint | null)[]): DraftRowGroup & DraftPrefillGroup {
114
+ const target = this.#target(view);
115
+ const rows = new QwenMtpRows(target, this.#module, sampling, []);
116
+ const prepareAppend = (checkpoints: readonly (DraftRowCheckpoint | null)[]) => {
117
+ const states: Array<MtpRowState | null> = [];
118
+ let change: PreparedStateChange | undefined;
119
+ try {
120
+ for (const checkpoint of checkpoints) states.push(checkpoint ? restoreQwenMtpState(checkpoint) : null);
121
+ change = rows.prepareAppend(states);
122
+ disposeResources(states.splice(0).flatMap(state => state ? [state.cache, state.hidden] : []));
123
+ return change;
124
+ } catch (error) {
125
+ return cleanupFailure(error, () => disposeResources([
126
+ ...states.flatMap(state => state ? [state.cache, state.hidden] : []), ...(change ? [change] : []),
127
+ ]));
128
+ }
129
+ };
130
+ const append = (checkpoints: readonly (DraftRowCheckpoint | null)[]) => applyStateChanges([() => prepareAppend(checkpoints)]);
131
+ try { append(checkpoints); }
132
+ catch (error) { return cleanupFailure(error, () => rows.dispose()); }
133
+ return {
134
+ namespace: this.#checkpointNamespace, prefillMode: "full", tapLayers: mtpTapLayers(target),
135
+ get rowCount() { return rows.rowCount; },
136
+ append, prepareAppend, prefill: (tokens, context) => rows.prefill(tokens, context!), materialize: rows.materialize.bind(rows),
137
+ filterRows: rows.filterRows.bind(rows),
138
+ draft: rows.draft.bind(rows), draftDevice: rows.draftDevice.bind(rows), preview: rows.preview.bind(rows), commit: rows.commit.bind(rows),
139
+ consume: rows.consume.bind(rows),
140
+ capture(row) {
141
+ const state = rows.extractRow(row);
142
+ try { return captureQwenMtpState(state); }
143
+ finally { disposeResources([state.cache, state.hidden]); }
144
+ },
145
+ dispose: rows.dispose.bind(rows),
146
+ };
147
+ }
148
+
149
+ dispose(): void {
150
+ // Release cached transpose views before their native weight maps. MLX
151
+ // retains buffers needed by outstanding GPU commands until completion.
152
+ this.#resources.dispose();
153
+ }
154
+ }
@@ -0,0 +1,75 @@
1
+ // Two-model speculative drafting — mlx-lm parity (`mlx_lm.server
2
+ // --draft-model`). A full second model drafts autoregressively in the grouped
3
+ // draft rows (bindings/two-model-rows.ts); the shared speculative group
4
+ // verifies with the target. L1 oracle:
5
+ // mlx_lm.server with the same target/draft pair, greedy, token-for-token
6
+ // (spec-vs-spec — both batch the verify lm-head, so neither is bit-exact to
7
+ // stock decode at knife-edges).
8
+ //
9
+ // Faithfulness notes (read from the oracle venv's generate.py):
10
+ // - drafts are sampled with the REQUEST sampler (generate.py:593-601) —
11
+ // greedy drafting under a temperature>0 request is not parity;
12
+ // - draft-cache rewind is max(n - kAccept - 1, 0) (generate.py:589-591),
13
+ // with the all-accept re-feed of the last draft kept pending in the rows
14
+ // and joined with the next target token (generate.py:645-648);
15
+ // - logits processors do NOT run on draft steps (they're target-side).
16
+
17
+ import { loadModelConfig } from "../../../artifacts/config";
18
+ import { Weights } from "../../../artifacts/weights";
19
+ import { createModel, type RuntimeModel } from "../../../models/factory";
20
+ import type { DraftProvider, GroupedDraftProvider } from "../source";
21
+ import { standaloneDraftGroups } from "../bindings/two-model-rows";
22
+ import { bindMlxAutoregressiveGraph } from "../../bindings/autoregressive";
23
+ import { artifactIdentity } from "../../../artifacts/identity";
24
+ import { configFingerprint } from "../../../artifacts/fingerprint";
25
+ import { cleanupFailure, disposeResources } from "../../../runtime/resources";
26
+
27
+ export class TwoModelProvider implements DraftProvider {
28
+ readonly id: string;
29
+ readonly weightsBytes: number;
30
+ readonly grouped: GroupedDraftProvider;
31
+
32
+ private constructor(
33
+ readonly model: RuntimeModel,
34
+ private readonly weights: Weights,
35
+ id: string,
36
+ namespace: string,
37
+ ) {
38
+ this.id = id;
39
+ this.grouped = standaloneDraftGroups(bindMlxAutoregressiveGraph(model), namespace);
40
+ this.weightsBytes = [...weights.shards.files.values()].reduce(
41
+ (a, f) => a + f.mmap.size,
42
+ 0,
43
+ );
44
+ }
45
+
46
+ /** Load the draft model from a snapshot dir. Vocab-size mismatch with the
47
+ * target is a WARNING (mlx-lm parity, server.py:363-368); the tokenizer-
48
+ * family hard check lives at the server (it owns both tokenizers). */
49
+ static async load(modelDir: string, targetVocabSize?: number): Promise<TwoModelProvider> {
50
+ const config = await loadModelConfig(modelDir);
51
+ const weights = await Weights.open(modelDir);
52
+ let model: RuntimeModel | null = null;
53
+ try {
54
+ model = createModel(weights, config);
55
+ if (
56
+ targetVocabSize !== undefined &&
57
+ config.text.vocabSize !== targetVocabSize
58
+ )
59
+ console.warn(
60
+ `draft model vocab size ${config.text.vocabSize} != target ${targetVocabSize} — ` +
61
+ `speculation will accept nothing useful (mlx-lm warns identically)`,
62
+ );
63
+ const identity = await artifactIdentity(configFingerprint(config),
64
+ [...weights.shards.files].map(([name, shard]) => ({ name, path: shard.path })));
65
+ return new TwoModelProvider(model, weights, modelDir.split("/").filter(Boolean).at(-1)!,
66
+ `standalone-draft-v1:${identity}`);
67
+ } catch (error) { return cleanupFailure(error, () => disposeResources([...(model ? [model] : []), weights])); }
68
+ }
69
+
70
+ /** The draft graph releases what it built (constants, Neural Engine programs),
71
+ * then its weights go. */
72
+ dispose(): void {
73
+ disposeResources([this.model, this.weights]);
74
+ }
75
+ }
@@ -0,0 +1,194 @@
1
+ // Streaming generation — port of mlx-lm's generate_step:
2
+ // - prefill in chunks; cache state evaluated per chunk (bounded transient
3
+ // memory), logits never computed for non-final prefill positions
4
+ // - decode pipelining via mx.async_eval: step n+1's graph is built and
5
+ // dispatched before step n's token is read back, so the GPU never idles
6
+ // on the JS round-trip
7
+ // - opt-in early token-zero yield reduces latency before that pipeline starts
8
+ // - sampling stays on-device; only the chosen token id crosses to JS
9
+
10
+ import { MlxArray } from "@mlx-bun/mlx/array";
11
+ import { type Cache } from "../contracts/mlx/cache";
12
+ import type { TokenLogprobs } from "../contracts/portable/generation";
13
+ import type { PromptResponseTrace } from "../runtime/trace";
14
+ import type { GrammarController } from "../sampling/grammar";
15
+ import {
16
+ type LogitsProcessorOptions,
17
+ type SamplerOptions
18
+ } from "../sampling/index";
19
+ import {
20
+ type FillSession,
21
+ type FillStats
22
+ } from "./fill/session";
23
+
24
+ export interface GenerateOptions extends SamplerOptions, LogitsProcessorOptions {
25
+ /** Application session affinity; independent of numerical cache identity. */
26
+ cacheSessionId?: string;
27
+ /** Resolved host policy. Direct compatibility calls resolve from their
28
+ * captured binding when this is absent. */
29
+ decodePolicy?: Readonly<Pick<import("../contracts/portable/execution").ResolvedExecution, "compiledDecode" | "grammarJump">>;
30
+ /** Cooperatively cancel at prefill/decode boundaries; pending native work
31
+ * finishes before owned resources are released. */
32
+ signal?: AbortSignal;
33
+ maxTokens?: number;
34
+ eosTokenIds?: number[];
35
+ prefillChunkSize?: number;
36
+ /** Whether the request supplied its seed explicitly. Durable generation
37
+ * checkpoints use this to distinguish a reproducible user policy from the
38
+ * server-generated seed that must be recovered from checkpoint metadata. */
39
+ seedWasExplicit?: boolean;
40
+ /** Fired once during prefill, at `snapshotAt` tokens (default: the full
41
+ * prompt) and BEFORE any further KV is written — the one moment the
42
+ * caches hold exactly that prefix (post-wrap rings can't be rewound
43
+ * later). The server's prompt-boundary cache snapshot hangs here. */
44
+ onPrefillDone?: () => void;
45
+ /** Token count at which onPrefillDone fires (the STABLE cache boundary —
46
+ * chat prompts end in a generation primer, e.g. 12B's thought-channel
47
+ * tokens, that the NEXT turn's re-render does not contain; snapshotting
48
+ * there would make the entry untrimmable-and-divergent). Prefill is
49
+ * split at this index when it falls mid-prompt. */
50
+ snapshotAt?: number;
51
+ /** Resume an interrupted autoregressive generation from a durable KV
52
+ * checkpoint. `cache` must cover every token in `promptTokens` exactly;
53
+ * `initialPendingToken` is the already-sampled next token, so no cache
54
+ * rewind is required (important for recurrent/untrimmable layers). */
55
+ initialPendingToken?: number;
56
+ /** Number of completion tokens already emitted before this resumed run. */
57
+ initialGeneratedTokens?: number;
58
+ /** Original request prompt length used for protocol usage accounting when
59
+ * `promptTokens` also contains replayed completion tokens. */
60
+ originalPromptTokens?: number;
61
+ /** Periodic, safe decode-boundary checkpoint hook. The cache covers
62
+ * `cacheTokens`; `pendingToken` has been sampled but not emitted. */
63
+ checkpointEveryTokens?: number;
64
+ onDecodeCheckpoint?: (state: {
65
+ cacheTokens: number[];
66
+ caches: Cache[];
67
+ generatedTokens: number;
68
+ pendingToken: number;
69
+ }) => void | Promise<void>;
70
+ /** Pre-warmed KV caches (e.g. from the prompt cache). cache[0].offset
71
+ * prompt tokens are treated as already prefilled; only the suffix is
72
+ * forwarded. Caller keeps ownership — generate() will not dispose. */
73
+ cache?: Cache[];
74
+ /** Vision path: pre-merged (unscaled) input embeddings [1, L, hidden]
75
+ * covering the whole prompt; prefilled in one shot (no chunking).
76
+ * Caller keeps ownership. */
77
+ promptEmbeddings?: MlxArray;
78
+ /** bool [L] marking image tokens (bidirectional attention among them).
79
+ * MUST be unset when the prompt contains any audio — audio prompts run
80
+ * fully causal (`02d723a:docs/design/generic-model-support.md` §6.6). */
81
+ imageMask?: MlxArray;
82
+ /** bool [L] marking ALL multimodal soft tokens (image | audio) for
83
+ * per-layer-input id zeroing (e2b/e4b), decoupled from imageMask so
84
+ * audio-only prompts (no bidirectional mask) still zero their positions.
85
+ * When unset, zeroing falls back to imageMask (the legacy vision shape).
86
+ * Caller keeps ownership. */
87
+ multimodalMask?: MlxArray;
88
+ /** Mounted LoRA adapter ids to apply (resolved/validated by
89
+ * AdapterManager.resolveSpec). Residuals sum in order. Set on the
90
+ * model's LoraState for exactly the duration of this generation —
91
+ * a plain field, safe because the generation queue is serialized. */
92
+ adapters?: string[];
93
+ /** DiffusionGemma image-text-to-text: channel-first pixel_values [1,3,H,W].
94
+ * When set, `promptTokens` are the spliced (<|image|>-expanded) ids and the
95
+ * denoising engine prefills the merged vision features. Caller keeps ownership. */
96
+ visionPixels?: MlxArray;
97
+ /** Capture each emitted token's log-probability (mlx_lm.server `logprobs`).
98
+ * The distribution matches mlx-lm generate_step exactly: full-vocab
99
+ * log-softmax of the logits AFTER logits processors, BEFORE the sampler's
100
+ * temperature/top-p/top-k/min-p/XTC (generate.py L409-422). Off by default —
101
+ * the hot path pays nothing when unset. */
102
+ logprobs?: boolean;
103
+ /** Capture the top-k (token id, logprob) pairs per emitted token from the
104
+ * same distribution (mlx_lm.server `top_logprobs`). 0/unset = off. */
105
+ topLogprobs?: number;
106
+ /** Grammar-constrained decoding (packages/inference/src/sampling/grammar.ts): a compiled GrammarController
107
+ * that masks invalid tokens to -inf each step. L2-class (oMLX oracle). When
108
+ * set, the decode loop takes a slightly different shape: it eager-reads the
109
+ * token id (acceptToken needs a JS number, which the pipelined loop defers),
110
+ * advances the matcher, and awaits the async mask precompute (which overlaps
111
+ * the GPU forward). Non-grammar requests keep the fast pipelined loop. */
112
+ grammar?: GrammarController;
113
+ /** Token fast-forwarding (packages/inference/src/generation/fill/,
114
+ * `02d723a:docs/design/speculative-decoding.md` §7 "Token fast-forwarding"):
115
+ * a per-request table of DETERMINED token spans
116
+ * (compiled from the request's `tools` + the chat template). When the
117
+ * stream enters one, the engine appends the whole span itself with ONE
118
+ * multi-token forward and resumes sampling after it.
119
+ *
120
+ * This is context extension, NOT speculation: nothing is drafted, verified,
121
+ * or rolled back, and no comparison is made against what the model would
122
+ * have produced. Injection bypasses the sampler, which is a documented
123
+ * behavior-policy deviation at temperature > 0 — hence opt-in
124
+ * (MLX_BUN_FILL=strict) and the request refusals in shouldUseFill.
125
+ * Serial lane only: the batch scheduler and the spec loop never read it. */
126
+ fill?: FillSession;
127
+ }
128
+
129
+ export interface GenerateStats {
130
+ promptTokens: number;
131
+ /** An observed terminal cause takes precedence over the token-count limit. */
132
+ finishReason?: "stop" | "length";
133
+ /** Prompt tokens skipped via a pre-warmed cache. */
134
+ cachedTokens: number;
135
+ generatedTokens: number;
136
+ prefillTps: number;
137
+ decodeTps: number;
138
+ prefillMs: number;
139
+ decodeMs: number;
140
+ /** Exact token sequence whose KV now lives in the cache (prompt + every
141
+ * decoded token that was forwarded, including a trailing EOS the
142
+ * pipeline forwarded before reading it). For PromptCache.put(). */
143
+ cacheTokens: number[];
144
+ /** Speculative-decoding telemetry (serve --draft-model path only).
145
+ * draftedByPos/acceptedByPos: per-draft-position round counts (index =
146
+ * position within a round's block) — the per-position
147
+ * acceptance signal. */
148
+ spec?: {
149
+ drafted: number; accepted: number; targetCalls: number;
150
+ draftedByPos?: number[]; acceptedByPos?: number[];
151
+ rejected?: number; rounds?: number; acceptanceLengths?: number[];
152
+ tokensPerForward?: number; forwardsSaved?: number;
153
+ /** Round phase wall time, summed over the request's rounds. Present only
154
+ * under `MLX_BUN_SPEC_PHASE_TIMING=1`, which forces an evaluation at each
155
+ * phase boundary (diagnostic: it removes the overlap production decode
156
+ * relies on, so the sum is not production round time). */
157
+ phaseMs?: SpecPhaseMs;
158
+ };
159
+ /** Token fast-forwarding telemetry (MLX_BUN_FILL=strict). Present only when
160
+ * a fill table was actually armed for this generation. */
161
+ fill?: FillStats;
162
+ }
163
+
164
+ /** Wall milliseconds per speculative round phase (see GenerateStats.spec). */
165
+ export interface SpecPhaseMs {
166
+ /** draft(): the drafter's chain including its proposal readback. */
167
+ draft: number;
168
+ /** Target verify forward, forced to completion before sampling. */
169
+ verify: number;
170
+ /** Window sampling and its readback, plus the host accept walk. */
171
+ sample: number;
172
+ /** Target transaction resolve plus draft commit. Includes retained-state
173
+ * evaluation when the target/drafter supply diagnostic materialize hooks. */
174
+ commit: number;
175
+ rounds: number;
176
+ /** Target-forward component wall ms (`MLX_BUN_SPEC_LAYER_PROFILE=1`): per-op
177
+ * evaluation barriers inside the verify forward, so `verify` grows while set. */
178
+ layers?: Record<string, number>;
179
+ /** Graph nodes built per op name (`MLX_BUN_SPEC_OP_INVENTORY=1`), summed over rounds. */
180
+ verifyOps?: Record<string, number>;
181
+ draftOps?: Record<string, number>;
182
+ }
183
+
184
+ export interface GenerateDiagnostics {
185
+ trace?: PromptResponseTrace;
186
+ mechanism?: "serial" | "continuous";
187
+ }
188
+
189
+ export interface GeneratedToken {
190
+ token: number;
191
+ index: number;
192
+ /** Present only when GenerateOptions.logprobs / topLogprobs requested it. */
193
+ logprobs?: TokenLogprobs;
194
+ }
package/src/index.ts ADDED
@@ -0,0 +1,20 @@
1
+ // Common library entry points. Specialized components have explicit subpath imports.
2
+ export { loadModelConfig } from "./artifacts/config";
3
+ export { Weights } from "./artifacts/weights";
4
+ export { createModel, openModel, openGlm52RuntimeModel } from "./models/factory";
5
+ export type { RuntimeModel, ModelOpenOptions, Glm52RuntimeOpenOptions } from "./models/factory";
6
+ export { resolveComposition } from "./models/composition";
7
+ export type { CompositionRequest } from "./models/composition";
8
+ export type { Composition } from "./contracts/portable/composition";
9
+ export { ModelImplementationRegistry } from "./models/implementation";
10
+ export { loadTokenizer } from "./input/tokenizer";
11
+ export type { LoadedTokenizer } from "./input/tokenizer";
12
+ export { ChatTemplate } from "./input/chat-template";
13
+ export { generate, bindGeneration } from "./generation/generate";
14
+ export { generateAutoregressive } from "./generation/autoregressive";
15
+ export { generateDenoising } from "./generation/denoising";
16
+ export { Generation } from "./generation/result";
17
+ export type { GenerateOptions, GenerateStats, GeneratedToken } from "./generation/types";
18
+ export { embedOne, embedMany, embeddingTerminatorId, isEmbeddingModel, withInstruction } from "./embeddings/text";
19
+ export type { EmbedResult, EmbeddingGraph } from "./embeddings/text";
20
+ export { AdapterManager } from "./adapters/manager";