mlx-bun 0.0.13 → 0.3.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 (427) hide show
  1. package/README.md +71 -578
  2. package/bin/mlx-bun.mjs +1 -1
  3. package/docs/README.md +91 -0
  4. package/docs/{design → archive}/hlg-sampling.md +3 -3
  5. package/docs/{design → archive/investigations}/audio-input-plan.md +4 -4
  6. package/docs/{design → archive/investigations}/colibri-glm52-port.md +1 -1
  7. package/docs/{design → archive/investigations}/diffusion-gemma-port.md +3 -3
  8. package/docs/{design → archive/investigations}/faithful-l1-consolidation.md +4 -4
  9. package/docs/{investigations → archive/investigations}/hlg-sampling-investigation.md +1 -1
  10. package/docs/{design → archive/investigations}/minicpm5-decode-megakernel.md +11 -11
  11. package/docs/{design → archive/investigations}/optimization_plan.md +1 -1
  12. package/docs/archive/investigations/pareto-specialized-runtime-findings.md +92 -0
  13. package/docs/{design → archive/investigations}/pre-colibri-stabilization.md +5 -5
  14. package/docs/{design → archive/investigations}/the-dreaming-handoff.md +2 -2
  15. package/docs/{planning → archive/planning}/chat-ui-vision.md +1 -1
  16. package/docs/{planning → archive/planning}/chunk-task-roadmap.md +1 -1
  17. package/docs/{planning → archive/planning}/curve-sampler-research-plan.md +4 -4
  18. package/docs/{planning → archive/planning}/memory-docs-and-dag-plan.md +1 -1
  19. package/docs/{planning → archive/planning}/release-notes-v0.0.9.md +1 -1
  20. package/docs/archive/planning/release-notes-v0.2.0.md +49 -0
  21. package/docs/{planning → archive/planning}/website-readme-pass-plan.md +1 -1
  22. package/docs/design/batching.md +569 -0
  23. package/docs/design/decode-speed-program.md +3178 -169
  24. package/docs/design/dreaming-nightly-pipeline.md +675 -282
  25. package/docs/design/generic-model-support.md +579 -334
  26. package/docs/design/kv-cache.md +680 -0
  27. package/docs/design/orpo-training.md +673 -1239
  28. package/docs/design/speculative-decoding.md +1627 -0
  29. package/docs/design/turboquant.md +2102 -0
  30. package/docs/design/unified-engine-frontier-plan.md +1831 -727
  31. package/docs/design/web-chat-redesign.md +666 -1083
  32. package/docs/planning/PRODUCT_ROADMAP.md +34 -1
  33. package/docs/planning/release-notes-v0.3.0.md +35 -0
  34. package/docs/planning/video-series.md +421 -0
  35. package/docs/reference/benchmarks.md +1162 -0
  36. package/docs/reference/cli.md +395 -149
  37. package/docs/reference/distribution.md +321 -181
  38. package/docs/reference/environment.md +348 -0
  39. package/docs/reference/glossary.md +39 -0
  40. package/docs/reference/library-api.md +580 -142
  41. package/docs/reference/memory.md +227 -64
  42. package/docs/reference/models.md +137 -6
  43. package/docs/reference/server-api.md +938 -422
  44. package/docs/reference/server-config.md +652 -320
  45. package/docs/reference/training.md +393 -254
  46. package/docs/reference/troubleshooting.md +166 -0
  47. package/package.json +10 -5
  48. package/src/admission-plan.ts +18 -0
  49. package/src/anthropic.ts +92 -3
  50. package/src/audio/decode.ts +2 -2
  51. package/src/audio/features.ts +2 -2
  52. package/src/backends/mlx/autoregressive.ts +108 -0
  53. package/src/backends/mlx/batch-group.ts +1646 -0
  54. package/src/backends/mlx/diffusion.ts +39 -0
  55. package/src/backends/mlx/draft-target.ts +47 -0
  56. package/src/backends/mlx/evaluation.ts +105 -0
  57. package/src/backends/mlx/fill-append.ts +45 -0
  58. package/src/backends/mlx/gateway-binding.ts +71 -0
  59. package/src/backends/mlx/graph.ts +38 -0
  60. package/src/backends/mlx/memory-client.ts +189 -0
  61. package/src/backends/mlx/memory-guard.ts +40 -0
  62. package/src/backends/mlx/methods.ts +90 -0
  63. package/src/backends/mlx/model-prompt.ts +164 -0
  64. package/src/backends/mlx/model-serving.ts +79 -0
  65. package/src/backends/mlx/prefill.ts +33 -0
  66. package/src/backends/mlx/request-policy.ts +20 -0
  67. package/src/backends/mlx/rollback.ts +51 -0
  68. package/src/backends/mlx/serial-executor.ts +273 -0
  69. package/src/backends/mlx/speculative.ts +114 -0
  70. package/src/backends/mlx/state-views.ts +26 -0
  71. package/src/backends/mlx/text-engine.ts +73 -0
  72. package/src/cli.ts +189 -61
  73. package/src/client.ts +66 -0
  74. package/src/config.ts +21 -4
  75. package/src/contracts/completion.ts +16 -0
  76. package/src/contracts/execution.ts +49 -0
  77. package/src/contracts/generation.ts +103 -0
  78. package/src/contracts/host.ts +7 -0
  79. package/src/contracts/jobs.ts +66 -0
  80. package/src/contracts/pi-provider.ts +30 -0
  81. package/src/contracts/pi.ts +259 -0
  82. package/src/contracts/resources.ts +18 -0
  83. package/src/contracts/scheduling.ts +27 -0
  84. package/src/contracts/tsconfig.json +14 -0
  85. package/src/diffusion/diffusion-generate.ts +218 -153
  86. package/src/embed.ts +1 -1
  87. package/src/engine/admission.ts +59 -0
  88. package/src/engine/cancellation.ts +38 -0
  89. package/src/engine/engine.ts +56 -0
  90. package/src/engine/execution-coordinator.ts +70 -0
  91. package/src/engine/execution-plan.ts +51 -0
  92. package/src/engine/resources.ts +42 -0
  93. package/src/engine/scheduler.ts +67 -0
  94. package/src/engine/session.ts +247 -0
  95. package/src/eval/README.md +44 -1
  96. package/src/eval/kl.ts +263 -23
  97. package/src/eval/reference-logits.ts +207 -0
  98. package/src/eval/runner.ts +10 -79
  99. package/src/eval/tasks/bfcl.ts +2 -1
  100. package/src/eval/tasks/gsm8k.ts +2 -1
  101. package/src/eval/tasks/hashhop.ts +2 -1
  102. package/src/eval/tasks/humaneval.ts +5 -4
  103. package/src/eval/tasks/ifeval.ts +2 -1
  104. package/src/eval/tasks/mmlu.ts +2 -1
  105. package/src/expert-io.ts +3 -1
  106. package/src/expert-offload.ts +3 -1
  107. package/src/fill/echo-index.ts +188 -0
  108. package/src/fill/fill-session.ts +452 -0
  109. package/src/fill/proposal.ts +68 -0
  110. package/src/fill/schema-rows.ts +506 -0
  111. package/src/fill/tool-boundary.ts +103 -0
  112. package/src/fit.ts +24 -43
  113. package/src/generate.ts +740 -337
  114. package/src/grammar.ts +14 -8
  115. package/src/harness-pi.ts +15 -34
  116. package/src/hub-rest.ts +4 -4
  117. package/src/index.ts +27 -0
  118. package/src/inference/denoising.ts +17 -0
  119. package/src/inference/graph.ts +33 -0
  120. package/src/inference/prefill.ts +39 -0
  121. package/src/inference/rollback.ts +7 -0
  122. package/src/jobs/db.ts +4 -0
  123. package/src/jobs/index.ts +2 -0
  124. package/src/jobs/job-entry.ts +15 -14
  125. package/src/jobs/runner.ts +98 -13
  126. package/src/jobs/task-client.ts +19 -0
  127. package/src/jobs/types.ts +2 -58
  128. package/src/kv-scheme.ts +199 -0
  129. package/src/kv-store.ts +459 -234
  130. package/src/lab/README.md +18 -0
  131. package/src/{assets → lab/curve}/curve-designer.html +2 -2
  132. package/src/{curve-sampler.ts → lab/curve/curve-sampler.ts} +2 -2
  133. package/src/{expert-trace.ts → lab/expert-trace/expert-trace.ts} +7 -5
  134. package/src/{model → lab/paged-kv}/paged-kv.ts +9 -6
  135. package/src/library.ts +40 -0
  136. package/src/lora.ts +18 -0
  137. package/src/media-fetch.ts +20 -4
  138. package/src/memory/article.ts +1 -1
  139. package/src/memory/chunk.ts +1 -1
  140. package/src/memory/model.ts +32 -170
  141. package/src/memory/prompts.ts +1 -1
  142. package/src/memory/rest.ts +1 -1
  143. package/src/memory/schedule.ts +1 -1
  144. package/src/memory/stages.ts +4 -1
  145. package/src/memory/vault.ts +3 -4
  146. package/src/mlx/array.ts +9 -10
  147. package/src/mlx/compile.ts +12 -2
  148. package/src/mlx/ffi.ts +66 -22
  149. package/src/mlx/materialize.ts +23 -0
  150. package/src/mlx/metal-kernel.ts +10 -11
  151. package/src/mlx/ops.ts +64 -19
  152. package/src/mlx/quantized-rows.ts +36 -0
  153. package/src/mlx/token-bitmask.ts +52 -0
  154. package/src/mlx/turboquant-kv-decode.ts +82 -0
  155. package/src/mlx/turboquant-kv-inverse.ts +122 -0
  156. package/src/mlx/turboquant-ops.ts +33 -3
  157. package/src/mlx/turboquant-tables.ts +2 -2
  158. package/src/model/batched-mask.ts +9 -3
  159. package/src/model/batched-quant.ts +2 -2
  160. package/src/model/batched-rotating-quant.ts +45 -99
  161. package/src/model/batched-rotating-state.ts +73 -0
  162. package/src/model/batched-rotating.ts +57 -106
  163. package/src/model/batched-row-storage.ts +127 -0
  164. package/src/model/compiled-decode.ts +4 -3
  165. package/src/model/diffusion-gemma.ts +8 -8
  166. package/src/model/factory.ts +87 -49
  167. package/src/model/fingerprint.ts +1 -1
  168. package/src/model/flash-attention.ts +3 -3
  169. package/src/model/gemma4-base.ts +187 -17
  170. package/src/model/gemma4.ts +6 -6
  171. package/src/model/generated/gemma4-12b.ts +52 -148
  172. package/src/model/generated/gemma4-26b.ts +34 -94
  173. package/src/model/generated/gemma4-e4b.ts +28 -76
  174. package/src/model/glm52-cache.ts +19 -9
  175. package/src/model/glm52-dsa.ts +13 -9
  176. package/src/model/glm52-memory.ts +28 -1
  177. package/src/model/implementation.ts +69 -0
  178. package/src/model/minicpm5.ts +7 -8
  179. package/src/model/profile.ts +443 -0
  180. package/src/model/qwen-append.ts +12 -0
  181. package/src/model/qwen-conv.ts +52 -0
  182. package/src/model/qwen3-delta.ts +98 -2
  183. package/src/model/qwen3-mrope.ts +252 -0
  184. package/src/model/qwen3_5-checkpoint.ts +164 -0
  185. package/src/model/qwen3_5.ts +336 -60
  186. package/src/model/support.ts +1 -1
  187. package/src/model/trellis-balanced-scatter.ts +51 -0
  188. package/src/model/trellis-linear.ts +672 -0
  189. package/src/model/trellis-shared-m.ts +151 -0
  190. package/src/model/trellis-shared-scatter.ts +144 -0
  191. package/src/model/trellis-splitk-prefill.ts +158 -0
  192. package/src/model/trellis-tiled-prefill.ts +136 -0
  193. package/src/model/trellis-vector-expand.ts +62 -0
  194. package/src/model/trellis-wide-prefill.ts +94 -0
  195. package/src/model/universal/dense.ts +1 -1
  196. package/src/model/universal/modules.ts +8 -1
  197. package/src/native/frame_extract.swift +140 -0
  198. package/src/native-pack.ts +15 -7
  199. package/src/pi-provider.ts +6 -64
  200. package/src/pi-web.ts +14 -320
  201. package/src/prompt-cache.ts +97 -54
  202. package/src/quantize/allocator.ts +1 -1
  203. package/src/quantize/atomic-output.ts +38 -0
  204. package/src/quantize/calibration.ts +2 -1
  205. package/src/quantize/config-writer.ts +16 -3
  206. package/src/quantize/index.ts +28 -1
  207. package/src/quantize/job.ts +11 -0
  208. package/src/quantize/quantizer.ts +265 -100
  209. package/src/quantize/rotate.ts +603 -0
  210. package/src/quantize/safetensors-writer.ts +79 -1
  211. package/src/quantize/sensitivity.ts +41 -59
  212. package/src/quantize/trellis.ts +586 -0
  213. package/src/quantize/weight-transform.ts +292 -0
  214. package/src/responses.ts +130 -3
  215. package/src/runtime-config.ts +81 -0
  216. package/src/sampler.ts +276 -4
  217. package/src/serve/admin-routes.ts +184 -0
  218. package/src/serve/aux-routes.ts +132 -0
  219. package/src/serve/batch-scheduler.ts +8 -1558
  220. package/src/serve/chat-request.ts +391 -0
  221. package/src/serve/chat-stage.ts +195 -0
  222. package/src/serve/checkpoint-identity.ts +64 -0
  223. package/src/serve/completion-executor.ts +354 -0
  224. package/src/serve/completion-sink.ts +157 -0
  225. package/src/serve/discovery-routes.ts +204 -0
  226. package/src/serve/generation-gateway.ts +211 -243
  227. package/src/serve/http.ts +159 -0
  228. package/src/serve/inference-request.ts +79 -0
  229. package/src/serve/isolate.ts +297 -105
  230. package/src/serve/kv-budget.ts +14 -0
  231. package/src/serve/lab-routes.ts +341 -0
  232. package/src/serve/lane-registry.ts +2 -1
  233. package/src/serve/model-admin-routes.ts +155 -0
  234. package/src/serve/model-binding.ts +43 -0
  235. package/src/serve/model-host.ts +512 -0
  236. package/src/serve/openai-wire.ts +103 -0
  237. package/src/serve/parent-application.ts +56 -0
  238. package/src/serve/pipeline.ts +33 -0
  239. package/src/serve/preparation.ts +33 -0
  240. package/src/serve/prompt-response-trace.ts +147 -0
  241. package/src/serve/request-plan.ts +162 -0
  242. package/src/serve/request-prep.ts +346 -0
  243. package/src/serve/response-lease.ts +24 -0
  244. package/src/serve/responses-client.ts +69 -0
  245. package/src/serve/session-completion-engine.ts +110 -0
  246. package/src/serve/session-search.ts +1 -1
  247. package/src/serve/static-routes.ts +101 -0
  248. package/src/serve/text-completion-stage.ts +104 -0
  249. package/src/serve/token-streams.ts +519 -0
  250. package/src/server.ts +523 -3551
  251. package/src/spec/assistant-source.ts +10 -44
  252. package/src/spec/deepspec-source.ts +6 -6
  253. package/src/spec/dflash-source.ts +9 -8
  254. package/src/spec/dspark/ab-stats.ts +3 -3
  255. package/src/spec/dspark/calibration.ts +2 -2
  256. package/src/spec/dspark/deepspec-module.ts +2 -2
  257. package/src/spec/dspark/generate-dflash.ts +2 -2
  258. package/src/spec/dspark/generate.ts +2 -2
  259. package/src/spec/dspark/loader.ts +1 -1
  260. package/src/spec/dspark/module-dflash.ts +5 -4
  261. package/src/spec/dspark/module.ts +3 -3
  262. package/src/spec/dspark/quantize-drafter.ts +1 -1
  263. package/src/spec/generate.ts +1 -1
  264. package/src/spec/glm52-mtp-source.ts +9 -1
  265. package/src/spec/ngram-source.ts +1 -1
  266. package/src/spec/prefix-state.ts +45 -0
  267. package/src/spec/qwen-mtp-source.ts +528 -0
  268. package/src/spec/serve-loop.ts +179 -213
  269. package/src/spec/source.ts +42 -10
  270. package/src/spec/two-model.ts +1 -1
  271. package/src/ssd-cache.ts +95 -24
  272. package/src/ssd-durability.ts +207 -0
  273. package/src/tool-call.ts +51 -14
  274. package/src/train/flash-cce.ts +14 -13
  275. package/src/train/forward.ts +38 -1
  276. package/src/train/loss.ts +3 -2
  277. package/src/train/prefix-shared.ts +5 -1
  278. package/src/train/segmented.ts +9 -6
  279. package/src/train/trainer.ts +9 -8
  280. package/src/vision/preprocess.ts +1 -1
  281. package/src/vision/prompt.ts +48 -2
  282. package/src/vision/qwen3vl-preprocess.ts +409 -0
  283. package/src/vision/qwen3vl-prompt.ts +196 -0
  284. package/src/vision/qwen3vl-tower.ts +555 -0
  285. package/src/vision/video-frames.ts +148 -0
  286. package/src/web/app.html +1 -1
  287. package/src/web/app.js +15 -6
  288. package/src/web/src/adapters-panel.ts +3 -3
  289. package/src/web/src/assistant.ts +2 -36
  290. package/src/web/src/chat.ts +16 -9
  291. package/src/web/src/composer.ts +4 -4
  292. package/src/web/src/hub.ts +1 -1
  293. package/src/web/src/markdown.ts +0 -0
  294. package/src/web/src/memory-panel.ts +1 -1
  295. package/src/web/src/model-picker.ts +1 -1
  296. package/src/web/src/palette.ts +1 -1
  297. package/src/web/src/protocol.ts +3 -39
  298. package/src/web/src/sessions.ts +1 -1
  299. package/src/web/src/ui-catalog.ts +4 -18
  300. package/src/web-assets.ts +47 -0
  301. package/src/weights.ts +134 -33
  302. package/docs/archive/mlx-bun-lab-report.html +0 -275
  303. package/docs/archive/wwdc-mlx-bun.html +0 -848
  304. package/docs/design/adapters-end-to-end.md +0 -205
  305. package/docs/design/batching-perf-path.md +0 -255
  306. package/docs/design/batching-v2-plan.md +0 -529
  307. package/docs/design/bucketing-stage.md +0 -197
  308. package/docs/design/compat-cli-surface-design.md +0 -230
  309. package/docs/design/docs-reorg-plan.md +0 -165
  310. package/docs/design/dspark-serving-program.md +0 -371
  311. package/docs/design/dspark-speculative-decoding.md +0 -268
  312. package/docs/design/grammar-spec-batching-integration.md +0 -301
  313. package/docs/design/memory-inference-path.md +0 -422
  314. package/docs/design/memory-synthesis.md +0 -287
  315. package/docs/design/memory-system.md +0 -237
  316. package/docs/design/mlx-lm-tool-parity-plan.md +0 -545
  317. package/docs/design/omlx-adoption-map.md +0 -98
  318. package/docs/design/orpo-dynamic-lambda.md +0 -220
  319. package/docs/design/orpo-future-enhancements.md +0 -340
  320. package/docs/design/paged-kv-cache.md +0 -214
  321. package/docs/design/parallel-slots.md +0 -567
  322. package/docs/design/parity-tier-dag.md +0 -161
  323. package/docs/design/repo-cleanup-plan.md +0 -189
  324. package/docs/design/runtime-isolation.md +0 -263
  325. package/docs/design/segmented-backward-training.md +0 -543
  326. package/docs/design/spec-decode-larger-targets.md +0 -229
  327. package/docs/design/ssd-kv-cold-tier.md +0 -288
  328. package/docs/design/structured-output.md +0 -484
  329. package/docs/design/tauri-desktop-app.md +0 -127
  330. package/docs/design/the-dreaming-master-plan.md +0 -445
  331. package/docs/design/turboquant-kv.md +0 -235
  332. package/docs/design/w4a16-compute-precision-spike.md +0 -232
  333. package/docs/design/web-chat-beat-matrix.md +0 -315
  334. package/docs/design/write-pipeline-entity.md +0 -468
  335. package/docs/investigations/curve-runs/bisector-route.json +0 -98
  336. package/docs/investigations/curve-runs/bisector-trace.json +0 -1393
  337. package/docs/investigations/curve-runs/curve-terrain.json +0 -1179
  338. package/docs/investigations/curve-runs/curve-terrain.svg +0 -42
  339. package/docs/investigations/hlg-ab.html +0 -34
  340. package/docs/investigations/hlg-explorer.html +0 -238
  341. package/docs/investigations/hlg-figs/cliff.svg +0 -1
  342. package/docs/investigations/hlg-figs/cross.svg +0 -1
  343. package/docs/investigations/hlg-figs/edges.svg +0 -1
  344. package/docs/investigations/hlg-figs/k20-grids.svg +0 -1
  345. package/docs/investigations/hlg-figs/k20-peaks.svg +0 -1
  346. package/docs/investigations/hlg-figs/lw-curve.svg +0 -1
  347. package/docs/investigations/hlg-figs/terrain.svg +0 -1
  348. package/docs/investigations/hlg-report.html +0 -262
  349. package/docs/investigations/hlg-runs/hlg-ab.json +0 -149
  350. package/docs/investigations/hlg-runs/hlg-blind-prompts.md +0 -87
  351. package/docs/investigations/hlg-runs/hlg-blind.json +0 -107
  352. package/docs/investigations/hlg-runs/hlg-cliff.json +0 -197
  353. package/docs/investigations/hlg-runs/hlg-cross.json +0 -505
  354. package/docs/investigations/hlg-runs/hlg-edge.json +0 -388
  355. package/docs/investigations/hlg-runs/hlg-eval1.json +0 -25
  356. package/docs/investigations/hlg-runs/hlg-frontier.json +0 -86
  357. package/docs/investigations/hlg-runs/hlg-grid.json +0 -242
  358. package/docs/investigations/hlg-runs/hlg-grid2.json +0 -343
  359. package/docs/investigations/hlg-runs/hlg-lw-coarse.json +0 -110
  360. package/docs/investigations/hlg-runs/hlg-map.json +0 -383
  361. package/docs/investigations/hlg-runs/run0-original.log +0 -159
  362. package/docs/investigations/hlg-runs/runA-recommended.log +0 -131
  363. package/docs/investigations/hlg-runs/runAA-cliff-cpm5.log +0 -26
  364. package/docs/investigations/hlg-runs/runAB-grid2-e4b.log +0 -18
  365. package/docs/investigations/hlg-runs/runAC-peak-e4b-partial.log +0 -25
  366. package/docs/investigations/hlg-runs/runAD-ab-samples.log +0 -8
  367. package/docs/investigations/hlg-runs/runAE-edge-e4b.log +0 -51
  368. package/docs/investigations/hlg-runs/runAF-logit-calibration.log +0 -10
  369. package/docs/investigations/hlg-runs/runAG-eval-config2.log +0 -16
  370. package/docs/investigations/hlg-runs/runB-gain-variants.log +0 -192
  371. package/docs/investigations/hlg-runs/runC-pivots.log +0 -162
  372. package/docs/investigations/hlg-runs/runD-oetf.log +0 -132
  373. package/docs/investigations/hlg-runs/runE-eotf.log +0 -162
  374. package/docs/investigations/hlg-runs/runF-shaper-working.log +0 -86
  375. package/docs/investigations/hlg-runs/runG-shaper-sweep.log +0 -101
  376. package/docs/investigations/hlg-runs/runH-wsweep.log +0 -176
  377. package/docs/investigations/hlg-runs/runI-asweep.log +0 -176
  378. package/docs/investigations/hlg-runs/runJ-knobmap.log +0 -49
  379. package/docs/investigations/hlg-runs/runK-frontier.log +0 -19
  380. package/docs/investigations/hlg-runs/runL-widemap.log +0 -65
  381. package/docs/investigations/hlg-runs/runM-frontier-emb.log +0 -15
  382. package/docs/investigations/hlg-runs/runN-verify.log +0 -116
  383. package/docs/investigations/hlg-runs/runO-frontier-seed5000.log +0 -15
  384. package/docs/investigations/hlg-runs/runP-grid-AxSm.log +0 -15
  385. package/docs/investigations/hlg-runs/runQ-grid-tgW.log +0 -15
  386. package/docs/investigations/hlg-runs/runR-blind-transcript.log +0 -79
  387. package/docs/investigations/hlg-runs/runS-cross-coherence.log +0 -33
  388. package/docs/investigations/hlg-runs/runT-cross-cpm5.log +0 -33
  389. package/docs/investigations/hlg-runs/runU-cross-12b.log +0 -33
  390. package/docs/investigations/hlg-runs/runV-lw-e4b.log +0 -22
  391. package/docs/investigations/hlg-runs/runW-lw-12b.log +0 -22
  392. package/docs/investigations/hlg-runs/runX-lw-cpm5.log +0 -22
  393. package/docs/investigations/hlg-runs/runY-cliff-e4b.log +0 -26
  394. package/docs/investigations/hlg-runs/runZ-cliff-12b.log +0 -26
  395. package/docs/planning/IDEAS.md +0 -69
  396. package/docs/reference/embedding.md +0 -197
  397. package/docs/reference/features-matrix.md +0 -100
  398. package/docs/reference/orpo-quickstart.md +0 -135
  399. package/src/flags.ts +0 -13
  400. /package/docs/{investigations → archive/investigations}/chunk-finetune-experiment.md +0 -0
  401. /package/docs/{investigations → archive/investigations}/colibri-oracle-pin.md +0 -0
  402. /package/docs/{investigations → archive/investigations}/curve-bisector-routing.md +0 -0
  403. /package/docs/{investigations → archive/investigations}/decode-roofline-lookagain.md +0 -0
  404. /package/docs/{investigations → archive/investigations}/dspark-handoff.md +0 -0
  405. /package/docs/{investigations → archive/investigations}/expert-offload-single-user-moe.md +0 -0
  406. /package/docs/{investigations → archive/investigations}/indexshare-performance-spike.md +0 -0
  407. /package/docs/{investigations → archive/investigations}/kernel-perf-review-2026-07.md +0 -0
  408. /package/docs/{investigations → archive/investigations}/lab-build-journal.md +0 -0
  409. /package/docs/{investigations → archive/investigations}/openwiki-evaluation.md +0 -0
  410. /package/docs/{investigations → archive/investigations}/orpo-base-uf-experiment-and-directions.md +0 -0
  411. /package/docs/{investigations → archive/investigations}/orpo-flash-cce-pin-leak.md +0 -0
  412. /package/docs/{investigations → archive/investigations}/orpo-uf-testing-handoff.md +0 -0
  413. /package/docs/{investigations → archive/investigations}/pi-builtin-investigation.md +0 -0
  414. /package/docs/{investigations → archive/investigations}/segmented-backward-handoff.md +0 -0
  415. /package/docs/{investigations → archive/investigations}/starter-model-port-handoff.md +0 -0
  416. /package/docs/{investigations → archive/investigations}/steel-flash-cce-handoff.md +0 -0
  417. /package/docs/{investigations → archive/investigations}/trainer-validation-experiment.md +0 -0
  418. /package/docs/{planning → archive/planning}/chat-ui-vision-memory-first.md +0 -0
  419. /package/docs/{planning → archive/planning}/journal.md +0 -0
  420. /package/docs/{planning → archive/planning}/pi-integration-review.md +0 -0
  421. /package/docs/{planning → archive/planning}/release-notes-v0.0.10.md +0 -0
  422. /package/docs/{planning → archive/planning}/release-notes-v0.0.11.md +0 -0
  423. /package/docs/{planning → archive/planning}/release-notes-v0.0.12.md +0 -0
  424. /package/docs/{planning → archive/planning}/release-notes-v0.0.13.md +0 -0
  425. /package/docs/{planning → archive/planning}/web-ui-pass-plan.md +0 -0
  426. /package/{docs/investigations → src/serve/assets}/curve-terrain.html +0 -0
  427. /package/{docs/dag → src/serve/assets}/training-inference-map.html +0 -0
@@ -1,3 +1,5 @@
1
+ import { leaseCacheState } from "./backends/mlx/state-views";
2
+ import { withResource, cleanupFailure, disposeResources, ownResource } from "./engine/resources";
1
3
  // Byte-capped LRU prompt cache — the RAM tier of the Layer-0 KV store.
2
4
  //
3
5
  // The mlx-lm lesson (PLAN.md): a count-capped cache of multi-GB KV
@@ -5,13 +7,14 @@
5
7
  // per entry) and evicts least-recently-used until under the cap.
6
8
  //
7
9
  // Usage pattern (single generation queue, so take/put is race-free):
8
- // const hit = cache.take(promptIds); // longest-prefix match → CLONES
10
+ // const hit = cache.take(promptIds); // longest-prefix match
9
11
  // generate(model, promptIds, { cache: hit?.caches ?? fresh })
10
12
  // cache.put([...promptIds, ...generated], caches, ns, hit?.retain);
11
- // take() is NON-CONSUMING (prefix sharing): it serves zero-copy clones and
12
- // leaves the donor entry in place — N agents sharing a system prompt all
13
- // clone from one donor, one prefill; put() supersedes same-ns
14
- // prefix-ancestors (when the new entry is trimmable) so a conversation
13
+ // take() is NON-CONSUMING for trimmable caches: it serves zero-copy clones
14
+ // and leaves the donor in place, so N agents can share one prefill.
15
+ // Qwen hybrid entries containing recurrent SSM state transfer ownership on
16
+ // an exact hit, avoiding an extra resident recurrent snapshot. put() supersedes
17
+ // same-ns prefix-ancestors (when the new entry is trimmable) so a conversation
15
18
  // stays one entry, not one per turn.
16
19
  //
17
20
  // TIERING (Layer 0, unified-engine plan): when a ColdTier is attached,
@@ -24,7 +27,7 @@
24
27
  // reachable); onPut lets the server schedule its debounced write-behind
25
28
  // snapshot for both lanes.
26
29
 
27
- import { TurboQuantKVCache, type Cache } from "./model/gemma4";
30
+ import type { Cache } from "./model/gemma4";
28
31
  import { cloneKvCaches } from "./kv-store";
29
32
 
30
33
  /** Reference-counted release: wraps an entry's `retain` (e.g. an mmap
@@ -55,8 +58,9 @@ function makeSharedRetain(retain: (() => void) | undefined): { acquire(): () =>
55
58
 
56
59
  /** The cold (SSD) tier the RAM cache tiers over. Structural — this module
57
60
  * never imports ssd-cache (which imports us); the server binds
58
- * SsdCacheStore + the model into this shape (src/server.ts). All methods
59
- * must be failure-proof: any error degrades to "no hit"/"not stored". */
61
+ * SsdCacheStore + the model into this shape (src/server.ts). Lookup and
62
+ * restore failures return null; store returns false on failure. Operations
63
+ * that require persistence retain their donor if storing fails. */
60
64
  export interface ColdTier {
61
65
  /** Longest stored usable prefix for prompt/ns — index-only, no I/O.
62
66
  * `handle` is the tier's opaque entry token, passed back to restore. */
@@ -65,7 +69,9 @@ export interface ColdTier {
65
69
  * pages fault in lazily). `retain` must run after the caches are
66
70
  * disposed (it unmaps the backing file). Null on any failure. */
67
71
  restore(handle: unknown): { tokens: number[]; caches: Cache[]; retain: () => void } | null;
68
- store(tokens: number[], caches: Cache[], ns: string): void;
72
+ /** Borrow live caches and finish persistence before returning. A false
73
+ * result prevents a required demotion or recurrent ownership transfer. */
74
+ store(tokens: number[], caches: Cache[], ns: string): boolean | void;
69
75
  }
70
76
 
71
77
  /** Spill sink for eviction/demotion (write-behind, 2026-07-06).
@@ -105,14 +111,7 @@ export interface PromptCacheEntry {
105
111
  export function cacheBytes(caches: Cache[]): number {
106
112
  let total = 0;
107
113
  for (const c of caches) {
108
- const state = c.state();
109
- for (const a of state) total += a.nbytes;
110
- // Most Cache kinds' state() returns their own live-owned arrays (safe
111
- // to just read), but TurboQuantKVCache allocates fresh trimmed slice
112
- // views per call (kv-store.ts snapshotCache/cloneKvCaches contract) —
113
- // those must be disposed here or they leak (see generate.ts
114
- // evalCacheState for the same hazard on the prefill path).
115
- if (c instanceof TurboQuantKVCache) for (const a of state) a.dispose();
114
+ total += withResource(leaseCacheState(c), (state) => state.reduce((bytes, a) => bytes + a.nbytes, 0));
116
115
  }
117
116
  return total;
118
117
  }
@@ -202,8 +201,8 @@ export class PromptCache {
202
201
  if (spill) try { spill(entry); } catch {}
203
202
  }
204
203
  }
205
- for (const c of entry.caches) c.dispose();
206
- entry.retain?.();
204
+ disposeResources(entry.caches);
205
+ entry.retain?.(); // backing release requires successful cache disposal
207
206
  }
208
207
 
209
208
  get totalBytes(): number {
@@ -214,14 +213,36 @@ export class PromptCache {
214
213
  return this.#entries.length;
215
214
  }
216
215
 
216
+ /** Release LRU entries until the caller's live-memory check is satisfied.
217
+ * Unlike background eviction, pressure relief must finish the SSD write
218
+ * and release the buffers now, not enqueue clones that keep them alive.
219
+ * Call under the engine lock, after taking the request's reusable prefix. */
220
+ relievePressure(overBudget: () => boolean): number {
221
+ let count = 0;
222
+ while (this.#entries.length && overBudget()) {
223
+ let oldest = 0;
224
+ for (let i = 1; i < this.#entries.length; i++)
225
+ if (this.#entries[i]!.lastUsed < this.#entries[oldest]!.lastUsed) oldest = i;
226
+ const { entry } = this.#entries[oldest]!;
227
+ // Keep the entry resident if persistence throws. A failed SSD write
228
+ // must not be presented as a successful demotion.
229
+ if (this.#cold) {
230
+ if (this.#cold.store(entry.tokens, entry.caches, entry.ns) === false) break;
231
+ }
232
+ else this.#spillSync?.(entry);
233
+ this.#entries.splice(oldest, 1);
234
+ this.#disposeEntry(entry, false);
235
+ this.demotions++;
236
+ count++;
237
+ }
238
+ return count;
239
+ }
240
+
217
241
  /** Find the entry with the longest usable common prefix of `prompt`
218
- * across BOTH tiers and serve it NON-CONSUMINGLY (prefix sharing,
219
- * 2026-07-05): the caller receives zero-copy CLONES trimmed to the
220
- * matched prefix (plus a ref-counted retain share); the donor entry
221
- * stays in the cache, ready for the next agent/session with the same
222
- * prefix. The caller owns the returned caches — dispose them or put()
223
- * an extended entry (which supersedes prefix-ancestors), honoring
224
- * `retain` either way.
242
+ * across BOTH tiers. Trimmable RAM entries are served non-consumingly as
243
+ * zero-copy clones; exact hits on Qwen hybrid entries containing recurrent
244
+ * SSM state transfer the donor itself. The caller owns the returned caches —
245
+ * dispose them or put() an extended entry, honoring `retain` either way.
225
246
  *
226
247
  * Usable prefix = common prefix capped at prompt.length - 1 (at least
227
248
  * one token must be forwarded to produce logits). Entries longer than
@@ -258,27 +279,22 @@ export class PromptCache {
258
279
  if (hit && hit.prefixLen > bestLen) {
259
280
  const loaded = this.#cold.restore(hit.handle);
260
281
  if (loaded) {
261
- const trimNeeded = loaded.tokens.length - hit.prefixLen;
262
- if (trimNeeded > 0 && !loaded.caches.every((c) => c.isTrimmable())) {
263
- // Divergent tail on an untrimmable kind: this file can't seed
264
- // the prompt — fall back to the RAM candidate. Loud: this used
265
- // to be the silent 84 s "restore-then-re-prefill" path (the
266
- // whole cold tier degrading with zero observables, 2026-07-06).
267
- console.warn(
268
- `[prompt-cache] cold entry unusable: ${loaded.tokens.length} tokens, ` +
269
- `needs trim ${trimNeeded} but untrimmable (wrapped ring/SSM) — re-prefilling`,
270
- );
271
- for (const c of loaded.caches) c.dispose();
272
- loaded.retain();
273
- } else {
274
- if (trimNeeded > 0) for (const c of loaded.caches) c.trim(trimNeeded);
275
- return {
276
- tokens: loaded.tokens.slice(0, hit.prefixLen),
277
- caches: loaded.caches,
278
- ns,
279
- retain: loaded.retain,
280
- };
281
- }
282
+ const owner = ownResource(loaded, (entry) =>
283
+ this.#disposeEntry({ ...entry, ns }, false));
284
+ const result = withResource(owner, (entry) => {
285
+ const trimNeeded = entry.tokens.length - hit.prefixLen;
286
+ if (trimNeeded > 0 && !entry.caches.every((cache) => cache.isTrimmable())) {
287
+ console.warn(
288
+ `[prompt-cache] cold entry unusable: ${entry.tokens.length} tokens, ` +
289
+ `needs trim ${trimNeeded} but untrimmable (wrapped ring/SSM) — re-prefilling`,
290
+ );
291
+ return null;
292
+ }
293
+ if (trimNeeded > 0) for (const cache of entry.caches) cache.trim(trimNeeded);
294
+ const tokens = entry.tokens.slice(0, hit.prefixLen);
295
+ return { ...owner.transfer(), tokens, ns };
296
+ });
297
+ if (result) return result;
282
298
  }
283
299
  }
284
300
  }
@@ -296,9 +312,25 @@ export class PromptCache {
296
312
  const rec = this.#entries[bestIdx]!;
297
313
  rec.lastUsed = ++this.#clock;
298
314
  rec.lastUsedMs = Date.now();
315
+ // Qwen recurrent caches are untrimmable. Transfer the exact-boundary
316
+ // entry instead of retaining a second recurrent snapshot in RAM.
317
+ // This reduced memory pressure in the recorded multi-turn reproduction.
318
+ // Save the boundary before consumption: the extended recurrent state
319
+ // cannot be trimmed back, and a delayed writer can no longer find it
320
+ // in RAM after ownership moves. An already durable boundary is cheap.
321
+ if (rec.entry.caches.some((c) => c.signature() === "ssm")) {
322
+ if (this.#cold?.store(rec.entry.tokens, rec.entry.caches, ns) === false)
323
+ throw new Error("prompt-cache: failed to persist recurrent boundary before transfer");
324
+ this.#entries.splice(bestIdx, 1);
325
+ return rec.entry;
326
+ }
299
327
  const clones = this.#clone(rec.entry.caches);
300
328
  const trimNeeded = rec.entry.tokens.length - bestLen;
301
- if (trimNeeded > 0) for (const c of clones) c.trim(trimNeeded);
329
+ try {
330
+ if (trimNeeded > 0) for (const c of clones) c.trim(trimNeeded);
331
+ } catch (error) {
332
+ cleanupFailure(error, () => disposeResources(clones));
333
+ }
302
334
  return {
303
335
  tokens: rec.entry.tokens.slice(0, bestLen),
304
336
  caches: clones,
@@ -337,10 +369,20 @@ export class PromptCache {
337
369
  * (spilling each to the cold tier first, when one is attached). If the
338
370
  * entry itself exceeds the cap it is spilled + disposed, not stored. */
339
371
  put(tokens: number[], caches: Cache[], ns = "", retain?: () => void): void {
372
+ // All cache-provided validation runs before ownership is adopted.
340
373
  const bytes = cacheBytes(caches);
374
+ const trimmable = caches.every((cache) => cache.isTrimmable());
375
+ const discard = (entry: PromptCacheEntry, spill: boolean) => {
376
+ try { this.#disposeEntry(entry, spill); }
377
+ catch (error) {
378
+ // The new entry is already owned here. Throwing back to its previous
379
+ // owner would invite disposal of state still held by this store.
380
+ console.warn(`[prompt-cache] entry cleanup failed: ${error}`);
381
+ }
382
+ };
341
383
  const entry: PromptCacheEntry = { tokens, caches, ns, retain };
342
384
  if (bytes > this.maxBytes) {
343
- this.#disposeEntry(entry, true);
385
+ discard(entry, true);
344
386
  return;
345
387
  }
346
388
  // The donor's retain becomes ref-counted so take()'s clones can hold
@@ -359,7 +401,7 @@ export class PromptCache {
359
401
  if (old.entry.tokens.length !== tokens.length) continue;
360
402
  if (commonPrefixLength(old.entry.tokens, tokens) !== tokens.length) continue;
361
403
  this.#entries = this.#entries.filter((r) => r !== old);
362
- this.#disposeEntry(old.entry, false);
404
+ discard(old.entry, false);
363
405
  }
364
406
  // SUPERSEDE strict prefix-ancestors (the SSD store's rule, brought to
365
407
  // RAM — prefix sharing would otherwise grow an entry per turn): same-ns
@@ -370,13 +412,13 @@ export class PromptCache {
370
412
  // can only serve exact-length matches, so shorter ancestors — e.g.
371
413
  // the prompt-boundary snapshot that makes drifted multi-turn agents
372
414
  // hit — must survive.
373
- if (caches.every((c) => c.isTrimmable())) {
415
+ if (trimmable) {
374
416
  for (const old of [...this.#entries]) {
375
417
  if (old === rec || old.entry.ns !== ns) continue;
376
418
  if (old.entry.tokens.length >= tokens.length) continue;
377
419
  if (commonPrefixLength(old.entry.tokens, tokens) !== old.entry.tokens.length) continue;
378
420
  this.#entries = this.#entries.filter((r) => r !== old);
379
- this.#disposeEntry(old.entry, false);
421
+ discard(old.entry, false);
380
422
  }
381
423
  }
382
424
  while (this.totalBytes > this.maxBytes && this.#entries.length > 1) {
@@ -384,7 +426,7 @@ export class PromptCache {
384
426
  for (let i = 1; i < this.#entries.length; i++)
385
427
  if (this.#entries[i]!.lastUsed < this.#entries[lruIdx]!.lastUsed) lruIdx = i;
386
428
  const [evicted] = this.#entries.splice(lruIdx, 1);
387
- this.#disposeEntry(evicted!.entry, true);
429
+ discard(evicted!.entry, true);
388
430
  }
389
431
  try { this.onPut?.(tokens, ns); } catch {}
390
432
  }
@@ -413,7 +455,8 @@ export class PromptCache {
413
455
  }
414
456
 
415
457
  clear(): void {
416
- for (const e of this.#entries) this.#disposeEntry(e.entry, false);
458
+ const entries = this.#entries;
417
459
  this.#entries = [];
460
+ disposeResources(entries.map(({ entry }) => ({ dispose: () => this.#disposeEntry(entry, false) })));
418
461
  }
419
462
  }
@@ -11,7 +11,7 @@
11
11
  // - NaN-sensitivity handling (treat as maximally sensitive)
12
12
  // - post-greedy block-run guard
13
13
  //
14
- // Verified bit-for-bit against the Python via tests/quantize-allocator.test.ts.
14
+ // Verified bit-for-bit against the Python via tests/parity/quantize-allocator.test.ts.
15
15
  //
16
16
  // The latency-aware variants (`optimize_latency_aware`,
17
17
  // `optimize_for_latency_budget`) are intentionally NOT ported — they pull in
@@ -0,0 +1,38 @@
1
+ import {
2
+ existsSync,
3
+ mkdirSync,
4
+ mkdtempSync,
5
+ readdirSync,
6
+ renameSync,
7
+ rmdirSync,
8
+ rmSync,
9
+ statSync,
10
+ } from "node:fs";
11
+ import { basename, dirname, join, resolve } from "node:path";
12
+
13
+ /** Build a complete directory beside its destination, then publish it with a
14
+ * single same-filesystem rename. Failed writers leave no partial destination. */
15
+ export async function writeAtomicDirectory<T>(
16
+ outDir: string,
17
+ write: (stagingDir: string) => Promise<T>,
18
+ ): Promise<T> {
19
+ const destination = resolve(outDir);
20
+ const replaceEmptyDestination = existsSync(destination);
21
+ if (
22
+ replaceEmptyDestination &&
23
+ (!statSync(destination).isDirectory() || readdirSync(destination).length !== 0)
24
+ ) throw new Error(`output directory already exists: ${outDir}`);
25
+
26
+ const parent = dirname(destination);
27
+ mkdirSync(parent, { recursive: true });
28
+ const staging = mkdtempSync(join(parent, `.${basename(destination)}.tmp-`));
29
+ try {
30
+ const result = await write(staging);
31
+ if (replaceEmptyDestination) rmdirSync(destination);
32
+ renameSync(staging, destination);
33
+ return result;
34
+ } catch (error) {
35
+ rmSync(staging, { recursive: true, force: true });
36
+ throw error;
37
+ }
38
+ }
@@ -20,6 +20,7 @@
20
20
 
21
21
  import { existsSync } from "node:fs";
22
22
  import type { LoadedTokenizer } from "../tokenizer";
23
+ import { runtimeValue } from "../runtime-config";
23
24
 
24
25
  /** One JSONL calibration sample (subset of the OptIQ schema we can consume). */
25
26
  interface CalibrationSample {
@@ -34,7 +35,7 @@ function bundledMixCandidates(): string[] {
34
35
  const home = process.env.HOME ?? "";
35
36
  const rel = "lib/python3.14/site-packages/optiq/calibration/data/optiq.jsonl";
36
37
  return [
37
- process.env.MLX_BUN_CALIBRATION_JSONL,
38
+ runtimeValue("MLX_BUN_CALIBRATION_JSONL"),
38
39
  `${home}/Code/mlx-lm-example/.venv/${rel}`,
39
40
  `${home}/Code/mlx-lm/.venv/${rel}`,
40
41
  ].filter((p): p is string => !!p);
@@ -13,7 +13,9 @@ import { existsSync } from "node:fs";
13
13
  import { join } from "node:path";
14
14
 
15
15
  /** A per-module quantization override. `false` means "left unquantized". */
16
- export type PerLayerEntry = { bits: number; groupSize: number } | false;
16
+ export type PerLayerEntry =
17
+ | { bits: number; groupSize: number; mode?: string; trellis?: { L: number; code: string; axis: 0 | 1 } }
18
+ | false;
17
19
 
18
20
  /** The default quantization definition for the model. */
19
21
  export interface QuantDef {
@@ -28,7 +30,7 @@ export interface QuantizationBlock {
28
30
  bits: number;
29
31
  mode: string;
30
32
  // plus per-module entries: { [modulePath]: {bits, group_size} | false }
31
- [modulePath: string]: number | string | { bits: number; group_size: number } | false;
33
+ [modulePath: string]: number | string | { bits: number; group_size: number; mode?: string; trellis?: { L: number; code: string; axis: 0 | 1 } } | false;
32
34
  }
33
35
 
34
36
  /**
@@ -47,7 +49,12 @@ export function buildQuantizationBlock(
47
49
  mode: def.mode ?? "affine",
48
50
  };
49
51
  for (const [path, entry] of perLayer) {
50
- block[path] = entry === false ? false : { bits: entry.bits, group_size: entry.groupSize };
52
+ if (entry === false) { block[path] = false; continue; }
53
+ const v: { bits: number; group_size: number; mode?: string; trellis?: { L: number; code: string; axis: 0 | 1 } } =
54
+ { bits: entry.bits, group_size: entry.groupSize };
55
+ if (entry.mode) v.mode = entry.mode;
56
+ if (entry.trellis) v.trellis = entry.trellis;
57
+ block[path] = v;
51
58
  }
52
59
  return block;
53
60
  }
@@ -76,6 +83,12 @@ export interface OptiqMetadata {
76
83
  group_size: number;
77
84
  achieved_bpw: number;
78
85
  per_layer_count: number;
86
+ weight_transforms?: Array<{
87
+ id: string;
88
+ seed: number;
89
+ family: string;
90
+ deviations: string[];
91
+ }>;
79
92
  }
80
93
 
81
94
  /**
@@ -2,13 +2,40 @@
2
2
  // import from here: quantize a model directory, write sharded safetensors,
3
3
  // build the config block, and resolve/inspect models for the wizard UI.
4
4
 
5
- export { quantizeModelDir, isQuantizable } from "./quantizer";
5
+ export { quantizeModelDir, isQuantizable, withPreparedProbe } from "./quantizer";
6
6
  export type {
7
+ PreparedProbe,
8
+ ProbeSource,
7
9
  QuantizeOptions,
8
10
  QuantizeResult,
9
11
  ProgressEvent,
10
12
  } from "./quantizer";
11
13
 
14
+ export {
15
+ planQwen35Fold,
16
+ planQwenMtpFold,
17
+ } from "./rotate";
18
+ export type {
19
+ FoldOptions,
20
+ QwenFoldOptions,
21
+ } from "./rotate";
22
+
23
+ export {
24
+ automaticRotationWeightTransform,
25
+ llamaWeightTransform,
26
+ planLlamaWeightTransform,
27
+ qwen35WeightTransform,
28
+ qwenMtpWeightTransform,
29
+ } from "./weight-transform";
30
+ export type {
31
+ LlamaWeightTransformPlan,
32
+ QwenWeightTransformPlan,
33
+ WeightTransform,
34
+ WeightTransformContext,
35
+ WeightTransformMetadata,
36
+ WeightTransformPlan,
37
+ } from "./weight-transform";
38
+
12
39
  export {
13
40
  writeShardedSafetensors,
14
41
  DEFAULT_SHARD_BYTES,
@@ -13,6 +13,7 @@ import { registerRunner } from "../jobs/runner";
13
13
  import { Registry } from "../registry";
14
14
  import { loadModelConfig } from "../config";
15
15
  import { quantizeModelDir, type QuantizeOptions } from "./quantizer";
16
+ import { automaticRotationWeightTransform } from "./weight-transform";
16
17
 
17
18
  /** Resolve the source model directory from a job config. Accepts an explicit
18
19
  * filesystem path (src_dir) or a registry query / model id (model_id). */
@@ -57,6 +58,9 @@ export const quantizeRunner: JobRunner = async (emit: Emit, config) => {
57
58
  // MUST be forwarded into opts or quantizeModelDir silently runs uniform.
58
59
  const targetBpw = config.target_bpw != null ? Number(config.target_bpw) : undefined;
59
60
  const mixed = targetBpw !== undefined;
61
+ const rotationSeed = Number(config.rotation_seed ?? 42);
62
+ if (config.rotate_weights && !Number.isInteger(rotationSeed))
63
+ throw new Error(`quantize job: rotation_seed must be an integer (got ${String(config.rotation_seed)})`);
60
64
 
61
65
  emit({
62
66
  type: "stage",
@@ -74,6 +78,13 @@ export const quantizeRunner: JobRunner = async (emit: Emit, config) => {
74
78
  ...(config.reference ? { reference: String(config.reference) } : {}),
75
79
  ...(config.calibration_mix ? { calibrationMix: String(config.calibration_mix) } : {}),
76
80
  ...(config.n_calibration != null ? { nCalibration: Number(config.n_calibration) } : {}),
81
+ ...(config.rotate_weights
82
+ ? {
83
+ weightTransform: automaticRotationWeightTransform({
84
+ seed: rotationSeed,
85
+ }),
86
+ }
87
+ : {}),
77
88
  };
78
89
 
79
90
  const r = await quantizeModelDir(srcDir, outDir, opts, (e) =>