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
@@ -0,0 +1,292 @@
1
+ // Quantizer-facing offline weight-transform seam. Recipe math lives in
2
+ // rotate.ts; this module owns planning, family adaptation, and tensor ownership
3
+ // so the artifact writer has one contract for every fold implementation.
4
+
5
+ import type { ModelConfig } from "../config";
6
+ import type { MlxArray } from "../mlx/array";
7
+ import type { Weights } from "../weights";
8
+ import {
9
+ foldLlamaWeights,
10
+ planQwen35Fold,
11
+ planQwenMtpFold,
12
+ QwenFoldContext,
13
+ type FoldGeometry,
14
+ type FoldOptions,
15
+ type QwenFoldOptions,
16
+ type QwenFoldPlan,
17
+ } from "./rotate";
18
+
19
+ /** Serialized alongside a quantized artifact so a folded basis is a property
20
+ * of the artifact, not an out-of-band experiment-script convention. */
21
+ export interface WeightTransformMetadata {
22
+ id: string;
23
+ seed: number;
24
+ family: string;
25
+ deviations: string[];
26
+ }
27
+
28
+ /** Pure output plan. `sourceByOutput` makes cloning/untie operations explicit:
29
+ * most outputs map to themselves; a synthesized head maps to its embedding. */
30
+ export interface WeightTransformPlan {
31
+ readonly id: string;
32
+ readonly outputNames: readonly string[];
33
+ readonly sourceByOutput: ReadonlyMap<string, string>;
34
+ readonly untieWordEmbeddings: boolean;
35
+ readonly metadata: WeightTransformMetadata;
36
+ }
37
+
38
+ /** Per-run executor. `apply` returns a lazy, owned array and never disposes
39
+ * `source`; the quantizer owns the result and the Weights object owns source. */
40
+ export interface WeightTransformContext {
41
+ apply(outputName: string, source: MlxArray): MlxArray;
42
+ dispose(): void;
43
+ }
44
+
45
+ /** Common seam for the Llama, Qwen3.5 trunk, and Qwen MTP fold recipes. */
46
+ export interface WeightTransform {
47
+ readonly id: string;
48
+ /** Name/config analysis only: no mlx arrays, model load, or device work. */
49
+ plan(names: readonly string[], config: ModelConfig): WeightTransformPlan;
50
+ createContext(weights: Weights, plan: WeightTransformPlan): WeightTransformContext;
51
+ }
52
+
53
+ export interface LlamaWeightTransformPlan extends WeightTransformPlan {
54
+ readonly kind: "llama";
55
+ readonly geometry: FoldGeometry;
56
+ readonly options: FoldOptions;
57
+ }
58
+
59
+ export interface QwenWeightTransformPlan extends WeightTransformPlan {
60
+ readonly kind: "qwen3_5" | "qwen3_5_mtp";
61
+ readonly hiddenSize: number;
62
+ readonly seed: number;
63
+ readonly fold: QwenFoldPlan;
64
+ }
65
+
66
+ function sourceMap(names: readonly string[]): Map<string, string> {
67
+ return new Map(names.map((name) => [name, name]));
68
+ }
69
+
70
+ function assertPow2(n: number, what: string): void {
71
+ if (n < 2 || (n & (n - 1)) !== 0)
72
+ throw new Error(
73
+ `rotation fold: ${what}=${n} is not a power of two — the Kronecker ` +
74
+ "Hadamard path is not implemented",
75
+ );
76
+ }
77
+
78
+ /** Pure Llama fold plan. Array work remains inside createContext/apply. */
79
+ export function planLlamaWeightTransform(
80
+ names: readonly string[],
81
+ config: ModelConfig,
82
+ options: FoldOptions,
83
+ ): LlamaWeightTransformPlan {
84
+ const has = new Set(names);
85
+ for (const required of ["model.embed_tokens.weight", "model.norm.weight"])
86
+ if (!has.has(required)) throw new Error(`rotation fold: missing tensor ${required}`);
87
+ if (has.has("lm_head.weight"))
88
+ throw new Error("rotation fold: llama adapter currently requires tied embeddings");
89
+
90
+ for (let i = 0; i < config.text.numHiddenLayers; i++) {
91
+ const layer = `model.layers.${i}`;
92
+ for (const required of [
93
+ `${layer}.input_layernorm.weight`,
94
+ `${layer}.post_attention_layernorm.weight`,
95
+ `${layer}.self_attn.q_proj.weight`,
96
+ `${layer}.self_attn.k_proj.weight`,
97
+ `${layer}.self_attn.v_proj.weight`,
98
+ `${layer}.self_attn.o_proj.weight`,
99
+ `${layer}.mlp.gate_proj.weight`,
100
+ `${layer}.mlp.up_proj.weight`,
101
+ `${layer}.mlp.down_proj.weight`,
102
+ ]) {
103
+ if (!has.has(required)) throw new Error(`rotation fold: missing tensor ${required}`);
104
+ }
105
+ }
106
+
107
+ const geometry: FoldGeometry = {
108
+ numLayers: config.text.numHiddenLayers,
109
+ hiddenSize: config.text.hiddenSize,
110
+ numHeads: config.text.numAttentionHeads,
111
+ numKvHeads: config.text.numKeyValueHeads,
112
+ headDim: config.text.headDim,
113
+ };
114
+ if (options.r1 ?? true) assertPow2(geometry.hiddenSize, "hidden_size");
115
+ if (options.r2 ?? true) assertPow2(geometry.headDim, "head_dim");
116
+
117
+ const outputNames = [...names, "lm_head.weight"];
118
+ const sourceByOutput = sourceMap(names);
119
+ sourceByOutput.set("lm_head.weight", "model.embed_tokens.weight");
120
+ return {
121
+ kind: "llama",
122
+ id: "rotation.llama",
123
+ outputNames,
124
+ sourceByOutput,
125
+ untieWordEmbeddings: true,
126
+ geometry,
127
+ options: { ...options },
128
+ metadata: {
129
+ id: "rotation.llama",
130
+ seed: options.seed,
131
+ family: "llama",
132
+ deviations: [
133
+ "no-embedding-mean-centering",
134
+ "no-R4-downproj-input-fold",
135
+ "no-R3",
136
+ "gamma-kept-in-module-as-ones (eps preserved)",
137
+ "fold-precision-f32",
138
+ ],
139
+ },
140
+ };
141
+ }
142
+
143
+ function createLlamaContext(
144
+ weights: Weights,
145
+ plan: LlamaWeightTransformPlan,
146
+ ): WeightTransformContext {
147
+ const folded = foldLlamaWeights(weights, plan.geometry, plan.options);
148
+ const pending = new Map(folded.tensors.map((tensor) => [tensor.name, tensor.array]));
149
+ return {
150
+ apply(outputName, source) {
151
+ const transformed = pending.get(outputName);
152
+ if (transformed) {
153
+ pending.delete(outputName);
154
+ return transformed;
155
+ }
156
+ // Preserve family-specific tensors outside the fold corridor.
157
+ return source.astype(source.dtype);
158
+ },
159
+ dispose() {
160
+ for (const array of pending.values()) array.dispose();
161
+ pending.clear();
162
+ },
163
+ };
164
+ }
165
+
166
+ function qwenTransformPlan(
167
+ names: readonly string[],
168
+ config: ModelConfig,
169
+ seed: number,
170
+ companion: boolean,
171
+ prefix?: string,
172
+ ): QwenWeightTransformPlan {
173
+ const fold = companion
174
+ ? planQwenMtpFold(names)
175
+ : planQwen35Fold(
176
+ names,
177
+ prefix ?? (names.includes("language_model.model.norm.weight") ? "language_model." : ""),
178
+ );
179
+ const outputNames = [...names];
180
+ const sourceByOutput = sourceMap(names);
181
+ if (fold.extraHead) {
182
+ outputNames.push(fold.extraHead.name);
183
+ sourceByOutput.set(fold.extraHead.name, fold.extraHead.from);
184
+ }
185
+ const family = companion ? "qwen3_5_mtp" : "qwen3_5";
186
+ return {
187
+ kind: family,
188
+ id: `rotation.${family}`,
189
+ outputNames,
190
+ sourceByOutput,
191
+ untieWordEmbeddings: fold.extraHead !== null,
192
+ hiddenSize: config.text.hiddenSize,
193
+ seed,
194
+ fold,
195
+ metadata: {
196
+ id: `rotation.${family}`,
197
+ seed,
198
+ family,
199
+ deviations: [...fold.deviations],
200
+ },
201
+ };
202
+ }
203
+
204
+ function createQwenContext(
205
+ weights: Weights,
206
+ plan: QwenWeightTransformPlan,
207
+ ): WeightTransformContext {
208
+ // Lazy mode composes into the quantizer's existing writer. The experiment
209
+ // script keeps QwenFoldContext's eager default because it releases shards.
210
+ const context = new QwenFoldContext(
211
+ weights,
212
+ plan.hiddenSize,
213
+ plan.seed,
214
+ plan.fold.gammaNames,
215
+ false,
216
+ );
217
+ return {
218
+ apply(outputName, source) {
219
+ const extra = plan.fold.extraHead;
220
+ if (extra && outputName === extra.name)
221
+ return context.apply({ kind: "input", gamma: extra.gamma }, source);
222
+ const op = plan.fold.ops.get(outputName);
223
+ if (!op) throw new Error(`weight transform ${plan.id}: unplanned output ${outputName}`);
224
+ return context.apply(op, source);
225
+ },
226
+ dispose: () => context.dispose(),
227
+ };
228
+ }
229
+
230
+ /** Llama-family γ+R1+R2 adapter. */
231
+ export function llamaWeightTransform(options: FoldOptions): WeightTransform {
232
+ return {
233
+ id: "rotation.llama",
234
+ plan: (names, config) => planLlamaWeightTransform(names, config, options),
235
+ createContext(weights, plan) {
236
+ if (!("kind" in plan) || plan.kind !== "llama")
237
+ throw new Error(`weight transform rotation.llama received plan ${plan.id}`);
238
+ return createLlamaContext(weights, plan as LlamaWeightTransformPlan);
239
+ },
240
+ };
241
+ }
242
+
243
+ /** Qwen3.5 trunk/VL adapter (R1 only because of the attention output gate). */
244
+ export function qwen35WeightTransform(options: QwenFoldOptions): WeightTransform {
245
+ return {
246
+ id: "rotation.qwen3_5",
247
+ plan: (names, config) =>
248
+ qwenTransformPlan(names, config, options.seed, false, options.prefix),
249
+ createContext(weights, plan) {
250
+ if (!("kind" in plan) || plan.kind !== "qwen3_5")
251
+ throw new Error(`weight transform rotation.qwen3_5 received plan ${plan.id}`);
252
+ return createQwenContext(weights, plan as QwenWeightTransformPlan);
253
+ },
254
+ };
255
+ }
256
+
257
+ /** Qwen3.5 MTP companion adapter. Must use the same seed as its trunk. */
258
+ export function qwenMtpWeightTransform(seed: number): WeightTransform {
259
+ return {
260
+ id: "rotation.qwen3_5_mtp",
261
+ plan: (names, config) => qwenTransformPlan(names, config, seed, true),
262
+ createContext(weights, plan) {
263
+ if (!("kind" in plan) || plan.kind !== "qwen3_5_mtp")
264
+ throw new Error(`weight transform rotation.qwen3_5_mtp received plan ${plan.id}`);
265
+ return createQwenContext(weights, plan as QwenWeightTransformPlan);
266
+ },
267
+ };
268
+ }
269
+
270
+ /** Select one of the three adapters from the source model and tensor schema. */
271
+ export function automaticRotationWeightTransform(
272
+ options: FoldOptions & { prefix?: string },
273
+ ): WeightTransform {
274
+ return {
275
+ id: "rotation.auto",
276
+ plan(names, config) {
277
+ if (names.includes("fc.weight") && names.includes("pre_fc_norm_hidden.weight"))
278
+ return qwenTransformPlan(names, config, options.seed, true);
279
+ if (config.modelType === "qwen3_5")
280
+ return qwenTransformPlan(names, config, options.seed, false, options.prefix);
281
+ if (config.modelType === "llama")
282
+ return planLlamaWeightTransform(names, config, options);
283
+ throw new Error(`rotation transform: unsupported model_type ${config.modelType}`);
284
+ },
285
+ createContext(weights, plan) {
286
+ if (!("kind" in plan)) throw new Error(`rotation transform: invalid plan ${plan.id}`);
287
+ return plan.kind === "llama"
288
+ ? createLlamaContext(weights, plan as LlamaWeightTransformPlan)
289
+ : createQwenContext(weights, plan as QwenWeightTransformPlan);
290
+ },
291
+ };
292
+ }
package/src/responses.ts CHANGED
@@ -17,6 +17,11 @@
17
17
  // - previous_response_id is echoed in the response when the request
18
18
  // carried one (oracle always emits null).
19
19
 
20
+ import type {
21
+ CompletionEvent,
22
+ CompletionStreamProtocol,
23
+ } from "./serve/completion-sink";
24
+
20
25
  // ---------------------------------------------------------------------
21
26
  // Response store (previous_response_id resumption)
22
27
  // ---------------------------------------------------------------------
@@ -38,7 +43,16 @@ const DEFAULT_MAX_BYTES = 32 * 1024 * 1024;
38
43
  /** Process-local TTL + byte-capped LRU (port of response_store.py).
39
44
  * Does not survive restarts — sufficient for local serving; anything
40
45
  * sturdier means external storage, out of scope upstream too. */
41
- export class ResponseStore {
46
+ export interface ResponseHistory {
47
+ readonly ttlMs: number;
48
+ readonly maxBytes: number;
49
+ readonly size: number;
50
+ readonly totalBytes: number;
51
+ put(id: string, entry: StoredResponse): void;
52
+ get(id: string): StoredResponse | null;
53
+ }
54
+
55
+ export class ResponseStore implements ResponseHistory {
42
56
  #items = new Map<string, StoreEntry>(); // Map iterates in insertion order
43
57
  #bytes = 0;
44
58
 
@@ -109,6 +123,24 @@ export class ResponseStore {
109
123
  }
110
124
  }
111
125
 
126
+ /** Conversation policy shared by direct and isolated application hosts. */
127
+ export function resolveResponsesConversation(body: ResponsesRequest, store: Pick<ResponseHistory, "get">) {
128
+ const previousId = body.previous_response_id ?? null;
129
+ if (previousId) {
130
+ const prior = store.get(previousId);
131
+ if (!prior) throw new Error(`previous_response_id '${previousId}' not found or expired`);
132
+ const next = typeof body.input === "string"
133
+ ? body.input ? [{ type: "message", role: "user", content: body.input }] : []
134
+ : body.input ?? [];
135
+ body = { ...body, input: [...prior.input, ...outputItemsToInputItems(prior.output), ...next] as Array<Record<string, unknown>>,
136
+ instructions: body.instructions ?? prior.instructions ?? undefined };
137
+ }
138
+ return { body, previousId,
139
+ input: typeof body.input === "string" ? [{ type: "message", role: "user", content: body.input }] : [...body.input ?? []],
140
+ instructions: body.instructions ?? null,
141
+ };
142
+ }
143
+
112
144
  // ---------------------------------------------------------------------
113
145
  // Request translation: Responses → Chat Completions
114
146
  // ---------------------------------------------------------------------
@@ -167,6 +199,55 @@ function coerceText(content: unknown): string {
167
199
  return parts.join("");
168
200
  }
169
201
 
202
+ /** Convert a Responses message content array to chat-shaped content: text
203
+ * flattens, media TRANSLATES (`input_image` → `image_url`, incl. the
204
+ * Responses-standard string `image_url` field; video symmetrically), and
205
+ * unknown non-text parts REJECT loudly — a silent media drop answers
206
+ * confidently about content the model never saw (the anthropic.ts audio
207
+ * doctrine). Text-only arrays keep the legacy flattened-string shape. */
208
+ function coerceContent(content: unknown): string | Record<string, unknown>[] {
209
+ if (content == null) return "";
210
+ if (typeof content === "string") return content;
211
+ if (!Array.isArray(content)) return String(content);
212
+ const parts: Record<string, unknown>[] = [];
213
+ let hasMedia = false;
214
+ for (const part of content) {
215
+ if (typeof part === "string") {
216
+ parts.push({ type: "text", text: part });
217
+ continue;
218
+ }
219
+ if (!part || typeof part !== "object") continue;
220
+ const p = part as Record<string, unknown>;
221
+ if (p.type === "input_image" || p.type === "image_url") {
222
+ const url = typeof p.image_url === "string"
223
+ ? p.image_url
224
+ : (p.image_url as { url?: string } | undefined)?.url;
225
+ if (typeof url !== "string")
226
+ throw new Error("input_image part missing image_url");
227
+ parts.push({ type: "image_url", image_url: { url } });
228
+ hasMedia = true;
229
+ } else if (p.type === "input_video" || p.type === "video_url") {
230
+ const url = typeof p.video_url === "string"
231
+ ? p.video_url
232
+ : (p.video_url as { url?: string } | undefined)?.url;
233
+ if (typeof url !== "string")
234
+ throw new Error("input_video part missing video_url");
235
+ parts.push({ type: "video_url", video_url: { url } });
236
+ hasMedia = true;
237
+ } else if (p.text != null) {
238
+ parts.push({ type: "text", text: String(p.text) });
239
+ } else {
240
+ throw new Error(
241
+ `unsupported Responses content part type "${String(p.type)}" — ` +
242
+ `use input_text, input_image, or input_video`,
243
+ );
244
+ }
245
+ }
246
+ if (!hasMedia)
247
+ return parts.map((p) => String((p as { text?: unknown }).text ?? "")).join("");
248
+ return parts;
249
+ }
250
+
170
251
  /** Convert a prior response's output array into input-shaped items for
171
252
  * previous_response_id resumption (reasoning items dropped — replaying
172
253
  * them invites the model to repeat itself). */
@@ -232,11 +313,14 @@ export function responsesToChatBody(body: ResponsesRequest): Record<string, unkn
232
313
  }
233
314
  // regular message item (explicit type or implicit by having role)
234
315
  let role = String(item.role ?? "user");
235
- const content = coerceText(item.content);
236
316
  if (role === "system" || role === "developer") {
237
- if (content) systemParts.push(content);
317
+ // System prompts are text by contract — flatten (media in a system
318
+ // item has no defined semantics on any surface we mirror).
319
+ const text = coerceText(item.content);
320
+ if (text) systemParts.push(text);
238
321
  continue;
239
322
  }
323
+ const content = coerceContent(item.content);
240
324
  if (!["user", "assistant", "tool"].includes(role)) role = "user";
241
325
  messages.push({ role, content });
242
326
  }
@@ -722,6 +806,49 @@ export class ResponsesStreamTranslator {
722
806
  }
723
807
  }
724
808
 
809
+ /** Direct semantic-event adapter used by the server. `onComplete` receives
810
+ * the same response.completed payload stored for previous_response_id. */
811
+ export function createResponsesStreamProtocol(
812
+ model: string,
813
+ previousResponseId: string | null,
814
+ onComplete: (final: Record<string, unknown>) => void,
815
+ ): CompletionStreamProtocol {
816
+ const translator = new ResponsesStreamTranslator(model, previousResponseId);
817
+ const chunk = (delta: Record<string, unknown>) => ({ choices: [{ delta }] });
818
+ return {
819
+ start: () => translator.addChunk(chunk({ role: "assistant", content: "" })),
820
+ addEvents(events: CompletionEvent[]) {
821
+ return events.flatMap((event) => {
822
+ if (event.type === "reasoning") {
823
+ return translator.addChunk(chunk({ reasoning: event.text }));
824
+ }
825
+ if (event.type === "content") {
826
+ return translator.addChunk(chunk({ content: event.text }));
827
+ }
828
+ return translator.addChunk(chunk({
829
+ tool_calls: event.calls.map((call, index) => ({ index, ...call })),
830
+ }));
831
+ });
832
+ },
833
+ finish(reason, usage) {
834
+ const frames = [
835
+ ...translator.addChunk({ choices: [{ delta: {}, finish_reason: reason }], usage }),
836
+ ...translator.finalize(),
837
+ ];
838
+ onComplete(translator.finalResponse());
839
+ return frames;
840
+ },
841
+ error(message) {
842
+ return [sse("error", {
843
+ type: "error",
844
+ code: "server_error",
845
+ message,
846
+ param: null,
847
+ })];
848
+ },
849
+ };
850
+ }
851
+
725
852
  /** Wrap our OpenAI SSE byte stream as a Responses SSE byte stream.
726
853
  * onComplete fires after response.completed with the final payload so
727
854
  * the route can store it for previous_response_id resumption. */
@@ -0,0 +1,81 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+
3
+ export type RuntimeKey = `MLX_BUN_${string}`;
4
+ export type RuntimeOverrides = Readonly<Partial<Record<RuntimeKey, string | undefined>>>;
5
+
6
+ export interface RuntimeConfig {
7
+ readonly values: Readonly<Record<string, string | undefined>>;
8
+ value(name: RuntimeKey): string | undefined;
9
+ flag(name: RuntimeKey, defaultOn: boolean): boolean;
10
+ number(name: RuntimeKey, fallback: number): number;
11
+ }
12
+
13
+ /** Build one immutable runtime snapshot. Only mlx-bun-owned keys cross this
14
+ * boundary; feature code never reads or mutates process.env. */
15
+ export function createRuntimeConfig(
16
+ source: Readonly<Record<string, string | undefined>>,
17
+ ): RuntimeConfig {
18
+ const values = Object.freeze(Object.fromEntries(
19
+ Object.entries(source).filter(([key, value]) =>
20
+ key.startsWith("MLX_BUN_") && value !== undefined),
21
+ ));
22
+ return Object.freeze({
23
+ values,
24
+ value: (name: RuntimeKey) => values[name],
25
+ flag: (name: RuntimeKey, defaultOn: boolean) => {
26
+ const value = values[name];
27
+ return value === "1" ? true : value === "0" ? false : defaultOn;
28
+ },
29
+ number: (name: RuntimeKey, fallback: number) => {
30
+ const value = values[name];
31
+ if (value === undefined) return fallback;
32
+ const parsed = Number(value);
33
+ return Number.isFinite(parsed) ? parsed : fallback;
34
+ },
35
+ });
36
+ }
37
+
38
+ let active = createRuntimeConfig(process.env);
39
+ const executionConfig = new AsyncLocalStorage<RuntimeConfig>();
40
+
41
+ /** Legacy kernels read through this port. A bound execution sees its own
42
+ * immutable snapshot across awaits, independently of later host settings. */
43
+ export function withRuntimeConfig<T>(config: RuntimeConfig, run: () => T): T {
44
+ return executionConfig.getStore() === config ? run() : executionConfig.run(config, run);
45
+ }
46
+
47
+ export function runtimeConfig(): RuntimeConfig {
48
+ return executionConfig.getStore() ?? active;
49
+ }
50
+
51
+ export function runtimeValue(name: RuntimeKey): string | undefined {
52
+ return runtimeConfig().value(name);
53
+ }
54
+
55
+ /** On/off env flag: an explicit "1"/"0" always wins; otherwise `defaultOn`.
56
+ * (Formerly src/flags.ts `flagOn` — same resolver, one module.) */
57
+ export function flagOn(name: RuntimeKey, defaultOn: boolean): boolean {
58
+ return runtimeFlag(name, defaultOn);
59
+ }
60
+ export function runtimeFlag(name: RuntimeKey, defaultOn: boolean): boolean {
61
+ return runtimeConfig().flag(name, defaultOn);
62
+ }
63
+
64
+ export function runtimeNumber(name: RuntimeKey, fallback: number): number {
65
+ return runtimeConfig().number(name, fallback);
66
+ }
67
+
68
+ export function runtimeKey(name: string): RuntimeKey {
69
+ if (!name.startsWith("MLX_BUN_"))
70
+ throw new Error(`runtime flag must start with MLX_BUN_ (got ${name})`);
71
+ return name as RuntimeKey;
72
+ }
73
+
74
+ /** Replace selected values by installing a new frozen snapshot. The CLI uses
75
+ * this once while resolving flags; tests may use the returned restore hook.
76
+ * No environment mutation is involved. */
77
+ export function configureRuntime(overrides: RuntimeOverrides): () => void {
78
+ const previous = active;
79
+ active = createRuntimeConfig({ ...previous.values, ...overrides });
80
+ return () => { active = previous; };
81
+ }