mlx-bun 0.0.13 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (427) hide show
  1. package/README.md +71 -578
  2. package/bin/mlx-bun.mjs +1 -1
  3. package/docs/README.md +91 -0
  4. package/docs/{design → archive}/hlg-sampling.md +3 -3
  5. package/docs/{design → archive/investigations}/audio-input-plan.md +4 -4
  6. package/docs/{design → archive/investigations}/colibri-glm52-port.md +1 -1
  7. package/docs/{design → archive/investigations}/diffusion-gemma-port.md +3 -3
  8. package/docs/{design → archive/investigations}/faithful-l1-consolidation.md +4 -4
  9. package/docs/{investigations → archive/investigations}/hlg-sampling-investigation.md +1 -1
  10. package/docs/{design → archive/investigations}/minicpm5-decode-megakernel.md +11 -11
  11. package/docs/{design → archive/investigations}/optimization_plan.md +1 -1
  12. package/docs/archive/investigations/pareto-specialized-runtime-findings.md +92 -0
  13. package/docs/{design → archive/investigations}/pre-colibri-stabilization.md +5 -5
  14. package/docs/{design → archive/investigations}/the-dreaming-handoff.md +2 -2
  15. package/docs/{planning → archive/planning}/chat-ui-vision.md +1 -1
  16. package/docs/{planning → archive/planning}/chunk-task-roadmap.md +1 -1
  17. package/docs/{planning → archive/planning}/curve-sampler-research-plan.md +4 -4
  18. package/docs/{planning → archive/planning}/memory-docs-and-dag-plan.md +1 -1
  19. package/docs/{planning → archive/planning}/release-notes-v0.0.9.md +1 -1
  20. package/docs/archive/planning/release-notes-v0.2.0.md +49 -0
  21. package/docs/{planning → archive/planning}/website-readme-pass-plan.md +1 -1
  22. package/docs/design/batching.md +569 -0
  23. package/docs/design/decode-speed-program.md +3178 -169
  24. package/docs/design/dreaming-nightly-pipeline.md +675 -282
  25. package/docs/design/generic-model-support.md +579 -334
  26. package/docs/design/kv-cache.md +680 -0
  27. package/docs/design/orpo-training.md +673 -1239
  28. package/docs/design/speculative-decoding.md +1627 -0
  29. package/docs/design/turboquant.md +2102 -0
  30. package/docs/design/unified-engine-frontier-plan.md +1831 -727
  31. package/docs/design/web-chat-redesign.md +666 -1083
  32. package/docs/planning/PRODUCT_ROADMAP.md +34 -1
  33. package/docs/planning/release-notes-v0.3.0.md +35 -0
  34. package/docs/planning/video-series.md +421 -0
  35. package/docs/reference/benchmarks.md +1162 -0
  36. package/docs/reference/cli.md +395 -149
  37. package/docs/reference/distribution.md +321 -181
  38. package/docs/reference/environment.md +348 -0
  39. package/docs/reference/glossary.md +39 -0
  40. package/docs/reference/library-api.md +580 -142
  41. package/docs/reference/memory.md +227 -64
  42. package/docs/reference/models.md +137 -6
  43. package/docs/reference/server-api.md +938 -422
  44. package/docs/reference/server-config.md +652 -320
  45. package/docs/reference/training.md +393 -254
  46. package/docs/reference/troubleshooting.md +166 -0
  47. package/package.json +10 -5
  48. package/src/admission-plan.ts +18 -0
  49. package/src/anthropic.ts +92 -3
  50. package/src/audio/decode.ts +2 -2
  51. package/src/audio/features.ts +2 -2
  52. package/src/backends/mlx/autoregressive.ts +108 -0
  53. package/src/backends/mlx/batch-group.ts +1646 -0
  54. package/src/backends/mlx/diffusion.ts +39 -0
  55. package/src/backends/mlx/draft-target.ts +47 -0
  56. package/src/backends/mlx/evaluation.ts +105 -0
  57. package/src/backends/mlx/fill-append.ts +45 -0
  58. package/src/backends/mlx/gateway-binding.ts +71 -0
  59. package/src/backends/mlx/graph.ts +38 -0
  60. package/src/backends/mlx/memory-client.ts +189 -0
  61. package/src/backends/mlx/memory-guard.ts +40 -0
  62. package/src/backends/mlx/methods.ts +90 -0
  63. package/src/backends/mlx/model-prompt.ts +164 -0
  64. package/src/backends/mlx/model-serving.ts +79 -0
  65. package/src/backends/mlx/prefill.ts +33 -0
  66. package/src/backends/mlx/request-policy.ts +20 -0
  67. package/src/backends/mlx/rollback.ts +51 -0
  68. package/src/backends/mlx/serial-executor.ts +273 -0
  69. package/src/backends/mlx/speculative.ts +114 -0
  70. package/src/backends/mlx/state-views.ts +26 -0
  71. package/src/backends/mlx/text-engine.ts +73 -0
  72. package/src/cli.ts +189 -61
  73. package/src/client.ts +66 -0
  74. package/src/config.ts +21 -4
  75. package/src/contracts/completion.ts +16 -0
  76. package/src/contracts/execution.ts +49 -0
  77. package/src/contracts/generation.ts +103 -0
  78. package/src/contracts/host.ts +7 -0
  79. package/src/contracts/jobs.ts +66 -0
  80. package/src/contracts/pi-provider.ts +30 -0
  81. package/src/contracts/pi.ts +259 -0
  82. package/src/contracts/resources.ts +18 -0
  83. package/src/contracts/scheduling.ts +27 -0
  84. package/src/contracts/tsconfig.json +14 -0
  85. package/src/diffusion/diffusion-generate.ts +218 -153
  86. package/src/embed.ts +1 -1
  87. package/src/engine/admission.ts +59 -0
  88. package/src/engine/cancellation.ts +38 -0
  89. package/src/engine/engine.ts +56 -0
  90. package/src/engine/execution-coordinator.ts +70 -0
  91. package/src/engine/execution-plan.ts +51 -0
  92. package/src/engine/resources.ts +42 -0
  93. package/src/engine/scheduler.ts +67 -0
  94. package/src/engine/session.ts +247 -0
  95. package/src/eval/README.md +44 -1
  96. package/src/eval/kl.ts +263 -23
  97. package/src/eval/reference-logits.ts +207 -0
  98. package/src/eval/runner.ts +10 -79
  99. package/src/eval/tasks/bfcl.ts +2 -1
  100. package/src/eval/tasks/gsm8k.ts +2 -1
  101. package/src/eval/tasks/hashhop.ts +2 -1
  102. package/src/eval/tasks/humaneval.ts +5 -4
  103. package/src/eval/tasks/ifeval.ts +2 -1
  104. package/src/eval/tasks/mmlu.ts +2 -1
  105. package/src/expert-io.ts +3 -1
  106. package/src/expert-offload.ts +3 -1
  107. package/src/fill/echo-index.ts +188 -0
  108. package/src/fill/fill-session.ts +452 -0
  109. package/src/fill/proposal.ts +68 -0
  110. package/src/fill/schema-rows.ts +506 -0
  111. package/src/fill/tool-boundary.ts +103 -0
  112. package/src/fit.ts +24 -43
  113. package/src/generate.ts +740 -337
  114. package/src/grammar.ts +14 -8
  115. package/src/harness-pi.ts +15 -34
  116. package/src/hub-rest.ts +4 -4
  117. package/src/index.ts +27 -0
  118. package/src/inference/denoising.ts +17 -0
  119. package/src/inference/graph.ts +33 -0
  120. package/src/inference/prefill.ts +39 -0
  121. package/src/inference/rollback.ts +7 -0
  122. package/src/jobs/db.ts +4 -0
  123. package/src/jobs/index.ts +2 -0
  124. package/src/jobs/job-entry.ts +15 -14
  125. package/src/jobs/runner.ts +98 -13
  126. package/src/jobs/task-client.ts +19 -0
  127. package/src/jobs/types.ts +2 -58
  128. package/src/kv-scheme.ts +199 -0
  129. package/src/kv-store.ts +459 -234
  130. package/src/lab/README.md +18 -0
  131. package/src/{assets → lab/curve}/curve-designer.html +2 -2
  132. package/src/{curve-sampler.ts → lab/curve/curve-sampler.ts} +2 -2
  133. package/src/{expert-trace.ts → lab/expert-trace/expert-trace.ts} +7 -5
  134. package/src/{model → lab/paged-kv}/paged-kv.ts +9 -6
  135. package/src/library.ts +40 -0
  136. package/src/lora.ts +18 -0
  137. package/src/media-fetch.ts +20 -4
  138. package/src/memory/article.ts +1 -1
  139. package/src/memory/chunk.ts +1 -1
  140. package/src/memory/model.ts +32 -170
  141. package/src/memory/prompts.ts +1 -1
  142. package/src/memory/rest.ts +1 -1
  143. package/src/memory/schedule.ts +1 -1
  144. package/src/memory/stages.ts +4 -1
  145. package/src/memory/vault.ts +3 -4
  146. package/src/mlx/array.ts +9 -10
  147. package/src/mlx/compile.ts +12 -2
  148. package/src/mlx/ffi.ts +66 -22
  149. package/src/mlx/materialize.ts +23 -0
  150. package/src/mlx/metal-kernel.ts +10 -11
  151. package/src/mlx/ops.ts +64 -19
  152. package/src/mlx/quantized-rows.ts +36 -0
  153. package/src/mlx/token-bitmask.ts +52 -0
  154. package/src/mlx/turboquant-kv-decode.ts +82 -0
  155. package/src/mlx/turboquant-kv-inverse.ts +122 -0
  156. package/src/mlx/turboquant-ops.ts +33 -3
  157. package/src/mlx/turboquant-tables.ts +2 -2
  158. package/src/model/batched-mask.ts +9 -3
  159. package/src/model/batched-quant.ts +2 -2
  160. package/src/model/batched-rotating-quant.ts +45 -99
  161. package/src/model/batched-rotating-state.ts +73 -0
  162. package/src/model/batched-rotating.ts +57 -106
  163. package/src/model/batched-row-storage.ts +127 -0
  164. package/src/model/compiled-decode.ts +4 -3
  165. package/src/model/diffusion-gemma.ts +8 -8
  166. package/src/model/factory.ts +87 -49
  167. package/src/model/fingerprint.ts +1 -1
  168. package/src/model/flash-attention.ts +3 -3
  169. package/src/model/gemma4-base.ts +187 -17
  170. package/src/model/gemma4.ts +6 -6
  171. package/src/model/generated/gemma4-12b.ts +52 -148
  172. package/src/model/generated/gemma4-26b.ts +34 -94
  173. package/src/model/generated/gemma4-e4b.ts +28 -76
  174. package/src/model/glm52-cache.ts +19 -9
  175. package/src/model/glm52-dsa.ts +13 -9
  176. package/src/model/glm52-memory.ts +28 -1
  177. package/src/model/implementation.ts +69 -0
  178. package/src/model/minicpm5.ts +7 -8
  179. package/src/model/profile.ts +443 -0
  180. package/src/model/qwen-append.ts +12 -0
  181. package/src/model/qwen-conv.ts +52 -0
  182. package/src/model/qwen3-delta.ts +98 -2
  183. package/src/model/qwen3-mrope.ts +252 -0
  184. package/src/model/qwen3_5-checkpoint.ts +164 -0
  185. package/src/model/qwen3_5.ts +336 -60
  186. package/src/model/support.ts +1 -1
  187. package/src/model/trellis-balanced-scatter.ts +51 -0
  188. package/src/model/trellis-linear.ts +672 -0
  189. package/src/model/trellis-shared-m.ts +151 -0
  190. package/src/model/trellis-shared-scatter.ts +144 -0
  191. package/src/model/trellis-splitk-prefill.ts +158 -0
  192. package/src/model/trellis-tiled-prefill.ts +136 -0
  193. package/src/model/trellis-vector-expand.ts +62 -0
  194. package/src/model/trellis-wide-prefill.ts +94 -0
  195. package/src/model/universal/dense.ts +1 -1
  196. package/src/model/universal/modules.ts +8 -1
  197. package/src/native/frame_extract.swift +140 -0
  198. package/src/native-pack.ts +15 -7
  199. package/src/pi-provider.ts +6 -64
  200. package/src/pi-web.ts +14 -320
  201. package/src/prompt-cache.ts +97 -54
  202. package/src/quantize/allocator.ts +1 -1
  203. package/src/quantize/atomic-output.ts +38 -0
  204. package/src/quantize/calibration.ts +2 -1
  205. package/src/quantize/config-writer.ts +16 -3
  206. package/src/quantize/index.ts +28 -1
  207. package/src/quantize/job.ts +11 -0
  208. package/src/quantize/quantizer.ts +265 -100
  209. package/src/quantize/rotate.ts +603 -0
  210. package/src/quantize/safetensors-writer.ts +79 -1
  211. package/src/quantize/sensitivity.ts +41 -59
  212. package/src/quantize/trellis.ts +586 -0
  213. package/src/quantize/weight-transform.ts +292 -0
  214. package/src/responses.ts +130 -3
  215. package/src/runtime-config.ts +81 -0
  216. package/src/sampler.ts +276 -4
  217. package/src/serve/admin-routes.ts +184 -0
  218. package/src/serve/aux-routes.ts +132 -0
  219. package/src/serve/batch-scheduler.ts +8 -1558
  220. package/src/serve/chat-request.ts +391 -0
  221. package/src/serve/chat-stage.ts +195 -0
  222. package/src/serve/checkpoint-identity.ts +64 -0
  223. package/src/serve/completion-executor.ts +354 -0
  224. package/src/serve/completion-sink.ts +157 -0
  225. package/src/serve/discovery-routes.ts +204 -0
  226. package/src/serve/generation-gateway.ts +211 -243
  227. package/src/serve/http.ts +159 -0
  228. package/src/serve/inference-request.ts +79 -0
  229. package/src/serve/isolate.ts +297 -105
  230. package/src/serve/kv-budget.ts +14 -0
  231. package/src/serve/lab-routes.ts +341 -0
  232. package/src/serve/lane-registry.ts +2 -1
  233. package/src/serve/model-admin-routes.ts +155 -0
  234. package/src/serve/model-binding.ts +43 -0
  235. package/src/serve/model-host.ts +512 -0
  236. package/src/serve/openai-wire.ts +103 -0
  237. package/src/serve/parent-application.ts +56 -0
  238. package/src/serve/pipeline.ts +33 -0
  239. package/src/serve/preparation.ts +33 -0
  240. package/src/serve/prompt-response-trace.ts +147 -0
  241. package/src/serve/request-plan.ts +162 -0
  242. package/src/serve/request-prep.ts +346 -0
  243. package/src/serve/response-lease.ts +24 -0
  244. package/src/serve/responses-client.ts +69 -0
  245. package/src/serve/session-completion-engine.ts +110 -0
  246. package/src/serve/session-search.ts +1 -1
  247. package/src/serve/static-routes.ts +101 -0
  248. package/src/serve/text-completion-stage.ts +104 -0
  249. package/src/serve/token-streams.ts +519 -0
  250. package/src/server.ts +523 -3551
  251. package/src/spec/assistant-source.ts +10 -44
  252. package/src/spec/deepspec-source.ts +6 -6
  253. package/src/spec/dflash-source.ts +9 -8
  254. package/src/spec/dspark/ab-stats.ts +3 -3
  255. package/src/spec/dspark/calibration.ts +2 -2
  256. package/src/spec/dspark/deepspec-module.ts +2 -2
  257. package/src/spec/dspark/generate-dflash.ts +2 -2
  258. package/src/spec/dspark/generate.ts +2 -2
  259. package/src/spec/dspark/loader.ts +1 -1
  260. package/src/spec/dspark/module-dflash.ts +5 -4
  261. package/src/spec/dspark/module.ts +3 -3
  262. package/src/spec/dspark/quantize-drafter.ts +1 -1
  263. package/src/spec/generate.ts +1 -1
  264. package/src/spec/glm52-mtp-source.ts +9 -1
  265. package/src/spec/ngram-source.ts +1 -1
  266. package/src/spec/prefix-state.ts +45 -0
  267. package/src/spec/qwen-mtp-source.ts +528 -0
  268. package/src/spec/serve-loop.ts +179 -213
  269. package/src/spec/source.ts +42 -10
  270. package/src/spec/two-model.ts +1 -1
  271. package/src/ssd-cache.ts +95 -24
  272. package/src/ssd-durability.ts +207 -0
  273. package/src/tool-call.ts +51 -14
  274. package/src/train/flash-cce.ts +14 -13
  275. package/src/train/forward.ts +38 -1
  276. package/src/train/loss.ts +3 -2
  277. package/src/train/prefix-shared.ts +5 -1
  278. package/src/train/segmented.ts +9 -6
  279. package/src/train/trainer.ts +9 -8
  280. package/src/vision/preprocess.ts +1 -1
  281. package/src/vision/prompt.ts +48 -2
  282. package/src/vision/qwen3vl-preprocess.ts +409 -0
  283. package/src/vision/qwen3vl-prompt.ts +196 -0
  284. package/src/vision/qwen3vl-tower.ts +555 -0
  285. package/src/vision/video-frames.ts +148 -0
  286. package/src/web/app.html +1 -1
  287. package/src/web/app.js +15 -6
  288. package/src/web/src/adapters-panel.ts +3 -3
  289. package/src/web/src/assistant.ts +2 -36
  290. package/src/web/src/chat.ts +16 -9
  291. package/src/web/src/composer.ts +4 -4
  292. package/src/web/src/hub.ts +1 -1
  293. package/src/web/src/markdown.ts +0 -0
  294. package/src/web/src/memory-panel.ts +1 -1
  295. package/src/web/src/model-picker.ts +1 -1
  296. package/src/web/src/palette.ts +1 -1
  297. package/src/web/src/protocol.ts +3 -39
  298. package/src/web/src/sessions.ts +1 -1
  299. package/src/web/src/ui-catalog.ts +4 -18
  300. package/src/web-assets.ts +47 -0
  301. package/src/weights.ts +134 -33
  302. package/docs/archive/mlx-bun-lab-report.html +0 -275
  303. package/docs/archive/wwdc-mlx-bun.html +0 -848
  304. package/docs/design/adapters-end-to-end.md +0 -205
  305. package/docs/design/batching-perf-path.md +0 -255
  306. package/docs/design/batching-v2-plan.md +0 -529
  307. package/docs/design/bucketing-stage.md +0 -197
  308. package/docs/design/compat-cli-surface-design.md +0 -230
  309. package/docs/design/docs-reorg-plan.md +0 -165
  310. package/docs/design/dspark-serving-program.md +0 -371
  311. package/docs/design/dspark-speculative-decoding.md +0 -268
  312. package/docs/design/grammar-spec-batching-integration.md +0 -301
  313. package/docs/design/memory-inference-path.md +0 -422
  314. package/docs/design/memory-synthesis.md +0 -287
  315. package/docs/design/memory-system.md +0 -237
  316. package/docs/design/mlx-lm-tool-parity-plan.md +0 -545
  317. package/docs/design/omlx-adoption-map.md +0 -98
  318. package/docs/design/orpo-dynamic-lambda.md +0 -220
  319. package/docs/design/orpo-future-enhancements.md +0 -340
  320. package/docs/design/paged-kv-cache.md +0 -214
  321. package/docs/design/parallel-slots.md +0 -567
  322. package/docs/design/parity-tier-dag.md +0 -161
  323. package/docs/design/repo-cleanup-plan.md +0 -189
  324. package/docs/design/runtime-isolation.md +0 -263
  325. package/docs/design/segmented-backward-training.md +0 -543
  326. package/docs/design/spec-decode-larger-targets.md +0 -229
  327. package/docs/design/ssd-kv-cold-tier.md +0 -288
  328. package/docs/design/structured-output.md +0 -484
  329. package/docs/design/tauri-desktop-app.md +0 -127
  330. package/docs/design/the-dreaming-master-plan.md +0 -445
  331. package/docs/design/turboquant-kv.md +0 -235
  332. package/docs/design/w4a16-compute-precision-spike.md +0 -232
  333. package/docs/design/web-chat-beat-matrix.md +0 -315
  334. package/docs/design/write-pipeline-entity.md +0 -468
  335. package/docs/investigations/curve-runs/bisector-route.json +0 -98
  336. package/docs/investigations/curve-runs/bisector-trace.json +0 -1393
  337. package/docs/investigations/curve-runs/curve-terrain.json +0 -1179
  338. package/docs/investigations/curve-runs/curve-terrain.svg +0 -42
  339. package/docs/investigations/hlg-ab.html +0 -34
  340. package/docs/investigations/hlg-explorer.html +0 -238
  341. package/docs/investigations/hlg-figs/cliff.svg +0 -1
  342. package/docs/investigations/hlg-figs/cross.svg +0 -1
  343. package/docs/investigations/hlg-figs/edges.svg +0 -1
  344. package/docs/investigations/hlg-figs/k20-grids.svg +0 -1
  345. package/docs/investigations/hlg-figs/k20-peaks.svg +0 -1
  346. package/docs/investigations/hlg-figs/lw-curve.svg +0 -1
  347. package/docs/investigations/hlg-figs/terrain.svg +0 -1
  348. package/docs/investigations/hlg-report.html +0 -262
  349. package/docs/investigations/hlg-runs/hlg-ab.json +0 -149
  350. package/docs/investigations/hlg-runs/hlg-blind-prompts.md +0 -87
  351. package/docs/investigations/hlg-runs/hlg-blind.json +0 -107
  352. package/docs/investigations/hlg-runs/hlg-cliff.json +0 -197
  353. package/docs/investigations/hlg-runs/hlg-cross.json +0 -505
  354. package/docs/investigations/hlg-runs/hlg-edge.json +0 -388
  355. package/docs/investigations/hlg-runs/hlg-eval1.json +0 -25
  356. package/docs/investigations/hlg-runs/hlg-frontier.json +0 -86
  357. package/docs/investigations/hlg-runs/hlg-grid.json +0 -242
  358. package/docs/investigations/hlg-runs/hlg-grid2.json +0 -343
  359. package/docs/investigations/hlg-runs/hlg-lw-coarse.json +0 -110
  360. package/docs/investigations/hlg-runs/hlg-map.json +0 -383
  361. package/docs/investigations/hlg-runs/run0-original.log +0 -159
  362. package/docs/investigations/hlg-runs/runA-recommended.log +0 -131
  363. package/docs/investigations/hlg-runs/runAA-cliff-cpm5.log +0 -26
  364. package/docs/investigations/hlg-runs/runAB-grid2-e4b.log +0 -18
  365. package/docs/investigations/hlg-runs/runAC-peak-e4b-partial.log +0 -25
  366. package/docs/investigations/hlg-runs/runAD-ab-samples.log +0 -8
  367. package/docs/investigations/hlg-runs/runAE-edge-e4b.log +0 -51
  368. package/docs/investigations/hlg-runs/runAF-logit-calibration.log +0 -10
  369. package/docs/investigations/hlg-runs/runAG-eval-config2.log +0 -16
  370. package/docs/investigations/hlg-runs/runB-gain-variants.log +0 -192
  371. package/docs/investigations/hlg-runs/runC-pivots.log +0 -162
  372. package/docs/investigations/hlg-runs/runD-oetf.log +0 -132
  373. package/docs/investigations/hlg-runs/runE-eotf.log +0 -162
  374. package/docs/investigations/hlg-runs/runF-shaper-working.log +0 -86
  375. package/docs/investigations/hlg-runs/runG-shaper-sweep.log +0 -101
  376. package/docs/investigations/hlg-runs/runH-wsweep.log +0 -176
  377. package/docs/investigations/hlg-runs/runI-asweep.log +0 -176
  378. package/docs/investigations/hlg-runs/runJ-knobmap.log +0 -49
  379. package/docs/investigations/hlg-runs/runK-frontier.log +0 -19
  380. package/docs/investigations/hlg-runs/runL-widemap.log +0 -65
  381. package/docs/investigations/hlg-runs/runM-frontier-emb.log +0 -15
  382. package/docs/investigations/hlg-runs/runN-verify.log +0 -116
  383. package/docs/investigations/hlg-runs/runO-frontier-seed5000.log +0 -15
  384. package/docs/investigations/hlg-runs/runP-grid-AxSm.log +0 -15
  385. package/docs/investigations/hlg-runs/runQ-grid-tgW.log +0 -15
  386. package/docs/investigations/hlg-runs/runR-blind-transcript.log +0 -79
  387. package/docs/investigations/hlg-runs/runS-cross-coherence.log +0 -33
  388. package/docs/investigations/hlg-runs/runT-cross-cpm5.log +0 -33
  389. package/docs/investigations/hlg-runs/runU-cross-12b.log +0 -33
  390. package/docs/investigations/hlg-runs/runV-lw-e4b.log +0 -22
  391. package/docs/investigations/hlg-runs/runW-lw-12b.log +0 -22
  392. package/docs/investigations/hlg-runs/runX-lw-cpm5.log +0 -22
  393. package/docs/investigations/hlg-runs/runY-cliff-e4b.log +0 -26
  394. package/docs/investigations/hlg-runs/runZ-cliff-12b.log +0 -26
  395. package/docs/planning/IDEAS.md +0 -69
  396. package/docs/reference/embedding.md +0 -197
  397. package/docs/reference/features-matrix.md +0 -100
  398. package/docs/reference/orpo-quickstart.md +0 -135
  399. package/src/flags.ts +0 -13
  400. /package/docs/{investigations → archive/investigations}/chunk-finetune-experiment.md +0 -0
  401. /package/docs/{investigations → archive/investigations}/colibri-oracle-pin.md +0 -0
  402. /package/docs/{investigations → archive/investigations}/curve-bisector-routing.md +0 -0
  403. /package/docs/{investigations → archive/investigations}/decode-roofline-lookagain.md +0 -0
  404. /package/docs/{investigations → archive/investigations}/dspark-handoff.md +0 -0
  405. /package/docs/{investigations → archive/investigations}/expert-offload-single-user-moe.md +0 -0
  406. /package/docs/{investigations → archive/investigations}/indexshare-performance-spike.md +0 -0
  407. /package/docs/{investigations → archive/investigations}/kernel-perf-review-2026-07.md +0 -0
  408. /package/docs/{investigations → archive/investigations}/lab-build-journal.md +0 -0
  409. /package/docs/{investigations → archive/investigations}/openwiki-evaluation.md +0 -0
  410. /package/docs/{investigations → archive/investigations}/orpo-base-uf-experiment-and-directions.md +0 -0
  411. /package/docs/{investigations → archive/investigations}/orpo-flash-cce-pin-leak.md +0 -0
  412. /package/docs/{investigations → archive/investigations}/orpo-uf-testing-handoff.md +0 -0
  413. /package/docs/{investigations → archive/investigations}/pi-builtin-investigation.md +0 -0
  414. /package/docs/{investigations → archive/investigations}/segmented-backward-handoff.md +0 -0
  415. /package/docs/{investigations → archive/investigations}/starter-model-port-handoff.md +0 -0
  416. /package/docs/{investigations → archive/investigations}/steel-flash-cce-handoff.md +0 -0
  417. /package/docs/{investigations → archive/investigations}/trainer-validation-experiment.md +0 -0
  418. /package/docs/{planning → archive/planning}/chat-ui-vision-memory-first.md +0 -0
  419. /package/docs/{planning → archive/planning}/journal.md +0 -0
  420. /package/docs/{planning → archive/planning}/pi-integration-review.md +0 -0
  421. /package/docs/{planning → archive/planning}/release-notes-v0.0.10.md +0 -0
  422. /package/docs/{planning → archive/planning}/release-notes-v0.0.11.md +0 -0
  423. /package/docs/{planning → archive/planning}/release-notes-v0.0.12.md +0 -0
  424. /package/docs/{planning → archive/planning}/release-notes-v0.0.13.md +0 -0
  425. /package/docs/{planning → archive/planning}/web-ui-pass-plan.md +0 -0
  426. /package/{docs/investigations → src/serve/assets}/curve-terrain.html +0 -0
  427. /package/{docs/dag → src/serve/assets}/training-inference-map.html +0 -0
@@ -0,0 +1,148 @@
1
+ // Video file → RGB frames via the AVFoundation sidecar (PLAN 14w) — the
2
+ // video twin of the audio path's afconvert doctrine: macOS-native codecs
3
+ // (H.264/HEVC/ProRes/…), zero vendored decoders. The sidecar
4
+ // (src/native/frame_extract.swift, shipped as `mlx-bun-frame-extract` beside
5
+ // the binary and in the native pack) samples frames at fps=2 with
6
+ // zero-tolerance timestamps — mirroring mlx-vlm's do_sample_frames — and
7
+ // writes PNGs that decode through the SAME fast-png path as image inputs.
8
+ //
9
+ // Resolution order (afconvert needs none of this because /usr/bin ships it;
10
+ // our extractor is the missing CLI face on Apple's decoder):
11
+ // MLX_BUN_FRAME_EXTRACT env → beside the executable (release bundle) →
12
+ // the native-pack cache → dist-native (dev tree) → compile-on-demand from
13
+ // src/native (from-source installs with Xcode CLT; cached in dist-native).
14
+
15
+ import { existsSync, mkdirSync } from "node:fs";
16
+ import { rm } from "node:fs/promises";
17
+ import { randomUUID } from "node:crypto";
18
+ import { tmpdir } from "node:os";
19
+ import { dirname, join } from "node:path";
20
+ import { nativePackDir } from "../native-pack";
21
+ import { decodeImage, type RGBImage } from "./preprocess";
22
+ import { runtimeValue } from "../runtime-config";
23
+
24
+ export const VIDEO_SAMPLE_FPS = 2;
25
+ export const VIDEO_MAX_FRAMES = 768; // Qwen3VLVideoProcessor max_frames
26
+
27
+ const BIN = "mlx-bun-frame-extract";
28
+
29
+ /** Memoize the PROMISE, not the result: a second video request arriving
30
+ * while the first compile is in flight must await the same compile, not
31
+ * observe a half-set cache and spuriously report the sidecar missing. */
32
+ let devCompile: Promise<string | null> | null = null;
33
+
34
+ /** Compile the sidecar from the repo tree (dev/from-source convenience —
35
+ * needs swiftc from the Xcode CLT). Null when the source or toolchain is
36
+ * unavailable. */
37
+ function compileFromSource(): Promise<string | null> {
38
+ devCompile ??= (async () => {
39
+ const src = join(import.meta.dir, "..", "native", "frame_extract.swift");
40
+ if (!existsSync(src)) return null;
41
+ const out = join(import.meta.dir, "..", "..", "dist-native", BIN);
42
+ try {
43
+ mkdirSync(dirname(out), { recursive: true });
44
+ const proc = Bun.spawn(["swiftc", "-O", src, "-o", out], {
45
+ stdout: "ignore", stderr: "pipe",
46
+ });
47
+ if ((await proc.exited) === 0 && existsSync(out)) return out;
48
+ } catch {
49
+ // no swiftc — resolver returns null and serving 400s with the reason
50
+ }
51
+ return null;
52
+ })();
53
+ return devCompile;
54
+ }
55
+
56
+ /** Locate (or dev-compile) the extractor; null ⟹ video input unavailable
57
+ * on this install (surfaced as a clear 400, never a crash). */
58
+ export async function resolveFrameExtract(): Promise<string | null> {
59
+ const explicit = runtimeValue("MLX_BUN_FRAME_EXTRACT");
60
+ if (explicit) return explicit;
61
+ const candidates = [
62
+ join(dirname(process.execPath), BIN),
63
+ join(nativePackDir(), BIN),
64
+ join(import.meta.dir, "..", "..", "dist-native", BIN),
65
+ ];
66
+ for (const c of candidates) if (existsSync(c)) return c;
67
+ return compileFromSource();
68
+ }
69
+
70
+ /** Decode a video container to sampled RGB frames. Throws with the
71
+ * sidecar's diagnostic on failure (the serve layer surfaces it as a 400,
72
+ * the afconvert pattern — timeout kill included). */
73
+ export async function extractVideoFrames(
74
+ bytes: Uint8Array,
75
+ opts: { fps?: number; maxFrames?: number } = {},
76
+ ): Promise<RGBImage[]> {
77
+ const bin = await resolveFrameExtract();
78
+ if (!bin)
79
+ throw new Error(
80
+ "video input needs the frame-extraction sidecar (mlx-bun-frame-extract) " +
81
+ "— ships beside the release binary and in the native pack; from a " +
82
+ "source tree it compiles on first use via the Xcode CLT (swiftc)",
83
+ );
84
+ const base = join(tmpdir(), `mlx-bun-video-${randomUUID()}`);
85
+ // AVFoundation infers the container from the path EXTENSION — sniff the
86
+ // ISO-BMFF `ftyp` box (mp4/mov share it; the `qt ` major brand is
87
+ // QuickTime) so the temp file opens. Unknown magic defaults to .mp4.
88
+ const isFtyp = bytes.length >= 12 &&
89
+ bytes[4] === 0x66 && bytes[5] === 0x74 && bytes[6] === 0x79 && bytes[7] === 0x70;
90
+ const brand = isFtyp
91
+ ? String.fromCharCode(bytes[8]!, bytes[9]!, bytes[10]!, bytes[11]!)
92
+ : "";
93
+ const ext = brand.startsWith("qt") ? "mov" : "mp4";
94
+ const inPath = `${base}.${ext}`;
95
+ const outDir = `${base}.frames`;
96
+ try {
97
+ // Inside the try so a part-way write failure (ENOSPC on a large clip)
98
+ // still hits the finally's cleanup instead of stranding the temp file.
99
+ await Bun.write(inPath, bytes);
100
+ const proc = Bun.spawn(
101
+ [
102
+ bin, inPath, outDir,
103
+ String(opts.fps ?? VIDEO_SAMPLE_FPS),
104
+ String(opts.maxFrames ?? VIDEO_MAX_FRAMES),
105
+ ],
106
+ { stdout: "pipe", stderr: "pipe" },
107
+ );
108
+ // Decoding is fast (hardware) but long clips take real time; a hung
109
+ // decoder must not pin the request forever — kill → nonzero → 400.
110
+ const killer = setTimeout(() => proc.kill(), 120_000);
111
+ const exit = await proc.exited;
112
+ clearTimeout(killer);
113
+ if (exit !== 0) {
114
+ const err = (await new Response(proc.stderr).text()).trim();
115
+ throw new Error(
116
+ `video decode failed (frame-extract exit ${exit}): ` +
117
+ `${err.split("\n").at(-1) || "unknown error"} — supported containers: ` +
118
+ `whatever AVFoundation decodes on this macOS (mp4/mov H.264/HEVC/ProRes/…)`,
119
+ );
120
+ }
121
+ const head = (await new Response(proc.stdout).text()).trim();
122
+ const n = Number(/^N (\d+)/.exec(head)?.[1] ?? 0);
123
+ if (!n) throw new Error(`video decode produced no frames (${head})`);
124
+ // Aggregate decoded-RGB budget (belt over the sidecar's 1024px
125
+ // longest-edge cap): a valid low-bitrate clip must not balloon into
126
+ // gigabytes of frame buffers before preprocessing.
127
+ const w = Number(/W (\d+)/.exec(head)?.[1] ?? 0);
128
+ const hh = Number(/H (\d+)/.exec(head)?.[1] ?? 0);
129
+ const DECODED_BUDGET = 1536 * 1024 * 1024; // 1.5 GiB
130
+ if (n * w * hh * 3 > DECODED_BUDGET)
131
+ throw new Error(
132
+ `video decodes to ${(n * w * hh * 3 / 1024 / 1024).toFixed(0)} MB of ` +
133
+ `frames (${n} × ${w}x${hh}) — over the ${DECODED_BUDGET / 1024 / 1024} MB ` +
134
+ `budget; send a shorter or smaller clip`,
135
+ );
136
+ const frames: RGBImage[] = [];
137
+ for (let i = 0; i < n; i++) {
138
+ const f = join(outDir, `frame-${String(i).padStart(4, "0")}.png`);
139
+ frames.push(await decodeImage(new Uint8Array(await Bun.file(f).arrayBuffer())));
140
+ }
141
+ return frames;
142
+ } finally {
143
+ await Promise.allSettled([
144
+ rm(inPath, { force: true }),
145
+ rm(outDir, { recursive: true, force: true }),
146
+ ]);
147
+ }
148
+ }
package/src/web/app.html CHANGED
@@ -1216,7 +1216,7 @@
1216
1216
  <!-- PWA installability (plan §9 Phase 3, beat-matrix Axis 10): manifest +
1217
1217
  inline SVG icon (src/web/manifest.webmanifest, src/web/icon.svg — no
1218
1218
  binary PNGs, per the hygiene gate; some browsers won't render an SVG
1219
- app icon and that's an accepted tradeoff, see features-matrix.md).
1219
+ app icon and that's an accepted tradeoff, see docs/reference/server-config.md).
1220
1220
  theme-color matches the app's --bg token so the OS chrome doesn't
1221
1221
  flash a mismatched color on launch. -->
1222
1222
  <link rel="manifest" href="/manifest.webmanifest">
package/src/web/app.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // GENERATED — do not edit by hand.
2
2
  // Source: src/web/src/*.ts (entrypoint main.ts). To regenerate:
3
3
  // bun scripts/build-web.ts
4
- // tests/web-build.test.ts enforces that this file matches the source.
4
+ // tests/using/web-build.test.ts enforces that this file matches the source.
5
5
  // src/web/src/api.ts
6
6
  async function api(path, opts) {
7
7
  const { body, ...rest } = opts || {};
@@ -2892,11 +2892,13 @@ function initMemoryPanel() {
2892
2892
  maybeShowConsentCard();
2893
2893
  }
2894
2894
 
2895
+ // src/contracts/pi.ts
2896
+ var APP_ROUTE_IDS = ["chat", "quantize", "finetune", "dataset", "status"];
2897
+
2895
2898
  // src/web/src/ui-catalog.ts
2896
- var ROUTE_IDS = ["chat", "quantize", "finetune", "dataset", "status"];
2897
2899
  var VIEW_IDS = ["memory-panel", "hub-panel", "settings", "adapters-panel"];
2898
2900
  function isRouteId(v) {
2899
- return ROUTE_IDS.includes(v);
2901
+ return APP_ROUTE_IDS.includes(v);
2900
2902
  }
2901
2903
  function isViewId(v) {
2902
2904
  return VIEW_IDS.includes(v);
@@ -3496,15 +3498,21 @@ function createChatController() {
3496
3498
  t0: performance.now(),
3497
3499
  tFirst: 0,
3498
3500
  tokens: 0,
3501
+ settled: false,
3499
3502
  blockState: { blocks: [] },
3500
3503
  scheduleText: () => {},
3501
3504
  scheduleThinking: () => {},
3502
3505
  citations: pendingCitations
3503
3506
  };
3504
3507
  pendingCitations = [];
3505
- curAssistant.scheduleText = makeFrameScheduler(() => renderBlocksIncremental(curAssistant.textNode, curAssistant.text, curAssistant.blockState), atBottom, stick);
3506
- curAssistant.scheduleThinking = makeFrameScheduler(() => {
3507
- curAssistant.thinkBody.textContent = curAssistant.thinking;
3508
+ const assistant = curAssistant;
3509
+ assistant.scheduleText = makeFrameScheduler(() => {
3510
+ if (!assistant.settled)
3511
+ renderBlocksIncremental(assistant.textNode, assistant.text, assistant.blockState);
3512
+ }, atBottom, stick);
3513
+ assistant.scheduleThinking = makeFrameScheduler(() => {
3514
+ if (!assistant.settled)
3515
+ assistant.thinkBody.textContent = assistant.thinking;
3508
3516
  }, atBottom, stick);
3509
3517
  stick(true);
3510
3518
  }
@@ -3670,6 +3678,7 @@ function createChatController() {
3670
3678
  function finishStreaming(a) {
3671
3679
  if (!a)
3672
3680
  return;
3681
+ a.settled = true;
3673
3682
  const previewIdx = captureCanvasViewStates(a.textNode);
3674
3683
  a.textNode.innerHTML = mdToHtml(a.text);
3675
3684
  restoreCanvasViewStates(a.textNode, previewIdx);
@@ -9,9 +9,9 @@
9
9
  // docs/reference/server-api.md), with compatible-graying and a why-not
10
10
  // tooltip. Actions: mount, select, unselect, and stack two compatible
11
11
  // adapters as "a+b" — resolveSpec/injectAdapter already support composite
12
- // ids end to end (proved in tests/pi-web.test.ts's stacking test; the
12
+ // ids end to end (proved in tests/research/pi-web.test.ts's stacking test; the
13
13
  // shape-validated mount is proved against real weights in the
14
- // MLX_BUN_TEST_LORA=1-gated tests/lora.test.ts).
14
+ // MLX_BUN_TEST_LORA=1-gated tests/parity/lora.test.ts).
15
15
  //
16
16
  // Single source of SELECTION state, not a single fetch: composer.ts's quick
17
17
  // <select> and this table each hit /v1/adapters(+/available) independently
@@ -158,7 +158,7 @@ export function renderAdapterRow(
158
158
  }
159
159
 
160
160
  /** Full table body: a stack-mode toggle + composed-spec bar (when picks
161
- * exist), then one section of rows. Exported so tests/web-app.test.ts can
161
+ * exist), then one section of rows. Exported so tests/using/web-app.test.ts can
162
162
  * exercise esc() discipline without a live DOM/network. */
163
163
  export function renderAdaptersBodyHtml(state: AdaptersPanelState): string {
164
164
  if (!state.available.length) {
@@ -1,3 +1,5 @@
1
+ import type { UiSnapshotElement, UiSnapshot, WizardStep } from "../../contracts/pi";
2
+ export type { UiSnapshotElement, UiSnapshot, WizardStep } from "../../contracts/pi";
1
3
  // GENERATED-ADJACENT source module — part of the src/web/src/* split (plan
2
4
  // §6.6 "the app-aware assistant", §9 Phase 3, beat matrix Axis 12). Built
3
5
  // into src/web/app.js by scripts/build-web.ts.
@@ -26,42 +28,6 @@
26
28
 
27
29
  import { getSpotlightTarget, isViewId, ROUTE_LABELS, type RouteId, type ViewId } from "./ui-catalog";
28
30
 
29
- /* ────────────────────────────────────────────────────────────────────
30
- 1. SEE — the structured DOM snapshot
31
- ──────────────────────────────────────────────────────────────────── */
32
-
33
- export interface UiSnapshotElement {
34
- ref: string;
35
- tag: string;
36
- label: string;
37
- kind: "interactive" | "region";
38
- role?: string;
39
- selector: string;
40
- spotlightId?: string;
41
- }
42
-
43
- export interface UiSnapshot {
44
- route: string;
45
- capturedAt: string;
46
- elements: UiSnapshotElement[];
47
- }
48
-
49
- /** Process-state fields layered onto the snapshot (§6.6 "the snapshot
50
- * carries process state, not just elements") — wizard step for the
51
- * quantize/finetune/dataset wizards, when the current route has one.
52
- * Derived by reading the DOM the step indicator already renders
53
- * (markdown.ts's renderSteps into #q-steps/#f-steps/#d-steps + the
54
- * [data-qstep]/[data-fstep]/[data-dstep] visibility toggle quantize.ts/
55
- * finetune.ts/dataset.ts already do) rather than adding a callback hook to
56
- * those three controllers — zero behavior change to files outside this
57
- * wave's scope, and the DOM IS the source of truth those controllers
58
- * already write to. */
59
- export interface WizardStep {
60
- index: number;
61
- count: number;
62
- label: string;
63
- }
64
-
65
31
  const STEP_CONTAINER_BY_ROUTE: Partial<Record<RouteId, string>> = {
66
32
  quantize: "q-steps",
67
33
  finetune: "f-steps",
@@ -10,15 +10,15 @@
10
10
  // typed, checkable seams between these concerns).
11
11
  //
12
12
  // Typed WS contract (plan §9 Phase 2 item 2): ClientMessage/ServerMessage
13
- // and the history/session shapes are imported TYPE-ONLY from ../../pi-web
13
+ // and the history/session shapes are imported TYPE-ONLY from ../../contracts/pi
14
14
  // so this module (and the whole bundle) contains zero server code — the
15
15
  // bundler errors on bun:ffi if a value import ever sneaks in here, which is
16
16
  // the intended guard (see scripts/build-web.ts).
17
17
 
18
18
  import type {
19
19
  ClientMessage, HistoryItem, ReadyGenDefaults, ServerMessage, SessionListItem,
20
- } from "../../pi-web";
21
- import type { Lane } from "../../serve/lane-registry";
20
+ } from "../../contracts/pi";
21
+ import type { Lane } from "../../contracts/pi";
22
22
  import {
23
23
  $, el, toast, currentRoute, closeDrawer,
24
24
  storedCodingToolsPreference, renderCodingToolsState, renderToolApprovals,
@@ -44,7 +44,7 @@ import { isRouteId } from "./ui-catalog";
44
44
 
45
45
  /* ────────────────────────────────────────────────────────────────────
46
46
  Chat-with-files RAG v1 — Sources panel (plan §9 Phase 3, beat matrix
47
- Axis 5). Pure HTML builder so tests/web-app.test.ts can exercise the
47
+ Axis 5). Pure HTML builder so tests/using/web-app.test.ts can exercise the
48
48
  esc() discipline directly, same reasoning as renderAdapterOptionsHtml
49
49
  etc. in composer.ts.
50
50
  ──────────────────────────────────────────────────────────────────── */
@@ -142,6 +142,7 @@ interface AssistantMsgState {
142
142
  t0: number;
143
143
  tFirst: number;
144
144
  tokens: number;
145
+ settled: boolean;
145
146
  blockState: BlockState;
146
147
  scheduleText: () => void;
147
148
  scheduleThinking: () => void;
@@ -373,7 +374,7 @@ export function createChatController() {
373
374
  const meta = el("div", "meta", m);
374
375
  curAssistant = {
375
376
  m, bubble, thinkBox, thinkBody, textNode, cursor, meta, tools: new Map(),
376
- text: "", thinking: "", t0: performance.now(), tFirst: 0, tokens: 0,
377
+ text: "", thinking: "", t0: performance.now(), tFirst: 0, tokens: 0, settled: false,
377
378
  // Block-memoization state (see renderBlocksIncremental) for the main
378
379
  // markdown text stream, plus a shared rAF scheduler so a burst of
379
380
  // deltas within one frame (e.g. spec-decode emitting several tokens
@@ -390,11 +391,16 @@ export function createChatController() {
390
391
  // Consumed — a later turn with no RAG'd attachments must not inherit
391
392
  // this turn's citation set (see the pendingCitations declaration above).
392
393
  pendingCitations = [];
393
- curAssistant.scheduleText = makeFrameScheduler(
394
- () => renderBlocksIncremental(curAssistant!.textNode, curAssistant!.text, curAssistant!.blockState),
394
+ const assistant = curAssistant;
395
+ assistant.scheduleText = makeFrameScheduler(
396
+ () => {
397
+ if (!assistant.settled) renderBlocksIncremental(assistant.textNode, assistant.text, assistant.blockState);
398
+ },
395
399
  atBottom, stick);
396
- curAssistant.scheduleThinking = makeFrameScheduler(
397
- () => { curAssistant!.thinkBody.textContent = curAssistant!.thinking; },
400
+ assistant.scheduleThinking = makeFrameScheduler(
401
+ () => {
402
+ if (!assistant.settled) assistant.thinkBody.textContent = assistant.thinking;
403
+ },
398
404
  atBottom, stick);
399
405
  stick(true);
400
406
  }
@@ -612,6 +618,7 @@ export function createChatController() {
612
618
  * directly on the full string. */
613
619
  function finishStreaming(a: AssistantMsgState | null): void {
614
620
  if (!a) return;
621
+ a.settled = true;
615
622
  // Preserve any Canvas Preview toggle the user made mid-stream (Principle
616
623
  // 9: this full non-memoized re-render must not throw away user
617
624
  // interaction state) — mdCodeBlock always emits qualifying fences back
@@ -10,8 +10,8 @@
10
10
  // the original single IIFE), but every WS send goes through a callback
11
11
  // passed in from chat.ts, which owns the actual WebSocket.
12
12
 
13
- import type { ReadyGenDefaults, SamplingOverrides } from "../../pi-web";
14
- import type { Lane } from "../../serve/lane-registry";
13
+ import type { ReadyGenDefaults, SamplingOverrides } from "../../contracts/pi";
14
+ import type { Lane } from "../../contracts/pi";
15
15
  import { api } from "./api";
16
16
  import type { ApiEnvelope } from "./protocol";
17
17
  import {
@@ -200,7 +200,7 @@ function escHtml(s: unknown): string {
200
200
 
201
201
  /** Pure: builds the <option> markup for the adapter <select> from the
202
202
  * /v1/adapters/available list. Split out from refreshAdapters() (which
203
- * does the fetch + DOM write) so tests/web-app.test.ts can exercise the
203
+ * does the fetch + DOM write) so tests/using/web-app.test.ts can exercise the
204
204
  * esc() discipline on this template directly without a DOM or network —
205
205
  * every interpolated field (id, rank, path, base_model) must be escaped,
206
206
  * since adapter ids/paths are user-controlled (on-disk directory names). */
@@ -719,7 +719,7 @@ export function renderLane(lane: Lane | undefined): void {
719
719
  already resolves, so the agent's memory tools pick it up naturally, same
720
720
  as in the vault's own prose). No vault -> files-only picker. Pure
721
721
  query-detection/insertion helpers below are unit-tested directly
722
- (tests/web-app.test.ts); DOM wiring (initMentionPicker) owns the
722
+ (tests/using/web-app.test.ts); DOM wiring (initMentionPicker) owns the
723
723
  picker's open/close/keyboard-nav state.
724
724
  ──────────────────────────────────────────────────────────────────── */
725
725
 
@@ -119,7 +119,7 @@ function localRowHtml(m: HubLocalRow): string {
119
119
  }
120
120
 
121
121
  /** Pure render, exported for esc()-discipline + empty-state tests
122
- * (tests/web-app.test.ts, mirroring renderModelPopBodyHtml's pattern). */
122
+ * (tests/using/web-app.test.ts, mirroring renderModelPopBodyHtml's pattern). */
123
123
  export function renderHubLocalHtml(models: HubLocalRow[]): string {
124
124
  if (!models.length) {
125
125
  return '<div class="hub-empty">No models downloaded yet — search Hugging Face below to get one.</div>';
Binary file
@@ -394,7 +394,7 @@ export async function refreshSidebarEntry(): Promise<void> {
394
394
  // by a literal list rather than an import: this module must stay
395
395
  // server-code-free (bundler-enforced, see chat.ts's header comment), so it
396
396
  // can't import a value from src/memory/tools.ts even though the identifiers
397
- // are the same. tests/web-app.test.ts cross-checks this list against the
397
+ // are the same. tests/using/web-app.test.ts cross-checks this list against the
398
398
  // real export so drift is caught at test time instead of silently.
399
399
  export const MEMORY_CHIP_TOOL_NAMES = [
400
400
  "memory_resolve", "memory_category", "memory_read", "memory_section",
@@ -85,7 +85,7 @@ function renderRow(m: LibraryRow): string {
85
85
  }
86
86
 
87
87
  /** Pure render of the popover body from a /library response. Exported for
88
- * tests/web-app.test.ts's esc() discipline check (repo ids are
88
+ * tests/using/web-app.test.ts's esc() discipline check (repo ids are
89
89
  * user-controlled HF strings — the same class of interpolation hazard
90
90
  * finding #15 flagged for the adapter dropdown). */
91
91
  export function renderModelPopBodyHtml(models: LibraryRow[]): string {
@@ -39,7 +39,7 @@ interface PaletteAction {
39
39
  }
40
40
 
41
41
  /** Pure: the static action list, independent of any live session data —
42
- * independently testable (tests/web-app.test.ts asserts labels/ids without
42
+ * independently testable (tests/using/web-app.test.ts asserts labels/ids without
43
43
  * needing a DOM). Session rows and message-search hits are appended
44
44
  * dynamically in refreshResults() below, not part of this list. */
45
45
  export function staticActions(): PaletteAction[] {
@@ -1,47 +1,11 @@
1
- // Shared frontend-only protocol shapes that don't already live on the
2
- // server side as exported types. The WS contract itself (ClientMessage /
3
- // ServerMessage / HistoryItem / SessionListItem / ReadyGenDefaults) is
4
- // imported type-only from ../../pi-web — see chat.ts. This file only holds
5
- // shapes with no server-side export to anchor to (e.g. the SSE job-stream
6
- // events, which live as a doc-comment in app.html today, not a type).
7
- //
8
- // Pointer comment for the server side: src/web/src/protocol.ts mirrors the
9
- // SSE line protocol documented at the jobStream() call site (api.ts) —
10
- // keep the two adjacent if the job event shape changes server-side
11
- // (scripts/ that emit `data:` lines for /api/jobs/:id/stream).
12
-
13
- /** One line of the /api/jobs/:id/stream SSE protocol (JSON per `data:` line). */
14
- export type JobEvent =
15
- | { type: "log"; line: string }
16
- | {
17
- type: "stage";
18
- stage: string;
19
- progress?: number;
20
- message?: string;
21
- output_dir?: string;
22
- adapter_path?: string;
23
- // Dataset-generation-specific row counts (present on the dataset
24
- // builder's job stream only; absent/ignored for quantize/finetune).
25
- n_train?: number;
26
- n_valid?: number;
27
- }
28
- | {
29
- type: "metric";
30
- kind: "train" | "val";
31
- step: number;
32
- loss: number;
33
- learning_rate?: number;
34
- tokens_per_sec?: number;
35
- progress?: number;
36
- message?: string;
37
- }
38
- | { type: "done"; n_train?: number; n_valid?: number }
39
- | { type: "failed"; error?: string };
1
+ import type { JobEvent } from "../../contracts/jobs";
2
+ export type { JobEvent } from "../../contracts/jobs";
40
3
 
41
4
  /** Handlers passed to jobStream(); each key is an optional callback for the
42
5
  * matching JobEvent variant, plus an `error` callback for the EventSource's
43
6
  * own onerror (transport failure, not a `failed` protocol event). */
44
7
  export interface JobStreamHandlers {
8
+ started?: (e: Extract<JobEvent, { type: "started" }>) => void;
45
9
  log?: (e: Extract<JobEvent, { type: "log" }>) => void;
46
10
  stage?: (e: Extract<JobEvent, { type: "stage" }>) => void;
47
11
  metric?: (e: Extract<JobEvent, { type: "metric" }>) => void;
@@ -20,7 +20,7 @@
20
20
  // wires each rendered `.sess` row's click to `onOpen` below — this just
21
21
  // finds and clicks the right row instead of duplicating that send()).
22
22
 
23
- import type { SessionListItem } from "../../pi-web";
23
+ import type { SessionListItem } from "../../contracts/pi";
24
24
  import { $, el, injectStyles } from "./shell";
25
25
  import { api } from "./api";
26
26
 
@@ -2,28 +2,14 @@
2
2
  // §7/§9 Phase 3, §6.6 "app-aware assistant"). Built into src/web/app.js by
3
3
  // scripts/build-web.ts.
4
4
  //
5
- // The frontend half of the app-aware assistant's route/spotlight catalog.
6
- // Mirrors PortfolioManager's ui-catalog.json pattern (client/src/lib/
7
- // ui-catalog.ts + server/src/agent/ui-catalog.ts, read together with
8
- // server/src/agent/portfolio-tools.ts as the reference implementation) but
9
- // inlined as a TS module (not a shared JSON file) since mlx-bun's server and
10
- // browser bundles are separate build outputs (scripts/build-web.ts vs bun's
11
- // own TS execution) with no shared-JSON-import convention today — pi-web.ts
12
- // mirrors ROUTE_IDS/SPOTLIGHT_TARGETS as plain string arrays for its own
13
- // server-side validation (navigate_app/spotlight_ui reject anything not in
14
- // that list BEFORE touching the browser) so route validity is checked at
15
- // both ends without a build-time shared asset.
16
- //
17
- // Keep this list's ROUTE_IDS in sync with shell.ts's ROUTES tuple (chat,
18
- // quantize, finetune, dataset, status) plus the Developer-only overlays that
19
- // aren't hash-routes (memory panel, hub panel, settings) — those are
20
- // `view`s, not `route`s (see UiContext.view below), reached by opening an
21
- // overlay rather than changing the URL hash.
5
+ // Shared route IDs keep browser navigation and server validation in agreement.
6
+ // Spotlight selectors and overlay IDs belong to the browser.
22
7
 
23
8
  /** A hash-routed page (shell.ts's Route union, minus "routes" — the DAG
24
9
  * diagram tab isn't a useful assistant destination and is itself
25
10
  * feature-detected/hidden when unavailable). */
26
- export const ROUTE_IDS = ["chat", "quantize", "finetune", "dataset", "status"] as const;
11
+ import { APP_ROUTE_IDS as ROUTE_IDS } from "../../contracts/pi";
12
+ export { ROUTE_IDS };
27
13
  export type RouteId = (typeof ROUTE_IDS)[number];
28
14
 
29
15
  /** A non-route overlay/panel the assistant can navigate to or spotlight
@@ -0,0 +1,47 @@
1
+ // Embedded web app — the unified SPA (chat / quantize / finetune /
2
+ // dataset / status). `with { type: "text" }` inlines the file in both
3
+ // `bun run` and the compiled single binary. bun-types types *.html
4
+ // imports as HTMLBundle (the html loader), but the text attribute makes
5
+ // the runtime value a string — hence the double cast.
6
+ import appHtml from "./web/app.html" with { type: "text" };
7
+ import curveDesignerHtml from "./lab/curve/curve-designer.html" with { type: "text" };
8
+ // Vendored, no-CDN static assets referenced by app.html (convention: any
9
+ // self-contained JS/CSS too big to inline gets `with { type: "text" }`
10
+ // imported here and served under /assets/<name>; see src/web/vendor/README
11
+ // for how hljs.js was built). Add new vendored assets the same way.
12
+ import hljsJs from "./web/vendor/hljs.js" with { type: "text" };
13
+ import hljsCss from "./web/vendor/hljs-theme.css" with { type: "text" };
14
+ // The frontend bundle (plan §7/§9 Phase 2 module split): GENERATED from
15
+ // src/web/src/*.ts by `bun scripts/build-web.ts` — see that file's header
16
+ // and tests/using/web-build.test.ts (the freshness gate). Same
17
+ // with { type: "text" } + /assets/<name> pattern as the vendored assets
18
+ // above; app.html's <script defer src="/assets/app.js"> loads it.
19
+ import appJs from "./web/app.js" with { type: "text" };
20
+ // PWA installability (plan §9 Phase 3, beat-matrix Axis 10): a manifest +
21
+ // a single inline SVG icon (no binary PNGs — the hygiene gate forbids
22
+ // tracked binary files; some browsers won't show an SVG app icon, which is
23
+ // an accepted tradeoff, see docs/reference/server-config.md) + a shell-
24
+ // only service worker. Same with { type: "text" } + /assets/<name>-shaped
25
+ // pattern as the vendored assets above; see src/web/sw.js's header for why
26
+ // it deliberately does NOT cache API/WS traffic.
27
+ import manifestWebmanifest from "./web/manifest.webmanifest" with { type: "text" };
28
+ import iconSvg from "./web/icon.svg" with { type: "text" };
29
+ import swJs from "./web/sw.js" with { type: "text" };
30
+ const APP_PAGE = appHtml as unknown as string;
31
+ const HLJS_JS = hljsJs as unknown as string;
32
+ const HLJS_CSS = hljsCss as unknown as string;
33
+ const APP_JS = appJs as unknown as string;
34
+ const MANIFEST_WEBMANIFEST = manifestWebmanifest as unknown as string;
35
+ const ICON_SVG = iconSvg as unknown as string;
36
+ const SW_JS = swJs as unknown as string;
37
+ const CURVE_PAGE = curveDesignerHtml as unknown as string;
38
+ export const STATIC_ROUTE_ASSETS = {
39
+ appPage: APP_PAGE,
40
+ appJs: APP_JS,
41
+ hljsJs: HLJS_JS,
42
+ hljsCss: HLJS_CSS,
43
+ manifest: MANIFEST_WEBMANIFEST,
44
+ iconSvg: ICON_SVG,
45
+ serviceWorker: SW_JS,
46
+ curvePage: CURVE_PAGE,
47
+ };