mlx-bun 0.4.0 → 1.0.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 (601) hide show
  1. package/README.md +1453 -88
  2. package/THIRD_PARTY_NOTICES.md +882 -0
  3. package/bin/mlx-bun.convert.mjs +4 -0
  4. package/bin/mlx-bun.fuse.mjs +4 -0
  5. package/bin/mlx-bun.generate.mjs +4 -0
  6. package/bin/mlx-bun.lora.mjs +4 -0
  7. package/bin/mlx-bun.mjs +13 -21
  8. package/bin/mlx-bun.server.mjs +4 -0
  9. package/bin/mlx-bun.upload.mjs +4 -0
  10. package/dist/web/app.js +9584 -0
  11. package/package.json +50 -53
  12. package/src/cli/ane-install.ts +76 -0
  13. package/src/cli/args.ts +179 -0
  14. package/src/cli/engine-entry.ts +68 -0
  15. package/src/cli/inference.ts +214 -0
  16. package/src/cli/job-entry.ts +97 -0
  17. package/src/cli/library-host.ts +117 -0
  18. package/src/cli/main.ts +57 -0
  19. package/src/cli/memory-engine.ts +163 -0
  20. package/src/cli/memory.ts +36 -0
  21. package/src/cli/mlx-lm-aliases.ts +309 -0
  22. package/src/cli/model-choice.ts +33 -0
  23. package/src/cli/model-selection.ts +84 -0
  24. package/src/cli/module-host.ts +11 -0
  25. package/src/cli/module-verbs.ts +50 -0
  26. package/src/cli/numerical-policy.ts +12 -0
  27. package/src/cli/perplexity.ts +89 -0
  28. package/src/cli/serve-host.ts +423 -0
  29. package/src/cli/serve-isolated.ts +217 -0
  30. package/src/cli/serve-options.ts +106 -0
  31. package/src/cli/serve-state.ts +205 -0
  32. package/src/cli/serve.ts +500 -0
  33. package/src/cli/served-model-host.ts +102 -0
  34. package/src/cli/server-entry.ts +148 -0
  35. package/src/cli/serving-unit.ts +177 -0
  36. package/src/{tui.ts → cli/terminal.ts} +13 -8
  37. package/src/cli/worker-adapters.ts +34 -0
  38. package/src/cli/worker-entry.ts +272 -0
  39. package/src/cli/worker-unit.ts +179 -0
  40. package/src/engine/adapter-operation.ts +26 -0
  41. package/src/engine/cache-services.ts +114 -0
  42. package/src/engine/completion.ts +39 -0
  43. package/src/engine/generation-gateway.ts +358 -0
  44. package/src/engine/index.ts +59 -0
  45. package/src/engine/kv-budget.ts +120 -0
  46. package/src/engine/media-preparation.ts +232 -0
  47. package/src/engine/model-binding.ts +24 -0
  48. package/src/engine/model-host.ts +513 -0
  49. package/src/engine/model-serving.ts +89 -0
  50. package/src/{serve → engine}/preparation.ts +10 -8
  51. package/src/{serve → engine}/session-completion-engine.ts +6 -6
  52. package/src/engine/telemetry.ts +109 -0
  53. package/src/hub/downloads.ts +116 -0
  54. package/src/jobs/db.ts +16 -7
  55. package/src/jobs/events.ts +29 -0
  56. package/src/jobs/executable.ts +5 -0
  57. package/src/jobs/host.ts +51 -0
  58. package/src/jobs/in-process.ts +55 -0
  59. package/src/{contracts/jobs.ts → jobs/protocol.ts} +7 -9
  60. package/src/jobs/runner.ts +150 -231
  61. package/src/jobs/service.ts +75 -0
  62. package/src/jobs/sse.ts +59 -23
  63. package/src/jobs/worker-memory.ts +46 -0
  64. package/src/jobs/worker-process.ts +163 -0
  65. package/src/jobs/worker-supervisor.ts +258 -0
  66. package/src/modules.ts +58 -0
  67. package/src/publishing/catalog-hub.ts +18 -0
  68. package/src/publishing/credentials.ts +31 -0
  69. package/src/publishing/upload.ts +37 -0
  70. package/src/residency/leased-adapters.ts +21 -0
  71. package/src/residency/local-records.ts +16 -0
  72. package/src/residency/model-residency.ts +405 -0
  73. package/src/residency/record-index.ts +28 -0
  74. package/src/residency/resident-estimate.ts +50 -0
  75. package/src/{anthropic.ts → server/anthropic.ts} +3 -81
  76. package/src/server/cache-routes.ts +36 -0
  77. package/src/{serve → server}/chat-request.ts +12 -10
  78. package/src/{serve → server}/chat-stage.ts +27 -22
  79. package/src/{client.ts → server/client.ts} +28 -2
  80. package/src/{serve → server}/completion-executor.ts +42 -42
  81. package/src/server/decision-body.ts +55 -0
  82. package/src/server/decision-routes.ts +134 -0
  83. package/src/server/decision-wire.ts +228 -0
  84. package/src/{serve → server}/discovery-routes.ts +42 -83
  85. package/src/server/generated-token-history.ts +57 -0
  86. package/src/{serve → server}/http.ts +25 -13
  87. package/src/{serve → server}/inference-request.ts +5 -5
  88. package/src/server/job-routes.ts +20 -0
  89. package/src/server/media-prompt.ts +63 -0
  90. package/src/server/memory-completion-client.ts +46 -0
  91. package/src/server/model-routes.ts +192 -0
  92. package/src/{serve → server}/openai-wire.ts +3 -2
  93. package/src/{serve → server}/pipeline.ts +1 -1
  94. package/src/server/prompt-builder.ts +13 -0
  95. package/src/server/prompt-contracts.ts +17 -0
  96. package/src/server/proxy-routes.ts +187 -0
  97. package/src/server/publishing-routes.ts +41 -0
  98. package/src/{serve → server}/request-plan.ts +8 -8
  99. package/src/{serve → server}/request-prep.ts +82 -68
  100. package/src/{serve → server}/responses-client.ts +30 -13
  101. package/src/{responses.ts → server/responses.ts} +12 -93
  102. package/src/server/routes.ts +205 -0
  103. package/src/server/start.ts +72 -0
  104. package/src/server/status-routes.ts +108 -0
  105. package/src/{serve → server}/text-completion-stage.ts +25 -4
  106. package/src/server/text-prompt.ts +12 -0
  107. package/src/{serve → server}/token-streams.ts +36 -38
  108. package/src/server/worker-routes.ts +311 -0
  109. package/src/storage/paths.ts +61 -0
  110. package/src/web/assets.ts +37 -0
  111. package/src/web/{src → browser}/api.ts +5 -23
  112. package/src/web/browser/chat-host.ts +17 -0
  113. package/src/web/browser/installed-panels.ts +6 -0
  114. package/src/web/browser/main.ts +55 -0
  115. package/src/web/browser/markdown.ts +279 -0
  116. package/src/web/browser/memory-panel.ts +9 -0
  117. package/src/web/browser/palette.ts +64 -0
  118. package/src/web/browser/protocol.ts +13 -0
  119. package/src/web/browser/shell.ts +467 -0
  120. package/src/web/{src → browser}/status.ts +32 -36
  121. package/src/web/build.ts +51 -0
  122. package/src/web/public/app.html +1054 -0
  123. package/src/web/{sw.js → public/sw.js} +4 -3
  124. package/src/web/{vendor → public/vendor}/hljs-theme.css +2 -2
  125. package/src/web/{vendor → public/vendor}/hljs.js +2 -2
  126. package/THIRD_PARTY_LICENSES.md +0 -51
  127. package/docs/README.md +0 -94
  128. package/docs/archive/hlg-sampling.md +0 -350
  129. package/docs/archive/investigations/audio-input-plan.md +0 -356
  130. package/docs/archive/investigations/chunk-finetune-experiment.md +0 -84
  131. package/docs/archive/investigations/colibri-glm52-port.md +0 -1486
  132. package/docs/archive/investigations/colibri-oracle-pin.md +0 -1284
  133. package/docs/archive/investigations/curve-bisector-routing.md +0 -123
  134. package/docs/archive/investigations/decode-roofline-lookagain.md +0 -348
  135. package/docs/archive/investigations/diffusion-gemma-port.md +0 -602
  136. package/docs/archive/investigations/dspark-handoff.md +0 -224
  137. package/docs/archive/investigations/expert-offload-single-user-moe.md +0 -292
  138. package/docs/archive/investigations/faithful-l1-consolidation.md +0 -310
  139. package/docs/archive/investigations/hlg-sampling-investigation.md +0 -970
  140. package/docs/archive/investigations/indexshare-performance-spike.md +0 -357
  141. package/docs/archive/investigations/kernel-perf-review-2026-07.md +0 -171
  142. package/docs/archive/investigations/lab-build-journal.md +0 -157
  143. package/docs/archive/investigations/minicpm5-decode-megakernel.md +0 -489
  144. package/docs/archive/investigations/openjarvis-fit.md +0 -198
  145. package/docs/archive/investigations/openwiki-evaluation.md +0 -249
  146. package/docs/archive/investigations/optimization_plan.md +0 -346
  147. package/docs/archive/investigations/orpo-base-uf-experiment-and-directions.md +0 -120
  148. package/docs/archive/investigations/orpo-flash-cce-pin-leak.md +0 -167
  149. package/docs/archive/investigations/orpo-uf-testing-handoff.md +0 -126
  150. package/docs/archive/investigations/pareto-specialized-runtime-findings.md +0 -92
  151. package/docs/archive/investigations/pi-builtin-investigation.md +0 -308
  152. package/docs/archive/investigations/pre-colibri-stabilization.md +0 -329
  153. package/docs/archive/investigations/qwen38-27b-campaign-log.md +0 -1092
  154. package/docs/archive/investigations/segmented-backward-handoff.md +0 -148
  155. package/docs/archive/investigations/starter-model-port-handoff.md +0 -342
  156. package/docs/archive/investigations/steel-flash-cce-handoff.md +0 -489
  157. package/docs/archive/investigations/the-dreaming-handoff.md +0 -141
  158. package/docs/archive/investigations/trainer-validation-experiment.md +0 -173
  159. package/docs/archive/planning/chat-ui-vision-memory-first.md +0 -199
  160. package/docs/archive/planning/chat-ui-vision.md +0 -50
  161. package/docs/archive/planning/chunk-task-roadmap.md +0 -77
  162. package/docs/archive/planning/curve-sampler-research-plan.md +0 -331
  163. package/docs/archive/planning/journal.md +0 -316
  164. package/docs/archive/planning/memory-docs-and-dag-plan.md +0 -194
  165. package/docs/archive/planning/pi-integration-review.md +0 -178
  166. package/docs/archive/planning/release-notes-v0.0.10.md +0 -57
  167. package/docs/archive/planning/release-notes-v0.0.11.md +0 -239
  168. package/docs/archive/planning/release-notes-v0.0.12.md +0 -80
  169. package/docs/archive/planning/release-notes-v0.0.13.md +0 -77
  170. package/docs/archive/planning/release-notes-v0.0.9.md +0 -122
  171. package/docs/archive/planning/release-notes-v0.2.0.md +0 -49
  172. package/docs/archive/planning/release-notes-v0.3.0.md +0 -35
  173. package/docs/archive/planning/web-ui-pass-plan.md +0 -213
  174. package/docs/archive/planning/website-readme-pass-plan.md +0 -224
  175. package/docs/design/batching.md +0 -1841
  176. package/docs/design/decode-speed-program.md +0 -2349
  177. package/docs/design/dreaming-nightly-pipeline.md +0 -684
  178. package/docs/design/generic-model-support.md +0 -705
  179. package/docs/design/kv-cache.md +0 -824
  180. package/docs/design/orpo-training.md +0 -680
  181. package/docs/design/speculative-decoding.md +0 -1990
  182. package/docs/design/turboquant.md +0 -2212
  183. package/docs/design/unified-engine-frontier-plan.md +0 -1880
  184. package/docs/design/web-chat-redesign.md +0 -695
  185. package/docs/planning/PRODUCT_ROADMAP.md +0 -594
  186. package/docs/planning/ResearchTopics.md +0 -119
  187. package/docs/planning/release-notes-v0.4.0.md +0 -45
  188. package/docs/planning/video-series.md +0 -421
  189. package/docs/reference/benchmarks.md +0 -3613
  190. package/docs/reference/cli.md +0 -585
  191. package/docs/reference/distribution.md +0 -355
  192. package/docs/reference/environment.md +0 -398
  193. package/docs/reference/glossary.md +0 -39
  194. package/docs/reference/library-api.md +0 -674
  195. package/docs/reference/memory.md +0 -260
  196. package/docs/reference/models.md +0 -334
  197. package/docs/reference/server-api.md +0 -1775
  198. package/docs/reference/server-config.md +0 -846
  199. package/docs/reference/training.md +0 -462
  200. package/docs/reference/troubleshooting.md +0 -158
  201. package/src/admission-plan.ts +0 -18
  202. package/src/audio/conformer.ts +0 -647
  203. package/src/audio/decode.ts +0 -133
  204. package/src/audio/features.ts +0 -202
  205. package/src/audio/transcode.ts +0 -67
  206. package/src/backends/mlx/assistant-target.ts +0 -46
  207. package/src/backends/mlx/autoregressive-draft-rows.ts +0 -120
  208. package/src/backends/mlx/autoregressive.ts +0 -108
  209. package/src/backends/mlx/batch-group.ts +0 -1790
  210. package/src/backends/mlx/cache-attachment.ts +0 -67
  211. package/src/backends/mlx/cache-layout.ts +0 -31
  212. package/src/backends/mlx/checkpoint-state.ts +0 -53
  213. package/src/backends/mlx/continuation-persistence.ts +0 -106
  214. package/src/backends/mlx/continuation-request.ts +0 -43
  215. package/src/backends/mlx/continuation.ts +0 -77
  216. package/src/backends/mlx/diffusion.ts +0 -39
  217. package/src/backends/mlx/draft-target.ts +0 -32
  218. package/src/backends/mlx/evaluation.ts +0 -105
  219. package/src/backends/mlx/fill-append.ts +0 -45
  220. package/src/backends/mlx/full-kv-row-append.ts +0 -32
  221. package/src/backends/mlx/full-kv-row-donor.ts +0 -54
  222. package/src/backends/mlx/full-transitioning-kv-rows.ts +0 -65
  223. package/src/backends/mlx/gateway-binding.ts +0 -130
  224. package/src/backends/mlx/graph.ts +0 -38
  225. package/src/backends/mlx/kv-codec.ts +0 -9
  226. package/src/backends/mlx/kv-maintenance.ts +0 -133
  227. package/src/backends/mlx/kv-tensor-rows.ts +0 -212
  228. package/src/backends/mlx/memory-client.ts +0 -189
  229. package/src/backends/mlx/methods.ts +0 -90
  230. package/src/backends/mlx/model-prompt.ts +0 -164
  231. package/src/backends/mlx/model-serving.ts +0 -79
  232. package/src/backends/mlx/prefill-cohort.ts +0 -89
  233. package/src/backends/mlx/prefill-rows.ts +0 -200
  234. package/src/backends/mlx/prefill.ts +0 -33
  235. package/src/backends/mlx/projected-context-rows.ts +0 -72
  236. package/src/backends/mlx/request-policy.ts +0 -20
  237. package/src/backends/mlx/request-state-policy.ts +0 -41
  238. package/src/backends/mlx/rollback.ts +0 -89
  239. package/src/backends/mlx/row-sampling.ts +0 -49
  240. package/src/backends/mlx/serial-executor.ts +0 -242
  241. package/src/backends/mlx/speculative-group.ts +0 -359
  242. package/src/backends/mlx/speculative-round.ts +0 -161
  243. package/src/backends/mlx/speculative.ts +0 -114
  244. package/src/backends/mlx/state-rows.ts +0 -104
  245. package/src/backends/mlx/state-views.ts +0 -46
  246. package/src/backends/mlx/target-layout-capability.ts +0 -35
  247. package/src/backends/mlx/text-engine.ts +0 -73
  248. package/src/backends/mlx/transitioning-kv-rows.ts +0 -165
  249. package/src/chat-template.ts +0 -382
  250. package/src/cli.ts +0 -3168
  251. package/src/config.ts +0 -399
  252. package/src/contracts/completion.ts +0 -16
  253. package/src/contracts/execution.ts +0 -60
  254. package/src/contracts/generation.ts +0 -103
  255. package/src/contracts/host.ts +0 -7
  256. package/src/contracts/pi-provider.ts +0 -30
  257. package/src/contracts/pi.ts +0 -259
  258. package/src/contracts/prefix-cache.ts +0 -23
  259. package/src/contracts/resources.ts +0 -25
  260. package/src/contracts/sampling.ts +0 -23
  261. package/src/contracts/scheduling.ts +0 -45
  262. package/src/contracts/tsconfig.json +0 -14
  263. package/src/dataset/generators.ts +0 -1087
  264. package/src/dataset/index.ts +0 -12
  265. package/src/dataset/job.ts +0 -81
  266. package/src/dataset/llm.ts +0 -71
  267. package/src/dataset/registry.ts +0 -528
  268. package/src/diffusion/diffusion-generate.ts +0 -507
  269. package/src/download.ts +0 -505
  270. package/src/embed.ts +0 -77
  271. package/src/engine/admission.ts +0 -59
  272. package/src/engine/cancellation.ts +0 -38
  273. package/src/engine/engine.ts +0 -56
  274. package/src/engine/execution-coordinator.ts +0 -70
  275. package/src/engine/execution-plan.ts +0 -53
  276. package/src/engine/resources.ts +0 -53
  277. package/src/engine/scheduler.ts +0 -72
  278. package/src/engine/session.ts +0 -247
  279. package/src/eval/README.md +0 -130
  280. package/src/eval/ifeval.ts +0 -81
  281. package/src/eval/kl-prompts.ts +0 -29
  282. package/src/eval/kl.ts +0 -590
  283. package/src/eval/perplexity.ts +0 -164
  284. package/src/eval/quality-db.ts +0 -92
  285. package/src/eval/reference-logits.ts +0 -207
  286. package/src/eval/runner.ts +0 -124
  287. package/src/eval/score.ts +0 -49
  288. package/src/eval/tasks/bfcl.ts +0 -535
  289. package/src/eval/tasks/gsm8k.ts +0 -98
  290. package/src/eval/tasks/hashhop.ts +0 -139
  291. package/src/eval/tasks/humaneval.ts +0 -275
  292. package/src/eval/tasks/ifeval.ts +0 -525
  293. package/src/eval/tasks/mmlu.ts +0 -157
  294. package/src/eval/ultrafeedback.ts +0 -60
  295. package/src/evaldb.ts +0 -199
  296. package/src/expert-io.ts +0 -393
  297. package/src/expert-offload-build.ts +0 -77
  298. package/src/expert-offload.ts +0 -76
  299. package/src/expert-residency.ts +0 -1134
  300. package/src/expert-usage.ts +0 -415
  301. package/src/fill/echo-index.ts +0 -188
  302. package/src/fill/fill-session.ts +0 -452
  303. package/src/fill/proposal.ts +0 -68
  304. package/src/fill/schema-rows.ts +0 -506
  305. package/src/fill/tool-boundary.ts +0 -103
  306. package/src/fit.ts +0 -249
  307. package/src/generate.ts +0 -1346
  308. package/src/grammar.ts +0 -591
  309. package/src/harness-pi.ts +0 -184
  310. package/src/hf-push.ts +0 -628
  311. package/src/hub-rest.ts +0 -242
  312. package/src/index.ts +0 -63
  313. package/src/inference/denoising.ts +0 -17
  314. package/src/inference/draft-acceptance.ts +0 -41
  315. package/src/inference/draft-output.ts +0 -49
  316. package/src/inference/graph.ts +0 -33
  317. package/src/inference/prefill.ts +0 -39
  318. package/src/inference/rollback.ts +0 -7
  319. package/src/jobs/index.ts +0 -31
  320. package/src/jobs/job-entry.ts +0 -107
  321. package/src/jobs/task-client.ts +0 -19
  322. package/src/jobs/types.ts +0 -2
  323. package/src/kv-scheme.ts +0 -257
  324. package/src/kv-store.ts +0 -1099
  325. package/src/lab/README.md +0 -18
  326. package/src/lab/curve/curve-designer.html +0 -303
  327. package/src/lab/curve/curve-sampler.ts +0 -122
  328. package/src/lab/expert-trace/expert-trace.ts +0 -69
  329. package/src/lab/paged-kv/paged-kv-rows.ts +0 -83
  330. package/src/lab/paged-kv/paged-kv.ts +0 -270
  331. package/src/library.ts +0 -40
  332. package/src/lora.ts +0 -408
  333. package/src/md-modules.d.ts +0 -49
  334. package/src/media-fetch.ts +0 -442
  335. package/src/memory/article.ts +0 -558
  336. package/src/memory/chunk-validation.ts +0 -150
  337. package/src/memory/chunk.ts +0 -318
  338. package/src/memory/cluster.ts +0 -351
  339. package/src/memory/coverage.ts +0 -134
  340. package/src/memory/crosslink.ts +0 -0
  341. package/src/memory/db.ts +0 -253
  342. package/src/memory/entity.ts +0 -203
  343. package/src/memory/gate.ts +0 -187
  344. package/src/memory/history.ts +0 -152
  345. package/src/memory/ingest.ts +0 -335
  346. package/src/memory/model.ts +0 -183
  347. package/src/memory/normalize.ts +0 -671
  348. package/src/memory/parse.ts +0 -22
  349. package/src/memory/pipeline.ts +0 -275
  350. package/src/memory/prompts.ts +0 -65
  351. package/src/memory/query.ts +0 -334
  352. package/src/memory/reconcile.ts +0 -734
  353. package/src/memory/redirect.ts +0 -108
  354. package/src/memory/reindex.ts +0 -325
  355. package/src/memory/resolve.ts +0 -307
  356. package/src/memory/rest.ts +0 -245
  357. package/src/memory/route.ts +0 -272
  358. package/src/memory/schedule.ts +0 -165
  359. package/src/memory/stages.ts +0 -777
  360. package/src/memory/synthesize.ts +0 -1638
  361. package/src/memory/tools.ts +0 -749
  362. package/src/memory/vault.ts +0 -1194
  363. package/src/memory/wikify.ts +0 -1064
  364. package/src/mlx/array.ts +0 -388
  365. package/src/mlx/autograd.ts +0 -304
  366. package/src/mlx/checkpoint.ts +0 -149
  367. package/src/mlx/compile.ts +0 -168
  368. package/src/mlx/custom-vjp.ts +0 -188
  369. package/src/mlx/ffi.ts +0 -512
  370. package/src/mlx/materialize.ts +0 -23
  371. package/src/mlx/metal-kernel.ts +0 -159
  372. package/src/mlx/ops.ts +0 -1021
  373. package/src/mlx/quantized-rows.ts +0 -36
  374. package/src/mlx/token-bitmask.ts +0 -52
  375. package/src/mlx/turboquant-kv-decode.ts +0 -82
  376. package/src/mlx/turboquant-kv-inverse.ts +0 -122
  377. package/src/mlx/turboquant-ops.ts +0 -861
  378. package/src/mlx/turboquant-tables.ts +0 -237
  379. package/src/mmap.ts +0 -90
  380. package/src/model/artifact-identity.ts +0 -73
  381. package/src/model/batched-kv.ts +0 -235
  382. package/src/model/batched-mask.ts +0 -279
  383. package/src/model/batched-quant.ts +0 -212
  384. package/src/model/batched-quantized-kv.ts +0 -144
  385. package/src/model/batched-rotating-quant.ts +0 -353
  386. package/src/model/batched-rotating-state.ts +0 -149
  387. package/src/model/batched-rotating.ts +0 -338
  388. package/src/model/batched-row-storage.ts +0 -179
  389. package/src/model/batched-ssm.ts +0 -52
  390. package/src/model/batched-turboquant-kv.ts +0 -93
  391. package/src/model/compiled-decode.ts +0 -712
  392. package/src/model/decoded-kv-donor.ts +0 -12
  393. package/src/model/delayed-quantized-kv.ts +0 -72
  394. package/src/model/delayed-rotating-quantized-kv.ts +0 -93
  395. package/src/model/delayed-turboquant-kv.ts +0 -55
  396. package/src/model/diffusion-gemma.ts +0 -1026
  397. package/src/model/factory.ts +0 -189
  398. package/src/model/fingerprint.ts +0 -33
  399. package/src/model/flash-attention.ts +0 -694
  400. package/src/model/full-prefill-padding.ts +0 -56
  401. package/src/model/full-prefill-row.ts +0 -105
  402. package/src/model/gemma4-base.ts +0 -2351
  403. package/src/model/gemma4.ts +0 -1315
  404. package/src/model/generated/gemma4-12b.ts +0 -429
  405. package/src/model/generated/gemma4-26b.ts +0 -448
  406. package/src/model/generated/gemma4-e4b.ts +0 -717
  407. package/src/model/generated/index.ts +0 -18
  408. package/src/model/glm52-atlas.ts +0 -511
  409. package/src/model/glm52-cache.ts +0 -792
  410. package/src/model/glm52-config.ts +0 -262
  411. package/src/model/glm52-container.ts +0 -305
  412. package/src/model/glm52-coupling.ts +0 -388
  413. package/src/model/glm52-dsa.ts +0 -606
  414. package/src/model/glm52-expert-layout.ts +0 -253
  415. package/src/model/glm52-layout.ts +0 -152
  416. package/src/model/glm52-memory.ts +0 -500
  417. package/src/model/glm52-mla.ts +0 -792
  418. package/src/model/glm52-moe.ts +0 -223
  419. package/src/model/glm52-pilot.ts +0 -537
  420. package/src/model/glm52-reference.ts +0 -445
  421. package/src/model/glm52-residency.ts +0 -557
  422. package/src/model/glm52-resident-weights.ts +0 -135
  423. package/src/model/glm52-streamed-experts.ts +0 -453
  424. package/src/model/glm52-streamed-metal.ts +0 -610
  425. package/src/model/glm52-weights.ts +0 -503
  426. package/src/model/glm52.ts +0 -1132
  427. package/src/model/implementation.ts +0 -69
  428. package/src/model/kv-attention-view.ts +0 -67
  429. package/src/model/minicpm5.ts +0 -376
  430. package/src/model/profile.ts +0 -443
  431. package/src/model/qwen-append.ts +0 -12
  432. package/src/model/qwen-conv.ts +0 -52
  433. package/src/model/qwen3-delta-state.ts +0 -74
  434. package/src/model/qwen3-delta.ts +0 -451
  435. package/src/model/qwen3-moe.ts +0 -404
  436. package/src/model/qwen3-mrope.ts +0 -252
  437. package/src/model/qwen3.ts +0 -277
  438. package/src/model/qwen3_5-checkpoint.ts +0 -164
  439. package/src/model/qwen3_5.ts +0 -819
  440. package/src/model/rotating-kv-donor.ts +0 -35
  441. package/src/model/rotating-kv-layout.ts +0 -262
  442. package/src/model/rotating-row-transaction.ts +0 -35
  443. package/src/model/speculative-rotating-kv.ts +0 -101
  444. package/src/model/ssm-prefill-padding.ts +0 -39
  445. package/src/model/support.ts +0 -102
  446. package/src/model/trellis-balanced-scatter.ts +0 -51
  447. package/src/model/trellis-linear.ts +0 -672
  448. package/src/model/trellis-shared-m.ts +0 -151
  449. package/src/model/trellis-shared-scatter.ts +0 -144
  450. package/src/model/trellis-splitk-prefill.ts +0 -158
  451. package/src/model/trellis-tiled-prefill.ts +0 -136
  452. package/src/model/trellis-vector-expand.ts +0 -62
  453. package/src/model/trellis-wide-prefill.ts +0 -94
  454. package/src/model/turboquant-codec.ts +0 -83
  455. package/src/model/universal/archs.ts +0 -332
  456. package/src/model/universal/dense.ts +0 -612
  457. package/src/model/universal/modules.ts +0 -170
  458. package/src/model/universal/rope.ts +0 -381
  459. package/src/native/expert_io.c +0 -523
  460. package/src/native/frame_extract.swift +0 -140
  461. package/src/native-pack.ts +0 -162
  462. package/src/pi-provider.ts +0 -53
  463. package/src/pi-session.ts +0 -81
  464. package/src/pi-terminal.ts +0 -274
  465. package/src/pi-web.ts +0 -1932
  466. package/src/preflight.ts +0 -158
  467. package/src/prompt-cache.ts +0 -460
  468. package/src/quantize/allocator.ts +0 -627
  469. package/src/quantize/atomic-output.ts +0 -38
  470. package/src/quantize/calibration.ts +0 -181
  471. package/src/quantize/config-writer.ts +0 -145
  472. package/src/quantize/index.ts +0 -84
  473. package/src/quantize/job.ts +0 -162
  474. package/src/quantize/quantizer.ts +0 -666
  475. package/src/quantize/rotate.ts +0 -603
  476. package/src/quantize/safetensors-writer.ts +0 -249
  477. package/src/quantize/sensitivity.ts +0 -216
  478. package/src/quantize/trellis.ts +0 -586
  479. package/src/quantize/weight-transform.ts +0 -292
  480. package/src/registry.ts +0 -602
  481. package/src/runtime-config.ts +0 -81
  482. package/src/safetensors.ts +0 -158
  483. package/src/sampler.ts +0 -1011
  484. package/src/serve/admin-routes.ts +0 -184
  485. package/src/serve/assets/curve-terrain.html +0 -105
  486. package/src/serve/assets/training-inference-map.html +0 -575
  487. package/src/serve/aux-routes.ts +0 -132
  488. package/src/serve/batch-scheduler.ts +0 -8
  489. package/src/serve/checkpoint-identity.ts +0 -64
  490. package/src/serve/generation-gateway.ts +0 -496
  491. package/src/serve/isolate.ts +0 -609
  492. package/src/serve/kv-budget.ts +0 -14
  493. package/src/serve/lab-routes.ts +0 -341
  494. package/src/serve/lane-registry.ts +0 -45
  495. package/src/serve/model-admin-routes.ts +0 -155
  496. package/src/serve/model-binding.ts +0 -43
  497. package/src/serve/model-host.ts +0 -511
  498. package/src/serve/parent-application.ts +0 -56
  499. package/src/serve/prompt-response-trace.ts +0 -147
  500. package/src/serve/response-lease.ts +0 -24
  501. package/src/serve/session-search.ts +0 -326
  502. package/src/serve/static-routes.ts +0 -101
  503. package/src/server.ts +0 -1314
  504. package/src/spec/assistant-rows.ts +0 -92
  505. package/src/spec/assistant-source.ts +0 -126
  506. package/src/spec/cache-identity.ts +0 -22
  507. package/src/spec/deepspec-rows.ts +0 -29
  508. package/src/spec/deepspec-source.ts +0 -145
  509. package/src/spec/dflash-source.ts +0 -149
  510. package/src/spec/drafter.ts +0 -304
  511. package/src/spec/dspark/ab-stats.ts +0 -136
  512. package/src/spec/dspark/calibration.ts +0 -112
  513. package/src/spec/dspark/data-dflash.ts +0 -156
  514. package/src/spec/dspark/data.ts +0 -201
  515. package/src/spec/dspark/deepspec-module.ts +0 -776
  516. package/src/spec/dspark/generate-dflash.ts +0 -245
  517. package/src/spec/dspark/generate.ts +0 -290
  518. package/src/spec/dspark/loader.ts +0 -23
  519. package/src/spec/dspark/loss.ts +0 -213
  520. package/src/spec/dspark/module-dflash.ts +0 -560
  521. package/src/spec/dspark/module.ts +0 -540
  522. package/src/spec/dspark/quantize-drafter.ts +0 -91
  523. package/src/spec/dspark/sample.ts +0 -112
  524. package/src/spec/generate.ts +0 -276
  525. package/src/spec/glm52-mtp-graph.ts +0 -29
  526. package/src/spec/glm52-mtp-rows.ts +0 -132
  527. package/src/spec/glm52-mtp-source.ts +0 -317
  528. package/src/spec/glm52-mtp-state.ts +0 -33
  529. package/src/spec/ngram-source.ts +0 -204
  530. package/src/spec/projected-draft-rows.ts +0 -73
  531. package/src/spec/qwen-mtp-module.ts +0 -171
  532. package/src/spec/qwen-mtp-rows.ts +0 -219
  533. package/src/spec/qwen-mtp-source.ts +0 -383
  534. package/src/spec/qwen-mtp-state.ts +0 -30
  535. package/src/spec/serve-loop.ts +0 -585
  536. package/src/spec/source.ts +0 -215
  537. package/src/spec/two-model-rows.ts +0 -61
  538. package/src/spec/two-model.ts +0 -113
  539. package/src/ssd-cache.ts +0 -372
  540. package/src/ssd-durability.ts +0 -211
  541. package/src/tokenizer.ts +0 -335
  542. package/src/tool-approvals.ts +0 -131
  543. package/src/tool-call.ts +0 -695
  544. package/src/train/dataset.ts +0 -484
  545. package/src/train/diffusion-lora.ts +0 -216
  546. package/src/train/export.ts +0 -32
  547. package/src/train/flash-cce.ts +0 -1234
  548. package/src/train/forward.ts +0 -266
  549. package/src/train/fuse.ts +0 -243
  550. package/src/train/index.ts +0 -46
  551. package/src/train/job.ts +0 -205
  552. package/src/train/lora-params.ts +0 -254
  553. package/src/train/loss.ts +0 -1591
  554. package/src/train/merge.ts +0 -195
  555. package/src/train/optimizer.ts +0 -183
  556. package/src/train/prefix-shared.ts +0 -490
  557. package/src/train/rank.ts +0 -137
  558. package/src/train/segmented.ts +0 -1828
  559. package/src/train/steel-qmm-header.ts +0 -1461
  560. package/src/train/trainer.ts +0 -1221
  561. package/src/train/watch.ts +0 -542
  562. package/src/vision/diffusion-vision.ts +0 -620
  563. package/src/vision/embedder.ts +0 -168
  564. package/src/vision/preprocess.ts +0 -247
  565. package/src/vision/prompt.ts +0 -373
  566. package/src/vision/qwen3vl-preprocess.ts +0 -409
  567. package/src/vision/qwen3vl-prompt.ts +0 -196
  568. package/src/vision/qwen3vl-tower.ts +0 -555
  569. package/src/vision/siglip.ts +0 -599
  570. package/src/vision/video-frames.ts +0 -148
  571. package/src/web/app.html +0 -2143
  572. package/src/web/app.js +0 -5703
  573. package/src/web/skills/memory/SKILL.md +0 -120
  574. package/src/web/skills/web-research/SKILL.md +0 -46
  575. package/src/web/skills.ts +0 -97
  576. package/src/web/src/adapters-panel.ts +0 -288
  577. package/src/web/src/assistant.ts +0 -451
  578. package/src/web/src/chat.ts +0 -1057
  579. package/src/web/src/composer.ts +0 -959
  580. package/src/web/src/dataset.ts +0 -132
  581. package/src/web/src/finetune.ts +0 -267
  582. package/src/web/src/hub.ts +0 -428
  583. package/src/web/src/main.ts +0 -98
  584. package/src/web/src/markdown.ts +0 -0
  585. package/src/web/src/memory-panel.ts +0 -572
  586. package/src/web/src/model-picker.ts +0 -159
  587. package/src/web/src/palette.ts +0 -346
  588. package/src/web/src/protocol.ts +0 -26
  589. package/src/web/src/quantize.ts +0 -167
  590. package/src/web/src/rag.ts +0 -274
  591. package/src/web/src/sessions.ts +0 -469
  592. package/src/web/src/shell.ts +0 -804
  593. package/src/web/src/ui-catalog.ts +0 -78
  594. package/src/web/vendor/README.md +0 -61
  595. package/src/web-assets.ts +0 -47
  596. package/src/web-tools.ts +0 -478
  597. package/src/weights.ts +0 -255
  598. /package/src/{serve → server}/completion-sink.ts +0 -0
  599. /package/src/web/{icon.svg → public/icon.svg} +0 -0
  600. /package/src/web/{manifest.webmanifest → public/manifest.webmanifest} +0 -0
  601. /package/src/web/{vendor → public/vendor}/hljs-LICENSE +0 -0
@@ -0,0 +1,467 @@
1
+ // The app's shell glue: what the page needs around the generic web shell (`@mlx-bun/web-shell`, which owns
2
+ // navigation, hash routing, theme, the Developer switch, the shortcut sheet, the Escape overlay sweep, panel mounting
3
+ // and the palette chrome). Here: the app's routes and chrome hooks, the Hugging Face token settings and the shared
4
+ // push-to-hub flow, the agent-tools settings (the chat panel's host side), the overlays and key bindings that reach the
5
+ // chat panel, the connection pill and model identity polling, and the routes-map probe. The generic helpers the
6
+ // per-page modules import from here are re-exported from the shell package. main.ts holds the boot order.
7
+
8
+ import { $, createShell, toast, trapFocus, type FocusTrap, type Overlay, type Palette, type RouteController, type ShellPanel } from "@mlx-bun/web-shell";
9
+ import { api } from "./api";
10
+ import type { ApiEnvelope } from "./protocol";
11
+
12
+ export { $, el, injectStyles, toast, trapFocus, type FocusTrap } from "@mlx-bun/web-shell";
13
+ export type Controller = RouteController;
14
+
15
+ /* ════════════════════════════════════════════════════════════════════
16
+ THE SHELL — the app's pages and the chrome that depends on the page
17
+ ════════════════════════════════════════════════════════════════════ */
18
+ /** The chat panel element's public methods, as the app calls them (the panel is `@mlx-bun/module-chat`'s: the shell mounts
19
+ * it as the first page, and the app reaches it through the element, never through an import). */
20
+ export interface ChatPanelApi extends HTMLElement {
21
+ newChat(): void;
22
+ copyLastResponse(): void;
23
+ setCodingTools(enabled: boolean): void;
24
+ refreshAdapters(): void;
25
+ focusComposer(): void;
26
+ toggleThinking(): void;
27
+ recentChats(): { title: string; path: string }[];
28
+ openSession(path: string): boolean;
29
+ exportActiveChat(format?: "md" | "json"): Promise<void>;
30
+ toggleDrawer(): void;
31
+ closeDrawer(): void;
32
+ drawerOpen(): boolean;
33
+ popoverOpen(): boolean;
34
+ closePopover(): boolean;
35
+ }
36
+ /** The mounted chat panel, once the shell has created it (it does on the first visit, which is the home page's). */
37
+ export const chatPanel = (): ChatPanelApi | null => document.querySelector<ChatPanelApi>("mlx-chat-panel");
38
+
39
+ /** The chat is the product (a workspace panel the shell mounts first); the pages below are developer tools behind the nav's Developer switch. */
40
+ export const shell = createShell({
41
+ routes: [
42
+ { id: "status", developer: true }, { id: "routes", developer: true },
43
+ ],
44
+ home: "chat",
45
+ onRoute(route) {
46
+ // dim the ambient bloom slightly in the chat workspace so text reads cleanly
47
+ $("bloom").style.opacity = route === "chat" ? "0.55" : "1";
48
+ // The mobile drawer hamburger only makes sense on /chat (it opens the recent-chats sidebar, which only exists
49
+ // there): CSS hides it >=760px; this hides it off-route regardless of viewport width.
50
+ $("chat-hamburger").style.display = route === "chat" ? "" : "none";
51
+ if (route !== "chat") chatPanel()?.closeDrawer();
52
+ },
53
+ });
54
+ /** Page controllers by route id, populated by main.ts; pages reach each other through it. */
55
+ export const controllers = shell.controllers;
56
+ export const currentRoute = (): string => shell.currentRoute();
57
+ export const isDeveloperMode = (): boolean => shell.isDeveloperMode();
58
+ export const setDeveloperMode = (on: boolean): void => shell.setDeveloperMode(on);
59
+
60
+ /* ════════════════════════════════════════════════════════════════════
61
+ SHARED HELPERS
62
+ ════════════════════════════════════════════════════════════════════ */
63
+ export const gb = (b: number | null | undefined): string => b == null ? "—" : (b / 2 ** 30).toFixed(2) + " GB";
64
+ export const mb = (b: number | null | undefined): string => b == null ? "—" : (b / 2 ** 20).toFixed(1) + " MB";
65
+ export const num = (n: number | null | undefined): string => n == null ? "—" : Math.round(n).toLocaleString();
66
+
67
+ /* ════════════════════════════════════════════════════════════════════
68
+ HUGGING FACE — shared token settings + push-to-hub flow
69
+ ════════════════════════════════════════════════════════════════════ */
70
+
71
+ /** Reflect saved-token state on the nav gear. */
72
+ export async function refreshHfGear(): Promise<boolean> {
73
+ try {
74
+ const d = await api("/api/settings/hf-token");
75
+ const saved = !!(d && d.ok && (d as { hasToken?: boolean }).hasToken);
76
+ $("nav-hf").classList.toggle("saved", saved);
77
+ $("nav-hf").title = saved ? "Hugging Face token saved · click to replace" : "Hugging Face token settings";
78
+ return saved;
79
+ } catch { return false; }
80
+ }
81
+
82
+ let hfOverlayTrap: FocusTrap | null = null; // set by initHfSettings() below
83
+
84
+ function openHfSettings(): void {
85
+ const ov = $("hf-overlay"); ov.classList.add("open");
86
+ if (hfOverlayTrap) hfOverlayTrap.capture();
87
+ ($("hf-token-input") as HTMLInputElement).value = ""; $("hf-settings-msg").innerHTML = "";
88
+ $("hf-state").textContent = "Checking for a saved token…";
89
+ api("/api/settings/hf-token").then((d) => {
90
+ const saved = !!(d && d.ok && (d as { hasToken?: boolean }).hasToken);
91
+ $("hf-state").innerHTML = saved
92
+ ? "A write token is <strong>saved</strong>. Enter a new one below to replace it."
93
+ : "No token saved yet. Add a write token to push models and datasets to the Hub.";
94
+ }).catch(() => { $("hf-state").textContent = "Could not reach the server."; });
95
+ setTimeout(() => $("hf-token-input").focus(), 50);
96
+ }
97
+ function closeHfSettings(): void {
98
+ $("hf-overlay").classList.remove("open");
99
+ if (hfOverlayTrap) hfOverlayTrap.restore();
100
+ }
101
+
102
+ async function saveHfToken(): Promise<void> {
103
+ const tokenInput = $("hf-token-input") as HTMLInputElement;
104
+ const token = tokenInput.value.trim();
105
+ const msg = $("hf-settings-msg");
106
+ if (!token) { msg.innerHTML = '<div class="flash err">Enter a token first.</div>'; return; }
107
+ const btn = $("hf-save") as HTMLButtonElement; btn.disabled = true;
108
+ const d = await api("/api/settings/hf-token", { method: "POST", body: { token } }).catch((): ApiEnvelope => ({ ok: false, error: "request failed" }));
109
+ btn.disabled = false;
110
+ if (!d.ok) { msg.innerHTML = '<div class="flash err">' + escHtml(d.error || "could not save token") + "</div>"; return; }
111
+ msg.innerHTML = '<div class="flash ok">Token saved to <code>~/.mlx-bun/hf.json</code>.</div>';
112
+ tokenInput.value = "";
113
+ refreshHfGear();
114
+ toast("Hugging Face token saved", "ok");
115
+ }
116
+
117
+ // Local esc() copy to avoid a circular import with markdown.ts (shell.ts
118
+ // only needs escaping, not the full markdown surface) — identical logic to
119
+ // markdown.ts's esc().
120
+ function escHtml(s: unknown): string {
121
+ return String(s ?? "").replace(/[&<>"]/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" } as Record<string, string>)[c]!);
122
+ }
123
+
124
+ export interface PushToHubOpts {
125
+ kind: "quantize" | "finetune" | "dataset";
126
+ job_id?: string;
127
+ source_path?: string;
128
+ }
129
+
130
+ /**
131
+ * Shared push-to-hub flow, rendered inline inside a done-step card.
132
+ * pushToHub(panelEl, { kind, job_id?, source_path? })
133
+ * kind: "quantize" | "finetune" | "dataset". Posts to /api/{kind}/push.
134
+ * Walks: ensure token -> repo_id + private -> POST -> success/error flash.
135
+ */
136
+ export async function pushToHub(panel: HTMLElement, opts: PushToHubOpts): Promise<void> {
137
+ const { kind, job_id, source_path } = opts;
138
+ panel.innerHTML = '<div class="pushpanel"><div class="flash"><span class="shimmer">checking Hugging Face token…</span></div></div>';
139
+ const wrap = panel.firstChild as HTMLElement;
140
+ let hasToken = false;
141
+ try { const s = await api("/api/settings/hf-token"); hasToken = !!(s && s.ok && (s as { hasToken?: boolean }).hasToken); } catch { /* treat as no token */ }
142
+
143
+ const renderForm = () => {
144
+ wrap.innerHTML =
145
+ (!hasToken
146
+ ? '<div class="field"><label>Hugging Face write token</label>' +
147
+ '<input type="password" class="p-token" placeholder="hf_…" autocomplete="off" spellcheck="false">' +
148
+ '<div class="hint">A <strong>write</strong> token from huggingface.co/settings/tokens. Stored locally at <code>~/.mlx-bun/hf.json</code>.</div></div>'
149
+ : "") +
150
+ '<div class="field"><label>Repository id</label>' +
151
+ '<input type="text" class="p-repo" placeholder="you/my-' + escHtml(kind === "dataset" ? "dataset" : "model") + '" autocomplete="off"></div>' +
152
+ '<div class="field"><label class="chk"><input type="checkbox" class="p-priv">Private repository</label></div>' +
153
+ '<div class="p-msg"></div>' +
154
+ '<div class="btnrow" style="margin-top:6px"><button class="btn primary sm p-go">' +
155
+ (hasToken ? "Push" : "Save token &amp; push") + "</button></div>";
156
+ (wrap.querySelector(".p-go") as HTMLButtonElement).onclick = go;
157
+ const focusEl = wrap.querySelector(hasToken ? ".p-repo" : ".p-token") as HTMLElement | null;
158
+ if (focusEl) focusEl.focus();
159
+ };
160
+
161
+ async function go(): Promise<void> {
162
+ const msg = wrap.querySelector(".p-msg") as HTMLElement;
163
+ const repo = ((wrap.querySelector(".p-repo") as HTMLInputElement).value || "").trim();
164
+ const priv = (wrap.querySelector(".p-priv") as HTMLInputElement).checked;
165
+ if (!repo) { msg.innerHTML = '<div class="flash err">Enter a repository id (e.g. <code>you/my-model</code>).</div>'; return; }
166
+ const btn = wrap.querySelector(".p-go") as HTMLButtonElement; btn.disabled = true;
167
+
168
+ if (!hasToken) {
169
+ const token = ((wrap.querySelector(".p-token") as HTMLInputElement).value || "").trim();
170
+ if (!token) { msg.innerHTML = '<div class="flash err">Enter a write token first.</div>'; btn.disabled = false; return; }
171
+ const sv = await api("/api/settings/hf-token", { method: "POST", body: { token } }).catch((): ApiEnvelope => ({ ok: false, error: "request failed" }));
172
+ if (!sv.ok) { msg.innerHTML = '<div class="flash err">' + escHtml(sv.error || "could not save token") + "</div>"; btn.disabled = false; return; }
173
+ hasToken = true; refreshHfGear();
174
+ }
175
+
176
+ msg.innerHTML = '<div class="flash"><span class="shimmer">pushing to ' + escHtml(repo) + "…</span></div>";
177
+ const body: Record<string, unknown> = { repo_id: repo, private: priv };
178
+ if (job_id != null) body.job_id = job_id;
179
+ if (source_path != null) body.source_path = source_path;
180
+ const d = await api("/api/" + kind + "/push", { method: "POST", body }).catch((): ApiEnvelope => ({ ok: false, error: "request failed" }));
181
+ btn.disabled = false;
182
+ if (!d.ok) { msg.innerHTML = '<div class="flash err">' + escHtml(d.error || "push failed") + "</div>"; return; }
183
+ const url = (d as { url?: string }).url || ("https://huggingface.co/" + repo);
184
+ wrap.innerHTML = '<div class="flash ok">Pushed to <a href="' + escHtml(url) + '" target="_blank" rel="noopener" style="text-decoration:underline">' + escHtml(url) + "</a></div>";
185
+ toast("Pushed to Hugging Face", "ok");
186
+ }
187
+
188
+ renderForm();
189
+ }
190
+
191
+ /* wire the nav gear + modal once at boot. The modal now also hosts the
192
+ * Agent tools section — see the block below;
193
+ * kept in this same init function since it's one modal, one open/close
194
+ * lifecycle, one focus trap. */
195
+ export function initHfSettings(): void {
196
+ $("nav-hf").onclick = openHfSettings;
197
+ $("hf-close").onclick = closeHfSettings;
198
+ $("hf-save").onclick = saveHfToken;
199
+ $("hf-overlay").addEventListener("click", (e) => { if (e.target === $("hf-overlay")) closeHfSettings(); });
200
+ $("hf-token-input").addEventListener("keydown", (e) => { if ((e as KeyboardEvent).key === "Enter") saveHfToken(); });
201
+ // Escape is handled globally by the shell's overlay sweep (one
202
+ // Escape mechanism for every popover/overlay, not a bespoke one per modal).
203
+ hfOverlayTrap = trapFocus($("hf-overlay"), () => $("hf-overlay").classList.contains("open"));
204
+ refreshHfGear();
205
+ initCodingToolsToggle();
206
+ }
207
+
208
+ /* ════════════════════════════════════════════════════════════════════
209
+ AGENT TOOLS SETTINGS — the codingTools
210
+ opt-in toggle + the durable "always allow" list. State of record for
211
+ BOTH is server-side (the toggle's enforcement, and the tool-approvals
212
+ config file); this module only reflects what the server last reported
213
+ (coding_tools/tool_approvals ServerMessages, relayed here by chat.ts —
214
+ shell.ts owns no WebSocket) plus the localStorage mirror that lets the
215
+ checkbox restore its last-requested state before the first `ready`
216
+ frame arrives.
217
+ ════════════════════════════════════════════════════════════════════ */
218
+ const CODING_TOOLS_KEY = "mlxbun.codingTools";
219
+
220
+ /** Last requested state (this browser). The server is the actual source of
221
+ * truth for enforcement — this is only UI restoration so the checkbox
222
+ * doesn't flash unchecked while waiting on the first `ready`/`coding_tools`
223
+ * frame after a reload. */
224
+ export function storedCodingToolsPreference(): boolean {
225
+ return localStorage.getItem(CODING_TOOLS_KEY) === "1";
226
+ }
227
+
228
+ function setStoredCodingToolsPreference(on: boolean): void {
229
+ localStorage.setItem(CODING_TOOLS_KEY, on ? "1" : "0");
230
+ }
231
+
232
+ /** Reflect the server's coding_tools frame {active, pending} into the
233
+ * checkbox + the honest status note. `active` is what THIS session's tool
234
+ * surface actually contains; `pending` is the last request, which only
235
+ * takes effect on the next new/opened/forked chat — the note says so
236
+ * explicitly rather than implying the toggle is live immediately. */
237
+ export function renderCodingToolsState(active: boolean, pending: boolean): void {
238
+ const cb = $("settings-coding-tools") as HTMLInputElement | null;
239
+ if (cb) cb.checked = pending;
240
+ const note = $("settings-coding-tools-note");
241
+ if (!note) return;
242
+ if (pending && !active) {
243
+ note.style.display = "";
244
+ note.textContent = "Will apply starting with your next new chat (this chat keeps its current tools).";
245
+ } else if (!pending && active) {
246
+ note.style.display = "";
247
+ note.textContent = "Turning this off won't remove tools from the CURRENT chat — start a new chat to fully disable.";
248
+ } else {
249
+ note.style.display = "none";
250
+ note.textContent = "";
251
+ }
252
+ }
253
+
254
+ /** Reflect the durable always-allow set (tool_approvals frame) into the
255
+ * settings list, each row with a "forget" button. `onForget` is supplied
256
+ * by chat.ts (it owns the WebSocket) — this module never sends frames
257
+ * itself, matching pushToHub/refreshHfGear's api()-only pattern above. */
258
+ export function renderToolApprovals(tools: readonly string[], onForget: (tool: string) => void): void {
259
+ const list = $("settings-approvals-list");
260
+ if (!list) return;
261
+ if (tools.length === 0) {
262
+ list.innerHTML = '<div class="settings-approvals-empty">No tools are set to always-allow yet.</div>';
263
+ return;
264
+ }
265
+ list.innerHTML = tools.map((t) =>
266
+ '<div class="settings-approval-row"><span class="satool">' + escHtml(t) +
267
+ '</span><button class="saforget" data-tool="' + escHtml(t) + '">Forget</button></div>'
268
+ ).join("");
269
+ list.querySelectorAll<HTMLButtonElement>(".saforget").forEach((btn) => {
270
+ btn.onclick = () => onForget(btn.dataset.tool || "");
271
+ });
272
+ }
273
+
274
+ /** Wire the checkbox; the actual set_coding_tools WS send is the chat panel's (`setCodingTools`), since this file owns no
275
+ * WebSocket. Until the panel exists, localStorage still records the preference (the panel re-sends it on every `ready`
276
+ * frame), so nothing is lost. */
277
+ function initCodingToolsToggle(): void {
278
+ const cb = $("settings-coding-tools") as HTMLInputElement | null;
279
+ if (!cb) return;
280
+ cb.checked = storedCodingToolsPreference();
281
+ cb.onchange = () => {
282
+ const on = cb.checked;
283
+ setStoredCodingToolsPreference(on);
284
+ chatPanel()?.setCodingTools(on);
285
+ };
286
+ }
287
+
288
+ /* ════════════════════════════════════════════════════════════════════
289
+ MOBILE DRAWER — the chat's recent-chats sidebar is a slide-over on narrow viewports. The sidebar, its backdrop and
290
+ its focus trap belong to the chat panel; this is the hamburger in the nav, which is app chrome (shown on the chat
291
+ route only, see the shell's onRoute).
292
+ ════════════════════════════════════════════════════════════════════ */
293
+ export function initDrawer(): void {
294
+ $("chat-hamburger").onclick = () => chatPanel()?.toggleDrawer();
295
+ }
296
+
297
+ /** A registered close callback for the memory overlay (memory-panel.ts's initMemoryPanel()) — avoids a circular import (shell.ts
298
+ * is imported BY memory-panel.ts for $/trapFocus/etc., so shell.ts can't
299
+ * import memory-panel.ts's closeMemPanel back). */
300
+ export let memPanelClose: (() => void) | null = null;
301
+ export function setMemPanelClose(fn: (() => void) | null): void { memPanelClose = fn; }
302
+
303
+
304
+ /** The overlays Escape closes, in priority order (the shell adds its shortcut sheet first): each is open when its
305
+ * element carries `.open` and its page registered a close callback. */
306
+ export function registerOverlays(palette: Palette): void {
307
+ const byId = (id: string, close: () => (() => void) | null): Overlay => ({
308
+ isOpen: () => { const e = document.getElementById(id); return !!e && e.classList.contains("open") && close() !== null; },
309
+ close: () => close()!(),
310
+ });
311
+ const add = (overlay: Overlay) => shell.overlays.add(overlay);
312
+ add({ isOpen: () => $("hf-overlay").classList.contains("open"), close: closeHfSettings });
313
+ // The chat panel's popovers (sampling, system prompt, adapter table) close themselves.
314
+ add({ isOpen: () => !!chatPanel()?.popoverOpen(), close: () => { chatPanel()?.closePopover(); } });
315
+ add(byId("mem-overlay", () => memPanelClose));
316
+ add(palette);
317
+ add({ isOpen: () => !!chatPanel()?.drawerOpen(), close: () => chatPanel()?.closeDrawer() });
318
+ }
319
+
320
+ /** The chat's keyboard bindings, consulted after the shell's own. */
321
+ export function appKeys(e: KeyboardEvent): boolean {
322
+ const mod = e.metaKey || e.ctrlKey;
323
+ // Cmd/Ctrl+Shift+O: new chat. (Ctrl+Shift+O is free in every major browser; Cmd+Shift+O has no macOS Safari/Chrome reservation either.)
324
+ if (mod && e.shiftKey && (e.key === "O" || e.key === "o")) {
325
+ if (currentRoute() !== "chat") return true; // no-op off the chat route
326
+ e.preventDefault();
327
+ chatPanel()?.newChat();
328
+ return true;
329
+ }
330
+ // Cmd/Ctrl+Shift+C: copy last response.
331
+ if (mod && e.shiftKey && (e.key === "C" || e.key === "c")) {
332
+ if (currentRoute() !== "chat") return true;
333
+ e.preventDefault();
334
+ chatPanel()?.copyLastResponse();
335
+ return true;
336
+ }
337
+ // Shift+Escape: focus the composer.
338
+ if (e.shiftKey && e.key === "Escape") {
339
+ if (currentRoute() !== "chat") return true;
340
+ e.preventDefault();
341
+ chatPanel()?.focusComposer();
342
+ return true;
343
+ }
344
+ return false;
345
+ }
346
+
347
+ /* ── Routes tab feature-detection ──
348
+ /dag reads a repo-relative doc that is absent from compiled binaries and npm installs. Probe once at boot with a
349
+ HEAD request; on 404 hide the Routes tab entirely (rather than leaving a dead link that iframes a raw 404) and, if
350
+ the user is already sitting on #/routes, swap in a graceful in-app note instead of the broken iframe. */
351
+ export async function initRoutesProbe(): Promise<void> {
352
+ let ok = true;
353
+ try {
354
+ const r = await fetch("/dag", { method: "HEAD" });
355
+ ok = r.ok;
356
+ } catch { ok = false; }
357
+ if (ok) return;
358
+ shell.markUnavailable("routes");
359
+ const section = $("s-routes");
360
+ if (section) {
361
+ section.innerHTML =
362
+ '<div class="wrap" style="max-width:640px;margin:60px auto;text-align:center;color:var(--dim)">' +
363
+ "<h2>Routes map unavailable</h2>" +
364
+ "<p>The training/inference route diagram ships alongside the repo checkout " +
365
+ "and isn't bundled into this build.</p></div>";
366
+ }
367
+ // If a deep link landed here directly, bounce to chat rather than sit on an orphaned nav state with no visible tab pointing at it.
368
+ if (currentRoute() === "routes") location.replace("#/chat");
369
+ }
370
+
371
+
372
+ /* ════════════════════════════════════════════════════════════════════
373
+ GLOBAL CONNECTION PILL + MODEL ID (polled lightly, always on)
374
+ ════════════════════════════════════════════════════════════════════ */
375
+ export let activeModelId: string | null = null;
376
+
377
+ export function setConn(state: string, text: string): void {
378
+ const p = $("nav-conn");
379
+ p.className = "pill " + (state || "");
380
+ $("nav-conn-text").textContent = text;
381
+ }
382
+
383
+ let defaultHelloSub: string | null = null;
384
+
385
+ export async function pollIdentity(): Promise<void> {
386
+ try {
387
+ const [models, dl] = await Promise.all([
388
+ fetch("/v1/models").then((r) => r.json()),
389
+ fetch("/downloads").then((r) => r.json()).catch(() => ({ downloads: [] })),
390
+ ]);
391
+ // The server marks the current model; a server that predates residency lists the served one first.
392
+ const listed: { id: string; current?: boolean }[] = models.data || [];
393
+ const served = listed.find((m) => m.current) || listed[0];
394
+ const next = served ? served.id : null;
395
+ const switched = activeModelId !== null && next !== null && next !== activeModelId;
396
+ activeModelId = next;
397
+ $("nav-model").textContent = activeModelId || "no model";
398
+ // Chat reads the model's capabilities when it connects: an idle chat reconnects to pick them up.
399
+ if (switched) window.dispatchEvent(new CustomEvent("mlx-model-changed", { detail: next }));
400
+ setConn("ok", "live · localhost");
401
+ updateDownloadIndicator((dl && dl.downloads) || []);
402
+ } catch {
403
+ $("nav-model").textContent = "server unreachable";
404
+ setConn("bad", "unreachable — retrying");
405
+ }
406
+ }
407
+
408
+ /** The nav's model label opens the Models panel (a page the shell mounts from the models module); a switch or an adapter change made
409
+ * there re-reads the served model's identity at once instead of at the next poll. */
410
+ export function initModelLink(): void {
411
+ $("nav-model").onclick = () => { location.hash = "#/models"; };
412
+ document.addEventListener("mlx-models-changed", () => { void pollIdentity(); });
413
+ }
414
+
415
+ interface DownloadInfo {
416
+ state: string;
417
+ repoId: string;
418
+ totalBytes?: number;
419
+ receivedBytes?: number;
420
+ }
421
+
422
+ /** Surface a background model download — the "bigger model arriving while you
423
+ * chat on the starter" case — as a live nav pill plus a download-aware
424
+ * greeting in the empty chat state. Hidden when nothing else is downloading. */
425
+ export function updateDownloadIndicator(downloads: DownloadInfo[]): void {
426
+ const sub = $("chat-hello-sub");
427
+ if (sub && defaultHelloSub === null) defaultHelloSub = sub.textContent;
428
+ const incoming = downloads.find((d) => d.state === "active" && d.repoId !== activeModelId);
429
+ const pill = $("nav-download");
430
+ if (incoming) {
431
+ const pct = incoming.totalBytes ? Math.floor(((incoming.receivedBytes || 0) / incoming.totalBytes) * 100) : 0;
432
+ const name = incoming.repoId.split("/").pop();
433
+ $("nav-download-text").textContent = "↓ " + name + " · " + pct + "%";
434
+ pill.style.display = "";
435
+ if (sub) sub.textContent = "You're on a small, fast starter model so you can chat right now — a more capable one (" + name + ") is downloading and takes over next launch. Ask me anything, or about mlx-bun itself.";
436
+ } else {
437
+ pill.style.display = "none";
438
+ if (sub && defaultHelloSub !== null) sub.textContent = defaultHelloSub;
439
+ }
440
+ }
441
+
442
+ /** Presentation the embedding app supplies to the job panels that consume it. */
443
+ export function connectPanels(panels: readonly ShellPanel[]): ShellPanel[] {
444
+ return panels.map(panel => {
445
+ if (!["mlx-quantize-panel", "mlx-train-panel", "mlx-datasets-panel"].includes(panel.tag)) return panel;
446
+ return { ...panel, connection: { ...panel.connection, ui: {
447
+ notify: toast,
448
+ publish: pushToHub,
449
+ ...(panel.tag === "mlx-datasets-panel" ? { modelId: () => activeModelId || undefined } : { catalogChanged: () => {
450
+ const status = controllers.status;
451
+ if (status?.refreshLibrary) (status.refreshLibrary as () => void)();
452
+ chatPanel()?.refreshAdapters();
453
+ } }),
454
+ } } };
455
+ });
456
+ }
457
+
458
+ /** Keep the app's existing navigation order while its pages move into installed panels. */
459
+ export function mountPanels(panels: readonly ShellPanel[]): void {
460
+ shell.mountPanels(connectPanels(panels));
461
+ const order = ["chat", "quantize", "finetune", "dataset", "status", "routes", "benchmarks", "metrics", "models"];
462
+ const tabs = $("tabs");
463
+ [...tabs.querySelectorAll<HTMLElement>(".tab")].sort((a, b) => {
464
+ const position = (tab: HTMLElement) => { const index = order.indexOf(tab.dataset.tab || ""); return index < 0 ? order.length : index; };
465
+ return position(a) - position(b);
466
+ }).forEach(tab => tabs.append(tab));
467
+ }
@@ -1,5 +1,6 @@
1
- // GENERATED-ADJACENT source module — part of the src/web/src/* split (plan
2
- // §7/§9 Phase 2). Built into src/web/app.js by scripts/build-web.ts.
1
+ // GENERATED-ADJACENT source module — part of the apps/mlx-bun/src/web/browser/*
2
+ // split. Built into apps/mlx-bun/dist/web/app.js by
3
+ // scripts/build-web.ts.
3
4
  //
4
5
  // STATUS CONTROLLER — ported dashboard (poll /stats + /v1/models + /fit +
5
6
  // /library + /downloads). Behavior-identical port of the original
@@ -46,7 +47,7 @@ interface SkuRow {
46
47
  export function createStatusController() {
47
48
  let timer: ReturnType<typeof setInterval> | null = null, libTimer: ReturnType<typeof setInterval> | null = null, fitLoaded = false;
48
49
  const dlRates: Record<string, { bytes: number; t: number }> = {};
49
- // Library staleness (web-ui-pass-plan.md #3): /library is server-cached for
50
+ // Library staleness (`02d723a:docs/archive/planning/web-ui-pass-plan.md` #3): /library is server-cached for
50
51
  // 30s, but the client used to fetch it exactly once per page load
51
52
  // (gated on `fitLoaded`) — a quantize job finishing, a fresh download
52
53
  // landing, or a manual drop into the HF cache never showed up without a
@@ -59,7 +60,8 @@ export function createStatusController() {
59
60
  fetch("/stats").then((r) => r.json()),
60
61
  fetch("/v1/models").then((r) => r.json()),
61
62
  ]);
62
- const m = models.data && models.data[0];
63
+ const listed: { id: string; context_window?: number; current?: boolean }[] = models.data || [];
64
+ const m = listed.find((x) => x.current) || listed[0];
63
65
  $("st-model-id").textContent = (m && m.id) || "—";
64
66
  const a = stats.admission || {};
65
67
  $("st-model-meta").textContent = num(m && m.context_window) + " token window · weights " + gb(a.weights_bytes);
@@ -90,25 +92,25 @@ export function createStatusController() {
90
92
  .map(([k, v]) => '<div class="kv"><b>' + esc(k) + ' layers</b><span class="num">' + esc(v) + "</span></div>").join("") +
91
93
  (att ? '<div class="kv"><b>attention</b><span class="num">' + esc(att.global) + " global · " + esc(att.sliding_window) + " sliding</span></div>" : "");
92
94
 
93
- const glm = stats.glm52;
94
- const expert = glm && glm.expert_runtime;
95
- const expertCard = $("st-glm-expert-card");
96
- expertCard.style.display = glm ? "" : "none";
97
- if (glm) {
95
+ const runtime = stats.runtime;
96
+ const expert = runtime && runtime.expert_runtime;
97
+ const expertCard = $("st-expert-card");
98
+ expertCard.style.display = runtime ? "" : "none";
99
+ if (runtime) {
98
100
  const rate = (d: { hits?: number; misses?: number } | null | undefined): string => {
99
101
  const total = (d?.hits || 0) + (d?.misses || 0);
100
102
  return total ? (100 * (d?.hits || 0) / total).toFixed(1) + "%" : "—";
101
103
  };
102
104
  const turn = expert && expert.last_turn;
103
- $("st-glm-main-hit").textContent = rate(turn?.main?.demand);
104
- $("st-glm-main-read").textContent = turn?.main?.demand
105
+ $("st-expert-main-hit").textContent = rate(turn?.main?.demand);
106
+ $("st-expert-main-read").textContent = turn?.main?.demand
105
107
  ? gb(turn.main.demand.readBytes) : "—";
106
- $("st-glm-mtp-hit").textContent = rate(turn?.mtp?.demand);
107
- $("st-glm-mtp-read").textContent = turn?.mtp?.demand
108
+ $("st-expert-mtp-hit").textContent = rate(turn?.mtp?.demand);
109
+ $("st-expert-mtp-read").textContent = turn?.mtp?.demand
108
110
  ? gb(turn.mtp.demand.readBytes) : "—";
109
111
  const main = expert?.main_residency;
110
112
  const mtp = expert?.mtp_residency;
111
- $("st-glm-residency").textContent = main
113
+ $("st-expert-residency").textContent = main
112
114
  ? "resident slots main " + num(main.resident + main.pinned) +
113
115
  " / " + num(main.resident + main.pinned + main.working) +
114
116
  (mtp ? " · MTP " + num(mtp.resident + mtp.pinned) +
@@ -176,7 +178,7 @@ export function createStatusController() {
176
178
  else if (!m.supported) status = '<span style="color:var(--dimmer)">unsupported (' + esc(m.model_type) + ")</span>";
177
179
  else if (a && a.fits) status = '<span style="color:var(--green);font-weight:600">fits</span>';
178
180
  else status = '<span style="color:var(--red);font-weight:600">too big</span>';
179
- // web-ui-pass-plan.md #20: max_safe_context is meaningful whenever
181
+ // `02d723a:docs/archive/planning/web-ui-pass-plan.md` #20: max_safe_context is meaningful whenever
180
182
  // it's > 0, even when `fits` is false at the library's default 8192
181
183
  // probe context — e.g. a model that doesn't fit at 8192 tokens but
182
184
  // does fit at a smaller context still gets a real number here rather
@@ -205,12 +207,10 @@ export function createStatusController() {
205
207
  machine?: { ram_bytes?: number; bandwidth_gbs?: number; chip?: string };
206
208
  sku_matrix_ctx?: number;
207
209
  sku_matrix?: SkuRow[];
208
- glm52?: {
210
+ plan?: {
209
211
  artifact_disk_bytes?: number | null;
210
- main_expert_slab_bytes?: number;
211
- mtp_expert_slab_bytes?: number;
212
- direct_oracle_warm_decode_tps?: number;
213
- aspirational_decode_tps?: number;
212
+ streamed_weights?: Record<string, number>;
213
+ max_generation_tokens?: number | null;
214
214
  };
215
215
  }
216
216
  let f: FitResponse;
@@ -221,31 +221,27 @@ export function createStatusController() {
221
221
  if (f.measured_decode_tps) {
222
222
  $("st-tps").textContent = tps(f.measured_decode_tps);
223
223
  $("st-tps").closest(".card")!.querySelector("h3")!.textContent = "Decode · measured";
224
- $("st-tps-cap").textContent = f.glm52
225
- ? "quality-preserving warm · direct oracle " +
226
- tps(f.glm52.direct_oracle_warm_decode_tps || 0) +
227
- " · aspiration " + tps(f.glm52.aspirational_decode_tps || 0)
228
- : "mlx-bun benchmark on this machine · predicted " +
229
- tps(f.typical_decode_tps || 0) + " at " + num(f.typical_context_tokens) + " ctx";
224
+ $("st-tps-cap").textContent = "mlx-bun benchmark on this machine · predicted " +
225
+ tps(f.typical_decode_tps || 0) + " at " + num(f.typical_context_tokens) + " ctx";
230
226
  } else if (f.typical_decode_tps) {
231
227
  $("st-tps").textContent = f.typical_decode_tps.toFixed(1);
232
228
  $("st-tps-cap").textContent = "at " + num(f.typical_context_tokens) + " context · " + (r.predicted_decode_tps || 0).toFixed(1) + " tok/s at the " + num(f.context_tokens) + " max (full-KV reads)";
233
229
  } else {
234
- $("st-tps").textContent = (r.predicted_decode_tps || 0).toFixed(1);
230
+ $("st-tps").textContent = r.predicted_decode_tps == null ? "—" : r.predicted_decode_tps.toFixed(1);
235
231
  }
236
232
  $("st-m-ram").textContent = gb(f.machine && f.machine.ram_bytes);
237
233
  $("st-m-bw").textContent = (f.machine && f.machine.bandwidth_gbs || "—") + " GB/s";
238
234
  $("st-m-fits").innerHTML = r.fits ? '<span style="color:var(--green);font-weight:700">FITS</span>' : '<span style="color:var(--red);font-weight:700">DOES NOT FIT</span>';
239
235
  $("st-fit-ctx").textContent = num(f.context_tokens);
240
- document.querySelectorAll<HTMLElement>("[data-glm-fit]").forEach((row) => {
241
- row.style.display = f.glm52 ? "" : "none";
236
+ document.querySelectorAll<HTMLElement>("[data-plan-fit]").forEach((row) => {
237
+ row.style.display = f.plan ? "" : "none";
242
238
  });
243
- $("st-f-weights-label").textContent = f.glm52 ? "resident weights" : "weights";
244
- $("st-f-transient-label").textContent = f.glm52 ? "other reserves" : "transient";
245
- $("st-f-artifact").textContent = f.glm52?.artifact_disk_bytes
246
- ? gb(f.glm52.artifact_disk_bytes) : "registry unavailable";
247
- $("st-f-main-slab").textContent = gb(f.glm52?.main_expert_slab_bytes);
248
- $("st-f-mtp-slab").textContent = gb(f.glm52?.mtp_expert_slab_bytes);
239
+ $("st-f-weights-label").textContent = f.plan ? "resident weights" : "weights";
240
+ $("st-f-transient-label").textContent = f.plan ? "other reserves" : "transient";
241
+ $("st-f-artifact").textContent = f.plan?.artifact_disk_bytes
242
+ ? gb(f.plan.artifact_disk_bytes) : "registry unavailable";
243
+ $("st-f-streamed").innerHTML = Object.entries(f.plan?.streamed_weights || {})
244
+ .map(([label, bytes]) => '<div class="kv"><b>' + esc(label) + '</b><span class="num">' + gb(bytes) + "</span></div>").join("");
249
245
  $("st-f-weights").textContent = gb(r.weights_bytes);
250
246
  $("st-f-kv").textContent = gb(r.kv_bytes);
251
247
  $("st-f-transient").textContent = gb(r.transient_bytes);
@@ -293,7 +289,7 @@ export function createStatusController() {
293
289
  // Exposed so a quantize job's `done` event (this same controller's own
294
290
  // quantize flow, see controllers.quantize below) can force an immediate
295
291
  // refresh instead of waiting up to 15s — the server invalidates its
296
- // /library cache the moment the job completes (server.ts onComplete),
292
+ // /library cache the moment the job completes (apps/mlx-bun/src/cli/serve-state.ts onComplete),
297
293
  // so an immediate re-fetch is guaranteed fresh, not a race.
298
294
  refreshLibrary: loadLibrary,
299
295
  };