@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,290 @@
1
+ // Sampling — port of mlx-lm's sample_utils.make_sampler /
2
+ // make_logits_processors (temperature, top-p, top-k, min-p, XTC,
3
+ // repetition/presence/frequency penalties, logit bias).
4
+ // All filtering happens on-device; only the chosen token id crosses to JS.
5
+ // Seeded: each step derives a fresh key from (seed, step) so runs are
6
+ // reproducible without sharing global RNG state. (mlx-lm draws XTC's
7
+ // uniform and the categorical from one global stream; we split the
8
+ // per-step key into (xtc, categorical) subkeys instead — deterministic,
9
+ // and the XTC-off path is unchanged.)
10
+
11
+ import { MlxArray } from "@mlx-bun/mlx/array";
12
+ import * as ops from "@mlx-bun/mlx/ops";
13
+
14
+ /** HLG sampling parameters — a piecewise tone curve on the logprobs.
15
+ * See `02d723a:docs/archive/hlg-sampling.md`. Knobs are in nats (the logprob unit). */
16
+ export interface HlgParams {
17
+ /** m — mid-region slope. Folds temperature: m = 1/temperature. */
18
+ gain: number;
19
+ /** w — half-width of the linear mid region. Infinity ⇒ no rolloff (pure temperature). */
20
+ width: number;
21
+ /** β_h — highlight rolloff scale. ≤ 0 ⇒ no shoulder (highlights stay linear). */
22
+ shoulder: number;
23
+ /** β_t — shadow rolloff scale. ≤ 0 ⇒ no toe (shadows stay linear). */
24
+ toe: number;
25
+ /** pivot (middle grey) placement — changes where the curve centers, hence its
26
+ * shape. "top": μ = max(ℓ) − offset. "entropy": μ = Σp·ℓ = −H (center of mass
27
+ * in tonal space). "median": μ = the logprob at the 50% cumulative-mass
28
+ * boundary (auto-levels). */
29
+ pivot?: "top" | "entropy" | "median";
30
+ /** shift applied to the pivot base: μ = base − pivotOffset. */
31
+ pivotOffset?: number;
32
+ }
33
+
34
+ const HLG_LOG_EPS = 1e-9;
35
+
36
+ /** Pivot (middle grey) μ_base for the tone curve, in logprob units — the same
37
+ * curve, centered three different ways. Operates on the full logprob vector. */
38
+ function hlgPivotBase(
39
+ lp: MlxArray,
40
+ mode: "top" | "entropy" | "median",
41
+ k: <T extends MlxArray>(a: T) => T,
42
+ ): MlxArray {
43
+ if (mode === "entropy") {
44
+ // center of mass in tonal space: μ = Σ p·ℓ = −H (p = exp(ℓ); ℓ are logprobs)
45
+ const probs = k(ops.exp(lp));
46
+ return k(ops.sumAxis(k(ops.mul(probs, lp)), -1, true));
47
+ }
48
+ if (mode === "median") {
49
+ // logprob at the 50% cumulative-mass boundary (auto-levels / histogram median)
50
+ const probs = k(ops.exp(lp));
51
+ const idxDesc = k(ops.argsortAxis(k(ops.neg(lp)), -1)); // ascending of −ℓ = ℓ descending
52
+ const sortedProbs = k(ops.takeAlongAxis(probs, idxDesc, -1));
53
+ const sortedLp = k(ops.takeAlongAxis(lp, idxDesc, -1));
54
+ const cum = k(ops.cumsum(sortedProbs, -1));
55
+ const keep = k(ops.greaterEqual(cum, k(ops.scalarLike(0.5, cum))));
56
+ const masked = k(ops.where(keep, sortedLp, k(ops.scalarLike(-Infinity, sortedLp))));
57
+ return k(ops.maxAxis(masked, -1, true)); // first crossover = max logprob of the ≥0.5 suffix
58
+ }
59
+ return k(ops.maxAxis(lp, -1, true)); // "top": the peak
60
+ }
61
+
62
+ /** Remap logprobs through the centered curve g(z), z = ℓ − μ:
63
+ * toe (z < −w): −m·w − m·β_t·ln(1 + (−z − w)/β_t) gentle shadow rolloff
64
+ * mid (|z| ≤ w): m·z contrast gain
65
+ * shoulder(z > w): m·w + m·β_h·ln(1 + ( z − w)/β_h) highlight rolloff
66
+ * Monotone in ℓ ⇒ ranking-preserving (argmax unchanged). With width = ∞ (or
67
+ * β_h, β_t ≤ 0) it returns mulScalar(lp, m) — temperature T = 1/m — bit-exact
68
+ * by construction (the same op the temperature path uses). `-inf` (masked)
69
+ * tokens map to `-inf`. */
70
+ export function applyHlg(lp: MlxArray, p: HlgParams): MlxArray {
71
+ const m = p.gain;
72
+ const hasShoulder = Number.isFinite(p.width) && p.shoulder > 0;
73
+ const hasToe = Number.isFinite(p.width) && p.toe > 0;
74
+ // No-rolloff regime ≡ temperature: identical op to the temperature sampler.
75
+ if (!hasShoulder && !hasToe) return ops.mulScalar(lp, m);
76
+
77
+ const w = p.width;
78
+ const off = p.pivotOffset ?? 0;
79
+ const tmp: MlxArray[] = [];
80
+ const k = <T extends MlxArray>(a: T): T => {
81
+ tmp.push(a);
82
+ return a;
83
+ };
84
+
85
+ // pivot μ = base(mode) − off ; centered coordinate z = ℓ − μ
86
+ const base = hlgPivotBase(lp, p.pivot ?? "top", k);
87
+ const mu = k(ops.sub(base, k(ops.scalarLike(off, base))));
88
+ const z = k(ops.sub(lp, mu));
89
+ const wC = k(ops.scalarLike(w, lp));
90
+ let g: MlxArray = k(ops.mulScalar(z, m)); // mid: m·z
91
+
92
+ if (hasShoulder) {
93
+ const bh = p.shoulder;
94
+ const inner = k(ops.add(k(ops.scalarLike(1, lp)), k(ops.mulScalar(k(ops.sub(z, wC)), 1 / bh))));
95
+ const clamped = k(ops.maximum(inner, k(ops.scalarLike(HLG_LOG_EPS, lp))));
96
+ const shoulder = k(ops.add(k(ops.scalarLike(m * w, lp)), k(ops.mulScalar(k(ops.log(clamped)), m * bh))));
97
+ g = k(ops.where(k(ops.greaterEqual(z, wC)), shoulder, g));
98
+ }
99
+ if (hasToe) {
100
+ const bt = p.toe;
101
+ const negz = k(ops.neg(z));
102
+ const inner = k(ops.add(k(ops.scalarLike(1, lp)), k(ops.mulScalar(k(ops.sub(negz, wC)), 1 / bt))));
103
+ const clamped = k(ops.maximum(inner, k(ops.scalarLike(HLG_LOG_EPS, lp))));
104
+ const toe = k(ops.sub(k(ops.scalarLike(-m * w, lp)), k(ops.mulScalar(k(ops.log(clamped)), m * bt))));
105
+ g = k(ops.where(k(ops.less(z, k(ops.scalarLike(-w, lp)))), toe, g));
106
+ }
107
+
108
+ for (const a of tmp) if (a !== g) a.dispose();
109
+ return g;
110
+ }
111
+
112
+ // Literal HLG OETF (ARIB STD-B67 / ITU-R BT.2100) — the actual transfer
113
+ // function, exact constants. Input L = p/p_max ∈ (0,1] (exposure-normalized: the
114
+ // top token is reference white). Output V ∈ [0,1]:
115
+ // V = √3 · √L for 0 ≤ L ≤ 1/12 (gamma/sqrt: shadows → 0 softly)
116
+ // V = a·ln(12L − b) + c for 1/12 < L ≤ 1 (log: highlights compressed)
117
+ // We sample ∝ V by feeding log(V) to the categorical draw. Monotone in ℓ ⇒
118
+ // ranking-preserving. No knobs — this is HLG itself.
119
+ const HLG_A = 0.17883277;
120
+ const HLG_B = 0.28466892; // 1 − 4a
121
+ const HLG_C = 0.55991073; // 0.5 − a·ln(4a)
122
+ const HLG_SQRT3 = Math.sqrt(3);
123
+ const HLG_KNEE = 1 / 12;
124
+
125
+ export function applyHlgOetf(lp: MlxArray): MlxArray {
126
+ const tmp: MlxArray[] = [];
127
+ const k = <T extends MlxArray>(a: T): T => {
128
+ tmp.push(a);
129
+ return a;
130
+ };
131
+
132
+ // L = p / p_max = exp(ℓ − ℓmax) ∈ (0, 1]
133
+ const lmax = k(ops.maxAxis(lp, -1, true));
134
+ const L = k(ops.exp(k(ops.sub(lp, lmax))));
135
+
136
+ // lower (L ≤ 1/12): V = √3 · √L
137
+ const lo = k(ops.mulScalar(k(ops.sqrt(L)), HLG_SQRT3));
138
+ // upper (L > 1/12): V = a·ln(12L − b) + c (clamp the arg > 0 for the unused lane)
139
+ const arg = k(ops.maximum(k(ops.sub(k(ops.mulScalar(L, 12)), k(ops.scalarLike(HLG_B, L)))), k(ops.scalarLike(HLG_LOG_EPS, L))));
140
+ const hi = k(ops.add(k(ops.mulScalar(k(ops.log(arg)), HLG_A)), k(ops.scalarLike(HLG_C, L))));
141
+ const V = k(ops.where(k(ops.greaterEqual(L, k(ops.scalarLike(HLG_KNEE, L)))), hi, lo));
142
+
143
+ // sample ∝ V → logits = log(V)
144
+ const out = ops.log(k(ops.maximum(V, k(ops.scalarLike(HLG_LOG_EPS, V)))));
145
+ for (const a of tmp) a.dispose();
146
+ return out;
147
+ }
148
+
149
+ /** OOTF system gamma from nominal peak display luminance L_W (cd/m²).
150
+ * γ = 1.2 + 0.42·log10(L_W/1000); γ = 1.2 exactly at L_W = 1000. */
151
+ export function hlgGammaForLw(lw: number): number {
152
+ return 1.2 + 0.42 * Math.log10(lw / 1000);
153
+ }
154
+
155
+ // Literal HLG EOTF (signal → display linear) = inverse OETF then OOTF — the
156
+ // DECODE direction. Treat p/p_max as the signal E'. The inverse OETF squares the
157
+ // lower half (E = E'²/3) so the tail is SUPPRESSED (the opposite of the OETF,
158
+ // which expands it). The OOTF on a single-"pixel" (grayscale) distribution has
159
+ // no colour channels for luminance to couple, so it reduces exactly to a gamma
160
+ // power law E^γ — i.e. temperature. Sample ∝ E^γ ⇒ logits = γ·log(E).
161
+ export function applyHlgEotf(lp: MlxArray, gamma: number): MlxArray {
162
+ const tmp: MlxArray[] = [];
163
+ const k = <T extends MlxArray>(a: T): T => {
164
+ tmp.push(a);
165
+ return a;
166
+ };
167
+
168
+ const d = k(ops.sub(lp, k(ops.maxAxis(lp, -1, true)))); // ℓ − ℓmax ≤ 0
169
+ const Ep = k(ops.exp(d)); // signal E' = p/p_max ∈ (0, 1]
170
+ // log E from the inverse OETF, computed stably per branch (the deep tail
171
+ // underflows if E is formed directly, so the lower branch stays in log-space):
172
+ // E' ≤ 1/2: E = E'²/3 → log E = 2·(ℓ−ℓmax) − ln3 (exact)
173
+ // E' > 1/2: E = (exp((E'−c)/a)+b)/12 → log E = log(that) (well-conditioned)
174
+ const logElo = k(ops.sub(k(ops.mulScalar(d, 2)), k(ops.scalarLike(Math.log(3), d))));
175
+ const hiArg = k(ops.exp(k(ops.mulScalar(k(ops.sub(Ep, k(ops.scalarLike(HLG_C, Ep)))), 1 / HLG_A))));
176
+ const hiE = k(ops.mulScalar(k(ops.add(hiArg, k(ops.scalarLike(HLG_B, Ep)))), 1 / 12));
177
+ const logEhi = k(ops.log(hiE));
178
+ const logE = k(ops.where(k(ops.greaterEqual(Ep, k(ops.scalarLike(0.5, Ep)))), logEhi, logElo));
179
+ // OOTF (grayscale) → gamma: sample ∝ E^γ ⇒ logits = γ·log(E)
180
+ const out = ops.mulScalar(logE, gamma);
181
+ for (const a of tmp) a.dispose();
182
+ return out;
183
+ }
184
+
185
+ // The FULL HLG chain: OETF signal shape, THEN OOTF scaling.
186
+ // 1. E = p/p_max ∈ (0,1] (top token = the max-brightness reference)
187
+ // 2. E' = √(3E) for E ≤ 1/12 (gamma/√ toe below the knee)
188
+ // = a·ln(12E−b)+c for E > 1/12 (log highlights above the knee)
189
+ // 3. R_d = α · E'^γ (OOTF: α = max brightness, scales everything
190
+ // under it; γ = 1.2+0.42·log10(L_W/1000))
191
+ // R_d are the final logits → categorical. α > 0 ⇒ monotone (ranking preserved).
192
+ export function applyHlgPipeline(lp: MlxArray, alpha: number, gamma: number): MlxArray {
193
+ const tmp: MlxArray[] = [];
194
+ const k = <T extends MlxArray>(a: T): T => {
195
+ tmp.push(a);
196
+ return a;
197
+ };
198
+
199
+ // 1. E = p/p_max ∈ (0,1]
200
+ const E = k(ops.exp(k(ops.sub(lp, k(ops.maxAxis(lp, -1, true))))));
201
+ // 2. OETF: √(3E) below the knee, a·ln(12E−b)+c above
202
+ const lo = k(ops.sqrt(k(ops.mulScalar(E, 3))));
203
+ const arg = k(ops.maximum(k(ops.sub(k(ops.mulScalar(E, 12)), k(ops.scalarLike(HLG_B, E)))), k(ops.scalarLike(HLG_LOG_EPS, E))));
204
+ const hi = k(ops.add(k(ops.mulScalar(k(ops.log(arg)), HLG_A)), k(ops.scalarLike(HLG_C, E))));
205
+ const Eprime = k(ops.where(k(ops.greaterEqual(E, k(ops.scalarLike(HLG_KNEE, E)))), hi, lo));
206
+ // 3. OOTF: R_d = α · E'^γ = α · exp(γ·log E')
207
+ const EpGamma = k(ops.exp(k(ops.mulScalar(k(ops.log(k(ops.maximum(Eprime, k(ops.scalarLike(HLG_LOG_EPS, Eprime)))))), gamma))));
208
+ const out = ops.mulScalar(EpGamma, alpha);
209
+ for (const a of tmp) a.dispose();
210
+ return out;
211
+ }
212
+
213
+ // ── User-specified HLGShaper (windowed-anchor input) ────────────────────────
214
+ // logit → windowed-anchor signal x∈[0,1] (top W nats span the curve; min-max
215
+ // over the 262k vocab dumped every candidate into the shoulder, so we anchor at
216
+ // the top instead) → piecewise OETF (log shoulder above x_m, power mid, CUBIC
217
+ // toe that suppresses to 0) → OOTF (normalize to peak, ^γ) → ×out_scale →
218
+ // softmax. Geometry constants derived once from the default knobs, exactly as
219
+ // HLGShaper.__init__ does (cubic toe coeffs from a 2×2 solve).
220
+ export interface HlgShaperParams {
221
+ lw?: number; // L_W (cd/m²) → OOTF γ
222
+ outScale?: number; // explicit override; default auto-derived from targetGap/refGap
223
+ targetGap?: number; // desired top-1-to-reference final-logit gap (sets sharpness, W-independent)
224
+ refGap?: number; // reference token sits this many nats below the top
225
+ window?: number; // W: nats below the top spanning the curve
226
+ xM?: number; yM?: number; xFloor?: number; yFloor?: number; p?: number;
227
+ sM?: number; // mid sharpness — how hard above-median tokens are elevated
228
+ A?: number; // shoulder compression — how hard confidence is tamed
229
+ }
230
+
231
+ export function applyHlgShaper(lp: MlxArray, opts: HlgShaperParams = {}): MlxArray {
232
+ const lw = opts.lw ?? 1200, window = opts.window ?? 10;
233
+ const xM = opts.xM ?? 0.55, yM = opts.yM ?? 0.5, xFloor = opts.xFloor ?? 0.2, yFloor = opts.yFloor ?? 0.18;
234
+ const p = opts.p ?? 2.0, sM = opts.sM ?? 0.7, A = opts.A ?? 0.35;
235
+ const targetGap = opts.targetGap ?? 15, refGap = opts.refGap ?? 4;
236
+ // geometry derived per call (cheap scalar math), exactly as HLGShaper.__init__
237
+ const dxf = xM - xFloor;
238
+ const kc = (yM - sM * dxf - yFloor) / Math.pow(dxf, p); // mid reaches y_floor
239
+ const sFloor = sM + kc * p * Math.pow(dxf, p - 1); // mid slope at the toe join
240
+ const det = -Math.pow(xFloor, 4); // solve [[xf³,xf²],[3xf²,2xf]]·[e,f]=[y_floor,s_floor]
241
+ const ec = (yFloor * (2 * xFloor) - xFloor ** 2 * sFloor) / det;
242
+ const fc = (xFloor ** 3 * sFloor - yFloor * (3 * xFloor ** 2)) / det;
243
+ const yPeak = yM + A * Math.log(1 + (sM / A) * (1 - xM));
244
+ const gamma = 1.2 + 0.42 * Math.log10(Math.max(lw, 1e-3) / 1000);
245
+
246
+ // out_scale AUTO-derived so the top-1-to-reference final-logit gap = targetGap,
247
+ // INDEPENDENT of W — decouples the two knobs so W is a clean 1-D sweep. The
248
+ // reference token sits refGap nats below the top; its post-shape value is the
249
+ // scalar curve evaluated in JS (no device cost). Calibrated so W=5 ⇒ os ≈ 18.
250
+ const oetfS = (xx: number): number => {
251
+ let yy: number;
252
+ if (xx >= xM) yy = yM + A * Math.log(Math.max(1 + (sM / A) * (xx - xM), 1e-9));
253
+ else if (xx >= xFloor) yy = yM - sM * (xM - xx) - kc * Math.pow(Math.max(xM - xx, 0), p);
254
+ else yy = ec * xx ** 3 + fc * xx ** 2;
255
+ return Math.max(yy, 0);
256
+ };
257
+ const shapeS = (xx: number): number => Math.pow(Math.max(oetfS(xx) / yPeak, 1e-9), gamma);
258
+ const xRef = Math.max(0, Math.min(1, 1 - refGap / window));
259
+ const outScale = opts.outScale ?? targetGap / Math.max(1e-6, 1 - shapeS(xRef));
260
+
261
+ const tmp: MlxArray[] = [];
262
+ const k = <T extends MlxArray>(a: T): T => {
263
+ tmp.push(a);
264
+ return a;
265
+ };
266
+ const C = (v: number, like: MlxArray): MlxArray => k(ops.scalarLike(v, like));
267
+
268
+ // x = clamp((ℓ − ℓmax)/W + 1, 0, 1) — windowed anchor at the top
269
+ const lmax = k(ops.maxAxis(lp, -1, true));
270
+ const x = k(ops.clip(k(ops.add(k(ops.mulScalar(k(ops.sub(lp, lmax)), 1 / window)), C(1, lp))), C(0, lp), C(1, lp)));
271
+
272
+ // OETF: up (x≥x_m) log shoulder, mid power, toe (x<x_floor) cubic suppress
273
+ const upArg = k(ops.maximum(k(ops.add(C(1, x), k(ops.mulScalar(k(ops.sub(x, C(xM, x))), sM / A)))), C(1e-9, x)));
274
+ const up = k(ops.add(C(yM, x), k(ops.mulScalar(k(ops.log(upArg)), A))));
275
+ const dm = k(ops.sub(C(xM, x), x));
276
+ const dmPow = k(ops.exp(k(ops.mulScalar(k(ops.log(k(ops.maximum(dm, C(1e-9, x))))), p))));
277
+ const mid = k(ops.sub(k(ops.sub(C(yM, x), k(ops.mulScalar(dm, sM)))), k(ops.mulScalar(dmPow, kc))));
278
+ const x2 = k(ops.square(x));
279
+ const x3 = k(ops.mul(x, x2));
280
+ const toe = k(ops.add(k(ops.mulScalar(x3, ec)), k(ops.mulScalar(x2, fc))));
281
+ const upMid = k(ops.where(k(ops.greaterEqual(x, C(xM, x))), up, mid));
282
+ const y = k(ops.maximum(k(ops.where(k(ops.greaterEqual(x, C(xFloor, x))), upMid, toe)), C(0, x)));
283
+
284
+ // OOTF: r = (max(y/y_peak, 1e-9))^γ ; then softmax(r · out_scale)
285
+ const yn = k(ops.maximum(k(ops.mulScalar(y, 1 / yPeak)), C(1e-9, y)));
286
+ const r = k(ops.exp(k(ops.mulScalar(k(ops.log(yn)), gamma))));
287
+ const out = ops.mulScalar(r, outScale);
288
+ for (const a of tmp) a.dispose();
289
+ return out;
290
+ }
@@ -0,0 +1,9 @@
1
+ export * from "./types";
2
+ export * from "./filters";
3
+ export * from "./hlg";
4
+ export * from "./processors";
5
+ export * from "./step";
6
+ export * from "./extras";
7
+ export * from "./sampler";
8
+ export * from "./grammar";
9
+ export * from "./curve";
@@ -0,0 +1,142 @@
1
+ // Sampling — port of mlx-lm's sample_utils.make_sampler /
2
+ // make_logits_processors (temperature, top-p, top-k, min-p, XTC,
3
+ // repetition/presence/frequency penalties, logit bias).
4
+ // All filtering happens on-device; only the chosen token id crosses to JS.
5
+ // Seeded: each step derives a fresh key from (seed, step) so runs are
6
+ // reproducible without sharing global RNG state. (mlx-lm draws XTC's
7
+ // uniform and the categorical from one global stream; we split the
8
+ // per-step key into (xtc, categorical) subkeys instead — deterministic,
9
+ // and the XTC-off path is unchanged.)
10
+
11
+ import { MlxArray } from "@mlx-bun/mlx/array";
12
+ import * as ops from "@mlx-bun/mlx/ops";
13
+ import { LogitsProcessor,LogitsProcessorOptions } from "./types";
14
+
15
+ /** Start of the recent-token window, matching Python's `tokens[-context_size:]`
16
+ * slice semantics exactly (context_size 0 ⇒ `[-0:]` ⇒ the WHOLE history). */
17
+ function windowStart(n: number, contextSize: number): number {
18
+ return contextSize === 0 ? 0 : Math.max(0, n - contextSize);
19
+ }
20
+
21
+ /** Retain only tokens an enabled processor can inspect. Bias uses no history.
22
+ * Zero-sized windows mean unlimited history, matching Python's [-0:]. */
23
+ export function logitsHistoryLimit(options: LogitsProcessorOptions): number {
24
+ let limit = 0;
25
+ for (const [penalty, context = 20] of [
26
+ [options.repetitionPenalty, options.repetitionContextSize],
27
+ [options.presencePenalty, options.presenceContextSize],
28
+ [options.frequencyPenalty, options.frequencyContextSize],
29
+ ]) {
30
+ if (penalty === undefined || penalty === 0) continue;
31
+ // Preserve existing processor behavior for unusual programmatic values.
32
+ if (!Number.isSafeInteger(context) || context <= 0) return Infinity;
33
+ limit = Math.max(limit, context);
34
+ }
35
+ return limit;
36
+ }
37
+
38
+ export function makeLogitsProcessors(opts: LogitsProcessorOptions = {}): LogitsProcessor[] {
39
+ const out: LogitsProcessor[] = [];
40
+ const {
41
+ logitBias,
42
+ repetitionPenalty, repetitionContextSize = 20,
43
+ presencePenalty, presenceContextSize = 20,
44
+ frequencyPenalty, frequencyContextSize = 20,
45
+ } = opts;
46
+
47
+ // logit_bias first, as in mlx-lm's make_logits_processors. Reference:
48
+ // `logits.at[:, indices].add(values)` — dict keys are unique, so a
49
+ // gather → add → put round-trip is exactly equivalent to the scatter-add.
50
+ const biasIds = logitBias ? Object.keys(logitBias).map(Number) : [];
51
+ if (logitBias && biasIds.length > 0) {
52
+ const biasVals = Float32Array.from(biasIds.map((id) => logitBias[id]!));
53
+ out.push((_tokens, logits) => {
54
+ const K = biasIds.length;
55
+ const idx = ops.fromInt32(biasIds, [1, K]);
56
+ const vals32 = MlxArray.fromFloat32(biasVals, [1, K]);
57
+ const vals = vals32.astype(logits.dtype);
58
+ const selected = ops.takeAlongAxis(logits, idx, -1);
59
+ const biased = ops.add(selected, vals);
60
+ const updated = ops.putAlongAxis(logits, idx, biased, -1);
61
+ for (const a of [idx, vals32, vals, selected, biased]) a.dispose();
62
+ return updated;
63
+ });
64
+ }
65
+
66
+ if (repetitionPenalty !== undefined && repetitionPenalty !== 0) {
67
+ if (repetitionPenalty < 0)
68
+ throw new Error("repetitionPenalty must be non-negative");
69
+ out.push((tokens, logits) => {
70
+ if (!tokens) return logits;
71
+ const n = tokens.shape[0]!;
72
+ if (n === 0) return logits;
73
+ const start = windowStart(n, repetitionContextSize);
74
+ const recent = tokens.slice([start], [n]);
75
+ const idx = ops.reshape(recent, [1, n - start]);
76
+ const selected = ops.takeAlongAxis(logits, idx, -1);
77
+ const zero = ops.scalarLike(0, selected);
78
+ const isNeg = ops.less(selected, zero);
79
+ const timesP = ops.mulScalar(selected, repetitionPenalty);
80
+ const pen = ops.scalarLike(repetitionPenalty, selected);
81
+ const overP = ops.div(selected, pen);
82
+ const penalized = ops.where(isNeg, timesP, overP);
83
+ const updated = ops.putAlongAxis(logits, idx, penalized, -1);
84
+ for (const a of [recent, idx, selected, zero, isNeg, timesP, pen, overP, penalized])
85
+ a.dispose();
86
+ return updated;
87
+ });
88
+ }
89
+
90
+ // make_presence_penalty: `logits[:, tokens] -= penalty` — a plain
91
+ // fancy-index assignment, so duplicate occurrences all write the SAME
92
+ // value (original − penalty): the penalty applies once per distinct token.
93
+ if (presencePenalty !== undefined && presencePenalty !== 0) {
94
+ out.push((tokens, logits) => {
95
+ if (!tokens) return logits;
96
+ const n = tokens.shape[0]!;
97
+ if (n === 0) return logits;
98
+ const start = windowStart(n, presenceContextSize);
99
+ const recent = tokens.slice([start], [n]);
100
+ const idx = ops.reshape(recent, [1, n - start]);
101
+ const selected = ops.takeAlongAxis(logits, idx, -1);
102
+ const pen = ops.scalarLike(presencePenalty, selected);
103
+ const penalized = ops.sub(selected, pen);
104
+ const updated = ops.putAlongAxis(logits, idx, penalized, -1);
105
+ for (const a of [recent, idx, selected, pen, penalized]) a.dispose();
106
+ return updated;
107
+ });
108
+ }
109
+
110
+ // make_frequency_penalty: `logits.at[:, tokens].subtract(penalty)` — a
111
+ // scatter-subtract that ACCUMULATES over duplicates: each token loses
112
+ // penalty × (occurrence count in the window). We compute the count per
113
+ // position ([m,m] equality matrix summed over a row — m ≤ contextSize, tiny)
114
+ // so every duplicate writes the identical final value and a put_along_axis
115
+ // reproduces the scatter-accumulate exactly.
116
+ if (frequencyPenalty !== undefined && frequencyPenalty !== 0) {
117
+ out.push((tokens, logits) => {
118
+ if (!tokens) return logits;
119
+ const n = tokens.shape[0]!;
120
+ if (n === 0) return logits;
121
+ const start = windowStart(n, frequencyContextSize);
122
+ const m = n - start;
123
+ const recent = tokens.slice([start], [n]);
124
+ const col = ops.reshape(recent, [m, 1]);
125
+ const idx = ops.reshape(recent, [1, m]);
126
+ const eq = ops.equal(col, idx); // [m, m]
127
+ const counts = ops.sumAxis(eq, -1, false); // [m] occurrences of tokens[i]
128
+ const countsF = counts.astype(logits.dtype);
129
+ const countsRow = ops.reshape(countsF, [1, m]);
130
+ const selected = ops.takeAlongAxis(logits, idx, -1);
131
+ const pen = ops.scalarLike(frequencyPenalty, selected);
132
+ const penTotal = ops.mul(countsRow, pen); // penalty × count
133
+ const penalized = ops.sub(selected, penTotal);
134
+ const updated = ops.putAlongAxis(logits, idx, penalized, -1);
135
+ for (const a of [recent, col, idx, eq, counts, countsF, countsRow, selected, pen, penTotal, penalized])
136
+ a.dispose();
137
+ return updated;
138
+ });
139
+ }
140
+
141
+ return out;
142
+ }
@@ -0,0 +1,120 @@
1
+ // Sampling — port of mlx-lm's sample_utils.make_sampler /
2
+ // make_logits_processors (temperature, top-p, top-k, min-p, XTC,
3
+ // repetition/presence/frequency penalties, logit bias).
4
+ // All filtering happens on-device; only the chosen token id crosses to JS.
5
+ // Seeded: each step derives a fresh key from (seed, step) so runs are
6
+ // reproducible without sharing global RNG state. (mlx-lm draws XTC's
7
+ // uniform and the categorical from one global stream; we split the
8
+ // per-step key into (xtc, categorical) subkeys instead — deterministic,
9
+ // and the XTC-off path is unchanged.)
10
+
11
+ import { MlxArray } from "@mlx-bun/mlx/array";
12
+ import * as ops from "@mlx-bun/mlx/ops";
13
+ import { applyCurve } from "./curve";
14
+ import { applyMinP,applyTopK,applyTopP,applyXtc } from "./filters";
15
+ import { HlgParams,applyHlg,applyHlgEotf,applyHlgOetf,applyHlgPipeline,applyHlgShaper,hlgGammaForLw } from "./hlg";
16
+ import { Sampler,SamplerOptions } from "./types";
17
+
18
+ const GOLDEN = 0x9e3779b97f4a7c15n;
19
+
20
+ /** The seeded per-step key: (seed, step) mixed by the golden-ratio constant. Also
21
+ * the derivation behind KeyStream (draft.ts). */
22
+ export function stepKey(seed: number, step: number): MlxArray {
23
+ const mixed = (BigInt(seed) ^ ((BigInt(step) + 1n) * GOLDEN)) & 0xffffffffffffffffn;
24
+ return ops.randomKey(mixed);
25
+ }
26
+
27
+ export function makeSampler(opts: SamplerOptions = {}): Sampler {
28
+ const {
29
+ temperature = 0, topP = 0, topK = 0, minP = 0, minTokensToKeep = 1,
30
+ xtcProbability = 0, xtcThreshold = 0, xtcSpecialTokens = [],
31
+ seed = 0, hlg, curve,
32
+ } = opts;
33
+
34
+ // v2 curve sampler: the drawn log-prob transfer curve REPLACES temperature +
35
+ // softmax. Stochastic and seeded by design (the curve IS the sampling shape),
36
+ // so it overrides the greedy default — the designer wants variety across N.
37
+ if (curve) {
38
+ return (lp, step) => {
39
+ const shaped = applyCurve(lp, curve);
40
+ const tok = ops.randomCategorical(shaped, stepKey(seed, step));
41
+ shaped.dispose();
42
+ return tok;
43
+ };
44
+ }
45
+
46
+ // Greedy: HLG is a no-op (a monotone curve cannot move the argmax), so the
47
+ // greedy path is untouched whether or not HLG is enabled.
48
+ if (temperature === 0)
49
+ return (lp) => ops.argmaxAxis(lp, -1);
50
+
51
+ // HLG is a REPLACEMENT sampler: when enabled, the tone curve IS the whole
52
+ // post-logits step — its toe does the tail control that top_p/top_k would, so
53
+ // they are NOT applied. Otherwise we do exactly what we used to: top_p, top_k,
54
+ // then temperature scaling. (Temperature still folds into the mid gain m = 1/T
55
+ // unless the config sets an explicit gain.)
56
+ if (hlg?.enabled === true) {
57
+ const useOetf = hlg.oetf === true;
58
+ const useEotf = hlg.eotf === true;
59
+ const usePipeline = hlg.pipeline === true;
60
+ const eotfGamma = hlgGammaForLw(hlg.lw ?? 1000);
61
+ const alpha = hlg.maxBrightness ?? 5;
62
+ const params: HlgParams = {
63
+ gain: hlg.gain ?? 1 / temperature,
64
+ width: hlg.width,
65
+ shoulder: hlg.shoulder,
66
+ toe: hlg.toe,
67
+ pivot: hlg.pivot,
68
+ pivotOffset: hlg.pivotOffset,
69
+ };
70
+ return (lp, step) => {
71
+ const scaled = hlg.shaper === true
72
+ ? applyHlgShaper(lp, { lw: hlg.lw, outScale: hlg.maxBrightness, window: hlg.window, sM: hlg.sM, A: hlg.shoulderA, targetGap: hlg.targetGap, refGap: hlg.refGap, xM: hlg.xM, yM: hlg.yM, xFloor: hlg.xFloor, yFloor: hlg.yFloor, p: hlg.p })
73
+ : usePipeline ? applyHlgPipeline(lp, alpha, eotfGamma)
74
+ : useEotf ? applyHlgEotf(lp, eotfGamma) : useOetf ? applyHlgOetf(lp) : applyHlg(lp, params);
75
+ const key = stepKey(seed, step);
76
+ const tok = ops.randomCategorical(scaled, key);
77
+ scaled.dispose();
78
+ key.dispose();
79
+ return tok;
80
+ };
81
+ }
82
+
83
+ // Filter chain order matches mlx-lm's make_sampler: top_p → min_p → xtc →
84
+ // top_k, then categorical(logprobs / temperature).
85
+ return (lp, step) => {
86
+ let cur = lp;
87
+ const owned: MlxArray[] = [];
88
+ let key = stepKey(seed, step);
89
+ if (topP > 0 && topP < 1) { cur = applyTopP(cur, topP); owned.push(cur); }
90
+ if (minP !== 0) { cur = applyMinP(cur, minP, minTokensToKeep); owned.push(cur); }
91
+ if (xtcProbability > 0) {
92
+ // Split the step key: subkey 0 → XTC's uniform, subkey 1 → categorical.
93
+ const split = ops.randomSplitNum(key, 2);
94
+ const row0 = split.slice([0, 0], [1, 2]);
95
+ const row1 = split.slice([1, 0], [2, 2]);
96
+ const xtcKey = ops.reshape(row0, [2]);
97
+ key.dispose();
98
+ key = ops.reshape(row1, [2]);
99
+ for (const a of [split, row0, row1]) a.dispose();
100
+ cur = applyXtc(cur, xtcProbability, xtcThreshold, xtcSpecialTokens, xtcKey);
101
+ owned.push(cur);
102
+ xtcKey.dispose();
103
+ }
104
+ if (topK > 0) { cur = applyTopK(cur, topK); owned.push(cur); }
105
+ const scaled = ops.mulScalar(cur, 1 / temperature);
106
+ const tok = ops.randomCategorical(scaled, key);
107
+ scaled.dispose();
108
+ key.dispose();
109
+ for (const a of owned) a.dispose();
110
+ return tok;
111
+ };
112
+ }
113
+
114
+ /** logits [..., V] → logprobs [..., V] (logits - logsumexp). */
115
+ export function toLogprobs(logits: MlxArray): MlxArray {
116
+ const lse = ops.logsumexpAxis(logits, -1, true);
117
+ const out = ops.sub(logits, lse);
118
+ lse.dispose();
119
+ return out;
120
+ }