mlx-bun 0.2.0 → 0.4.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 (433) hide show
  1. package/README.md +71 -588
  2. package/docs/README.md +94 -0
  3. package/docs/{design → archive/investigations}/audio-input-plan.md +4 -4
  4. package/docs/{design → archive/investigations}/diffusion-gemma-port.md +3 -3
  5. package/docs/{design → archive/investigations}/faithful-l1-consolidation.md +4 -4
  6. package/docs/{design → archive/investigations}/minicpm5-decode-megakernel.md +11 -11
  7. package/docs/archive/investigations/openjarvis-fit.md +198 -0
  8. package/docs/{design → archive/investigations}/optimization_plan.md +1 -1
  9. package/docs/{design → archive/investigations}/pre-colibri-stabilization.md +5 -5
  10. package/docs/archive/investigations/qwen38-27b-campaign-log.md +1092 -0
  11. package/docs/{design → archive/investigations}/the-dreaming-handoff.md +2 -2
  12. package/docs/archive/planning/release-notes-v0.3.0.md +35 -0
  13. package/docs/design/batching.md +1841 -0
  14. package/docs/design/decode-speed-program.md +2346 -169
  15. package/docs/design/dreaming-nightly-pipeline.md +675 -282
  16. package/docs/design/generic-model-support.md +655 -334
  17. package/docs/design/kv-cache.md +824 -0
  18. package/docs/design/orpo-training.md +673 -1239
  19. package/docs/design/speculative-decoding.md +1990 -0
  20. package/docs/design/turboquant.md +2212 -0
  21. package/docs/design/unified-engine-frontier-plan.md +1833 -727
  22. package/docs/design/web-chat-redesign.md +666 -1083
  23. package/docs/planning/PRODUCT_ROADMAP.md +50 -1
  24. package/docs/planning/release-notes-v0.4.0.md +45 -0
  25. package/docs/planning/video-series.md +2 -2
  26. package/docs/reference/benchmarks.md +3613 -0
  27. package/docs/reference/cli.md +434 -160
  28. package/docs/reference/distribution.md +328 -182
  29. package/docs/reference/environment.md +398 -0
  30. package/docs/reference/glossary.md +39 -0
  31. package/docs/reference/library-api.md +566 -168
  32. package/docs/reference/memory.md +227 -64
  33. package/docs/reference/models.md +113 -6
  34. package/docs/reference/server-api.md +944 -429
  35. package/docs/reference/server-config.md +740 -338
  36. package/docs/reference/training.md +393 -254
  37. package/docs/reference/troubleshooting.md +158 -0
  38. package/package.json +9 -4
  39. package/src/audio/decode.ts +2 -2
  40. package/src/audio/features.ts +2 -2
  41. package/src/backends/mlx/assistant-target.ts +46 -0
  42. package/src/backends/mlx/autoregressive-draft-rows.ts +120 -0
  43. package/src/backends/mlx/autoregressive.ts +108 -0
  44. package/src/backends/mlx/batch-group.ts +1790 -0
  45. package/src/backends/mlx/cache-attachment.ts +67 -0
  46. package/src/backends/mlx/cache-layout.ts +31 -0
  47. package/src/backends/mlx/checkpoint-state.ts +53 -0
  48. package/src/backends/mlx/continuation-persistence.ts +106 -0
  49. package/src/backends/mlx/continuation-request.ts +43 -0
  50. package/src/backends/mlx/continuation.ts +77 -0
  51. package/src/backends/mlx/diffusion.ts +39 -0
  52. package/src/backends/mlx/draft-target.ts +32 -0
  53. package/src/backends/mlx/evaluation.ts +105 -0
  54. package/src/backends/mlx/fill-append.ts +45 -0
  55. package/src/backends/mlx/full-kv-row-append.ts +32 -0
  56. package/src/backends/mlx/full-kv-row-donor.ts +54 -0
  57. package/src/backends/mlx/full-transitioning-kv-rows.ts +65 -0
  58. package/src/backends/mlx/gateway-binding.ts +130 -0
  59. package/src/backends/mlx/graph.ts +38 -0
  60. package/src/backends/mlx/kv-codec.ts +9 -0
  61. package/src/backends/mlx/kv-maintenance.ts +133 -0
  62. package/src/backends/mlx/kv-tensor-rows.ts +212 -0
  63. package/src/backends/mlx/memory-client.ts +189 -0
  64. package/src/backends/mlx/methods.ts +90 -0
  65. package/src/backends/mlx/model-prompt.ts +164 -0
  66. package/src/backends/mlx/model-serving.ts +79 -0
  67. package/src/backends/mlx/prefill-cohort.ts +89 -0
  68. package/src/backends/mlx/prefill-rows.ts +200 -0
  69. package/src/backends/mlx/prefill.ts +33 -0
  70. package/src/backends/mlx/projected-context-rows.ts +72 -0
  71. package/src/backends/mlx/request-policy.ts +20 -0
  72. package/src/backends/mlx/request-state-policy.ts +41 -0
  73. package/src/backends/mlx/rollback.ts +89 -0
  74. package/src/backends/mlx/row-sampling.ts +49 -0
  75. package/src/backends/mlx/serial-executor.ts +242 -0
  76. package/src/backends/mlx/speculative-group.ts +359 -0
  77. package/src/backends/mlx/speculative-round.ts +161 -0
  78. package/src/backends/mlx/speculative.ts +114 -0
  79. package/src/backends/mlx/state-rows.ts +104 -0
  80. package/src/backends/mlx/state-views.ts +46 -0
  81. package/src/backends/mlx/target-layout-capability.ts +35 -0
  82. package/src/backends/mlx/text-engine.ts +73 -0
  83. package/src/backends/mlx/transitioning-kv-rows.ts +165 -0
  84. package/src/cli.ts +66 -58
  85. package/src/client.ts +66 -0
  86. package/src/config.ts +21 -4
  87. package/src/contracts/completion.ts +16 -0
  88. package/src/contracts/execution.ts +60 -0
  89. package/src/contracts/generation.ts +103 -0
  90. package/src/contracts/host.ts +7 -0
  91. package/src/contracts/jobs.ts +66 -0
  92. package/src/contracts/pi-provider.ts +30 -0
  93. package/src/contracts/pi.ts +259 -0
  94. package/src/contracts/prefix-cache.ts +23 -0
  95. package/src/contracts/resources.ts +25 -0
  96. package/src/contracts/sampling.ts +23 -0
  97. package/src/contracts/scheduling.ts +45 -0
  98. package/src/contracts/tsconfig.json +14 -0
  99. package/src/diffusion/diffusion-generate.ts +218 -153
  100. package/src/embed.ts +1 -1
  101. package/src/engine/admission.ts +59 -0
  102. package/src/engine/cancellation.ts +38 -0
  103. package/src/engine/engine.ts +56 -0
  104. package/src/engine/execution-coordinator.ts +70 -0
  105. package/src/engine/execution-plan.ts +53 -0
  106. package/src/engine/resources.ts +53 -0
  107. package/src/engine/scheduler.ts +72 -0
  108. package/src/engine/session.ts +247 -0
  109. package/src/eval/README.md +44 -1
  110. package/src/eval/kl.ts +236 -3
  111. package/src/eval/reference-logits.ts +207 -0
  112. package/src/eval/runner.ts +8 -96
  113. package/src/fill/echo-index.ts +188 -0
  114. package/src/fill/fill-session.ts +452 -0
  115. package/src/fill/proposal.ts +68 -0
  116. package/src/fill/schema-rows.ts +506 -0
  117. package/src/fill/tool-boundary.ts +103 -0
  118. package/src/fit.ts +30 -16
  119. package/src/generate.ts +709 -417
  120. package/src/grammar.ts +12 -7
  121. package/src/harness-pi.ts +14 -33
  122. package/src/hub-rest.ts +4 -4
  123. package/src/index.ts +7 -0
  124. package/src/inference/denoising.ts +17 -0
  125. package/src/inference/draft-acceptance.ts +41 -0
  126. package/src/inference/draft-output.ts +49 -0
  127. package/src/inference/graph.ts +33 -0
  128. package/src/inference/prefill.ts +39 -0
  129. package/src/inference/rollback.ts +7 -0
  130. package/src/jobs/db.ts +4 -0
  131. package/src/jobs/index.ts +2 -0
  132. package/src/jobs/job-entry.ts +12 -12
  133. package/src/jobs/runner.ts +98 -13
  134. package/src/jobs/task-client.ts +19 -0
  135. package/src/jobs/types.ts +2 -58
  136. package/src/kv-scheme.ts +70 -12
  137. package/src/kv-store.ts +177 -63
  138. package/src/lab/README.md +18 -0
  139. package/src/{assets → lab/curve}/curve-designer.html +2 -2
  140. package/src/{curve-sampler.ts → lab/curve/curve-sampler.ts} +2 -2
  141. package/src/{expert-trace.ts → lab/expert-trace/expert-trace.ts} +5 -5
  142. package/src/lab/paged-kv/paged-kv-rows.ts +83 -0
  143. package/src/{model → lab/paged-kv}/paged-kv.ts +32 -15
  144. package/src/library.ts +40 -0
  145. package/src/lora.ts +18 -0
  146. package/src/media-fetch.ts +1 -1
  147. package/src/memory/article.ts +1 -1
  148. package/src/memory/chunk.ts +1 -1
  149. package/src/memory/model.ts +30 -169
  150. package/src/memory/prompts.ts +1 -1
  151. package/src/memory/rest.ts +1 -1
  152. package/src/memory/schedule.ts +1 -1
  153. package/src/memory/stages.ts +4 -1
  154. package/src/memory/vault.ts +1 -3
  155. package/src/mlx/array.ts +11 -11
  156. package/src/mlx/compile.ts +12 -2
  157. package/src/mlx/ffi.ts +58 -11
  158. package/src/mlx/materialize.ts +23 -0
  159. package/src/mlx/metal-kernel.ts +10 -11
  160. package/src/mlx/ops.ts +33 -13
  161. package/src/mlx/quantized-rows.ts +36 -0
  162. package/src/mlx/token-bitmask.ts +52 -0
  163. package/src/mlx/turboquant-kv-decode.ts +82 -0
  164. package/src/mlx/turboquant-kv-inverse.ts +122 -0
  165. package/src/mlx/turboquant-ops.ts +33 -3
  166. package/src/mlx/turboquant-tables.ts +2 -2
  167. package/src/model/artifact-identity.ts +73 -0
  168. package/src/model/batched-kv.ts +235 -0
  169. package/src/model/batched-mask.ts +20 -6
  170. package/src/model/batched-quant.ts +9 -3
  171. package/src/model/batched-quantized-kv.ts +144 -0
  172. package/src/model/batched-rotating-quant.ts +78 -17
  173. package/src/model/batched-rotating-state.ts +76 -0
  174. package/src/model/batched-rotating.ts +65 -23
  175. package/src/model/batched-row-storage.ts +52 -0
  176. package/src/model/batched-ssm.ts +52 -0
  177. package/src/model/batched-turboquant-kv.ts +93 -0
  178. package/src/model/compiled-decode.ts +8 -2
  179. package/src/model/decoded-kv-donor.ts +12 -0
  180. package/src/model/delayed-quantized-kv.ts +72 -0
  181. package/src/model/delayed-rotating-quantized-kv.ts +93 -0
  182. package/src/model/delayed-turboquant-kv.ts +55 -0
  183. package/src/model/diffusion-gemma.ts +8 -8
  184. package/src/model/factory.ts +76 -33
  185. package/src/model/fingerprint.ts +1 -1
  186. package/src/model/flash-attention.ts +3 -3
  187. package/src/model/full-prefill-padding.ts +56 -0
  188. package/src/model/full-prefill-row.ts +105 -0
  189. package/src/model/gemma4-base.ts +179 -80
  190. package/src/model/gemma4.ts +40 -32
  191. package/src/model/generated/gemma4-12b.ts +6 -3
  192. package/src/model/generated/gemma4-26b.ts +6 -3
  193. package/src/model/generated/gemma4-e4b.ts +6 -3
  194. package/src/model/glm52-cache.ts +80 -4
  195. package/src/model/glm52-dsa.ts +13 -9
  196. package/src/model/glm52-memory.ts +1 -1
  197. package/src/model/glm52-mla.ts +12 -6
  198. package/src/model/glm52.ts +19 -40
  199. package/src/model/implementation.ts +69 -0
  200. package/src/model/kv-attention-view.ts +67 -0
  201. package/src/model/minicpm5.ts +17 -15
  202. package/src/model/profile.ts +12 -2
  203. package/src/model/qwen-append.ts +12 -0
  204. package/src/model/qwen-conv.ts +52 -0
  205. package/src/model/qwen3-delta-state.ts +74 -0
  206. package/src/model/qwen3-delta.ts +59 -36
  207. package/src/model/qwen3_5-checkpoint.ts +164 -0
  208. package/src/model/qwen3_5.ts +202 -78
  209. package/src/model/rotating-kv-donor.ts +35 -0
  210. package/src/model/rotating-kv-layout.ts +262 -0
  211. package/src/model/rotating-row-transaction.ts +35 -0
  212. package/src/model/speculative-rotating-kv.ts +101 -0
  213. package/src/model/ssm-prefill-padding.ts +39 -0
  214. package/src/model/support.ts +1 -1
  215. package/src/model/trellis-balanced-scatter.ts +51 -0
  216. package/src/model/trellis-linear.ts +672 -0
  217. package/src/model/trellis-shared-m.ts +151 -0
  218. package/src/model/trellis-shared-scatter.ts +144 -0
  219. package/src/model/trellis-splitk-prefill.ts +158 -0
  220. package/src/model/trellis-tiled-prefill.ts +136 -0
  221. package/src/model/trellis-vector-expand.ts +62 -0
  222. package/src/model/trellis-wide-prefill.ts +94 -0
  223. package/src/model/turboquant-codec.ts +83 -0
  224. package/src/model/universal/dense.ts +15 -14
  225. package/src/model/universal/modules.ts +8 -1
  226. package/src/native-pack.ts +6 -5
  227. package/src/pi-provider.ts +6 -64
  228. package/src/pi-web.ts +8 -315
  229. package/src/preflight.ts +31 -15
  230. package/src/prompt-cache.ts +110 -69
  231. package/src/quantize/allocator.ts +1 -1
  232. package/src/quantize/config-writer.ts +10 -3
  233. package/src/quantize/rotate.ts +4 -4
  234. package/src/quantize/trellis.ts +586 -0
  235. package/src/responses.ts +28 -1
  236. package/src/runtime-config.ts +18 -4
  237. package/src/sampler.ts +40 -29
  238. package/src/serve/batch-scheduler.ts +8 -1671
  239. package/src/serve/chat-request.ts +391 -0
  240. package/src/serve/chat-stage.ts +195 -0
  241. package/src/serve/checkpoint-identity.ts +64 -0
  242. package/src/serve/completion-executor.ts +15 -7
  243. package/src/serve/discovery-routes.ts +12 -13
  244. package/src/serve/generation-gateway.ts +183 -213
  245. package/src/serve/http.ts +159 -0
  246. package/src/serve/inference-request.ts +79 -0
  247. package/src/serve/isolate.ts +297 -105
  248. package/src/serve/lab-routes.ts +3 -0
  249. package/src/serve/lane-registry.ts +2 -1
  250. package/src/serve/model-admin-routes.ts +7 -5
  251. package/src/serve/model-binding.ts +43 -0
  252. package/src/serve/model-host.ts +511 -0
  253. package/src/serve/openai-wire.ts +103 -0
  254. package/src/serve/parent-application.ts +56 -0
  255. package/src/serve/pipeline.ts +33 -0
  256. package/src/serve/preparation.ts +33 -0
  257. package/src/serve/request-plan.ts +23 -18
  258. package/src/serve/request-prep.ts +344 -0
  259. package/src/serve/response-lease.ts +24 -0
  260. package/src/serve/responses-client.ts +69 -0
  261. package/src/serve/session-completion-engine.ts +110 -0
  262. package/src/serve/session-search.ts +1 -1
  263. package/src/serve/static-routes.ts +5 -5
  264. package/src/serve/text-completion-stage.ts +104 -0
  265. package/src/serve/token-streams.ts +519 -0
  266. package/src/server.ts +335 -2711
  267. package/src/spec/assistant-rows.ts +92 -0
  268. package/src/spec/assistant-source.ts +31 -55
  269. package/src/spec/cache-identity.ts +22 -0
  270. package/src/spec/deepspec-rows.ts +29 -0
  271. package/src/spec/deepspec-source.ts +16 -14
  272. package/src/spec/dflash-source.ts +36 -12
  273. package/src/spec/drafter.ts +153 -142
  274. package/src/spec/dspark/ab-stats.ts +3 -3
  275. package/src/spec/dspark/calibration.ts +2 -2
  276. package/src/spec/dspark/deepspec-module.ts +97 -122
  277. package/src/spec/dspark/generate-dflash.ts +2 -2
  278. package/src/spec/dspark/generate.ts +2 -2
  279. package/src/spec/dspark/loader.ts +1 -1
  280. package/src/spec/dspark/module-dflash.ts +129 -172
  281. package/src/spec/dspark/module.ts +3 -3
  282. package/src/spec/dspark/quantize-drafter.ts +1 -1
  283. package/src/spec/generate.ts +1 -1
  284. package/src/spec/glm52-mtp-graph.ts +29 -0
  285. package/src/spec/glm52-mtp-rows.ts +132 -0
  286. package/src/spec/glm52-mtp-source.ts +54 -137
  287. package/src/spec/glm52-mtp-state.ts +33 -0
  288. package/src/spec/ngram-source.ts +93 -21
  289. package/src/spec/projected-draft-rows.ts +73 -0
  290. package/src/spec/qwen-mtp-module.ts +171 -0
  291. package/src/spec/qwen-mtp-rows.ts +219 -0
  292. package/src/spec/qwen-mtp-source.ts +147 -195
  293. package/src/spec/qwen-mtp-state.ts +30 -0
  294. package/src/spec/serve-loop.ts +201 -201
  295. package/src/spec/source.ts +110 -13
  296. package/src/spec/two-model-rows.ts +61 -0
  297. package/src/spec/two-model.ts +44 -102
  298. package/src/ssd-cache.ts +99 -19
  299. package/src/ssd-durability.ts +36 -20
  300. package/src/tool-call.ts +51 -14
  301. package/src/train/flash-cce.ts +2 -2
  302. package/src/train/forward.ts +6 -0
  303. package/src/train/loss.ts +1 -1
  304. package/src/train/prefix-shared.ts +5 -1
  305. package/src/train/segmented.ts +5 -3
  306. package/src/train/trainer.ts +6 -6
  307. package/src/vision/prompt.ts +1 -1
  308. package/src/vision/qwen3vl-tower.ts +52 -10
  309. package/src/web/app.html +1 -1
  310. package/src/web/app.js +62 -60
  311. package/src/web/src/adapters-panel.ts +3 -3
  312. package/src/web/src/assistant.ts +2 -36
  313. package/src/web/src/chat.ts +4 -4
  314. package/src/web/src/composer.ts +4 -4
  315. package/src/web/src/hub.ts +1 -1
  316. package/src/web/src/markdown.ts +0 -0
  317. package/src/web/src/memory-panel.ts +1 -1
  318. package/src/web/src/model-picker.ts +1 -1
  319. package/src/web/src/palette.ts +1 -1
  320. package/src/web/src/protocol.ts +3 -39
  321. package/src/web/src/sessions.ts +1 -1
  322. package/src/web/src/ui-catalog.ts +4 -18
  323. package/src/web-assets.ts +47 -0
  324. package/src/weights.ts +55 -9
  325. package/docs/archive/investigations/curve-runs/bisector-route.json +0 -98
  326. package/docs/archive/investigations/curve-runs/bisector-trace.json +0 -1393
  327. package/docs/archive/investigations/curve-runs/curve-terrain.json +0 -1179
  328. package/docs/archive/investigations/curve-runs/curve-terrain.svg +0 -42
  329. package/docs/archive/investigations/hlg-ab.html +0 -34
  330. package/docs/archive/investigations/hlg-explorer.html +0 -238
  331. package/docs/archive/investigations/hlg-figs/cliff.svg +0 -1
  332. package/docs/archive/investigations/hlg-figs/cross.svg +0 -1
  333. package/docs/archive/investigations/hlg-figs/edges.svg +0 -1
  334. package/docs/archive/investigations/hlg-figs/k20-grids.svg +0 -1
  335. package/docs/archive/investigations/hlg-figs/k20-peaks.svg +0 -1
  336. package/docs/archive/investigations/hlg-figs/lw-curve.svg +0 -1
  337. package/docs/archive/investigations/hlg-figs/terrain.svg +0 -1
  338. package/docs/archive/investigations/hlg-report.html +0 -262
  339. package/docs/archive/investigations/hlg-runs/hlg-ab.json +0 -149
  340. package/docs/archive/investigations/hlg-runs/hlg-blind-prompts.md +0 -87
  341. package/docs/archive/investigations/hlg-runs/hlg-blind.json +0 -107
  342. package/docs/archive/investigations/hlg-runs/hlg-cliff.json +0 -197
  343. package/docs/archive/investigations/hlg-runs/hlg-cross.json +0 -505
  344. package/docs/archive/investigations/hlg-runs/hlg-edge.json +0 -388
  345. package/docs/archive/investigations/hlg-runs/hlg-eval1.json +0 -25
  346. package/docs/archive/investigations/hlg-runs/hlg-frontier.json +0 -86
  347. package/docs/archive/investigations/hlg-runs/hlg-grid.json +0 -242
  348. package/docs/archive/investigations/hlg-runs/hlg-grid2.json +0 -343
  349. package/docs/archive/investigations/hlg-runs/hlg-lw-coarse.json +0 -110
  350. package/docs/archive/investigations/hlg-runs/hlg-map.json +0 -383
  351. package/docs/archive/investigations/hlg-runs/run0-original.log +0 -159
  352. package/docs/archive/investigations/hlg-runs/runA-recommended.log +0 -131
  353. package/docs/archive/investigations/hlg-runs/runAA-cliff-cpm5.log +0 -26
  354. package/docs/archive/investigations/hlg-runs/runAB-grid2-e4b.log +0 -18
  355. package/docs/archive/investigations/hlg-runs/runAC-peak-e4b-partial.log +0 -25
  356. package/docs/archive/investigations/hlg-runs/runAD-ab-samples.log +0 -8
  357. package/docs/archive/investigations/hlg-runs/runAE-edge-e4b.log +0 -51
  358. package/docs/archive/investigations/hlg-runs/runAF-logit-calibration.log +0 -10
  359. package/docs/archive/investigations/hlg-runs/runAG-eval-config2.log +0 -16
  360. package/docs/archive/investigations/hlg-runs/runB-gain-variants.log +0 -192
  361. package/docs/archive/investigations/hlg-runs/runC-pivots.log +0 -162
  362. package/docs/archive/investigations/hlg-runs/runD-oetf.log +0 -132
  363. package/docs/archive/investigations/hlg-runs/runE-eotf.log +0 -162
  364. package/docs/archive/investigations/hlg-runs/runF-shaper-working.log +0 -86
  365. package/docs/archive/investigations/hlg-runs/runG-shaper-sweep.log +0 -101
  366. package/docs/archive/investigations/hlg-runs/runH-wsweep.log +0 -176
  367. package/docs/archive/investigations/hlg-runs/runI-asweep.log +0 -176
  368. package/docs/archive/investigations/hlg-runs/runJ-knobmap.log +0 -49
  369. package/docs/archive/investigations/hlg-runs/runK-frontier.log +0 -19
  370. package/docs/archive/investigations/hlg-runs/runL-widemap.log +0 -65
  371. package/docs/archive/investigations/hlg-runs/runM-frontier-emb.log +0 -15
  372. package/docs/archive/investigations/hlg-runs/runN-verify.log +0 -116
  373. package/docs/archive/investigations/hlg-runs/runO-frontier-seed5000.log +0 -15
  374. package/docs/archive/investigations/hlg-runs/runP-grid-AxSm.log +0 -15
  375. package/docs/archive/investigations/hlg-runs/runQ-grid-tgW.log +0 -15
  376. package/docs/archive/investigations/hlg-runs/runR-blind-transcript.log +0 -79
  377. package/docs/archive/investigations/hlg-runs/runS-cross-coherence.log +0 -33
  378. package/docs/archive/investigations/hlg-runs/runT-cross-cpm5.log +0 -33
  379. package/docs/archive/investigations/hlg-runs/runU-cross-12b.log +0 -33
  380. package/docs/archive/investigations/hlg-runs/runV-lw-e4b.log +0 -22
  381. package/docs/archive/investigations/hlg-runs/runW-lw-12b.log +0 -22
  382. package/docs/archive/investigations/hlg-runs/runX-lw-cpm5.log +0 -22
  383. package/docs/archive/investigations/hlg-runs/runY-cliff-e4b.log +0 -26
  384. package/docs/archive/investigations/hlg-runs/runZ-cliff-12b.log +0 -26
  385. package/docs/archive/mlx-bun-lab-report.html +0 -275
  386. package/docs/archive/wwdc-mlx-bun.html +0 -848
  387. package/docs/design/adapters-end-to-end.md +0 -205
  388. package/docs/design/batching-perf-path.md +0 -255
  389. package/docs/design/batching-v2-plan.md +0 -529
  390. package/docs/design/bucketing-stage.md +0 -197
  391. package/docs/design/compat-cli-surface-design.md +0 -230
  392. package/docs/design/docs-reorg-plan.md +0 -165
  393. package/docs/design/dspark-serving-program.md +0 -371
  394. package/docs/design/dspark-speculative-decoding.md +0 -318
  395. package/docs/design/grammar-spec-batching-integration.md +0 -301
  396. package/docs/design/memory-inference-path.md +0 -422
  397. package/docs/design/memory-synthesis.md +0 -287
  398. package/docs/design/memory-system.md +0 -237
  399. package/docs/design/mlx-lm-serving-execution-seam.md +0 -81
  400. package/docs/design/mlx-lm-tool-parity-plan.md +0 -545
  401. package/docs/design/omlx-adoption-map.md +0 -98
  402. package/docs/design/orpo-dynamic-lambda.md +0 -220
  403. package/docs/design/orpo-future-enhancements.md +0 -340
  404. package/docs/design/paged-kv-cache.md +0 -214
  405. package/docs/design/parallel-slots.md +0 -567
  406. package/docs/design/parity-tier-dag.md +0 -161
  407. package/docs/design/repo-cleanup-plan.md +0 -231
  408. package/docs/design/runtime-isolation.md +0 -263
  409. package/docs/design/segmented-backward-training.md +0 -543
  410. package/docs/design/spec-decode-larger-targets.md +0 -229
  411. package/docs/design/ssd-kv-cold-tier.md +0 -415
  412. package/docs/design/structured-output.md +0 -484
  413. package/docs/design/tauri-desktop-app.md +0 -127
  414. package/docs/design/the-dreaming-master-plan.md +0 -445
  415. package/docs/design/turboquant-kv.md +0 -235
  416. package/docs/design/turboquant-weights.md +0 -467
  417. package/docs/design/w4a16-compute-precision-spike.md +0 -232
  418. package/docs/design/web-chat-beat-matrix.md +0 -315
  419. package/docs/design/write-pipeline-entity.md +0 -468
  420. package/docs/planning/IDEAS.md +0 -69
  421. package/docs/reference/embedding.md +0 -197
  422. package/docs/reference/features-matrix.md +0 -101
  423. package/docs/reference/orpo-quickstart.md +0 -135
  424. package/src/flags.ts +0 -11
  425. /package/docs/{design → archive/investigations}/colibri-glm52-port.md +0 -0
  426. /package/docs/{planning → archive/planning}/chunk-task-roadmap.md +0 -0
  427. /package/docs/{planning → archive/planning}/curve-sampler-research-plan.md +0 -0
  428. /package/docs/{planning → archive/planning}/memory-docs-and-dag-plan.md +0 -0
  429. /package/docs/{planning → archive/planning}/pi-integration-review.md +0 -0
  430. /package/docs/{planning → archive/planning}/release-notes-v0.2.0.md +0 -0
  431. /package/src/{memory-plan.ts → admission-plan.ts} +0 -0
  432. /package/{docs/archive/investigations → src/serve/assets}/curve-terrain.html +0 -0
  433. /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).
@@ -52,7 +56,7 @@ import { MEMORY_TOOL_NAMES, REFERENCE_TOOL_NAMES } from "./memory/tools";
52
56
  import { buildPiAgentSurface } from "./pi-session";
53
57
  import { buildPiProvider, DEFAULT_CONTEXT_WINDOW, PI_LOCAL_MODEL_ID } from "./pi-provider";
54
58
  import { downloadsSnapshot } from "./download";
55
- import { getLane, type Lane } from "./serve/lane-registry";
59
+ import { getLane } from "./serve/lane-registry";
56
60
  import { isToolAlwaysAllowed, setToolAlwaysAllowed, listAlwaysAllowedTools } from "./tool-approvals";
57
61
 
58
62
  /**
@@ -356,188 +360,7 @@ export interface PiWsData {
356
360
 
357
361
  type PiWs = ServerWebSocket<PiWsData>;
358
362
 
359
- // ---- WS protocol message shapes --------------------------------------
360
-
361
- /** Decision a browser returns for a gated tool call. `editedArgs`, when
362
- * present on an "allow", replaces the tool's proposed input before it runs
363
- * (LM Studio's editable-args pattern — plan §5.4/§6.5). `alwaysAllow` marks
364
- * the decision as "and remember this tool" — handled by resolveApproval,
365
- * which persists it to the durable tool-approvals config (src/tool-
366
- * approvals.ts) before settling the pending promise. */
367
- export type ApprovalDecision = "allow" | "deny";
368
-
369
- /** An image attachment from the browser: base64 (no data: prefix) + mime. */
370
- export interface ImageAttachment {
371
- data: string;
372
- mimeType: string;
373
- }
374
-
375
- /** Client -> server frames. Exported type-only for the web frontend
376
- * (src/web/src/*.ts import it via `import type` — see tsconfig.web.json
377
- * and scripts/build-web.ts) so the WS contract is checked at compile time
378
- * on both ends instead of drifting between server TS and untyped inline
379
- * browser JS (the observed Phase-0 bug class). */
380
- export type ClientMessage =
381
- | { type: "prompt"; text: string; images?: ImageAttachment[] }
382
- | { type: "abort" }
383
- // `editedArgs`: when the user edited the proposed arguments in the
384
- // approval card's textarea before approving, the (re-parsed) JSON object
385
- // to substitute for the tool's original input — mutated onto the pi SDK's
386
- // ToolCallEvent.input in place (the SDK's documented mutation contract;
387
- // see installApprovalGate). Ignored on "deny". `alwaysAllow`: persist this
388
- // tool to the durable always-allow config (src/tool-approvals.ts) so
389
- // future calls to the SAME TOOL NAME skip the card entirely, on this and
390
- // every other session.
391
- | { type: "approval"; callId: string; decision: ApprovalDecision; editedArgs?: Record<string, unknown>; alwaysAllow?: boolean }
392
- // Toggle the model's reasoning channel on/off (only meaningful when the
393
- // model supports thinking — ready.thinking). Maps to Pi's session thinking
394
- // level: "medium" (on) ↔ "off". Pi sends it as enable_thinking to the server.
395
- | { type: "set_thinking"; enabled: boolean }
396
- // Opt-in toggle (plan §5.4/§6.5/§9 Phase 2, default OFF): "let the agent
397
- // touch files on this machine". Persisted per-browser by the client
398
- // (localStorage `mlxbun.codingTools`); the ALLOWLIST decision is enforced
399
- // here, server-side. buildPiAgentSurface's tool list is fixed for the
400
- // life of an AgentSession (pi's DefaultResourceLoader config is baked in
401
- // at createAgentSessionServices time), so this can't rewire an
402
- // in-progress session — it takes effect starting with the next
403
- // new_session/open_session/fork_session (createRuntimeFactory reads
404
- // this.codingToolsRequested fresh every time the SDK calls it, including
405
- // from AgentSessionRuntime.newSession()'s internal re-invocation). The
406
- // `coding_tools` ServerMessage below reports the honest current-vs-pending
407
- // state so the UI can say so instead of implying it applies immediately.
408
- | { type: "set_coding_tools"; enabled: boolean }
409
- // Select the active LoRA adapter for subsequent turns (null = none/base).
410
- // app.html mounts it (POST /v1/adapters) before sending this; the
411
- // before_provider_request hook injects it into the provider payload.
412
- | { type: "set_adapter"; id: string | null }
413
- // Per-request sampling overrides. Each field is optional; null/undefined
414
- // means "leave it to the server default" (the mode-aware recommended
415
- // value resolved in toOptions). A present numeric value is injected into
416
- // the provider payload and always wins. The before_provider_request hook
417
- // injects whatever is set here.
418
- //
419
- // `scope` (plan §9 Phase 3 / beat matrix Axis 4 "per-message sampling
420
- // scope"): "session" (default, omitting the field means this too) persists
421
- // the override on the connection until changed — today's behavior,
422
- // unchanged. "next_turn" stores a ONE-SHOT override applied to exactly
423
- // the next prompt's injection, then cleared automatically — it never
424
- // touches the session-level values (a later plain set_sampling with
425
- // scope:"session" or omitted still sees whatever was there before this
426
- // message). Composition when both are present: next_turn's SET fields
427
- // win over session's for that one request; anything next_turn leaves
428
- // null/unset falls back to the session-level override for that field
429
- // (composeSampling — session-level itself falls back to the server's
430
- // mode-aware default per injectSampling's existing contract).
431
- | {
432
- type: "set_sampling";
433
- scope?: "session" | "next_turn";
434
- temperature?: number | null;
435
- top_p?: number | null;
436
- top_k?: number | null;
437
- min_p?: number | null;
438
- xtc_probability?: number | null;
439
- xtc_threshold?: number | null;
440
- repetition_penalty?: number | null;
441
- repetition_context_size?: number | null;
442
- presence_penalty?: number | null;
443
- frequency_penalty?: number | null;
444
- seed?: number | null;
445
- }
446
- // Per-session USER system prompt, layered ON TOP OF (not replacing) the
447
- // built-in surface prompt (buildWebChatSystemPrompt + memoryHint). null
448
- // clears it. Applied by the before_agent_start hook on the NEXT turn (pi
449
- // calls it fresh inside every session.prompt(), so this is a true
450
- // per-turn injection, not a session-creation-only setting — see
451
- // installSystemPromptHook). Presets v1 (composer.ts) send this alongside
452
- // set_sampling to apply a saved bundle.
453
- | { type: "set_system_prompt"; text: string | null }
454
- // Session management (recent-chats sidebar + new chat).
455
- | { type: "new_session" }
456
- | { type: "list_sessions" }
457
- | { type: "open_session"; path: string }
458
- | { type: "fork_session"; path: string }
459
- | { type: "delete_session"; path: string }
460
- // Message actions (plan §5.2). All three navigate the session's leaf
461
- // pointer via AgentSession.navigateTree() then re-prompt — a sibling
462
- // branch in the SAME session file, never a new one (see the helpers above
463
- // findLastUserMessageEntry for the full rationale). Regenerate re-sends the
464
- // last user message's original content verbatim; edit_resend re-sends it
465
- // with edited text (images preserved); switch_sibling moves the active
466
- // leaf to a previously-created sibling (an earlier edit/regeneration)
467
- // without sending anything new.
468
- | { type: "regenerate" }
469
- | { type: "edit_resend"; text: string }
470
- | { type: "switch_sibling"; entryId: string }
471
- // App-aware assistant (plan §6.6, §9 Phase 3, beat matrix Axis 12): pushed
472
- // by chat.ts on every route change AND on wizard-step change (quantize/
473
- // finetune/dataset), never on a timer. `context` is opaque here (the
474
- // browser's AppContext shape, src/web/src/assistant.ts) — stored verbatim
475
- // as the connection's currentAppContext and returned by the
476
- // get_current_app_context tool, plus mined for the compact one-line
477
- // ambient context auto-prepended to the NEXT prompt (see
478
- // installAppContextHook / ambientContextLine). This is a DIFFERENT frame
479
- // from the server->client `context` ServerMessage (context-window usage,
480
- // above) — same name, opposite direction, disambiguated by which type
481
- // union it's a member of; the two are never in scope at the same call
482
- // site (ClientMessage here vs. ServerMessage below).
483
- | { type: "context"; context: AppUiContext };
484
-
485
- // ---- App-aware assistant (plan §6.6, §9 Phase 3, beat matrix Axis 12) --
486
- //
487
- // Mirrors src/web/src/assistant.ts's browser-side types (which are the
488
- // source of truth for shape — this server-side copy is intentionally loose
489
- // (mostly `unknown`/optional) since the server never constructs a
490
- // UiSnapshot itself, only stores and forwards what the browser sends. Kept
491
- // here (not imported) because src/web/src/assistant.ts is bundled into the
492
- // browser and importing it here would pull browser code into the server
493
- // build — the inverse of the type-only ClientMessage/ServerMessage import
494
- // direction the frontend uses for pi-web.ts.
495
-
496
- /** One element in a captured DOM snapshot — see assistant.ts's
497
- * UiSnapshotElement for the authoritative shape/doc. */
498
- export interface UiSnapshotElement {
499
- ref: string;
500
- tag: string;
501
- label: string;
502
- kind: "interactive" | "region";
503
- role?: string;
504
- selector: string;
505
- spotlightId?: string;
506
- }
507
-
508
- export interface UiSnapshot {
509
- route: string;
510
- capturedAt: string;
511
- elements: UiSnapshotElement[];
512
- }
513
-
514
- /** The wizard-step process-state fields (§6.6 "carries process state, not
515
- * just elements") — present only on routes with a step wizard. */
516
- export interface WizardStep {
517
- index: number;
518
- count: number;
519
- label: string;
520
- }
521
-
522
- /** The full context payload pushed by chat.ts on route/step change — see
523
- * assistant.ts's buildAppContext. Stored verbatim per-connection. */
524
- export interface AppUiContext {
525
- route: string;
526
- view?: string;
527
- step?: WizardStep;
528
- snapshot: UiSnapshot;
529
- }
530
-
531
- /** Route catalog mirror (src/web/src/ui-catalog.ts's ROUTE_IDS) for
532
- * server-side validation of navigate_app's route/page param BEFORE it
533
- * ever reaches the browser — an unknown route is rejected here as a tool
534
- * error rather than sent as a `ui_navigate` frame the router can't match.
535
- * Keep in sync with ui-catalog.ts's ROUTE_IDS by hand (no shared-JSON
536
- * import between the server and browser bundles — see that file's
537
- * top-of-file comment for why). */
538
- export const APP_ROUTE_IDS = ["chat", "quantize", "finetune", "dataset", "status"] as const;
539
- export type AppRouteId = (typeof APP_ROUTE_IDS)[number];
540
-
363
+ /** Validate assistant navigation against the shared browser/server route IDs. */
541
364
  export function isAppRouteId(v: string): v is AppRouteId {
542
365
  return (APP_ROUTE_IDS as readonly string[]).includes(v);
543
366
  }
@@ -570,117 +393,6 @@ export function ambientContextLine(ctx: AppUiContext | null | undefined): string
570
393
  return `[user is on: ${place}${stepPart}]`;
571
394
  }
572
395
 
573
- /** Model-author recommended sampling (generation_config.json, server-CLI
574
- * overrides applied) — sent once on `ready` so the sampling popover can show
575
- * per-model defaults instead of one hardcoded shape (web-ui-pass-plan.md
576
- * #14). A field is null when neither the model nor the server configured one
577
- * (the built-in fallback in toOptions still applies server-side). */
578
- export interface ReadyGenDefaults {
579
- temperature: number | null;
580
- topP: number | null;
581
- topK: number | null;
582
- }
583
-
584
- /** Server -> client frames. Exported type-only — see ClientMessage above. */
585
- export type ServerMessage =
586
- // `vision`: whether the loaded model can accept images (drives the UI's
587
- // image-attach affordance — false on e4b until the SigLIP sidecar lands).
588
- // `audio`: whether the loaded model can accept `input_audio` parts (audio
589
- // tower loaded or loadable). Discovery-only for now: pi's Model.input type
590
- // has no "audio" modality, so unlike `vision` this flag never feeds the
591
- // provider declaration — clients use it instead of probing for a 400.
592
- // `thinking`: whether the model has a switchable reasoning channel (drives
593
- // the UI's thinking on/off toggle; false hides it).
594
- | { type: "ready"; model: string; vision: boolean; audio: boolean; thinking: boolean; genDefaults: ReadyGenDefaults }
595
- | { type: "turn_start" }
596
- | { type: "text_delta"; delta: string }
597
- | { type: "thinking_delta"; delta: string }
598
- | { type: "tool_start"; callId: string; tool: string; args: unknown }
599
- | { type: "tool_approval_request"; callId: string; tool: string; args: unknown }
600
- | { type: "tool_update"; callId: string; chunk: unknown }
601
- | { type: "tool_end"; callId: string; ok: boolean; result: unknown }
602
- // `lane`: the serving lane the just-finished turn ran on (serial /
603
- // serial+spec / batched), correlated via the lane registry keyed by the
604
- // AssistantMessage's responseId (the pi SDK's own usage parsing drops
605
- // custom fields — see src/serve/lane-registry.ts). Absent when the turn
606
- // produced no assistant message with a responseId (e.g. an aborted turn
607
- // before any model call) — never guessed client-side (risk #5).
608
- | { type: "turn_end"; lane?: Lane }
609
- | { type: "queue_update"; steering: readonly string[]; followUp: readonly string[] }
610
- // Replay a session's transcript (rebuilds the thread); and the sidebar list.
611
- | { type: "history"; items: HistoryItem[] }
612
- | { type: "sessions"; items: SessionListItem[]; activePath?: string }
613
- // Sibling group for the LAST user message (edit-and-resend's `< i/n >`
614
- // toggle, plan §5.2). Sent after every history rebuild and after a
615
- // completed turn. `count` <= 1 means no toggle to show (the common case:
616
- // no edits/regenerations yet). `entryId` is the currently-active sibling's
617
- // id; `siblingIds` is the full ordered group so the client can resolve
618
- // "previous/next" locally and send switch_sibling with a concrete id
619
- // (never inferred/guessed — the server is the source of truth for order).
620
- | { type: "siblings"; entryId?: string; index: number; count: number; siblingIds: string[] }
621
- // Context-window usage indicator. tokens/percent are null right after a
622
- // compaction until the next assistant reply (pi can't estimate yet).
623
- | { type: "context"; tokens: number | null; contextWindow: number; percent: number | null }
624
- // Effective vs. pending codingTools state (set_coding_tools above).
625
- // `active` is what the CURRENT session actually built with (gates
626
- // whether the approval card can ever fire); `pending` is the browser's
627
- // most recent request, which only takes effect on the next
628
- // new/opened/forked session — surfaced so the settings copy can say
629
- // "will apply to your next new chat" instead of lying about immediacy.
630
- | { type: "coding_tools"; active: boolean; pending: boolean }
631
- // Full always-allow set for THIS machine (src/tool-approvals.ts), sent on
632
- // `ready` and after any change, so the settings panel can list/forget
633
- // durable per-tool approvals without a separate REST round-trip.
634
- | { type: "tool_approvals"; alwaysAllow: string[] }
635
- // App-aware assistant (plan §6.6): the navigate_app / spotlight_ui tools'
636
- // side-channel notifications, mapped 1:1 from the tool call's params —
637
- // never guessed or re-derived, so chat.ts's router/spotlight get exactly
638
- // what the model asked for. `route` here is always a validated
639
- // AppRouteId (isAppRouteId already ran server-side before this frame is
640
- // ever sent — see navigate_app's execute). ui_spotlight's fields mirror
641
- // SpotlightRequest 1:1 (assistant.ts resolves ref/label/selector/target
642
- // client-side, in that precedence order, against its last snapshot).
643
- | { type: "ui_navigate"; route: AppRouteId }
644
- | { type: "ui_spotlight"; ref?: string; label?: string; selector?: string; target?: string; message?: string; route?: AppRouteId }
645
- | { type: "error"; message: string };
646
-
647
- // ---- Session serialization (pure, unit-tested) -----------------------
648
-
649
- /** A finished tool call as rendered in replayed history. */
650
- export interface HistoryToolItem {
651
- callId: string;
652
- name: string;
653
- args: unknown;
654
- /** Tool result text, filled from the matching toolResult message. */
655
- result: string;
656
- }
657
-
658
- /** One replayed transcript turn: a user or assistant message (assistant
659
- * messages carry any tool calls they made, with results merged in). */
660
- export interface HistoryItem {
661
- role: "user" | "assistant";
662
- text: string;
663
- /** Model reasoning/thinking, kept separate from the final answer. */
664
- thinking?: string;
665
- tools: HistoryToolItem[];
666
- /** Session entry id (user items only). Lets the browser correlate "the
667
- * last user message" in the replayed thread with the `siblings` frame's
668
- * entryId, so it knows which DOM node gets the edit/sibling-toggle UI
669
- * (plan §5.2). Undefined for assistant items — they aren't fork targets. */
670
- entryId?: string;
671
- }
672
-
673
- /** A row in the recent-chats sidebar, derived from pi's SessionInfo. */
674
- export interface SessionListItem {
675
- path: string;
676
- id: string;
677
- title: string;
678
- /** Last-modified epoch ms (newest first). */
679
- modified: number;
680
- messageCount: number;
681
- forked: boolean;
682
- }
683
-
684
396
  /** Flatten a content value (string | content-parts) to its text. */
685
397
  function contentText(content: unknown): string {
686
398
  if (typeof content === "string") return content;
@@ -964,25 +676,6 @@ export function injectAdapter(
964
676
  return { ...payload, adapter: selected };
965
677
  }
966
678
 
967
- /** Per-request sampling overrides carried on the session and injected into the
968
- * provider payload by the before_provider_request hook. Each field is either a
969
- * user-set override or null/undefined ("use the server's mode-aware default").
970
- * Field names match the server's ChatRequest wire names (not toOptions' camelCase)
971
- * since these are injected directly into the outgoing chat-completions payload. */
972
- export interface SamplingOverrides {
973
- temperature?: number | null;
974
- top_p?: number | null;
975
- top_k?: number | null;
976
- min_p?: number | null;
977
- xtc_probability?: number | null;
978
- xtc_threshold?: number | null;
979
- repetition_penalty?: number | null;
980
- repetition_context_size?: number | null;
981
- presence_penalty?: number | null;
982
- frequency_penalty?: number | null;
983
- seed?: number | null;
984
- }
985
-
986
679
  /** Every SamplingOverrides field name, in wire order — the single source of
987
680
  * truth `injectSampling` and the `set_sampling` handler both walk, so a new
988
681
  * field only needs adding here + the interface above. */
@@ -1158,7 +851,7 @@ function appAwareTextResult(text: string, details: unknown = {}): { content: [{
1158
851
  * null before the first one arrives); `notify` sends a ServerMessage
1159
852
  * (ui_navigate/ui_spotlight) to that same browser tab. Pure enough to
1160
853
  * unit test the tool -> frame mapping via a fake notify collecting sent
1161
- * frames (tests/pi-web.test.ts). */
854
+ * frames (tests/research/pi-web.test.ts). */
1162
855
  export function createAppAwareTools(
1163
856
  getContext: () => AppUiContext | null,
1164
857
  notify: (msg: ServerMessage) => void,
@@ -1267,7 +960,7 @@ class PiWebSession {
1267
960
  * "Per-message sampling scope" block comment above composeSampling for
1268
961
  * the full lifecycle. Wrapped in SamplingScopeState (not two loose
1269
962
  * fields) so the exact same applySetSampling/consumeForRequest pure
1270
- * functions run here and in tests/pi-web.test.ts. */
963
+ * functions run here and in tests/research/pi-web.test.ts. */
1271
964
  private samplingScope: SamplingScopeState = initialSamplingScopeState();
1272
965
  /** User's custom system-prompt text for this connection (set via
1273
966
  * set_system_prompt), null = none. Read by the before_agent_start hook
package/src/preflight.ts CHANGED
@@ -32,6 +32,9 @@ export interface MachineState {
32
32
  /** Foreign processes holding > bigRssMB resident (excludes kernel,
33
33
  * WindowServer, and our own bun/python benchmark processes). */
34
34
  bigProcesses: { rssMB: number; command: string }[];
35
+ /** Explicitly permitted CPU-only background commands; RSS limits still apply. */
36
+ allowedCpuProcesses?: string[];
37
+ backgroundCpuProcesses?: { rssMB: number; command: string }[];
35
38
  ok: boolean;
36
39
  problems: string[];
37
40
  at: string;
@@ -41,6 +44,29 @@ export interface PreflightLimits {
41
44
  maxSwapUsedMB?: number; // default 512
42
45
  minFreePercent?: number; // default 35
43
46
  bigRssMB?: number; // default 2048
47
+ allowCpuProcesses?: string[];
48
+ }
49
+
50
+ export function foreignProcessFindings(output: string, limits: PreflightLimits = {}) {
51
+ const bigProcesses: { rssMB: number; command: string }[] = [];
52
+ const backgroundCpuProcesses: { rssMB: number; command: string }[] = [];
53
+ for (const line of output.split("\n")) {
54
+ const m = line.match(/^\s*([\d.]+)\s+(\d+)\s+(.*)$/);
55
+ if (!m) continue;
56
+ const cpuPct = Number(m[1]);
57
+ const rssMB = Number(m[2]) / 1024;
58
+ const command = m[3]!;
59
+ if (rssMB < (limits.bigRssMB ?? 2048) && cpuPct < 50) continue;
60
+ if (/(bun|\.venv\/bin\/python|mlx_lm|optiq)/.test(command) ||
61
+ /(kernel_task|WindowServer|launchd|mds|spotlight)/i.test(command)) continue;
62
+ const finding = { rssMB: Math.round(rssMB),
63
+ command: command.slice(0, 80) + (cpuPct >= 50 ? ` (${cpuPct.toFixed(0)}% cpu)` : "") };
64
+ // Exact command match; permission to tolerate CPU activity never permits
65
+ // that process to consume the benchmark's memory headroom.
66
+ const allowed = rssMB < (limits.bigRssMB ?? 2048) && limits.allowCpuProcesses?.includes(command);
67
+ (allowed ? backgroundCpuProcesses : bigProcesses).push(finding);
68
+ }
69
+ return { bigProcesses, backgroundCpuProcesses };
44
70
  }
45
71
 
46
72
  function sh(cmd: string[]): string {
@@ -51,7 +77,6 @@ function sh(cmd: string[]): string {
51
77
  export function checkMachine(limits: PreflightLimits = {}): MachineState {
52
78
  const maxSwap = limits.maxSwapUsedMB ?? 512;
53
79
  const minFree = limits.minFreePercent ?? 35;
54
- const bigRss = limits.bigRssMB ?? 2048;
55
80
  const problems: string[] = [];
56
81
 
57
82
  // swap: "vm.swapusage: total = 7168.00M used = 6413.06M free = ..."
@@ -95,26 +120,15 @@ export function checkMachine(limits: PreflightLimits = {}): MachineState {
95
120
  // one clean sample doesn't prove absence (the run-spread stability
96
121
  // policy in bench-h2h.ts is the direct signal); a hot sample here is
97
122
  // still a cheap early warning.
98
- const SELF_PATTERN = /(bun|\.venv\/bin\/python|mlx_lm|optiq)/;
99
- const SYSTEM_PATTERN = /(kernel_task|WindowServer|launchd|mds|spotlight)/i;
100
- const BIG_CPU_PCT = 50;
101
- const bigProcesses: { rssMB: number; command: string }[] = [];
102
- for (const line of sh(["ps", "axo", "pcpu=,rss=,command="]).split("\n")) {
103
- const m = line.match(/^\s*([\d.]+)\s+(\d+)\s+(.*)$/);
104
- if (!m) continue;
105
- const cpuPct = Number(m[1]);
106
- const rssMB = Number(m[2]) / 1024;
107
- const command = m[3]!.slice(0, 80);
108
- if (rssMB < bigRss && cpuPct < BIG_CPU_PCT) continue;
109
- if (SELF_PATTERN.test(command) || SYSTEM_PATTERN.test(command)) continue;
110
- bigProcesses.push({ rssMB: Math.round(rssMB), command: cpuPct >= BIG_CPU_PCT ? `${command} (${cpuPct.toFixed(0)}% cpu)` : command });
111
- }
123
+ const { bigProcesses, backgroundCpuProcesses } = foreignProcessFindings(
124
+ sh(["ps", "axo", "pcpu=,rss=,command="]), limits);
112
125
  for (const p of bigProcesses)
113
126
  problems.push(`big process: ${p.rssMB} MB — ${p.command}`);
114
127
 
115
128
  return {
116
129
  swapUsedMB, freePercent, cpuSpeedLimit, gpuWiredLimitMB, loadAvg1m,
117
130
  bigProcesses,
131
+ allowedCpuProcesses: limits.allowCpuProcesses ?? [], backgroundCpuProcesses,
118
132
  ok: problems.length === 0,
119
133
  problems,
120
134
  at: new Date().toISOString(),
@@ -136,6 +150,8 @@ export function machineStateJson(s: MachineState): string {
136
150
  gpu_wired_mb: s.gpuWiredLimitMB,
137
151
  load1m: s.loadAvg1m,
138
152
  big_procs: s.bigProcesses.length,
153
+ allowed_cpu_processes: s.allowedCpuProcesses ?? [],
154
+ background_cpu_processes: s.backgroundCpuProcesses ?? [],
139
155
  ok: s.ok,
140
156
  at: s.at,
141
157
  });