mlx-bun 0.0.10 → 0.0.11
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.
- package/README.md +66 -21
- package/THIRD_PARTY_LICENSES.md +1 -0
- package/docs/archive/mlx-bun-lab-report.html +275 -0
- package/docs/archive/wwdc-mlx-bun.html +848 -0
- package/docs/design/audio-input-plan.md +356 -0
- package/docs/design/batching-perf-path.md +58 -35
- package/docs/design/batching-v2-plan.md +23 -9
- package/docs/design/bucketing-stage.md +2 -1
- package/docs/design/compat-cli-surface-design.md +4 -3
- package/docs/design/decode-speed-program.md +172 -0
- package/docs/design/docs-reorg-plan.md +1 -1
- package/docs/design/dspark-serving-program.md +371 -0
- package/docs/design/dspark-speculative-decoding.md +167 -5
- package/docs/design/faithful-l1-consolidation.md +310 -0
- package/docs/design/generic-model-support.md +8 -5
- package/docs/design/grammar-spec-batching-integration.md +301 -0
- package/docs/design/minicpm5-decode-megakernel.md +16 -11
- package/docs/design/mlx-lm-tool-parity-plan.md +11 -1
- package/docs/design/omlx-adoption-map.md +14 -6
- package/docs/design/orpo-training.md +34 -30
- package/docs/design/paged-kv-cache.md +214 -0
- package/docs/design/parallel-slots.md +82 -49
- package/docs/design/parity-tier-dag.md +43 -33
- package/docs/design/repo-cleanup-plan.md +189 -0
- package/docs/design/runtime-isolation.md +19 -3
- package/docs/design/segmented-backward-training.md +3 -2
- package/docs/design/ssd-kv-cold-tier.md +130 -0
- package/docs/design/structured-output.md +484 -0
- package/docs/design/the-dreaming-master-plan.md +2 -3
- package/docs/design/turboquant-kv.md +235 -0
- package/docs/design/unified-engine-frontier-plan.md +774 -0
- package/docs/design/web-chat-beat-matrix.md +315 -0
- package/docs/design/web-chat-redesign.md +1112 -0
- package/docs/investigations/dspark-handoff.md +182 -16
- package/docs/investigations/lab-build-journal.md +2 -2
- package/docs/investigations/openwiki-evaluation.md +249 -0
- package/docs/planning/IDEAS.md +14 -0
- package/docs/planning/PRODUCT_ROADMAP.md +2 -3
- package/docs/planning/chat-ui-vision-memory-first.md +199 -0
- package/docs/planning/chat-ui-vision.md +50 -0
- package/docs/planning/memory-docs-and-dag-plan.md +15 -6
- package/docs/planning/release-notes-v0.0.11.md +239 -0
- package/docs/reference/cli.md +35 -16
- package/docs/reference/distribution.md +13 -6
- package/docs/reference/embedding.md +35 -14
- package/docs/reference/features-matrix.md +97 -0
- package/docs/reference/library-api.md +30 -9
- package/docs/reference/memory.md +26 -6
- package/docs/reference/models.md +11 -1
- package/docs/reference/orpo-quickstart.md +3 -4
- package/docs/reference/server-api.md +634 -22
- package/docs/reference/server-config.md +250 -121
- package/docs/reference/training.md +14 -15
- package/package.json +5 -3
- package/src/anthropic.ts +13 -0
- package/src/audio/conformer.ts +647 -0
- package/src/audio/decode.ts +133 -0
- package/src/audio/features.ts +202 -0
- package/src/audio/transcode.ts +67 -0
- package/src/cli.ts +356 -105
- package/src/config.ts +49 -2
- package/src/download.ts +40 -0
- package/src/eval/README.md +7 -6
- package/src/eval/kl.ts +59 -3
- package/src/eval/quality-db.ts +2 -2
- package/src/eval/runner.ts +3 -3
- package/src/expert-offload.ts +15 -2
- package/src/flags.ts +13 -0
- package/src/generate.ts +330 -24
- package/src/grammar.ts +585 -0
- package/src/hub-rest.ts +242 -0
- package/src/kv-store.ts +442 -88
- package/src/lora.ts +8 -0
- package/src/md-modules.d.ts +42 -0
- package/src/media-fetch.ts +284 -0
- package/src/memory/rest.ts +245 -0
- package/src/memory/vault.ts +74 -0
- package/src/mlx/array.ts +106 -19
- package/src/mlx/autograd.ts +2 -2
- package/src/mlx/ffi.ts +27 -3
- package/src/mlx/metal-kernel.ts +7 -4
- package/src/mlx/ops.ts +153 -23
- package/src/mlx/turboquant-ops.ts +831 -0
- package/src/mlx/turboquant-tables.ts +237 -0
- package/src/model/batched-mask.ts +62 -1
- package/src/model/batched-quant.ts +206 -0
- package/src/model/batched-rotating-quant.ts +346 -0
- package/src/model/batched-rotating.ts +46 -1
- package/src/model/compiled-decode.ts +4 -15
- package/src/model/factory.ts +10 -4
- package/src/model/gemma4-base.ts +363 -39
- package/src/model/gemma4.ts +122 -33
- package/src/model/generated/gemma4-12b.ts +9 -13
- package/src/model/generated/gemma4-26b.ts +10 -5
- package/src/model/generated/gemma4-e4b.ts +14 -9
- package/src/model/minicpm5.ts +58 -102
- package/src/model/paged-kv.ts +253 -0
- package/src/model/qwen3-delta.ts +76 -15
- package/src/model/qwen3-moe.ts +404 -0
- package/src/model/qwen3.ts +9 -8
- package/src/model/qwen3_5.ts +88 -23
- package/src/model/support.ts +12 -1
- package/src/model/universal/dense.ts +40 -5
- package/src/model/universal/rope.ts +36 -21
- package/src/pi-web.ts +1299 -82
- package/src/preflight.ts +27 -8
- package/src/prompt-cache.ts +293 -33
- package/src/quantize/quantizer.ts +16 -1
- package/src/registry.ts +57 -2
- package/src/serve/batch-scheduler.ts +965 -72
- package/src/serve/generation-gateway.ts +214 -11
- package/src/serve/isolate.ts +417 -0
- package/src/serve/lane-registry.ts +44 -0
- package/src/serve/session-search.ts +326 -0
- package/src/server.ts +1380 -135
- package/src/spec/assistant-source.ts +150 -0
- package/src/spec/deepspec-source.ts +143 -0
- package/src/spec/dflash-source.ts +124 -0
- package/src/spec/dspark/ab-stats.ts +136 -0
- package/src/spec/dspark/calibration.ts +112 -0
- package/src/spec/dspark/deepspec-module.ts +801 -0
- package/src/spec/dspark/generate-dflash.ts +72 -20
- package/src/spec/dspark/loader.ts +23 -0
- package/src/spec/dspark/module-dflash.ts +278 -36
- package/src/spec/dspark/quantize-drafter.ts +91 -0
- package/src/spec/generate.ts +59 -25
- package/src/spec/ngram-source.ts +132 -0
- package/src/spec/serve-loop.ts +536 -0
- package/src/spec/source.ts +93 -0
- package/src/spec/two-model.ts +171 -0
- package/src/ssd-cache.ts +107 -35
- package/src/tokenizer.ts +288 -2
- package/src/tool-approvals.ts +131 -0
- package/src/tool-call.ts +408 -20
- package/src/train/flash-cce.ts +2 -2
- package/src/train/job.ts +0 -2
- package/src/train/trainer.ts +1 -4
- package/src/vision/prompt.ts +217 -48
- package/src/web/app.html +1184 -1789
- package/src/web/app.js +5667 -0
- package/src/web/icon.svg +13 -0
- package/src/web/manifest.webmanifest +24 -0
- package/src/web/src/adapters-panel.ts +288 -0
- package/src/web/src/api.ts +57 -0
- package/src/web/src/assistant.ts +485 -0
- package/src/web/src/chat.ts +1050 -0
- package/src/web/src/composer.ts +959 -0
- package/src/web/src/dataset.ts +132 -0
- package/src/web/src/finetune.ts +267 -0
- package/src/web/src/hub.ts +428 -0
- package/src/web/src/main.ts +98 -0
- package/src/web/src/markdown.ts +0 -0
- package/src/web/src/memory-panel.ts +572 -0
- package/src/web/src/model-picker.ts +159 -0
- package/src/web/src/palette.ts +346 -0
- package/src/web/src/protocol.ts +62 -0
- package/src/web/src/quantize.ts +167 -0
- package/src/web/src/rag.ts +274 -0
- package/src/web/src/sessions.ts +469 -0
- package/src/web/src/shell.ts +804 -0
- package/src/web/src/status.ts +252 -0
- package/src/web/src/ui-catalog.ts +92 -0
- package/src/web/sw.js +71 -0
- package/src/web/vendor/README.md +61 -0
- package/src/web/vendor/hljs-LICENSE +29 -0
- package/src/web/vendor/hljs-theme.css +59 -0
- package/src/web/vendor/hljs.js +26 -0
- package/src/model/fused-decode-kernel.ts +0 -312
- package/src/model/fused-geglu-kernel.ts +0 -198
- package/src/model/fused-mlp-kernel.ts +0 -169
- package/src/model/fused-swiglu-kernel.ts +0 -240
- package/src/model/steel-linear-kernel.ts +0 -96
- package/src/status-page.html +0 -497
package/docs/reference/cli.md
CHANGED
|
@@ -11,14 +11,15 @@ candidates — just make it more specific.
|
|
|
11
11
|
Bare `mlx-bun` with no verb runs `serve` — the appliance path: first run
|
|
12
12
|
downloads a starter model, serves it, and opens the chat UI.
|
|
13
13
|
|
|
14
|
-
>
|
|
14
|
+
> All verbs below ship in current releases; the release notes in
|
|
15
|
+
> `docs/planning/` record when each verb first appeared.
|
|
15
16
|
|
|
16
17
|
## Serving & chat
|
|
17
18
|
|
|
18
19
|
### `serve` — run the server
|
|
19
20
|
|
|
20
|
-
Start the OpenAI/Anthropic-compatible server plus the
|
|
21
|
-
|
|
21
|
+
Start the OpenAI/Anthropic-compatible server plus the browser web app (chat,
|
|
22
|
+
status, and model tools).
|
|
22
23
|
|
|
23
24
|
```sh
|
|
24
25
|
mlx-bun serve # default model, http://localhost:8080
|
|
@@ -34,16 +35,32 @@ Common flags (full list in [server-config.md](server-config.md)):
|
|
|
34
35
|
| `--host <addr>` | Interface to bind (default `127.0.0.1`, loopback only; `0.0.0.0` to expose) |
|
|
35
36
|
| `--port <n>` | Listen port (default 8080) |
|
|
36
37
|
| `--memory-budget <GB>` | Reject loads/requests that can't fit the budget |
|
|
37
|
-
| `--kv-
|
|
38
|
+
| `--kv-budget <GB>` | Aggregate KV budget across concurrent batch rows: over-budget joiners queue until rows finish; a request over the budget alone is rejected (off unless set) |
|
|
39
|
+
| `--prompt-cache <GB>` | RAM prefix-KV cache, byte-capped LRU (default 8; `0` disables). Non-consuming prefix sharing: a hit clones instead of consuming the donor entry |
|
|
40
|
+
| `--isolate` | Run the inference engine as a crash-isolated child process on a unix socket; this process becomes a pure reverse-proxy (instant under GPU load, auto-respawns on engine crash) — default off ([runtime-isolation.md](../design/runtime-isolation.md)) |
|
|
41
|
+
| `--model-pool <n>` | With `--isolate`: cap on resident per-model engine children (default 1); over the cap the LRU engine drains its cache to the SSD tier and exits, respawning on demand |
|
|
42
|
+
| `--ssd-cache <dir>` | SSD cold tier under the prompt cache: idle/evicted prefix-KV spills to disk and restores on reattach, surviving restarts (default off — [ssd-kv-cold-tier.md](../design/ssd-kv-cold-tier.md)) |
|
|
43
|
+
| `--ssd-cache-max <GB>` | SSD tier byte cap, oldest-mtime evicted first (default 32; `--ssd-cache` only) |
|
|
44
|
+
| `--ssd-cache-verify` | Verify every tensor hash on restore, not just the header (integrity paranoia; roughly doubles restore reads; `--ssd-cache` only) |
|
|
45
|
+
| `--ssd-demote-idle <sec>` | Idle prompt-cache entries spill to the SSD tier and free GPU memory after this long (default 300 with `--ssd-cache`; `0` disables) |
|
|
46
|
+
| `--kv-quant config\|off\|4\|8\|turbo[:k<bits>v<bits>]` | KV cache quantization: per-layer `kv_config.json`, bf16, uniform bits, or TurboQuant (rotation-based, default `k8v3` — [turboquant-kv.md](../design/turboquant-kv.md); full-attention layers only, solo-only/serial) (default `off` — quantized KV trades 5–20% decode speed for memory headroom, so it's opt-in) |
|
|
47
|
+
| `--paged-kv` | OPTIONAL vLLM-style paged KV cache (block pool + gather before the stock SDPA; env `MLX_BUN_PAGED_KV=1`) — bit-exact with the plain path, default off. v1: serial only (pins `--batch 1` unless `--batch` is given; refuses `--batch N>1`, `--kv-quant`, `--draft-model`), Gemma4-family, bf16; bypasses the prompt cache and runs uncompiled decode. Expect a small decode cost at batch=1 — v1 ships the abstraction for batched/CoW follow-ups ([paged-kv-cache.md](../design/paged-kv-cache.md)) |
|
|
48
|
+
| `--paged-kv-block-size <n>` | Tokens per KV block (default 256 = the plain cache's growth step; `--paged-kv` only) |
|
|
38
49
|
| `--adapter <dir>` | Mount a LoRA adapter at startup (`--adapter-path` accepted as the mlx_lm.server alias) |
|
|
39
|
-
| `--
|
|
50
|
+
| `--draft-model <path\|query>` | Speculative decoding: a drafter proposes, the main model verifies — exact results, faster decode when drafts land. The artifact's kind is auto-detected: a full same-tokenizer model (mlx_lm.server parity), a Gemma `-assistant` KV-borrowing drafter, a DSpark checkpoint trained here, or one of DeepSeek's released DSpark drafters (DeepSpec `Gemma4DSparkModel`, e.g. `dspark_gemma4_12b_block7`). Serial lane only: with `--batch N` a mounted draft routes every request serial |
|
|
51
|
+
| `--draft-kind <kind>` | Override draft-artifact detection: `two-model` \| `assistant` \| `dspark` \| `deepspec` \| `ngram` (default: auto). `ngram` is MODEL-FREE prompt lookup — no `--draft-model` (mounting one alongside it is refused): drafts are copied from the request's own prompt+generation whenever its trailing tokens have occurred earlier in that stream, verified by the target like any other draft, so results stay exact at any temperature. Zero weights, zero memory; best on agentic/RAG/code-edit traffic that re-emits spans already in context (prior art: prompt-lookup decoding / vLLM's `ngram` proposer) |
|
|
52
|
+
| `--num-draft-tokens <n>` | Drafts per verify round (default 3; `ngram` defaults to 10 — drafting is free; a DSpark draft pins to its trained block width) |
|
|
53
|
+
| `--ngram-max <k>` / `--ngram-min <k>` | Prompt-lookup match-window bounds, `--draft-kind ngram` only: the longest/shortest trailing k-gram searched (defaults 3 / 1, the reference values) |
|
|
54
|
+
| `--batch <n>` | Continuous-batched serving cap, mlx-lm B=N parity (default 8; `--batch 1` pins the serial path) |
|
|
40
55
|
| `--temperature` / `--top-p` / `--top-k` / `--max-tokens` | Server-wide sampling defaults (per-request fields still win) |
|
|
41
|
-
| `--l1` / `--l2`
|
|
56
|
+
| `--l1` / `--l2` | Parity tier alias: bit-exact to mlx-lm / bit-exact to mlx-optiq. **No tier = `--l1`** (the default since 2026-07-05 — output-changing levers are opt-in until they beat the L1 baseline in a paired A/B). Each expands to per-fork flags (`--compiled-decode`, `--compiled-activations`, `--fused-sdpa`, `--kv-quant`); a fork flag overrides one. `--l3` was removed 2026-07-05 and now errors (the Lab replaces it — [unified-engine-frontier-plan.md](../design/unified-engine-frontier-plan.md)). See [server-config.md](server-config.md#fidelity-tiers-and-the-decode-route---l1----l2). |
|
|
57
|
+
| `--allow-private-media` | Let `image_url`/`audio_url` parts fetch from private/loopback/link-local hosts (blocked by default — SSRF guard; the 10 s timeout and 64 MB cap on remote media apply either way) |
|
|
42
58
|
| `--no-open` | Don't auto-open the chat UI |
|
|
43
59
|
|
|
44
60
|
Endpoints: `/v1/chat/completions`, `/v1/completions`, `/v1/messages`,
|
|
45
61
|
`/v1/responses`, `/v1/models`, `/v1/adapters`, `/health`, `/stats`, `/fit`,
|
|
46
|
-
`/library`, `/downloads` —
|
|
62
|
+
`/library`, `/downloads` — web app at `/` (lands on chat); `/chat`, `/status`,
|
|
63
|
+
`/quantize`, `/finetune`, `/dataset` deep-link its views. Full
|
|
47
64
|
schemas in [server-api.md](server-api.md).
|
|
48
65
|
|
|
49
66
|
### `pi` — built-in coding agent
|
|
@@ -73,7 +90,7 @@ mlx-bun harness pi --remove # disconnect
|
|
|
73
90
|
|
|
74
91
|
Load the model, generate, print, exit — no server. Renders through the chat
|
|
75
92
|
template by default; `--raw` feeds the prompt verbatim. Sampling and
|
|
76
|
-
decode-path levers mirror `serve` (`--temperature`, `--seed`, `--l1/--l2
|
|
93
|
+
decode-path levers mirror `serve` (`--temperature`, `--seed`, `--l1/--l2`,
|
|
77
94
|
`--kv-quant`, …).
|
|
78
95
|
|
|
79
96
|
```sh
|
|
@@ -81,7 +98,7 @@ mlx-bun generate gemma "a haiku about metal shaders"
|
|
|
81
98
|
mlx-bun gen e4b --prompt "…" --max-tokens 512 --seed 42
|
|
82
99
|
```
|
|
83
100
|
|
|
84
|
-
### `embed` — text embeddings
|
|
101
|
+
### `embed` — text embeddings
|
|
85
102
|
|
|
86
103
|
One-shot embeddings from a local Qwen3-Embedding model (last-token pooled,
|
|
87
104
|
L2-normalized — bit-exact vs mlx-lm). One JSON vector per input line.
|
|
@@ -125,10 +142,12 @@ mlx-bun ls --vision --max-size 10GB # filter
|
|
|
125
142
|
mlx-bun ls --all-revisions # one row per cached snapshot
|
|
126
143
|
```
|
|
127
144
|
|
|
128
|
-
### `gc` — reclaim disk
|
|
145
|
+
### `gc` — reclaim disk
|
|
129
146
|
|
|
130
147
|
Delete superseded snapshots and the blobs only they reference. Prints the plan
|
|
131
|
-
by default; `--yes` actually deletes.
|
|
148
|
+
by default; `--yes` actually deletes. Same planner (`src/registry.ts`
|
|
149
|
+
`planGc`/`executeGc`) also backs `GET /api/gc/plan` / `POST /api/gc/execute`
|
|
150
|
+
on a running `serve` — see [server-api.md](server-api.md#get-apigcplan--post-apigcexecute).
|
|
132
151
|
|
|
133
152
|
```sh
|
|
134
153
|
mlx-bun gc # dry-run: what would be reclaimed
|
|
@@ -170,7 +189,7 @@ Tails an adapter dir's `metrics.jsonl` and renders live loss / speed / memory.
|
|
|
170
189
|
mlx-bun train-watch ~/.cache/mlx-bun/mlx-bun-finetunes/orpo-e4b
|
|
171
190
|
```
|
|
172
191
|
|
|
173
|
-
### `fuse` — merge an adapter into the base
|
|
192
|
+
### `fuse` — merge an adapter into the base
|
|
174
193
|
|
|
175
194
|
Folds LoRA deltas into the base weights and writes a standalone snapshot; a
|
|
176
195
|
quantized base keeps its exact quantization layout. Flag names match
|
|
@@ -181,7 +200,7 @@ mlx-bun fuse e4b --adapter ./adapters --save-path ./fused_model
|
|
|
181
200
|
mlx-bun serve ./fused_model
|
|
182
201
|
```
|
|
183
202
|
|
|
184
|
-
### `convert` — quantize a model
|
|
203
|
+
### `convert` — quantize a model
|
|
185
204
|
|
|
186
205
|
Quantize an HF model (local path, downloaded model, or repo id) into a local
|
|
187
206
|
MLX snapshot — uniform 4/8-bit, or mixed-precision via `--target-bpw`
|
|
@@ -192,7 +211,7 @@ mlx-bun convert Qwen/Qwen3-4B -q # uniform 4-bit
|
|
|
192
211
|
mlx-bun convert Qwen/Qwen3-4B --target-bpw 4.5 # mixed precision
|
|
193
212
|
```
|
|
194
213
|
|
|
195
|
-
### `upload` — push to the Hugging Face Hub
|
|
214
|
+
### `upload` — push to the Hugging Face Hub
|
|
196
215
|
|
|
197
216
|
Native push-to-hub, no Python: creates the repo if needed, uploads via the
|
|
198
217
|
git-LFS batch protocol, commits. Flag names match `mlx_lm.upload`.
|
|
@@ -201,7 +220,7 @@ git-LFS batch protocol, commits. Flag names match `mlx_lm.upload`.
|
|
|
201
220
|
mlx-bun upload --path ./fused_model --upload-repo you/my-model
|
|
202
221
|
```
|
|
203
222
|
|
|
204
|
-
### `perplexity` — evaluate on your data
|
|
223
|
+
### `perplexity` — evaluate on your data
|
|
205
224
|
|
|
206
225
|
`mlx_lm.perplexity` methodology exactly, over a **local** `.jsonl`/`.txt` file.
|
|
207
226
|
|
|
@@ -226,7 +245,7 @@ mlx-bun memory synthesize # conversations → cross-linked articles, all
|
|
|
226
245
|
mlx-bun memory schedule --at 03:00
|
|
227
246
|
```
|
|
228
247
|
|
|
229
|
-
`setup` is an alias for `memory
|
|
248
|
+
`setup` is an alias for `memory`.
|
|
230
249
|
|
|
231
250
|
## Measurement
|
|
232
251
|
|
|
@@ -156,8 +156,8 @@ manual escape hatch if offline.
|
|
|
156
156
|
|
|
157
157
|
## npm / bunx
|
|
158
158
|
|
|
159
|
-
mlx-bun is published to npm as `mlx-bun
|
|
160
|
-
|
|
159
|
+
mlx-bun is published to npm as `mlx-bun`. Install or run without a
|
|
160
|
+
permanent install:
|
|
161
161
|
|
|
162
162
|
```sh
|
|
163
163
|
# one-off (no install)
|
|
@@ -168,10 +168,17 @@ bun install -g mlx-bun
|
|
|
168
168
|
mlx-bun --version
|
|
169
169
|
```
|
|
170
170
|
|
|
171
|
-
The npm package
|
|
172
|
-
|
|
173
|
-
|
|
171
|
+
The npm package is a thin launcher (no postinstall hook): it imports
|
|
172
|
+
`src/cli.ts` under Bun, which fetches the small (~52 MB compressed,
|
|
173
|
+
sha256-verified) native runtime pack — `libmlxc`/`libmlx`/`libjaccl`/
|
|
174
|
+
`mlx.metallib` — into `~/Library/Caches/mlx-bun/` on first invocation if
|
|
175
|
+
no copy is already resolvable (env / beside the binary / cache /
|
|
176
|
+
Homebrew). This is the same npm/sidecar mechanism described above, not
|
|
177
|
+
the signed/notarized Homebrew bundle. `bun publish` is already run
|
|
178
|
+
automatically and idempotently as step 4 of `PUBLISH=1
|
|
179
|
+
./scripts/release-binary.sh`; run it standalone only as a manual
|
|
180
|
+
fallback/retry:
|
|
174
181
|
|
|
175
182
|
```sh
|
|
176
|
-
bun publish #
|
|
183
|
+
bun publish # manual retry; package.json version must already be bumped
|
|
177
184
|
```
|
|
@@ -19,15 +19,29 @@ Produces a relocatable directory:
|
|
|
19
19
|
|
|
20
20
|
| file | what | size (arm64) |
|
|
21
21
|
|---|---|---|
|
|
22
|
-
| `mlx-bun` | the CLI/server, compiled with `bun build --compile` | ~
|
|
22
|
+
| `mlx-bun` | the CLI/server, compiled with `bun build --compile` | ~70-75 MB |
|
|
23
23
|
| `libmlxc.dylib` | mlx-c, rewritten to load `@loader_path/libmlx.dylib` | ~0.7 MB |
|
|
24
24
|
| `libmlx.dylib` | mlx core (+`@loader_path` rpath added for libjaccl) | ~15 MB |
|
|
25
25
|
| `libjaccl.dylib` | mlx's distributed-comm dependency | ~0.6 MB |
|
|
26
26
|
| `mlx.metallib` | Metal kernels — libmlx loads it from its own directory | ~150 MB |
|
|
27
27
|
| `photon_rs_bg.wasm` | pi image codec — only the web chat's `read`-on-image path; resolved next to the executable | ~1.8 MB |
|
|
28
28
|
|
|
29
|
+
`build-binary.sh` also sidecars a second set of assets for the embedded
|
|
30
|
+
pi **terminal** (`mlx-bun pi`, `src/pi-terminal.ts` → `InteractiveMode`),
|
|
31
|
+
none of which the headless web chat touches:
|
|
32
|
+
|
|
33
|
+
| file | what |
|
|
34
|
+
|---|---|
|
|
35
|
+
| `theme/*.json` | TUI color themes (built-in dark/light fallback exists in code; shipped so custom theme reads and the schema resolve) |
|
|
36
|
+
| `assets/*.png` | TUI startup art |
|
|
37
|
+
| `export-html/template.html`, `export-html/vendor/*.js` | the `/export` command's HTML template + vendor JS |
|
|
38
|
+
| `package.json`, `CHANGELOG.md` | version banner + startup changelog |
|
|
39
|
+
| `native/darwin/prebuilds/<arch>/darwin-modifiers.node` | pi-tui's native modifier-key detection (degrades gracefully if absent) |
|
|
40
|
+
|
|
29
41
|
Library resolution order (src/mlx/ffi.ts): `MLX_BUN_LIBMLXC` env var →
|
|
30
|
-
`libmlxc.dylib` next to the executable →
|
|
42
|
+
`libmlxc.dylib` next to the executable → the downloaded native-pack
|
|
43
|
+
cache (`~/Library/Caches/mlx-bun/native-v<ver>-<arch>/`, populated on
|
|
44
|
+
first run when no sidecar or homebrew install is found) → homebrew
|
|
31
45
|
(`/opt/homebrew/lib`, `/usr/local/lib`). The whole directory can be
|
|
32
46
|
renamed/moved; nothing references absolute paths after the build
|
|
33
47
|
script's `install_name_tool` fixups.
|
|
@@ -60,21 +74,28 @@ crashing), so it is best-effort, not load-bearing.
|
|
|
60
74
|
> The web chat itself is unaffected (its provider is text-only), and the
|
|
61
75
|
> wasm is shipped so it will work once Bun's support lands.
|
|
62
76
|
|
|
63
|
-
|
|
64
|
-
|
|
77
|
+
## Embedded pi terminal (`mlx-bun pi`)
|
|
78
|
+
|
|
79
|
+
The compiled binary also embeds pi's full interactive TUI
|
|
80
|
+
(`src/pi-terminal.ts` → `InteractiveMode`), reachable via `mlx-bun pi`.
|
|
81
|
+
Unlike the headless web chat, the terminal *does* resolve theme JSON,
|
|
82
|
+
startup art, the `/export` template, the version banner, and the
|
|
83
|
+
pi-tui native modifier-key helper by path — the second table above is
|
|
84
|
+
sidecar'd for exactly this mode. `src/pi-web.ts`'s session (the web
|
|
85
|
+
chat) still builds with `noThemes`/`noSkills`/`noExtensions`/
|
|
86
|
+
`noPromptTemplates`/`noContextFiles`, so none of that table is reached
|
|
87
|
+
from `/ws/chat` — only `mlx-bun pi` uses it.
|
|
88
|
+
|
|
89
|
+
**Omitted** (upstream pi ships these beside its own binary; neither
|
|
90
|
+
mlx-bun mode reaches them):
|
|
65
91
|
|
|
66
92
|
| omitted asset | what it's for |
|
|
67
93
|
|---|---|
|
|
68
|
-
| `
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
These are gated behind TUI code paths and the explicit `exportToHtml()`
|
|
74
|
-
method; `createAgentSession`'s import graph (`core/sdk.js`) pulls in no
|
|
75
|
-
theme/asset/export-html loaders, and `src/pi-web.ts` builds the session
|
|
76
|
-
with `noThemes`/`noSkills`/`noExtensions`/`noPromptTemplates`/
|
|
77
|
-
`noContextFiles`.
|
|
94
|
+
| `docs/`, `examples/`, `README.md` | upstream's own help/doc browsing, not exposed by either mlx-bun entry point |
|
|
95
|
+
|
|
96
|
+
`createAgentSession`'s import graph (`core/sdk.js`) pulls in no loaders
|
|
97
|
+
for these; both `src/pi-web.ts` and `src/pi-terminal.ts` build sessions
|
|
98
|
+
that never reference them.
|
|
78
99
|
|
|
79
100
|
**Verifying it.** `build-binary.sh` runs `scripts/verify-binary-pi.ts` as
|
|
80
101
|
a sibling compiled binary inside the bundle (so `process.execPath` points
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Features matrix — everything mlx-bun serves, in one table
|
|
2
|
+
|
|
3
|
+
The complete option inventory: every serving feature, its default, which
|
|
4
|
+
execution lane it runs on, which fidelity tier verifies it, and its knob.
|
|
5
|
+
This is the *what-exists* view; per-flag detail lives in
|
|
6
|
+
[server-config.md](server-config.md), wire formats in
|
|
7
|
+
[server-api.md](server-api.md), CLI verbs in [cli.md](cli.md).
|
|
8
|
+
|
|
9
|
+
**Lanes:** `serial` = the default single-queue path; `batch` = the
|
|
10
|
+
`--batch N` continuous-batching engine (bf16 compat mode, mlx-lm B=N
|
|
11
|
+
parity). **Tiers:** L1 = bit-exact vs mlx-lm · L2 = bit-exact vs mlx-optiq
|
|
12
|
+
· Lab = no external oracle; KL/eval-gated experiments (see
|
|
13
|
+
[server-config.md → Fidelity tiers](server-config.md#fidelity-tiers-and-the-decode-route---l1----l2)).
|
|
14
|
+
|
|
15
|
+
## Serving & performance
|
|
16
|
+
|
|
17
|
+
| Feature | Default | Lane | Tier | Knob |
|
|
18
|
+
| --- | --- | --- | --- | --- |
|
|
19
|
+
| OpenAI chat completions (`/v1/chat/completions`, SSE) | on | both | — | — |
|
|
20
|
+
| Raw text completions (`/v1/completions`) | on | both | — | — |
|
|
21
|
+
| Anthropic Messages (`/v1/messages`) | on | both | — | — |
|
|
22
|
+
| OpenAI Responses shim (`/v1/responses`) | on | both | — | — |
|
|
23
|
+
| Continuous batching (mlx-lm B=N parity) | **on** — cap 8 (default flipped 2026-07-05; a lone request runs the exact serial engine, so the cap engages only under real concurrency; `--batch 1` pins serial) | batch | L1 | `--batch <n>` |
|
|
24
|
+
| Prompt cache (prefix KV reuse) | on, 8 GB | both | — | `--prompt-cache <GB>` (0 = off) |
|
|
25
|
+
| **SSD KV cold tier** (cache survives eviction + restarts) | off | both | — | `--ssd-cache <dir>` (+ `-max`, `-verify`, `-demote-idle <sec>` — default 300s once `--ssd-cache` is on, `0` disables) |
|
|
26
|
+
| **Runtime isolation** (engine runs as a crash-isolated CHILD process behind a reverse-proxy parent; UI stays instant under GPU load and survives engine crashes — [runtime-isolation.md](../design/runtime-isolation.md)) | off | both | — | `--isolate` |
|
|
27
|
+
| **Model pool** (with `--isolate`: LRU-capped RESIDENT model engines; over the cap the least-recently-used engine demotes its cache to the SSD tier and exits, respawning on the next request) | 1 resident engine | both | — | `--model-pool <n>` (requires `--isolate`) |
|
|
28
|
+
| Mixed-precision KV (`kv_config.json`, optiq's scheme) | **off** — opt-in (default flipped to bf16 2026-07-05; quantized KV trades 5–20% decode for memory headroom) | serial + **batch** (per-layer configs batch on every shipped model — full-attention layers Phase 3.1, rotating layers milestone 2; uniform bits stay serial) | L2 | `--kv-quant config\|off\|4\|8`, `--l2` |
|
|
29
|
+
| **TurboQuant KV** (rotation-based: affine keys + FWHT/Lloyd-Max values) | off — opt-in ([turboquant-kv.md](../design/turboquant-kv.md); v1 dequantize-on-fetch, full-attention layers only, no speed claim) | serial only (solo-only, unconditionally) | Lab (codec is oracle-backed vs vllm-metal; the cache class is unvalidated) | `--kv-quant turbo[:k<bits>v<bits>]` (default `k8v3`) |
|
|
30
|
+
| Compiled decode (bit-exact graph replay) | on, every tier | serial | L1/L2 | `--compiled-decode on\|off` |
|
|
31
|
+
| Compiled activations (faithful geglu/swiglu — mlx-lm's `@mx.compile`) | **on**, every tier | both | L1 | `--compiled-activations on\|off` |
|
|
32
|
+
| Fused SDPA (optiq-exact quantized-KV attention) | follows `--kv-quant`: on for `config`, off for uniform/bf16 | serial | L2 | `--fused-sdpa on\|off` |
|
|
33
|
+
| **Paged KV** (vLLM-style block pool: host-side block table + gather before the stock SDPA, no fused kernel in v1 — [paged-kv-cache.md](../design/paged-kv-cache.md)) | off | serial (pins `--batch 1` unless `--batch` given) | gated bit-exact vs the plain `KVCache` (`tests/paged-kv-parity.test.ts`) | `--paged-kv`, `--paged-kv-block-size <n>` (default 256) — v1 scope Gemma4-family bf16; refuses `--batch N>1`, `--kv-quant`, `--draft-model` |
|
|
34
|
+
| **Speculative decoding** (auto-detected drafter: two-model = mlx-lm parity/L1, Gemma `-assistant` = optiq/L2, DSpark local = Lab, DeepSpec released = DeepSpec-reference oracle) | off | serial (forces all-serial) | per-drafter oracle | `--draft-model <path\|query>`, `--draft-kind`, `--num-draft-tokens` |
|
|
35
|
+
| Speculative decoding, **model-free prompt lookup** (drafts copied from the request's own context; port of prompt-lookup decoding / vLLM `ngram`; zero weights) | off | serial (forces all-serial) | lossless by verify (gated vs non-spec greedy, tests/spec-ngram.test.ts) | `--draft-kind ngram` (no `--draft-model`), `--ngram-max`, `--ngram-min`, `--num-draft-tokens` (default 10) |
|
|
36
|
+
| Memory admission (refuse what can't fit; never GPU-OOM) | on (RAM × 0.75) | both | — | `--memory-budget <GB>` |
|
|
37
|
+
| Aggregate KV admission for batch rows (queue, don't OOM) | off | batch | — | `--kv-budget <GB>` |
|
|
38
|
+
| Expert offload (MoE cold experts on mmap) | off | serial | Lab | `--expert-offload` |
|
|
39
|
+
| Extend-join (O(1) batch admission) | on | batch | L1 (own oracle) | `MLX_BUN_BATCH_EXTEND=0` |
|
|
40
|
+
| Vectorized greedy batch sampling | on | batch | bit-equal A/B | `MLX_BUN_BATCH_VEC_SAMPLE=0` |
|
|
41
|
+
|
|
42
|
+
## Request features
|
|
43
|
+
|
|
44
|
+
| Feature | Default | Lane | Tier | Knob |
|
|
45
|
+
| --- | --- | --- | --- | --- |
|
|
46
|
+
| **Structured output** (`response_format` json_object/json_schema) | on | both | L2 (oMLX) | request field; `MLX_BUN_GRAMMAR=0` kills |
|
|
47
|
+
| Structured output **jump-forward** (grammar-forced spans emitted without per-token forwards; SGLang technique via xgrammar) | **off** | serial only | Lab (string-lossless + validity gates, tests/grammar-jump.test.ts; token stream may differ — no oracle) | `MLX_BUN_GRAMMAR_JUMP=1` |
|
|
48
|
+
| `guided_grammar` (EBNF) / `guided_regex`¹ / `guided_choice` / `structured_outputs` | on | both | L2 | request fields |
|
|
49
|
+
| Structured output × speculative decoding | on (when both active) | serial | Lab (validity+equivalence) | — |
|
|
50
|
+
| Quantized KV × speculative decoding (any axis: uniform / config / turbo) | KV scheme wins — drafted requests decode serially WITHOUT speculation (spec lane is bf16-KV-only in v1; startup warning) | serial | — | omit `--kv-quant` to speculate |
|
|
51
|
+
| Tool calling (Gemma sentinel / CPM+Qwen XML) + `role:"tool"` loops | on | both | — | request `tools` |
|
|
52
|
+
| Vision (`image_url` parts; PNG/JPEG/HEIC/AVIF/WebP/TIFF/GIF/BMP) | on (models with a tower); remote fetches refuse private/loopback/link-local hosts by default (SSRF guard) | serial | L1/L2 | `--allow-private-media` / `MLX_BUN_ALLOW_PRIVATE_MEDIA=1` re-permits LAN hosts |
|
|
53
|
+
| **Audio input** (`input_audio`/`audio`/`audio_url` parts; WAV native, mp3/m4a/flac/ogg/aiff via CoreAudio; ≤30 s / 750 tokens per clip; mixes with images) | on (models with `audio_config` + sidecar tower: e4b); remote fetches refuse private/loopback/link-local hosts by default (SSRF guard) | serial³ | L2 (greedy stream EXACT vs the optiq internal model) | `--allow-private-media` / `MLX_BUN_ALLOW_PRIVATE_MEDIA=1` re-permits LAN hosts |
|
|
54
|
+
| LoRA adapters (mount at start / hot-swap at runtime) | off | serial | — | `--adapter <dir>`, `POST /v1/adapters` |
|
|
55
|
+
| Sampling: temperature / top-p / top-k / min-p / XTC / logit_bias / presence+frequency+repetition penalties | per-request | both | L1 (mlx-lm-faithful) | request fields / server defaults |
|
|
56
|
+
| `logprobs` / `top_logprobs` (mlx-lm semantics) | off | serial | L1 | request fields |
|
|
57
|
+
| Fixed `seed` reproducibility | off | serial (routes solo) | — | request field |
|
|
58
|
+
| Thinking-mode control (hybrid-reasoning models) | model default | both | — | `--thinking`, `chat_template_kwargs` |
|
|
59
|
+
| Stop sequences / streaming / usage accounting | on | both | — | request fields |
|
|
60
|
+
| HLG tone-curve sampling | off | serial | Lab | `--hlg-sampling on` |
|
|
61
|
+
| Spec-decode telemetry (`usage.speculation`) | on with a draft | serial | — | — |
|
|
62
|
+
| Per-turn lane telemetry (`usage.lane`: serial / serial+spec / batched) | on | both | — | — |
|
|
63
|
+
|
|
64
|
+
## Model coverage (per-model validated cells — no generic path is trusted untested)
|
|
65
|
+
|
|
66
|
+
| Family | Serial | Batch | Notes |
|
|
67
|
+
| --- | --- | --- | --- |
|
|
68
|
+
| MiniCPM5 (cpm5) | ✅ L1/L2 | ✅ | the starter model |
|
|
69
|
+
| Gemma 4 (1B/e4b/12B/26B, + vision e4b/12B, + audio e4b) | ✅ L1/L2 | ✅ | sliding+full interleaved; MoE 26B |
|
|
70
|
+
| Qwen3.5 (gated-DeltaNet hybrid) | ✅ L1/L2 | ✅ (SSM path) | `MLX_BUN_BATCH_SSM=0` reverts |
|
|
71
|
+
| DiffusionGemma-26B (non-autoregressive) | ✅ (own engine) | — serial always | first bit-exact non-AR port |
|
|
72
|
+
| Tier-0 universal (llama/qwen2/qwen3/olmo2/…, 11 archs) | ✅ L1 | ✅ plain full-attention archs² | gemma2-family/sliding universal → serial |
|
|
73
|
+
|
|
74
|
+
## Beyond serving (the same binary)
|
|
75
|
+
|
|
76
|
+
Training (`mlx-bun train`: ORPO/DPO/SFT, flash-CCE, segmented backward) ·
|
|
77
|
+
quantization (`convert`, `fuse`, `--target-bpw`) · embeddings · local
|
|
78
|
+
memory/wiki (`mlx-bun memory`) · pi agent integration (`mlx-bun pi`) ·
|
|
79
|
+
model registry + `fit` planner + `gc` · HF `upload` · web chat Model Hub
|
|
80
|
+
(`/api/hub/local` + `/search` + `/download`, per-row `/fit` verdict;
|
|
81
|
+
`/api/hub/serve` is `restart_required`-only today — no in-process model-swap
|
|
82
|
+
seam reaches `/ws/chat`, see [server-api.md](server-api.md#model-hub-apihub))
|
|
83
|
+
· **PWA installability** (manifest + shell-only service worker —
|
|
84
|
+
installable, instant static-shell paint; explicitly not offline chat, see
|
|
85
|
+
[server-api.md](server-api.md#web-app-static-routes--pwa-installability)).
|
|
86
|
+
See [cli.md](cli.md) and the per-topic reference docs.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
¹ `guided_regex` accepts the regex∩EBNF subset today (no `\d`/anchors — those degrade to prompt injection); real regex support is tracked.
|
|
90
|
+
² Gated token-exact vs mlx-lm B=2 (static + dynamic join/leave) on Llama-3.2-3B.
|
|
91
|
+
³ Audio is a capability neither ancestor SERVES: mlx-lm strips the audio tower at load and 400s non-text parts; optiq ships the full machinery but never wires it into its serve frontend — mlx-bun exposes it. Serial lane by design (embeddings prefill; batched audio has no oracle → novel-territory gates would apply), prompt cache skipped.
|
|
92
|
+
|
|
93
|
+
Composition rules and exclusions (what combines with what):
|
|
94
|
+
[server-config.md → Compatibility matrix](server-config.md#compatibility-matrix).
|
|
95
|
+
Performance per mode: `scripts/bench-modes.ts` (TTFT / prefill / decode /
|
|
96
|
+
peak-memory across every cell above); feature-composition perf:
|
|
97
|
+
`scripts/bench-feature-matrix.ts`.
|
|
@@ -3,16 +3,19 @@
|
|
|
3
3
|
The HTTP server is one consumer of a library-first API. Everything it
|
|
4
4
|
does — generation, sampling, KV schemes, LoRA, vision, caching, memory
|
|
5
5
|
admission — is importable directly into a Bun process. Published as
|
|
6
|
-
`mlx-bun` on npm
|
|
6
|
+
`mlx-bun` on npm; `bunx mlx-bun` works out of the box, or
|
|
7
7
|
`import … from "mlx-bun"` for programmatic use.
|
|
8
8
|
|
|
9
|
-
One rule everywhere: **one generation at a time per process** (one GPU
|
|
10
|
-
|
|
9
|
+
One rule everywhere: **one generation at a time per process** (one GPU).
|
|
10
|
+
The server serializes through a queue (or, under `--batch N`, its
|
|
11
|
+
continuous-batching scheduler — a server-lane feature, not a library
|
|
12
|
+
surface); direct library callers must do the same.
|
|
11
13
|
|
|
12
14
|
## Quick start
|
|
13
15
|
|
|
14
16
|
```ts
|
|
15
17
|
import {
|
|
18
|
+
ensureNativeRuntime,
|
|
16
19
|
loadModelConfig,
|
|
17
20
|
Weights,
|
|
18
21
|
createModel, // dispatches to Gemma4Model / MiniCPM5Model / Qwen35Model
|
|
@@ -21,6 +24,7 @@ import {
|
|
|
21
24
|
generate,
|
|
22
25
|
} from "mlx-bun"; // or "./src/index" in-repo
|
|
23
26
|
|
|
27
|
+
await ensureNativeRuntime();
|
|
24
28
|
const dir = "/path/to/hf-snapshot"; // mlx-bun ls prints these
|
|
25
29
|
const config = await loadModelConfig(dir);
|
|
26
30
|
const model = createModel(await Weights.open(dir), config); // returns RuntimeModel
|
|
@@ -29,7 +33,7 @@ const template = await ChatTemplate.load(dir);
|
|
|
29
33
|
// Gemma4Model and MiniCPM5Model can still be imported directly from "mlx-bun"
|
|
30
34
|
// if you need the concrete type. Qwen35Model is NOT exported from the public
|
|
31
35
|
// package — use createModel/RuntimeModel (preferred dispatch), or import from
|
|
32
|
-
// "./src/model/
|
|
36
|
+
// "./src/model/qwen3_5" in-repo.
|
|
33
37
|
|
|
34
38
|
const ids = tok.encode(template.render([{ role: "user", content: "hi" }]));
|
|
35
39
|
const promptIds = ids[0] === ids[1] && ids[0] === tok.bosTokenId ? ids.slice(1) : ids;
|
|
@@ -44,6 +48,14 @@ console.log(gen.stats); // set once iteration ends
|
|
|
44
48
|
Weight loading is lazy (mmap + mlx native loader): construction is
|
|
45
49
|
milliseconds; weights materialize on first forward.
|
|
46
50
|
|
|
51
|
+
> **First run:** library consumers bypass the CLI's first-run step, so
|
|
52
|
+
> call `await ensureNativeRuntime()` once before constructing a model on
|
|
53
|
+
> a machine that may not have the MLX native runtime yet — it downloads
|
|
54
|
+
> the sha256-verified native pack to `~/Library/Caches/mlx-bun/` and is
|
|
55
|
+
> a no-op when the runtime is already present (beside the executable,
|
|
56
|
+
> already cached, or installed via homebrew). `nativeRuntimeDir()`
|
|
57
|
+
> returns the resolved directory, or `null` on a fresh machine.
|
|
58
|
+
|
|
47
59
|
## generate(model, promptTokens, options) → Generation
|
|
48
60
|
|
|
49
61
|
`Generation` is an `AsyncIterable<GeneratedToken>` with a `stats`
|
|
@@ -64,13 +76,20 @@ after an early `break`, which cleanly cancels the in-flight step).
|
|
|
64
76
|
| `kvConfig` | off | per-layer mixed precision from `kv_config.json` (`config.kvQuant`); overrides `kvBits`, start 0 — optiq serve semantics |
|
|
65
77
|
| `adapters` | none | mounted LoRA adapter ids, applied for exactly this generation |
|
|
66
78
|
| `promptEmbeddings` / `imageMask` | — | vision path (see `src/vision/`) |
|
|
79
|
+
| `logprobs` / `topLogprobs` | off | per-token logprob capture (mlx_lm.server parity): `logprobs` captures the emitted token's log-probability, `topLogprobs` (0/unset = off) captures the top-k (id, logprob) pairs — same full-vocab log-softmax distribution mlx-lm's generate_step samples from, taken after logits processors and before the sampler |
|
|
80
|
+
| `grammar` | off | a compiled `GrammarController` (`src/grammar.ts`) for structured output — masks invalid tokens to `-inf` each step (L2-class, oMLX oracle) |
|
|
81
|
+
| `turboQuant` | off | TurboQuant KV scheme (docs/design/turboquant-kv.md), a rotation-based alternative to uniform `kvBits`; mutually exclusive with `kvBits`/`kvConfig` |
|
|
82
|
+
| `pagedKv` | off | `{ blockSize? }` — OPTIONAL paged KV cache (docs/design/paged-kv-cache.md); v1 scope is serial batch=1 Gemma4-family bf16, mutually exclusive with `kvBits`/`kvConfig`/`turboQuant`/draft/compiled decode |
|
|
67
83
|
|
|
68
84
|
`GenerateStats`: `promptTokens`, `cachedTokens`, `generatedTokens`,
|
|
69
85
|
`prefillTps` / `prefillMs`, `decodeTps` / `decodeMs`, `cacheTokens`
|
|
70
86
|
(the exact token sequence whose KV is in the cache — feed it to
|
|
71
87
|
`PromptCache.put`). Timing semantics match mlx-lm: the prompt clock
|
|
72
88
|
runs until the first token arrives (the prefill→decode boundary is
|
|
73
|
-
prompt time), the decode clock from there.
|
|
89
|
+
prompt time), the decode clock from there. An optional `spec` field
|
|
90
|
+
carries speculative-decoding telemetry (serve `--draft-model` path
|
|
91
|
+
only): `drafted`, `accepted`, `targetCalls`, and per-draft-position
|
|
92
|
+
`draftedByPos` / `acceptedByPos` counts.
|
|
74
93
|
|
|
75
94
|
## Serving pieces
|
|
76
95
|
|
|
@@ -80,7 +99,7 @@ import { loadContext, createServer } from "mlx-bun";
|
|
|
80
99
|
const ctx = await loadContext(dir, "my-model", { memoryBudgetBytes: 12e9 });
|
|
81
100
|
const server = createServer(ctx, 8080, {
|
|
82
101
|
promptCacheBytes: 2e9, // byte-capped LRU (never count-capped)
|
|
83
|
-
kvQuant: undefined, // default: kv_config.json; "off" | bits
|
|
102
|
+
kvQuant: undefined, // default: kv_config.json; "off" | "config" | bits
|
|
84
103
|
memoryBudgetBytes: 12e9, // admission control — the only OOM defense
|
|
85
104
|
});
|
|
86
105
|
```
|
|
@@ -135,11 +154,13 @@ under one adapter must not seed another's prefill).
|
|
|
135
154
|
```ts
|
|
136
155
|
import { saveKvCache, loadKvCache } from "./src/kv-store";
|
|
137
156
|
saveKvCache("/tmp/prefix.kv", tokens, caches); // page-aligned file
|
|
138
|
-
const { tokens, caches, mmap } = loadKvCache("/tmp/prefix.kv", model
|
|
157
|
+
const { tokens, caches, mmap } = loadKvCache("/tmp/prefix.kv", model);
|
|
139
158
|
// reload is a zero-copy MAP_PRIVATE mmap straight to the GPU (~1 ms);
|
|
140
159
|
// keep `mmap` referenced as long as the caches live
|
|
141
|
-
// Note: loadKvCache
|
|
142
|
-
//
|
|
160
|
+
// Note: loadKvCache accepts anything with makeCache(): Cache[] — it validates
|
|
161
|
+
// the entry count against the cache list makeCache() returns (not
|
|
162
|
+
// model.layers.length, which is wrong for KV-shared models like e4b, whose
|
|
163
|
+
// makeCache() returns donors only). RuntimeModel qualifies directly, no cast.
|
|
143
164
|
```
|
|
144
165
|
|
|
145
166
|
Quantized caches are not persistable yet (documented gap).
|
package/docs/reference/memory.md
CHANGED
|
@@ -42,18 +42,38 @@ mlx-bun memory unschedule
|
|
|
42
42
|
|
|
43
43
|
## Agent tools
|
|
44
44
|
|
|
45
|
-
Both `mlx-bun pi` and the web chat expose these read-only tools:
|
|
45
|
+
Both `mlx-bun pi` and the web chat expose these read-only tools, in the recommended call order — FIND the article, READ it small, follow the graph, fall back to reference docs and utilities, search only as a last resort:
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
- `
|
|
49
|
-
- `
|
|
50
|
-
|
|
51
|
-
-
|
|
47
|
+
**FIND** (deterministic lookup, never a vector search):
|
|
48
|
+
- `memory_resolve` — name/alias → the article
|
|
49
|
+
- `memory_category` — category/type/series → members
|
|
50
|
+
|
|
51
|
+
**READ** (TOC → one section, not a full-article dump):
|
|
52
|
+
- `memory_read` — TOC + lead by default; `force=true` for the full article
|
|
53
|
+
- `memory_section` — one section's body (the default granularity)
|
|
54
|
+
|
|
55
|
+
**Follow the graph**:
|
|
56
|
+
- `memory_links` — outbound/inbound wikilinks
|
|
57
|
+
- `memory_infobox` — read an article's infobox fields (there is no infobox *query* tool — the infobox is content the model reads, not a filter)
|
|
58
|
+
|
|
59
|
+
**Reference docs** (mlx-bun's own docs, mirrored read-only into the vault):
|
|
60
|
+
- `reference_search`
|
|
61
|
+
- `reference_read`
|
|
62
|
+
- `reference_list`
|
|
63
|
+
|
|
64
|
+
**Utility**:
|
|
52
65
|
- `memory_list` — user articles plus read-only `Reference/*` docs
|
|
53
66
|
- `memory_status` — vault path, setup state, article count, git state, last synthesis run (from the vault's git log), schedule state, recent changed articles
|
|
54
67
|
|
|
68
|
+
**Last resort**:
|
|
69
|
+
- `memory_search` — substring fallback when FIND failed
|
|
70
|
+
|
|
55
71
|
The tools are always registered. If no vault exists, they return a setup message instead of disappearing. Search/read results prefixed with `Reference/` are mlx-bun docs, not user memory articles.
|
|
56
72
|
|
|
73
|
+
## Web chat REST surface
|
|
74
|
+
|
|
75
|
+
The web chat's Memory panel talks to a separate, HTTP-only `/api/memory/*` route surface (status/list/search/article/links/history/diff + a `POST /api/memory/init` consent-card endpoint) — thin wrappers over the same vault read path above, documented in [server-api.md](server-api.md#get-apimemory--post-apimemoryinit). The agent-tool surface above is unaffected by it.
|
|
76
|
+
|
|
57
77
|
## Obsidian
|
|
58
78
|
|
|
59
79
|
```bash
|
package/docs/reference/models.md
CHANGED
|
@@ -79,6 +79,8 @@ Schema (table `models`, one row **per snapshot**, keyed on `path`):
|
|
|
79
79
|
| `quant_bits`, `quant_group_size`, `quant_mode` | quantization |
|
|
80
80
|
| `has_vision_sidecar` | sidecar file present |
|
|
81
81
|
| `vision_config_type` | `config.json`'s `vision_config.model_type` when it names a vision tower (`*_vision`) |
|
|
82
|
+
| `has_audio_config` | `config.json` declares an `audio_config` block |
|
|
83
|
+
| `has_audio_tower` | sidecar header names `audio_tower.*` tensors |
|
|
82
84
|
| `has_kv_config`, `has_tool_template`, `license` | capabilities/terms |
|
|
83
85
|
| `scanned_at` | freshness (canonical tie-break) |
|
|
84
86
|
|
|
@@ -89,6 +91,14 @@ Schema (table `models`, one row **per snapshot**, keyed on `path`):
|
|
|
89
91
|
Presence of a `vision_config` key alone is **not** a signal — Qwen3.5
|
|
90
92
|
nests a copy of its own text config there.
|
|
91
93
|
|
|
94
|
+
**Audio capability** is `has_audio_config AND has_audio_tower`: both
|
|
95
|
+
legs are required because the 12B OptiQ snapshot carries an
|
|
96
|
+
`audio_config` but a stub sidecar whose only audio entry is
|
|
97
|
+
`embed_audio.embedding_projection.weight` (no `audio_tower.*` Conformer
|
|
98
|
+
tensors) — config presence alone would advertise audio that fails at
|
|
99
|
+
request time. The check reads only the sidecar's safetensors header,
|
|
100
|
+
never tensor bytes.
|
|
101
|
+
|
|
92
102
|
## Query resolution rules (per verb)
|
|
93
103
|
|
|
94
104
|
Every verb resolves fuzzy queries the same way, with revision collapsing
|
|
@@ -98,7 +108,7 @@ so a stale snapshot never makes a repo "ambiguous":
|
|
|
98
108
|
row per repo** (the canonical revision). `--all-revisions` shows the
|
|
99
109
|
per-snapshot truth with the canonical marked `*`. Capabilities column
|
|
100
110
|
labels the support tier: `supported (targeted)` (dedicated forward,
|
|
101
|
-
L2/
|
|
111
|
+
L2/opt-in paths) vs `supported (generic)` (Tier-0 universal module).
|
|
102
112
|
- **`fit` / `serve` / `train` / … (single-model verbs)** — `resolve()`:
|
|
103
113
|
the query must match exactly one **repo**; multiple cached revisions of
|
|
104
114
|
that repo collapse to the canonical snapshot (refs/main, else most
|
|
@@ -14,9 +14,9 @@ mlx-bun train <model> --data <dir>
|
|
|
14
14
|
- `<model>` is a query or snapshot path (e.g. `e4b`, `MiniCPM5`); omit it to auto-pick.
|
|
15
15
|
- `--data <dir>` is a directory with `train.jsonl` (+ optional `valid.jsonl`); rows are
|
|
16
16
|
`{"prompt": "...", "chosen": "...", "rejected": "..."}`.
|
|
17
|
-
- The
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
- The full stack (flash head + prefix-share + segmented) is on by default. No env-flag
|
|
18
|
+
setup is needed for any model (the old Gemma training-flag requirement is gone —
|
|
19
|
+
the no-vjp kernels were deleted 2026-07-05).
|
|
20
20
|
- It prints a plan box (dataset counts, format, the resolved knobs), streams per-step loss
|
|
21
21
|
+ peak memory, and saves a **mountable** adapter (`mlx-bun serve <model> --adapter <dir>`).
|
|
22
22
|
- `--dry-run` inspects the dataset and prints the plan without training. `mlx-bun help train`
|
|
@@ -59,7 +59,6 @@ mlx-bun train e4b --data ./prefs --resume ~/.cache/mlx-bun/mlx-bun-finetunes/orp
|
|
|
59
59
|
MODEL=/path/to/snapshot DATA=/path/to/datadir bun scripts/train-orpo.ts
|
|
60
60
|
```
|
|
61
61
|
- `DATA` is a directory with `train.jsonl` (+ optional `valid.jsonl`).
|
|
62
|
-
- Auto-detects e4b/Gemma and sets the training env flags, same as the CLI.
|
|
63
62
|
|
|
64
63
|
### Preconfigured defaults (override via env)
|
|
65
64
|
| env | default | meaning |
|