mlx-bun 0.0.13 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (427) hide show
  1. package/README.md +71 -578
  2. package/bin/mlx-bun.mjs +1 -1
  3. package/docs/README.md +91 -0
  4. package/docs/{design → archive}/hlg-sampling.md +3 -3
  5. package/docs/{design → archive/investigations}/audio-input-plan.md +4 -4
  6. package/docs/{design → archive/investigations}/colibri-glm52-port.md +1 -1
  7. package/docs/{design → archive/investigations}/diffusion-gemma-port.md +3 -3
  8. package/docs/{design → archive/investigations}/faithful-l1-consolidation.md +4 -4
  9. package/docs/{investigations → archive/investigations}/hlg-sampling-investigation.md +1 -1
  10. package/docs/{design → archive/investigations}/minicpm5-decode-megakernel.md +11 -11
  11. package/docs/{design → archive/investigations}/optimization_plan.md +1 -1
  12. package/docs/archive/investigations/pareto-specialized-runtime-findings.md +92 -0
  13. package/docs/{design → archive/investigations}/pre-colibri-stabilization.md +5 -5
  14. package/docs/{design → archive/investigations}/the-dreaming-handoff.md +2 -2
  15. package/docs/{planning → archive/planning}/chat-ui-vision.md +1 -1
  16. package/docs/{planning → archive/planning}/chunk-task-roadmap.md +1 -1
  17. package/docs/{planning → archive/planning}/curve-sampler-research-plan.md +4 -4
  18. package/docs/{planning → archive/planning}/memory-docs-and-dag-plan.md +1 -1
  19. package/docs/{planning → archive/planning}/release-notes-v0.0.9.md +1 -1
  20. package/docs/archive/planning/release-notes-v0.2.0.md +49 -0
  21. package/docs/{planning → archive/planning}/website-readme-pass-plan.md +1 -1
  22. package/docs/design/batching.md +569 -0
  23. package/docs/design/decode-speed-program.md +3178 -169
  24. package/docs/design/dreaming-nightly-pipeline.md +675 -282
  25. package/docs/design/generic-model-support.md +579 -334
  26. package/docs/design/kv-cache.md +680 -0
  27. package/docs/design/orpo-training.md +673 -1239
  28. package/docs/design/speculative-decoding.md +1627 -0
  29. package/docs/design/turboquant.md +2102 -0
  30. package/docs/design/unified-engine-frontier-plan.md +1831 -727
  31. package/docs/design/web-chat-redesign.md +666 -1083
  32. package/docs/planning/PRODUCT_ROADMAP.md +34 -1
  33. package/docs/planning/release-notes-v0.3.0.md +35 -0
  34. package/docs/planning/video-series.md +421 -0
  35. package/docs/reference/benchmarks.md +1162 -0
  36. package/docs/reference/cli.md +395 -149
  37. package/docs/reference/distribution.md +321 -181
  38. package/docs/reference/environment.md +348 -0
  39. package/docs/reference/glossary.md +39 -0
  40. package/docs/reference/library-api.md +580 -142
  41. package/docs/reference/memory.md +227 -64
  42. package/docs/reference/models.md +137 -6
  43. package/docs/reference/server-api.md +938 -422
  44. package/docs/reference/server-config.md +652 -320
  45. package/docs/reference/training.md +393 -254
  46. package/docs/reference/troubleshooting.md +166 -0
  47. package/package.json +10 -5
  48. package/src/admission-plan.ts +18 -0
  49. package/src/anthropic.ts +92 -3
  50. package/src/audio/decode.ts +2 -2
  51. package/src/audio/features.ts +2 -2
  52. package/src/backends/mlx/autoregressive.ts +108 -0
  53. package/src/backends/mlx/batch-group.ts +1646 -0
  54. package/src/backends/mlx/diffusion.ts +39 -0
  55. package/src/backends/mlx/draft-target.ts +47 -0
  56. package/src/backends/mlx/evaluation.ts +105 -0
  57. package/src/backends/mlx/fill-append.ts +45 -0
  58. package/src/backends/mlx/gateway-binding.ts +71 -0
  59. package/src/backends/mlx/graph.ts +38 -0
  60. package/src/backends/mlx/memory-client.ts +189 -0
  61. package/src/backends/mlx/memory-guard.ts +40 -0
  62. package/src/backends/mlx/methods.ts +90 -0
  63. package/src/backends/mlx/model-prompt.ts +164 -0
  64. package/src/backends/mlx/model-serving.ts +79 -0
  65. package/src/backends/mlx/prefill.ts +33 -0
  66. package/src/backends/mlx/request-policy.ts +20 -0
  67. package/src/backends/mlx/rollback.ts +51 -0
  68. package/src/backends/mlx/serial-executor.ts +273 -0
  69. package/src/backends/mlx/speculative.ts +114 -0
  70. package/src/backends/mlx/state-views.ts +26 -0
  71. package/src/backends/mlx/text-engine.ts +73 -0
  72. package/src/cli.ts +189 -61
  73. package/src/client.ts +66 -0
  74. package/src/config.ts +21 -4
  75. package/src/contracts/completion.ts +16 -0
  76. package/src/contracts/execution.ts +49 -0
  77. package/src/contracts/generation.ts +103 -0
  78. package/src/contracts/host.ts +7 -0
  79. package/src/contracts/jobs.ts +66 -0
  80. package/src/contracts/pi-provider.ts +30 -0
  81. package/src/contracts/pi.ts +259 -0
  82. package/src/contracts/resources.ts +18 -0
  83. package/src/contracts/scheduling.ts +27 -0
  84. package/src/contracts/tsconfig.json +14 -0
  85. package/src/diffusion/diffusion-generate.ts +218 -153
  86. package/src/embed.ts +1 -1
  87. package/src/engine/admission.ts +59 -0
  88. package/src/engine/cancellation.ts +38 -0
  89. package/src/engine/engine.ts +56 -0
  90. package/src/engine/execution-coordinator.ts +70 -0
  91. package/src/engine/execution-plan.ts +51 -0
  92. package/src/engine/resources.ts +42 -0
  93. package/src/engine/scheduler.ts +67 -0
  94. package/src/engine/session.ts +247 -0
  95. package/src/eval/README.md +44 -1
  96. package/src/eval/kl.ts +263 -23
  97. package/src/eval/reference-logits.ts +207 -0
  98. package/src/eval/runner.ts +10 -79
  99. package/src/eval/tasks/bfcl.ts +2 -1
  100. package/src/eval/tasks/gsm8k.ts +2 -1
  101. package/src/eval/tasks/hashhop.ts +2 -1
  102. package/src/eval/tasks/humaneval.ts +5 -4
  103. package/src/eval/tasks/ifeval.ts +2 -1
  104. package/src/eval/tasks/mmlu.ts +2 -1
  105. package/src/expert-io.ts +3 -1
  106. package/src/expert-offload.ts +3 -1
  107. package/src/fill/echo-index.ts +188 -0
  108. package/src/fill/fill-session.ts +452 -0
  109. package/src/fill/proposal.ts +68 -0
  110. package/src/fill/schema-rows.ts +506 -0
  111. package/src/fill/tool-boundary.ts +103 -0
  112. package/src/fit.ts +24 -43
  113. package/src/generate.ts +740 -337
  114. package/src/grammar.ts +14 -8
  115. package/src/harness-pi.ts +15 -34
  116. package/src/hub-rest.ts +4 -4
  117. package/src/index.ts +27 -0
  118. package/src/inference/denoising.ts +17 -0
  119. package/src/inference/graph.ts +33 -0
  120. package/src/inference/prefill.ts +39 -0
  121. package/src/inference/rollback.ts +7 -0
  122. package/src/jobs/db.ts +4 -0
  123. package/src/jobs/index.ts +2 -0
  124. package/src/jobs/job-entry.ts +15 -14
  125. package/src/jobs/runner.ts +98 -13
  126. package/src/jobs/task-client.ts +19 -0
  127. package/src/jobs/types.ts +2 -58
  128. package/src/kv-scheme.ts +199 -0
  129. package/src/kv-store.ts +459 -234
  130. package/src/lab/README.md +18 -0
  131. package/src/{assets → lab/curve}/curve-designer.html +2 -2
  132. package/src/{curve-sampler.ts → lab/curve/curve-sampler.ts} +2 -2
  133. package/src/{expert-trace.ts → lab/expert-trace/expert-trace.ts} +7 -5
  134. package/src/{model → lab/paged-kv}/paged-kv.ts +9 -6
  135. package/src/library.ts +40 -0
  136. package/src/lora.ts +18 -0
  137. package/src/media-fetch.ts +20 -4
  138. package/src/memory/article.ts +1 -1
  139. package/src/memory/chunk.ts +1 -1
  140. package/src/memory/model.ts +32 -170
  141. package/src/memory/prompts.ts +1 -1
  142. package/src/memory/rest.ts +1 -1
  143. package/src/memory/schedule.ts +1 -1
  144. package/src/memory/stages.ts +4 -1
  145. package/src/memory/vault.ts +3 -4
  146. package/src/mlx/array.ts +9 -10
  147. package/src/mlx/compile.ts +12 -2
  148. package/src/mlx/ffi.ts +66 -22
  149. package/src/mlx/materialize.ts +23 -0
  150. package/src/mlx/metal-kernel.ts +10 -11
  151. package/src/mlx/ops.ts +64 -19
  152. package/src/mlx/quantized-rows.ts +36 -0
  153. package/src/mlx/token-bitmask.ts +52 -0
  154. package/src/mlx/turboquant-kv-decode.ts +82 -0
  155. package/src/mlx/turboquant-kv-inverse.ts +122 -0
  156. package/src/mlx/turboquant-ops.ts +33 -3
  157. package/src/mlx/turboquant-tables.ts +2 -2
  158. package/src/model/batched-mask.ts +9 -3
  159. package/src/model/batched-quant.ts +2 -2
  160. package/src/model/batched-rotating-quant.ts +45 -99
  161. package/src/model/batched-rotating-state.ts +73 -0
  162. package/src/model/batched-rotating.ts +57 -106
  163. package/src/model/batched-row-storage.ts +127 -0
  164. package/src/model/compiled-decode.ts +4 -3
  165. package/src/model/diffusion-gemma.ts +8 -8
  166. package/src/model/factory.ts +87 -49
  167. package/src/model/fingerprint.ts +1 -1
  168. package/src/model/flash-attention.ts +3 -3
  169. package/src/model/gemma4-base.ts +187 -17
  170. package/src/model/gemma4.ts +6 -6
  171. package/src/model/generated/gemma4-12b.ts +52 -148
  172. package/src/model/generated/gemma4-26b.ts +34 -94
  173. package/src/model/generated/gemma4-e4b.ts +28 -76
  174. package/src/model/glm52-cache.ts +19 -9
  175. package/src/model/glm52-dsa.ts +13 -9
  176. package/src/model/glm52-memory.ts +28 -1
  177. package/src/model/implementation.ts +69 -0
  178. package/src/model/minicpm5.ts +7 -8
  179. package/src/model/profile.ts +443 -0
  180. package/src/model/qwen-append.ts +12 -0
  181. package/src/model/qwen-conv.ts +52 -0
  182. package/src/model/qwen3-delta.ts +98 -2
  183. package/src/model/qwen3-mrope.ts +252 -0
  184. package/src/model/qwen3_5-checkpoint.ts +164 -0
  185. package/src/model/qwen3_5.ts +336 -60
  186. package/src/model/support.ts +1 -1
  187. package/src/model/trellis-balanced-scatter.ts +51 -0
  188. package/src/model/trellis-linear.ts +672 -0
  189. package/src/model/trellis-shared-m.ts +151 -0
  190. package/src/model/trellis-shared-scatter.ts +144 -0
  191. package/src/model/trellis-splitk-prefill.ts +158 -0
  192. package/src/model/trellis-tiled-prefill.ts +136 -0
  193. package/src/model/trellis-vector-expand.ts +62 -0
  194. package/src/model/trellis-wide-prefill.ts +94 -0
  195. package/src/model/universal/dense.ts +1 -1
  196. package/src/model/universal/modules.ts +8 -1
  197. package/src/native/frame_extract.swift +140 -0
  198. package/src/native-pack.ts +15 -7
  199. package/src/pi-provider.ts +6 -64
  200. package/src/pi-web.ts +14 -320
  201. package/src/prompt-cache.ts +97 -54
  202. package/src/quantize/allocator.ts +1 -1
  203. package/src/quantize/atomic-output.ts +38 -0
  204. package/src/quantize/calibration.ts +2 -1
  205. package/src/quantize/config-writer.ts +16 -3
  206. package/src/quantize/index.ts +28 -1
  207. package/src/quantize/job.ts +11 -0
  208. package/src/quantize/quantizer.ts +265 -100
  209. package/src/quantize/rotate.ts +603 -0
  210. package/src/quantize/safetensors-writer.ts +79 -1
  211. package/src/quantize/sensitivity.ts +41 -59
  212. package/src/quantize/trellis.ts +586 -0
  213. package/src/quantize/weight-transform.ts +292 -0
  214. package/src/responses.ts +130 -3
  215. package/src/runtime-config.ts +81 -0
  216. package/src/sampler.ts +276 -4
  217. package/src/serve/admin-routes.ts +184 -0
  218. package/src/serve/aux-routes.ts +132 -0
  219. package/src/serve/batch-scheduler.ts +8 -1558
  220. package/src/serve/chat-request.ts +391 -0
  221. package/src/serve/chat-stage.ts +195 -0
  222. package/src/serve/checkpoint-identity.ts +64 -0
  223. package/src/serve/completion-executor.ts +354 -0
  224. package/src/serve/completion-sink.ts +157 -0
  225. package/src/serve/discovery-routes.ts +204 -0
  226. package/src/serve/generation-gateway.ts +211 -243
  227. package/src/serve/http.ts +159 -0
  228. package/src/serve/inference-request.ts +79 -0
  229. package/src/serve/isolate.ts +297 -105
  230. package/src/serve/kv-budget.ts +14 -0
  231. package/src/serve/lab-routes.ts +341 -0
  232. package/src/serve/lane-registry.ts +2 -1
  233. package/src/serve/model-admin-routes.ts +155 -0
  234. package/src/serve/model-binding.ts +43 -0
  235. package/src/serve/model-host.ts +512 -0
  236. package/src/serve/openai-wire.ts +103 -0
  237. package/src/serve/parent-application.ts +56 -0
  238. package/src/serve/pipeline.ts +33 -0
  239. package/src/serve/preparation.ts +33 -0
  240. package/src/serve/prompt-response-trace.ts +147 -0
  241. package/src/serve/request-plan.ts +162 -0
  242. package/src/serve/request-prep.ts +346 -0
  243. package/src/serve/response-lease.ts +24 -0
  244. package/src/serve/responses-client.ts +69 -0
  245. package/src/serve/session-completion-engine.ts +110 -0
  246. package/src/serve/session-search.ts +1 -1
  247. package/src/serve/static-routes.ts +101 -0
  248. package/src/serve/text-completion-stage.ts +104 -0
  249. package/src/serve/token-streams.ts +519 -0
  250. package/src/server.ts +523 -3551
  251. package/src/spec/assistant-source.ts +10 -44
  252. package/src/spec/deepspec-source.ts +6 -6
  253. package/src/spec/dflash-source.ts +9 -8
  254. package/src/spec/dspark/ab-stats.ts +3 -3
  255. package/src/spec/dspark/calibration.ts +2 -2
  256. package/src/spec/dspark/deepspec-module.ts +2 -2
  257. package/src/spec/dspark/generate-dflash.ts +2 -2
  258. package/src/spec/dspark/generate.ts +2 -2
  259. package/src/spec/dspark/loader.ts +1 -1
  260. package/src/spec/dspark/module-dflash.ts +5 -4
  261. package/src/spec/dspark/module.ts +3 -3
  262. package/src/spec/dspark/quantize-drafter.ts +1 -1
  263. package/src/spec/generate.ts +1 -1
  264. package/src/spec/glm52-mtp-source.ts +9 -1
  265. package/src/spec/ngram-source.ts +1 -1
  266. package/src/spec/prefix-state.ts +45 -0
  267. package/src/spec/qwen-mtp-source.ts +528 -0
  268. package/src/spec/serve-loop.ts +179 -213
  269. package/src/spec/source.ts +42 -10
  270. package/src/spec/two-model.ts +1 -1
  271. package/src/ssd-cache.ts +95 -24
  272. package/src/ssd-durability.ts +207 -0
  273. package/src/tool-call.ts +51 -14
  274. package/src/train/flash-cce.ts +14 -13
  275. package/src/train/forward.ts +38 -1
  276. package/src/train/loss.ts +3 -2
  277. package/src/train/prefix-shared.ts +5 -1
  278. package/src/train/segmented.ts +9 -6
  279. package/src/train/trainer.ts +9 -8
  280. package/src/vision/preprocess.ts +1 -1
  281. package/src/vision/prompt.ts +48 -2
  282. package/src/vision/qwen3vl-preprocess.ts +409 -0
  283. package/src/vision/qwen3vl-prompt.ts +196 -0
  284. package/src/vision/qwen3vl-tower.ts +555 -0
  285. package/src/vision/video-frames.ts +148 -0
  286. package/src/web/app.html +1 -1
  287. package/src/web/app.js +15 -6
  288. package/src/web/src/adapters-panel.ts +3 -3
  289. package/src/web/src/assistant.ts +2 -36
  290. package/src/web/src/chat.ts +16 -9
  291. package/src/web/src/composer.ts +4 -4
  292. package/src/web/src/hub.ts +1 -1
  293. package/src/web/src/markdown.ts +0 -0
  294. package/src/web/src/memory-panel.ts +1 -1
  295. package/src/web/src/model-picker.ts +1 -1
  296. package/src/web/src/palette.ts +1 -1
  297. package/src/web/src/protocol.ts +3 -39
  298. package/src/web/src/sessions.ts +1 -1
  299. package/src/web/src/ui-catalog.ts +4 -18
  300. package/src/web-assets.ts +47 -0
  301. package/src/weights.ts +134 -33
  302. package/docs/archive/mlx-bun-lab-report.html +0 -275
  303. package/docs/archive/wwdc-mlx-bun.html +0 -848
  304. package/docs/design/adapters-end-to-end.md +0 -205
  305. package/docs/design/batching-perf-path.md +0 -255
  306. package/docs/design/batching-v2-plan.md +0 -529
  307. package/docs/design/bucketing-stage.md +0 -197
  308. package/docs/design/compat-cli-surface-design.md +0 -230
  309. package/docs/design/docs-reorg-plan.md +0 -165
  310. package/docs/design/dspark-serving-program.md +0 -371
  311. package/docs/design/dspark-speculative-decoding.md +0 -268
  312. package/docs/design/grammar-spec-batching-integration.md +0 -301
  313. package/docs/design/memory-inference-path.md +0 -422
  314. package/docs/design/memory-synthesis.md +0 -287
  315. package/docs/design/memory-system.md +0 -237
  316. package/docs/design/mlx-lm-tool-parity-plan.md +0 -545
  317. package/docs/design/omlx-adoption-map.md +0 -98
  318. package/docs/design/orpo-dynamic-lambda.md +0 -220
  319. package/docs/design/orpo-future-enhancements.md +0 -340
  320. package/docs/design/paged-kv-cache.md +0 -214
  321. package/docs/design/parallel-slots.md +0 -567
  322. package/docs/design/parity-tier-dag.md +0 -161
  323. package/docs/design/repo-cleanup-plan.md +0 -189
  324. package/docs/design/runtime-isolation.md +0 -263
  325. package/docs/design/segmented-backward-training.md +0 -543
  326. package/docs/design/spec-decode-larger-targets.md +0 -229
  327. package/docs/design/ssd-kv-cold-tier.md +0 -288
  328. package/docs/design/structured-output.md +0 -484
  329. package/docs/design/tauri-desktop-app.md +0 -127
  330. package/docs/design/the-dreaming-master-plan.md +0 -445
  331. package/docs/design/turboquant-kv.md +0 -235
  332. package/docs/design/w4a16-compute-precision-spike.md +0 -232
  333. package/docs/design/web-chat-beat-matrix.md +0 -315
  334. package/docs/design/write-pipeline-entity.md +0 -468
  335. package/docs/investigations/curve-runs/bisector-route.json +0 -98
  336. package/docs/investigations/curve-runs/bisector-trace.json +0 -1393
  337. package/docs/investigations/curve-runs/curve-terrain.json +0 -1179
  338. package/docs/investigations/curve-runs/curve-terrain.svg +0 -42
  339. package/docs/investigations/hlg-ab.html +0 -34
  340. package/docs/investigations/hlg-explorer.html +0 -238
  341. package/docs/investigations/hlg-figs/cliff.svg +0 -1
  342. package/docs/investigations/hlg-figs/cross.svg +0 -1
  343. package/docs/investigations/hlg-figs/edges.svg +0 -1
  344. package/docs/investigations/hlg-figs/k20-grids.svg +0 -1
  345. package/docs/investigations/hlg-figs/k20-peaks.svg +0 -1
  346. package/docs/investigations/hlg-figs/lw-curve.svg +0 -1
  347. package/docs/investigations/hlg-figs/terrain.svg +0 -1
  348. package/docs/investigations/hlg-report.html +0 -262
  349. package/docs/investigations/hlg-runs/hlg-ab.json +0 -149
  350. package/docs/investigations/hlg-runs/hlg-blind-prompts.md +0 -87
  351. package/docs/investigations/hlg-runs/hlg-blind.json +0 -107
  352. package/docs/investigations/hlg-runs/hlg-cliff.json +0 -197
  353. package/docs/investigations/hlg-runs/hlg-cross.json +0 -505
  354. package/docs/investigations/hlg-runs/hlg-edge.json +0 -388
  355. package/docs/investigations/hlg-runs/hlg-eval1.json +0 -25
  356. package/docs/investigations/hlg-runs/hlg-frontier.json +0 -86
  357. package/docs/investigations/hlg-runs/hlg-grid.json +0 -242
  358. package/docs/investigations/hlg-runs/hlg-grid2.json +0 -343
  359. package/docs/investigations/hlg-runs/hlg-lw-coarse.json +0 -110
  360. package/docs/investigations/hlg-runs/hlg-map.json +0 -383
  361. package/docs/investigations/hlg-runs/run0-original.log +0 -159
  362. package/docs/investigations/hlg-runs/runA-recommended.log +0 -131
  363. package/docs/investigations/hlg-runs/runAA-cliff-cpm5.log +0 -26
  364. package/docs/investigations/hlg-runs/runAB-grid2-e4b.log +0 -18
  365. package/docs/investigations/hlg-runs/runAC-peak-e4b-partial.log +0 -25
  366. package/docs/investigations/hlg-runs/runAD-ab-samples.log +0 -8
  367. package/docs/investigations/hlg-runs/runAE-edge-e4b.log +0 -51
  368. package/docs/investigations/hlg-runs/runAF-logit-calibration.log +0 -10
  369. package/docs/investigations/hlg-runs/runAG-eval-config2.log +0 -16
  370. package/docs/investigations/hlg-runs/runB-gain-variants.log +0 -192
  371. package/docs/investigations/hlg-runs/runC-pivots.log +0 -162
  372. package/docs/investigations/hlg-runs/runD-oetf.log +0 -132
  373. package/docs/investigations/hlg-runs/runE-eotf.log +0 -162
  374. package/docs/investigations/hlg-runs/runF-shaper-working.log +0 -86
  375. package/docs/investigations/hlg-runs/runG-shaper-sweep.log +0 -101
  376. package/docs/investigations/hlg-runs/runH-wsweep.log +0 -176
  377. package/docs/investigations/hlg-runs/runI-asweep.log +0 -176
  378. package/docs/investigations/hlg-runs/runJ-knobmap.log +0 -49
  379. package/docs/investigations/hlg-runs/runK-frontier.log +0 -19
  380. package/docs/investigations/hlg-runs/runL-widemap.log +0 -65
  381. package/docs/investigations/hlg-runs/runM-frontier-emb.log +0 -15
  382. package/docs/investigations/hlg-runs/runN-verify.log +0 -116
  383. package/docs/investigations/hlg-runs/runO-frontier-seed5000.log +0 -15
  384. package/docs/investigations/hlg-runs/runP-grid-AxSm.log +0 -15
  385. package/docs/investigations/hlg-runs/runQ-grid-tgW.log +0 -15
  386. package/docs/investigations/hlg-runs/runR-blind-transcript.log +0 -79
  387. package/docs/investigations/hlg-runs/runS-cross-coherence.log +0 -33
  388. package/docs/investigations/hlg-runs/runT-cross-cpm5.log +0 -33
  389. package/docs/investigations/hlg-runs/runU-cross-12b.log +0 -33
  390. package/docs/investigations/hlg-runs/runV-lw-e4b.log +0 -22
  391. package/docs/investigations/hlg-runs/runW-lw-12b.log +0 -22
  392. package/docs/investigations/hlg-runs/runX-lw-cpm5.log +0 -22
  393. package/docs/investigations/hlg-runs/runY-cliff-e4b.log +0 -26
  394. package/docs/investigations/hlg-runs/runZ-cliff-12b.log +0 -26
  395. package/docs/planning/IDEAS.md +0 -69
  396. package/docs/reference/embedding.md +0 -197
  397. package/docs/reference/features-matrix.md +0 -100
  398. package/docs/reference/orpo-quickstart.md +0 -135
  399. package/src/flags.ts +0 -13
  400. /package/docs/{investigations → archive/investigations}/chunk-finetune-experiment.md +0 -0
  401. /package/docs/{investigations → archive/investigations}/colibri-oracle-pin.md +0 -0
  402. /package/docs/{investigations → archive/investigations}/curve-bisector-routing.md +0 -0
  403. /package/docs/{investigations → archive/investigations}/decode-roofline-lookagain.md +0 -0
  404. /package/docs/{investigations → archive/investigations}/dspark-handoff.md +0 -0
  405. /package/docs/{investigations → archive/investigations}/expert-offload-single-user-moe.md +0 -0
  406. /package/docs/{investigations → archive/investigations}/indexshare-performance-spike.md +0 -0
  407. /package/docs/{investigations → archive/investigations}/kernel-perf-review-2026-07.md +0 -0
  408. /package/docs/{investigations → archive/investigations}/lab-build-journal.md +0 -0
  409. /package/docs/{investigations → archive/investigations}/openwiki-evaluation.md +0 -0
  410. /package/docs/{investigations → archive/investigations}/orpo-base-uf-experiment-and-directions.md +0 -0
  411. /package/docs/{investigations → archive/investigations}/orpo-flash-cce-pin-leak.md +0 -0
  412. /package/docs/{investigations → archive/investigations}/orpo-uf-testing-handoff.md +0 -0
  413. /package/docs/{investigations → archive/investigations}/pi-builtin-investigation.md +0 -0
  414. /package/docs/{investigations → archive/investigations}/segmented-backward-handoff.md +0 -0
  415. /package/docs/{investigations → archive/investigations}/starter-model-port-handoff.md +0 -0
  416. /package/docs/{investigations → archive/investigations}/steel-flash-cce-handoff.md +0 -0
  417. /package/docs/{investigations → archive/investigations}/trainer-validation-experiment.md +0 -0
  418. /package/docs/{planning → archive/planning}/chat-ui-vision-memory-first.md +0 -0
  419. /package/docs/{planning → archive/planning}/journal.md +0 -0
  420. /package/docs/{planning → archive/planning}/pi-integration-review.md +0 -0
  421. /package/docs/{planning → archive/planning}/release-notes-v0.0.10.md +0 -0
  422. /package/docs/{planning → archive/planning}/release-notes-v0.0.11.md +0 -0
  423. /package/docs/{planning → archive/planning}/release-notes-v0.0.12.md +0 -0
  424. /package/docs/{planning → archive/planning}/release-notes-v0.0.13.md +0 -0
  425. /package/docs/{planning → archive/planning}/web-ui-pass-plan.md +0 -0
  426. /package/{docs/investigations → src/serve/assets}/curve-terrain.html +0 -0
  427. /package/{docs/dag → src/serve/assets}/training-inference-map.html +0 -0
@@ -0,0 +1,94 @@
1
+ // Packed Trellis prefill with MLX 0.32.2 GemvWide arithmetic.
2
+ // Ported from ml-explore/mlx v0.32.2, mlx/backend/metal/kernels/gemv.h
3
+ // (MIT). Decode weights to bf16 inside the native dot/unroll/shuffle order;
4
+ // share each decoded row across every input vector in this narrow regime.
5
+ import { MetalKernel } from "../mlx/metal-kernel";
6
+ import { type MlxArray } from "../mlx/array";
7
+ import { Dtype, deviceArchitecture } from "../mlx/ffi";
8
+ import { type TrellisGeometry } from "./trellis-linear";
9
+
10
+ /** Matches the bundled runtime's native reduction on M3 and newer GPUs. */
11
+ export function nativeTrellisWidePrefill(m: number): boolean {
12
+ return m >= 5 && m <= 15 &&
13
+ Number(/^applegpu_[a-z](\d{2})/.exec(deviceArchitecture())?.[1] ?? 0) >= 15;
14
+ }
15
+
16
+ export function wideTrellisPrefillEligible(g: TrellisGeometry, m: number, dtype: Dtype): boolean {
17
+ return dtype === Dtype.bfloat16 && nativeTrellisWidePrefill(m) &&
18
+ g.axis === 1 && g.T === 256 && g.L === 12 && [2, 3, 4].includes(g.k) &&
19
+ g.inFeatures === 5120 && g.outFeatures === 17408 && !g.blockInterleave;
20
+ }
21
+
22
+ let kernel: MetalKernel | undefined;
23
+ function wideKernel() {
24
+ return kernel ??= new MetalKernel({ name: 'mlx_bun_trellis_wide_prefill',
25
+ inputNames: ['x', 'codes', 'scales'], outputNames: ['out'], source: String.raw`
26
+ constexpr uint unroll=8, rows_per_simd=32/KL, simdgroups=KL/8;
27
+ const uint lane=thread_index_in_simdgroup, sg=simdgroup_index_in_threadgroup;
28
+ const uint kl=lane%KL, row=threadgroup_position_in_grid.y*4+sg*rows_per_simd+lane/KL;
29
+ const uint vec0=threadgroup_position_in_grid.x*SM;
30
+ constexpr uint wpb=BT*BITS/32, row_words=KC*BITS/32;
31
+ const float scale=float(scales[row]);
32
+ constexpr uint n_v4=KC/4, n_main=n_v4-n_v4%(KL*unroll);
33
+ float result[SM]={0};
34
+ for(uint base=0;base<n_main;base+=KL*unroll) {
35
+ float4 wf[unroll];
36
+ #pragma clang loop unroll(full)
37
+ for(uint i=0;i<unroll;i++) {
38
+ #pragma clang loop unroll(full)
39
+ for(uint c=0;c<4;c++) {
40
+ const uint k=(base+i*KL+kl)*4+c, block=k/BT, t=k%BT;
41
+ const device uint* bw=codes+(ulong)row*row_words+block*wpb;
42
+ const uint pos=(BT-1-t)*BITS, wi=pos>>5, off=pos&31u;
43
+ uint win=bw[wi]>>off;
44
+ if(off+L>32)win|=bw[wi+1==wpb?0:wi+1]<<(32-off);
45
+ win&=(1u<<L)-1;
46
+ const uint z=win*34038481u+76625530u;
47
+ const uint p=(z&0x00FF00FFu)+((z>>8)&0x00FF00FFu);
48
+ const int code=int((p&0xFFFFu)+(p>>16))-510;
49
+ const float reciprocal=1.0f/147.800537109375f;
50
+ const float approx=float(code)*reciprocal;
51
+ const float residual=metal::fma(-approx,147.800537109375f,float(code));
52
+ const float value=metal::fma(residual,reciprocal,approx);
53
+ wf[i][c]=float(T(value*scale));
54
+ }
55
+ }
56
+ #pragma clang loop unroll(full)
57
+ for(uint v=0;v<SM;v++) {
58
+ const uint m=min(vec0+v,uint(M-1));
59
+ float acc=0;
60
+ #pragma clang loop unroll(full)
61
+ for(uint i=0;i<unroll;i++) {
62
+ const ulong offset=(ulong)m*KC+(base+i*KL+kl)*4;
63
+ const float4 xv=float4(float(x[offset]),float(x[offset+1]),float(x[offset+2]),float(x[offset+3]));
64
+ acc+=metal::dot(wf[i],xv);
65
+ }
66
+ result[v]+=acc;
67
+ }
68
+ }
69
+ #pragma clang loop unroll(full)
70
+ for(uint v=0;v<SM;v++) {
71
+ #pragma clang loop unroll(full)
72
+ for(ushort off=KL/2;off>=1;off>>=1) result[v]+=simd_shuffle_down(result[v],off);
73
+ if(kl==0 && vec0+v<M) out[(ulong)(vec0+v)*N+row]=T(result[v]);
74
+ }
75
+ ` });
76
+ }
77
+ /** Requires the caller to prove aligned, row-contiguous x, as Qwen does
78
+ * with its RMSNorm output. Preserve native fallback when that proof is absent. */
79
+ export function wideTrellisPrefill(x: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry): MlxArray {
80
+ const [m, k] = x.shape;
81
+ if (x.ndim !== 2 || x.dtype !== Dtype.bfloat16 || !m || m < 5 || m > 15 ||
82
+ k !== 5120 || g.inFeatures !== k || g.axis !== 1 || g.T !== 256 || g.L !== 12 ||
83
+ ![2, 3, 4].includes(g.k) || g.blockInterleave || g.rows < 4 || g.rows % 4 ||
84
+ g.outFeatures !== g.rows || g.cols !== k || codes.dtype !== Dtype.uint32 ||
85
+ codes.ndim !== 2 || codes.shape[0] !== g.rows || codes.shape[1] !== k * g.k / 32 || scales.size !== g.rows)
86
+ throw new Error("unsupported wide trellis prefill geometry, dtype or layout");
87
+ const kl = m <= 5 ? 32 : 16;
88
+ return wideKernel().apply([x, codes, scales], {
89
+ outputs: [{ shape: [m, g.outFeatures], dtype: x.dtype }],
90
+ grid: [32, g.outFeatures / 4 * (kl / 8), 1], threadGroup: [32, kl / 8, 1],
91
+ templateDtypes: { T: x.dtype },
92
+ templateInts: { M: m, SM: m, KL: kl, KC: k, N: g.outFeatures, BT: g.T, L: g.L, BITS: g.k },
93
+ })[0]!;
94
+ }
@@ -3,7 +3,7 @@
3
3
  // like qwen3.ts, with every arch delta selected by the UniversalArgs
4
4
  // descriptor (archs.ts). Monolith path only: no compiled
5
5
  // decode, no kv-quant — slow, never broken. The bar is L1 bit-exactness
6
- // vs mlx-lm on this machine's GPU (tests/universal-parity.test.ts).
6
+ // vs mlx-lm on this machine's GPU (tests/parity/universal-parity.test.ts).
7
7
  //
8
8
  // Porting discipline: each branch transcribes its mlx-lm source op-for-op
9
9
  // (q/k-norm before vs after reshape, rope order, scale points, softcap,
@@ -11,6 +11,7 @@ import type { Weights } from "../../weights";
11
11
  import { MlxArray } from "../../mlx/array";
12
12
  import * as ops from "../../mlx/ops";
13
13
  import { QuantizedEmbedding, QuantizedLinear, RMSNorm } from "../gemma4-base";
14
+ import { TrellisLinear } from "../trellis-linear";
14
15
 
15
16
  /** Records every tensor a universal load consumes; `finish` diffs against
16
17
  * the shard index so a descriptor mistake is a LOAD error (unconsumed /
@@ -66,7 +67,7 @@ export class DenseLinear {
66
67
  }
67
68
 
68
69
  /** Either linear flavor behind one call surface. */
69
- export type AnyLinear = QuantizedLinear | DenseLinear;
70
+ export type AnyLinear = QuantizedLinear | DenseLinear | TrellisLinear;
70
71
 
71
72
  /** Quantized when `.scales` exists (MLX-quantized checkpoints), else dense
72
73
  * bf16/f16/f32 (Phase 1.5). Both flavors carry the optional ADDITIVE
@@ -74,6 +75,12 @@ export type AnyLinear = QuantizedLinear | DenseLinear;
74
75
  export function loadLinear(
75
76
  weights: Weights, path: string, config: ModelConfig, audit: WeightAudit,
76
77
  ): AnyLinear {
78
+ if (TrellisLinear.isTrellis(config, path)) {
79
+ const lin = TrellisLinear.load(weights, path, config);
80
+ audit.use(`${path}.weight`);
81
+ audit.use(`${path}.scales`);
82
+ return lin;
83
+ }
77
84
  if (weights.has(`${path}.scales`)) {
78
85
  const lin = QuantizedLinear.load(weights, path, config);
79
86
  audit.use(`${path}.weight`);
@@ -0,0 +1,140 @@
1
+ // AVFoundation frame-extraction sidecar probe (PLAN 14w) — the video
2
+ // equivalent of the audio path's afconvert doctrine: macOS-native codecs,
3
+ // zero vendored dependencies.
4
+ //
5
+ // frame-extract <video> <outDir> [fps=2] [maxFrames=768]
6
+ // → writes frame-%04d.png (RGB) + prints "N <count> W <w> H <h>"
7
+ // frame-extract --make-fixture <out.mov>
8
+ // → writes the deterministic 6-frame 320x240 gradient test clip
9
+ //
10
+ // Sampling mirrors mlx-vlm's do_sample_frames: timestamps k/fps for
11
+ // k = 0..min(ceil(duration*fps), maxFrames)-1, precise tolerance.
12
+
13
+ import AVFoundation
14
+ import Foundation
15
+ import ImageIO
16
+ import UniformTypeIdentifiers
17
+
18
+ func die(_ msg: String) -> Never {
19
+ FileHandle.standardError.write((msg + "\n").data(using: .utf8)!)
20
+ exit(1)
21
+ }
22
+
23
+ func makeFixture(_ path: String) {
24
+ let url = URL(fileURLWithPath: path)
25
+ try? FileManager.default.removeItem(at: url)
26
+ guard let writer = try? AVAssetWriter(outputURL: url, fileType: .mov) else {
27
+ die("AVAssetWriter init failed")
28
+ }
29
+ let W = 320, H = 240, FRAMES = 6
30
+ let settings: [String: Any] = [
31
+ AVVideoCodecKey: AVVideoCodecType.h264,
32
+ AVVideoWidthKey: W,
33
+ AVVideoHeightKey: H,
34
+ ]
35
+ let input = AVAssetWriterInput(mediaType: .video, outputSettings: settings)
36
+ let adaptor = AVAssetWriterInputPixelBufferAdaptor(
37
+ assetWriterInput: input,
38
+ sourcePixelBufferAttributes: [
39
+ kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32ARGB,
40
+ kCVPixelBufferWidthKey as String: W,
41
+ kCVPixelBufferHeightKey as String: H,
42
+ ])
43
+ writer.add(input)
44
+ writer.startWriting()
45
+ writer.startSession(atSourceTime: .zero)
46
+ for f in 0..<FRAMES {
47
+ while !input.isReadyForMoreMediaData { Thread.sleep(forTimeInterval: 0.01) }
48
+ var pb: CVPixelBuffer?
49
+ CVPixelBufferCreate(nil, W, H, kCVPixelFormatType_32ARGB, nil, &pb)
50
+ guard let pixelBuffer = pb else { die("CVPixelBufferCreate failed") }
51
+ CVPixelBufferLockBaseAddress(pixelBuffer, [])
52
+ let base = CVPixelBufferGetBaseAddress(pixelBuffer)!
53
+ let bpr = CVPixelBufferGetBytesPerRow(pixelBuffer)
54
+ let p = base.assumingMemoryBound(to: UInt8.self)
55
+ for y in 0..<H {
56
+ for x in 0..<W {
57
+ let o = y * bpr + x * 4
58
+ p[o] = 255
59
+ p[o + 1] = UInt8((x * 255 / W + f * 20) % 256)
60
+ p[o + 2] = UInt8((y * 255 / H + f * 10) % 256)
61
+ p[o + 3] = UInt8(((x + y) * 255 / (W + H) + f * 30) % 256)
62
+ }
63
+ }
64
+ CVPixelBufferUnlockBaseAddress(pixelBuffer, [])
65
+ adaptor.append(pixelBuffer, withPresentationTime: CMTime(value: CMTimeValue(f), timescale: 2))
66
+ }
67
+ input.markAsFinished()
68
+ let sem = DispatchSemaphore(value: 0)
69
+ writer.finishWriting { sem.signal() }
70
+ sem.wait()
71
+ guard writer.status == .completed else { die("finishWriting status \(writer.status.rawValue)") }
72
+ print("fixture \(path)")
73
+ }
74
+
75
+ let args = CommandLine.arguments
76
+ if args.count >= 3 && args[1] == "--make-fixture" {
77
+ makeFixture(args[2])
78
+ exit(0)
79
+ }
80
+ guard args.count >= 3 else { die("usage: frame-extract <video> <outDir> [fps] [maxFrames]") }
81
+ let videoPath = args[1]
82
+ let outDir = args[2]
83
+ let fps = args.count > 3 ? Double(args[3]) ?? 2.0 : 2.0
84
+ let maxFrames = args.count > 4 ? Int(args[4]) ?? 768 : 768
85
+
86
+ let asset = AVURLAsset(url: URL(fileURLWithPath: videoPath))
87
+ let sem = DispatchSemaphore(value: 0)
88
+ var duration = CMTime.zero
89
+ var loadError: Error?
90
+ Task {
91
+ do { duration = try await asset.load(.duration) } catch { loadError = error }
92
+ sem.signal()
93
+ }
94
+ sem.wait()
95
+ if let e = loadError { die("asset load failed: \(e.localizedDescription)") }
96
+ // Fragmented/malformed containers can load with an indefinite duration —
97
+ // CMTimeGetSeconds yields NaN and Int(NaN) is a Swift runtime TRAP. Fall
98
+ // back to the frame cap; the extraction loop below already stops at the
99
+ // first undecodable timestamp.
100
+ let seconds = CMTimeGetSeconds(duration)
101
+ let count = seconds.isFinite
102
+ ? max(1, min(Int((seconds * fps).rounded(.up)), maxFrames))
103
+ : maxFrames
104
+
105
+ let gen = AVAssetImageGenerator(asset: asset)
106
+ gen.appliesPreferredTrackTransform = true
107
+ gen.requestedTimeToleranceBefore = .zero
108
+ gen.requestedTimeToleranceAfter = .zero
109
+ // Bound DECODED memory at the source: the language pipeline's video pixel
110
+ // budget always downscales frames far below 1024px anyway (max_pixels
111
+ // 32·32·768 across t·h·w), so capping the longest edge here loses nothing
112
+ // it would have kept while keeping a 4K clip from materializing ~24 MB per
113
+ // frame (768 frames ≈ 17.8 GiB) before preprocessing.
114
+ gen.maximumSize = CGSize(width: 1024, height: 1024)
115
+
116
+ try? FileManager.default.createDirectory(
117
+ atPath: outDir, withIntermediateDirectories: true)
118
+ var written = 0
119
+ var lastW = 0, lastH = 0
120
+ for k in 0..<count {
121
+ let t = CMTime(seconds: Double(k) / fps, preferredTimescale: 600)
122
+ let img: CGImage
123
+ do {
124
+ img = try gen.copyCGImage(at: t, actualTime: nil)
125
+ } catch {
126
+ // Past-end sampling on short clips: stop at the last decodable frame.
127
+ break
128
+ }
129
+ lastW = img.width
130
+ lastH = img.height
131
+ let out = URL(fileURLWithPath: String(format: "%@/frame-%04d.png", outDir, k))
132
+ guard let dest = CGImageDestinationCreateWithURL(
133
+ out as CFURL, UTType.png.identifier as CFString, 1, nil)
134
+ else { die("png destination failed") }
135
+ CGImageDestinationAddImage(dest, img, nil)
136
+ guard CGImageDestinationFinalize(dest) else { die("png write failed") }
137
+ written += 1
138
+ }
139
+ guard written > 0 else { die("no frames decodable from \(videoPath)") }
140
+ print("N \(written) W \(lastW) H \(lastH)")
@@ -8,25 +8,32 @@
8
8
  //
9
9
  // Resolution order for the libs (mirrored in src/mlx/ffi.ts):
10
10
  // MLX_BUN_LIBMLXC env > beside the executable (sidecar dist/ layout,
11
- // docs/reference/embedding.md) > the native-pack cache dir > homebrew.
11
+ // docs/reference/distribution.md) > the native-pack cache dir > homebrew.
12
12
  // Dev trees and embedders therefore never download anything.
13
13
 
14
14
  import { existsSync, mkdirSync, renameSync, rmSync } from "node:fs";
15
15
  import { homedir, tmpdir } from "node:os";
16
16
  import { dirname, join } from "node:path";
17
17
  import { downloadOne } from "./download";
18
+ import { runtimeValue } from "./runtime-config";
18
19
 
19
- export const NATIVE_PACK_VERSION = "0.2.0";
20
+ export const NATIVE_PACK_VERSION = "0.4.0";
21
+ export const MLX_CORE_VERSION = "0.32.2";
20
22
  export const NATIVE_PACK_FILES = [
21
23
  "libmlxc.dylib", "libmlx.dylib", "libjaccl.dylib", "mlx.metallib",
22
- "libmlx_bun_expert_io.dylib",
24
+ "libmlx_bun_expert_io.dylib", "mlx-bun-frame-extract",
23
25
  ] as const;
24
26
 
27
+ // RELEASE-TIME BAKE: scripts/build-native-pack.sh prints the sha256/size for
28
+ // the freshly built tarball — publish `native-v0.4.0` with both assets and
29
+ // paste the values here BEFORE tagging the package release (the download
30
+ // 404s until the GitHub release exists; dev trees resolve via homebrew/env
31
+ // and never hit this path).
25
32
  const SHA256: Record<string, string> = {
26
- arm64: "9bd3795c5ea8f52b18413501f2d68c32c264a20751302300a08dc04cd67df97c",
33
+ arm64: "f2b0857658aa0826aee14b94a6b83d4c86c08f2c07d716991de6afd038f5ca5d",
27
34
  };
28
35
  const SIZE: Record<string, number> = {
29
- arm64: 52_307_647,
36
+ arm64: 41931583,
30
37
  };
31
38
 
32
39
  export function nativePackName(arch = process.arch): string {
@@ -37,7 +44,7 @@ export function nativePackName(arch = process.arch): string {
37
44
  * the repo is private the download needs a token (GITHUB_TOKEN or
38
45
  * `gh auth token`); once public it works anonymously. */
39
46
  export function nativePackUrl(arch = process.arch): string {
40
- return process.env.MLX_BUN_NATIVE_PACK_URL ??
47
+ return runtimeValue("MLX_BUN_NATIVE_PACK_URL") ??
41
48
  `https://github.com/joshuarossi/mlx-bun/releases/download/native-v${NATIVE_PACK_VERSION}/${nativePackName(arch)}`;
42
49
  }
43
50
 
@@ -48,7 +55,8 @@ export function nativePackDir(arch = process.arch): string {
48
55
  /** Where the native runtime currently resolves from, or null if absent
49
56
  * everywhere (= a fresh machine that needs the pack). */
50
57
  export function nativeRuntimeDir(): string | null {
51
- if (process.env.MLX_BUN_LIBMLXC) return dirname(process.env.MLX_BUN_LIBMLXC);
58
+ const explicit = runtimeValue("MLX_BUN_LIBMLXC");
59
+ if (explicit) return dirname(explicit);
52
60
  const candidates = [
53
61
  dirname(process.execPath),
54
62
  nativePackDir(),
@@ -17,37 +17,11 @@ import { AuthStorage, ModelRegistry } from "@earendil-works/pi-coding-agent";
17
17
  * derive it from the registry's `find()` return type. */
18
18
  export type PiModel = NonNullable<ReturnType<ModelRegistry["find"]>>;
19
19
 
20
- // Provider/model constants — kept aligned with src/harness-pi.ts so every
21
- // path (web embed, terminal embed, external pi) registers the same provider.
22
- export const PI_PROVIDER_ID = "mlx-bun";
23
- export const PI_LOCAL_MODEL_ID = "local";
24
- export const PI_API_KEY = "sk-mlx-bun-local";
25
- export const PI_API = "openai-completions" as const;
26
-
27
- export const DEFAULT_CONTEXT_WINDOW = 32_768;
28
- export const DEFAULT_MAX_TOKENS = 8_192;
29
-
30
- export interface PiProviderOptions {
31
- /** Advertised context window. Default: DEFAULT_CONTEXT_WINDOW. */
32
- contextWindow?: number;
33
- /** Advertised max output tokens. Default: DEFAULT_MAX_TOKENS. */
34
- maxTokens?: number;
35
- /** Human-readable model label (e.g. the real repo id). Default: "mlx-bun (local)". */
36
- name?: string;
37
- /** The loaded model has a switchable reasoning channel (server's
38
- * `ctx.template.supportsThinking` — true for any model whose chat template
39
- * gates on enable_thinking: Qwen3.5, MiniCPM5, …). When true Pi engages
40
- * reasoning and sends the on/off switch the server maps to enable_thinking.
41
- * Default false. */
42
- reasoning?: boolean;
43
- /** The loaded model can accept images (server's `ctx.vision != null`).
44
- * This MUST match the real model: pi-ai serializes user content as OpenAI
45
- * multimodal content-parts (`[{type:"text",…}]`) for image-capable models
46
- * and as a plain string otherwise. A text-only chat template renders nothing
47
- * for a parts array, so declaring a non-vision model as image-capable makes
48
- * the user's turn vanish ("I don't see any message"). Default false. */
49
- vision?: boolean;
50
- }
20
+ import { PI_PROVIDER_ID, PI_API_KEY, PI_API, PI_LOCAL_MODEL_ID, piModelDefinition,
21
+ type PiModelOptions } from "./contracts/pi-provider";
22
+ export { PI_PROVIDER_ID, PI_API_KEY, PI_API, PI_LOCAL_MODEL_ID,
23
+ DEFAULT_CONTEXT_WINDOW, DEFAULT_MAX_TOKENS } from "./contracts/pi-provider";
24
+ export interface PiProviderOptions extends PiModelOptions {}
51
25
 
52
26
  export interface PiProviderWiring {
53
27
  authStorage: AuthStorage;
@@ -70,39 +44,7 @@ export function buildPiProvider(baseUrl: string, opts: PiProviderOptions = {}):
70
44
  baseUrl,
71
45
  apiKey: PI_API_KEY,
72
46
  api: PI_API,
73
- models: [
74
- {
75
- id: PI_LOCAL_MODEL_ID,
76
- name: opts.name ?? "mlx-bun (local)",
77
- api: PI_API,
78
- reasoning: opts.reasoning ?? false,
79
- // Compat flags that make pi emit the wire format our local server's
80
- // chat templates expect (docs/custom-provider.md "Model Definition
81
- // Reference"):
82
- // - supportsDeveloperRole:false → pi sends the system prompt as the
83
- // `system` role, not `developer` (our templates only know
84
- // system/user/assistant/tool).
85
- // - thinkingFormat:"qwen-chat-template" (reasoning models only) → pi
86
- // sends chat_template_kwargs.enable_thinking, the boolean our
87
- // Qwen3.5/MiniCPM5 templates gate on. pi computes the boolean from
88
- // the selected thinking level (off → false), so no thinkingLevelMap.
89
- compat: {
90
- supportsDeveloperRole: false,
91
- ...(opts.reasoning ? { thinkingFormat: "qwen-chat-template" as const } : {}),
92
- },
93
- // input MUST match the loaded model. pi-ai serializes user content as a
94
- // plain string for text-only models and as OpenAI content-parts
95
- // (`[{type:"text",…}]`) once a model declares image input — and a
96
- // text-only chat template renders NOTHING for a parts array, dropping
97
- // the user's turn ("I don't see any message"). So declare image input
98
- // only for an actual vision model; the web `ready` frame's `vision`
99
- // flag is the same signal that drives the UI's image affordance.
100
- input: opts.vision ? ["text", "image"] : ["text"],
101
- cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
102
- contextWindow: opts.contextWindow ?? DEFAULT_CONTEXT_WINDOW,
103
- maxTokens: opts.maxTokens ?? DEFAULT_MAX_TOKENS,
104
- },
105
- ],
47
+ models: [piModelDefinition(opts)],
106
48
  });
107
49
 
108
50
  const model = modelRegistry.find(PI_PROVIDER_ID, PI_LOCAL_MODEL_ID);