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
package/src/pi-web.ts CHANGED
@@ -1,3 +1,7 @@
1
+ import { APP_ROUTE_IDS } from "./contracts/pi";
2
+ export { APP_ROUTE_IDS } from "./contracts/pi";
3
+ import type { ApprovalDecision, ImageAttachment, ClientMessage, UiSnapshotElement, UiSnapshot, WizardStep, AppUiContext, AppRouteId, ReadyGenDefaults, ServerMessage, HistoryToolItem, HistoryItem, SessionListItem, SamplingOverrides, Lane } from "./contracts/pi";
4
+ export type { ApprovalDecision, ImageAttachment, ClientMessage, UiSnapshotElement, UiSnapshot, WizardStep, AppUiContext, AppRouteId, ReadyGenDefaults, ServerMessage, HistoryToolItem, HistoryItem, SessionListItem, SamplingOverrides } from "./contracts/pi";
1
5
  // mlx-bun pi-web — server-side embed of the pi agent SDK that bridges a
2
6
  // browser WebSocket to an in-process AgentSession driving mlx-bun's own
3
7
  // local model (Phase 16, web half).
@@ -27,6 +31,7 @@ import { createHash } from "node:crypto";
27
31
  import { mkdirSync, rmSync } from "node:fs";
28
32
  import { homedir } from "node:os";
29
33
  import { join, resolve } from "node:path";
34
+ import { runtimeValue } from "./runtime-config";
30
35
  import type { ServerWebSocket, WebSocketHandler } from "bun";
31
36
  import {
32
37
  createAgentSessionFromServices,
@@ -51,7 +56,7 @@ import { MEMORY_TOOL_NAMES, REFERENCE_TOOL_NAMES } from "./memory/tools";
51
56
  import { buildPiAgentSurface } from "./pi-session";
52
57
  import { buildPiProvider, DEFAULT_CONTEXT_WINDOW, PI_LOCAL_MODEL_ID } from "./pi-provider";
53
58
  import { downloadsSnapshot } from "./download";
54
- import { getLane, type Lane } from "./serve/lane-registry";
59
+ import { getLane } from "./serve/lane-registry";
55
60
  import { isToolAlwaysAllowed, setToolAlwaysAllowed, listAlwaysAllowedTools } from "./tool-approvals";
56
61
 
57
62
  /**
@@ -355,188 +360,7 @@ export interface PiWsData {
355
360
 
356
361
  type PiWs = ServerWebSocket<PiWsData>;
357
362
 
358
- // ---- WS protocol message shapes --------------------------------------
359
-
360
- /** Decision a browser returns for a gated tool call. `editedArgs`, when
361
- * present on an "allow", replaces the tool's proposed input before it runs
362
- * (LM Studio's editable-args pattern — plan §5.4/§6.5). `alwaysAllow` marks
363
- * the decision as "and remember this tool" — handled by resolveApproval,
364
- * which persists it to the durable tool-approvals config (src/tool-
365
- * approvals.ts) before settling the pending promise. */
366
- export type ApprovalDecision = "allow" | "deny";
367
-
368
- /** An image attachment from the browser: base64 (no data: prefix) + mime. */
369
- export interface ImageAttachment {
370
- data: string;
371
- mimeType: string;
372
- }
373
-
374
- /** Client -> server frames. Exported type-only for the web frontend
375
- * (src/web/src/*.ts import it via `import type` — see tsconfig.web.json
376
- * and scripts/build-web.ts) so the WS contract is checked at compile time
377
- * on both ends instead of drifting between server TS and untyped inline
378
- * browser JS (the observed Phase-0 bug class). */
379
- export type ClientMessage =
380
- | { type: "prompt"; text: string; images?: ImageAttachment[] }
381
- | { type: "abort" }
382
- // `editedArgs`: when the user edited the proposed arguments in the
383
- // approval card's textarea before approving, the (re-parsed) JSON object
384
- // to substitute for the tool's original input — mutated onto the pi SDK's
385
- // ToolCallEvent.input in place (the SDK's documented mutation contract;
386
- // see installApprovalGate). Ignored on "deny". `alwaysAllow`: persist this
387
- // tool to the durable always-allow config (src/tool-approvals.ts) so
388
- // future calls to the SAME TOOL NAME skip the card entirely, on this and
389
- // every other session.
390
- | { type: "approval"; callId: string; decision: ApprovalDecision; editedArgs?: Record<string, unknown>; alwaysAllow?: boolean }
391
- // Toggle the model's reasoning channel on/off (only meaningful when the
392
- // model supports thinking — ready.thinking). Maps to Pi's session thinking
393
- // level: "medium" (on) ↔ "off". Pi sends it as enable_thinking to the server.
394
- | { type: "set_thinking"; enabled: boolean }
395
- // Opt-in toggle (plan §5.4/§6.5/§9 Phase 2, default OFF): "let the agent
396
- // touch files on this machine". Persisted per-browser by the client
397
- // (localStorage `mlxbun.codingTools`); the ALLOWLIST decision is enforced
398
- // here, server-side. buildPiAgentSurface's tool list is fixed for the
399
- // life of an AgentSession (pi's DefaultResourceLoader config is baked in
400
- // at createAgentSessionServices time), so this can't rewire an
401
- // in-progress session — it takes effect starting with the next
402
- // new_session/open_session/fork_session (createRuntimeFactory reads
403
- // this.codingToolsRequested fresh every time the SDK calls it, including
404
- // from AgentSessionRuntime.newSession()'s internal re-invocation). The
405
- // `coding_tools` ServerMessage below reports the honest current-vs-pending
406
- // state so the UI can say so instead of implying it applies immediately.
407
- | { type: "set_coding_tools"; enabled: boolean }
408
- // Select the active LoRA adapter for subsequent turns (null = none/base).
409
- // app.html mounts it (POST /v1/adapters) before sending this; the
410
- // before_provider_request hook injects it into the provider payload.
411
- | { type: "set_adapter"; id: string | null }
412
- // Per-request sampling overrides. Each field is optional; null/undefined
413
- // means "leave it to the server default" (the mode-aware recommended
414
- // value resolved in toOptions). A present numeric value is injected into
415
- // the provider payload and always wins. The before_provider_request hook
416
- // injects whatever is set here.
417
- //
418
- // `scope` (plan §9 Phase 3 / beat matrix Axis 4 "per-message sampling
419
- // scope"): "session" (default, omitting the field means this too) persists
420
- // the override on the connection until changed — today's behavior,
421
- // unchanged. "next_turn" stores a ONE-SHOT override applied to exactly
422
- // the next prompt's injection, then cleared automatically — it never
423
- // touches the session-level values (a later plain set_sampling with
424
- // scope:"session" or omitted still sees whatever was there before this
425
- // message). Composition when both are present: next_turn's SET fields
426
- // win over session's for that one request; anything next_turn leaves
427
- // null/unset falls back to the session-level override for that field
428
- // (composeSampling — session-level itself falls back to the server's
429
- // mode-aware default per injectSampling's existing contract).
430
- | {
431
- type: "set_sampling";
432
- scope?: "session" | "next_turn";
433
- temperature?: number | null;
434
- top_p?: number | null;
435
- top_k?: number | null;
436
- min_p?: number | null;
437
- xtc_probability?: number | null;
438
- xtc_threshold?: number | null;
439
- repetition_penalty?: number | null;
440
- repetition_context_size?: number | null;
441
- presence_penalty?: number | null;
442
- frequency_penalty?: number | null;
443
- seed?: number | null;
444
- }
445
- // Per-session USER system prompt, layered ON TOP OF (not replacing) the
446
- // built-in surface prompt (buildWebChatSystemPrompt + memoryHint). null
447
- // clears it. Applied by the before_agent_start hook on the NEXT turn (pi
448
- // calls it fresh inside every session.prompt(), so this is a true
449
- // per-turn injection, not a session-creation-only setting — see
450
- // installSystemPromptHook). Presets v1 (composer.ts) send this alongside
451
- // set_sampling to apply a saved bundle.
452
- | { type: "set_system_prompt"; text: string | null }
453
- // Session management (recent-chats sidebar + new chat).
454
- | { type: "new_session" }
455
- | { type: "list_sessions" }
456
- | { type: "open_session"; path: string }
457
- | { type: "fork_session"; path: string }
458
- | { type: "delete_session"; path: string }
459
- // Message actions (plan §5.2). All three navigate the session's leaf
460
- // pointer via AgentSession.navigateTree() then re-prompt — a sibling
461
- // branch in the SAME session file, never a new one (see the helpers above
462
- // findLastUserMessageEntry for the full rationale). Regenerate re-sends the
463
- // last user message's original content verbatim; edit_resend re-sends it
464
- // with edited text (images preserved); switch_sibling moves the active
465
- // leaf to a previously-created sibling (an earlier edit/regeneration)
466
- // without sending anything new.
467
- | { type: "regenerate" }
468
- | { type: "edit_resend"; text: string }
469
- | { type: "switch_sibling"; entryId: string }
470
- // App-aware assistant (plan §6.6, §9 Phase 3, beat matrix Axis 12): pushed
471
- // by chat.ts on every route change AND on wizard-step change (quantize/
472
- // finetune/dataset), never on a timer. `context` is opaque here (the
473
- // browser's AppContext shape, src/web/src/assistant.ts) — stored verbatim
474
- // as the connection's currentAppContext and returned by the
475
- // get_current_app_context tool, plus mined for the compact one-line
476
- // ambient context auto-prepended to the NEXT prompt (see
477
- // installAppContextHook / ambientContextLine). This is a DIFFERENT frame
478
- // from the server->client `context` ServerMessage (context-window usage,
479
- // above) — same name, opposite direction, disambiguated by which type
480
- // union it's a member of; the two are never in scope at the same call
481
- // site (ClientMessage here vs. ServerMessage below).
482
- | { type: "context"; context: AppUiContext };
483
-
484
- // ---- App-aware assistant (plan §6.6, §9 Phase 3, beat matrix Axis 12) --
485
- //
486
- // Mirrors src/web/src/assistant.ts's browser-side types (which are the
487
- // source of truth for shape — this server-side copy is intentionally loose
488
- // (mostly `unknown`/optional) since the server never constructs a
489
- // UiSnapshot itself, only stores and forwards what the browser sends. Kept
490
- // here (not imported) because src/web/src/assistant.ts is bundled into the
491
- // browser and importing it here would pull browser code into the server
492
- // build — the inverse of the type-only ClientMessage/ServerMessage import
493
- // direction the frontend uses for pi-web.ts.
494
-
495
- /** One element in a captured DOM snapshot — see assistant.ts's
496
- * UiSnapshotElement for the authoritative shape/doc. */
497
- export interface UiSnapshotElement {
498
- ref: string;
499
- tag: string;
500
- label: string;
501
- kind: "interactive" | "region";
502
- role?: string;
503
- selector: string;
504
- spotlightId?: string;
505
- }
506
-
507
- export interface UiSnapshot {
508
- route: string;
509
- capturedAt: string;
510
- elements: UiSnapshotElement[];
511
- }
512
-
513
- /** The wizard-step process-state fields (§6.6 "carries process state, not
514
- * just elements") — present only on routes with a step wizard. */
515
- export interface WizardStep {
516
- index: number;
517
- count: number;
518
- label: string;
519
- }
520
-
521
- /** The full context payload pushed by chat.ts on route/step change — see
522
- * assistant.ts's buildAppContext. Stored verbatim per-connection. */
523
- export interface AppUiContext {
524
- route: string;
525
- view?: string;
526
- step?: WizardStep;
527
- snapshot: UiSnapshot;
528
- }
529
-
530
- /** Route catalog mirror (src/web/src/ui-catalog.ts's ROUTE_IDS) for
531
- * server-side validation of navigate_app's route/page param BEFORE it
532
- * ever reaches the browser — an unknown route is rejected here as a tool
533
- * error rather than sent as a `ui_navigate` frame the router can't match.
534
- * Keep in sync with ui-catalog.ts's ROUTE_IDS by hand (no shared-JSON
535
- * import between the server and browser bundles — see that file's
536
- * top-of-file comment for why). */
537
- export const APP_ROUTE_IDS = ["chat", "quantize", "finetune", "dataset", "status"] as const;
538
- export type AppRouteId = (typeof APP_ROUTE_IDS)[number];
539
-
363
+ /** Validate assistant navigation against the shared browser/server route IDs. */
540
364
  export function isAppRouteId(v: string): v is AppRouteId {
541
365
  return (APP_ROUTE_IDS as readonly string[]).includes(v);
542
366
  }
@@ -569,117 +393,6 @@ export function ambientContextLine(ctx: AppUiContext | null | undefined): string
569
393
  return `[user is on: ${place}${stepPart}]`;
570
394
  }
571
395
 
572
- /** Model-author recommended sampling (generation_config.json, server-CLI
573
- * overrides applied) — sent once on `ready` so the sampling popover can show
574
- * per-model defaults instead of one hardcoded shape (web-ui-pass-plan.md
575
- * #14). A field is null when neither the model nor the server configured one
576
- * (the built-in fallback in toOptions still applies server-side). */
577
- export interface ReadyGenDefaults {
578
- temperature: number | null;
579
- topP: number | null;
580
- topK: number | null;
581
- }
582
-
583
- /** Server -> client frames. Exported type-only — see ClientMessage above. */
584
- export type ServerMessage =
585
- // `vision`: whether the loaded model can accept images (drives the UI's
586
- // image-attach affordance — false on e4b until the SigLIP sidecar lands).
587
- // `audio`: whether the loaded model can accept `input_audio` parts (audio
588
- // tower loaded or loadable). Discovery-only for now: pi's Model.input type
589
- // has no "audio" modality, so unlike `vision` this flag never feeds the
590
- // provider declaration — clients use it instead of probing for a 400.
591
- // `thinking`: whether the model has a switchable reasoning channel (drives
592
- // the UI's thinking on/off toggle; false hides it).
593
- | { type: "ready"; model: string; vision: boolean; audio: boolean; thinking: boolean; genDefaults: ReadyGenDefaults }
594
- | { type: "turn_start" }
595
- | { type: "text_delta"; delta: string }
596
- | { type: "thinking_delta"; delta: string }
597
- | { type: "tool_start"; callId: string; tool: string; args: unknown }
598
- | { type: "tool_approval_request"; callId: string; tool: string; args: unknown }
599
- | { type: "tool_update"; callId: string; chunk: unknown }
600
- | { type: "tool_end"; callId: string; ok: boolean; result: unknown }
601
- // `lane`: the serving lane the just-finished turn ran on (serial /
602
- // serial+spec / batched), correlated via the lane registry keyed by the
603
- // AssistantMessage's responseId (the pi SDK's own usage parsing drops
604
- // custom fields — see src/serve/lane-registry.ts). Absent when the turn
605
- // produced no assistant message with a responseId (e.g. an aborted turn
606
- // before any model call) — never guessed client-side (risk #5).
607
- | { type: "turn_end"; lane?: Lane }
608
- | { type: "queue_update"; steering: readonly string[]; followUp: readonly string[] }
609
- // Replay a session's transcript (rebuilds the thread); and the sidebar list.
610
- | { type: "history"; items: HistoryItem[] }
611
- | { type: "sessions"; items: SessionListItem[]; activePath?: string }
612
- // Sibling group for the LAST user message (edit-and-resend's `< i/n >`
613
- // toggle, plan §5.2). Sent after every history rebuild and after a
614
- // completed turn. `count` <= 1 means no toggle to show (the common case:
615
- // no edits/regenerations yet). `entryId` is the currently-active sibling's
616
- // id; `siblingIds` is the full ordered group so the client can resolve
617
- // "previous/next" locally and send switch_sibling with a concrete id
618
- // (never inferred/guessed — the server is the source of truth for order).
619
- | { type: "siblings"; entryId?: string; index: number; count: number; siblingIds: string[] }
620
- // Context-window usage indicator. tokens/percent are null right after a
621
- // compaction until the next assistant reply (pi can't estimate yet).
622
- | { type: "context"; tokens: number | null; contextWindow: number; percent: number | null }
623
- // Effective vs. pending codingTools state (set_coding_tools above).
624
- // `active` is what the CURRENT session actually built with (gates
625
- // whether the approval card can ever fire); `pending` is the browser's
626
- // most recent request, which only takes effect on the next
627
- // new/opened/forked session — surfaced so the settings copy can say
628
- // "will apply to your next new chat" instead of lying about immediacy.
629
- | { type: "coding_tools"; active: boolean; pending: boolean }
630
- // Full always-allow set for THIS machine (src/tool-approvals.ts), sent on
631
- // `ready` and after any change, so the settings panel can list/forget
632
- // durable per-tool approvals without a separate REST round-trip.
633
- | { type: "tool_approvals"; alwaysAllow: string[] }
634
- // App-aware assistant (plan §6.6): the navigate_app / spotlight_ui tools'
635
- // side-channel notifications, mapped 1:1 from the tool call's params —
636
- // never guessed or re-derived, so chat.ts's router/spotlight get exactly
637
- // what the model asked for. `route` here is always a validated
638
- // AppRouteId (isAppRouteId already ran server-side before this frame is
639
- // ever sent — see navigate_app's execute). ui_spotlight's fields mirror
640
- // SpotlightRequest 1:1 (assistant.ts resolves ref/label/selector/target
641
- // client-side, in that precedence order, against its last snapshot).
642
- | { type: "ui_navigate"; route: AppRouteId }
643
- | { type: "ui_spotlight"; ref?: string; label?: string; selector?: string; target?: string; message?: string; route?: AppRouteId }
644
- | { type: "error"; message: string };
645
-
646
- // ---- Session serialization (pure, unit-tested) -----------------------
647
-
648
- /** A finished tool call as rendered in replayed history. */
649
- export interface HistoryToolItem {
650
- callId: string;
651
- name: string;
652
- args: unknown;
653
- /** Tool result text, filled from the matching toolResult message. */
654
- result: string;
655
- }
656
-
657
- /** One replayed transcript turn: a user or assistant message (assistant
658
- * messages carry any tool calls they made, with results merged in). */
659
- export interface HistoryItem {
660
- role: "user" | "assistant";
661
- text: string;
662
- /** Model reasoning/thinking, kept separate from the final answer. */
663
- thinking?: string;
664
- tools: HistoryToolItem[];
665
- /** Session entry id (user items only). Lets the browser correlate "the
666
- * last user message" in the replayed thread with the `siblings` frame's
667
- * entryId, so it knows which DOM node gets the edit/sibling-toggle UI
668
- * (plan §5.2). Undefined for assistant items — they aren't fork targets. */
669
- entryId?: string;
670
- }
671
-
672
- /** A row in the recent-chats sidebar, derived from pi's SessionInfo. */
673
- export interface SessionListItem {
674
- path: string;
675
- id: string;
676
- title: string;
677
- /** Last-modified epoch ms (newest first). */
678
- modified: number;
679
- messageCount: number;
680
- forked: boolean;
681
- }
682
-
683
396
  /** Flatten a content value (string | content-parts) to its text. */
684
397
  function contentText(content: unknown): string {
685
398
  if (typeof content === "string") return content;
@@ -963,25 +676,6 @@ export function injectAdapter(
963
676
  return { ...payload, adapter: selected };
964
677
  }
965
678
 
966
- /** Per-request sampling overrides carried on the session and injected into the
967
- * provider payload by the before_provider_request hook. Each field is either a
968
- * user-set override or null/undefined ("use the server's mode-aware default").
969
- * Field names match the server's ChatRequest wire names (not toOptions' camelCase)
970
- * since these are injected directly into the outgoing chat-completions payload. */
971
- export interface SamplingOverrides {
972
- temperature?: number | null;
973
- top_p?: number | null;
974
- top_k?: number | null;
975
- min_p?: number | null;
976
- xtc_probability?: number | null;
977
- xtc_threshold?: number | null;
978
- repetition_penalty?: number | null;
979
- repetition_context_size?: number | null;
980
- presence_penalty?: number | null;
981
- frequency_penalty?: number | null;
982
- seed?: number | null;
983
- }
984
-
985
679
  /** Every SamplingOverrides field name, in wire order — the single source of
986
680
  * truth `injectSampling` and the `set_sampling` handler both walk, so a new
987
681
  * field only needs adding here + the interface above. */
@@ -1157,7 +851,7 @@ function appAwareTextResult(text: string, details: unknown = {}): { content: [{
1157
851
  * null before the first one arrives); `notify` sends a ServerMessage
1158
852
  * (ui_navigate/ui_spotlight) to that same browser tab. Pure enough to
1159
853
  * unit test the tool -> frame mapping via a fake notify collecting sent
1160
- * frames (tests/pi-web.test.ts). */
854
+ * frames (tests/research/pi-web.test.ts). */
1161
855
  export function createAppAwareTools(
1162
856
  getContext: () => AppUiContext | null,
1163
857
  notify: (msg: ServerMessage) => void,
@@ -1266,7 +960,7 @@ class PiWebSession {
1266
960
  * "Per-message sampling scope" block comment above composeSampling for
1267
961
  * the full lifecycle. Wrapped in SamplingScopeState (not two loose
1268
962
  * fields) so the exact same applySetSampling/consumeForRequest pure
1269
- * functions run here and in tests/pi-web.test.ts. */
963
+ * functions run here and in tests/research/pi-web.test.ts. */
1270
964
  private samplingScope: SamplingScopeState = initialSamplingScopeState();
1271
965
  /** User's custom system-prompt text for this connection (set via
1272
966
  * set_system_prompt), null = none. Read by the before_agent_start hook
@@ -1394,7 +1088,7 @@ class PiWebSession {
1394
1088
  (d) => d.state === "active" && d.repoId !== this.opts.modelId,
1395
1089
  )?.repoId ?? null,
1396
1090
  }, { hasTools: WELCOME_TOOLS.length > 0 }) + surface.memoryHint;
1397
- if (process.env.MLX_BUN_PI_DEBUG) {
1091
+ if (runtimeValue("MLX_BUN_PI_DEBUG")) {
1398
1092
  console.error(`[pi-web] prompt ${WEB_CHAT_PROMPT_VERSION} sha=${webChatPromptFingerprint(webPrompt)} memory=${surface.memoryEnabled ? "on" : "off"} codingTools=${this.codingToolsActive ? "on" : "off"}`);
1399
1093
  }
1400
1094
  const services = await createAgentSessionServices({
@@ -1826,7 +1520,7 @@ class PiWebSession {
1826
1520
 
1827
1521
  pi.on("tool_call", (event: ToolCallEvent) => {
1828
1522
  const block = decideBeforeToolCall(this.loopHygiene, event.toolName, event.input);
1829
- if (block && process.env.MLX_BUN_PI_DEBUG) {
1523
+ if (block && runtimeValue("MLX_BUN_PI_DEBUG")) {
1830
1524
  console.error(`[pi-web] loop-hygiene blocked ${event.toolName}: ${block.reason.split("\n")[0]}`);
1831
1525
  }
1832
1526
  return block ? { block: true, reason: block.reason } : undefined;
@@ -1852,7 +1546,7 @@ class PiWebSession {
1852
1546
  private installApprovalGate(pi: ExtensionAPI): void {
1853
1547
  pi.on("tool_call", async (event: ToolCallEvent) => {
1854
1548
  const tool = event.toolName;
1855
- if (process.env.MLX_BUN_PI_DEBUG) {
1549
+ if (runtimeValue("MLX_BUN_PI_DEBUG")) {
1856
1550
  console.error(`[pi-web] tool_call ${tool} args=${JSON.stringify(event.input)}`);
1857
1551
  }
1858
1552
 
@@ -1945,7 +1639,7 @@ class PiWebSession {
1945
1639
  }
1946
1640
 
1947
1641
  private onSessionEvent(event: AgentSessionEvent): void {
1948
- if (process.env.MLX_BUN_PI_DEBUG) {
1642
+ if (runtimeValue("MLX_BUN_PI_DEBUG")) {
1949
1643
  const extra = event.type === "message_update"
1950
1644
  ? `/${(event as { assistantMessageEvent?: { type?: string } }).assistantMessageEvent?.type}` : "";
1951
1645
  console.error(`[pi-event] ${event.type}${extra}`);
@@ -2025,7 +1719,7 @@ class PiWebSession {
2025
1719
  // isStreaming atomically inside prompt(), so this read can't strand a
2026
1720
  // message at the turn boundary.
2027
1721
  case "prompt": {
2028
- if (process.env.MLX_BUN_PI_DEBUG) {
1722
+ if (runtimeValue("MLX_BUN_PI_DEBUG")) {
2029
1723
  console.error(`[pi-web] prompt text=${JSON.stringify(msg.text.slice(0, 500))} images=${msg.images?.length ?? 0} streaming=${session.isStreaming} adapter=${this.selectedAdapter ?? "base"}`);
2030
1724
  }
2031
1725
  const images = toPiImages(msg.images);