mlx-bun 0.3.0 → 0.4.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.
- package/docs/README.md +4 -1
- package/docs/archive/investigations/openjarvis-fit.md +198 -0
- package/docs/archive/investigations/qwen38-27b-campaign-log.md +1092 -0
- package/docs/design/batching.md +1321 -49
- package/docs/design/decode-speed-program.md +331 -1163
- package/docs/design/generic-model-support.md +79 -3
- package/docs/design/kv-cache.md +198 -54
- package/docs/design/speculative-decoding.md +387 -24
- package/docs/design/turboquant.md +123 -13
- package/docs/design/unified-engine-frontier-plan.md +144 -142
- package/docs/planning/PRODUCT_ROADMAP.md +16 -0
- package/docs/planning/release-notes-v0.4.0.md +45 -0
- package/docs/reference/benchmarks.md +2457 -6
- package/docs/reference/cli.md +41 -2
- package/docs/reference/distribution.md +16 -9
- package/docs/reference/environment.md +55 -5
- package/docs/reference/models.md +13 -4
- package/docs/reference/server-api.md +79 -25
- package/docs/reference/server-config.md +178 -84
- package/docs/reference/troubleshooting.md +13 -21
- package/package.json +1 -1
- package/src/backends/mlx/assistant-target.ts +46 -0
- package/src/backends/mlx/autoregressive-draft-rows.ts +120 -0
- package/src/backends/mlx/batch-group.ts +368 -224
- package/src/backends/mlx/cache-attachment.ts +67 -0
- package/src/backends/mlx/cache-layout.ts +31 -0
- package/src/backends/mlx/checkpoint-state.ts +53 -0
- package/src/backends/mlx/continuation-persistence.ts +106 -0
- package/src/backends/mlx/continuation-request.ts +43 -0
- package/src/backends/mlx/continuation.ts +77 -0
- package/src/backends/mlx/draft-target.ts +7 -22
- package/src/backends/mlx/full-kv-row-append.ts +32 -0
- package/src/backends/mlx/full-kv-row-donor.ts +54 -0
- package/src/backends/mlx/full-transitioning-kv-rows.ts +65 -0
- package/src/backends/mlx/gateway-binding.ts +77 -18
- package/src/backends/mlx/kv-codec.ts +9 -0
- package/src/backends/mlx/kv-maintenance.ts +133 -0
- package/src/backends/mlx/kv-tensor-rows.ts +212 -0
- package/src/backends/mlx/model-serving.ts +1 -1
- package/src/backends/mlx/prefill-cohort.ts +89 -0
- package/src/backends/mlx/prefill-rows.ts +200 -0
- package/src/backends/mlx/prefill.ts +1 -1
- package/src/backends/mlx/projected-context-rows.ts +72 -0
- package/src/backends/mlx/request-state-policy.ts +41 -0
- package/src/backends/mlx/rollback.ts +41 -3
- package/src/backends/mlx/row-sampling.ts +49 -0
- package/src/backends/mlx/serial-executor.ts +35 -66
- package/src/backends/mlx/speculative-group.ts +359 -0
- package/src/backends/mlx/speculative-round.ts +161 -0
- package/src/backends/mlx/state-rows.ts +104 -0
- package/src/backends/mlx/state-views.ts +21 -1
- package/src/backends/mlx/target-layout-capability.ts +35 -0
- package/src/backends/mlx/transitioning-kv-rows.ts +165 -0
- package/src/cli.ts +11 -36
- package/src/contracts/execution.ts +11 -0
- package/src/contracts/prefix-cache.ts +23 -0
- package/src/contracts/resources.ts +7 -0
- package/src/contracts/sampling.ts +23 -0
- package/src/contracts/scheduling.ts +18 -0
- package/src/engine/execution-plan.ts +18 -16
- package/src/engine/resources.ts +12 -1
- package/src/engine/scheduler.ts +10 -5
- package/src/fit.ts +29 -15
- package/src/generate.ts +77 -173
- package/src/inference/draft-acceptance.ts +41 -0
- package/src/inference/draft-output.ts +49 -0
- package/src/inference/rollback.ts +2 -2
- package/src/kv-scheme.ts +70 -12
- package/src/kv-store.ts +70 -16
- package/src/lab/paged-kv/paged-kv-rows.ts +83 -0
- package/src/lab/paged-kv/paged-kv.ts +25 -11
- package/src/mlx/array.ts +2 -1
- package/src/model/artifact-identity.ts +73 -0
- package/src/model/batched-kv.ts +235 -0
- package/src/model/batched-mask.ts +12 -4
- package/src/model/batched-quant.ts +8 -2
- package/src/model/batched-quantized-kv.ts +144 -0
- package/src/model/batched-rotating-quant.ts +76 -15
- package/src/model/batched-rotating-state.ts +76 -0
- package/src/model/batched-rotating.ts +64 -22
- package/src/model/batched-row-storage.ts +52 -0
- package/src/model/batched-ssm.ts +52 -0
- package/src/model/batched-turboquant-kv.ts +93 -0
- package/src/model/compiled-decode.ts +7 -1
- package/src/model/decoded-kv-donor.ts +12 -0
- package/src/model/delayed-quantized-kv.ts +72 -0
- package/src/model/delayed-rotating-quantized-kv.ts +93 -0
- package/src/model/delayed-turboquant-kv.ts +55 -0
- package/src/model/full-prefill-padding.ts +56 -0
- package/src/model/full-prefill-row.ts +105 -0
- package/src/model/gemma4-base.ts +162 -80
- package/src/model/gemma4.ts +34 -26
- package/src/model/generated/gemma4-12b.ts +4 -1
- package/src/model/generated/gemma4-26b.ts +4 -1
- package/src/model/generated/gemma4-e4b.ts +4 -1
- package/src/model/glm52-cache.ts +80 -4
- package/src/model/glm52-mla.ts +12 -6
- package/src/model/glm52.ts +19 -40
- package/src/model/kv-attention-view.ts +67 -0
- package/src/model/minicpm5.ts +11 -7
- package/src/model/qwen3-delta-state.ts +74 -0
- package/src/model/qwen3-delta.ts +59 -36
- package/src/model/qwen3_5.ts +82 -42
- package/src/model/rotating-kv-donor.ts +35 -0
- package/src/model/rotating-kv-layout.ts +262 -0
- package/src/model/rotating-row-transaction.ts +35 -0
- package/src/model/speculative-rotating-kv.ts +101 -0
- package/src/model/ssm-prefill-padding.ts +39 -0
- package/src/model/trellis-linear.ts +2 -2
- package/src/model/turboquant-codec.ts +83 -0
- package/src/model/universal/dense.ts +14 -13
- package/src/preflight.ts +31 -15
- package/src/prompt-cache.ts +42 -44
- package/src/sampler.ts +36 -25
- package/src/serve/chat-stage.ts +2 -2
- package/src/serve/generation-gateway.ts +39 -30
- package/src/serve/model-host.ts +3 -4
- package/src/serve/request-plan.ts +4 -3
- package/src/serve/request-prep.ts +2 -4
- package/src/serve/text-completion-stage.ts +2 -2
- package/src/server.ts +64 -108
- package/src/spec/assistant-rows.ts +92 -0
- package/src/spec/assistant-source.ts +28 -18
- package/src/spec/cache-identity.ts +22 -0
- package/src/spec/deepspec-rows.ts +29 -0
- package/src/spec/deepspec-source.ts +12 -10
- package/src/spec/dflash-source.ts +28 -4
- package/src/spec/drafter.ts +153 -142
- package/src/spec/dspark/deepspec-module.ts +95 -120
- package/src/spec/dspark/module-dflash.ts +126 -170
- package/src/spec/glm52-mtp-graph.ts +29 -0
- package/src/spec/glm52-mtp-rows.ts +132 -0
- package/src/spec/glm52-mtp-source.ts +53 -136
- package/src/spec/glm52-mtp-state.ts +33 -0
- package/src/spec/ngram-source.ts +92 -20
- package/src/spec/projected-draft-rows.ts +73 -0
- package/src/spec/qwen-mtp-module.ts +171 -0
- package/src/spec/qwen-mtp-rows.ts +219 -0
- package/src/spec/qwen-mtp-source.ts +81 -226
- package/src/spec/qwen-mtp-state.ts +30 -0
- package/src/spec/serve-loop.ts +70 -68
- package/src/spec/source.ts +80 -15
- package/src/spec/two-model-rows.ts +61 -0
- package/src/spec/two-model.ts +43 -101
- package/src/ssd-cache.ts +33 -21
- package/src/ssd-durability.ts +11 -7
- package/src/web/app.js +57 -57
- package/src/backends/mlx/memory-guard.ts +0 -40
- package/src/spec/prefix-state.ts +0 -45
- /package/docs/{planning → archive/planning}/release-notes-v0.3.0.md +0 -0
package/docs/reference/cli.md
CHANGED
|
@@ -64,6 +64,24 @@ mlx-bun serve GLM-5.2 --context-length 4096
|
|
|
64
64
|
semantics, and which combinations compose live in
|
|
65
65
|
**[server-config.md](server-config.md)** — this page only names them.
|
|
66
66
|
|
|
67
|
+
Library requests support delayed uniform or per-layer affine conversion with
|
|
68
|
+
qualified shared drafting providers, including rotating caches. CLI affine
|
|
69
|
+
quantization starts at zero.
|
|
70
|
+
|
|
71
|
+
The unreleased shared executor supports qualified Qwen MTP and start-zero
|
|
72
|
+
TurboQuant at one or several active rows; `--batch 1` still selects the
|
|
73
|
+
legacy serial control. No new CLI flag is required for the shared interfaces.
|
|
74
|
+
Full-attention and rotating targets, including Llama, MiniCPM and Gemma, use shared bf16, uniform KV4/KV8, per-layer affine KV or TurboQuant
|
|
75
|
+
prompt lookup and standalone drafting, including generated RAM/SSD state.
|
|
76
|
+
Gemma assistant drafting also shares these target layouts and caches its last true target
|
|
77
|
+
hidden alongside target KV through the same RAM/SSD interfaces.
|
|
78
|
+
DeepSpec and DSpark use the same executor and persist their projected context through those
|
|
79
|
+
interfaces. DeepSpec accepts bf16 or affine-quantized weights; DSpark retains
|
|
80
|
+
its Markov/RNN head and checkpoint confidence policy.
|
|
81
|
+
|
|
82
|
+
Shared Qwen MTP retains completed decode state through the existing
|
|
83
|
+
`--prompt-cache` and `--ssd-cache` settings.
|
|
84
|
+
|
|
67
85
|
| Group | Flags |
|
|
68
86
|
|---|---|
|
|
69
87
|
| Network | `--host`, `--port`, `--no-open`, `--allow-private-media` |
|
|
@@ -71,13 +89,17 @@ semantics, and which combinations compose live in
|
|
|
71
89
|
| Process model | `--isolate`, `--model-pool`, `--unix` (internal — the engine half of `--isolate`) |
|
|
72
90
|
| Scheduling | `--batch` (`--decode-concurrency` accepted as the mlx_lm.server alias) |
|
|
73
91
|
| KV cache | `--kv-quant`, `--paged-kv`, `--paged-kv-block-size` |
|
|
74
|
-
| Adapters | `--adapter` (`--adapter-path` alias) |
|
|
75
|
-
| Speculative decoding | `--draft-model`, `--draft-kind`, `--num-draft-tokens`, `--ngram-max`, `--ngram-min` |
|
|
92
|
+
| Adapters (compatible sets can batch) | `--adapter` (`--adapter-path` alias) |
|
|
93
|
+
| Speculative decoding (Qwen methods and full-attention/rotating lookup/standalone and Gemma assistant/DeepSpec/DSpark drafting share execution) | `--draft-model`, `--draft-kind`, `--num-draft-tokens`, `--ngram-max`, `--ngram-min` |
|
|
76
94
|
| GLM-5.2 | `--mtp`, `--context-length` |
|
|
77
95
|
| Sampling defaults | `--temperature` (`--temp` alias), `--top-p`, `--top-k`, `--max-tokens`, `--thinking`, `--hlg-sampling`, `--hlg-width`, `--hlg-shoulder`, `--hlg-toe`, `--hlg-pivot-offset` |
|
|
78
96
|
| Parity tier | `--l1`, `--l2` (`--l3` errors — removed) |
|
|
79
97
|
| Kill switches | `--compiled-decode`, `--compiled-activations`, `--fused-sdpa`, `--force-wire`, `--expert-offload` |
|
|
80
98
|
|
|
99
|
+
Serving treats memory estimates as advisory by default and attempts the request.
|
|
100
|
+
`--memory-budget` opts into estimated admission limits; `--kv-budget` opts
|
|
101
|
+
into aggregate KV limits. `--max-tokens` supplies an explicit output cap.
|
|
102
|
+
|
|
81
103
|
Endpoints: `/v1/chat/completions`, `/v1/completions`, `/v1/messages`,
|
|
82
104
|
`/v1/responses`, `/v1/embeddings`, `/v1/models`, `/v1/adapters`, `/health`,
|
|
83
105
|
`/stats`, `/fit`, `/library`, `/downloads`; the web app at `/` (`/chat`,
|
|
@@ -469,6 +491,11 @@ and optiq reference servers and writes a dated report:
|
|
|
469
491
|
```sh
|
|
470
492
|
bun scripts/bench-serve.ts all
|
|
471
493
|
bun scripts/bench-serve.ts all --models cpm5,e4b --arms mlx-bun,mlx-lm --out report.md
|
|
494
|
+
bun scripts/bench-serve.ts all --models qwen27b --arms mlx-bun-serial,mlx-bun --logprobs --top-logprobs 3
|
|
495
|
+
# Same KV settings on both executors
|
|
496
|
+
bun scripts/bench-serve.ts all --models qwen27b --arms mlx-bun-serial,mlx-bun --kv-quant 4
|
|
497
|
+
# Same adapter settings on both execution arms:
|
|
498
|
+
bun scripts/bench-serve.ts all --models e4b --arms mlx-bun-serial,mlx-bun --adapter fixtures/adapters/upper
|
|
472
499
|
```
|
|
473
500
|
|
|
474
501
|
Curated results: [benchmarks.md](benchmarks.md).
|
|
@@ -544,3 +571,15 @@ behind each "not covered" row is in
|
|
|
544
571
|
Native verbs with no mlx-lm counterpart — `pi`, `harness pi`, `embed`,
|
|
545
572
|
`fit`, `train-watch`, `memory`, `evals` — are the surface that makes mlx-bun
|
|
546
573
|
more than a drop-in.
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
`--kv-quant turbo` composes with grouped lookup, standalone, Gemma assistant,
|
|
577
|
+
DeepSpec and DSpark drafting on supported targets. Sliding layers stay bf16.
|
|
578
|
+
See [batching design](../design/batching.md) for composition evidence and limits.
|
|
579
|
+
|
|
580
|
+
Paged KV retains the configured `--batch` size. Gemma4 bf16 requests use the shared executor and bypass the prompt cache; quantized KV and draft combinations remain unavailable. See [server configuration](server-config.md).
|
|
581
|
+
|
|
582
|
+
`--generation-checkpoint N` requires `--ssd-cache` and queues owned snapshots
|
|
583
|
+
for eligible ordinary requests. Shared continuation supports eligible Qwen, Llama, MiniCPM and Gemma4 requests with or without adapters, excluding media, grammar, fill, paging, logprobs or speculation.
|
|
584
|
+
Repeat the identical request to replay and resume; flush before shutdown for
|
|
585
|
+
eventual queued snapshots to become durable.
|
|
@@ -186,6 +186,13 @@ npm if the version is live. Env overrides: `MLX_BUN_SIGN_IDENTITY`,
|
|
|
186
186
|
`NOTARY_PROFILE`, `BUILD_DIR`, `OUT_DIR` (release); `OUT_DIR`, `REPO`,
|
|
187
187
|
`TAP_REPO` (publish).
|
|
188
188
|
|
|
189
|
+
For an SSH-driven release, a local keychain unlock may still leave
|
|
190
|
+
`notarytool` reporting `keychainLocked` in the SSH session. The v0.3.0
|
|
191
|
+
release succeeded by running `release-binary.sh` in the M1 Max's local
|
|
192
|
+
Terminal, then `publish-release.sh` over SSH. Both steps used the same clean
|
|
193
|
+
merged source and `OUT_DIR`. Check `npm whoami` from the actual release
|
|
194
|
+
checkout too: a project `.npmrc` can override the user's configuration.
|
|
195
|
+
|
|
189
196
|
### The notarization lesson (v0.2.0, 2026-08-24)
|
|
190
197
|
|
|
191
198
|
The first v0.2.0 submission came back **Invalid**. The release added
|
|
@@ -311,7 +318,7 @@ sh scripts/build-native-pack.sh <ver> dist-native
|
|
|
311
318
|
gh release create native-v<ver> \
|
|
312
319
|
dist-native/mlx-bun-native-v<ver>-arm64.tar.gz \
|
|
313
320
|
dist-native/mlx-bun-native-v<ver>-arm64.tar.gz.sha256 \
|
|
314
|
-
--title "mlx-bun native runtime v<ver>" --notes "<what changed>"
|
|
321
|
+
--latest=false --title "mlx-bun native runtime v<ver>" --notes "<what changed>"
|
|
315
322
|
```
|
|
316
323
|
|
|
317
324
|
`build-native-pack.sh` stages the same six files with the same
|
|
@@ -323,13 +330,13 @@ package. Pre-publish smoke: a fresh-cache extraction plus a real MLX
|
|
|
323
330
|
`dlopen` (and, when the helpers changed, an expert read or a video decode).
|
|
324
331
|
The pack is ad-hoc signed only — `build-native-pack.sh` never touches a
|
|
325
332
|
Developer ID and nothing notarizes it; it is `dlopen`ed by the user's own Bun
|
|
326
|
-
process, not by our signed executable.
|
|
327
|
-
|
|
333
|
+
process, not by our signed executable. Use `--latest=false` so a native pack
|
|
334
|
+
does not replace the application release behind the direct installer's URL.
|
|
328
335
|
|
|
329
|
-
|
|
330
|
-
`c74db5307cc8ce122f48d97ef951b30578674e7f`. Its six-file macOS 14
|
|
331
|
-
|
|
332
|
-
|
|
336
|
+
Native pack 0.4.0 was published on 2026-09-08 with MLX 0.32.2 and MLX-C
|
|
337
|
+
`c74db5307cc8ce122f48d97ef951b30578674e7f`. Its six-file macOS 14 archive
|
|
338
|
+
was uploaded from the M1 Max and downloaded again; its checksum matches the
|
|
339
|
+
package manifest. It was published before mlx-bun v0.3.0. Runtime bindings
|
|
333
340
|
match this one C API, and startup checks the linked core version. The old
|
|
334
341
|
runtime and source controls remain separate for benchmark comparisons.
|
|
335
342
|
|
|
@@ -338,8 +345,8 @@ CI builds that pinned C wrapper with
|
|
|
338
345
|
`MLX_BUN_LIBMLXC` to its `lib/libmlxc.dylib`. The script verifies the official
|
|
339
346
|
macOS 14 MLX-Metal archive hash and checks out the exact MLX-C commit. It
|
|
340
347
|
extracts native libraries and headers without running Python or compiling
|
|
341
|
-
Metal sources. This also reproduces
|
|
342
|
-
|
|
348
|
+
Metal sources. This also reproduces the native-pack build inputs;
|
|
349
|
+
Homebrew's C wrapper is not the CI runtime.
|
|
343
350
|
|
|
344
351
|
Managed jobs in the compiled binary re-exec that binary through a private job
|
|
345
352
|
entry, with the database/log paths passed in the environment. They do not depend
|
|
@@ -134,10 +134,10 @@ eleven skips on the old core. The local native-pack
|
|
|
134
134
|
candidate under `native-pack-candidate/` extracts into `native-pack-extracted/`;
|
|
135
135
|
all five Mach-O files target 14.0, have valid ad-hoc signatures and load their
|
|
136
136
|
non-system dependencies from siblings. These checks ran on macOS 27, not an
|
|
137
|
-
actual macOS 14 host.
|
|
138
|
-
|
|
139
|
-
`/Users/joshrossi/Library/Caches/mlx-bun/native-v0.4.0-arm64`.
|
|
140
|
-
|
|
137
|
+
actual macOS 14 host. This build is published as native pack 0.4.0 and the
|
|
138
|
+
verified local cache is
|
|
139
|
+
`/Users/joshrossi/Library/Caches/mlx-bun/native-v0.4.0-arm64`. Publication
|
|
140
|
+
details are in distribution.md. The consolidated source passes 52 complete Qwen
|
|
141
141
|
forward/state/continuation cases and six Trellis generations, with fixed
|
|
142
142
|
source/runtime/reference hashes and clean worker exits. The consolidated
|
|
143
143
|
model-free suite passes 1,875 tests with ten skips; all typechecks pass.
|
|
@@ -179,6 +179,40 @@ against an M4 Pro output fixture. The test still requires exact output and
|
|
|
179
179
|
state hashes; Python runs only the external reference. Trellis variant
|
|
180
180
|
matrix tests allow 30 seconds for first-use kernel compilation on CI.
|
|
181
181
|
|
|
182
|
+
The M1 Max override was replayed on 2026-09-08 with the same inputs using
|
|
183
|
+
`/Users/joshrossi/Code/mlx-lm/.venv-mlx-0.32.2-macos14` (MLX/MLX-Metal
|
|
184
|
+
0.32.2, MLX-LM 0.31.3). Bun matches its outputs and recurrent-state hashes
|
|
185
|
+
exactly. The review file is
|
|
186
|
+
`reports/qwen38-closeout/qwen-delta-m1-review.json`.
|
|
187
|
+
|
|
188
|
+
Qwen3-Embedding tests also resolve `goldenPath("qwen3-embed")`, including
|
|
189
|
+
machine overrides, and skip when their required binary blobs are absent.
|
|
190
|
+
Regenerate with the matching Python and
|
|
191
|
+
`scripts/oracle/gen-qwen3-embed-golden.py <artifact> --replay goldens/qwen3-embed/meta.json`;
|
|
192
|
+
`--output-dir` selects a review directory. Replay preserves the text and token
|
|
193
|
+
IDs and checks the tokenizer against them. Metadata records the device,
|
|
194
|
+
runtime, artifact config, original metadata and output hashes. The M1 Max
|
|
195
|
+
replay matches hidden states and pooled embeddings exactly. Cosine uses both
|
|
196
|
+
vector norms: bf16 normalization does not guarantee a unit norm when the
|
|
197
|
+
result is subsequently read as float32.
|
|
198
|
+
|
|
199
|
+
The same M1 validation found June MiniCPM logit blobs without runtime
|
|
200
|
+
provenance. Explicit `bun scripts/regen.ts minicpm5` with the matching venv
|
|
201
|
+
preserves the artifact, prompt IDs and greedy trajectory; the regenerated
|
|
202
|
+
logits match Bun exactly. The generator now records runtime/device/config
|
|
203
|
+
provenance and all blob hashes. The old files and reviewed differences remain
|
|
204
|
+
under `reports/qwen38-closeout/minicpm5-golden-before/` and
|
|
205
|
+
`minicpm5-golden-review.json`.
|
|
206
|
+
|
|
207
|
+
The Gemma bf16 and mixed-KV M1 replays also pass with unchanged prompt IDs
|
|
208
|
+
on MLX 0.32.2. This current M1 venv contains **mlx-optiq 0.2.7** by installed
|
|
209
|
+
distribution metadata, matching the documented M4 installation; it is not
|
|
210
|
+
the historical 0.2.15 environment. OptiQ's module `__version__` incorrectly
|
|
211
|
+
reports 0.2.5 there, so regeneration records distribution metadata. Old
|
|
212
|
+
fixtures remain under `reports/qwen38-closeout/{parity,mixed-kv}-golden-before/`.
|
|
213
|
+
These are current-stack parity checks, not a runtime-only A/B against the
|
|
214
|
+
older mixed-KV fixture's 0.31.2/0.2.15 combination.
|
|
215
|
+
|
|
182
216
|
Readable oracle source, in that `site-packages/`: `mlx_lm/models/gemma3.py`
|
|
183
217
|
and `mlx_lm/server.py` for the port targets; `mlx_lm/models/cache.py` for the
|
|
184
218
|
cache classes; `mlx_lm/tokenizer_utils.py` for prompt rendering;
|
|
@@ -250,7 +284,19 @@ servers DO validate: the Bearer token must start with `sk-optiq-`
|
|
|
250
284
|
|
|
251
285
|
## Bun and FFI facts
|
|
252
286
|
|
|
253
|
-
**Bun
|
|
287
|
+
**Development and CI: Bun 1.4.2.** Build the committed frontend bundle with
|
|
288
|
+
that version so its byte-for-byte freshness check uses the same compiler.
|
|
289
|
+
Performance comparisons record the runtime and use the same version in both
|
|
290
|
+
arms; historical results retain their original version.
|
|
291
|
+
|
|
292
|
+
Non-login SSH on the M4 Pro can omit `/Users/joshrossi/.bun/bin` from `PATH`.
|
|
293
|
+
Put that directory on the remote command's PATH when running the test suite:
|
|
294
|
+
launching the parent Bun by absolute path alone does not let subprocess tests
|
|
295
|
+
find `bun`. The quantized-row validation's initial seven command-entry/job
|
|
296
|
+
failures disappear with that invocation corrected; no product code change was
|
|
297
|
+
needed for those failures.
|
|
298
|
+
|
|
299
|
+
**Runtime minimum: Bun ≥ 1.4.0.** `package.json` `engines.bun` is `>=1.4.0`. `Bun.Image`
|
|
254
300
|
(native OS codecs via ImageIO, EXIF auto-orient, off-thread) is the vision
|
|
255
301
|
decode path (`src/vision/preprocess.ts`); `Bun.Image.resize` is deliberately
|
|
256
302
|
not used. The FFI ABI fix below is the other reason for the pin.
|
|
@@ -346,3 +392,7 @@ holds self-contained reproductions for upstream bug reports (the two Bun
|
|
|
346
392
|
issues above, plus `optiq-mixed-kv-inert` and `vllm-metal-turboquant`); they
|
|
347
393
|
are not part of the build. Committed absolute paths (the venv, the weights
|
|
348
394
|
snapshot, `serve.sh`) are machine-specific on purpose — do not "correct" them.
|
|
395
|
+
|
|
396
|
+
The quantized-KV golden producer (`bun scripts/regen.ts kvq`) passes an absolute output directory to Python, since the child runs from `scripts/`. This preserves the selected machine directory and existing prompt IDs. Missing M4 blobs were regenerated from the pinned oracle into the isolated `delayed-affine-m4-oracle` override; numerical expectations were not produced by the inference implementation. Evidence: `reports/qwen38-closeout/composition-baseline/oracle-generator-path/`.
|
|
397
|
+
|
|
398
|
+
The M1 rotating-KV reference still identified MLX 0.31.2 and disagreed with both unchanged control and candidate on the KV8 greedy prefix. Regeneration with pinned MLX 0.32.2 retains the prompt IDs and passes exact logits plus both continuation checks. The matching M1 override and M4 reference caches are refreshed; previous manifests/blobs and provenance are retained with the generator-path evidence.
|
package/docs/reference/models.md
CHANGED
|
@@ -34,7 +34,7 @@ already-downloaded repos (it must match exactly one repo; see
|
|
|
34
34
|
| `Qwen3-30B` | `mlx-community/Qwen3-30B-A3B-Thinking-2507-4bit` | Qwen3-MoE (`qwen3_moe`) · dedicated `qwen3-moe` graph · L1 (opt-in slow parity test, `MLX_BUN_TEST_QWEN3_MOE=1`) | text | two-model · ngram | bf16 (the artifact ships no kv_config.json) | Sparse top-k SwitchGLU experts. |
|
|
35
35
|
| `diffusiongemma` | `mlx-community/diffusiongemma-26B-A4B-it-OptiQ-4bit` | DiffusionGemma (`diffusion_gemma`) · dedicated graph + **denoising loop** (non-autoregressive) · L2 (optiq) | text · **image** (single image; its own inline-quantized SigLIP tower). No video / audio | — (no AR verify loop) | — (canvas model; the `--kv-quant` axis does not apply) | Serial lane always. Diffusion-native LoRA trains. |
|
|
36
36
|
| `GLM-5.2-colibri` | `mateogrgic/GLM-5.2-colibri-int4-with-int8-mtp` @ `3cc8db99b1b13fc79325d987ba3c1c430766b3b8` | GLM-5.2 (`glm_moe_dsa`) · **Colibri container loader** + dedicated `glm5.2` graph (streamed experts) · **exact artifact profile**, L3 | text | **checkpoint-native MTP** (`--mtp on`, the default; mutually exclusive with `--draft-model`) | checkpoint-native compressed **MLA/DSA** cache (its own scheme; SSD tier v3 persists it) | Fixed-context admission: `--context-length` (4096) and `--max-tokens` (128) are reserved by the header-only resource equation before weights open; `--memory-budget` defaults to min(25 GiB, RAM). `--mtp off` enables ordinary batching. Embeddings, vision/audio, adapters, and training are unsupported. See [below](#direct-container-artifacts-glm-5x). |
|
|
37
|
-
| Tier-0 generic | validated manifest (`tests/support/universal-manifest.ts`): `Llama-3.2-1B-Instruct-4bit`, `Qwen2.5-0.5B-Instruct-4bit`, `Qwen3-0.6B-4bit`, `quantized-gemma-2b-it`, `gemma-2-2b-it-4bit`, `Phi-3.5-mini-instruct-4bit`, `GLM-4-9B-0414-4bit`, `granite-3.3-2b-instruct-4bit`, `starcoder2-3b-4bit`, `SmolLM3-3B-4bit` (all `mlx-community/`) and `ekryski/OLMo-2-0425-1B-Instruct-4bit` | 11 `model_type`s: `llama`, `smollm3`, `qwen2`, `qwen3`, `gemma`, `gemma2`, `phi3`, `olmo2`, `glm4`, `granite`, `starcoder2` (+ mlx-lm remaps `mistral`, `iquestcoder` → `llama`) · `universal-dense` graph · L1 | text | two-model · ngram | bf16
|
|
37
|
+
| Tier-0 generic | validated manifest (`tests/support/universal-manifest.ts`): `Llama-3.2-1B-Instruct-4bit`, `Qwen2.5-0.5B-Instruct-4bit`, `Qwen3-0.6B-4bit`, `quantized-gemma-2b-it`, `gemma-2-2b-it-4bit`, `Phi-3.5-mini-instruct-4bit`, `GLM-4-9B-0414-4bit`, `granite-3.3-2b-instruct-4bit`, `starcoder2-3b-4bit`, `SmolLM3-3B-4bit` (all `mlx-community/`) and `ekryski/OLMo-2-0425-1B-Instruct-4bit` | 11 `model_type`s: `llama`, `smollm3`, `qwen2`, `qwen3`, `gemma`, `gemma2`, `phi3`, `olmo2`, `glm4`, `granite`, `starcoder2` (+ mlx-lm remaps `mistral`, `iquestcoder` → `llama`) · `universal-dense` graph · L1 | text | two-model · ngram | bf16; unreleased Llama full-attention uniform KV4/KV8 | `ls` labels these `supported (generic)`. Shared full-attention execution is qualified on Llama-3.2-3B at B1/B4, including speculative KV4/KV8 and generated RAM/SSD state; gemma2-family / sliding-window archs run serial. No compiled specialization. A `model_type` absent from the table refuses to load. |
|
|
38
38
|
|
|
39
39
|
Rules that apply across rows (all enforced in `src/server.ts`):
|
|
40
40
|
|
|
@@ -45,8 +45,11 @@ Rules that apply across rows (all enforced in `src/server.ts`):
|
|
|
45
45
|
MTP is its own row. Qwen MTP companions may store dense or affine-quantized
|
|
46
46
|
projections; the loader uses each module's quantization metadata. Target
|
|
47
47
|
verification is unchanged, while draft acceptance and speed depend on the
|
|
48
|
-
companion.
|
|
49
|
-
|
|
48
|
+
companion. In the unreleased shared executor, qualified plain, uniform,
|
|
49
|
+
per-layer affine and TurboQuant layouts compose with drafting through the
|
|
50
|
+
target/provider interfaces. Positive affine conversion thresholds are also
|
|
51
|
+
supported by library requests. The loaded model and provider determine
|
|
52
|
+
which combinations can execute.
|
|
50
53
|
- **Qwen3.5-family checkpoint generations.** Both ship the same graph and both
|
|
51
54
|
load: the mlx-lm-converted naming (`language_model.model.*`,
|
|
52
55
|
`language_model.lm_head`, `vision_tower.*`) and the transformers-5.8 export
|
|
@@ -60,7 +63,9 @@ Rules that apply across rows (all enforced in `src/server.ts`):
|
|
|
60
63
|
- **KV schemes.** `--kv-quant 4|8` (uniform, L1) and `config` (per-layer
|
|
61
64
|
`kv_config.json`, L2) apply to the autoregressive families that ship the
|
|
62
65
|
file; `turbo` additionally requires a full-attention `head_dim` in
|
|
63
|
-
{64, 128, 256, 512} (refused at startup otherwise)
|
|
66
|
+
{64, 128, 256, 512} (refused at startup otherwise). Qualified TurboQuant
|
|
67
|
+
targets support shared ordinary and speculative execution; sliding layers
|
|
68
|
+
remain bf16;
|
|
64
69
|
`--paged-kv` is Gemma 4 only, bf16, serial. Flag detail:
|
|
65
70
|
[server-config.md](server-config.md).
|
|
66
71
|
- **Modalities.** Image requests reach a Gemma 4 model only when
|
|
@@ -323,3 +328,7 @@ Safety rails:
|
|
|
323
328
|
|
|
324
329
|
After a real deletion, gc re-scans so the registry drops the reaped
|
|
325
330
|
rows immediately.
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
Non-Qwen grouped TurboQuant drafting, including assistant donor attention, uses
|
|
334
|
+
the shared cache interfaces. See [composition coverage](../design/batching.md#turboquant-donor-attention-and-grouped-draft-composition).
|
|
@@ -117,8 +117,8 @@ Request body (OpenAI chat schema; unknown fields ignored):
|
|
|
117
117
|
"stream": false,
|
|
118
118
|
"max_tokens": 1024, // or max_completion_tokens (wins); unset =
|
|
119
119
|
// no cap — generate until EOS or the
|
|
120
|
-
//
|
|
121
|
-
//
|
|
120
|
+
// an explicit operator limit is reached;
|
|
121
|
+
// --max-tokens sets a server default
|
|
122
122
|
"temperature": 0.7, // 0 = greedy
|
|
123
123
|
"top_p": 0, "top_k": 0, // 0 = off
|
|
124
124
|
"seed": 1234, // omit for time-derived
|
|
@@ -369,15 +369,34 @@ Speculative decoding is a **server-level mode** (`serve --draft-model`,
|
|
|
369
369
|
or the model-free `serve --draft-kind ngram`, which mounts no draft
|
|
370
370
|
model); there is no per-request draft field. The `speculation` usage
|
|
371
371
|
extension appears on chat and text completions alike, non-streaming and on
|
|
372
|
-
the final stream chunk. Spec-eligible requests are text-only on base weights
|
|
373
|
-
|
|
374
|
-
uniform KV4
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
372
|
+
the final stream chunk. Spec-eligible requests are text-only on base weights.
|
|
373
|
+
In the unreleased shared executor, Qwen grouped MTP, prompt lookup and standalone drafting support logprobs and
|
|
374
|
+
bf16, uniform KV4/KV8 or per-layer affine KV, or TurboQuant. Qwen MTP and prompt lookup also support
|
|
375
|
+
positive library conversion thresholds for uniform KV4/KV8. Per-layer mixed KV and
|
|
376
|
+
adapters remain incompatible with speculation. Strict legacy serial execution
|
|
377
|
+
retains its narrower bf16/KV4 policy. The KV4 compatibility control is
|
|
378
|
+
`MLX_BUN_QWEN_SPEC_KV4=0`.
|
|
379
|
+
Ineligible requests decode normally and omit the field. Qwen MTP reuses paired
|
|
380
|
+
target/draft prefill and completed decode state through the shared RAM/SSD cache by default in the
|
|
381
|
+
unreleased source, reported in `cached_tokens`. Configured SSD persistence
|
|
382
|
+
supports reuse after restart; `MLX_BUN_MTP_PROMPT_CACHE=0` disables reuse.
|
|
383
|
+
Generated checkpoints cover processed tokens and use queued SSD persistence.
|
|
384
|
+
Long-conversation performance acceptance remains open. Qwen prompt lookup also
|
|
385
|
+
retains prefill and completed-output state in the common RAM/SSD cache, with
|
|
386
|
+
its committed token history stored as a companion attachment. Standalone drafting
|
|
387
|
+
on Qwen targets stores the draft model’s attention/recurrent state and pending
|
|
388
|
+
last draft token as companion state, including restoration after restart. Qualified Qwen
|
|
389
|
+
MTP, prompt lookup and standalone drafting use shared execution at one or several active rows and
|
|
390
|
+
report `usage.lane: "batched"`. Supported full-attention and rotating targets, including
|
|
391
|
+
Llama, MiniCPM and Gemma, use shared bf16, uniform KV4/KV8 or per-layer affine KV or TurboQuant lookup and standalone drafting, with
|
|
392
|
+
logprobs and generated RAM/SSD checkpoints. Delayed and per-layer affine rotating speculation uses the same row lifecycle; positive conversion thresholds are a library setting, while served schemes default to zero. Gemma assistant drafting also shares execution with bf16, uniform KV4/KV8 or per-layer affine KV or TurboQuant target storage and stores its
|
|
393
|
+
last true target hidden alongside generated RAM/SSD prefixes. Donor attention
|
|
394
|
+
handles row validity independently of the draft graph. DeepSpec and DSpark also use these shared target layouts and the common RAM/SSD cache
|
|
395
|
+
for projected context, with independent confidence-based proposal lengths.
|
|
396
|
+
Other provider/target combinations still
|
|
397
|
+
use the serial executor.
|
|
398
|
+
Prompt-lookup concurrent performance acceptance remains open. Ineligible requests can use continuous ordinary execution
|
|
399
|
+
when their features support it, even while a draft is mounted.
|
|
381
400
|
|
|
382
401
|
`usage.fill` reports **token fast-forwarding** (`MLX_BUN_FILL=strict|echo`).
|
|
383
402
|
Strict mode appends structural spans from the request's tools and chat
|
|
@@ -400,6 +419,13 @@ echo index proposed and `injected` is what survived. `wastedSamples` counts
|
|
|
400
419
|
only ASSERT fills (a verify fill consumes the in-flight sample as its first
|
|
401
420
|
position's check instead of discarding it).
|
|
402
421
|
|
|
422
|
+
An explicit `seed` controls a request-local random stream and can use
|
|
423
|
+
continuous execution. Repeating a request reproduces sampling at the same
|
|
424
|
+
model arithmetic and batch composition. Different batch shapes can change
|
|
425
|
+
floating-point results even with identical random draws; `--batch 1` retains
|
|
426
|
+
the existing fixed-shape control. This differs from mlx-lm's policy of routing
|
|
427
|
+
explicit seeds to its single-request generator.
|
|
428
|
+
|
|
403
429
|
### logprobs / top_logprobs
|
|
404
430
|
|
|
405
431
|
With `"logprobs": true` and/or `"top_logprobs": k` (1–11), the
|
|
@@ -432,8 +458,8 @@ penalties), **before** the sampler's temperature/top-p/top-k/min-p/XTC.
|
|
|
432
458
|
mlx-lm's top-k order is unspecified (argpartition); ours is sorted
|
|
433
459
|
descending — the same set, so the entry is deterministically the argmax.
|
|
434
460
|
Stream chunks never carry logprobs (mlx-lm's streaming responses don't
|
|
435
|
-
either). Requests with logprobs
|
|
436
|
-
|
|
461
|
+
either). Requests with logprobs can use ordinary continuous execution under
|
|
462
|
+
`--batch N`; other feature exclusions still apply. Invalid values are rejected
|
|
437
463
|
with mlx-lm's exact messages (see Errors).
|
|
438
464
|
|
|
439
465
|
### Streaming
|
|
@@ -544,11 +570,10 @@ Design and fidelity notes: [docs/reference/server-api.md](./server-api.md).
|
|
|
544
570
|
|
|
545
571
|
### Errors
|
|
546
572
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
generation checkpoints remain available for an identical retry.
|
|
573
|
+
Memory estimates do not reject or shorten requests by default. Actual runtime
|
|
574
|
+
failures use the request/stream error path when recoverable; native Metal
|
|
575
|
+
allocation failure can terminate the process. Saved generation checkpoints
|
|
576
|
+
remain available for an identical retry.
|
|
552
577
|
|
|
553
578
|
All errors are `{ "error": { "message": …, ... } }`.
|
|
554
579
|
|
|
@@ -567,10 +592,12 @@ All errors are `{ "error": { "message": …, ... } }`.
|
|
|
567
592
|
'low', 'medium', 'high', 'xhigh'`).
|
|
568
593
|
- `400` with `"type": "memory_admission"`, `"code":
|
|
569
594
|
"context_over_budget"` — the PROMPT itself leaves no generation slot
|
|
570
|
-
within
|
|
595
|
+
within an explicitly configured context/budget limit (`src/serve/request-plan.ts`). A prompt that
|
|
571
596
|
fits is never rejected for a broad `max_tokens`: the upper bound is
|
|
572
597
|
capped to the remaining room (`max_tokens` is a ceiling, not a promise)
|
|
573
|
-
and generation proceeds.
|
|
598
|
+
and generation proceeds. This is opt-in via an operator budget/context cap
|
|
599
|
+
(or the fixed GLM-5.2 layout), never enforced from default fit estimates.
|
|
600
|
+
`/stats.admission.enforced_context_tokens` is null when no cap applies.
|
|
574
601
|
- `429` with `"type": "resource_admission"`, `"code": "queue_full"` when
|
|
575
602
|
a preparation or generation queue has 64 waiting requests. If SSE headers
|
|
576
603
|
are already sent, the stream emits its terminal error instead.
|
|
@@ -590,7 +617,7 @@ and adapter selection as chat.
|
|
|
590
617
|
"prompt": "Once upon a time", // REQUIRED, non-empty string only (token
|
|
591
618
|
// arrays rejected, matching mlx_lm.server)
|
|
592
619
|
"max_tokens": 512, // unset = no cap: generate until EOS or the
|
|
593
|
-
//
|
|
620
|
+
// an explicit operator limit (DEVIATION: mlx_lm.server
|
|
594
621
|
// defaults 512 — pass --max-tokens 512 to
|
|
595
622
|
// reproduce); max_completion_tokens wins
|
|
596
623
|
"stream": false,
|
|
@@ -849,8 +876,9 @@ vision/audio, adapters, and training are not emulated by the serving port.
|
|
|
849
876
|
"pending_spill_bytes": 0, "dropped_spills": 0,
|
|
850
877
|
"failed_spills": 0, "longest_durable_prefix_tokens": 0 },
|
|
851
878
|
"admission": {
|
|
852
|
-
"max_safe_context": 0, //
|
|
853
|
-
"
|
|
879
|
+
"max_safe_context": 0, // advisory fit estimate, tokens
|
|
880
|
+
"enforced_context_tokens": null, // explicit cap or fixed layout; null = none
|
|
881
|
+
"memory_budget_bytes": null, // explicit budget, or null
|
|
854
882
|
"usable_bytes": 0,
|
|
855
883
|
"weights_bytes": 0
|
|
856
884
|
},
|
|
@@ -924,7 +952,7 @@ generic all-resident SKU estimator is inapplicable
|
|
|
924
952
|
```jsonc
|
|
925
953
|
{
|
|
926
954
|
"machine": { "chip": "M4 Pro", "ram_bytes": 0, "bandwidth_gbs": 0.0 },
|
|
927
|
-
"context_tokens": 8192, //
|
|
955
|
+
"context_tokens": 8192, // estimated context capacity
|
|
928
956
|
"typical_context_tokens": 8192, // min(8192, context_tokens)
|
|
929
957
|
"typical_decode_tps": 0.0, // predicted at typical_context_tokens
|
|
930
958
|
"measured_decode_tps": null, // real number from eval DB, or null
|
|
@@ -959,7 +987,11 @@ generic all-resident SKU estimator is inapplicable
|
|
|
959
987
|
## Adapters (LoRA hot-swap)
|
|
960
988
|
|
|
961
989
|
Routes in `src/serve/model-admin-routes.ts`; the manager is
|
|
962
|
-
`AdapterManager` in `src/lora.ts`.
|
|
990
|
+
`AdapterManager` in `src/lora.ts`. Requests selecting the same ordered adapter
|
|
991
|
+
set can share a continuous group. Different sets wait for the current group
|
|
992
|
+
to finish and then use the same executor. Prefix-cache identity is resolved
|
|
993
|
+
under the execution lease, so replacing an adapter while a request is queued
|
|
994
|
+
cannot reuse state from its previous weights.
|
|
963
995
|
|
|
964
996
|
- `GET /v1/adapters` — `{ adapters: [{ id, path, rank, scale, size_bytes,
|
|
965
997
|
mounted_layers, ram_bytes }] }` — currently-mounted adapters only.
|
|
@@ -1719,3 +1751,25 @@ Under `--isolate`, the parent owns Responses continuation history and exposes it
|
|
|
1719
1751
|
bounded store counters in `GET /engine` as `response_store`. Model-worker restart
|
|
1720
1752
|
or eviction preserves that history; restarting the parent clears it. Direct
|
|
1721
1753
|
serving retains the same process-local TTL and byte limits.
|
|
1754
|
+
|
|
1755
|
+
|
|
1756
|
+
Supported grouped TurboQuant drafting retains `usage.speculation`, seeded
|
|
1757
|
+
sampling, logprobs, structured output and generated RAM/SSD continuations.
|
|
1758
|
+
The cache codec does not select the scheduler or sampler implementation.
|
|
1759
|
+
Composition coverage: [batching design](../design/batching.md).
|
|
1760
|
+
|
|
1761
|
+
With paged KV enabled, supported Gemma4 bf16 text requests report the batched lane when submitted through continuous scheduling. Seeded sampling, logprobs and grammar use the same interfaces. These requests bypass prompt-cache lookup/publication; paging does not provide SSD persistence.
|
|
1762
|
+
|
|
1763
|
+
Ordinary adapter checkpoints are isolated by ordered adapter IDs and mounted
|
|
1764
|
+
content revisions. Base-model requests cannot restore or remove an adapter checkpoint.
|
|
1765
|
+
With generation checkpointing enabled, repeating an identical eligible request
|
|
1766
|
+
replays its saved completion prefix and resumes from the saved pending token.
|
|
1767
|
+
Cancellation retains queued snapshots; successful completion removes them.
|
|
1768
|
+
`POST /admin/cache/flush` drains both prompt spills and generation checkpoints,
|
|
1769
|
+
and its elapsed time and durability statistics include both queues. A hard
|
|
1770
|
+
process exit can lose snapshots that have not drained.
|
|
1771
|
+
|
|
1772
|
+
For resumed generation checkpoints, `usage.prompt_tokens_details.cached_tokens`
|
|
1773
|
+
counts only the reused original prompt, bounded by `usage.prompt_tokens`. Saved
|
|
1774
|
+
completion tokens are replayed as completion output and do not increase that
|
|
1775
|
+
prompt-cache usage counter.
|