mlx-bun 0.5.0 → 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 (640) hide show
  1. package/README.md +1449 -109
  2. package/THIRD_PARTY_NOTICES.md +882 -0
  3. package/bin/mlx-bun.convert.mjs +4 -0
  4. package/bin/mlx-bun.fuse.mjs +4 -0
  5. package/bin/mlx-bun.generate.mjs +4 -0
  6. package/bin/mlx-bun.lora.mjs +4 -0
  7. package/bin/mlx-bun.mjs +13 -21
  8. package/bin/mlx-bun.server.mjs +4 -0
  9. package/bin/mlx-bun.upload.mjs +4 -0
  10. package/dist/web/app.js +9584 -0
  11. package/package.json +50 -53
  12. package/src/cli/ane-install.ts +76 -0
  13. package/src/cli/args.ts +179 -0
  14. package/src/cli/engine-entry.ts +68 -0
  15. package/src/cli/inference.ts +214 -0
  16. package/src/cli/job-entry.ts +97 -0
  17. package/src/cli/library-host.ts +117 -0
  18. package/src/cli/main.ts +57 -0
  19. package/src/cli/memory-engine.ts +163 -0
  20. package/src/cli/memory.ts +36 -0
  21. package/src/cli/mlx-lm-aliases.ts +309 -0
  22. package/src/cli/model-choice.ts +33 -0
  23. package/src/cli/model-selection.ts +84 -0
  24. package/src/cli/module-host.ts +11 -0
  25. package/src/cli/module-verbs.ts +50 -0
  26. package/src/cli/numerical-policy.ts +12 -0
  27. package/src/cli/perplexity.ts +89 -0
  28. package/src/cli/serve-host.ts +423 -0
  29. package/src/cli/serve-isolated.ts +217 -0
  30. package/src/cli/serve-options.ts +106 -0
  31. package/src/cli/serve-state.ts +205 -0
  32. package/src/cli/serve.ts +500 -0
  33. package/src/cli/served-model-host.ts +102 -0
  34. package/src/cli/server-entry.ts +148 -0
  35. package/src/cli/serving-unit.ts +177 -0
  36. package/src/{tui.ts → cli/terminal.ts} +13 -8
  37. package/src/cli/worker-adapters.ts +34 -0
  38. package/src/cli/worker-entry.ts +272 -0
  39. package/src/cli/worker-unit.ts +179 -0
  40. package/src/engine/adapter-operation.ts +26 -0
  41. package/src/engine/cache-services.ts +114 -0
  42. package/src/engine/completion.ts +39 -0
  43. package/src/engine/generation-gateway.ts +358 -0
  44. package/src/engine/index.ts +59 -0
  45. package/src/engine/kv-budget.ts +120 -0
  46. package/src/engine/media-preparation.ts +232 -0
  47. package/src/engine/model-binding.ts +24 -0
  48. package/src/engine/model-host.ts +513 -0
  49. package/src/engine/model-serving.ts +89 -0
  50. package/src/{serve → engine}/preparation.ts +7 -5
  51. package/src/{serve → engine}/session-completion-engine.ts +6 -6
  52. package/src/engine/telemetry.ts +109 -0
  53. package/src/hub/downloads.ts +116 -0
  54. package/src/jobs/db.ts +16 -7
  55. package/src/jobs/events.ts +29 -0
  56. package/src/jobs/executable.ts +5 -0
  57. package/src/jobs/host.ts +51 -0
  58. package/src/jobs/in-process.ts +55 -0
  59. package/src/{contracts/jobs.ts → jobs/protocol.ts} +7 -9
  60. package/src/jobs/runner.ts +150 -231
  61. package/src/jobs/service.ts +75 -0
  62. package/src/jobs/sse.ts +59 -23
  63. package/src/jobs/worker-memory.ts +46 -0
  64. package/src/jobs/worker-process.ts +163 -0
  65. package/src/jobs/worker-supervisor.ts +258 -0
  66. package/src/modules.ts +58 -0
  67. package/src/publishing/catalog-hub.ts +18 -0
  68. package/src/publishing/credentials.ts +31 -0
  69. package/src/publishing/upload.ts +37 -0
  70. package/src/residency/leased-adapters.ts +21 -0
  71. package/src/residency/local-records.ts +16 -0
  72. package/src/residency/model-residency.ts +405 -0
  73. package/src/residency/record-index.ts +28 -0
  74. package/src/residency/resident-estimate.ts +50 -0
  75. package/src/{anthropic.ts → server/anthropic.ts} +3 -81
  76. package/src/server/cache-routes.ts +36 -0
  77. package/src/{serve → server}/chat-request.ts +10 -10
  78. package/src/{serve → server}/chat-stage.ts +14 -14
  79. package/src/{client.ts → server/client.ts} +28 -2
  80. package/src/{serve → server}/completion-executor.ts +33 -41
  81. package/src/server/decision-body.ts +55 -0
  82. package/src/server/decision-routes.ts +134 -0
  83. package/src/server/decision-wire.ts +228 -0
  84. package/src/{serve → server}/discovery-routes.ts +25 -82
  85. package/src/{serve → server}/http.ts +25 -13
  86. package/src/{serve → server}/inference-request.ts +5 -5
  87. package/src/server/job-routes.ts +20 -0
  88. package/src/server/media-prompt.ts +63 -0
  89. package/src/server/memory-completion-client.ts +46 -0
  90. package/src/server/model-routes.ts +192 -0
  91. package/src/{serve → server}/openai-wire.ts +3 -2
  92. package/src/{serve → server}/pipeline.ts +1 -1
  93. package/src/server/prompt-builder.ts +13 -0
  94. package/src/server/prompt-contracts.ts +17 -0
  95. package/src/server/proxy-routes.ts +187 -0
  96. package/src/server/publishing-routes.ts +41 -0
  97. package/src/{serve → server}/request-plan.ts +6 -8
  98. package/src/{serve → server}/request-prep.ts +47 -50
  99. package/src/{serve → server}/responses-client.ts +30 -13
  100. package/src/{responses.ts → server/responses.ts} +12 -93
  101. package/src/server/routes.ts +205 -0
  102. package/src/server/start.ts +72 -0
  103. package/src/server/status-routes.ts +108 -0
  104. package/src/{serve → server}/text-completion-stage.ts +25 -4
  105. package/src/server/text-prompt.ts +12 -0
  106. package/src/{serve → server}/token-streams.ts +36 -38
  107. package/src/server/worker-routes.ts +311 -0
  108. package/src/storage/paths.ts +61 -0
  109. package/src/web/assets.ts +37 -0
  110. package/src/web/{src → browser}/api.ts +5 -23
  111. package/src/web/browser/chat-host.ts +17 -0
  112. package/src/web/browser/installed-panels.ts +6 -0
  113. package/src/web/browser/main.ts +55 -0
  114. package/src/web/browser/markdown.ts +279 -0
  115. package/src/web/browser/memory-panel.ts +9 -0
  116. package/src/web/browser/palette.ts +64 -0
  117. package/src/web/browser/protocol.ts +13 -0
  118. package/src/web/browser/shell.ts +467 -0
  119. package/src/web/{src → browser}/status.ts +32 -36
  120. package/src/web/build.ts +51 -0
  121. package/src/web/public/app.html +1054 -0
  122. package/src/web/{sw.js → public/sw.js} +4 -3
  123. package/src/web/{vendor → public/vendor}/hljs-theme.css +2 -2
  124. package/src/web/{vendor → public/vendor}/hljs.js +2 -2
  125. package/THIRD_PARTY_LICENSES.md +0 -51
  126. package/docs/README.md +0 -107
  127. package/docs/archive/hlg-sampling.md +0 -350
  128. package/docs/archive/investigations/audio-input-plan.md +0 -356
  129. package/docs/archive/investigations/benchmark-ledger-through-v0.4.0.md +0 -3617
  130. package/docs/archive/investigations/chunk-finetune-experiment.md +0 -84
  131. package/docs/archive/investigations/colibri-glm52-port.md +0 -1486
  132. package/docs/archive/investigations/colibri-oracle-pin.md +0 -1284
  133. package/docs/archive/investigations/curve-bisector-routing.md +0 -123
  134. package/docs/archive/investigations/decode-roofline-lookagain.md +0 -348
  135. package/docs/archive/investigations/diffusion-gemma-port.md +0 -602
  136. package/docs/archive/investigations/dspark-handoff.md +0 -224
  137. package/docs/archive/investigations/expert-offload-single-user-moe.md +0 -292
  138. package/docs/archive/investigations/faithful-l1-consolidation.md +0 -310
  139. package/docs/archive/investigations/hlg-sampling-investigation.md +0 -970
  140. package/docs/archive/investigations/indexshare-performance-spike.md +0 -357
  141. package/docs/archive/investigations/kernel-perf-review-2026-07.md +0 -171
  142. package/docs/archive/investigations/lab-build-journal.md +0 -157
  143. package/docs/archive/investigations/minicpm5-decode-megakernel.md +0 -489
  144. package/docs/archive/investigations/openjarvis-fit.md +0 -198
  145. package/docs/archive/investigations/openwiki-evaluation.md +0 -249
  146. package/docs/archive/investigations/optimization_plan.md +0 -346
  147. package/docs/archive/investigations/orpo-base-uf-experiment-and-directions.md +0 -120
  148. package/docs/archive/investigations/orpo-flash-cce-pin-leak.md +0 -167
  149. package/docs/archive/investigations/orpo-uf-testing-handoff.md +0 -126
  150. package/docs/archive/investigations/pareto-specialized-runtime-findings.md +0 -92
  151. package/docs/archive/investigations/pi-builtin-investigation.md +0 -308
  152. package/docs/archive/investigations/pre-colibri-stabilization.md +0 -329
  153. package/docs/archive/investigations/qwen38-27b-campaign-log.md +0 -1092
  154. package/docs/archive/investigations/segmented-backward-handoff.md +0 -148
  155. package/docs/archive/investigations/starter-model-port-handoff.md +0 -342
  156. package/docs/archive/investigations/steel-flash-cce-handoff.md +0 -489
  157. package/docs/archive/investigations/the-dreaming-handoff.md +0 -141
  158. package/docs/archive/investigations/trainer-validation-experiment.md +0 -173
  159. package/docs/archive/planning/chat-ui-vision-memory-first.md +0 -199
  160. package/docs/archive/planning/chat-ui-vision.md +0 -50
  161. package/docs/archive/planning/chunk-task-roadmap.md +0 -77
  162. package/docs/archive/planning/curve-sampler-research-plan.md +0 -331
  163. package/docs/archive/planning/journal.md +0 -316
  164. package/docs/archive/planning/memory-docs-and-dag-plan.md +0 -194
  165. package/docs/archive/planning/pi-integration-review.md +0 -178
  166. package/docs/archive/planning/release-notes-v0.0.10.md +0 -57
  167. package/docs/archive/planning/release-notes-v0.0.11.md +0 -239
  168. package/docs/archive/planning/release-notes-v0.0.12.md +0 -80
  169. package/docs/archive/planning/release-notes-v0.0.13.md +0 -77
  170. package/docs/archive/planning/release-notes-v0.0.9.md +0 -122
  171. package/docs/archive/planning/release-notes-v0.2.0.md +0 -49
  172. package/docs/archive/planning/release-notes-v0.3.0.md +0 -35
  173. package/docs/archive/planning/release-notes-v0.4.0.md +0 -45
  174. package/docs/archive/planning/release-notes-v0.5.0.md +0 -37
  175. package/docs/archive/planning/web-ui-pass-plan.md +0 -213
  176. package/docs/archive/planning/website-readme-pass-plan.md +0 -224
  177. package/docs/design/batching.md +0 -2054
  178. package/docs/design/decode-speed-program.md +0 -2404
  179. package/docs/design/dreaming-nightly-pipeline.md +0 -684
  180. package/docs/design/generic-model-support.md +0 -821
  181. package/docs/design/kv-cache.md +0 -993
  182. package/docs/design/orpo-training.md +0 -680
  183. package/docs/design/speculative-decoding.md +0 -2129
  184. package/docs/design/turboquant.md +0 -2225
  185. package/docs/design/unified-engine-frontier-plan.md +0 -1987
  186. package/docs/design/web-chat-redesign.md +0 -695
  187. package/docs/planning/PRODUCT_ROADMAP.md +0 -593
  188. package/docs/planning/ResearchTopics.md +0 -119
  189. package/docs/planning/public-readiness-handoff.md +0 -244
  190. package/docs/planning/public-readiness.md +0 -149
  191. package/docs/planning/video-series.md +0 -421
  192. package/docs/reference/benchmarks.md +0 -3587
  193. package/docs/reference/cli.md +0 -646
  194. package/docs/reference/distribution.md +0 -380
  195. package/docs/reference/environment.md +0 -494
  196. package/docs/reference/glossary.md +0 -39
  197. package/docs/reference/library-api.md +0 -688
  198. package/docs/reference/memory.md +0 -260
  199. package/docs/reference/models.md +0 -346
  200. package/docs/reference/server-api.md +0 -1945
  201. package/docs/reference/server-config.md +0 -973
  202. package/docs/reference/training.md +0 -462
  203. package/docs/reference/troubleshooting.md +0 -158
  204. package/src/admission-plan.ts +0 -18
  205. package/src/audio/audiotoolbox.ts +0 -112
  206. package/src/audio/conformer.ts +0 -655
  207. package/src/audio/decode.ts +0 -133
  208. package/src/audio/features.ts +0 -202
  209. package/src/audio/mic-capture.ts +0 -98
  210. package/src/audio/silero-vad.ts +0 -379
  211. package/src/audio/transcode.ts +0 -67
  212. package/src/audio/whisper-decode.ts +0 -774
  213. package/src/audio/whisper-fast.ts +0 -732
  214. package/src/audio/whisper-format.ts +0 -73
  215. package/src/audio/whisper-mel.ts +0 -185
  216. package/src/audio/whisper-timing.ts +0 -274
  217. package/src/audio/whisper-tokenizer.ts +0 -239
  218. package/src/audio/whisper-transcribe.ts +0 -410
  219. package/src/backends/mlx/assistant-target.ts +0 -46
  220. package/src/backends/mlx/autoregressive-draft-rows.ts +0 -120
  221. package/src/backends/mlx/autoregressive.ts +0 -129
  222. package/src/backends/mlx/batch-group.ts +0 -1874
  223. package/src/backends/mlx/cache-attachment.ts +0 -67
  224. package/src/backends/mlx/cache-layout.ts +0 -31
  225. package/src/backends/mlx/checkpoint-state.ts +0 -53
  226. package/src/backends/mlx/continuation-persistence.ts +0 -107
  227. package/src/backends/mlx/continuation-request.ts +0 -43
  228. package/src/backends/mlx/continuation.ts +0 -77
  229. package/src/backends/mlx/diffusion.ts +0 -39
  230. package/src/backends/mlx/draft-target.ts +0 -32
  231. package/src/backends/mlx/encoder-cache.ts +0 -25
  232. package/src/backends/mlx/evaluation.ts +0 -105
  233. package/src/backends/mlx/fill-append.ts +0 -58
  234. package/src/backends/mlx/fill-group.ts +0 -497
  235. package/src/backends/mlx/full-kv-row-append.ts +0 -32
  236. package/src/backends/mlx/full-kv-row-donor.ts +0 -54
  237. package/src/backends/mlx/full-transitioning-kv-rows.ts +0 -65
  238. package/src/backends/mlx/gateway-binding.ts +0 -174
  239. package/src/backends/mlx/graph.ts +0 -38
  240. package/src/backends/mlx/kv-codec.ts +0 -9
  241. package/src/backends/mlx/kv-maintenance.ts +0 -161
  242. package/src/backends/mlx/kv-tensor-rows.ts +0 -212
  243. package/src/backends/mlx/memory-client.ts +0 -189
  244. package/src/backends/mlx/methods.ts +0 -90
  245. package/src/backends/mlx/mixed-iteration.ts +0 -62
  246. package/src/backends/mlx/model-prompt.ts +0 -178
  247. package/src/backends/mlx/model-serving.ts +0 -80
  248. package/src/backends/mlx/paged-cache-codec.ts +0 -27
  249. package/src/backends/mlx/prefill-cohort.ts +0 -100
  250. package/src/backends/mlx/prefill-policy.ts +0 -26
  251. package/src/backends/mlx/prefill-rows.ts +0 -244
  252. package/src/backends/mlx/prefill.ts +0 -33
  253. package/src/backends/mlx/projected-context-rows.ts +0 -72
  254. package/src/backends/mlx/prompt-input.ts +0 -29
  255. package/src/backends/mlx/qwen-prompt-input.ts +0 -40
  256. package/src/backends/mlx/request-policy.ts +0 -20
  257. package/src/backends/mlx/request-state-policy.ts +0 -54
  258. package/src/backends/mlx/rollback.ts +0 -92
  259. package/src/backends/mlx/row-sampling.ts +0 -49
  260. package/src/backends/mlx/serial-executor.ts +0 -251
  261. package/src/backends/mlx/speculative-group.ts +0 -438
  262. package/src/backends/mlx/speculative-round.ts +0 -161
  263. package/src/backends/mlx/speculative.ts +0 -131
  264. package/src/backends/mlx/state-rows.ts +0 -104
  265. package/src/backends/mlx/state-views.ts +0 -46
  266. package/src/backends/mlx/target-layout-capability.ts +0 -35
  267. package/src/backends/mlx/text-engine.ts +0 -73
  268. package/src/backends/mlx/transitioning-kv-rows.ts +0 -173
  269. package/src/chat-template.ts +0 -382
  270. package/src/cli.ts +0 -3490
  271. package/src/config.ts +0 -399
  272. package/src/contracts/completion.ts +0 -16
  273. package/src/contracts/execution.ts +0 -70
  274. package/src/contracts/generation.ts +0 -103
  275. package/src/contracts/host.ts +0 -7
  276. package/src/contracts/object-cache.ts +0 -8
  277. package/src/contracts/pi-provider.ts +0 -30
  278. package/src/contracts/pi.ts +0 -261
  279. package/src/contracts/prefix-cache.ts +0 -33
  280. package/src/contracts/resources.ts +0 -25
  281. package/src/contracts/sampling.ts +0 -23
  282. package/src/contracts/scheduling.ts +0 -54
  283. package/src/contracts/tsconfig.json +0 -14
  284. package/src/dataset/generators.ts +0 -1087
  285. package/src/dataset/index.ts +0 -12
  286. package/src/dataset/job.ts +0 -81
  287. package/src/dataset/llm.ts +0 -71
  288. package/src/dataset/registry.ts +0 -528
  289. package/src/diffusion/diffusion-generate.ts +0 -507
  290. package/src/download.ts +0 -505
  291. package/src/embed.ts +0 -77
  292. package/src/engine/admission.ts +0 -59
  293. package/src/engine/cancellation.ts +0 -38
  294. package/src/engine/engine.ts +0 -56
  295. package/src/engine/execution-coordinator.ts +0 -70
  296. package/src/engine/execution-plan.ts +0 -64
  297. package/src/engine/execution-tasks.ts +0 -44
  298. package/src/engine/namespaced-cache.ts +0 -13
  299. package/src/engine/resources.ts +0 -53
  300. package/src/engine/scheduler.ts +0 -92
  301. package/src/engine/session.ts +0 -247
  302. package/src/eval/README.md +0 -130
  303. package/src/eval/ifeval.ts +0 -81
  304. package/src/eval/kl-prompts.ts +0 -29
  305. package/src/eval/kl.ts +0 -590
  306. package/src/eval/perplexity.ts +0 -164
  307. package/src/eval/quality-db.ts +0 -92
  308. package/src/eval/reference-logits.ts +0 -207
  309. package/src/eval/runner.ts +0 -124
  310. package/src/eval/score.ts +0 -49
  311. package/src/eval/tasks/bfcl.ts +0 -535
  312. package/src/eval/tasks/gsm8k.ts +0 -98
  313. package/src/eval/tasks/hashhop.ts +0 -139
  314. package/src/eval/tasks/humaneval.ts +0 -275
  315. package/src/eval/tasks/ifeval.ts +0 -525
  316. package/src/eval/tasks/mmlu.ts +0 -157
  317. package/src/eval/ultrafeedback.ts +0 -60
  318. package/src/evaldb.ts +0 -199
  319. package/src/expert-io.ts +0 -393
  320. package/src/expert-offload-build.ts +0 -77
  321. package/src/expert-offload.ts +0 -76
  322. package/src/expert-residency.ts +0 -1134
  323. package/src/expert-usage.ts +0 -415
  324. package/src/fill/echo-index.ts +0 -188
  325. package/src/fill/fill-session.ts +0 -463
  326. package/src/fill/proposal.ts +0 -68
  327. package/src/fill/schema-rows.ts +0 -506
  328. package/src/fill/tool-boundary.ts +0 -103
  329. package/src/fit.ts +0 -249
  330. package/src/generate.ts +0 -1352
  331. package/src/grammar.ts +0 -604
  332. package/src/harness-pi.ts +0 -184
  333. package/src/hf-push.ts +0 -628
  334. package/src/hub-rest.ts +0 -242
  335. package/src/index.ts +0 -63
  336. package/src/inference/denoising.ts +0 -17
  337. package/src/inference/draft-acceptance.ts +0 -41
  338. package/src/inference/draft-output.ts +0 -49
  339. package/src/inference/graph.ts +0 -33
  340. package/src/inference/prefill.ts +0 -45
  341. package/src/inference/rollback.ts +0 -7
  342. package/src/jobs/index.ts +0 -31
  343. package/src/jobs/job-entry.ts +0 -107
  344. package/src/jobs/task-client.ts +0 -19
  345. package/src/jobs/types.ts +0 -2
  346. package/src/kv-scheme.ts +0 -279
  347. package/src/kv-store.ts +0 -1135
  348. package/src/lab/README.md +0 -22
  349. package/src/lab/curve/curve-designer.html +0 -303
  350. package/src/lab/curve/curve-sampler.ts +0 -122
  351. package/src/lab/expert-trace/expert-trace.ts +0 -69
  352. package/src/lab/paged-kv/paged-attention.ts +0 -117
  353. package/src/lab/paged-kv/paged-kv-rows.ts +0 -111
  354. package/src/lab/paged-kv/paged-kv.ts +0 -336
  355. package/src/library.ts +0 -40
  356. package/src/lora.ts +0 -408
  357. package/src/md-modules.d.ts +0 -54
  358. package/src/media-fetch.ts +0 -442
  359. package/src/memory/article.ts +0 -558
  360. package/src/memory/chunk-validation.ts +0 -150
  361. package/src/memory/chunk.ts +0 -318
  362. package/src/memory/cluster.ts +0 -351
  363. package/src/memory/coverage.ts +0 -134
  364. package/src/memory/crosslink.ts +0 -0
  365. package/src/memory/db.ts +0 -253
  366. package/src/memory/entity.ts +0 -203
  367. package/src/memory/gate.ts +0 -187
  368. package/src/memory/history.ts +0 -152
  369. package/src/memory/ingest.ts +0 -335
  370. package/src/memory/model.ts +0 -183
  371. package/src/memory/normalize.ts +0 -671
  372. package/src/memory/parse.ts +0 -22
  373. package/src/memory/pipeline.ts +0 -275
  374. package/src/memory/prompts.ts +0 -65
  375. package/src/memory/query.ts +0 -334
  376. package/src/memory/reconcile.ts +0 -734
  377. package/src/memory/redirect.ts +0 -108
  378. package/src/memory/reindex.ts +0 -325
  379. package/src/memory/resolve.ts +0 -307
  380. package/src/memory/rest.ts +0 -245
  381. package/src/memory/route.ts +0 -272
  382. package/src/memory/schedule.ts +0 -165
  383. package/src/memory/stages.ts +0 -777
  384. package/src/memory/synthesize.ts +0 -1638
  385. package/src/memory/tools.ts +0 -749
  386. package/src/memory/vault.ts +0 -1194
  387. package/src/memory/wikify.ts +0 -1064
  388. package/src/mlx/array.ts +0 -425
  389. package/src/mlx/autograd.ts +0 -304
  390. package/src/mlx/checkpoint.ts +0 -149
  391. package/src/mlx/compile.ts +0 -168
  392. package/src/mlx/custom-vjp.ts +0 -188
  393. package/src/mlx/ffi.ts +0 -531
  394. package/src/mlx/materialize.ts +0 -23
  395. package/src/mlx/metal-kernel.ts +0 -159
  396. package/src/mlx/normalized-argmax.ts +0 -116
  397. package/src/mlx/ops.ts +0 -1108
  398. package/src/mlx/quantized-rows.ts +0 -36
  399. package/src/mlx/token-bitmask.ts +0 -52
  400. package/src/mlx/turboquant-kv-decode.ts +0 -82
  401. package/src/mlx/turboquant-kv-inverse.ts +0 -122
  402. package/src/mlx/turboquant-ops.ts +0 -861
  403. package/src/mlx/turboquant-tables.ts +0 -237
  404. package/src/mmap.ts +0 -90
  405. package/src/model/artifact-identity.ts +0 -73
  406. package/src/model/batched-kv.ts +0 -235
  407. package/src/model/batched-mask.ts +0 -279
  408. package/src/model/batched-quant.ts +0 -212
  409. package/src/model/batched-quantized-kv.ts +0 -144
  410. package/src/model/batched-rotating-quant.ts +0 -353
  411. package/src/model/batched-rotating-state.ts +0 -149
  412. package/src/model/batched-rotating.ts +0 -338
  413. package/src/model/batched-row-storage.ts +0 -179
  414. package/src/model/batched-ssm.ts +0 -52
  415. package/src/model/batched-turboquant-kv.ts +0 -94
  416. package/src/model/compiled-decode.ts +0 -712
  417. package/src/model/decoded-kv-donor.ts +0 -12
  418. package/src/model/delayed-quantized-kv.ts +0 -72
  419. package/src/model/delayed-rotating-quantized-kv.ts +0 -93
  420. package/src/model/delayed-turboquant-kv.ts +0 -57
  421. package/src/model/diffusion-gemma.ts +0 -1026
  422. package/src/model/factory.ts +0 -215
  423. package/src/model/fingerprint.ts +0 -45
  424. package/src/model/flash-attention.ts +0 -694
  425. package/src/model/full-prefill-padding.ts +0 -56
  426. package/src/model/full-prefill-row.ts +0 -105
  427. package/src/model/gemma4-base.ts +0 -2370
  428. package/src/model/gemma4.ts +0 -1395
  429. package/src/model/generated/gemma4-12b.ts +0 -429
  430. package/src/model/generated/gemma4-26b.ts +0 -448
  431. package/src/model/generated/gemma4-e4b.ts +0 -717
  432. package/src/model/generated/index.ts +0 -18
  433. package/src/model/glm52-atlas.ts +0 -511
  434. package/src/model/glm52-cache.ts +0 -792
  435. package/src/model/glm52-config.ts +0 -262
  436. package/src/model/glm52-container.ts +0 -305
  437. package/src/model/glm52-coupling.ts +0 -388
  438. package/src/model/glm52-dsa.ts +0 -606
  439. package/src/model/glm52-expert-layout.ts +0 -253
  440. package/src/model/glm52-layout.ts +0 -152
  441. package/src/model/glm52-memory.ts +0 -500
  442. package/src/model/glm52-mla.ts +0 -792
  443. package/src/model/glm52-moe.ts +0 -223
  444. package/src/model/glm52-pilot.ts +0 -537
  445. package/src/model/glm52-reference.ts +0 -445
  446. package/src/model/glm52-residency.ts +0 -557
  447. package/src/model/glm52-resident-weights.ts +0 -135
  448. package/src/model/glm52-streamed-experts.ts +0 -453
  449. package/src/model/glm52-streamed-metal.ts +0 -610
  450. package/src/model/glm52-weights.ts +0 -503
  451. package/src/model/glm52.ts +0 -1132
  452. package/src/model/implementation.ts +0 -69
  453. package/src/model/kv-attention-view.ts +0 -70
  454. package/src/model/minicpm5.ts +0 -376
  455. package/src/model/profile.ts +0 -468
  456. package/src/model/quantized-append-attention.ts +0 -31
  457. package/src/model/qwen-append.ts +0 -12
  458. package/src/model/qwen-conv.ts +0 -52
  459. package/src/model/qwen3-delta-state.ts +0 -74
  460. package/src/model/qwen3-delta.ts +0 -451
  461. package/src/model/qwen3-moe.ts +0 -404
  462. package/src/model/qwen3-mrope.ts +0 -250
  463. package/src/model/qwen3.ts +0 -277
  464. package/src/model/qwen3_5-checkpoint.ts +0 -164
  465. package/src/model/qwen3_5.ts +0 -881
  466. package/src/model/rotating-kv-donor.ts +0 -35
  467. package/src/model/rotating-kv-layout.ts +0 -262
  468. package/src/model/rotating-row-transaction.ts +0 -35
  469. package/src/model/speculative-rotating-kv.ts +0 -101
  470. package/src/model/ssm-prefill-padding.ts +0 -39
  471. package/src/model/support.ts +0 -110
  472. package/src/model/token-groups.ts +0 -66
  473. package/src/model/trellis-balanced-scatter.ts +0 -51
  474. package/src/model/trellis-linear.ts +0 -672
  475. package/src/model/trellis-shared-m.ts +0 -151
  476. package/src/model/trellis-shared-scatter.ts +0 -144
  477. package/src/model/trellis-splitk-prefill.ts +0 -158
  478. package/src/model/trellis-tiled-prefill.ts +0 -136
  479. package/src/model/trellis-vector-expand.ts +0 -62
  480. package/src/model/trellis-wide-prefill.ts +0 -94
  481. package/src/model/turboquant-codec.ts +0 -89
  482. package/src/model/universal/archs.ts +0 -332
  483. package/src/model/universal/dense.ts +0 -612
  484. package/src/model/universal/modules.ts +0 -170
  485. package/src/model/universal/rope.ts +0 -381
  486. package/src/model/whisper.ts +0 -435
  487. package/src/native/expert_io.c +0 -523
  488. package/src/native/frame_extract.swift +0 -140
  489. package/src/native/mic_capture.swift +0 -92
  490. package/src/native-pack.ts +0 -163
  491. package/src/pi-provider.ts +0 -53
  492. package/src/pi-session.ts +0 -81
  493. package/src/pi-terminal.ts +0 -274
  494. package/src/pi-web.ts +0 -1940
  495. package/src/preflight.ts +0 -158
  496. package/src/prompt-cache.ts +0 -682
  497. package/src/quantize/allocator.ts +0 -627
  498. package/src/quantize/atomic-output.ts +0 -38
  499. package/src/quantize/calibration.ts +0 -181
  500. package/src/quantize/config-writer.ts +0 -145
  501. package/src/quantize/index.ts +0 -84
  502. package/src/quantize/job.ts +0 -162
  503. package/src/quantize/quantizer.ts +0 -666
  504. package/src/quantize/rotate.ts +0 -603
  505. package/src/quantize/safetensors-writer.ts +0 -249
  506. package/src/quantize/sensitivity.ts +0 -216
  507. package/src/quantize/trellis.ts +0 -586
  508. package/src/quantize/weight-transform.ts +0 -292
  509. package/src/registry.ts +0 -602
  510. package/src/runtime-config.ts +0 -77
  511. package/src/safetensors.ts +0 -165
  512. package/src/sampler.ts +0 -1012
  513. package/src/serve/admin-routes.ts +0 -184
  514. package/src/serve/assets/curve-terrain.html +0 -105
  515. package/src/serve/assets/training-inference-map.html +0 -575
  516. package/src/serve/audio-routes.ts +0 -323
  517. package/src/serve/aux-routes.ts +0 -132
  518. package/src/serve/batch-scheduler.ts +0 -8
  519. package/src/serve/checkpoint-identity.ts +0 -64
  520. package/src/serve/generation-gateway.ts +0 -537
  521. package/src/serve/isolate.ts +0 -609
  522. package/src/serve/kv-budget.ts +0 -14
  523. package/src/serve/lab-routes.ts +0 -341
  524. package/src/serve/lane-registry.ts +0 -45
  525. package/src/serve/model-admin-routes.ts +0 -155
  526. package/src/serve/model-binding.ts +0 -49
  527. package/src/serve/model-host.ts +0 -511
  528. package/src/serve/parent-application.ts +0 -56
  529. package/src/serve/prompt-response-trace.ts +0 -161
  530. package/src/serve/response-lease.ts +0 -24
  531. package/src/serve/session-search.ts +0 -326
  532. package/src/serve/static-routes.ts +0 -101
  533. package/src/serve/transcription-server.ts +0 -64
  534. package/src/serve/transcription-service.ts +0 -502
  535. package/src/server.ts +0 -1282
  536. package/src/spec/assistant-rows.ts +0 -93
  537. package/src/spec/assistant-source.ts +0 -126
  538. package/src/spec/cache-identity.ts +0 -22
  539. package/src/spec/deepspec-rows.ts +0 -29
  540. package/src/spec/deepspec-source.ts +0 -145
  541. package/src/spec/dflash-source.ts +0 -149
  542. package/src/spec/drafter.ts +0 -304
  543. package/src/spec/dspark/ab-stats.ts +0 -136
  544. package/src/spec/dspark/calibration.ts +0 -112
  545. package/src/spec/dspark/data-dflash.ts +0 -156
  546. package/src/spec/dspark/data.ts +0 -201
  547. package/src/spec/dspark/deepspec-module.ts +0 -776
  548. package/src/spec/dspark/generate-dflash.ts +0 -245
  549. package/src/spec/dspark/generate.ts +0 -290
  550. package/src/spec/dspark/loader.ts +0 -23
  551. package/src/spec/dspark/loss.ts +0 -213
  552. package/src/spec/dspark/module-dflash.ts +0 -560
  553. package/src/spec/dspark/module.ts +0 -540
  554. package/src/spec/dspark/quantize-drafter.ts +0 -91
  555. package/src/spec/dspark/sample.ts +0 -112
  556. package/src/spec/generate.ts +0 -276
  557. package/src/spec/glm52-mtp-graph.ts +0 -29
  558. package/src/spec/glm52-mtp-rows.ts +0 -132
  559. package/src/spec/glm52-mtp-source.ts +0 -318
  560. package/src/spec/glm52-mtp-state.ts +0 -33
  561. package/src/spec/ngram-source.ts +0 -226
  562. package/src/spec/projected-draft-rows.ts +0 -73
  563. package/src/spec/qwen-mtp-module.ts +0 -171
  564. package/src/spec/qwen-mtp-rows.ts +0 -230
  565. package/src/spec/qwen-mtp-source.ts +0 -386
  566. package/src/spec/qwen-mtp-state.ts +0 -30
  567. package/src/spec/serve-loop.ts +0 -587
  568. package/src/spec/source.ts +0 -228
  569. package/src/spec/two-model-rows.ts +0 -62
  570. package/src/spec/two-model.ts +0 -113
  571. package/src/ssd-cache.ts +0 -431
  572. package/src/ssd-durability.ts +0 -209
  573. package/src/storage/host-buffer.ts +0 -24
  574. package/src/storage/kv-writer.ts +0 -83
  575. package/src/storage/kv-writer.worker.js +0 -264
  576. package/src/storage/retention-policy.ts +0 -37
  577. package/src/tiered-prompt-cache.ts +0 -45
  578. package/src/tokenizer.ts +0 -335
  579. package/src/tool-approvals.ts +0 -131
  580. package/src/tool-call.ts +0 -695
  581. package/src/train/dataset.ts +0 -484
  582. package/src/train/diffusion-lora.ts +0 -216
  583. package/src/train/export.ts +0 -32
  584. package/src/train/flash-cce.ts +0 -1234
  585. package/src/train/forward.ts +0 -266
  586. package/src/train/fuse.ts +0 -243
  587. package/src/train/index.ts +0 -46
  588. package/src/train/job.ts +0 -205
  589. package/src/train/lora-params.ts +0 -254
  590. package/src/train/loss.ts +0 -1591
  591. package/src/train/merge.ts +0 -195
  592. package/src/train/optimizer.ts +0 -183
  593. package/src/train/prefix-shared.ts +0 -490
  594. package/src/train/rank.ts +0 -137
  595. package/src/train/segmented.ts +0 -1828
  596. package/src/train/steel-qmm-header.ts +0 -1461
  597. package/src/train/trainer.ts +0 -1221
  598. package/src/train/watch.ts +0 -542
  599. package/src/vision/diffusion-vision.ts +0 -620
  600. package/src/vision/embedder.ts +0 -176
  601. package/src/vision/preprocess.ts +0 -247
  602. package/src/vision/prompt.ts +0 -409
  603. package/src/vision/qwen3vl-preprocess.ts +0 -409
  604. package/src/vision/qwen3vl-prompt.ts +0 -233
  605. package/src/vision/qwen3vl-tower.ts +0 -566
  606. package/src/vision/siglip.ts +0 -607
  607. package/src/vision/video-frames.ts +0 -148
  608. package/src/web/app.html +0 -2155
  609. package/src/web/app.js +0 -5863
  610. package/src/web/skills/memory/SKILL.md +0 -120
  611. package/src/web/skills/web-research/SKILL.md +0 -46
  612. package/src/web/skills.ts +0 -97
  613. package/src/web/src/adapters-panel.ts +0 -288
  614. package/src/web/src/assistant.ts +0 -451
  615. package/src/web/src/chat.ts +0 -1060
  616. package/src/web/src/composer.ts +0 -962
  617. package/src/web/src/dataset.ts +0 -132
  618. package/src/web/src/finetune.ts +0 -267
  619. package/src/web/src/hub.ts +0 -428
  620. package/src/web/src/main.ts +0 -98
  621. package/src/web/src/markdown.ts +0 -0
  622. package/src/web/src/memory-panel.ts +0 -572
  623. package/src/web/src/model-picker.ts +0 -159
  624. package/src/web/src/palette.ts +0 -346
  625. package/src/web/src/protocol.ts +0 -26
  626. package/src/web/src/quantize.ts +0 -167
  627. package/src/web/src/rag.ts +0 -274
  628. package/src/web/src/sessions.ts +0 -469
  629. package/src/web/src/shell.ts +0 -804
  630. package/src/web/src/ui-catalog.ts +0 -78
  631. package/src/web/src/voice.ts +0 -141
  632. package/src/web/vendor/README.md +0 -61
  633. package/src/web-assets.ts +0 -47
  634. package/src/web-tools.ts +0 -478
  635. package/src/weights.ts +0 -255
  636. /package/src/{serve → server}/completion-sink.ts +0 -0
  637. /package/src/{serve → server}/generated-token-history.ts +0 -0
  638. /package/src/web/{icon.svg → public/icon.svg} +0 -0
  639. /package/src/web/{manifest.webmanifest → public/manifest.webmanifest} +0 -0
  640. /package/src/web/{vendor → public/vendor}/hljs-LICENSE +0 -0
package/src/sampler.ts DELETED
@@ -1,1012 +0,0 @@
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 { Dtype } from "./mlx/ffi";
12
- import { normalizedArgmax } from "./mlx/normalized-argmax";
13
- import { MlxArray } from "./mlx/array";
14
- import * as ops from "./mlx/ops";
15
- import type { TokenLogprobs } from "./contracts/generation";
16
- import type { SampledToken, SamplingSession } from "./contracts/sampling";
17
- import { applyCurve, type CurveParams } from "./lab/curve/curve-sampler";
18
-
19
- /** Resolved HLG sampling config (the user-facing knobs). The mid gain is NOT
20
- * here — it folds from temperature (m = 1/T) when the sampler is built. */
21
- export interface HlgConfig {
22
- enabled: boolean;
23
- width: number;
24
- shoulder: number;
25
- toe: number;
26
- pivot?: "top" | "entropy" | "median";
27
- pivotOffset: number;
28
- /** Use the LITERAL HLG OETF (gamma below 1/12, log above) instead of the
29
- * parametric toe/mid/shoulder curve. Ignores gain/width/shoulder/toe/pivot. */
30
- oetf?: boolean;
31
- /** Use the LITERAL HLG EOTF (inverse OETF → OOTF gamma) — the decode/display
32
- * direction (suppresses the tail). Ignores the parametric knobs. */
33
- eotf?: boolean;
34
- /** EOTF only: nominal peak display luminance L_W (cd/m²) → OOTF gamma.
35
- * Default 1000 (γ = 1.2). Lower = flatter (more diverse), higher = sharper. */
36
- lw?: number;
37
- /** Use the FULL HLG chain: OETF signal shape → OOTF scaling (applyHlgPipeline).
38
- * γ from `lw`. Ignores the parametric knobs. */
39
- pipeline?: boolean;
40
- /** Pipeline only: α = max brightness — the top logit the OOTF scales everything
41
- * under ("the most confidence we want"). Default 5. For the shaper, reused as
42
- * `out_scale` (default 12). */
43
- maxBrightness?: number;
44
- /** Use the user-specified HLGShaper (windowed anchor → piecewise OETF with a
45
- * cubic suppress-toe → OOTF → ×out_scale). `lw`→L_W, `maxBrightness`→out_scale. */
46
- shaper?: boolean;
47
- /** Shaper only: W = nats of headroom below the top logit that span the curve
48
- * (`x = clamp((ℓ−ℓmax)/W + 1, 0, 1)`). Default 10. */
49
- window?: number;
50
- /** Shaper only: s_m — mid sharpness (how hard above-median tokens are elevated). */
51
- sM?: number;
52
- /** Shaper only: A — shoulder compression (how hard top-end confidence is tamed). */
53
- shoulderA?: number;
54
- /** Shaper only: target top-to-reference logit gap (out_scale auto-derives from this
55
- * so it's decoupled from W). Default 15. */
56
- targetGap?: number;
57
- /** Shaper only: reference token nats below the top for the auto out_scale. Default 4. */
58
- refGap?: number;
59
- /** Shaper only: curve geometry (the pivots / toe / mid power). Default to the
60
- * HLGShaper constants (xM 0.55, yM 0.5, xFloor 0.2, yFloor 0.18, p 2.0) when unset. */
61
- xM?: number; yM?: number; xFloor?: number; yFloor?: number; p?: number;
62
- /** Optional explicit mid gain m. Default: folds from temperature (m = 1/T),
63
- * so temperature stays the contrast knob. An explicit value decouples mid
64
- * contrast from temperature — needed to probe mid-boost while holding the
65
- * model's recommended temperature fixed. */
66
- gain?: number;
67
- }
68
-
69
- export interface SamplerOptions {
70
- temperature?: number;
71
- topP?: number;
72
- topK?: number;
73
- /** min-p: keep tokens whose probability ≥ minP · p(top token). mlx-lm's
74
- * `min_p`. Applied after top-p, before XTC/top-k (reference chain order). */
75
- minP?: number;
76
- /** Minimum number of tokens min-p may never filter out. Default 1. */
77
- minTokensToKeep?: number;
78
- /** XTC ("exclude top choices"): with this probability per step, drop every
79
- * token above the threshold EXCEPT the least likely of them. */
80
- xtcProbability?: number;
81
- /** Probability a token must exceed to be an XTC removal candidate. [0, 0.5]. */
82
- xtcThreshold?: number;
83
- /** Token ids XTC never removes (mlx-lm's server passes EOS + "\n"). */
84
- xtcSpecialTokens?: number[];
85
- seed?: number;
86
- /** HLG tone-curve sampling. When enabled, replaces temperature's flat slope
87
- * with the piecewise curve (temperature becomes the mid gain). Off/undefined
88
- * ⇒ the plain temperature path, unchanged. docs/archive/hlg-sampling.md. */
89
- hlg?: HlgConfig;
90
- /** v2 log-prob transfer-curve sampler. When set, the drawn monotone curve
91
- * REPLACES temperature+softmax entirely (stochastic, seeded) — see
92
- * src/lab/curve/curve-sampler.ts. Identity curve ≡ temperature 1. */
93
- curve?: CurveParams;
94
- }
95
-
96
- export interface LogitsProcessorOptions {
97
- /** Additive per-token-id logit bias, applied before any penalty
98
- * (mlx-lm's `logit_bias`: {tokenId: bias}). */
99
- logitBias?: Record<number, number>;
100
- repetitionPenalty?: number;
101
- repetitionContextSize?: number;
102
- /** OpenAI-style presence penalty: subtracted ONCE from a token's logit if it
103
- * occurred at all in the recent window. May be negative. */
104
- presencePenalty?: number;
105
- presenceContextSize?: number;
106
- /** OpenAI-style frequency penalty: subtracted once PER OCCURRENCE of the
107
- * token in the recent window. May be negative. */
108
- frequencyPenalty?: number;
109
- frequencyContextSize?: number;
110
- }
111
-
112
- /** logprobs [1, V] → sampled token array (uint32, shape [1]). */
113
- export type Sampler = (logprobs: MlxArray, step: number) => MlxArray;
114
-
115
- /** (deviceTokens [n] | null, logits [1, V]) → logits [1, V]. */
116
- export type LogitsProcessor = (tokens: MlxArray | null, logits: MlxArray) => MlxArray;
117
-
118
- /** Optional arrays captured from the same post-processor logprobs used to
119
- * sample a token. The caller controls readback timing and owns disposal. */
120
- export interface StepExtras {
121
- sel: MlxArray | null;
122
- topIdx: MlxArray | null;
123
- topVals: MlxArray | null;
124
- }
125
-
126
- export type StepSample<T> = SampledToken<T, StepExtras>;
127
-
128
- interface StepGrammar {
129
- readonly isTerminated: boolean;
130
- ready(): Promise<void>;
131
- applyMask(logits: MlxArray): MlxArray;
132
- accept(token: number): void;
133
- }
134
-
135
- export interface StepSamplerOptions extends SamplerOptions, LogitsProcessorOptions {
136
- grammar?: StepGrammar | null;
137
- }
138
-
139
- interface StepSamplerConfigBase {
140
- /** The grammar owner already awaited ready(), or this sampler must do it. */
141
- grammarWait: "external" | "before-sample";
142
- /** Update processor history in sample(), or let the decode loop commit later. */
143
- historyUpdate: "after-sample" | "manual";
144
- initialHistory?: readonly number[];
145
- captureSelectedLogprob?: boolean;
146
- captureTopLogprobs?: number;
147
- /** Eager-number mode can advance grammar after sampling. */
148
- acceptGrammar?: boolean;
149
- eosTokenIds?: readonly number[];
150
- /** Reuse a sampler already shared with a speculative draft source. */
151
- sampler?: Sampler;
152
- }
153
-
154
- export interface DeviceStepSamplerConfig extends StepSamplerConfigBase {
155
- tokenRepresentation: "device";
156
- grammarWait: "external";
157
- }
158
-
159
- export interface NumberStepSamplerConfig extends StepSamplerConfigBase {
160
- tokenRepresentation: "number";
161
- grammarWait: "before-sample";
162
- }
163
-
164
- export type DeviceStepSampler = SamplingSession<MlxArray, MlxArray, StepSample<MlxArray>>;
165
- export type NumberStepSampler = SamplingSession<MlxArray, MlxArray, Promise<StepSample<number>>>;
166
-
167
- const GOLDEN = 0x9e3779b97f4a7c15n;
168
-
169
- function stepKey(seed: number, step: number): MlxArray {
170
- const mixed = (BigInt(seed) ^ ((BigInt(step) + 1n) * GOLDEN)) & 0xffffffffffffffffn;
171
- return ops.randomKey(mixed);
172
- }
173
-
174
- function negInfLike(a: MlxArray): MlxArray {
175
- return ops.scalarLike(-Infinity, a);
176
- }
177
-
178
- /** apply_top_p: keep the smallest set of tokens whose cumulative
179
- * probability exceeds top_p; others → -inf. */
180
- export function applyTopP(lp: MlxArray, topP: number): MlxArray {
181
- const probs = ops.exp(lp);
182
- const sortedIdx = ops.argsortAxis(lp, -1);
183
- const sortedProbs = ops.takeAlongAxis(probs, sortedIdx, -1);
184
- const cum = ops.cumsum(sortedProbs, -1);
185
- // scatter arange back through sortedIdx to invert the permutation
186
- const V = lp.shape[lp.shape.length - 1]!;
187
- const zerosIdx = ops.zeros(sortedIdx.shape, sortedIdx.dtype);
188
- const ar = ops.arange(0, V, 1, sortedIdx.dtype);
189
- const arB = ops.reshape(ar, sortedIdx.shape);
190
- const inverse = ops.putAlongAxis(zerosIdx, sortedIdx, arB, -1);
191
- const cumOrig = ops.takeAlongAxis(cum, inverse, -1);
192
- const threshold = ops.scalarLike(1 - topP, cumOrig);
193
- const keep = ops.less(threshold, cumOrig); // cum > 1 - topP
194
- const ninf = negInfLike(lp);
195
- const out = ops.where(keep, lp, ninf);
196
- for (const a of [probs, sortedIdx, sortedProbs, cum, zerosIdx, ar, arB, inverse, cumOrig, threshold, keep, ninf])
197
- a.dispose();
198
- return out;
199
- }
200
-
201
- /** apply_top_k: all but the k highest logprobs → -inf. */
202
- export function applyTopK(lp: MlxArray, topK: number): MlxArray {
203
- const V = lp.shape[lp.shape.length - 1]!;
204
- const negLp = ops.neg(lp);
205
- const part = ops.argpartitionAxis(negLp, topK - 1, -1);
206
- const maskIdx = part.slice([0, topK], [1, V]);
207
- const ninf = negInfLike(lp);
208
- const out = ops.putAlongAxis(lp, maskIdx, ninf, -1);
209
- for (const a of [negLp, part, maskIdx, ninf]) a.dispose();
210
- return out;
211
- }
212
-
213
- /** apply_min_p: mask tokens whose probability is below minP · p(top token).
214
- * Faithful to the reference (mlx-lm 0.31.3 sample_utils.apply_min_p): the
215
- * threshold is computed in log space directly against the max logprob —
216
- * `scaled_min_p = max(lp) + log(minP)` — no full sort; min_tokens_to_keep
217
- * survivors are recovered with an argpartition on the top tail. */
218
- export function applyMinP(lp: MlxArray, minP: number, minTokensToKeep = 1): MlxArray {
219
- if (!(minP >= 0 && minP <= 1))
220
- throw new Error(`minP has to be a float in the [0, 1] interval, but is ${minP}`);
221
- if (!Number.isInteger(minTokensToKeep) || minTokensToKeep < 1)
222
- throw new Error(`minTokensToKeep has to be a positive integer, but is ${minTokensToKeep}`);
223
-
224
- const owned: MlxArray[] = [];
225
- const k = <T extends MlxArray>(a: T): T => { owned.push(a); return a; };
226
-
227
- // Mask tokens that have a probability less than max(p) * min_p
228
- const top = k(ops.maxAxis(lp, -1, true));
229
- const scaledMinP = k(ops.add(top, k(ops.scalarLike(Math.log(minP), top))));
230
- let remove = k(ops.less(lp, scaledMinP));
231
-
232
- // Ensure at least min_tokens_to_keep survive the filter
233
- if (minTokensToKeep > 1) {
234
- const V = lp.shape[lp.shape.length - 1]!;
235
- // mx.argpartition(lp, kth=-min_tokens_to_keep): negative kth ≡ V - k
236
- const part = k(ops.argpartitionAxis(lp, V - minTokensToKeep, -1));
237
- const topIdx = k(part.slice([0, V - minTokensToKeep], [1, V]));
238
- const falses = k(ops.zeros([1, minTokensToKeep], Dtype.bool));
239
- remove = k(ops.putAlongAxis(remove, topIdx, falses, -1));
240
- }
241
-
242
- const ninf = k(negInfLike(lp));
243
- const out = ops.where(remove, ninf, lp);
244
- for (const a of owned) a.dispose();
245
- return out;
246
- }
247
-
248
- /** apply_xtc: with probability xtcProbability, remove every token whose
249
- * probability exceeds the minimum above-threshold probability — i.e. drop
250
- * the top choices, keeping the least likely token that still clears the
251
- * threshold (plus everything below it). Special tokens are never removed.
252
- * `key` seeds the per-step uniform draw (the reference uses the global RNG). */
253
- export function applyXtc(
254
- logits: MlxArray,
255
- xtcProbability: number,
256
- xtcThreshold: number,
257
- xtcSpecialTokens: number[],
258
- key: MlxArray | null,
259
- ): MlxArray {
260
- if (!(xtcThreshold >= 0 && xtcThreshold <= 0.5))
261
- throw new Error(`xtcThreshold has to be a float in the [0, 0.5] interval, but is ${xtcThreshold}`);
262
- if (!(xtcProbability >= 0 && xtcProbability <= 1))
263
- throw new Error(`xtcProbability has to be a float in the [0, 1] interval, but is ${xtcProbability}`);
264
-
265
- const owned: MlxArray[] = [];
266
- const k = <T extends MlxArray>(a: T): T => { owned.push(a); return a; };
267
-
268
- const probs = k(ops.softmaxAxis(logits, -1, false));
269
- // mask = probs > min(where(probs > threshold, probs, inf))
270
- const thresh = k(ops.scalarLike(xtcThreshold, probs));
271
- const above = k(ops.less(thresh, probs)); // probs > threshold
272
- const inf = k(ops.scalarLike(Infinity, probs));
273
- const aboveProbs = k(ops.where(above, probs, inf));
274
- // min(x) = -max(-x) (no min reduction in the ops layer)
275
- const minAbove = k(ops.neg(k(ops.maxAxis(k(ops.neg(aboveProbs)), -1, true))));
276
- let mask = k(ops.less(minAbove, probs)); // probs > min above-threshold prob
277
- if (xtcSpecialTokens.length > 0) {
278
- const n = xtcSpecialTokens.length;
279
- const idx = k(ops.fromInt32(xtcSpecialTokens, [1, n]));
280
- const falses = k(ops.zeros([1, n], Dtype.bool));
281
- mask = k(ops.putAlongAxis(mask, idx, falses, -1));
282
- }
283
-
284
- // where(uniform() > xtcProbability, logits, where(mask, -inf, logits))
285
- const u = k(ops.randomUniform([1], Dtype.float32, 0, 1, key));
286
- const pArr = k(ops.scalarLike(xtcProbability, u));
287
- const skip = k(ops.less(pArr, u)); // u > xtcProbability → leave logits alone
288
- const ninf = k(negInfLike(logits));
289
- const culled = k(ops.where(mask, ninf, logits));
290
- const out = ops.where(skip, logits, culled);
291
- for (const a of owned) a.dispose();
292
- return out;
293
- }
294
-
295
- /** HLG sampling parameters — a piecewise tone curve on the logprobs.
296
- * See docs/archive/hlg-sampling.md. Knobs are in nats (the logprob unit). */
297
- export interface HlgParams {
298
- /** m — mid-region slope. Folds temperature: m = 1/temperature. */
299
- gain: number;
300
- /** w — half-width of the linear mid region. Infinity ⇒ no rolloff (pure temperature). */
301
- width: number;
302
- /** β_h — highlight rolloff scale. ≤ 0 ⇒ no shoulder (highlights stay linear). */
303
- shoulder: number;
304
- /** β_t — shadow rolloff scale. ≤ 0 ⇒ no toe (shadows stay linear). */
305
- toe: number;
306
- /** pivot (middle grey) placement — changes where the curve centers, hence its
307
- * shape. "top": μ = max(ℓ) − offset. "entropy": μ = Σp·ℓ = −H (center of mass
308
- * in tonal space). "median": μ = the logprob at the 50% cumulative-mass
309
- * boundary (auto-levels). */
310
- pivot?: "top" | "entropy" | "median";
311
- /** shift applied to the pivot base: μ = base − pivotOffset. */
312
- pivotOffset?: number;
313
- }
314
-
315
- const HLG_LOG_EPS = 1e-9;
316
-
317
- /** Pivot (middle grey) μ_base for the tone curve, in logprob units — the same
318
- * curve, centered three different ways. Operates on the full logprob vector. */
319
- function hlgPivotBase(
320
- lp: MlxArray,
321
- mode: "top" | "entropy" | "median",
322
- k: <T extends MlxArray>(a: T) => T,
323
- ): MlxArray {
324
- if (mode === "entropy") {
325
- // center of mass in tonal space: μ = Σ p·ℓ = −H (p = exp(ℓ); ℓ are logprobs)
326
- const probs = k(ops.exp(lp));
327
- return k(ops.sumAxis(k(ops.mul(probs, lp)), -1, true));
328
- }
329
- if (mode === "median") {
330
- // logprob at the 50% cumulative-mass boundary (auto-levels / histogram median)
331
- const probs = k(ops.exp(lp));
332
- const idxDesc = k(ops.argsortAxis(k(ops.neg(lp)), -1)); // ascending of −ℓ = ℓ descending
333
- const sortedProbs = k(ops.takeAlongAxis(probs, idxDesc, -1));
334
- const sortedLp = k(ops.takeAlongAxis(lp, idxDesc, -1));
335
- const cum = k(ops.cumsum(sortedProbs, -1));
336
- const keep = k(ops.greaterEqual(cum, k(ops.scalarLike(0.5, cum))));
337
- const masked = k(ops.where(keep, sortedLp, k(ops.scalarLike(-Infinity, sortedLp))));
338
- return k(ops.maxAxis(masked, -1, true)); // first crossover = max logprob of the ≥0.5 suffix
339
- }
340
- return k(ops.maxAxis(lp, -1, true)); // "top": the peak
341
- }
342
-
343
- /** Remap logprobs through the centered curve g(z), z = ℓ − μ:
344
- * toe (z < −w): −m·w − m·β_t·ln(1 + (−z − w)/β_t) gentle shadow rolloff
345
- * mid (|z| ≤ w): m·z contrast gain
346
- * shoulder(z > w): m·w + m·β_h·ln(1 + ( z − w)/β_h) highlight rolloff
347
- * Monotone in ℓ ⇒ ranking-preserving (argmax unchanged). With width = ∞ (or
348
- * β_h, β_t ≤ 0) it returns mulScalar(lp, m) — temperature T = 1/m — bit-exact
349
- * by construction (the same op the temperature path uses). `-inf` (masked)
350
- * tokens map to `-inf`. */
351
- export function applyHlg(lp: MlxArray, p: HlgParams): MlxArray {
352
- const m = p.gain;
353
- const hasShoulder = Number.isFinite(p.width) && p.shoulder > 0;
354
- const hasToe = Number.isFinite(p.width) && p.toe > 0;
355
- // No-rolloff regime ≡ temperature: identical op to the temperature sampler.
356
- if (!hasShoulder && !hasToe) return ops.mulScalar(lp, m);
357
-
358
- const w = p.width;
359
- const off = p.pivotOffset ?? 0;
360
- const tmp: MlxArray[] = [];
361
- const k = <T extends MlxArray>(a: T): T => {
362
- tmp.push(a);
363
- return a;
364
- };
365
-
366
- // pivot μ = base(mode) − off ; centered coordinate z = ℓ − μ
367
- const base = hlgPivotBase(lp, p.pivot ?? "top", k);
368
- const mu = k(ops.sub(base, k(ops.scalarLike(off, base))));
369
- const z = k(ops.sub(lp, mu));
370
- const wC = k(ops.scalarLike(w, lp));
371
- let g: MlxArray = k(ops.mulScalar(z, m)); // mid: m·z
372
-
373
- if (hasShoulder) {
374
- const bh = p.shoulder;
375
- const inner = k(ops.add(k(ops.scalarLike(1, lp)), k(ops.mulScalar(k(ops.sub(z, wC)), 1 / bh))));
376
- const clamped = k(ops.maximum(inner, k(ops.scalarLike(HLG_LOG_EPS, lp))));
377
- const shoulder = k(ops.add(k(ops.scalarLike(m * w, lp)), k(ops.mulScalar(k(ops.log(clamped)), m * bh))));
378
- g = k(ops.where(k(ops.greaterEqual(z, wC)), shoulder, g));
379
- }
380
- if (hasToe) {
381
- const bt = p.toe;
382
- const negz = k(ops.neg(z));
383
- const inner = k(ops.add(k(ops.scalarLike(1, lp)), k(ops.mulScalar(k(ops.sub(negz, wC)), 1 / bt))));
384
- const clamped = k(ops.maximum(inner, k(ops.scalarLike(HLG_LOG_EPS, lp))));
385
- const toe = k(ops.sub(k(ops.scalarLike(-m * w, lp)), k(ops.mulScalar(k(ops.log(clamped)), m * bt))));
386
- g = k(ops.where(k(ops.less(z, k(ops.scalarLike(-w, lp)))), toe, g));
387
- }
388
-
389
- for (const a of tmp) if (a !== g) a.dispose();
390
- return g;
391
- }
392
-
393
- // Literal HLG OETF (ARIB STD-B67 / ITU-R BT.2100) — the actual transfer
394
- // function, exact constants. Input L = p/p_max ∈ (0,1] (exposure-normalized: the
395
- // top token is reference white). Output V ∈ [0,1]:
396
- // V = √3 · √L for 0 ≤ L ≤ 1/12 (gamma/sqrt: shadows → 0 softly)
397
- // V = a·ln(12L − b) + c for 1/12 < L ≤ 1 (log: highlights compressed)
398
- // We sample ∝ V by feeding log(V) to the categorical draw. Monotone in ℓ ⇒
399
- // ranking-preserving. No knobs — this is HLG itself.
400
- const HLG_A = 0.17883277;
401
- const HLG_B = 0.28466892; // 1 − 4a
402
- const HLG_C = 0.55991073; // 0.5 − a·ln(4a)
403
- const HLG_SQRT3 = Math.sqrt(3);
404
- const HLG_KNEE = 1 / 12;
405
-
406
- export function applyHlgOetf(lp: MlxArray): MlxArray {
407
- const tmp: MlxArray[] = [];
408
- const k = <T extends MlxArray>(a: T): T => {
409
- tmp.push(a);
410
- return a;
411
- };
412
-
413
- // L = p / p_max = exp(ℓ − ℓmax) ∈ (0, 1]
414
- const lmax = k(ops.maxAxis(lp, -1, true));
415
- const L = k(ops.exp(k(ops.sub(lp, lmax))));
416
-
417
- // lower (L ≤ 1/12): V = √3 · √L
418
- const lo = k(ops.mulScalar(k(ops.sqrt(L)), HLG_SQRT3));
419
- // upper (L > 1/12): V = a·ln(12L − b) + c (clamp the arg > 0 for the unused lane)
420
- 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))));
421
- const hi = k(ops.add(k(ops.mulScalar(k(ops.log(arg)), HLG_A)), k(ops.scalarLike(HLG_C, L))));
422
- const V = k(ops.where(k(ops.greaterEqual(L, k(ops.scalarLike(HLG_KNEE, L)))), hi, lo));
423
-
424
- // sample ∝ V → logits = log(V)
425
- const out = ops.log(k(ops.maximum(V, k(ops.scalarLike(HLG_LOG_EPS, V)))));
426
- for (const a of tmp) a.dispose();
427
- return out;
428
- }
429
-
430
- /** OOTF system gamma from nominal peak display luminance L_W (cd/m²).
431
- * γ = 1.2 + 0.42·log10(L_W/1000); γ = 1.2 exactly at L_W = 1000. */
432
- export function hlgGammaForLw(lw: number): number {
433
- return 1.2 + 0.42 * Math.log10(lw / 1000);
434
- }
435
-
436
- // Literal HLG EOTF (signal → display linear) = inverse OETF then OOTF — the
437
- // DECODE direction. Treat p/p_max as the signal E'. The inverse OETF squares the
438
- // lower half (E = E'²/3) so the tail is SUPPRESSED (the opposite of the OETF,
439
- // which expands it). The OOTF on a single-"pixel" (grayscale) distribution has
440
- // no colour channels for luminance to couple, so it reduces exactly to a gamma
441
- // power law E^γ — i.e. temperature. Sample ∝ E^γ ⇒ logits = γ·log(E).
442
- export function applyHlgEotf(lp: MlxArray, gamma: number): MlxArray {
443
- const tmp: MlxArray[] = [];
444
- const k = <T extends MlxArray>(a: T): T => {
445
- tmp.push(a);
446
- return a;
447
- };
448
-
449
- const d = k(ops.sub(lp, k(ops.maxAxis(lp, -1, true)))); // ℓ − ℓmax ≤ 0
450
- const Ep = k(ops.exp(d)); // signal E' = p/p_max ∈ (0, 1]
451
- // log E from the inverse OETF, computed stably per branch (the deep tail
452
- // underflows if E is formed directly, so the lower branch stays in log-space):
453
- // E' ≤ 1/2: E = E'²/3 → log E = 2·(ℓ−ℓmax) − ln3 (exact)
454
- // E' > 1/2: E = (exp((E'−c)/a)+b)/12 → log E = log(that) (well-conditioned)
455
- const logElo = k(ops.sub(k(ops.mulScalar(d, 2)), k(ops.scalarLike(Math.log(3), d))));
456
- const hiArg = k(ops.exp(k(ops.mulScalar(k(ops.sub(Ep, k(ops.scalarLike(HLG_C, Ep)))), 1 / HLG_A))));
457
- const hiE = k(ops.mulScalar(k(ops.add(hiArg, k(ops.scalarLike(HLG_B, Ep)))), 1 / 12));
458
- const logEhi = k(ops.log(hiE));
459
- const logE = k(ops.where(k(ops.greaterEqual(Ep, k(ops.scalarLike(0.5, Ep)))), logEhi, logElo));
460
- // OOTF (grayscale) → gamma: sample ∝ E^γ ⇒ logits = γ·log(E)
461
- const out = ops.mulScalar(logE, gamma);
462
- for (const a of tmp) a.dispose();
463
- return out;
464
- }
465
-
466
- // The FULL HLG chain: OETF signal shape, THEN OOTF scaling.
467
- // 1. E = p/p_max ∈ (0,1] (top token = the max-brightness reference)
468
- // 2. E' = √(3E) for E ≤ 1/12 (gamma/√ toe below the knee)
469
- // = a·ln(12E−b)+c for E > 1/12 (log highlights above the knee)
470
- // 3. R_d = α · E'^γ (OOTF: α = max brightness, scales everything
471
- // under it; γ = 1.2+0.42·log10(L_W/1000))
472
- // R_d are the final logits → categorical. α > 0 ⇒ monotone (ranking preserved).
473
- export function applyHlgPipeline(lp: MlxArray, alpha: number, gamma: number): MlxArray {
474
- const tmp: MlxArray[] = [];
475
- const k = <T extends MlxArray>(a: T): T => {
476
- tmp.push(a);
477
- return a;
478
- };
479
-
480
- // 1. E = p/p_max ∈ (0,1]
481
- const E = k(ops.exp(k(ops.sub(lp, k(ops.maxAxis(lp, -1, true))))));
482
- // 2. OETF: √(3E) below the knee, a·ln(12E−b)+c above
483
- const lo = k(ops.sqrt(k(ops.mulScalar(E, 3))));
484
- 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))));
485
- const hi = k(ops.add(k(ops.mulScalar(k(ops.log(arg)), HLG_A)), k(ops.scalarLike(HLG_C, E))));
486
- const Eprime = k(ops.where(k(ops.greaterEqual(E, k(ops.scalarLike(HLG_KNEE, E)))), hi, lo));
487
- // 3. OOTF: R_d = α · E'^γ = α · exp(γ·log E')
488
- const EpGamma = k(ops.exp(k(ops.mulScalar(k(ops.log(k(ops.maximum(Eprime, k(ops.scalarLike(HLG_LOG_EPS, Eprime)))))), gamma))));
489
- const out = ops.mulScalar(EpGamma, alpha);
490
- for (const a of tmp) a.dispose();
491
- return out;
492
- }
493
-
494
- // ── User-specified HLGShaper (windowed-anchor input) ────────────────────────
495
- // logit → windowed-anchor signal x∈[0,1] (top W nats span the curve; min-max
496
- // over the 262k vocab dumped every candidate into the shoulder, so we anchor at
497
- // the top instead) → piecewise OETF (log shoulder above x_m, power mid, CUBIC
498
- // toe that suppresses to 0) → OOTF (normalize to peak, ^γ) → ×out_scale →
499
- // softmax. Geometry constants derived once from the default knobs, exactly as
500
- // HLGShaper.__init__ does (cubic toe coeffs from a 2×2 solve).
501
- export interface HlgShaperParams {
502
- lw?: number; // L_W (cd/m²) → OOTF γ
503
- outScale?: number; // explicit override; default auto-derived from targetGap/refGap
504
- targetGap?: number; // desired top-1-to-reference final-logit gap (sets sharpness, W-independent)
505
- refGap?: number; // reference token sits this many nats below the top
506
- window?: number; // W: nats below the top spanning the curve
507
- xM?: number; yM?: number; xFloor?: number; yFloor?: number; p?: number;
508
- sM?: number; // mid sharpness — how hard above-median tokens are elevated
509
- A?: number; // shoulder compression — how hard confidence is tamed
510
- }
511
-
512
- export function applyHlgShaper(lp: MlxArray, opts: HlgShaperParams = {}): MlxArray {
513
- const lw = opts.lw ?? 1200, window = opts.window ?? 10;
514
- const xM = opts.xM ?? 0.55, yM = opts.yM ?? 0.5, xFloor = opts.xFloor ?? 0.2, yFloor = opts.yFloor ?? 0.18;
515
- const p = opts.p ?? 2.0, sM = opts.sM ?? 0.7, A = opts.A ?? 0.35;
516
- const targetGap = opts.targetGap ?? 15, refGap = opts.refGap ?? 4;
517
- // geometry derived per call (cheap scalar math), exactly as HLGShaper.__init__
518
- const dxf = xM - xFloor;
519
- const kc = (yM - sM * dxf - yFloor) / Math.pow(dxf, p); // mid reaches y_floor
520
- const sFloor = sM + kc * p * Math.pow(dxf, p - 1); // mid slope at the toe join
521
- const det = -Math.pow(xFloor, 4); // solve [[xf³,xf²],[3xf²,2xf]]·[e,f]=[y_floor,s_floor]
522
- const ec = (yFloor * (2 * xFloor) - xFloor ** 2 * sFloor) / det;
523
- const fc = (xFloor ** 3 * sFloor - yFloor * (3 * xFloor ** 2)) / det;
524
- const yPeak = yM + A * Math.log(1 + (sM / A) * (1 - xM));
525
- const gamma = 1.2 + 0.42 * Math.log10(Math.max(lw, 1e-3) / 1000);
526
-
527
- // out_scale AUTO-derived so the top-1-to-reference final-logit gap = targetGap,
528
- // INDEPENDENT of W — decouples the two knobs so W is a clean 1-D sweep. The
529
- // reference token sits refGap nats below the top; its post-shape value is the
530
- // scalar curve evaluated in JS (no device cost). Calibrated so W=5 ⇒ os ≈ 18.
531
- const oetfS = (xx: number): number => {
532
- let yy: number;
533
- if (xx >= xM) yy = yM + A * Math.log(Math.max(1 + (sM / A) * (xx - xM), 1e-9));
534
- else if (xx >= xFloor) yy = yM - sM * (xM - xx) - kc * Math.pow(Math.max(xM - xx, 0), p);
535
- else yy = ec * xx ** 3 + fc * xx ** 2;
536
- return Math.max(yy, 0);
537
- };
538
- const shapeS = (xx: number): number => Math.pow(Math.max(oetfS(xx) / yPeak, 1e-9), gamma);
539
- const xRef = Math.max(0, Math.min(1, 1 - refGap / window));
540
- const outScale = opts.outScale ?? targetGap / Math.max(1e-6, 1 - shapeS(xRef));
541
-
542
- const tmp: MlxArray[] = [];
543
- const k = <T extends MlxArray>(a: T): T => {
544
- tmp.push(a);
545
- return a;
546
- };
547
- const C = (v: number, like: MlxArray): MlxArray => k(ops.scalarLike(v, like));
548
-
549
- // x = clamp((ℓ − ℓmax)/W + 1, 0, 1) — windowed anchor at the top
550
- const lmax = k(ops.maxAxis(lp, -1, true));
551
- 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)));
552
-
553
- // OETF: up (x≥x_m) log shoulder, mid power, toe (x<x_floor) cubic suppress
554
- 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)));
555
- const up = k(ops.add(C(yM, x), k(ops.mulScalar(k(ops.log(upArg)), A))));
556
- const dm = k(ops.sub(C(xM, x), x));
557
- const dmPow = k(ops.exp(k(ops.mulScalar(k(ops.log(k(ops.maximum(dm, C(1e-9, x))))), p))));
558
- const mid = k(ops.sub(k(ops.sub(C(yM, x), k(ops.mulScalar(dm, sM)))), k(ops.mulScalar(dmPow, kc))));
559
- const x2 = k(ops.square(x));
560
- const x3 = k(ops.mul(x, x2));
561
- const toe = k(ops.add(k(ops.mulScalar(x3, ec)), k(ops.mulScalar(x2, fc))));
562
- const upMid = k(ops.where(k(ops.greaterEqual(x, C(xM, x))), up, mid));
563
- const y = k(ops.maximum(k(ops.where(k(ops.greaterEqual(x, C(xFloor, x))), upMid, toe)), C(0, x)));
564
-
565
- // OOTF: r = (max(y/y_peak, 1e-9))^γ ; then softmax(r · out_scale)
566
- const yn = k(ops.maximum(k(ops.mulScalar(y, 1 / yPeak)), C(1e-9, y)));
567
- const r = k(ops.exp(k(ops.mulScalar(k(ops.log(yn)), gamma))));
568
- const out = ops.mulScalar(r, outScale);
569
- for (const a of tmp) a.dispose();
570
- return out;
571
- }
572
-
573
- export function makeSampler(opts: SamplerOptions = {}): Sampler {
574
- const {
575
- temperature = 0, topP = 0, topK = 0, minP = 0, minTokensToKeep = 1,
576
- xtcProbability = 0, xtcThreshold = 0, xtcSpecialTokens = [],
577
- seed = 0, hlg, curve,
578
- } = opts;
579
-
580
- // v2 curve sampler: the drawn log-prob transfer curve REPLACES temperature +
581
- // softmax. Stochastic and seeded by design (the curve IS the sampling shape),
582
- // so it overrides the greedy default — the designer wants variety across N.
583
- if (curve) {
584
- return (lp, step) => {
585
- const shaped = applyCurve(lp, curve);
586
- const tok = ops.randomCategorical(shaped, stepKey(seed, step));
587
- shaped.dispose();
588
- return tok;
589
- };
590
- }
591
-
592
- // Greedy: HLG is a no-op (a monotone curve cannot move the argmax), so the
593
- // greedy path is untouched whether or not HLG is enabled.
594
- if (temperature === 0)
595
- return (lp) => ops.argmaxAxis(lp, -1);
596
-
597
- // HLG is a REPLACEMENT sampler: when enabled, the tone curve IS the whole
598
- // post-logits step — its toe does the tail control that top_p/top_k would, so
599
- // they are NOT applied. Otherwise we do exactly what we used to: top_p, top_k,
600
- // then temperature scaling. (Temperature still folds into the mid gain m = 1/T
601
- // unless the config sets an explicit gain.)
602
- if (hlg?.enabled === true) {
603
- const useOetf = hlg.oetf === true;
604
- const useEotf = hlg.eotf === true;
605
- const usePipeline = hlg.pipeline === true;
606
- const eotfGamma = hlgGammaForLw(hlg.lw ?? 1000);
607
- const alpha = hlg.maxBrightness ?? 5;
608
- const params: HlgParams = {
609
- gain: hlg.gain ?? 1 / temperature,
610
- width: hlg.width,
611
- shoulder: hlg.shoulder,
612
- toe: hlg.toe,
613
- pivot: hlg.pivot,
614
- pivotOffset: hlg.pivotOffset,
615
- };
616
- return (lp, step) => {
617
- const scaled = hlg.shaper === true
618
- ? 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 })
619
- : usePipeline ? applyHlgPipeline(lp, alpha, eotfGamma)
620
- : useEotf ? applyHlgEotf(lp, eotfGamma) : useOetf ? applyHlgOetf(lp) : applyHlg(lp, params);
621
- const key = stepKey(seed, step);
622
- const tok = ops.randomCategorical(scaled, key);
623
- scaled.dispose();
624
- key.dispose();
625
- return tok;
626
- };
627
- }
628
-
629
- // Filter chain order matches mlx-lm's make_sampler: top_p → min_p → xtc →
630
- // top_k, then categorical(logprobs / temperature).
631
- return (lp, step) => {
632
- let cur = lp;
633
- const owned: MlxArray[] = [];
634
- let key = stepKey(seed, step);
635
- if (topP > 0 && topP < 1) { cur = applyTopP(cur, topP); owned.push(cur); }
636
- if (minP !== 0) { cur = applyMinP(cur, minP, minTokensToKeep); owned.push(cur); }
637
- if (xtcProbability > 0) {
638
- // Split the step key: subkey 0 → XTC's uniform, subkey 1 → categorical.
639
- const split = ops.randomSplitNum(key, 2);
640
- const row0 = split.slice([0, 0], [1, 2]);
641
- const row1 = split.slice([1, 0], [2, 2]);
642
- const xtcKey = ops.reshape(row0, [2]);
643
- key.dispose();
644
- key = ops.reshape(row1, [2]);
645
- for (const a of [split, row0, row1]) a.dispose();
646
- cur = applyXtc(cur, xtcProbability, xtcThreshold, xtcSpecialTokens, xtcKey);
647
- owned.push(cur);
648
- xtcKey.dispose();
649
- }
650
- if (topK > 0) { cur = applyTopK(cur, topK); owned.push(cur); }
651
- const scaled = ops.mulScalar(cur, 1 / temperature);
652
- const tok = ops.randomCategorical(scaled, key);
653
- scaled.dispose();
654
- key.dispose();
655
- for (const a of owned) a.dispose();
656
- return tok;
657
- };
658
- }
659
-
660
- /** Start of the recent-token window, matching Python's `tokens[-context_size:]`
661
- * slice semantics exactly (context_size 0 ⇒ `[-0:]` ⇒ the WHOLE history). */
662
- function windowStart(n: number, contextSize: number): number {
663
- return contextSize === 0 ? 0 : Math.max(0, n - contextSize);
664
- }
665
-
666
- export function makeLogitsProcessors(opts: LogitsProcessorOptions = {}): LogitsProcessor[] {
667
- const out: LogitsProcessor[] = [];
668
- const {
669
- logitBias,
670
- repetitionPenalty, repetitionContextSize = 20,
671
- presencePenalty, presenceContextSize = 20,
672
- frequencyPenalty, frequencyContextSize = 20,
673
- } = opts;
674
-
675
- // logit_bias first, as in mlx-lm's make_logits_processors. Reference:
676
- // `logits.at[:, indices].add(values)` — dict keys are unique, so a
677
- // gather → add → put round-trip is exactly equivalent to the scatter-add.
678
- const biasIds = logitBias ? Object.keys(logitBias).map(Number) : [];
679
- if (logitBias && biasIds.length > 0) {
680
- const biasVals = Float32Array.from(biasIds.map((id) => logitBias[id]!));
681
- out.push((_tokens, logits) => {
682
- const K = biasIds.length;
683
- const idx = ops.fromInt32(biasIds, [1, K]);
684
- const vals32 = MlxArray.fromFloat32(biasVals, [1, K]);
685
- const vals = vals32.astype(logits.dtype);
686
- const selected = ops.takeAlongAxis(logits, idx, -1);
687
- const biased = ops.add(selected, vals);
688
- const updated = ops.putAlongAxis(logits, idx, biased, -1);
689
- for (const a of [idx, vals32, vals, selected, biased]) a.dispose();
690
- return updated;
691
- });
692
- }
693
-
694
- if (repetitionPenalty !== undefined && repetitionPenalty !== 0) {
695
- if (repetitionPenalty < 0)
696
- throw new Error("repetitionPenalty must be non-negative");
697
- out.push((tokens, logits) => {
698
- if (!tokens) return logits;
699
- const n = tokens.shape[0]!;
700
- if (n === 0) return logits;
701
- const start = windowStart(n, repetitionContextSize);
702
- const recent = tokens.slice([start], [n]);
703
- const idx = ops.reshape(recent, [1, n - start]);
704
- const selected = ops.takeAlongAxis(logits, idx, -1);
705
- const zero = ops.scalarLike(0, selected);
706
- const isNeg = ops.less(selected, zero);
707
- const timesP = ops.mulScalar(selected, repetitionPenalty);
708
- const pen = ops.scalarLike(repetitionPenalty, selected);
709
- const overP = ops.div(selected, pen);
710
- const penalized = ops.where(isNeg, timesP, overP);
711
- const updated = ops.putAlongAxis(logits, idx, penalized, -1);
712
- for (const a of [recent, idx, selected, zero, isNeg, timesP, pen, overP, penalized])
713
- a.dispose();
714
- return updated;
715
- });
716
- }
717
-
718
- // make_presence_penalty: `logits[:, tokens] -= penalty` — a plain
719
- // fancy-index assignment, so duplicate occurrences all write the SAME
720
- // value (original − penalty): the penalty applies once per distinct token.
721
- if (presencePenalty !== undefined && presencePenalty !== 0) {
722
- out.push((tokens, logits) => {
723
- if (!tokens) return logits;
724
- const n = tokens.shape[0]!;
725
- if (n === 0) return logits;
726
- const start = windowStart(n, presenceContextSize);
727
- const recent = tokens.slice([start], [n]);
728
- const idx = ops.reshape(recent, [1, n - start]);
729
- const selected = ops.takeAlongAxis(logits, idx, -1);
730
- const pen = ops.scalarLike(presencePenalty, selected);
731
- const penalized = ops.sub(selected, pen);
732
- const updated = ops.putAlongAxis(logits, idx, penalized, -1);
733
- for (const a of [recent, idx, selected, pen, penalized]) a.dispose();
734
- return updated;
735
- });
736
- }
737
-
738
- // make_frequency_penalty: `logits.at[:, tokens].subtract(penalty)` — a
739
- // scatter-subtract that ACCUMULATES over duplicates: each token loses
740
- // penalty × (occurrence count in the window). We compute the count per
741
- // position ([m,m] equality matrix summed over a row — m ≤ contextSize, tiny)
742
- // so every duplicate writes the identical final value and a put_along_axis
743
- // reproduces the scatter-accumulate exactly.
744
- if (frequencyPenalty !== undefined && frequencyPenalty !== 0) {
745
- out.push((tokens, logits) => {
746
- if (!tokens) return logits;
747
- const n = tokens.shape[0]!;
748
- if (n === 0) return logits;
749
- const start = windowStart(n, frequencyContextSize);
750
- const m = n - start;
751
- const recent = tokens.slice([start], [n]);
752
- const col = ops.reshape(recent, [m, 1]);
753
- const idx = ops.reshape(recent, [1, m]);
754
- const eq = ops.equal(col, idx); // [m, m]
755
- const counts = ops.sumAxis(eq, -1, false); // [m] occurrences of tokens[i]
756
- const countsF = counts.astype(logits.dtype);
757
- const countsRow = ops.reshape(countsF, [1, m]);
758
- const selected = ops.takeAlongAxis(logits, idx, -1);
759
- const pen = ops.scalarLike(frequencyPenalty, selected);
760
- const penTotal = ops.mul(countsRow, pen); // penalty × count
761
- const penalized = ops.sub(selected, penTotal);
762
- const updated = ops.putAlongAxis(logits, idx, penalized, -1);
763
- for (const a of [recent, col, idx, eq, counts, countsF, countsRow, selected, pen, penTotal, penalized])
764
- a.dispose();
765
- return updated;
766
- });
767
- }
768
-
769
- return out;
770
- }
771
-
772
- /** Whether scores can use stateless greedy sampling across independent rows. */
773
- export function isPlainGreedy(
774
- opts: StepSamplerOptions,
775
- hasProcessors = makeLogitsProcessors(opts).length > 0,
776
- ): boolean {
777
- return (opts.temperature ?? 0) === 0 && !opts.curve && !hasProcessors && !opts.grammar;
778
- }
779
-
780
- export function stepExtrasArrays(extras: StepExtras | null): MlxArray[] {
781
- return extras
782
- ? [extras.sel, extras.topIdx, extras.topVals].filter(
783
- (array): array is MlxArray => array !== null,
784
- )
785
- : [];
786
- }
787
-
788
- export function disposeStepExtras(extras: StepExtras | null): void {
789
- if (!extras) return;
790
- extras.sel?.dispose();
791
- extras.topIdx?.dispose();
792
- extras.topVals?.dispose();
793
- }
794
-
795
- /** Read captured probabilities with their token, without adding casts behind
796
- * the next decode step. Consumes the capture on success and failure. */
797
- export function readStepExtras(extras: StepExtras | null): TokenLogprobs | undefined {
798
- if (!extras) return undefined;
799
- try {
800
- const out: TokenLogprobs = {};
801
- if (extras.sel) out.logprob = extras.sel.toFloat32Host()[0]!;
802
- if (extras.topIdx && extras.topVals) {
803
- const ids = extras.topIdx.toIntTokens();
804
- const vals = extras.topVals.toFloat32Host();
805
- out.top = Array.from(ids, (id, i) => ({ id, logprob: vals[i]! }))
806
- .sort((a, b) => b.logprob - a.logprob);
807
- }
808
- return out;
809
- } finally { disposeStepExtras(extras); }
810
- }
811
-
812
- export function makeStepSampler(
813
- options: StepSamplerOptions,
814
- config: DeviceStepSamplerConfig,
815
- ): DeviceStepSampler;
816
- export function makeStepSampler(
817
- options: StepSamplerOptions,
818
- config: NumberStepSamplerConfig,
819
- ): NumberStepSampler;
820
- export function makeStepSampler(
821
- options: StepSamplerOptions,
822
- config: DeviceStepSamplerConfig | NumberStepSamplerConfig,
823
- ): DeviceStepSampler | NumberStepSampler {
824
- const sampler = config.sampler ?? makeSampler(options);
825
- const processors = makeLogitsProcessors(options);
826
- const grammar = options.grammar ?? null;
827
- const captureSelected = config.captureSelectedLogprob === true;
828
- const captureTop = Math.max(0, config.captureTopLogprobs ?? 0);
829
- const capture = captureSelected || captureTop > 0;
830
- const greedyWithoutMetadata = (options.temperature ?? 0) === 0 && !options.curve && !capture && !config.sampler;
831
- let history: MlxArray | null = null;
832
-
833
- const seedHistory = (tokens: readonly number[]): void => {
834
- if (processors.length === 0) return;
835
- const next = ops.fromInt32([...tokens], [tokens.length]);
836
- const previous = history;
837
- history = next;
838
- previous?.dispose();
839
- };
840
-
841
- const commitDevice = (token: MlxArray): void => {
842
- if (processors.length === 0) return;
843
- const one = ops.reshape(token, [1]);
844
- if (!history) {
845
- history = one;
846
- return;
847
- }
848
- const previous = history;
849
- try {
850
- history = ops.concatAxis([previous, one], 0);
851
- previous.dispose();
852
- } finally {
853
- one.dispose();
854
- }
855
- };
856
-
857
- const commitNumbers = (tokens: readonly number[]): void => {
858
- if (tokens.length === 0 || processors.length === 0) return;
859
- const next = ops.fromInt32([...tokens], [tokens.length]);
860
- if (!history) {
861
- history = next;
862
- return;
863
- }
864
- const previous = history;
865
- try {
866
- history = ops.concatAxis([previous, next], 0);
867
- previous.dispose();
868
- } finally {
869
- next.dispose();
870
- }
871
- };
872
-
873
- const sampleDevice = (input: MlxArray, step: number): StepSample<MlxArray> => {
874
- const vocab = input.shape[input.shape.length - 1]!;
875
- let current = input.shape.length === 2 ? input : ops.reshape(input, [1, vocab]);
876
- let ownsCurrent = current !== input;
877
- let logprobs: MlxArray | null = null;
878
- let token: MlxArray | null = null;
879
- let extras: StepExtras | null = null;
880
- try {
881
- for (const processor of processors) {
882
- const next = processor(history, current);
883
- if (ownsCurrent && next !== current) current.dispose();
884
- current = next;
885
- ownsCurrent = current !== input;
886
- }
887
- if (grammar && !grammar.isTerminated) {
888
- const next = grammar.applyMask(current);
889
- if (ownsCurrent && next !== current) current.dispose();
890
- current = next;
891
- ownsCurrent = current !== input;
892
- }
893
- if (greedyWithoutMetadata)
894
- return { token: normalizedArgmax(current), extras: null };
895
- logprobs = toLogprobs(current);
896
- if (ownsCurrent) current.dispose();
897
- current = input;
898
- ownsCurrent = false;
899
- token = sampler(logprobs, step);
900
-
901
- if (capture) {
902
- extras = { sel: null, topIdx: null, topVals: null };
903
- if (captureSelected) {
904
- const idx = ops.reshape(token, [1, 1]);
905
- try {
906
- extras.sel = ops.takeAlongAxis(logprobs, idx, -1);
907
- } finally {
908
- idx.dispose();
909
- }
910
- }
911
- if (captureTop > 0) {
912
- const k = Math.min(captureTop, vocab);
913
- let neg: MlxArray | null = null;
914
- let partition: MlxArray | null = null;
915
- let view: MlxArray | null = null;
916
- try {
917
- neg = ops.neg(logprobs);
918
- partition = ops.argpartitionAxis(neg, k - 1, -1);
919
- view = partition.slice([0, 0], [1, k]);
920
- extras.topIdx = ops.contiguous(view);
921
- extras.topVals = ops.takeAlongAxis(logprobs, extras.topIdx, -1);
922
- } finally {
923
- neg?.dispose();
924
- partition?.dispose();
925
- view?.dispose();
926
- }
927
- }
928
- }
929
-
930
- logprobs.dispose();
931
- logprobs = null;
932
- const result = { token, extras };
933
- token = null;
934
- extras = null;
935
- return result;
936
- } finally {
937
- if (ownsCurrent) current.dispose();
938
- logprobs?.dispose();
939
- token?.dispose();
940
- disposeStepExtras(extras);
941
- }
942
- };
943
-
944
- if (config.initialHistory) seedHistory(config.initialHistory);
945
-
946
- const common = {
947
- independent: isPlainGreedy(options, processors.length > 0) && !capture && !config.sampler
948
- ? independentGreedySampling : undefined,
949
- isPlainGreedy: isPlainGreedy(options, processors.length > 0),
950
- capturesLogprobs: capture,
951
- needsHistory: processors.length > 0,
952
- seedHistory,
953
- commitDevice,
954
- commitNumbers,
955
- dispose: () => {
956
- history?.dispose();
957
- history = null;
958
- },
959
- };
960
-
961
- if (config.tokenRepresentation === "device") {
962
- return {
963
- ...common,
964
- sample(logits, step) {
965
- const result = sampleDevice(logits, step);
966
- if (config.historyUpdate === "after-sample") commitDevice(result.token);
967
- return result;
968
- },
969
- };
970
- }
971
-
972
- return {
973
- ...common,
974
- async sample(logits, step) {
975
- if (grammar && !grammar.isTerminated) await grammar.ready();
976
- const result = sampleDevice(logits, step);
977
- let tokenArray: MlxArray | null = result.token;
978
- try {
979
- // Read the sampler's integer result directly. Adding an astype here
980
- // would append work behind the next dispatched decode step.
981
- const token = ops.itemUint32(tokenArray);
982
- tokenArray.dispose();
983
- tokenArray = null;
984
- if (config.acceptGrammar && grammar && !config.eosTokenIds?.includes(token))
985
- grammar.accept(token);
986
- if (config.historyUpdate === "after-sample") commitNumbers([token]);
987
- return { token, extras: result.extras };
988
- } catch (error) {
989
- disposeStepExtras(result.extras);
990
- throw error;
991
- } finally {
992
- tokenArray?.dispose();
993
- }
994
- },
995
- };
996
- }
997
-
998
- /** Stateless sampling across rows or verification positions. Preserve the
999
- * normalized-score argmax, including rounding-created ties. */
1000
- export const independentGreedySampling = Object.freeze({
1001
- sample: normalizedArgmax,
1002
- });
1003
-
1004
- /** logits [..., V] → logprobs [..., V] (logits - logsumexp). */
1005
- export function toLogprobs(logits: MlxArray): MlxArray {
1006
- const lse = ops.logsumexpAxis(logits, -1, true);
1007
- const out = ops.sub(logits, lse);
1008
- lse.dispose();
1009
- return out;
1010
- }
1011
-
1012
- export { Dtype };