@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,505 @@
1
+ import type { GenerateOptions } from "../generation/index";
2
+ import type { MlxTokenGraph } from "../models/graph";
3
+ import type { Cache } from "../contracts/mlx/cache";
4
+ import type { MlxArray } from "@mlx-bun/mlx/array";
5
+ import * as ops from "@mlx-bun/mlx/ops";
6
+ import { clearCache } from "@mlx-bun/mlx/ffi";
7
+ import { makeStepSampler, type DeviceStepSampler, type NumberStepSampler } from "../sampling/index";
8
+ import type { FillSession, Proposal } from "../generation/fill/session";
9
+ import { disposeResources, cleanupFailure, withResource } from "../runtime/resources";
10
+ import { snapshotGenerationPolicy } from "./request-policy";
11
+ import { MlxPrefillCohort } from "./prefill-cohort";
12
+ import { MlxStateRows } from "../state/rows";
13
+ import { targetCacheLayout } from "../state/layout";
14
+ import { leaseCacheStates } from "../state/leases";
15
+ import { MlxPhaseDispatch } from "../generation/phase-dispatch";
16
+ import { tokenPhasesOf } from "../models/capabilities";
17
+ import { type MlxKnownSpans } from "../contracts/mlx/graph";
18
+ import { appendHiddenRows } from "../generation/fill-append";
19
+ import { advanceSpeculativeOutputs } from "../generation/speculative/round";
20
+ import { bindRowCacheRollback } from "../state/rollback";
21
+ import { bindSpeculativeTargetModel, type MlxSpeculativeTargetBinding } from "../generation/speculative/bindings/binding";
22
+ import type { MlxForwardWork } from "../contracts/mlx/forward-work";
23
+ import type { MlxGroupedMethod, MlxGroupMethodHost, MlxGroupMethodRequest, MlxGroupPreparation, Row } from "./batch-types";
24
+
25
+ interface RequestState {
26
+ sampling: DeviceStepSampler;
27
+ fill: FillSession;
28
+ proposal?: { value: Proposal; emitted: number };
29
+ }
30
+
31
+ /** Strict continuations share preparation, row layouts and queueing with other
32
+ * methods. Sampled tokens remain pipelined; committed tokens bypass sampling.
33
+ * This binding is qualified independently before serving advertises it. */
34
+ export function bindFillGroupRequests(model: MlxTokenGraph) {
35
+ return (input: GenerateOptions): MlxGroupMethodRequest => {
36
+ const options = snapshotGenerationPolicy(input);
37
+ return {
38
+ key: JSON.stringify(["fill"]),
39
+ data: options,
40
+ open: host => new FillGroup(host, model),
41
+ };
42
+ };
43
+ }
44
+
45
+ class FillGroup implements MlxGroupedMethod {
46
+ readonly #dispatch: MlxPhaseDispatch;
47
+ /** The graph's committed known-token spans, when it declares them, this
48
+ * group's rows carry no active adapter and the KV scheme keeps their
49
+ * one-position arithmetic; otherwise known tokens append one at a time. */
50
+ readonly #spans: MlxKnownSpans | null;
51
+ readonly #verify: MlxSpeculativeTargetBinding;
52
+ readonly #requests = new Map<Row, RequestState>();
53
+ #target: MlxStateRows<ReturnType<typeof targetCacheLayout>> | null = null;
54
+ #pending: MlxArray | null = null;
55
+ #known: boolean[] = [];
56
+ #real: boolean[] = [];
57
+ #steps = 0;
58
+
59
+ constructor(readonly host: MlxGroupMethodHost, readonly model: MlxTokenGraph) {
60
+ this.#dispatch = new MlxPhaseDispatch(tokenPhasesOf(model));
61
+ this.#verify = bindSpeculativeTargetModel(model);
62
+ const spans = model.knownSpans;
63
+ this.#spans = spans && !model.loraState?.active.length ? spans : null;
64
+ }
65
+
66
+ /** Positions one known-token call takes: up to the spans' limit for one row, one per row otherwise. */
67
+ #knownChunk(caches: readonly Cache[], rows: number): number {
68
+ return this.#spans && rows === 1 ? this.#spans.maxChunkSize(caches) : 1;
69
+ }
70
+
71
+ get runningTokens(): number { return this.host.rows.length * Math.max(1, this.#burstLength(), this.#verifyLength()); }
72
+
73
+ #verifyLength(): number {
74
+ if (!this.#pending || !this.host.rows.length ||
75
+ this.host.rows.some(row => this.#requests.get(row)!.proposal?.value.policy === "assert")) return 0;
76
+ return Math.max(...this.host.rows.map(row => {
77
+ const proposal = this.#requests.get(row)!.proposal;
78
+ return proposal ? proposal.value.ids.length - proposal.emitted : 0;
79
+ }));
80
+ }
81
+
82
+ #burstLength(): number {
83
+ const rows = this.host.rows;
84
+ if (!rows.length || !this.#pending || this.#known.some(known => !known) ||
85
+ this.#knownChunk(this.#target!.caches, rows.length) <= 1) return 0;
86
+ return Math.min(...rows.map(row => {
87
+ const proposal = this.#requests.get(row)!.proposal;
88
+ return proposal?.value.policy === "assert" ? proposal.value.ids.length - proposal.emitted : 0;
89
+ }));
90
+ }
91
+
92
+ prepare(first: Row): MlxGroupPreparation {
93
+ const ready: { row: Row; caches: Cache[]; retain?: () => void }[] = [];
94
+ const target = new MlxPrefillCohort({
95
+ chunkSize: this.host.prefillChunkSize,
96
+ tailSplit: this.host.prefillTailSplit,
97
+ cache: this.host.cache, maintain: this.host.kvMaintenance,
98
+ forward: async (ids, caches, step) => this.#dispatch.prompt(step.phase, step.sequences, step.tokens)(ids, caches, null),
99
+ project: (hidden, _caches, _completed, step) => this.#dispatch.logits(step.sequences * step.tokens)(hidden),
100
+ complete: async (state, logits) => {
101
+ const row = state.row;
102
+ const request = this.#requests.get(row)!;
103
+ using scores = ops.reshape(logits, [1, logits.shape.at(-1)!]);
104
+ using token = request.sampling.sample(scores, 0).token;
105
+ row.generated = row.sampled = 1;
106
+ try {
107
+ const reason = await this.#emit(row, token.toIntTokens()[0]!, false);
108
+ if (reason) {
109
+ this.#put(row, state.solo, state.retain);
110
+ state.solo = []; state.retain = undefined;
111
+ this.#closeRequest(row); this.host.finish(row, reason);
112
+ } else {
113
+ ready.push({ row, caches: state.solo, retain: state.retain });
114
+ }
115
+ } catch (error) { this.#closeRequest(row); throw error; }
116
+ },
117
+ reject: (row, error) => { this.#closeRequest(row); row.reject(error); },
118
+ });
119
+ const admit = (row: Row) => {
120
+ const options = row.req.method!.data as GenerateOptions;
121
+ const request: RequestState = { fill: options.fill!,
122
+ sampling: makeStepSampler(options, { tokenRepresentation: "device", grammarWait: "external",
123
+ historyUpdate: "manual", initialHistory: row.req.promptIds }) };
124
+ row.fill = request.fill.stats;
125
+ this.#requests.set(row, request);
126
+ try { target.admit(row); }
127
+ catch (error) { this.#closeRequest(row); throw error; }
128
+ };
129
+ const preparation: MlxGroupPreparation = {
130
+ get rows() { return [...target.rows, ...ready.map(state => state.row)]; },
131
+ get canAdmit() { return target.canAdmit; },
132
+ get tokenWeight() { return target.tokenWeight + ready.reduce((sum, state) => sum + state.row.promptTokens - state.row.cachedTokens, 0); },
133
+ admit,
134
+ advance: async work => {
135
+ if (!ready.length) {
136
+ const done = await target.advance(work);
137
+ return done && !ready.length;
138
+ }
139
+ // Flush before membership changes. Prepared output was already
140
+ // published on the preceding scheduler iteration.
141
+ await this.#flush();
142
+ while (ready.length) {
143
+ const state = ready.shift()!;
144
+ try {
145
+ if (state.row.req.signal?.aborted) {
146
+ this.#closeRequest(state.row); state.row.reject(state.row.req.signal.reason); continue;
147
+ }
148
+ this.host.kvMaintenance?.prepareBatch?.(state.caches);
149
+ this.#target ??= new MlxStateRows(state.caches.map(targetCacheLayout));
150
+ this.#target.append(state.caches);
151
+ // Copies must settle before releasing a restored SSD lease.
152
+ if (state.retain) withResource(leaseCacheStates(this.#target.caches), arrays => ops.evalAll([...arrays]));
153
+ this.host.join(state.row);
154
+ } finally { disposeResources([...state.caches, { dispose: () => state.retain?.() }]); }
155
+ }
156
+ return !target.rows.length;
157
+ },
158
+ dispose: () => {
159
+ const rows = preparation.rows;
160
+ disposeResources([target, ...ready.splice(0).flatMap(state => [...state.caches,
161
+ { dispose: () => state.retain?.() }]), { dispose: () => {
162
+ for (const row of rows) if (!this.host.rows.includes(row)) this.#closeRequest(row);
163
+ } }]);
164
+ },
165
+ };
166
+ try { admit(first); return preparation; }
167
+ catch (error) { return cleanupFailure(error, () => preparation.dispose()); }
168
+ }
169
+
170
+ async advance(work?: MlxForwardWork): Promise<void> {
171
+ const live = this.host.rows.flatMap((row, index) => row.req.signal?.aborted ? [] : [index]);
172
+ if (live.length !== this.host.rows.length) {
173
+ for (const row of this.host.rows) if (row.req.signal?.aborted) row.reject(row.req.signal.reason);
174
+ this.host.filterRows(live);
175
+ }
176
+ const rows = [...this.host.rows], B = rows.length;
177
+ if (!B) return;
178
+ const verifyLength = this.#verifyLength();
179
+ if (!work && verifyLength > 1) { await this.#verifyKnown(verifyLength); return; }
180
+ const burst = this.#burstLength();
181
+ if (!work && burst > 1) { await this.#appendKnown(burst); return; }
182
+ const previous = this.#pending, known = this.#known, real = this.#real;
183
+ const anyLive = rows.some(row => row.sampled < row.req.maxTokens);
184
+ let next: MlxArray | null = null;
185
+ const nextKnown: boolean[] = [], nextReal: boolean[] = [];
186
+ if (anyLive) {
187
+ using input = previous ? ops.reshape(previous, [B, 1]) : ops.fromInt32(rows.map(row => row.current), [B, 1]);
188
+ const own = async () => this.#dispatch.decode(B)(input, this.#target!.caches, null);
189
+ using hidden = await (work ? work(input, this.#target!.caches, { phase: "decode", rows: B, capture: null, own }) : own());
190
+ const selected = rows.map((row, index) => {
191
+ const request = this.#requests.get(row)!;
192
+ // The next selected token is not committed until it becomes input.
193
+ // Discarding a speculative sample for an assert cannot pollute history.
194
+ if (request.sampling.needsHistory) {
195
+ using current = input.slice([index, 0], [index + 1, 1]);
196
+ request.sampling.commitDevice(current);
197
+ }
198
+ const value = request.proposal?.value.policy === "assert"
199
+ ? request.proposal.value.ids[request.proposal.emitted + Number(!!previous && known[index])] : undefined;
200
+ nextKnown.push(value !== undefined); nextReal.push(row.sampled < row.req.maxTokens);
201
+ return value;
202
+ });
203
+ const needScores = rows.some((_row, index) => nextReal[index] && !nextKnown[index]);
204
+ using logits = needScores ? this.#dispatch.logits(B)(hidden) : null;
205
+ const tokens: MlxArray[] = [];
206
+ try {
207
+ for (let index = 0; index < B; index++) {
208
+ const row = rows[index]!;
209
+ if (!nextReal[index]) { tokens.push(ops.fromInt32([0], [1])); continue; }
210
+ if (nextKnown[index]) tokens.push(ops.fromInt32([selected[index]!], [1]));
211
+ else {
212
+ using slice = logits!.slice([index, 0, 0], [index + 1, 1, logits!.shape[2]!]);
213
+ using scores = ops.reshape(slice, [1, slice.shape[2]!]);
214
+ tokens.push(this.#requests.get(row)!.sampling.sample(scores, row.sampled).token);
215
+ }
216
+ row.sampled++;
217
+ }
218
+ next = ops.concatAxis(tokens, 0);
219
+ // Constant known tokens have no dependency on the model graph.
220
+ // Submit state explicitly when the vocabulary projection is omitted.
221
+ if (needScores) ops.asyncEvalAll([next]);
222
+ else withResource(leaseCacheStates(this.#target!.caches), state => ops.asyncEvalAll([next!, hidden, ...state]));
223
+ } catch (error) { next?.dispose(); next = null; throw error; }
224
+ finally { disposeResources(tokens); }
225
+ }
226
+ this.#pending = next; this.#known = nextKnown; this.#real = nextReal;
227
+ if (previous) {
228
+ let values: number[];
229
+ try { values = previous.toIntTokens(); } finally { previous.dispose(); }
230
+ if (anyLive) for (let index = 0; index < B; index++) {
231
+ if (real[index]) rows[index]!.fed.push(values[index]!);
232
+ else rows[index]!.fedTainted = true;
233
+ }
234
+ await this.#emitRows(values, known);
235
+ } else if (anyLive) for (const row of rows) row.fed.push(row.current);
236
+ this.#checkPendingProposals();
237
+ if (++this.#steps % 256 === 0) clearCache();
238
+ }
239
+
240
+ /** The pending sample already verifies an echo's first token. Asserted
241
+ * continuations keep their append policy; other rows can join a verified
242
+ * span with an empty proposal through the existing row verifier. */
243
+ #checkPendingProposals(): void {
244
+ if (!this.#pending) return;
245
+ const rows = this.host.rows;
246
+ if (!rows.some(row => this.#requests.get(row)!.proposal?.value.policy === "verify")) return;
247
+ const tokens = this.#pending.toIntTokens();
248
+ for (const [index, row] of rows.entries()) {
249
+ const request = this.#requests.get(row)!, proposal = request.proposal;
250
+ if (proposal?.value.policy !== "verify") continue;
251
+ if (tokens[index] === proposal.value.ids[proposal.emitted]) this.#known[index] = true;
252
+ else {
253
+ request.fill.commit(proposal.value, proposal.emitted);
254
+ request.proposal = undefined;
255
+ }
256
+ }
257
+ }
258
+
259
+ async #verifyKnown(width: number): Promise<void> {
260
+ // Publish the already verified pending token before changing geometry.
261
+ await this.#flush();
262
+ const rows = [...this.host.rows];
263
+ if (!rows.length) return;
264
+ // Publishing an ordinary row can discover a strict template span. Let
265
+ // its append policy choose the next operation before verifying echoes.
266
+ if (rows.some(row => this.#requests.get(row)!.proposal?.value.policy === "assert")) return;
267
+ const pending = rows.map(row => row.current);
268
+ const proposals = rows.map(row => {
269
+ const proposal = this.#requests.get(row)!.proposal;
270
+ // A newly discovered proposal cannot exceed this iteration's declared
271
+ // token work. Its remaining continuation stays request-owned.
272
+ return proposal?.value.policy === "verify"
273
+ ? proposal.value.ids.slice(proposal.emitted, proposal.emitted + width - 1) : [];
274
+ });
275
+ const depth = Math.max(...proposals.map(ids => ids.length));
276
+ const samplers = rows.map(row => {
277
+ const sampling = this.#requests.get(row)!.sampling;
278
+ sampling.commitNumbers([row.current]);
279
+ let previous: number | undefined;
280
+ // A second sample is requested only after the preceding candidate was
281
+ // accepted. Leave the final correction out of manual processor history
282
+ // until the next forward actually consumes it.
283
+ return { ...sampling,
284
+ async sample(scores, step) {
285
+ if (previous !== undefined) sampling.commitNumbers([previous]);
286
+ const result = sampling.sample(scores, step);
287
+ try { previous = result.token.toIntTokens()[0]!; return { token: previous, extras: result.extras }; }
288
+ finally { result.token.dispose(); }
289
+ },
290
+ } satisfies NumberStepSampler;
291
+ });
292
+ const halted = new Set<Row>();
293
+ const rollback = bindRowCacheRollback(this.#target!.caches, rows.length);
294
+ const verifying = rows.filter(row => this.#requests.get(row)!.proposal?.value.policy === "verify")
295
+ .map(row => this.#requests.get(row)!.fill);
296
+ {
297
+ const completed = await advanceSpeculativeOutputs(rows.map((row, index) => ({
298
+ pending: pending[index]!, step: row.sampled, remaining: row.req.maxTokens - row.generated,
299
+ eosTokenIds: row.req.eosTokenIds, sampling: samplers[index]!,
300
+ output: { commit: async ids => {
301
+ const proposal = this.#requests.get(row)!.proposal;
302
+ const known = proposal?.value.policy === "verify" && ids[0] === proposal.value.ids[proposal.emitted];
303
+ if (!known) this.#settleProposal(row);
304
+ row.generated++;
305
+ const reason = await this.#emit(row, ids[0]!, known);
306
+ if (reason === "stop") { halted.add(row); return false; }
307
+ } },
308
+ })), depth, { draft: () => proposals, commit: () => {} }, {
309
+ transaction: { ...rollback,
310
+ begin(depth) {
311
+ const start = performance.now(); rollback.begin(depth);
312
+ const elapsed = performance.now() - start;
313
+ for (const fill of verifying) fill.noteVerifyEvent(elapsed);
314
+ },
315
+ resolve(accepted) {
316
+ const start = performance.now(); rollback.resolve(accepted);
317
+ const elapsed = performance.now() - start;
318
+ for (const fill of verifying) fill.stats.checkpointMs += elapsed;
319
+ },
320
+ },
321
+ forward: async (ids, window) => {
322
+ const result = await this.#verify.verify(ids, this.#target!.caches, window);
323
+ const context = result.ctxML ?? result.hidden;
324
+ try { return { logits: this.#verify.projectLogits(result.hidden, window.sequences * window.positions), context }; }
325
+ catch (error) { context.dispose(); throw error; }
326
+ finally { if (result.ctxML) result.hidden.dispose(); }
327
+ },
328
+ });
329
+ const keep: number[] = [];
330
+ for (const [index, row] of rows.entries()) {
331
+ const output = completed.outputs[index]!, round = completed.rounds[index]!;
332
+ if (output.kind !== "failed" && output.kind !== "cancelled")
333
+ row.fed.push(pending[index]!, ...round.drafts.slice(0, output.accepted));
334
+ row.sampled += round.acceptance.emitted.length + Number(round.acceptance.sawEos);
335
+ if (output.kind === "continue") { row.current = output.pending; keep.push(index); }
336
+ else if (output.kind === "failed") row.reject(output.error);
337
+ else if (output.kind === "cancelled") row.reject(row.req.signal?.reason ?? new Error(output.reason));
338
+ else {
339
+ if (!halted.has(row) && round.acceptance.sawEos && row.generated < row.req.maxTokens) row.generated++;
340
+ this.#put(row, this.#target!.extractRow(index));
341
+ this.#settleProposal(row); this.host.finish(row, output.kind);
342
+ }
343
+ }
344
+ if (keep.length !== rows.length) this.host.filterRows(keep);
345
+ if (++this.#steps % 256 === 0) clearCache();
346
+ }
347
+ }
348
+
349
+ /** Multi-position arithmetic is model-owned. Wider cohorts whose model
350
+ * declares one position keep the pipelined single-position implementation. */
351
+ async #appendKnown(length: number): Promise<void> {
352
+ const rows = [...this.host.rows], B = rows.length;
353
+ const spans = new Map(rows.map(row => {
354
+ const proposal = this.#requests.get(row)!.proposal!;
355
+ return [row, proposal.value.ids.slice(proposal.emitted, proposal.emitted + length)] as const;
356
+ }));
357
+ using input = ops.fromInt32(rows.flatMap(row => spans.get(row)!), [B, length]);
358
+ // One row appends its span through appendKnown; several rows append one known token each through decode.
359
+ using hidden = await appendHiddenRows((part, caches, positions) => B === 1
360
+ ? this.#dispatch.known(positions)(part, caches) : this.#dispatch.decode(B)(part, caches, null),
361
+ this.#target!.caches, input,
362
+ (caches, count) => Math.min(this.#knownChunk(caches, count),
363
+ this.host.kvMaintenance?.maxAppendTokens?.(caches) ?? Infinity,
364
+ ...rows.map(row => this.#requests.get(row)!.fill.appendChunkSize || Infinity)));
365
+ const nextKnown: boolean[] = [], nextReal: boolean[] = [];
366
+ const selected = rows.map(row => {
367
+ const request = this.#requests.get(row)!, proposal = request.proposal!;
368
+ request.sampling.commitNumbers(spans.get(row)!);
369
+ row.fed.push(...spans.get(row)!);
370
+ const next = proposal.value.ids[proposal.emitted + length];
371
+ const real = row.generated + length < row.req.maxTokens;
372
+ nextKnown.push(next !== undefined); nextReal.push(real);
373
+ row.sampled = row.generated + length + Number(real);
374
+ return next;
375
+ });
376
+ const needScores = rows.some((_row, index) => nextReal[index] && !nextKnown[index]);
377
+ using last = needScores ? hidden.slice([0, length - 1, 0], [B, length, hidden.shape[2]!]) : null;
378
+ using logits = last ? this.#dispatch.logits(B)(last) : null;
379
+ const tokens: MlxArray[] = [];
380
+ let next: MlxArray | null = null;
381
+ try {
382
+ for (const [index, row] of rows.entries()) {
383
+ if (!nextReal[index] || nextKnown[index]) tokens.push(ops.fromInt32([selected[index] ?? 0], [1]));
384
+ else {
385
+ using slice = logits!.slice([index, 0, 0], [index + 1, 1, logits!.shape[2]!]);
386
+ using scores = ops.reshape(slice, [1, slice.shape[2]!]);
387
+ tokens.push(this.#requests.get(row)!.sampling.sample(scores, row.generated + length).token);
388
+ }
389
+ }
390
+ next = ops.concatAxis(tokens, 0);
391
+ if (needScores) ops.asyncEvalAll([next]);
392
+ else withResource(leaseCacheStates(this.#target!.caches), state => ops.asyncEvalAll([hidden, ...state]));
393
+ this.#pending!.dispose(); this.#pending = next; next = null;
394
+ this.#known = nextKnown; this.#real = nextReal;
395
+ } finally { next?.dispose(); disposeResources(tokens); }
396
+ for (let column = 0; column < length && this.host.rows.length; column++) {
397
+ const active = [...this.host.rows];
398
+ await this.#emitRows(active.map(row => spans.get(row)![column]!), active.map(() => true));
399
+ }
400
+ if (++this.#steps % 256 === 0) clearCache();
401
+ }
402
+
403
+ async #emit(row: Row, token: number, known: boolean): Promise<"stop" | "length" | undefined> {
404
+ row.req.signal?.throwIfAborted();
405
+ const request = this.#requests.get(row)!;
406
+ if (row.req.eosTokenIds.includes(token)) return "stop";
407
+ // Account a known token even when the consumer stops on this token.
408
+ if (known) {
409
+ const proposal = request.proposal!;
410
+ if (++proposal.emitted === proposal.value.ids.length) {
411
+ request.fill.commit(proposal.value, proposal.emitted); request.proposal = undefined;
412
+ }
413
+ }
414
+ if (!known) {
415
+ const proposal = request.fill.push(token, row.req.maxTokens - row.generated);
416
+ if (proposal) {
417
+ request.proposal = { value: proposal, emitted: 0 };
418
+ }
419
+ }
420
+ const more = await this.host.publish(row, token);
421
+ if (more === false) return "stop";
422
+ if (row.generated >= row.req.maxTokens) return "length";
423
+ row.current = token;
424
+ }
425
+
426
+ async #emitRows(values: number[], known: readonly boolean[]): Promise<void> {
427
+ const rows = [...this.host.rows], keep: number[] = [];
428
+ const replacement = new Map<number, number>();
429
+ for (let index = 0; index < rows.length; index++) {
430
+ const row = rows[index]!;
431
+ row.generated++;
432
+ try {
433
+ const reason = await this.#emit(row, values[index]!, known[index] ?? false);
434
+ if (reason) {
435
+ this.#put(row, this.#target!.extractRow(index));
436
+ this.#settleProposal(row); this.host.finish(row, reason);
437
+ } else {
438
+ keep.push(index);
439
+ const request = this.#requests.get(row)!;
440
+ if (!known[index] && request.proposal?.value.policy === "assert" && this.#pending) {
441
+ replacement.set(index, request.proposal.value.ids[0]!);
442
+ request.fill.noteWastedSample(); this.#known[index] = true;
443
+ }
444
+ }
445
+ } catch (error) { row.reject(error); }
446
+ }
447
+ if (replacement.size) {
448
+ const parts: MlxArray[] = [];
449
+ try {
450
+ for (let index = 0; index < rows.length; index++) parts.push(replacement.has(index)
451
+ ? ops.fromInt32([replacement.get(index)!], [1]) : this.#pending!.slice([index], [index + 1]));
452
+ const next = ops.concatAxis(parts, 0); this.#pending!.dispose(); this.#pending = next;
453
+ } finally { disposeResources(parts); }
454
+ }
455
+ if (keep.length !== rows.length) this.host.filterRows(keep);
456
+ }
457
+
458
+ async #flush(): Promise<void> {
459
+ const pending = this.#pending, known = this.#known;
460
+ if (!pending) return;
461
+ this.#pending = null; this.#known = []; this.#real = [];
462
+ let values: number[];
463
+ try { values = pending.toIntTokens(); } finally { pending.dispose(); }
464
+ await this.#emitRows(values, known);
465
+ }
466
+
467
+ #put(row: Row, caches: Cache[], retain?: () => void): void {
468
+ try {
469
+ if (this.host.cache.keeps(row.req) && !row.fedTainted && !row.req.signal?.aborted) {
470
+ this.host.cache.publish(row.req, row.cacheNamespace ?? "", [...row.req.promptIds, ...row.fed], { caches, retain });
471
+ caches = []; retain = undefined;
472
+ }
473
+ } finally { disposeResources([...caches, { dispose: () => retain?.() }]); }
474
+ }
475
+
476
+ #settleProposal(row: Row): void {
477
+ const request = this.#requests.get(row);
478
+ if (request?.proposal) {
479
+ const proposal = request.proposal; request.proposal = undefined;
480
+ request.fill.commit(proposal.value, proposal.emitted);
481
+ }
482
+ }
483
+ #closeRequest(row: Row): void {
484
+ this.#settleProposal(row);
485
+ const request = this.#requests.get(row); this.#requests.delete(row); request?.sampling.dispose();
486
+ }
487
+ filterRows(keep: readonly number[], _discard: boolean): void {
488
+ if (this.#pending) {
489
+ // The last row can leave while a token is pipelined: no rows, no index array.
490
+ let next: MlxArray | null = null;
491
+ if (keep.length) { using indices = ops.fromInt32([...keep], [keep.length]); next = ops.takeAxis(this.#pending, indices, 0); }
492
+ this.#pending.dispose(); this.#pending = next;
493
+ }
494
+ this.#known = keep.map(index => this.#known[index]!); this.#real = keep.map(index => this.#real[index]!);
495
+ this.#target?.filterRows(keep);
496
+ const retained = new Set(keep.map(index => this.host.rows[index]!));
497
+ for (const row of this.host.rows) if (!retained.has(row)) this.#closeRequest(row);
498
+ }
499
+ dispose(): void {
500
+ const pending = this.#pending, target = this.#target;
501
+ this.#pending = null; this.#target = null;
502
+ disposeResources([...(pending ? [pending] : []), ...(target ? [target] : []),
503
+ { dispose: () => { for (const row of this.#requests.keys()) this.#closeRequest(row); } }]);
504
+ }
505
+ }