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
@@ -1,3 +1,4 @@
1
+ import { CancellationSource } from "../engine/cancellation";
1
2
  // Job runner: turns a registered `JobRunner` into a tracked, logged job.
2
3
  // Two execution modes — both create a row, both stream NDJSON events to the
3
4
  // log, both own terminal status:
@@ -14,6 +15,8 @@
14
15
  // Port of optiq lab jobs.py `submit` + `_job_main`, split across this file
15
16
  // and job-entry.ts.
16
17
 
18
+ import type { DisposableResource } from "../contracts/resources";
19
+ import { createJobTaskClient } from "./task-client";
17
20
  import { appendFileSync } from "node:fs";
18
21
  import { fileURLToPath } from "node:url";
19
22
  import type { Emit, JobEvent, JobRunner } from "./types";
@@ -104,18 +107,28 @@ export interface SubmitResult {
104
107
  * on success sets 'done'/progress 1/ended_at + emits 'done', on throw sets
105
108
  * 'failed'/error/ended_at + emits 'failed'. Returns once the task is
106
109
  * scheduled (does not await completion — poll the row / tail the log). */
110
+ interface InProcessWork { cancellation: CancellationSource; done: Promise<void>; }
111
+ const inProcess = new WeakMap<JobStore, Set<InProcessWork>>();
112
+
107
113
  export function submitInProcess(
108
114
  store: JobStore,
109
115
  kind: string,
110
116
  config: Record<string, unknown>,
111
117
  outputPath?: string,
112
118
  ): SubmitResult {
119
+ if (closedStores.has(store)) throw new Error("job host is closed");
113
120
  const row = store.create(kind, config, outputPath);
114
121
  const emit = makeEmit(store, row.id, row.log_path);
115
122
  store.setStatus(row.id, "running");
116
123
  emit({ type: "started", ts: Date.now() });
117
124
 
118
125
  const runner = getRunner(kind);
126
+ const cancellation = new CancellationSource();
127
+ const running = inProcess.get(store) ?? new Set<InProcessWork>();
128
+ inProcess.set(store, running);
129
+ let finish!: () => void;
130
+ const work = { cancellation, done: new Promise<void>((resolve) => { finish = resolve; }) };
131
+ running.add(work);
119
132
  void (async () => {
120
133
  if (!runner) {
121
134
  const error = `no runner registered for kind "${kind}"`;
@@ -124,7 +137,7 @@ export function submitInProcess(
124
137
  return;
125
138
  }
126
139
  try {
127
- const result = await runner(emit, JSON.parse(row.config_json));
140
+ const result = await createJobTaskClient(runner).run(JSON.parse(row.config_json), emit, cancellation);
128
141
  const out = result?.outputPath;
129
142
  if (out) store.setOutputPath(row.id, out);
130
143
  store.setProgress(row.id, 1);
@@ -135,7 +148,7 @@ export function submitInProcess(
135
148
  store.setStatus(row.id, "failed", { error, endedAt: nowIso() });
136
149
  emit({ type: "failed", error, ts: Date.now() });
137
150
  }
138
- })();
151
+ })().finally(() => { running.delete(work); finish(); });
139
152
 
140
153
  return { jobId: row.id, outputPath };
141
154
  }
@@ -145,16 +158,25 @@ export function submitInProcess(
145
158
  // ---------------------------------------------------------------------------
146
159
 
147
160
  interface QueuedSpawn {
161
+ acquire?: (signal: AbortSignal) => Promise<DisposableResource>;
162
+ lease?: DisposableResource;
163
+ abort: AbortController;
164
+ proc?: Bun.Subprocess;
165
+ finished: Promise<void>;
166
+ finish(): void;
148
167
  store: JobStore;
149
168
  jobId: string;
150
169
  entry: string;
151
170
  bin: string;
171
+ compiled: boolean;
152
172
  spawn: typeof Bun.spawn;
153
173
  onComplete?: (jobId: string, code: number) => void;
154
174
  }
155
175
 
156
176
  let gpuLeaseHolder: string | null = null;
157
177
  const spawnQueue: QueuedSpawn[] = [];
178
+ let activeSpawn: QueuedSpawn | undefined;
179
+ const closedStores = new WeakSet<JobStore>();
158
180
 
159
181
  /** True while a GPU (subprocess) job is running — the server gates token
160
182
  * generation on this so quantize/finetune don't fight live inference. */
@@ -168,6 +190,8 @@ export function currentGpuJob(): string | null {
168
190
  }
169
191
 
170
192
  export interface SubprocessOpts {
193
+ /** Host execution lease, held until child exit (including crashes). */
194
+ acquire?: (signal: AbortSignal) => Promise<DisposableResource>;
171
195
  /** Override the entry script (tests). Defaults to JOB_ENTRY_PATH. */
172
196
  entry?: string;
173
197
  /** Override the runtime binary (tests). Defaults to "bun". */
@@ -189,14 +213,20 @@ export function submitSubprocess(
189
213
  outputPath?: string,
190
214
  opts: SubprocessOpts = {},
191
215
  ): SubmitResult {
216
+ if (closedStores.has(store)) throw new Error("job host is closed");
192
217
  const row = store.create(kind, config, outputPath);
218
+ let finish!: () => void;
219
+ const finished = new Promise<void>((resolve) => { finish = resolve; });
193
220
  const item: QueuedSpawn = {
221
+ abort: new AbortController(), finished, finish,
194
222
  store,
195
223
  jobId: row.id,
196
224
  entry: opts.entry ?? JOB_ENTRY_PATH,
225
+ compiled: opts.entry === undefined && opts.bin === undefined && JOB_ENTRY_PATH.includes("$bunfs"),
197
226
  bin: opts.bin ?? "bun",
198
227
  spawn: opts.spawn ?? Bun.spawn,
199
228
  onComplete: opts.onComplete,
229
+ acquire: opts.acquire,
200
230
  };
201
231
  spawnQueue.push(item);
202
232
  drainQueue();
@@ -215,7 +245,7 @@ function spawnNow(item: QueuedSpawn): void {
215
245
  // a file-backed DB.
216
246
  let proc: Bun.Subprocess<"ignore", "pipe", "pipe">;
217
247
  try {
218
- proc = spawn([bin, entry, jobId], {
248
+ proc = spawn(item.compiled ? [process.execPath, "__job", jobId] : [bin, entry, jobId], {
219
249
  stdout: "pipe",
220
250
  stderr: "pipe",
221
251
  env: {
@@ -230,14 +260,16 @@ function spawnNow(item: QueuedSpawn): void {
230
260
  error: errString(e),
231
261
  endedAt: nowIso(),
232
262
  });
263
+ } catch (error) {
264
+ console.error(`[jobs] failed to record spawn failure: ${errString(error)}`);
233
265
  } finally {
234
- releaseLease(jobId);
266
+ releaseLease(item);
235
267
  }
236
268
  return;
237
269
  }
238
270
 
239
- const row = store.get(jobId);
240
- const logPath = row?.log_path;
271
+ item.proc = proc;
272
+ const logPath = store.get(jobId)?.log_path;
241
273
  const logLine = (line: string) => {
242
274
  if (!line || !logPath) return;
243
275
  const ev: JobEvent = { type: "log", line };
@@ -252,7 +284,7 @@ function spawnNow(item: QueuedSpawn): void {
252
284
  // code 0 ⇒ trust the child's terminal status (it set done/failed itself).
253
285
  // non-zero ⇒ if the row never reached terminal (crash before the wrapper
254
286
  // could write), force it failed.
255
- if (code !== 0) {
287
+ try { if (code !== 0) {
256
288
  const cur = store.get(jobId);
257
289
  if (cur && (cur.status === "queued" || cur.status === "running")) {
258
290
  store.setStatus(jobId, "failed", {
@@ -260,15 +292,25 @@ function spawnNow(item: QueuedSpawn): void {
260
292
  endedAt: nowIso(),
261
293
  });
262
294
  }
295
+ } } catch (error) {
296
+ console.error(`[jobs] failed to record child exit: ${errString(error)}`);
297
+ } finally {
298
+ releaseLease(item);
299
+ try { item.onComplete?.(jobId, code); } catch {}
300
+ drainQueue();
263
301
  }
264
- releaseLease(jobId);
265
- try { item.onComplete?.(jobId, code); } catch {}
266
- drainQueue();
267
302
  })();
268
303
  }
269
304
 
270
- function releaseLease(jobId: string): void {
271
- if (gpuLeaseHolder === jobId) gpuLeaseHolder = null;
305
+ function releaseLease(item: QueuedSpawn): void {
306
+ try { item.lease?.dispose(); }
307
+ catch (error) { console.error(`[jobs] execution lease cleanup failed: ${errString(error)}`); }
308
+ finally {
309
+ item.lease = undefined;
310
+ if (gpuLeaseHolder === item.jobId) gpuLeaseHolder = null;
311
+ if (activeSpawn === item) activeSpawn = undefined;
312
+ item.finish();
313
+ }
272
314
  }
273
315
 
274
316
  /** Run the next queued subprocess job if the lease is free. */
@@ -279,8 +321,51 @@ export function drainQueue(): void {
279
321
  // A synchronous spawn failure releases the lease. Keep draining
280
322
  // iteratively so a run of bad queue entries cannot recurse or wedge the
281
323
  // first startable job behind them.
282
- spawnNow(next);
324
+ activeSpawn = next;
325
+ if (next.acquire) {
326
+ gpuLeaseHolder = next.jobId; // reserve FIFO order while inference drains
327
+ void Promise.resolve().then(() => next.acquire!(next.abort.signal)).then((lease) => {
328
+ next.lease = lease;
329
+ if (next.abort.signal.aborted) throw next.abort.signal.reason;
330
+ spawnNow(next);
331
+ }).catch((error) => {
332
+ try {
333
+ next.store.setStatus(next.jobId, "failed", { error: errString(error), endedAt: nowIso() });
334
+ } catch (recordError) {
335
+ console.error(`[jobs] failed to record admission failure: ${errString(recordError)}`);
336
+ } finally { releaseLease(next); }
337
+ }).finally(drainQueue);
338
+ } else spawnNow(next);
339
+ }
340
+ }
341
+
342
+ /** Dataset work stays in-process, but belongs to the application host too. */
343
+ export async function closeInProcessJobs(store: JobStore): Promise<void> {
344
+ closedStores.add(store);
345
+ const active = [...inProcess.get(store) ?? []];
346
+ for (const work of active) work.cancellation.cancel("engine_closed");
347
+ await Promise.all(active.map((work) => work.done));
348
+ }
349
+
350
+ /** Stop only this host's managed GPU jobs. Await process death before releasing
351
+ * the execution lease; queued and admission-waiting jobs never spawn. */
352
+ export async function closeSubprocessJobs(store: JobStore): Promise<void> {
353
+ closedStores.add(store);
354
+ for (let i = spawnQueue.length - 1; i >= 0; i--) {
355
+ const item = spawnQueue[i]!;
356
+ if (item.store !== store) continue;
357
+ spawnQueue.splice(i, 1);
358
+ store.setStatus(item.jobId, "failed", { error: "job host closed", endedAt: nowIso() });
359
+ item.finish();
283
360
  }
361
+ const active = activeSpawn;
362
+ if (!active || active.store !== store) return;
363
+ active.abort.abort(new Error("job host closed"));
364
+ const proc = active.proc;
365
+ if (proc) proc.kill("SIGTERM");
366
+ const force = proc ? setTimeout(() => { if (proc.exitCode === null) proc.kill("SIGKILL"); }, 3000) : undefined;
367
+ try { await active.finished; }
368
+ finally { if (force) clearTimeout(force); }
284
369
  }
285
370
 
286
371
  /** Read a child stream line-by-line, buffering partial trailing lines, and
@@ -0,0 +1,19 @@
1
+ import type { TaskClient } from "../contracts/completion";
2
+ import { throwIfCancelled } from "../engine/cancellation";
3
+ import type { JobEvent, JobRunner } from "./types";
4
+
5
+ /** Numerical runners retain their artifact policy; the client owns delivery
6
+ * and cooperative cancellation at progress boundaries. No event buffering. */
7
+ export function createJobTaskClient(runner: JobRunner): TaskClient<
8
+ Record<string, unknown>, JobEvent, { outputPath?: string } | void
9
+ > {
10
+ return {
11
+ async run(request, report, cancellation) {
12
+ const check = () => { if (cancellation) throwIfCancelled(cancellation); };
13
+ check();
14
+ const result = await runner((event) => { check(); report(event); check(); }, request);
15
+ check();
16
+ return result;
17
+ },
18
+ };
19
+ }
package/src/jobs/types.ts CHANGED
@@ -1,58 +1,2 @@
1
- // Shared job-system contract. Both the job runner (src/jobs/*) and every
2
- // job producer (src/dataset/*, src/quantize/*, src/train/*) speak this
3
- // vocabulary. Mirrors the optiq lab SSE event grammar so the web wizards
4
- // port over mechanically (started → log/stage/metric → done|failed).
5
-
6
- /** A single streamed job event, serialized one-per-line into the job's
7
- * NDJSON log and re-emitted to the browser as SSE `data:` frames. */
8
- export type JobEvent =
9
- | { type: "started"; ts: number }
10
- | { type: "log"; line: string }
11
- | {
12
- type: "stage";
13
- stage: string;
14
- progress?: number; // 0..1
15
- message?: string;
16
- [k: string]: unknown;
17
- }
18
- | {
19
- type: "metric";
20
- kind: "train" | "val";
21
- step: number;
22
- loss: number;
23
- [k: string]: unknown; // grad_norm, learning_rate, tokens_per_sec, accuracy, margin, progress, message
24
- }
25
- | { type: "done"; ts: number; output_dir?: string; summary?: unknown; [k: string]: unknown }
26
- | { type: "failed"; error: string; ts: number };
27
-
28
- /** Sink a job calls to report progress. Implementations append to the log
29
- * file and (for stage/metric events carrying `progress`/`message`) update
30
- * the SQLite row. Never throws — a logging failure must not kill a job. */
31
- export type Emit = (e: JobEvent) => void;
32
-
33
- /** The unit of work. Returns an optional output path recorded on the row.
34
- * Receives the parsed `config` from the submit request. */
35
- export type JobRunner = (
36
- emit: Emit,
37
- config: Record<string, unknown>,
38
- ) => Promise<{ outputPath?: string } | void>;
39
-
40
- /** Job kinds in the system. */
41
- export type JobKind = "quantize" | "finetune" | "dataset" | "noop" | "crash";
42
-
43
- export type JobStatus = "queued" | "running" | "done" | "failed" | "zombie";
44
-
45
- /** A persisted job row (shape returned by the HTTP `GET /api/jobs/:id`). */
46
- export interface JobRow {
47
- id: string;
48
- kind: string;
49
- status: JobStatus;
50
- config_json: string;
51
- progress: number;
52
- message: string | null;
53
- log_path: string;
54
- output_path: string | null;
55
- error: string | null;
56
- started_at: string;
57
- ended_at: string | null;
58
- }
1
+ /** Compatibility exports; producer and browser share the portable wire contract. */
2
+ export type * from "../contracts/jobs";
@@ -0,0 +1,199 @@
1
+ import type { KvQuantSpec, ModelConfig, TurboQuantScheme } from "./config";
2
+
3
+ const BF16_BYTES = 2;
4
+
5
+ export type KvQuantOverride = "off" | "config" | number | undefined;
6
+
7
+ export interface KvSchemeOptions {
8
+ kvBits?: number;
9
+ kvGroupSize?: number;
10
+ kvConfig?: KvQuantSpec[];
11
+ quantizedKvStart?: number;
12
+ turboQuant?: TurboQuantScheme;
13
+ }
14
+
15
+ interface ResolvedKvSchemeOptions extends Omit<KvSchemeOptions, "kvConfig" | "turboQuant"> {
16
+ readonly kvConfig?: readonly Readonly<KvQuantSpec>[];
17
+ readonly turboQuant?: Readonly<TurboQuantScheme>;
18
+ }
19
+
20
+ export type KvSchemeKind = "bf16" | "affine-uniform" | "affine-config" | "turbo";
21
+
22
+ export interface KvGeometry {
23
+ fullBytesPerToken: number;
24
+ slidingBytesPerToken: number;
25
+ linearStateBytes: number;
26
+ window: number;
27
+ }
28
+
29
+ /** Bytes per stored affine-quantized KV element, including scale and bias. */
30
+ export function kvQuantBytesPerElement(bits: number, groupSize: number): number {
31
+ return bits / 8 + 4 / groupSize;
32
+ }
33
+
34
+ export function kvGeometry(config: ModelConfig, options: KvSchemeOptions = {}): KvGeometry {
35
+ const text = config.text;
36
+ const byLayer = options.kvConfig?.length
37
+ ? new Map(options.kvConfig.map((entry) => [entry.layerIdx, entry]))
38
+ : null;
39
+ const uniformBytes = options.kvBits
40
+ ? kvQuantBytesPerElement(options.kvBits, options.kvGroupSize ?? 64)
41
+ : BF16_BYTES;
42
+ const elementBytes = (layer: number): number => {
43
+ const entry = byLayer?.get(layer);
44
+ return entry
45
+ ? kvQuantBytesPerElement(entry.bits, entry.groupSize)
46
+ : byLayer ? BF16_BYTES : uniformBytes;
47
+ };
48
+
49
+ let linearLayers = 0;
50
+ let fullBytesPerToken = 0;
51
+ let slidingBytesPerToken = 0;
52
+ for (let layer = 0; layer < text.numHiddenLayers; layer++) {
53
+ const type = text.layerTypes[layer] ?? "full_attention";
54
+ if (type === "linear_attention") {
55
+ linearLayers++;
56
+ } else if (type === "sliding_attention") {
57
+ slidingBytesPerToken +=
58
+ 2 * text.numKeyValueHeads * text.headDim * elementBytes(layer);
59
+ } else {
60
+ fullBytesPerToken +=
61
+ 2 * text.numGlobalKeyValueHeads * text.globalHeadDim * elementBytes(layer);
62
+ }
63
+ }
64
+ const convDim = 2 * text.linearNumKeyHeads * text.linearKeyHeadDim +
65
+ text.linearNumValueHeads * text.linearValueHeadDim;
66
+ const linearStateBytes = linearLayers === 0 ? 0 : linearLayers * (
67
+ text.linearNumValueHeads * text.linearValueHeadDim * text.linearKeyHeadDim * 4 +
68
+ Math.max(0, text.linearConvKernelDim - 1) * convDim * BF16_BYTES
69
+ );
70
+ return {
71
+ fullBytesPerToken,
72
+ slidingBytesPerToken,
73
+ linearStateBytes,
74
+ window: text.slidingWindow,
75
+ };
76
+ }
77
+
78
+ export function kvBytesAt(
79
+ config: ModelConfig,
80
+ tokens: number,
81
+ options: KvSchemeOptions = {},
82
+ ): number {
83
+ const value = kvGeometry(config, options);
84
+ return value.fullBytesPerToken * tokens +
85
+ value.slidingBytesPerToken * Math.min(tokens, value.window) +
86
+ value.linearStateBytes;
87
+ }
88
+
89
+ export class KvScheme {
90
+ readonly kind: KvSchemeKind;
91
+ readonly options: Readonly<ResolvedKvSchemeOptions>;
92
+
93
+ constructor(kind: KvSchemeKind, options: KvSchemeOptions) {
94
+ this.kind = kind;
95
+ const kvConfig = options.kvConfig?.map((entry) =>
96
+ Object.freeze({ ...entry }),
97
+ );
98
+ const turboQuant = options.turboQuant
99
+ ? Object.freeze({ ...options.turboQuant })
100
+ : undefined;
101
+ this.options = Object.freeze({
102
+ ...options,
103
+ ...(kvConfig ? { kvConfig: Object.freeze(kvConfig) } : {}),
104
+ ...(turboQuant ? { turboQuant } : {}),
105
+ });
106
+ }
107
+
108
+ get quantized(): boolean {
109
+ return this.kind !== "bf16";
110
+ }
111
+
112
+ get cacheKey(): string {
113
+ if (this.kind === "turbo") {
114
+ const turbo = this.options.turboQuant!;
115
+ return `turbo-k${turbo.kBits}v${turbo.vBits}`;
116
+ }
117
+ if (this.kind === "affine-uniform") return `kv${this.options.kvBits}`;
118
+ if (this.kind === "affine-config") return "config";
119
+ return "bf16";
120
+ }
121
+
122
+ get label(): string {
123
+ if (this.kind === "turbo") {
124
+ const turbo = this.options.turboQuant!;
125
+ return `turbo k${turbo.kBits}v${turbo.vBits}`;
126
+ }
127
+ if (this.kind === "affine-uniform") return `uniform-kv${this.options.kvBits}`;
128
+ if (this.kind === "affine-config") return "mixed (kv_config.json)";
129
+ return "bf16";
130
+ }
131
+
132
+ bytesAt(config: ModelConfig, tokens: number): number {
133
+ // TurboQuant stays conservatively billed as bf16 until its packed layout
134
+ // exposes a stable projector.
135
+ return kvBytesAt(config, tokens, this.fitOptions);
136
+ }
137
+
138
+ /** Mutable compatibility value for the numerical generator. The scheme
139
+ * keeps its declaration immutable and hands legacy consumers owned copies. */
140
+ get generationOptions(): KvSchemeOptions {
141
+ const { kvConfig, turboQuant, ...scalar } = this.options;
142
+ return {
143
+ ...scalar,
144
+ ...(kvConfig
145
+ ? { kvConfig: kvConfig.map((entry) => ({ ...entry })) }
146
+ : {}),
147
+ ...(turboQuant
148
+ ? { turboQuant: { ...turboQuant } }
149
+ : {}),
150
+ };
151
+ }
152
+
153
+ get fitOptions(): KvSchemeOptions {
154
+ return this.kind === "turbo" ? {} : this.generationOptions;
155
+ }
156
+
157
+ /** The current batch engine accepts only per-layer affine schemes whose
158
+ * named cache instances can perform the required conversion. The capability
159
+ * probe is mandatory for quantized schemes so config shape alone can never
160
+ * authorize placement. */
161
+ batchable(config: ModelConfig, canConvert?: (layerIdx: number) => boolean): boolean {
162
+ if (this.kind === "bf16") return true;
163
+ if (this.kind !== "affine-config") return false;
164
+ if (!canConvert) return false;
165
+ return this.options.kvConfig!.every((entry) => {
166
+ if (entry.layerIdx < 0 || entry.layerIdx >= config.text.numHiddenLayers) return false;
167
+ return (config.text.layerTypes[entry.layerIdx] ?? "full_attention") !== "linear_attention" &&
168
+ canConvert(entry.layerIdx);
169
+ });
170
+ }
171
+ }
172
+
173
+ export function resolveKvScheme(input: {
174
+ override?: KvQuantOverride;
175
+ turboQuant?: TurboQuantScheme;
176
+ config?: readonly KvQuantSpec[] | null;
177
+ missingConfig?: "bf16" | "error";
178
+ }): KvScheme {
179
+ if (input.turboQuant) {
180
+ return new KvScheme("turbo", {
181
+ turboQuant: input.turboQuant,
182
+ quantizedKvStart: 0,
183
+ });
184
+ }
185
+ if (input.override === "off" || input.override === undefined)
186
+ return new KvScheme("bf16", {});
187
+ if (input.override === "config") {
188
+ if (!input.config?.length) {
189
+ if (input.missingConfig === "error")
190
+ throw new Error("model has no kv_config.json (--kv-quant config)");
191
+ return new KvScheme("bf16", {});
192
+ }
193
+ return new KvScheme("affine-config", { kvConfig: [...input.config] });
194
+ }
195
+ return new KvScheme("affine-uniform", {
196
+ kvBits: input.override,
197
+ quantizedKvStart: 0,
198
+ });
199
+ }