@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,135 @@
1
+ import type { MlxArray } from "@mlx-bun/mlx/array";
2
+ import type { Glm52WeightSource } from "../../contracts/mlx/glm52-weights";
3
+ import { ColibriGlm52Container } from "./container";
4
+ import { ColibriGlm52Weights } from "./weights";
5
+
6
+ const ROUTED_EXPERT = /\.mlp\.experts\.\d+\./;
7
+
8
+ /**
9
+ * Dense/shared/router-only view of the direct Colibri artifact. Even if an
10
+ * owning safetensors shard also contains routed tensors, this boundary refuses
11
+ * their names so the streamed model cannot silently fall back to mmap.
12
+ */
13
+ export class ColibriGlm52ResidentWeights implements Glm52WeightSource {
14
+ readonly container: ColibriGlm52Container;
15
+ readonly weightsBytes: number;
16
+ readonly source: ColibriGlm52Weights;
17
+ readonly #allowed: ReadonlySet<string>;
18
+
19
+ private constructor(
20
+ container: ColibriGlm52Container,
21
+ source: ColibriGlm52Weights,
22
+ allowed: ReadonlySet<string>,
23
+ weightsBytes: number,
24
+ ) {
25
+ this.container = container;
26
+ this.source = source;
27
+ this.#allowed = allowed;
28
+ this.weightsBytes = weightsBytes;
29
+ }
30
+
31
+ static open(
32
+ modelDir: string,
33
+ options: { includeMtp?: boolean } = {},
34
+ ): ColibriGlm52ResidentWeights {
35
+ const container = ColibriGlm52Container.open(modelDir);
36
+ const names = [...container.tensors.values()]
37
+ .filter((tensor) =>
38
+ (options.includeMtp !== false || tensor.family !== "mtp") &&
39
+ !ROUTED_EXPERT.test(tensor.name))
40
+ .map((tensor) => tensor.name);
41
+ const allowed = new Set(names);
42
+ const weightsBytes = names.reduce(
43
+ (total, name) => total + container.info(name).byteLength,
44
+ 0,
45
+ );
46
+ const source = ColibriGlm52Weights.openSelected(modelDir, names);
47
+ return new ColibriGlm52ResidentWeights(
48
+ container,
49
+ source,
50
+ allowed,
51
+ weightsBytes,
52
+ );
53
+ }
54
+
55
+ get mappedShardCount(): number {
56
+ return this.source.mappedShardCount;
57
+ }
58
+
59
+ get mappedShardBytes(): number {
60
+ return this.source.mappedShardBytes;
61
+ }
62
+
63
+ has(name: string): boolean {
64
+ return this.#allowed.has(name);
65
+ }
66
+
67
+ tensor(name: string): MlxArray {
68
+ this.#check(name);
69
+ return this.source.tensor(name);
70
+ }
71
+
72
+ dequantized(
73
+ name: string,
74
+ outputRows: number,
75
+ inputColumns: number,
76
+ ): MlxArray {
77
+ this.#check(name);
78
+ return this.source.dequantized(name, outputRows, inputColumns);
79
+ }
80
+
81
+ linear(
82
+ input: MlxArray,
83
+ name: string,
84
+ outputRows: number,
85
+ inputColumns: number,
86
+ ): MlxArray {
87
+ this.#check(name);
88
+ const info = this.container.info(name);
89
+ const descriptor = info.dtype === "U8"
90
+ ? this.source.quantized(name, outputRows, inputColumns)
91
+ : null;
92
+ if (name === "lm_head.weight" && descriptor?.bits === 8) {
93
+ return this.source.linearInt8Tiled(
94
+ input,
95
+ name,
96
+ outputRows,
97
+ inputColumns,
98
+ );
99
+ }
100
+ if (
101
+ descriptor?.bits === 4 &&
102
+ inputColumns >= 32 &&
103
+ inputColumns % 32 === 0
104
+ ) {
105
+ return this.source.linearQ4(
106
+ input,
107
+ name,
108
+ outputRows,
109
+ inputColumns,
110
+ );
111
+ }
112
+ return this.source.linear(input, name, outputRows, inputColumns);
113
+ }
114
+
115
+ embedding(
116
+ ids: MlxArray,
117
+ name: string,
118
+ vocabSize: number,
119
+ hiddenSize: number,
120
+ ): MlxArray {
121
+ this.#check(name);
122
+ return this.source.embeddingRows(ids, name, vocabSize, hiddenSize);
123
+ }
124
+
125
+ dispose(): void {
126
+ this.source.dispose();
127
+ }
128
+
129
+ #check(name: string): void {
130
+ if (ROUTED_EXPERT.test(name))
131
+ throw new Error(`${name}: routed experts require the slab residency backend`);
132
+ if (!this.#allowed.has(name))
133
+ throw new Error(`${name}: tensor is outside the resident GLM weight set`);
134
+ }
135
+ }
@@ -0,0 +1,503 @@
1
+ // Direct MLX tensor source for Colibri's out-*.safetensors artifact.
2
+ //
3
+ // The container catalog supplies logical tensor geometry and exact file
4
+ // ownership. Native MLX keeps each shard's tensors lazy. G2 uses an explicit
5
+ // dequantize→f32 matmul reference path; G3 replaces routed-expert materializing
6
+ // with the aligned slab/custom-Metal path without changing the model graph.
7
+
8
+ import { ptr, read } from "bun:ffi";
9
+ import { statSync } from "node:fs";
10
+ import { MlxArray, cpuStream, gpuStream } from "@mlx-bun/mlx/array";
11
+ import { C, Dtype, synchronize } from "@mlx-bun/mlx/ffi";
12
+ import * as ops from "@mlx-bun/mlx/ops";
13
+ import {
14
+ ColibriGlm52Container,
15
+ type ColibriQuantTensorInfo,
16
+ } from "./container";
17
+
18
+ const cstr = (value: string): Buffer => Buffer.from(`${value}\0`, "utf8");
19
+
20
+ /**
21
+ * Colibri writes four-bit weights as consecutive bytes (two input columns per
22
+ * byte). MLX's affine dequantizer expects the same nibbles packed into uint32
23
+ * words. Repack lazily with MLX ops so the direct artifact never round-trips
24
+ * through a 100s-of-MiB JS buffer.
25
+ */
26
+ function packInt4BytesForMlx(
27
+ raw: MlxArray,
28
+ outputRows: number,
29
+ inputColumns: number,
30
+ ): MlxArray {
31
+ const rowBytes = Math.ceil(inputColumns / 2);
32
+ const words = Math.ceil(rowBytes / 4);
33
+ let bytes = ops.reshape(raw, [outputRows, rowBytes]);
34
+ const paddedBytes = words * 4;
35
+ if (paddedBytes !== rowBytes) {
36
+ const padding = ops.zeros(
37
+ [outputRows, paddedBytes - rowBytes],
38
+ Dtype.uint8,
39
+ );
40
+ const padded = ops.concatAxis([bytes, padding], 1);
41
+ bytes.dispose();
42
+ padding.dispose();
43
+ bytes = padded;
44
+ }
45
+ const lanes = ops.reshape(bytes, [outputRows, words, 4]);
46
+ bytes.dispose();
47
+ let packed = ops.zeros([outputRows, words], Dtype.uint32);
48
+ for (let lane = 0; lane < 4; lane++) {
49
+ const view = lanes.slice(
50
+ [0, 0, lane],
51
+ [outputRows, words, lane + 1],
52
+ );
53
+ const flat = ops.reshape(view, [outputRows, words]);
54
+ view.dispose();
55
+ const word = flat.astype(Dtype.uint32);
56
+ flat.dispose();
57
+ const shiftI32 = MlxArray.fromInt32(new Int32Array([lane * 8]), []);
58
+ const shift = shiftI32.astype(Dtype.uint32);
59
+ shiftI32.dispose();
60
+ const shifted = ops.leftShift(word, shift);
61
+ word.dispose();
62
+ shift.dispose();
63
+ const next = ops.bitwiseOr(packed, shifted);
64
+ packed.dispose();
65
+ shifted.dispose();
66
+ packed = next;
67
+ }
68
+ lanes.dispose();
69
+ return packed;
70
+ }
71
+
72
+ export class ColibriGlm52Weights {
73
+ readonly container: ColibriGlm52Container;
74
+ readonly weightsBytes: number;
75
+ readonly #maps = new Map<string, bigint>();
76
+ readonly #arrays = new Map<string, MlxArray>();
77
+
78
+ private constructor(container: ColibriGlm52Container) {
79
+ this.container = container;
80
+ this.weightsBytes = container.files.reduce(
81
+ (total, file) => total + statSync(file.path).size,
82
+ 0,
83
+ );
84
+ }
85
+
86
+ static #openFiles(
87
+ container: ColibriGlm52Container,
88
+ paths: ReadonlySet<string>,
89
+ ): ColibriGlm52Weights {
90
+ const self = new ColibriGlm52Weights(container);
91
+ try {
92
+ for (const { path } of self.container.files) {
93
+ if (!paths.has(path)) continue;
94
+ const arraysOut = new BigUint64Array([C.mlx_map_string_to_array_new()]);
95
+ const metadataOut = new BigUint64Array([C.mlx_map_string_to_string_new()]);
96
+ const arraysPtr = ptr(arraysOut);
97
+ const metadataPtr = ptr(metadataOut);
98
+ const status = C.mlx_load_safetensors(
99
+ arraysPtr,
100
+ metadataPtr,
101
+ ptr(cstr(path)),
102
+ cpuStream,
103
+ );
104
+ const metadata = read.u64(metadataPtr, 0);
105
+ C.mlx_map_string_to_string_free(metadata);
106
+ const arrays = read.u64(arraysPtr, 0);
107
+ if (status !== 0) {
108
+ C.mlx_map_string_to_array_free(arrays);
109
+ throw new Error(`mlx_load_safetensors(${path}) failed`);
110
+ }
111
+ self.#maps.set(path, arrays);
112
+ }
113
+ return self;
114
+ } catch (error) {
115
+ self.dispose();
116
+ throw error;
117
+ }
118
+ }
119
+
120
+ static open(modelDir: string): ColibriGlm52Weights {
121
+ const container = ColibriGlm52Container.open(modelDir);
122
+ return ColibriGlm52Weights.#openFiles(
123
+ container,
124
+ new Set(container.files.map(({ path }) => path)),
125
+ );
126
+ }
127
+
128
+ /**
129
+ * Open only the shards that own `tensorNames`.
130
+ *
131
+ * This is an explicit probe/tooling seam, not a partial-model constructor.
132
+ * Quantized callers must include both the packed tensor and its `.qs`
133
+ * companion. Accessing any catalogued tensor in an unopened shard fails.
134
+ */
135
+ static openSelected(
136
+ modelDir: string,
137
+ tensorNames: readonly string[],
138
+ ): ColibriGlm52Weights {
139
+ if (tensorNames.length === 0)
140
+ throw new Error("selected Colibri weights require at least one tensor");
141
+ const container = ColibriGlm52Container.open(modelDir);
142
+ const paths = new Set(tensorNames.map((name) => container.info(name).file));
143
+ return ColibriGlm52Weights.#openFiles(container, paths);
144
+ }
145
+
146
+ get mappedShardCount(): number {
147
+ return this.#maps.size;
148
+ }
149
+
150
+ get mappedShardBytes(): number {
151
+ let total = 0;
152
+ for (const path of this.#maps.keys()) total += statSync(path).size;
153
+ return total;
154
+ }
155
+
156
+ has(name: string): boolean {
157
+ return this.container.has(name);
158
+ }
159
+
160
+ tensor(name: string): MlxArray {
161
+ let array = this.#arrays.get(name);
162
+ if (array) return array;
163
+ const info = this.container.info(name);
164
+ const map = this.#maps.get(info.file);
165
+ if (map === undefined)
166
+ throw new Error(`${name}: shard ${info.file} is not open`);
167
+ const out = new BigUint64Array([C.mlx_array_new()]);
168
+ const outPtr = ptr(out);
169
+ if (C.mlx_map_string_to_array_get(outPtr, map, ptr(cstr(name))) !== 0)
170
+ throw new Error(`${name}: missing from native safetensors map`);
171
+ array = new MlxArray(read.u64(outPtr, 0));
172
+ this.#arrays.set(name, array);
173
+ return array;
174
+ }
175
+
176
+ quantized(name: string, outputRows: number, inputColumns: number): ColibriQuantTensorInfo {
177
+ return this.container.quantized(name, outputRows, inputColumns);
178
+ }
179
+
180
+ /**
181
+ * Materialize the logical [output,input] tensor as f32.
182
+ *
183
+ * This is intentionally the slow correctness path. Colibri int4 is
184
+ * offset-binary (`nibble - 8`); int8 is signed two's-complement. Neither is
185
+ * inferred from config.quantization_config, which still describes the
186
+ * pre-conversion FP8 checkpoint.
187
+ */
188
+ dequantized(name: string, outputRows: number, inputColumns: number): MlxArray {
189
+ const descriptor = this.quantized(name, outputRows, inputColumns);
190
+ const raw = this.tensor(name);
191
+ const scaleRaw = this.tensor(`${name}.qs`);
192
+ const groups = descriptor.groupSize === null
193
+ ? 1
194
+ : Math.ceil(inputColumns / descriptor.groupSize);
195
+ let scales = ops.reshape(scaleRaw, [outputRows, groups]);
196
+
197
+ if (descriptor.bits === 4) {
198
+ // MLX only instantiates affine-dequant Metal kernels for its supported
199
+ // quantization group sizes. Colibri's ordinary Q4 tensors carry one
200
+ // scale for the complete row, which would otherwise request kernels such
201
+ // as `gs_6144`. Repeating that same scale over 32-value groups is exactly
202
+ // value-preserving and selects MLX's production-supported kernel.
203
+ let dequantGroupSize = descriptor.groupSize ?? inputColumns;
204
+ if (
205
+ descriptor.groupSize === null &&
206
+ inputColumns > 32 &&
207
+ inputColumns % 32 === 0
208
+ ) {
209
+ dequantGroupSize = 32;
210
+ const expandedGroups = inputColumns / dequantGroupSize;
211
+ const zeroGroups = ops.zeros(
212
+ [outputRows, expandedGroups],
213
+ Dtype.float32,
214
+ );
215
+ const expandedScales = ops.add(scales, zeroGroups);
216
+ scales.dispose();
217
+ zeroGroups.dispose();
218
+ scales = expandedScales;
219
+ }
220
+ const packed = packInt4BytesForMlx(raw, outputRows, inputColumns);
221
+ const minusEight = ops.mulScalar(scales, -8);
222
+ const dequant = ops.dequantize(
223
+ packed,
224
+ scales,
225
+ minusEight,
226
+ {
227
+ bits: 4,
228
+ groupSize: dequantGroupSize,
229
+ mode: "affine",
230
+ },
231
+ );
232
+ packed.dispose();
233
+ scales.dispose();
234
+ minusEight.dispose();
235
+ // MLX's packed shape can round the final lane for odd logical widths.
236
+ // Full GLM dimensions are even; fixtures may deliberately exercise odd
237
+ // tails through the host reference implementation instead.
238
+ if (dequant.shape[1] !== inputColumns) {
239
+ const sliced = dequant.slice([0, 0], [outputRows, inputColumns]);
240
+ dequant.dispose();
241
+ return sliced;
242
+ }
243
+ return dequant;
244
+ }
245
+
246
+ const bytes = ops.reshape(raw, [outputRows, inputColumns]);
247
+ // Colibri stores the byte view of int8. Casting uint8→int8 restores the
248
+ // two's-complement value before conversion to f32.
249
+ const signed = bytes.astype(Dtype.int8);
250
+ const values = signed.astype(Dtype.float32);
251
+ const out = ops.mul(values, scales);
252
+ bytes.dispose();
253
+ signed.dispose();
254
+ values.dispose();
255
+ scales.dispose();
256
+ return out;
257
+ }
258
+
259
+ /** Reference f32-MAC linear: x[...,I] × W[O,I]^T. */
260
+ linear(
261
+ x: MlxArray,
262
+ name: string,
263
+ outputRows: number,
264
+ inputColumns: number,
265
+ ): MlxArray {
266
+ const weights = this.dequantized(name, outputRows, inputColumns);
267
+ const transposed = ops.transposeAxes(weights, [1, 0]);
268
+ const xf32 = x.dtype === Dtype.float32 ? x : x.astype(Dtype.float32);
269
+ const out = ops.matmul(xf32, transposed);
270
+ if (xf32 !== x) xf32.dispose();
271
+ transposed.dispose();
272
+ weights.dispose();
273
+ return out;
274
+ }
275
+
276
+ /**
277
+ * MLX affine-Q4 linear for the streamed resident spine.
278
+ *
279
+ * Colibri stores already-packed nibbles but exposes them as uint8. Packing
280
+ * those bytes into MLX's uint32 view is still far smaller than expanding the
281
+ * complete matrix to f32, and preserves the exact `(nibble - 8) * scale`
282
+ * affine values.
283
+ */
284
+ linearQ4(
285
+ x: MlxArray,
286
+ name: string,
287
+ outputRows: number,
288
+ inputColumns: number,
289
+ ): MlxArray {
290
+ const descriptor = this.quantized(name, outputRows, inputColumns);
291
+ if (descriptor.bits !== 4)
292
+ throw new Error(`${name}: Q4 linear requires four-bit weights`);
293
+ const raw = this.tensor(name);
294
+ const scaleRaw = this.tensor(`${name}.qs`);
295
+ const groups = descriptor.groupSize === null
296
+ ? 1
297
+ : Math.ceil(inputColumns / descriptor.groupSize);
298
+ let scales = ops.reshape(scaleRaw, [outputRows, groups]);
299
+ let groupSize = descriptor.groupSize ?? inputColumns;
300
+ if (descriptor.groupSize === null && inputColumns > 32) {
301
+ if (inputColumns % 32 !== 0)
302
+ throw new Error(`${name}: per-row Q4 width must be divisible by 32`);
303
+ groupSize = 32;
304
+ const zeros = ops.zeros(
305
+ [outputRows, inputColumns / groupSize],
306
+ Dtype.float32,
307
+ );
308
+ const expanded = ops.add(scales, zeros);
309
+ scales.dispose();
310
+ zeros.dispose();
311
+ scales = expanded;
312
+ }
313
+ const packed = packInt4BytesForMlx(raw, outputRows, inputColumns);
314
+ const biases = ops.mulScalar(scales, -8);
315
+ const xf32 = x.dtype === Dtype.float32 ? x : x.astype(Dtype.float32);
316
+ const output = ops.quantizedMatmul(
317
+ xf32,
318
+ packed,
319
+ scales,
320
+ biases,
321
+ { bits: 4, groupSize, mode: "affine" },
322
+ true,
323
+ );
324
+ if (xf32 !== x) xf32.dispose();
325
+ packed.dispose();
326
+ scales.dispose();
327
+ biases.dispose();
328
+ return output;
329
+ }
330
+
331
+ /**
332
+ * G2 reference embedding lookup. This intentionally materializes the
333
+ * checkpoint-native quantized table through the same exact dequantizer as
334
+ * linear weights; G3 replaces the full-table materialization with a
335
+ * row-gather path.
336
+ */
337
+ embedding(
338
+ ids: MlxArray,
339
+ name: string,
340
+ vocabSize: number,
341
+ hiddenSize: number,
342
+ ): MlxArray {
343
+ const table = this.dequantized(name, vocabSize, hiddenSize);
344
+ const out = ops.takeAxis(table, ids, 0);
345
+ table.dispose();
346
+ return out;
347
+ }
348
+
349
+ /**
350
+ * Gather only the requested embedding rows before dequantization.
351
+ *
352
+ * The production GLM table is signed int8 and expands to ~3.8 GiB as f32.
353
+ * The streamed path must never create that full-table transient merely to
354
+ * read a handful of token rows.
355
+ */
356
+ embeddingRows(
357
+ ids: MlxArray,
358
+ name: string,
359
+ vocabSize: number,
360
+ hiddenSize: number,
361
+ ): MlxArray {
362
+ const descriptor = this.quantized(name, vocabSize, hiddenSize);
363
+ const rowCount = ids.shape.reduce((product, value) => product * value, 1);
364
+ const flatIds = ops.reshape(ids, [rowCount]);
365
+ const raw = this.tensor(name);
366
+ const scaleRaw = this.tensor(`${name}.qs`);
367
+ const groups = descriptor.groupSize === null
368
+ ? 1
369
+ : Math.ceil(hiddenSize / descriptor.groupSize);
370
+ const scaleTable = ops.reshape(scaleRaw, [vocabSize, groups]);
371
+ const selectedScales = ops.takeAxis(scaleTable, flatIds, 0);
372
+ scaleTable.dispose();
373
+ let values: MlxArray | null = null;
374
+ try {
375
+ if (descriptor.bits === 8) {
376
+ const byteTable = ops.reshape(raw, [vocabSize, hiddenSize]);
377
+ const selectedBytes = ops.takeAxis(byteTable, flatIds, 0);
378
+ byteTable.dispose();
379
+ const signed = selectedBytes.astype(Dtype.int8);
380
+ selectedBytes.dispose();
381
+ const f32 = signed.astype(Dtype.float32);
382
+ signed.dispose();
383
+ values = ops.mul(f32, selectedScales);
384
+ f32.dispose();
385
+ } else if (descriptor.bits === 4) {
386
+ const rowBytes = Math.ceil(hiddenSize / 2);
387
+ const byteTable = ops.reshape(raw, [vocabSize, rowBytes]);
388
+ const selectedBytes = ops.takeAxis(byteTable, flatIds, 0);
389
+ byteTable.dispose();
390
+ const packed = packInt4BytesForMlx(
391
+ selectedBytes,
392
+ rowCount,
393
+ hiddenSize,
394
+ );
395
+ selectedBytes.dispose();
396
+ let scales = selectedScales;
397
+ let groupSize = descriptor.groupSize ?? hiddenSize;
398
+ if (
399
+ descriptor.groupSize === null &&
400
+ hiddenSize > 32 &&
401
+ hiddenSize % 32 === 0
402
+ ) {
403
+ groupSize = 32;
404
+ const zeros = ops.zeros(
405
+ [rowCount, hiddenSize / groupSize],
406
+ Dtype.float32,
407
+ );
408
+ scales = ops.add(selectedScales, zeros);
409
+ zeros.dispose();
410
+ }
411
+ const biases = ops.mulScalar(scales, -8);
412
+ values = ops.dequantize(
413
+ packed,
414
+ scales,
415
+ biases,
416
+ { bits: 4, groupSize, mode: "affine" },
417
+ );
418
+ packed.dispose();
419
+ biases.dispose();
420
+ if (scales !== selectedScales) scales.dispose();
421
+ } else {
422
+ throw new Error(`${name}: unsupported embedding width ${descriptor.bits}`);
423
+ }
424
+ return ops.reshape(values, [...ids.shape, hiddenSize]);
425
+ } finally {
426
+ values?.dispose();
427
+ selectedScales.dispose();
428
+ flatIds.dispose();
429
+ }
430
+ }
431
+
432
+ /**
433
+ * Bounded signed-int8 linear used by the streamed production lm_head.
434
+ *
435
+ * Each output-row tile is fully evaluated before the next tile is built, so
436
+ * MLX cannot retain a lazy graph containing the complete f32-expanded head.
437
+ * Concatenation retains only the small materialized logits tiles.
438
+ */
439
+ linearInt8Tiled(
440
+ x: MlxArray,
441
+ name: string,
442
+ outputRows: number,
443
+ inputColumns: number,
444
+ tileRows = 2048,
445
+ ): MlxArray {
446
+ const descriptor = this.quantized(name, outputRows, inputColumns);
447
+ if (descriptor.bits !== 8 || descriptor.groupSize !== null)
448
+ throw new Error(`${name}: tiled linear requires signed per-row int8`);
449
+ if (!Number.isSafeInteger(tileRows) || tileRows < 1)
450
+ throw new RangeError("tiled linear row count must be a positive integer");
451
+
452
+ const byteTable = ops.reshape(
453
+ this.tensor(name),
454
+ [outputRows, inputColumns],
455
+ );
456
+ const scaleTable = ops.reshape(
457
+ this.tensor(`${name}.qs`),
458
+ [outputRows, 1],
459
+ );
460
+ const xf32 = x.dtype === Dtype.float32 ? x : x.astype(Dtype.float32);
461
+ const tiles: MlxArray[] = [];
462
+ try {
463
+ for (let start = 0; start < outputRows; start += tileRows) {
464
+ const stop = Math.min(outputRows, start + tileRows);
465
+ const bytes = byteTable.slice(
466
+ [start, 0],
467
+ [stop, inputColumns],
468
+ );
469
+ const signed = bytes.astype(Dtype.int8);
470
+ bytes.dispose();
471
+ const f32 = signed.astype(Dtype.float32);
472
+ signed.dispose();
473
+ const scales = scaleTable.slice([start, 0], [stop, 1]);
474
+ const weights = ops.mul(f32, scales);
475
+ f32.dispose();
476
+ scales.dispose();
477
+ const transposed = ops.transposeAxes(weights, [1, 0]);
478
+ weights.dispose();
479
+ const output = ops.matmul(xf32, transposed);
480
+ transposed.dispose();
481
+ output.eval();
482
+ synchronize(gpuStream);
483
+ tiles.push(output);
484
+ }
485
+ if (tiles.length === 1) return tiles[0]!;
486
+ return ops.concatAxis(tiles, x.shape.length - 1);
487
+ } finally {
488
+ byteTable.dispose();
489
+ scaleTable.dispose();
490
+ if (xf32 !== x) xf32.dispose();
491
+ if (tiles.length > 1)
492
+ for (const tile of tiles) tile.dispose();
493
+ }
494
+ }
495
+
496
+ dispose(): void {
497
+ for (const array of this.#arrays.values()) array.dispose();
498
+ this.#arrays.clear();
499
+ for (const map of this.#maps.values())
500
+ C.mlx_map_string_to_array_free(map);
501
+ this.#maps.clear();
502
+ }
503
+ }