mlx-bun 0.0.13 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (427) hide show
  1. package/README.md +71 -578
  2. package/bin/mlx-bun.mjs +1 -1
  3. package/docs/README.md +91 -0
  4. package/docs/{design → archive}/hlg-sampling.md +3 -3
  5. package/docs/{design → archive/investigations}/audio-input-plan.md +4 -4
  6. package/docs/{design → archive/investigations}/colibri-glm52-port.md +1 -1
  7. package/docs/{design → archive/investigations}/diffusion-gemma-port.md +3 -3
  8. package/docs/{design → archive/investigations}/faithful-l1-consolidation.md +4 -4
  9. package/docs/{investigations → archive/investigations}/hlg-sampling-investigation.md +1 -1
  10. package/docs/{design → archive/investigations}/minicpm5-decode-megakernel.md +11 -11
  11. package/docs/{design → archive/investigations}/optimization_plan.md +1 -1
  12. package/docs/archive/investigations/pareto-specialized-runtime-findings.md +92 -0
  13. package/docs/{design → archive/investigations}/pre-colibri-stabilization.md +5 -5
  14. package/docs/{design → archive/investigations}/the-dreaming-handoff.md +2 -2
  15. package/docs/{planning → archive/planning}/chat-ui-vision.md +1 -1
  16. package/docs/{planning → archive/planning}/chunk-task-roadmap.md +1 -1
  17. package/docs/{planning → archive/planning}/curve-sampler-research-plan.md +4 -4
  18. package/docs/{planning → archive/planning}/memory-docs-and-dag-plan.md +1 -1
  19. package/docs/{planning → archive/planning}/release-notes-v0.0.9.md +1 -1
  20. package/docs/archive/planning/release-notes-v0.2.0.md +49 -0
  21. package/docs/{planning → archive/planning}/website-readme-pass-plan.md +1 -1
  22. package/docs/design/batching.md +569 -0
  23. package/docs/design/decode-speed-program.md +3178 -169
  24. package/docs/design/dreaming-nightly-pipeline.md +675 -282
  25. package/docs/design/generic-model-support.md +579 -334
  26. package/docs/design/kv-cache.md +680 -0
  27. package/docs/design/orpo-training.md +673 -1239
  28. package/docs/design/speculative-decoding.md +1627 -0
  29. package/docs/design/turboquant.md +2102 -0
  30. package/docs/design/unified-engine-frontier-plan.md +1831 -727
  31. package/docs/design/web-chat-redesign.md +666 -1083
  32. package/docs/planning/PRODUCT_ROADMAP.md +34 -1
  33. package/docs/planning/release-notes-v0.3.0.md +35 -0
  34. package/docs/planning/video-series.md +421 -0
  35. package/docs/reference/benchmarks.md +1162 -0
  36. package/docs/reference/cli.md +395 -149
  37. package/docs/reference/distribution.md +321 -181
  38. package/docs/reference/environment.md +348 -0
  39. package/docs/reference/glossary.md +39 -0
  40. package/docs/reference/library-api.md +580 -142
  41. package/docs/reference/memory.md +227 -64
  42. package/docs/reference/models.md +137 -6
  43. package/docs/reference/server-api.md +938 -422
  44. package/docs/reference/server-config.md +652 -320
  45. package/docs/reference/training.md +393 -254
  46. package/docs/reference/troubleshooting.md +166 -0
  47. package/package.json +10 -5
  48. package/src/admission-plan.ts +18 -0
  49. package/src/anthropic.ts +92 -3
  50. package/src/audio/decode.ts +2 -2
  51. package/src/audio/features.ts +2 -2
  52. package/src/backends/mlx/autoregressive.ts +108 -0
  53. package/src/backends/mlx/batch-group.ts +1646 -0
  54. package/src/backends/mlx/diffusion.ts +39 -0
  55. package/src/backends/mlx/draft-target.ts +47 -0
  56. package/src/backends/mlx/evaluation.ts +105 -0
  57. package/src/backends/mlx/fill-append.ts +45 -0
  58. package/src/backends/mlx/gateway-binding.ts +71 -0
  59. package/src/backends/mlx/graph.ts +38 -0
  60. package/src/backends/mlx/memory-client.ts +189 -0
  61. package/src/backends/mlx/memory-guard.ts +40 -0
  62. package/src/backends/mlx/methods.ts +90 -0
  63. package/src/backends/mlx/model-prompt.ts +164 -0
  64. package/src/backends/mlx/model-serving.ts +79 -0
  65. package/src/backends/mlx/prefill.ts +33 -0
  66. package/src/backends/mlx/request-policy.ts +20 -0
  67. package/src/backends/mlx/rollback.ts +51 -0
  68. package/src/backends/mlx/serial-executor.ts +273 -0
  69. package/src/backends/mlx/speculative.ts +114 -0
  70. package/src/backends/mlx/state-views.ts +26 -0
  71. package/src/backends/mlx/text-engine.ts +73 -0
  72. package/src/cli.ts +189 -61
  73. package/src/client.ts +66 -0
  74. package/src/config.ts +21 -4
  75. package/src/contracts/completion.ts +16 -0
  76. package/src/contracts/execution.ts +49 -0
  77. package/src/contracts/generation.ts +103 -0
  78. package/src/contracts/host.ts +7 -0
  79. package/src/contracts/jobs.ts +66 -0
  80. package/src/contracts/pi-provider.ts +30 -0
  81. package/src/contracts/pi.ts +259 -0
  82. package/src/contracts/resources.ts +18 -0
  83. package/src/contracts/scheduling.ts +27 -0
  84. package/src/contracts/tsconfig.json +14 -0
  85. package/src/diffusion/diffusion-generate.ts +218 -153
  86. package/src/embed.ts +1 -1
  87. package/src/engine/admission.ts +59 -0
  88. package/src/engine/cancellation.ts +38 -0
  89. package/src/engine/engine.ts +56 -0
  90. package/src/engine/execution-coordinator.ts +70 -0
  91. package/src/engine/execution-plan.ts +51 -0
  92. package/src/engine/resources.ts +42 -0
  93. package/src/engine/scheduler.ts +67 -0
  94. package/src/engine/session.ts +247 -0
  95. package/src/eval/README.md +44 -1
  96. package/src/eval/kl.ts +263 -23
  97. package/src/eval/reference-logits.ts +207 -0
  98. package/src/eval/runner.ts +10 -79
  99. package/src/eval/tasks/bfcl.ts +2 -1
  100. package/src/eval/tasks/gsm8k.ts +2 -1
  101. package/src/eval/tasks/hashhop.ts +2 -1
  102. package/src/eval/tasks/humaneval.ts +5 -4
  103. package/src/eval/tasks/ifeval.ts +2 -1
  104. package/src/eval/tasks/mmlu.ts +2 -1
  105. package/src/expert-io.ts +3 -1
  106. package/src/expert-offload.ts +3 -1
  107. package/src/fill/echo-index.ts +188 -0
  108. package/src/fill/fill-session.ts +452 -0
  109. package/src/fill/proposal.ts +68 -0
  110. package/src/fill/schema-rows.ts +506 -0
  111. package/src/fill/tool-boundary.ts +103 -0
  112. package/src/fit.ts +24 -43
  113. package/src/generate.ts +740 -337
  114. package/src/grammar.ts +14 -8
  115. package/src/harness-pi.ts +15 -34
  116. package/src/hub-rest.ts +4 -4
  117. package/src/index.ts +27 -0
  118. package/src/inference/denoising.ts +17 -0
  119. package/src/inference/graph.ts +33 -0
  120. package/src/inference/prefill.ts +39 -0
  121. package/src/inference/rollback.ts +7 -0
  122. package/src/jobs/db.ts +4 -0
  123. package/src/jobs/index.ts +2 -0
  124. package/src/jobs/job-entry.ts +15 -14
  125. package/src/jobs/runner.ts +98 -13
  126. package/src/jobs/task-client.ts +19 -0
  127. package/src/jobs/types.ts +2 -58
  128. package/src/kv-scheme.ts +199 -0
  129. package/src/kv-store.ts +459 -234
  130. package/src/lab/README.md +18 -0
  131. package/src/{assets → lab/curve}/curve-designer.html +2 -2
  132. package/src/{curve-sampler.ts → lab/curve/curve-sampler.ts} +2 -2
  133. package/src/{expert-trace.ts → lab/expert-trace/expert-trace.ts} +7 -5
  134. package/src/{model → lab/paged-kv}/paged-kv.ts +9 -6
  135. package/src/library.ts +40 -0
  136. package/src/lora.ts +18 -0
  137. package/src/media-fetch.ts +20 -4
  138. package/src/memory/article.ts +1 -1
  139. package/src/memory/chunk.ts +1 -1
  140. package/src/memory/model.ts +32 -170
  141. package/src/memory/prompts.ts +1 -1
  142. package/src/memory/rest.ts +1 -1
  143. package/src/memory/schedule.ts +1 -1
  144. package/src/memory/stages.ts +4 -1
  145. package/src/memory/vault.ts +3 -4
  146. package/src/mlx/array.ts +9 -10
  147. package/src/mlx/compile.ts +12 -2
  148. package/src/mlx/ffi.ts +66 -22
  149. package/src/mlx/materialize.ts +23 -0
  150. package/src/mlx/metal-kernel.ts +10 -11
  151. package/src/mlx/ops.ts +64 -19
  152. package/src/mlx/quantized-rows.ts +36 -0
  153. package/src/mlx/token-bitmask.ts +52 -0
  154. package/src/mlx/turboquant-kv-decode.ts +82 -0
  155. package/src/mlx/turboquant-kv-inverse.ts +122 -0
  156. package/src/mlx/turboquant-ops.ts +33 -3
  157. package/src/mlx/turboquant-tables.ts +2 -2
  158. package/src/model/batched-mask.ts +9 -3
  159. package/src/model/batched-quant.ts +2 -2
  160. package/src/model/batched-rotating-quant.ts +45 -99
  161. package/src/model/batched-rotating-state.ts +73 -0
  162. package/src/model/batched-rotating.ts +57 -106
  163. package/src/model/batched-row-storage.ts +127 -0
  164. package/src/model/compiled-decode.ts +4 -3
  165. package/src/model/diffusion-gemma.ts +8 -8
  166. package/src/model/factory.ts +87 -49
  167. package/src/model/fingerprint.ts +1 -1
  168. package/src/model/flash-attention.ts +3 -3
  169. package/src/model/gemma4-base.ts +187 -17
  170. package/src/model/gemma4.ts +6 -6
  171. package/src/model/generated/gemma4-12b.ts +52 -148
  172. package/src/model/generated/gemma4-26b.ts +34 -94
  173. package/src/model/generated/gemma4-e4b.ts +28 -76
  174. package/src/model/glm52-cache.ts +19 -9
  175. package/src/model/glm52-dsa.ts +13 -9
  176. package/src/model/glm52-memory.ts +28 -1
  177. package/src/model/implementation.ts +69 -0
  178. package/src/model/minicpm5.ts +7 -8
  179. package/src/model/profile.ts +443 -0
  180. package/src/model/qwen-append.ts +12 -0
  181. package/src/model/qwen-conv.ts +52 -0
  182. package/src/model/qwen3-delta.ts +98 -2
  183. package/src/model/qwen3-mrope.ts +252 -0
  184. package/src/model/qwen3_5-checkpoint.ts +164 -0
  185. package/src/model/qwen3_5.ts +336 -60
  186. package/src/model/support.ts +1 -1
  187. package/src/model/trellis-balanced-scatter.ts +51 -0
  188. package/src/model/trellis-linear.ts +672 -0
  189. package/src/model/trellis-shared-m.ts +151 -0
  190. package/src/model/trellis-shared-scatter.ts +144 -0
  191. package/src/model/trellis-splitk-prefill.ts +158 -0
  192. package/src/model/trellis-tiled-prefill.ts +136 -0
  193. package/src/model/trellis-vector-expand.ts +62 -0
  194. package/src/model/trellis-wide-prefill.ts +94 -0
  195. package/src/model/universal/dense.ts +1 -1
  196. package/src/model/universal/modules.ts +8 -1
  197. package/src/native/frame_extract.swift +140 -0
  198. package/src/native-pack.ts +15 -7
  199. package/src/pi-provider.ts +6 -64
  200. package/src/pi-web.ts +14 -320
  201. package/src/prompt-cache.ts +97 -54
  202. package/src/quantize/allocator.ts +1 -1
  203. package/src/quantize/atomic-output.ts +38 -0
  204. package/src/quantize/calibration.ts +2 -1
  205. package/src/quantize/config-writer.ts +16 -3
  206. package/src/quantize/index.ts +28 -1
  207. package/src/quantize/job.ts +11 -0
  208. package/src/quantize/quantizer.ts +265 -100
  209. package/src/quantize/rotate.ts +603 -0
  210. package/src/quantize/safetensors-writer.ts +79 -1
  211. package/src/quantize/sensitivity.ts +41 -59
  212. package/src/quantize/trellis.ts +586 -0
  213. package/src/quantize/weight-transform.ts +292 -0
  214. package/src/responses.ts +130 -3
  215. package/src/runtime-config.ts +81 -0
  216. package/src/sampler.ts +276 -4
  217. package/src/serve/admin-routes.ts +184 -0
  218. package/src/serve/aux-routes.ts +132 -0
  219. package/src/serve/batch-scheduler.ts +8 -1558
  220. package/src/serve/chat-request.ts +391 -0
  221. package/src/serve/chat-stage.ts +195 -0
  222. package/src/serve/checkpoint-identity.ts +64 -0
  223. package/src/serve/completion-executor.ts +354 -0
  224. package/src/serve/completion-sink.ts +157 -0
  225. package/src/serve/discovery-routes.ts +204 -0
  226. package/src/serve/generation-gateway.ts +211 -243
  227. package/src/serve/http.ts +159 -0
  228. package/src/serve/inference-request.ts +79 -0
  229. package/src/serve/isolate.ts +297 -105
  230. package/src/serve/kv-budget.ts +14 -0
  231. package/src/serve/lab-routes.ts +341 -0
  232. package/src/serve/lane-registry.ts +2 -1
  233. package/src/serve/model-admin-routes.ts +155 -0
  234. package/src/serve/model-binding.ts +43 -0
  235. package/src/serve/model-host.ts +512 -0
  236. package/src/serve/openai-wire.ts +103 -0
  237. package/src/serve/parent-application.ts +56 -0
  238. package/src/serve/pipeline.ts +33 -0
  239. package/src/serve/preparation.ts +33 -0
  240. package/src/serve/prompt-response-trace.ts +147 -0
  241. package/src/serve/request-plan.ts +162 -0
  242. package/src/serve/request-prep.ts +346 -0
  243. package/src/serve/response-lease.ts +24 -0
  244. package/src/serve/responses-client.ts +69 -0
  245. package/src/serve/session-completion-engine.ts +110 -0
  246. package/src/serve/session-search.ts +1 -1
  247. package/src/serve/static-routes.ts +101 -0
  248. package/src/serve/text-completion-stage.ts +104 -0
  249. package/src/serve/token-streams.ts +519 -0
  250. package/src/server.ts +523 -3551
  251. package/src/spec/assistant-source.ts +10 -44
  252. package/src/spec/deepspec-source.ts +6 -6
  253. package/src/spec/dflash-source.ts +9 -8
  254. package/src/spec/dspark/ab-stats.ts +3 -3
  255. package/src/spec/dspark/calibration.ts +2 -2
  256. package/src/spec/dspark/deepspec-module.ts +2 -2
  257. package/src/spec/dspark/generate-dflash.ts +2 -2
  258. package/src/spec/dspark/generate.ts +2 -2
  259. package/src/spec/dspark/loader.ts +1 -1
  260. package/src/spec/dspark/module-dflash.ts +5 -4
  261. package/src/spec/dspark/module.ts +3 -3
  262. package/src/spec/dspark/quantize-drafter.ts +1 -1
  263. package/src/spec/generate.ts +1 -1
  264. package/src/spec/glm52-mtp-source.ts +9 -1
  265. package/src/spec/ngram-source.ts +1 -1
  266. package/src/spec/prefix-state.ts +45 -0
  267. package/src/spec/qwen-mtp-source.ts +528 -0
  268. package/src/spec/serve-loop.ts +179 -213
  269. package/src/spec/source.ts +42 -10
  270. package/src/spec/two-model.ts +1 -1
  271. package/src/ssd-cache.ts +95 -24
  272. package/src/ssd-durability.ts +207 -0
  273. package/src/tool-call.ts +51 -14
  274. package/src/train/flash-cce.ts +14 -13
  275. package/src/train/forward.ts +38 -1
  276. package/src/train/loss.ts +3 -2
  277. package/src/train/prefix-shared.ts +5 -1
  278. package/src/train/segmented.ts +9 -6
  279. package/src/train/trainer.ts +9 -8
  280. package/src/vision/preprocess.ts +1 -1
  281. package/src/vision/prompt.ts +48 -2
  282. package/src/vision/qwen3vl-preprocess.ts +409 -0
  283. package/src/vision/qwen3vl-prompt.ts +196 -0
  284. package/src/vision/qwen3vl-tower.ts +555 -0
  285. package/src/vision/video-frames.ts +148 -0
  286. package/src/web/app.html +1 -1
  287. package/src/web/app.js +15 -6
  288. package/src/web/src/adapters-panel.ts +3 -3
  289. package/src/web/src/assistant.ts +2 -36
  290. package/src/web/src/chat.ts +16 -9
  291. package/src/web/src/composer.ts +4 -4
  292. package/src/web/src/hub.ts +1 -1
  293. package/src/web/src/markdown.ts +0 -0
  294. package/src/web/src/memory-panel.ts +1 -1
  295. package/src/web/src/model-picker.ts +1 -1
  296. package/src/web/src/palette.ts +1 -1
  297. package/src/web/src/protocol.ts +3 -39
  298. package/src/web/src/sessions.ts +1 -1
  299. package/src/web/src/ui-catalog.ts +4 -18
  300. package/src/web-assets.ts +47 -0
  301. package/src/weights.ts +134 -33
  302. package/docs/archive/mlx-bun-lab-report.html +0 -275
  303. package/docs/archive/wwdc-mlx-bun.html +0 -848
  304. package/docs/design/adapters-end-to-end.md +0 -205
  305. package/docs/design/batching-perf-path.md +0 -255
  306. package/docs/design/batching-v2-plan.md +0 -529
  307. package/docs/design/bucketing-stage.md +0 -197
  308. package/docs/design/compat-cli-surface-design.md +0 -230
  309. package/docs/design/docs-reorg-plan.md +0 -165
  310. package/docs/design/dspark-serving-program.md +0 -371
  311. package/docs/design/dspark-speculative-decoding.md +0 -268
  312. package/docs/design/grammar-spec-batching-integration.md +0 -301
  313. package/docs/design/memory-inference-path.md +0 -422
  314. package/docs/design/memory-synthesis.md +0 -287
  315. package/docs/design/memory-system.md +0 -237
  316. package/docs/design/mlx-lm-tool-parity-plan.md +0 -545
  317. package/docs/design/omlx-adoption-map.md +0 -98
  318. package/docs/design/orpo-dynamic-lambda.md +0 -220
  319. package/docs/design/orpo-future-enhancements.md +0 -340
  320. package/docs/design/paged-kv-cache.md +0 -214
  321. package/docs/design/parallel-slots.md +0 -567
  322. package/docs/design/parity-tier-dag.md +0 -161
  323. package/docs/design/repo-cleanup-plan.md +0 -189
  324. package/docs/design/runtime-isolation.md +0 -263
  325. package/docs/design/segmented-backward-training.md +0 -543
  326. package/docs/design/spec-decode-larger-targets.md +0 -229
  327. package/docs/design/ssd-kv-cold-tier.md +0 -288
  328. package/docs/design/structured-output.md +0 -484
  329. package/docs/design/tauri-desktop-app.md +0 -127
  330. package/docs/design/the-dreaming-master-plan.md +0 -445
  331. package/docs/design/turboquant-kv.md +0 -235
  332. package/docs/design/w4a16-compute-precision-spike.md +0 -232
  333. package/docs/design/web-chat-beat-matrix.md +0 -315
  334. package/docs/design/write-pipeline-entity.md +0 -468
  335. package/docs/investigations/curve-runs/bisector-route.json +0 -98
  336. package/docs/investigations/curve-runs/bisector-trace.json +0 -1393
  337. package/docs/investigations/curve-runs/curve-terrain.json +0 -1179
  338. package/docs/investigations/curve-runs/curve-terrain.svg +0 -42
  339. package/docs/investigations/hlg-ab.html +0 -34
  340. package/docs/investigations/hlg-explorer.html +0 -238
  341. package/docs/investigations/hlg-figs/cliff.svg +0 -1
  342. package/docs/investigations/hlg-figs/cross.svg +0 -1
  343. package/docs/investigations/hlg-figs/edges.svg +0 -1
  344. package/docs/investigations/hlg-figs/k20-grids.svg +0 -1
  345. package/docs/investigations/hlg-figs/k20-peaks.svg +0 -1
  346. package/docs/investigations/hlg-figs/lw-curve.svg +0 -1
  347. package/docs/investigations/hlg-figs/terrain.svg +0 -1
  348. package/docs/investigations/hlg-report.html +0 -262
  349. package/docs/investigations/hlg-runs/hlg-ab.json +0 -149
  350. package/docs/investigations/hlg-runs/hlg-blind-prompts.md +0 -87
  351. package/docs/investigations/hlg-runs/hlg-blind.json +0 -107
  352. package/docs/investigations/hlg-runs/hlg-cliff.json +0 -197
  353. package/docs/investigations/hlg-runs/hlg-cross.json +0 -505
  354. package/docs/investigations/hlg-runs/hlg-edge.json +0 -388
  355. package/docs/investigations/hlg-runs/hlg-eval1.json +0 -25
  356. package/docs/investigations/hlg-runs/hlg-frontier.json +0 -86
  357. package/docs/investigations/hlg-runs/hlg-grid.json +0 -242
  358. package/docs/investigations/hlg-runs/hlg-grid2.json +0 -343
  359. package/docs/investigations/hlg-runs/hlg-lw-coarse.json +0 -110
  360. package/docs/investigations/hlg-runs/hlg-map.json +0 -383
  361. package/docs/investigations/hlg-runs/run0-original.log +0 -159
  362. package/docs/investigations/hlg-runs/runA-recommended.log +0 -131
  363. package/docs/investigations/hlg-runs/runAA-cliff-cpm5.log +0 -26
  364. package/docs/investigations/hlg-runs/runAB-grid2-e4b.log +0 -18
  365. package/docs/investigations/hlg-runs/runAC-peak-e4b-partial.log +0 -25
  366. package/docs/investigations/hlg-runs/runAD-ab-samples.log +0 -8
  367. package/docs/investigations/hlg-runs/runAE-edge-e4b.log +0 -51
  368. package/docs/investigations/hlg-runs/runAF-logit-calibration.log +0 -10
  369. package/docs/investigations/hlg-runs/runAG-eval-config2.log +0 -16
  370. package/docs/investigations/hlg-runs/runB-gain-variants.log +0 -192
  371. package/docs/investigations/hlg-runs/runC-pivots.log +0 -162
  372. package/docs/investigations/hlg-runs/runD-oetf.log +0 -132
  373. package/docs/investigations/hlg-runs/runE-eotf.log +0 -162
  374. package/docs/investigations/hlg-runs/runF-shaper-working.log +0 -86
  375. package/docs/investigations/hlg-runs/runG-shaper-sweep.log +0 -101
  376. package/docs/investigations/hlg-runs/runH-wsweep.log +0 -176
  377. package/docs/investigations/hlg-runs/runI-asweep.log +0 -176
  378. package/docs/investigations/hlg-runs/runJ-knobmap.log +0 -49
  379. package/docs/investigations/hlg-runs/runK-frontier.log +0 -19
  380. package/docs/investigations/hlg-runs/runL-widemap.log +0 -65
  381. package/docs/investigations/hlg-runs/runM-frontier-emb.log +0 -15
  382. package/docs/investigations/hlg-runs/runN-verify.log +0 -116
  383. package/docs/investigations/hlg-runs/runO-frontier-seed5000.log +0 -15
  384. package/docs/investigations/hlg-runs/runP-grid-AxSm.log +0 -15
  385. package/docs/investigations/hlg-runs/runQ-grid-tgW.log +0 -15
  386. package/docs/investigations/hlg-runs/runR-blind-transcript.log +0 -79
  387. package/docs/investigations/hlg-runs/runS-cross-coherence.log +0 -33
  388. package/docs/investigations/hlg-runs/runT-cross-cpm5.log +0 -33
  389. package/docs/investigations/hlg-runs/runU-cross-12b.log +0 -33
  390. package/docs/investigations/hlg-runs/runV-lw-e4b.log +0 -22
  391. package/docs/investigations/hlg-runs/runW-lw-12b.log +0 -22
  392. package/docs/investigations/hlg-runs/runX-lw-cpm5.log +0 -22
  393. package/docs/investigations/hlg-runs/runY-cliff-e4b.log +0 -26
  394. package/docs/investigations/hlg-runs/runZ-cliff-12b.log +0 -26
  395. package/docs/planning/IDEAS.md +0 -69
  396. package/docs/reference/embedding.md +0 -197
  397. package/docs/reference/features-matrix.md +0 -100
  398. package/docs/reference/orpo-quickstart.md +0 -135
  399. package/src/flags.ts +0 -13
  400. /package/docs/{investigations → archive/investigations}/chunk-finetune-experiment.md +0 -0
  401. /package/docs/{investigations → archive/investigations}/colibri-oracle-pin.md +0 -0
  402. /package/docs/{investigations → archive/investigations}/curve-bisector-routing.md +0 -0
  403. /package/docs/{investigations → archive/investigations}/decode-roofline-lookagain.md +0 -0
  404. /package/docs/{investigations → archive/investigations}/dspark-handoff.md +0 -0
  405. /package/docs/{investigations → archive/investigations}/expert-offload-single-user-moe.md +0 -0
  406. /package/docs/{investigations → archive/investigations}/indexshare-performance-spike.md +0 -0
  407. /package/docs/{investigations → archive/investigations}/kernel-perf-review-2026-07.md +0 -0
  408. /package/docs/{investigations → archive/investigations}/lab-build-journal.md +0 -0
  409. /package/docs/{investigations → archive/investigations}/openwiki-evaluation.md +0 -0
  410. /package/docs/{investigations → archive/investigations}/orpo-base-uf-experiment-and-directions.md +0 -0
  411. /package/docs/{investigations → archive/investigations}/orpo-flash-cce-pin-leak.md +0 -0
  412. /package/docs/{investigations → archive/investigations}/orpo-uf-testing-handoff.md +0 -0
  413. /package/docs/{investigations → archive/investigations}/pi-builtin-investigation.md +0 -0
  414. /package/docs/{investigations → archive/investigations}/segmented-backward-handoff.md +0 -0
  415. /package/docs/{investigations → archive/investigations}/starter-model-port-handoff.md +0 -0
  416. /package/docs/{investigations → archive/investigations}/steel-flash-cce-handoff.md +0 -0
  417. /package/docs/{investigations → archive/investigations}/trainer-validation-experiment.md +0 -0
  418. /package/docs/{planning → archive/planning}/chat-ui-vision-memory-first.md +0 -0
  419. /package/docs/{planning → archive/planning}/journal.md +0 -0
  420. /package/docs/{planning → archive/planning}/pi-integration-review.md +0 -0
  421. /package/docs/{planning → archive/planning}/release-notes-v0.0.10.md +0 -0
  422. /package/docs/{planning → archive/planning}/release-notes-v0.0.11.md +0 -0
  423. /package/docs/{planning → archive/planning}/release-notes-v0.0.12.md +0 -0
  424. /package/docs/{planning → archive/planning}/release-notes-v0.0.13.md +0 -0
  425. /package/docs/{planning → archive/planning}/web-ui-pass-plan.md +0 -0
  426. /package/{docs/investigations → src/serve/assets}/curve-terrain.html +0 -0
  427. /package/{docs/dag → src/serve/assets}/training-inference-map.html +0 -0
package/src/grammar.ts CHANGED
@@ -33,6 +33,8 @@ import xgrammar, {
33
33
  import { readFileSync } from "node:fs";
34
34
  import { MlxArray } from "./mlx/array";
35
35
  import * as ops from "./mlx/ops";
36
+ import { applyTokenBitmask } from "./mlx/token-bitmask";
37
+ import { runtimeValue } from "./runtime-config";
36
38
  import type { LoadedTokenizer } from "./tokenizer";
37
39
 
38
40
  /** The request shape — the union of every structured-output field name across
@@ -51,7 +53,7 @@ export interface GrammarRequest {
51
53
  guided_grammar?: string;
52
54
  /** vLLM/oMLX: regex. Compiled via `root ::= <regex>` EBNF embedding, so
53
55
  * only the regex∩EBNF subset works (the F5 gap — real regex→EBNF or
54
- * structural-tag RegexFormat is the tracked fix, structured-output.md). */
56
+ * structural-tag RegexFormat is the tracked fix, docs/reference/server-api.md). */
55
57
  guidedRegex?: string;
56
58
  guided_regex?: string;
57
59
  /** vLLM/oMLX: restrict output to one of these strings (enum). */
@@ -79,7 +81,7 @@ export interface CompiledGrammarResult {
79
81
  /** Module-level serializer for ALL xgrammar WASM calls. The WASM instance is
80
82
  * single-threaded; CONCURRENT async calls corrupt emscripten's binding
81
83
  * layer (BindingError: Expected null or instance of VectorInt, got an
82
- * instance of VectorInt — reproduced in tests/grammar.test.ts B1 test, which
84
+ * instance of VectorInt — reproduced in tests/parity/grammar.test.ts B1 test, which
83
85
  * fires 4 overlapping compiles + fills). Under `--batch N` the scheduler
84
86
  * fires N accept()s (each kicks an async fill) then awaits ready() on all;
85
87
  * and the server compiles grammar for concurrent requests. Without
@@ -118,7 +120,7 @@ let cachedTokenizerInfo: {
118
120
  * - decoder is Sequence w/ ByteFallback → byte_fallback (Gemma/SP)
119
121
  * - otherwise → raw
120
122
  * prependSpace is true for byte_level (ByteLevel pretokenizers add a leading
121
- * space). Validated in scripts/experiments/xgrammar-spike.ts across Gemma
123
+ * space). Validated in xgrammar-spike.ts (deleted 2026-08-23; git history) across Gemma
122
124
  * (byte_fallback, 256k), Llama-3 / Qwen2.5 (byte_level, 128k/151k). */
123
125
  function loadVocab(tokenizerJsonPath: string): {
124
126
  vocab: string[];
@@ -206,6 +208,7 @@ export class GrammarController {
206
208
  private pending: Promise<void> | null;
207
209
  private terminated = false;
208
210
  private disposed = false;
211
+ private readonly metalMask = runtimeValue("MLX_BUN_TOKEN_MASK") === "metal";
209
212
  /** Tokens emitted via jumpForward() this generation — telemetry/test hook. */
210
213
  jumpedTokens = 0;
211
214
 
@@ -237,6 +240,7 @@ export class GrammarController {
237
240
  * Sync — the mask is already materialized. Returns a NEW array (caller
238
241
  * disposes the input). Mirrors oMLX's apply_token_bitmask_mlx. */
239
242
  applyMask(logits: MlxArray): MlxArray {
243
+ if (this.metalMask) return applyTokenBitmask(logits, this.readyMask);
240
244
  // Build a -inf/0 additive float mask on device from the int32 bitmask.
241
245
  // Each int32 bit b (little-endian within the word) gates token
242
246
  // word*32 + b. Set = valid (xgrammar convention). Adding -inf → -inf,
@@ -254,7 +258,9 @@ export class GrammarController {
254
258
  const valid = (w >>> bit) & 1;
255
259
  maskArr[id] = valid ? 0 : -Infinity;
256
260
  }
257
- const mask = MlxArray.fromFloat32(maskArr, [1, V]).astype(logits.dtype);
261
+ const raw = MlxArray.fromFloat32(maskArr, [1, V]);
262
+ const mask = raw.astype(logits.dtype);
263
+ raw.dispose();
258
264
  const out = ops.add(logits, mask);
259
265
  mask.dispose();
260
266
  return out;
@@ -284,7 +290,7 @@ export class GrammarController {
284
290
  * time: a controller disposed while its fill is still queued (an exception
285
291
  * between accept/jumpForward and ready()) must not call into the deleted
286
292
  * WASM matcher — that BindingError poisons the module-wide wasmChain for
287
- * every later grammar request (found by tests/grammar-jump.test.ts). */
293
+ * every later grammar request (found by tests/parity/grammar-jump.test.ts). */
288
294
  private fireFill(): Promise<void> {
289
295
  return wasmQueue(() =>
290
296
  this.disposed
@@ -457,7 +463,7 @@ export async function compileGrammarRequest(
457
463
  if (!degradeHint) degradeHint = resolved.degradeDescription ?? "grammar compile failed";
458
464
  // The compiler is the cached per-TokenizerInfo instance (F4) — a failed
459
465
  // compile must NOT dispose it; the WASM abort is catchable and the
460
- // compiler state survives (verified in tests/grammar.test.ts).
466
+ // compiler state survives (verified in tests/parity/grammar.test.ts).
461
467
  // Return the hint (NOT bare null): it drives the degrade path's
462
468
  // system-prompt injection + Warning header. Dropping it here served
463
469
  // unconstrained output with no Warning at all (found 2026-07-07 sweep).
@@ -538,7 +544,7 @@ function resolveGrammarRequest(req: GrammarRequest):
538
544
  kind: "json_schema",
539
545
  schema,
540
546
  strict: js?.strict,
541
- // Whitespace-stall escape hatch (structured-output.md known gaps):
547
+ // Whitespace-stall escape hatch (docs/reference/server-api.md known gaps):
542
548
  // any_whitespace=false compiles the schema with xgrammar's compact
543
549
  // separators — no whitespace choice points, so a whitespace-
544
550
  // degenerate base model can't greedily tab-loop to max_tokens.
@@ -581,5 +587,5 @@ function resolveGrammarRequest(req: GrammarRequest):
581
587
  * (requests degrade to prompt injection). Matches the project's envelope-gated
582
588
  * kill-switch discipline (MLX_BUN_COMPILED_DECODE, MLX_BUN_GRAMMAR_BATCH, …). */
583
589
  export function grammarEnabled(): boolean {
584
- return process.env.MLX_BUN_GRAMMAR !== "0";
590
+ return runtimeValue("MLX_BUN_GRAMMAR") !== "0";
585
591
  }
package/src/harness-pi.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  // mlx-bun harness pi — register mlx-bun as a provider in the user's pi
2
- // install (Phase 16 P1, docs/investigations/pi-builtin-investigation.md).
2
+ // install (Phase 16 P1, docs/archive/investigations/pi-builtin-investigation.md).
3
3
  //
4
4
  // Mechanism: a generated extension file in ~/.pi/agent/extensions/ that
5
5
  // calls pi.registerProvider() with dynamic discovery — it fetches
@@ -13,7 +13,9 @@ import { homedir } from "node:os";
13
13
  import { dirname, join } from "node:path";
14
14
 
15
15
  export const PI_EXTENSION_FILENAME = "mlx-bun-provider.ts";
16
- export const PI_PROVIDER_ID = "mlx-bun";
16
+ import { PI_PROVIDER_ID, PI_LOCAL_MODEL_ID, PI_API_KEY, PI_API, piModelDefinition,
17
+ DEFAULT_CONTEXT_WINDOW, DEFAULT_MAX_TOKENS } from "./contracts/pi-provider";
18
+ export { PI_PROVIDER_ID, PI_LOCAL_MODEL_ID } from "./contracts/pi-provider";
17
19
  /** Stable pi-facing model id. The server runs exactly one model at a time
18
20
  * (memory: the 26B alone is 18 GB) and which one varies run-to-run, so
19
21
  * advertising the real, changing repo id makes pi's persisted default go
@@ -21,7 +23,7 @@ export const PI_PROVIDER_ID = "mlx-bun";
21
23
  * model is loaded; the real model is carried in the `name` field, and the
22
24
  * server still reports the true id in /v1/models and responses. Gives a
23
25
  * clean `mlx-bun/local` handle instead of `mlx-bun/mlx-community/…`. */
24
- export const PI_LOCAL_MODEL_ID = "local";
26
+
25
27
  // 127.0.0.1 (the server's actual default bind), not "localhost": the generated
26
28
  // extension runs under the USER'S pi (node/jiti, not Bun), so don't depend on
27
29
  // how that runtime's resolver maps localhost.
@@ -89,8 +91,8 @@ export async function fetchServerModels(baseUrl: string, timeoutMs = 3000): Prom
89
91
  if (!served) return [];
90
92
  return [{
91
93
  id: served.id,
92
- contextWindow: served.context_window ?? 32768,
93
- maxTokens: 8192,
94
+ contextWindow: served.context_window ?? DEFAULT_CONTEXT_WINDOW,
95
+ maxTokens: DEFAULT_MAX_TOKENS,
94
96
  reasoning: !!served.reasoning,
95
97
  vision: !!served.vision,
96
98
  }];
@@ -120,6 +122,7 @@ export function renderPiExtension(baseUrl: string, fallbackModels: ServerModel[]
120
122
  // is the fallback when the server isn't running.
121
123
  const BASE_URL = ${JSON.stringify(baseUrl)};
122
124
  const FALLBACK_MODELS = ${fallback};
125
+ const modelEntry = ${piModelDefinition.toString()};
123
126
 
124
127
  export default async function (pi: any) {
125
128
  let models = FALLBACK_MODELS;
@@ -131,27 +134,19 @@ export default async function (pi: any) {
131
134
  // The SERVED model is the row with the capability extras (first);
132
135
  // the rest are servable-but-not-served registry entries.
133
136
  const served = data.find((m: any) => m.context_window !== undefined) ?? data[0];
134
- models = [{
135
- id: ${JSON.stringify(PI_LOCAL_MODEL_ID)},
137
+ models = [modelEntry({
136
138
  name: \`\${served.id} (mlx-bun local)\`,
137
- reasoning: !!served.reasoning,
138
- compat: {
139
- supportsDeveloperRole: false,
140
- ...(served.reasoning ? { thinkingFormat: "qwen-chat-template" } : {}),
141
- },
142
- input: served.vision ? ["text", "image"] : ["text"],
143
- cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
144
- contextWindow: served.context_window ?? 32768,
145
- maxTokens: 8192,
146
- }];
139
+ reasoning: !!served.reasoning, vision: !!served.vision,
140
+ contextWindow: served.context_window,
141
+ })];
147
142
  }
148
143
  }
149
144
  } catch {}
150
145
  if (models.length === 0) return; // nothing to register
151
146
  pi.registerProvider(${JSON.stringify(PI_PROVIDER_ID)}, {
152
147
  baseUrl: BASE_URL,
153
- apiKey: "sk-mlx-bun-local",
154
- api: "openai-completions",
148
+ apiKey: ${JSON.stringify(PI_API_KEY)},
149
+ api: ${JSON.stringify(PI_API)},
155
150
  models,
156
151
  });
157
152
  }
@@ -159,21 +154,7 @@ export default async function (pi: any) {
159
154
  }
160
155
 
161
156
  function modelEntry(m: ServerModel) {
162
- return {
163
- id: PI_LOCAL_MODEL_ID,
164
- name: `${m.id} (mlx-bun local)`,
165
- reasoning: !!m.reasoning,
166
- // Kept aligned with buildPiProvider (src/pi-provider.ts): the system
167
- // prompt must arrive as `system`, not `developer`.
168
- compat: {
169
- supportsDeveloperRole: false,
170
- ...(m.reasoning ? { thinkingFormat: "qwen-chat-template" } : {}),
171
- },
172
- input: m.vision ? ["text", "image"] : ["text"],
173
- cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
174
- contextWindow: m.contextWindow,
175
- maxTokens: m.maxTokens,
176
- };
157
+ return piModelDefinition({ ...m, name: `${m.id} (mlx-bun local)` });
177
158
  }
178
159
 
179
160
  export interface InstallResult {
package/src/hub-rest.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  // Axis 3 "Hub" row). Same posture as src/memory/rest.ts: pure (request|url)
4
4
  // => Response handlers with no `ctx` dependency, dispatched from
5
5
  // src/server.ts by path+method, so they're unit-testable without booting a
6
- // model context (see tests/hub-rest.test.ts).
6
+ // model context (see tests/serve/hub-rest.test.ts).
7
7
  //
8
8
  // Three sources, same as optiq Lab's Hub, plus the hardware-fit column optiq
9
9
  // lacks:
@@ -19,7 +19,7 @@
19
19
  // - POST /api/hub/serve — model-swap investigation (see the doc header
20
20
  // above the handler): today this ALWAYS returns
21
21
  // { ok:false, restart_required:true, command } — see
22
- // docs/design/runtime-isolation.md for why no in-process swap seam is
22
+ // docs/reference/server-config.md for why no in-process swap seam is
23
23
  // reachable from the web chat's serving path today.
24
24
 
25
25
  import { loadModelConfig } from "./config";
@@ -43,7 +43,7 @@ function jsonErr(error: string, status = 400): Response {
43
43
  * fixed 8k context (the same "typical" context /fit and /library use, so
44
44
  * the three surfaces never disagree). `reg`/`hubDir` are injectable so
45
45
  * tests can point at a synthetic hub dir instead of the real
46
- * ~/.cache/huggingface/hub (matching tests/registry-fit.test.ts's pattern);
46
+ * ~/.cache/huggingface/hub (matching tests/unit/registry-fit.test.ts's pattern);
47
47
  * the live server route omits both and gets the real registry. */
48
48
  export async function handleHubLocal(
49
49
  opts: { reg?: Registry; hubDir?: string } = {},
@@ -210,7 +210,7 @@ export async function handleHubDownload(request: Request): Promise<Response> {
210
210
 
211
211
  // ---- POST /api/hub/serve --------------------------------------------------
212
212
 
213
- /** Model-swap investigation (docs/design/runtime-isolation.md): the web
213
+ /** Model-swap investigation (docs/reference/server-config.md): the web
214
214
  * chat's `/ws/chat` is explicitly NOT proxied even under `--isolate`
215
215
  * (src/serve/isolate.ts serves it a 501 with a pointer back to the direct,
216
216
  * non-isolated server) and `--isolate` itself is opt-in, not the default —
package/src/index.ts CHANGED
@@ -16,10 +16,36 @@ export {
16
16
  createModel,
17
17
  openGlm52RuntimeModel,
18
18
  openModel,
19
+ type ModelOpenOptions,
19
20
  type Glm52RuntimeOpenOptions,
20
21
  type RuntimeModel,
21
22
  } from "./model/factory";
23
+ export { ModelImplementationRegistry, type ModelImplementation, type ModelImplementationProvider } from "./model/implementation";
24
+ export type { ModelServingBinding, ModelPromptBuilder, BuiltPrompt, ServedModelInfo } from "./serve/model-binding";
25
+ export type { ServingContext, ModelHostSource, AdapterService } from "./serve/model-host";
26
+ export type { MlxGatewayBinding, MlxBatchGroup } from "./backends/mlx/gateway-binding";
27
+ export type { MlxSerialServices, MlxSerialBinding } from "./backends/mlx/serial-executor";
22
28
  export { Qwen3Model } from "./model/qwen3";
29
+ export { configFingerprint } from "./model/fingerprint";
30
+ export {
31
+ BUILTIN_ARTIFACT_PROFILES,
32
+ ENGINE_CAPABILITIES,
33
+ externalArtifactFingerprint,
34
+ resolveModelProfile,
35
+ type ArtifactModelProfile,
36
+ type EngineCapability,
37
+ type FidelityTarget,
38
+ type FidelityTier,
39
+ type GenerationLoop,
40
+ type ModelArtifactIdentity,
41
+ type ModelExecutionComposition,
42
+ type ModelGraph,
43
+ type ModelLoader,
44
+ type ModelProfile,
45
+ type ModelSpecialization,
46
+ type ResolveModelProfileOptions,
47
+ type ResolvedModelProfile,
48
+ } from "./model/profile";
23
49
  export { generate } from "./generate";
24
50
  export { loadTokenizer } from "./tokenizer";
25
51
  export { embedOne, embedMany, isEmbeddingModel, withInstruction, type EmbedResult } from "./embed";
@@ -29,6 +55,7 @@ export { downloadModel } from "./download";
29
55
  export { Registry } from "./registry";
30
56
  export {
31
57
  createServer,
58
+ shutdownServer,
32
59
  loadContext,
33
60
  type LoadContextOptions,
34
61
  type ServerContext,
@@ -0,0 +1,17 @@
1
+ import type { GraphDescriptor } from "./graph";
2
+
3
+ /** Denoising has canvas state and feedback, independent of AR token caches.
4
+ * Returned tensors/state are owned by the run. Inputs remain borrowed. A
5
+ * fused method may bypass this graph and implement InferenceMethod directly. */
6
+ export interface DenoisingGraph<Tensor, State> {
7
+ readonly descriptor: GraphDescriptor;
8
+ readonly vocabSize: number;
9
+ readonly canvasLength: number;
10
+ readonly embedScale: number;
11
+ prefill(promptIds: number[], vision?: Tensor): State;
12
+ extendPrefill(tokens: Tensor, state: State): void;
13
+ decoderLogits(canvas: Tensor, state: State, feedback: Tensor | null): Tensor;
14
+ dequantEmbedWeight(): Tensor;
15
+ softEmbeddings(logits: Tensor, weight: Tensor): Tensor;
16
+ closeState(state: State): void;
17
+ }
@@ -0,0 +1,33 @@
1
+ /** Describes an implementation's ABI, not a claim of oracle parity or speed. */
2
+ export interface GraphDescriptor {
3
+ readonly id: string;
4
+ readonly backend: string;
5
+ readonly graphAbi: string;
6
+ readonly stateAbi: string;
7
+ readonly artifact: string;
8
+ }
9
+
10
+ export type LogitSelection =
11
+ | { readonly type: "all" }
12
+ | { readonly type: "last" }
13
+ | { readonly type: "range"; readonly start: number; readonly end: number };
14
+
15
+ /** Backend-bound graph. Tensor/State/Inputs stay concrete within the binding.
16
+ * Inputs and hidden are borrowed until the returned lazy work completes;
17
+ * returned hidden/logits are owned by the caller. The graph appends to state.
18
+ * Hidden is [batch, positions, hidden-width]; logits are [batch, selected
19
+ * positions, vocabulary]. Selection precedes the vocabulary projection.
20
+ * Dtypes and evaluation/fence semantics belong to the declared backend ABI.
21
+ * Per-run masks, positions, media, taps, and adapters belong in Inputs or in
22
+ * a bound graph context; they are not mutable session fields. */
23
+ export interface AutoregressiveGraph<Tensor, State, Inputs> {
24
+ readonly descriptor: GraphDescriptor;
25
+ forwardHidden(inputs: Inputs, state: State): Tensor | Promise<Tensor>;
26
+ projectLogits(hidden: Tensor, selection: LogitSelection): Tensor;
27
+ }
28
+
29
+ /** A fused InferenceMethod can bypass this graph interface entirely. It need
30
+ * only satisfy the method's output, cancellation, and ownership contracts. */
31
+ export interface GraphFactory<Artifact, Binding, Graph> {
32
+ open(artifact: Artifact, binding: Binding): Promise<{ graph: Graph; close(): Promise<void> }>;
33
+ }
@@ -0,0 +1,39 @@
1
+ export interface PrefillPosition {
2
+ readonly length: number;
3
+ readonly position: number;
4
+ readonly chunkSize: number;
5
+ readonly tailSplit: boolean;
6
+ readonly snapshotAt?: number | null;
7
+ }
8
+
9
+ export interface PrefillStep {
10
+ readonly start: number;
11
+ readonly end: number;
12
+ readonly kind: "drain" | "final";
13
+ readonly snapshot: boolean;
14
+ /** Batch admission may finish a short last drain and token zero in one tick.
15
+ * Serial execution still yields between every drain and the next forward. */
16
+ readonly batchYield: boolean;
17
+ }
18
+
19
+ /** Shared serial/solo-batch prefill program. No tensors, runtime policy reads,
20
+ * or sampling. Advance position only after executing the returned step. */
21
+ export function nextPrefillStep(input: PrefillPosition): PrefillStep {
22
+ const { length, position, chunkSize, tailSplit, snapshotAt } = input;
23
+ if (!Number.isSafeInteger(length) || !Number.isSafeInteger(position) ||
24
+ !Number.isSafeInteger(chunkSize) || chunkSize < 1 || position < 0 || position >= length)
25
+ throw new Error("invalid prefill position or chunk size");
26
+ if (snapshotAt != null && (!Number.isSafeInteger(snapshotAt) || snapshotAt < 0 || snapshotAt > length))
27
+ throw new Error("invalid prefill snapshot boundary");
28
+ if (snapshotAt != null && snapshotAt > position && snapshotAt < length) {
29
+ const end = Math.min(position + chunkSize, snapshotAt);
30
+ return { start: position, end, kind: "drain", snapshot: end === snapshotAt, batchYield: true };
31
+ }
32
+ const remaining = length - position;
33
+ if (remaining > (tailSplit ? 1 : chunkSize)) {
34
+ const end = position + (tailSplit ? Math.min(chunkSize, remaining - 1) : chunkSize);
35
+ return { start: position, end, kind: "drain", snapshot: false,
36
+ batchYield: !tailSplit || remaining - 1 > chunkSize };
37
+ }
38
+ return { start: position, end: length, kind: "final", snapshot: false, batchYield: false };
39
+ }
@@ -0,0 +1,7 @@
1
+ /** A complete transaction over every participating target state layer.
2
+ * A failed begin/resolve invalidates the run; its state must be discarded. */
3
+ export interface SpeculativeTransaction {
4
+ canBegin(drafts: number): boolean;
5
+ begin(drafts: number): void;
6
+ resolve(accepted: number): void;
7
+ }
package/src/jobs/db.ts CHANGED
@@ -55,6 +55,10 @@ export class JobStore {
55
55
  this.dbPath = dbPath;
56
56
  this.logsDir = logsDir;
57
57
  this.db = new Database(dbPath);
58
+ // Parent submissions and child progress updates share this WAL database.
59
+ // Wait for a short writer transaction instead of failing a valid job with
60
+ // SQLITE_BUSY while the other process commits its terminal event.
61
+ this.db.exec("PRAGMA busy_timeout = 5000");
58
62
  this.db.exec("PRAGMA journal_mode = WAL");
59
63
  this.db.exec(SCHEMA);
60
64
  this.migrate();
package/src/jobs/index.ts CHANGED
@@ -8,6 +8,8 @@ export {
8
8
  getRunner,
9
9
  submitInProcess,
10
10
  submitSubprocess,
11
+ closeSubprocessJobs,
12
+ closeInProcessJobs,
11
13
  makeEmit,
12
14
  isGpuBusy,
13
15
  currentGpuJob,
@@ -7,17 +7,19 @@
7
7
  // the runner, runs it with a log-appending emit, sets terminal status, and
8
8
  // exits 0 (done) / 1 (failed).
9
9
 
10
+ import { createJobTaskClient } from "./task-client";
10
11
  import { JobStore } from "./db";
11
12
  import { getRunner, makeEmit } from "./runner";
12
13
  import type { JobRunner } from "./types";
14
+ import { runtimeValue } from "../runtime-config";
13
15
 
14
16
  /** kind → module to dynamically import so it registers its runner. Real job
15
17
  * kinds are built by parallel efforts; importing the module is expected to
16
18
  * call `registerRunner(kind, ...)` at top level. Missing module ⇒ the job
17
19
  * fails cleanly (see resolveRunner). */
18
- const KIND_MODULES: Record<string, string> = {
19
- quantize: "../quantize/job.ts",
20
- finetune: "../train/job.ts",
20
+ const KIND_MODULES: Record<string, () => Promise<unknown>> = {
21
+ quantize: () => import("../quantize/job"),
22
+ finetune: () => import("../train/job"),
21
23
  };
22
24
 
23
25
  /** Resolve a runner for `kind`. Test kinds (noop/crash) are pre-registered in
@@ -27,19 +29,19 @@ async function resolveRunner(kind: string): Promise<JobRunner> {
27
29
  const existing = getRunner(kind);
28
30
  if (existing) return existing;
29
31
 
30
- const modPath = KIND_MODULES[kind];
31
- if (modPath) {
32
+ const load = KIND_MODULES[kind];
33
+ if (load) {
32
34
  try {
33
- await import(modPath);
35
+ await load();
34
36
  } catch (e) {
35
37
  throw new Error(
36
- `kind "${kind}": failed to load runner module ${modPath} ` +
38
+ `kind "${kind}": failed to load runner module ${kind} ` +
37
39
  `(${e instanceof Error ? e.message : String(e)})`,
38
40
  );
39
41
  }
40
42
  const loaded = getRunner(kind);
41
43
  if (loaded) return loaded;
42
- throw new Error(`kind "${kind}": module ${modPath} did not register a runner`);
44
+ throw new Error(`kind "${kind}": module ${kind} did not register a runner`);
43
45
  }
44
46
  throw new Error(`no runner registered for kind "${kind}"`);
45
47
  }
@@ -48,8 +50,7 @@ function nowIso(): string {
48
50
  return new Date().toISOString().replace("T", " ").slice(0, 19);
49
51
  }
50
52
 
51
- async function main(): Promise<void> {
52
- const jobId = process.argv[2];
53
+ export async function runJobEntry(jobId = process.argv[2]): Promise<void> {
53
54
  if (!jobId) {
54
55
  console.error("usage: bun job-entry.ts <jobId>");
55
56
  process.exit(2);
@@ -58,8 +59,8 @@ async function main(): Promise<void> {
58
59
  // Own fresh connection — overrides come from env so a spawned child finds
59
60
  // the same DB/logs the parent used (tests set these to a tmp dir).
60
61
  const store = new JobStore(
61
- process.env.MLX_BUN_JOBS_DB || undefined,
62
- process.env.MLX_BUN_JOBS_DIR || undefined,
62
+ runtimeValue("MLX_BUN_JOBS_DB") || undefined,
63
+ runtimeValue("MLX_BUN_JOBS_DIR") || undefined,
63
64
  );
64
65
 
65
66
  const row = store.get(jobId);
@@ -86,7 +87,7 @@ async function main(): Promise<void> {
86
87
 
87
88
  try {
88
89
  const runner = await resolveRunner(row.kind);
89
- const result = await runner(emit, config);
90
+ const result = await createJobTaskClient(runner).run(config, emit);
90
91
  const out = result?.outputPath;
91
92
  if (out) store.setOutputPath(jobId, out);
92
93
  store.setProgress(jobId, 1);
@@ -103,4 +104,4 @@ async function main(): Promise<void> {
103
104
  }
104
105
  }
105
106
 
106
- main();
107
+ if (import.meta.main) void runJobEntry();