mlx-bun 0.0.11 → 0.0.13
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 +63 -27
- package/THIRD_PARTY_LICENSES.md +9 -0
- package/docs/design/colibri-glm52-port.md +1486 -0
- package/docs/design/pre-colibri-stabilization.md +329 -0
- package/docs/investigations/colibri-oracle-pin.md +1284 -0
- package/docs/investigations/indexshare-performance-spike.md +357 -0
- package/docs/planning/release-notes-v0.0.12.md +80 -0
- package/docs/planning/release-notes-v0.0.13.md +77 -0
- package/docs/reference/cli.md +28 -2
- package/docs/reference/distribution.md +25 -1
- package/docs/reference/embedding.md +5 -2
- package/docs/reference/features-matrix.md +5 -2
- package/docs/reference/library-api.md +41 -13
- package/docs/reference/models.md +49 -2
- package/docs/reference/server-api.md +113 -20
- package/docs/reference/server-config.md +21 -14
- package/docs/reference/training.md +10 -1
- package/package.json +1 -1
- package/src/anthropic.ts +54 -44
- package/src/chat-template.ts +189 -11
- package/src/cli.ts +127 -8
- package/src/config.ts +81 -26
- package/src/diffusion/diffusion-generate.ts +14 -8
- package/src/download.ts +103 -12
- package/src/eval/ifeval.ts +63 -120
- package/src/eval/runner.ts +14 -5
- package/src/eval/tasks/ifeval.ts +167 -31
- package/src/expert-io.ts +391 -0
- package/src/expert-residency.ts +1134 -0
- package/src/expert-usage.ts +415 -0
- package/src/generate.ts +114 -17
- package/src/hf-push.ts +1 -1
- package/src/index.ts +14 -2
- package/src/jobs/runner.ts +37 -18
- package/src/kv-store.ts +147 -8
- package/src/lora.ts +77 -14
- package/src/media-fetch.ts +198 -56
- package/src/mlx/array.ts +43 -0
- package/src/mlx/autograd.ts +51 -14
- package/src/mlx/checkpoint.ts +46 -13
- package/src/mlx/custom-vjp.ts +83 -35
- package/src/model/factory.ts +96 -5
- package/src/model/gemma4-base.ts +32 -0
- package/src/model/glm52-atlas.ts +511 -0
- package/src/model/glm52-cache.ts +706 -0
- package/src/model/glm52-config.ts +262 -0
- package/src/model/glm52-container.ts +305 -0
- package/src/model/glm52-coupling.ts +388 -0
- package/src/model/glm52-dsa.ts +602 -0
- package/src/model/glm52-expert-layout.ts +253 -0
- package/src/model/glm52-layout.ts +152 -0
- package/src/model/glm52-memory.ts +473 -0
- package/src/model/glm52-mla.ts +786 -0
- package/src/model/glm52-moe.ts +223 -0
- package/src/model/glm52-pilot.ts +537 -0
- package/src/model/glm52-reference.ts +445 -0
- package/src/model/glm52-residency.ts +557 -0
- package/src/model/glm52-resident-weights.ts +135 -0
- package/src/model/glm52-streamed-experts.ts +453 -0
- package/src/model/glm52-streamed-metal.ts +610 -0
- package/src/model/glm52-weights.ts +503 -0
- package/src/model/glm52.ts +1153 -0
- package/src/model/support.ts +8 -1
- package/src/native/expert_io.c +523 -0
- package/src/native-pack.ts +6 -4
- package/src/responses.ts +62 -49
- package/src/serve/batch-scheduler.ts +95 -16
- package/src/serve/generation-gateway.ts +41 -16
- package/src/server.ts +471 -93
- package/src/spec/glm52-mtp-source.ts +392 -0
- package/src/spec/serve-loop.ts +99 -18
- package/src/spec/source.ts +31 -6
- package/src/ssd-cache.ts +6 -2
- package/src/tool-call.ts +30 -2
- package/src/train/job.ts +0 -10
- package/src/train/lora-params.ts +17 -6
- package/src/train/trainer.ts +59 -26
- package/src/web/app.html +13 -2
- package/src/web/app.js +30 -3
- package/src/web/src/status.ts +51 -3
- package/src/web-tools.ts +54 -2
- package/src/weights.ts +82 -19
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
# IndexShare / IndexCache performance spike
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-08-16
|
|
4
|
+
**Status:** accepted research spike; paper/code audit complete; implementation and
|
|
5
|
+
full-model measurement not started
|
|
6
|
+
**Target:** GLM-5.2 DSA on the M1 Max 32 GB Colibri path
|
|
7
|
+
|
|
8
|
+
## Recommendation
|
|
9
|
+
|
|
10
|
+
Run the spike, but do not treat it as a new model feature. The GLM-5.2 path
|
|
11
|
+
already implements the checkpoint's cross-layer IndexShare schedule: retained
|
|
12
|
+
`full` layers run the DSA indexer and intervening `shared` layers reuse the most
|
|
13
|
+
recent selection. The useful work is to make that correctness path production
|
|
14
|
+
shaped, prove long-context parity, and measure whether the saved indexer work is
|
|
15
|
+
visible behind expert I/O on Apple Silicon.
|
|
16
|
+
|
|
17
|
+
The first prerequisite is the exact stock indexer overlay. The pinned public
|
|
18
|
+
Colibri artifact has no `out-idx-*` files, so every full-model result recorded
|
|
19
|
+
to date is DSA-off. The second prerequisite is a scalable indexer path: current
|
|
20
|
+
code materializes a large `[heads, context, head_dim]` product, copies every
|
|
21
|
+
score to the host, sorts the full score vector in JavaScript, and supports
|
|
22
|
+
sparse DSA only for single-token decode. Those choices are good correctness
|
|
23
|
+
scaffolding but cannot test the paper's long-prefill result.
|
|
24
|
+
|
|
25
|
+
This spike must not change the trained `full`/`shared` pattern or expose it as a
|
|
26
|
+
normal user knob. GLM-5.2 ships IndexShare as checkpoint architecture, not as an
|
|
27
|
+
optional quality/performance preset.
|
|
28
|
+
|
|
29
|
+
## Naming and source claims
|
|
30
|
+
|
|
31
|
+
The linked paper calls the method **IndexCache**. The GLM-5.2 model card calls
|
|
32
|
+
the deployed architecture **IndexShare**. They use the same core mechanism:
|
|
33
|
+
cache the top-k positions produced by a retained DSA indexer and reuse them in
|
|
34
|
+
subsequent shared layers.
|
|
35
|
+
|
|
36
|
+
Primary sources:
|
|
37
|
+
|
|
38
|
+
- [IndexCache paper, arXiv:2603.12201v1](https://arxiv.org/abs/2603.12201v1)
|
|
39
|
+
- [authors' SGLang/vLLM reference patches](https://github.com/THUDM/IndexCache)
|
|
40
|
+
- [pinned GLM-5.2 model card](https://huggingface.co/zai-org/GLM-5.2/blob/f6142f127a14b58dc602592e996cd7d8ff139351/README.md)
|
|
41
|
+
- [pinned GLM-5.2 configuration](https://huggingface.co/zai-org/GLM-5.2/blob/f6142f127a14b58dc602592e996cd7d8ff139351/config.json)
|
|
42
|
+
|
|
43
|
+
The sources establish three different claims that must not be blended:
|
|
44
|
+
|
|
45
|
+
| Claim | Published evidence | What mlx-bun may say before local measurement |
|
|
46
|
+
|---|---|---|
|
|
47
|
+
| Cross-layer reuse | F layers compute top-k; S layers reuse the nearest preceding F layer | Implemented semantics, once parity is gated |
|
|
48
|
+
| IndexCache speed | On a 30B DSA model on an 8x H100 node, 1/4 retention reached up to 1.82x prefill and 1.48x per-request decode at 200K context | Paper result only; not a Mac prediction |
|
|
49
|
+
| GLM-5.2 IndexShare | The model card says one retained indexer per four sparse-attention layers reduces per-token FLOPs by 2.9x at 1M context | Vendor FLOP claim only; not end-to-end speed |
|
|
50
|
+
|
|
51
|
+
The paper also reports that uniform 1/4 retention hurts a frozen 30B model's
|
|
52
|
+
long-context average (50.2 to 43.0), while a loss-searched pattern recovers it
|
|
53
|
+
to 49.9. Training-aware IndexCache makes uniform interleaving viable. Therefore
|
|
54
|
+
mlx-bun must preserve GLM-5.2's trained schedule rather than search a new one
|
|
55
|
+
during this spike.
|
|
56
|
+
|
|
57
|
+
## GLM-5.2 schedule
|
|
58
|
+
|
|
59
|
+
The pinned GLM-5.2 config has 78 layers, `index_topk=2048`,
|
|
60
|
+
`index_topk_freq=4`, and `index_skip_topk_offset=3`. Its explicit schedule has
|
|
61
|
+
21 full and 57 shared layers:
|
|
62
|
+
|
|
63
|
+
```text
|
|
64
|
+
FFFSSSFSSSFSSSF...FSSS
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Relative to an all-full counterfactual, the checkpoint omits 57/78 = 73.1% of
|
|
68
|
+
layer indexer invocations. It does not ship the missing shared-layer indexer
|
|
69
|
+
weights, so a true same-checkpoint `IndexShare off` A/B is impossible. Any
|
|
70
|
+
estimated all-full number must be labeled a component counterfactual, not an
|
|
71
|
+
end-to-end model benchmark.
|
|
72
|
+
|
|
73
|
+
`index_share_for_mtp_iteration` is a second, orthogonal optimization: reuse
|
|
74
|
+
indices across speculative draft iterations. mlx-bun parses that field but does
|
|
75
|
+
not currently consume it in the MTP runtime. Keep its measurement separate so
|
|
76
|
+
cross-layer IndexShare and MTP-iteration sharing each receive an attributable
|
|
77
|
+
result.
|
|
78
|
+
|
|
79
|
+
## Current mlx-bun state
|
|
80
|
+
|
|
81
|
+
Already present:
|
|
82
|
+
|
|
83
|
+
- [`src/model/glm52-config.ts`](../../src/model/glm52-config.ts) parses explicit
|
|
84
|
+
`indexer_types` and the frequency/offset fallback.
|
|
85
|
+
- [`src/model/glm52.ts`](../../src/model/glm52.ts) constructs DSA indexers only
|
|
86
|
+
for full layers and passes one request-local selection state through the
|
|
87
|
+
decoder stack.
|
|
88
|
+
- [`src/model/glm52-dsa.ts`](../../src/model/glm52-dsa.ts) records a full
|
|
89
|
+
layer's exact dense/sparse selection and serves it to shared layers.
|
|
90
|
+
- [`tests/glm52-config-container.test.ts`](../../tests/glm52-config-container.test.ts)
|
|
91
|
+
and [`tests/glm52-dsa.test.ts`](../../tests/glm52-dsa.test.ts) cover schedule
|
|
92
|
+
parsing, missing-owner refusal, context consistency, and exact reuse.
|
|
93
|
+
|
|
94
|
+
Known blockers and likely bottlenecks:
|
|
95
|
+
|
|
96
|
+
1. **No production DSA overlay.** The public Colibri artifact deliberately
|
|
97
|
+
disables DSA because every full-layer indexer tensor is absent. Producing the
|
|
98
|
+
exact overlay requires selective reads from 20 pinned source shards (about
|
|
99
|
+
99.90 GiB input, about 197 MB output). This is a Josh-run acquisition step,
|
|
100
|
+
not an agent-session download.
|
|
101
|
+
2. **No sparse long prefill.** `Glm52DsaIndexer.projectAndSelect()` rejects a
|
|
102
|
+
multi-token prefill once context exceeds `index_topk`. The paper's prefill
|
|
103
|
+
headline is therefore out of scope until chunked/sparse DSA prefill exists.
|
|
104
|
+
3. **Quadratic transient shape.** `glm52DsaScoresMlx()` forms the broadcast
|
|
105
|
+
product before reduction. At production geometry this scales as
|
|
106
|
+
`32 * context * 128` float elements rather than streaming/tiled score
|
|
107
|
+
accumulation.
|
|
108
|
+
4. **GPU-to-host top-k.** The full score vector crosses to a `Float32Array`,
|
|
109
|
+
then `selectDsaThresholdTiesF32()` clones and sorts all positions. This is
|
|
110
|
+
`O(context log context)` host work in each full layer, unlike the production
|
|
111
|
+
GPU top-k assumed by the paper.
|
|
112
|
+
5. **Shared-index copies.** Shared layers clone the 2,048-element JavaScript
|
|
113
|
+
positions list, and absorbed MLA uploads it again before each gather. The
|
|
114
|
+
paper's temporary index tensor is reused in place. Measure this separately;
|
|
115
|
+
remove copies only after ownership and asynchronous lifetime are gated.
|
|
116
|
+
6. **The current short-context bottleneck is elsewhere.** At 128 tokens the
|
|
117
|
+
full model is limited by streamed expert delivery, and DSA cannot prune a
|
|
118
|
+
prefix smaller than 2,048. No short-context speedup should be expected.
|
|
119
|
+
|
|
120
|
+
## Hypotheses
|
|
121
|
+
|
|
122
|
+
- **H1 - component cost:** at the longest context that fits the 32 GB contract,
|
|
123
|
+
retained-indexer time is material and grows roughly linearly per decode token
|
|
124
|
+
with context length.
|
|
125
|
+
- **H2 - sharing value:** avoiding 57 of 78 indexer invocations removes a
|
|
126
|
+
measurable amount of counterfactual work even after a tiled score/top-k
|
|
127
|
+
kernel is used.
|
|
128
|
+
- **H3 - product value:** DSA plus the shipped IndexShare schedule improves
|
|
129
|
+
end-to-end long-context decode over DSA-off full attention, without token
|
|
130
|
+
drift from the official DSA runtime. This comparison measures the combined
|
|
131
|
+
sparse-attention product, not IndexShare in isolation.
|
|
132
|
+
- **H4 - MTP interaction:** any win remains a win with native MTP enabled. A
|
|
133
|
+
decode-only win that disappears under the product MTP path is not a default
|
|
134
|
+
performance claim.
|
|
135
|
+
|
|
136
|
+
## Bounded experiment
|
|
137
|
+
|
|
138
|
+
### Stage 0 - artifact and parity gate
|
|
139
|
+
|
|
140
|
+
1. Generate the immutable `out-idx-*` overlay from the pinned
|
|
141
|
+
`zai-org/GLM-5.2-FP8` revision. Record source revision, selected shard list,
|
|
142
|
+
tensor inventory, byte count, and SHA-256 values. Do not mutate the 357 GiB
|
|
143
|
+
serving snapshot.
|
|
144
|
+
2. Header-validate exactly the 21 full-layer indexers required by the shipped
|
|
145
|
+
schedule and prove that shared-layer indexers are neither required nor
|
|
146
|
+
silently loaded.
|
|
147
|
+
3. Add an official-runtime oracle at contexts above 2,048. Gate selected
|
|
148
|
+
positions, logits on tie-free rows, and greedy token IDs before taking any
|
|
149
|
+
performance number.
|
|
150
|
+
|
|
151
|
+
#### Stage 0 result — pass (2026-08-17)
|
|
152
|
+
|
|
153
|
+
The stock overlay was generated outside mlx-bun from
|
|
154
|
+
`zai-org/GLM-5.2-FP8@ba978f7d347eaf65d22f1a86833408afdb953541`
|
|
155
|
+
with `colibri@ecade075cfc2eae684097ea7de5570c3786ce199`. It contains 20
|
|
156
|
+
`out-idx-*` files totaling 197,202,400 bytes. The existing header validator
|
|
157
|
+
finds 118,646 tensors, 59,066 quantized tensors, 19,456 routed experts,
|
|
158
|
+
complete DSA and MTP families, all 21 required full-layer indexers, and no
|
|
159
|
+
shared-layer indexer requirement.
|
|
160
|
+
|
|
161
|
+
The first-sparse gate prefills exactly 2,048 deterministic tokens, then sends
|
|
162
|
+
one greedy token at context 2,049 with MTP off. The mlx-bun probe observes the
|
|
163
|
+
21 configured full layers and exactly 2,048 selected positions per layer. A
|
|
164
|
+
detached pinned Colibri build captures each official score row, selection,
|
|
165
|
+
float32 logit vector, and token trajectory. Replaying the captured scores with
|
|
166
|
+
`Glm52DsaSelectionState` gives:
|
|
167
|
+
|
|
168
|
+
- 21/21 exact ordered position vectors;
|
|
169
|
+
- 21/21 exact float32 thresholds;
|
|
170
|
+
- 21/21 tie-free boundaries, minimum boundary gap 0.025123596;
|
|
171
|
+
- exact greedy trajectory `[264, 264]` and the same sparse-step top-1 token;
|
|
172
|
+
- 154,880-logit cosine 0.997645, RMSE 0.200109, maximum absolute drift
|
|
173
|
+
0.947218, with wide top-1 margins in both runtimes (9.571914 / 9.567580).
|
|
174
|
+
|
|
175
|
+
The direct full-runtime selections are 10/21 ordered-exact and 14/21
|
|
176
|
+
set-exact. Each of the seven set differences swaps only the single excluded
|
|
177
|
+
position at this top-2,048-of-2,049 boundary. This is upstream numerical drift
|
|
178
|
+
from the runtimes' different quantized-matmul accumulation before DSA, not a
|
|
179
|
+
selector mismatch; replaying identical official scores proves the isolated
|
|
180
|
+
DSA threshold/tie contract exactly. No performance claim is made from either
|
|
181
|
+
correctness run.
|
|
182
|
+
|
|
183
|
+
Reproduction is split between
|
|
184
|
+
`scripts/probe-colibri-glm52-dsa-long.ts` and
|
|
185
|
+
`scripts/check-colibri-glm52-dsa-long.ts`. The raw capture, external Colibri
|
|
186
|
+
instrumentation patch, and SHA-256 inventory are machine-local at
|
|
187
|
+
`~/.cache/mlx-bun/evidence/glm52-dsa-stage0-2026-08-17/`; manifest SHA-256 is
|
|
188
|
+
`6ecb88d944b055146dd700a1714af97b61845d4218527282fcbea009663fe3b4`.
|
|
189
|
+
|
|
190
|
+
### Stage 1 - production-shaped indexer kernel
|
|
191
|
+
|
|
192
|
+
Build a model-free benchmark at exact geometry (`32` heads, head dimension
|
|
193
|
+
`128`, top-k `2048`) for contexts `2,048`, `8,192`, and `32,768`:
|
|
194
|
+
|
|
195
|
+
- tiled score accumulation that never materializes `[H,L,D]`;
|
|
196
|
+
- on-device/native deterministic top-k with the current threshold and
|
|
197
|
+
lower-position tie contract;
|
|
198
|
+
- one compact index buffer retained across F -> S layers;
|
|
199
|
+
- direct gather consumption without a score-vector host copy or per-shared-
|
|
200
|
+
layer index re-upload.
|
|
201
|
+
|
|
202
|
+
Compare the candidate against the existing reference composition for exact
|
|
203
|
+
selected positions on random, tied, all-equal, and production-captured rows.
|
|
204
|
+
Record kernel time, synchronization time, peak MLX allocation, process
|
|
205
|
+
footprint, and bytes copied to/from the host. Negative results count.
|
|
206
|
+
|
|
207
|
+
#### Stage 1 result — pass (2026-08-17)
|
|
208
|
+
|
|
209
|
+
The production path now computes `[H,D] @ [D,L] -> [H,L]` and never forms the
|
|
210
|
+
old `[H,L,D]` broadcast product. Deterministic device selection encodes the
|
|
211
|
+
lexicographic `(score descending, position ascending)` rank into `uint64`, uses
|
|
212
|
+
MLX `argpartition`, and then restores Colibri's observable two-scan ordering
|
|
213
|
+
(strictly above threshold first, threshold ties second). A FULL layer retains
|
|
214
|
+
only the resulting 2,048-entry, 8 KiB index buffer; SHARED layers borrow that
|
|
215
|
+
same device array and MLA gathers from it directly. Normal inference performs
|
|
216
|
+
no score/index host readback or per-SHARED-layer upload. The probe observer is
|
|
217
|
+
the explicit diagnostic exception.
|
|
218
|
+
|
|
219
|
+
Correctness gates pass for deterministic random rows, threshold ties,
|
|
220
|
+
all-equal rows, the exact 2,049/2,048 boundary, borrowed MLA consumption, and
|
|
221
|
+
all 21 production-captured Colibri score rows. The latter reproduce exact
|
|
222
|
+
ordered positions and float32 thresholds on device. A fresh full-model run
|
|
223
|
+
also reproduced all 21 prior mlx-bun position vectors and both greedy tokens;
|
|
224
|
+
its complete 154,880-float decode-logit payload is byte-identical (SHA-256
|
|
225
|
+
`d1f62be2de4877d2fc8ae8feab88e522958210252b50ef96eb786cb22581ba18`).
|
|
226
|
+
Tiled accumulation moved nine diagnostic thresholds by at most
|
|
227
|
+
`3.0517578125e-5`, but no selection boundary moved.
|
|
228
|
+
|
|
229
|
+
The exact-geometry, warm synchronized component benchmark (seven repeats) is:
|
|
230
|
+
|
|
231
|
+
| Context | Production behavior | Score median | Score + top-k median | Timed host copies | MLX peak |
|
|
232
|
+
|---:|---|---:|---:|---:|---:|
|
|
233
|
+
| 2,048 | dense boundary; production skips score/top-k | 0.448 ms (diagnostic only) | — | 0 B | 1.27 MiB |
|
|
234
|
+
| 8,192 | sparse | 0.473 ms | 0.929 ms | 0 B | 5.41 MiB |
|
|
235
|
+
| 32,768 | sparse | 0.748 ms | 1.269 ms | 0 B | 21.35 MiB |
|
|
236
|
+
|
|
237
|
+
At those contexts the removed broadcast product would have been 32, 128, and
|
|
238
|
+
512 MiB respectively; the tiled dot output is 0.25, 1, and 4 MiB. These are
|
|
239
|
+
model-free component measurements, not end-to-end inference claims. The
|
|
240
|
+
benchmark is `scripts/bench-glm52-dsa-indexer.ts`. Machine-local evidence is
|
|
241
|
+
under `~/.cache/mlx-bun/evidence/glm52-dsa-stage1-2026-08-17/`; manifest
|
|
242
|
+
SHA-256 is
|
|
243
|
+
`600ec92c41d4c66735e1834a678a09f2ae55ecdddfab31c3dd1bf31ee9709fef`.
|
|
244
|
+
|
|
245
|
+
### Stage 2 - decode matrix
|
|
246
|
+
|
|
247
|
+
Use direct library inference, not a server. Run separate fresh processes and
|
|
248
|
+
the standard quiet-machine preflight.
|
|
249
|
+
|
|
250
|
+
| Axis | Cells |
|
|
251
|
+
|---|---|
|
|
252
|
+
| Context | 2,048; 8,192; 32,768; 64K only if the exact planner remains inside the 25 GiB process ceiling |
|
|
253
|
+
| DSA | off/full attention; on with the checkpoint's 21F/57S schedule |
|
|
254
|
+
| MTP | off to isolate DSA; on for the product decision |
|
|
255
|
+
| Residency | the same fixed expert policy and seed profile in every paired arm |
|
|
256
|
+
| Repeats | three fresh processes per default-eligible cell; cold and warm turn in each process |
|
|
257
|
+
|
|
258
|
+
For each turn record TTFT, prefill wall time, decode tok/s, total wall time,
|
|
259
|
+
DSA projection/score/top-k/gather time, MLA time, expert disk service/wait,
|
|
260
|
+
target forwards, MTP acceptance, physical footprint, compression, swap, and
|
|
261
|
+
exact token IDs.
|
|
262
|
+
|
|
263
|
+
The DSA-off versus DSA-on result combines sparse core attention with
|
|
264
|
+
IndexShare. To estimate IndexShare's isolated contribution, report the measured
|
|
265
|
+
retained-indexer total and a clearly labeled all-full component counterfactual
|
|
266
|
+
derived from the same per-layer exact-geometry benchmark. Do not present that
|
|
267
|
+
counterfactual as a runnable checkpoint.
|
|
268
|
+
|
|
269
|
+
#### Stage 2 result — pass, negative product-performance decision (2026-08-17)
|
|
270
|
+
|
|
271
|
+
The fresh-process runner planned 36 cells. Twenty-four were eligible under the
|
|
272
|
+
G5 25 GiB process ceiling and completed: contexts 2,048 and 8,192, four DSA/MTP
|
|
273
|
+
arms, and three repeats. Every process ran cold and warm turns. Cold/warm,
|
|
274
|
+
cross-repeat, and MTP-off/on greedy token vectors were exact; all emitted
|
|
275
|
+
sixteen token IDs equal to `264`. The twelve 32K combinations were not run:
|
|
276
|
+
the exact planner reports 29,334,150,784 bytes (27.320 GiB) MTP-off and
|
|
277
|
+
30,644,281,216 bytes (28.540 GiB) MTP-on, both above the unchanged 25 GiB
|
|
278
|
+
process limit. The initial refusal is retained in the evidence as an attempt
|
|
279
|
+
record. This is contract ineligibility, not an allocation crash.
|
|
280
|
+
|
|
281
|
+
Long prompts use an explicitly bounded benchmark seam: dense batched prompt
|
|
282
|
+
construction ends at the exact prompt boundary, and every subsequent decode or
|
|
283
|
+
MTP verification row uses exact DSA. These numbers characterize decode and
|
|
284
|
+
whole-turn wall time only. They are not sparse-prefill measurements.
|
|
285
|
+
|
|
286
|
+
Warm medians across three fresh processes are:
|
|
287
|
+
|
|
288
|
+
| Context | DSA | MTP | Decode tok/s | Total wall |
|
|
289
|
+
|---:|---|---|---:|---:|
|
|
290
|
+
| 2,048 | off | off | 0.1363 | 260.9 s |
|
|
291
|
+
| 2,048 | on | off | 0.1318 | 271.5 s |
|
|
292
|
+
| 2,048 | off | on | 0.1312 | 281.7 s |
|
|
293
|
+
| 2,048 | on | on | 0.0880 | 338.7 s |
|
|
294
|
+
| 8,192 | off | off | 0.1292 | 722.1 s |
|
|
295
|
+
| 8,192 | on | off | 0.1420 | 711.8 s |
|
|
296
|
+
| 8,192 | off | on | 0.1587 | 711.8 s |
|
|
297
|
+
| 8,192 | on | on | 0.1042 | 770.1 s |
|
|
298
|
+
|
|
299
|
+
At 8K without MTP, the paired median DSA delta is +12.38% decode throughput
|
|
300
|
+
and -1.89% total wall time. Expert I/O and prompt work hide most of the decode
|
|
301
|
+
gain, leaving the whole-turn result below the required 5%. With MTP enabled,
|
|
302
|
+
the paired median delta reverses to -34.33% decode throughput and +8.19% total
|
|
303
|
+
wall time. The exact MTP trace explains part of the product result: DSA-off
|
|
304
|
+
accepted ten drafts in five rounds (3.2 tokens/target forward, six target
|
|
305
|
+
calls), whereas DSA-on accepted eight drafts in seven rounds (2.286
|
|
306
|
+
tokens/target forward, eight target calls). Small verify batches now keep
|
|
307
|
+
residual/MLP/expert work batched, but exact causal sparse attention still runs
|
|
308
|
+
per verification row. Two of the three 8K DSA+MTP cells observed net swap
|
|
309
|
+
growth, so the memory side of the win gate also does not close.
|
|
310
|
+
|
|
311
|
+
The immutable external overlay retains 197,202,400 bytes of indexers. As a
|
|
312
|
+
clearly labeled non-runnable component counterfactual, Stage 1's 8K
|
|
313
|
+
score+top-k median implies 19.51 ms for the shipped 21 FULL layers versus
|
|
314
|
+
72.48 ms for hypothetical 78 FULL layers, so IndexShare avoids about 52.97 ms
|
|
315
|
+
of selection work per target row. At 32K the corresponding component-only
|
|
316
|
+
figures are 26.64 ms, 98.95 ms, and 72.31 ms avoided. The checkpoint lacks the
|
|
317
|
+
57 missing indexers, and these sums exclude the rest of model execution.
|
|
318
|
+
|
|
319
|
+
The product decision is negative: retain the exact 21F/57S implementation as
|
|
320
|
+
model semantics and land its correctness/scalability work, but make no local
|
|
321
|
+
end-to-end speed claim. Decode is conclusive, so Stage 3 remains a separate
|
|
322
|
+
deferred prefill experiment rather than a G6R exit requirement. Evidence is
|
|
323
|
+
under `~/.cache/mlx-bun/evidence/glm52-dsa-stage2-2026-08-17/`; manifest
|
|
324
|
+
SHA-256 is
|
|
325
|
+
`90b3fe4ed53714604b7a747991b3bb1b87aedbf57a139915065f5b4be42cda38`.
|
|
326
|
+
|
|
327
|
+
### Stage 3 - deferred prefill follow-up
|
|
328
|
+
|
|
329
|
+
Only after decode is characterized, implement chunked sparse prefill with exact
|
|
330
|
+
causal selection semantics and run the same context ladder. This is the stage
|
|
331
|
+
that can test whether the paper's growing prefill benefit translates to MLX;
|
|
332
|
+
the existing single-token path cannot support that claim.
|
|
333
|
+
|
|
334
|
+
## Decision rules
|
|
335
|
+
|
|
336
|
+
- Preserve the shipped 21F/57S schedule regardless of outcome; it is model
|
|
337
|
+
semantics.
|
|
338
|
+
- Call the work a local performance win only when three fresh MTP-on processes
|
|
339
|
+
are token-identical and the paired median end-to-end wall time improves by at
|
|
340
|
+
least 5% at a context that fits the 32 GB contract, without new swap or a
|
|
341
|
+
footprint regression outside the existing G5 bounds.
|
|
342
|
+
- If the kernel saves DSA time but expert I/O hides the wall win, land only the
|
|
343
|
+
correctness/scalability work and record the negative end-to-end result.
|
|
344
|
+
- Do not quote the paper's H100 speedups or GLM-5.2's 1M-token FLOP reduction as
|
|
345
|
+
mlx-bun speed. Curated claims require this machine's `benchmark.sh`-quality
|
|
346
|
+
evidence and belong in `benchmarks/RESULTS.md` only after the gate passes.
|
|
347
|
+
- Evaluate MTP-iteration index sharing as a separate follow-up with its own
|
|
348
|
+
on/off control and acceptance trace.
|
|
349
|
+
|
|
350
|
+
## Exit
|
|
351
|
+
|
|
352
|
+
The spike closes when the DSA overlay is provenance-pinned, long-context
|
|
353
|
+
IndexShare matches an official runtime, the production-shaped score/top-k path
|
|
354
|
+
has exact model-free gates, and the paired MTP-off/on decode matrix has a
|
|
355
|
+
written decision. Prefill may remain a separately tracked follow-up only if the
|
|
356
|
+
decode result is already conclusive; otherwise sparse long prefill is required
|
|
357
|
+
before closure.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# v0.0.12 release notes
|
|
2
|
+
|
|
3
|
+
mlx-bun 0.0.12 completes the native Colibri/GLM-5.2 program: a Python-free,
|
|
4
|
+
direct-container runtime that can serve the approximately 357 GiB artifact on
|
|
5
|
+
a 32 GiB Apple Silicon Mac by keeping a bounded working set in memory and
|
|
6
|
+
streaming routed experts from fast storage.
|
|
7
|
+
|
|
8
|
+
## GLM-5.2 direct-container serving
|
|
9
|
+
|
|
10
|
+
- Loads `mateogrgic/GLM-5.2-colibri-int4-with-int8-mtp` directly. No converted
|
|
11
|
+
copy and no Python process are involved in the serving path.
|
|
12
|
+
- Preserves checkpoint precision and true top-8 routing. The port is gated
|
|
13
|
+
against pinned Colibri at tiny, production-component, real-model, MTP, cache,
|
|
14
|
+
and first-sparse DSA boundaries.
|
|
15
|
+
- Native int8 MTP is enabled by default and uses the serial speculative lane.
|
|
16
|
+
It produced a measured 1.306x warm end-to-end win over MTP-off on the 32 GiB
|
|
17
|
+
reference machine while preserving all target tokens.
|
|
18
|
+
- Compressed MLA/DSA/MTP cache persistence, restart restore, compressed-byte
|
|
19
|
+
admission, ordinary continuous batching, mixed-length join/leave/cancel, and
|
|
20
|
+
cross-row expert union are included. Per-row batched MTP remains a later
|
|
21
|
+
feature; MTP requests truthfully report `serial+spec`.
|
|
22
|
+
- Chat completions, text completions, Anthropic Messages, OpenAI Responses,
|
|
23
|
+
SSE, tools, structured output, stops, sampling, usage, and serial logprobs
|
|
24
|
+
are supported. Embeddings, vision/audio, LoRA, and training are explicitly
|
|
25
|
+
reported unsupported for this model instead of being emulated.
|
|
26
|
+
|
|
27
|
+
## Memory and acquisition contract
|
|
28
|
+
|
|
29
|
+
- `mlx-bun get` now computes the exact remaining payload before the first
|
|
30
|
+
payload request, credits verified shared blobs and resumable prefixes, and
|
|
31
|
+
refuses an acquisition that cannot leave a fixed 1 GiB safety reserve.
|
|
32
|
+
- The GLM header-only preflight runs before resident weights or expert slabs
|
|
33
|
+
open. With the stock DSA overlay installed, 4,096 context / 128 generation
|
|
34
|
+
tokens and MTP on produce a 19.89 GiB plan under a 25 GiB process ceiling,
|
|
35
|
+
leaving 5.11 GiB of process/macOS headroom on a 32 GiB machine.
|
|
36
|
+
- `fit`, `/fit`, `/stats`, and the status page now distinguish the complete
|
|
37
|
+
artifact on disk from resident weights, main/MTP slabs, compressed KV, and
|
|
38
|
+
reserves. They also expose main/MTP residency, hit rate, SSD bytes, policy
|
|
39
|
+
telemetry, and repin events.
|
|
40
|
+
|
|
41
|
+
## Performance: measured, not predicted
|
|
42
|
+
|
|
43
|
+
- Warm quality-preserving throughput on the M1 Max 32 GiB reference machine is
|
|
44
|
+
0.1577 decode tok/s / 0.1487 end-to-end tok/s with MTP on. The same-machine
|
|
45
|
+
direct-Colibri control is approximately 0.27 tok/s.
|
|
46
|
+
- The 2 tok/s figure remains an aspiration, not a release gate or `fit`
|
|
47
|
+
prediction. The measured warm end-to-end result is 13.45x below it.
|
|
48
|
+
- Replicated telemetry measured 1,974,949,363,712 logical expert bytes per
|
|
49
|
+
128-token warm turn (15.429 decimal GB/token) and a 1.66% cache hit rate.
|
|
50
|
+
Startup auto-pin, live LFRU, PILOT hints, two-step prediction, and coupling
|
|
51
|
+
did not improve paired end-to-end performance and remain off by default.
|
|
52
|
+
- The checkpoint's 21-full/57-shared DSA schedule is implemented and exact.
|
|
53
|
+
Paired 2K/8K tests did not establish an MTP-on product-speed win, so this
|
|
54
|
+
release makes no DSA speed claim. The public Colibri artifact does not ship
|
|
55
|
+
the stock DSA indexer overlay; without it the runtime follows the artifact's
|
|
56
|
+
available attention path.
|
|
57
|
+
|
|
58
|
+
## Distribution and operator experience
|
|
59
|
+
|
|
60
|
+
- First-run native pack v0.2.0 adds the bounded native expert-I/O helper. The
|
|
61
|
+
npm/bunx fresh-cache path downloads, verifies, and extracts all five runtime
|
|
62
|
+
files; the signed/Homebrew bundle includes the same helper beside the binary.
|
|
63
|
+
- The pinned 32 GiB quickstart, volume selection, interrupted-download recovery,
|
|
64
|
+
model lineage, licenses, resource plan, measured performance, and limitations
|
|
65
|
+
are documented in README and the reference guides.
|
|
66
|
+
- The interactive Atlas report reproduces Colibri's expert topic-affinity
|
|
67
|
+
result: 29/30 leave-one-prompt-out classifications (96.7%) and 1,065 strong
|
|
68
|
+
specialists among 13,236 replicated experts.
|
|
69
|
+
|
|
70
|
+
## Stability fixes since v0.0.11
|
|
71
|
+
|
|
72
|
+
- Closed pre-Colibri correctness and lifecycle findings, including expert-slab
|
|
73
|
+
post-close and lazy-graph reuse hazards, with forced native/MLX churn gates.
|
|
74
|
+
- Fixed selected-logprob readback stalling and revalidated the audio splice
|
|
75
|
+
boundary against the oracle.
|
|
76
|
+
- Corrected current Hugging Face LFS checksum-field handling and retained the
|
|
77
|
+
older spelling for compatibility.
|
|
78
|
+
|
|
79
|
+
Full provenance and exact numbers are in `benchmarks/RESULTS.md`, `STATUS.md`,
|
|
80
|
+
and `docs/design/colibri-glm52-port.md`.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# v0.0.13 release notes
|
|
2
|
+
|
|
3
|
+
Everything since v0.0.12. One theme: **Qwen 3.8**. The current-generation
|
|
4
|
+
Qwen (released August 2026) is brought up on the published OptiQ
|
|
5
|
+
artifact at the repo's standard bar — bit-exact logit parity with
|
|
6
|
+
mlx-lm — with its thinking controls served faithfully. Vision, video,
|
|
7
|
+
and native Qwen MTP remain separately gated follow-ups.
|
|
8
|
+
|
|
9
|
+
## Qwen3.8-27B (text, bit-exact)
|
|
10
|
+
|
|
11
|
+
- `mlx-community/Qwen3.8-27B-OptiQ-4bit` serves on the existing
|
|
12
|
+
qwen3_5 hybrid graph (gated DeltaNet + gated attention) — the
|
|
13
|
+
architecture audit found byte-identical geometry to the verified
|
|
14
|
+
port, and parity confirmed it: **every logit at every prompt
|
|
15
|
+
position plus 32 greedy decode steps, bit-exact vs stock mlx-lm**
|
|
16
|
+
(the parity harness grew a full prefill-grid golden and
|
|
17
|
+
manifest-driven step counts in the process).
|
|
18
|
+
- The config's new `output_gate_type: "swish"` field is inert in every
|
|
19
|
+
implementation (transformers ground truth included) — a load-time
|
|
20
|
+
guard now fails loudly if a future checkpoint carries a value we
|
|
21
|
+
haven't verified.
|
|
22
|
+
- Fit reality: the artifact is 20.35 GB of shards. 32 GB machines
|
|
23
|
+
serve it comfortably; 24 GB machines need `--memory-budget` and
|
|
24
|
+
should prefer the uniform 4-bit conversion until the planned
|
|
25
|
+
~4 bpw TurboQuant×weights artifact lands (PLAN 14z).
|
|
26
|
+
|
|
27
|
+
## Thinking controls (Qwen 3.8's serving surface)
|
|
28
|
+
|
|
29
|
+
- Thinking is on by default and streams as OpenAI `reasoning` deltas;
|
|
30
|
+
`chat_template_kwargs.enable_thinking: false` selects instruct mode.
|
|
31
|
+
- `reasoning_effort` is now a real depth control on templates that read
|
|
32
|
+
it: OpenAI levels map onto Qwen's `low`/`medium`/`xhigh` (with
|
|
33
|
+
`xhigh` accepted as a first-class request value), and the variable is
|
|
34
|
+
only passed to templates that declare it — the Qwen 3.8 template
|
|
35
|
+
raises on unknown level names, so the server never forwards unmapped
|
|
36
|
+
strings.
|
|
37
|
+
- `preserve_thinking` (new in Qwen 3.8, default on) is forwarded:
|
|
38
|
+
history keeps its think blocks, which also improves prompt-cache
|
|
39
|
+
reuse in agent loops.
|
|
40
|
+
- Tool calling: Qwen 3.8's XML call format
|
|
41
|
+
(`<tool_call><function=name><parameter=…>`) parses through the
|
|
42
|
+
existing Qwen-style parser into OpenAI `tool_calls`, multiline
|
|
43
|
+
parameters included.
|
|
44
|
+
|
|
45
|
+
## Qwen native MTP is deliberately not shipped yet
|
|
46
|
+
|
|
47
|
+
- Qwen 3.8 ships a multi-step MTP head trained alongside the model;
|
|
48
|
+
mlx-community publishes it split out
|
|
49
|
+
(`mlx-community/Qwen3.8-27B-MTP-bf16`). Review found that the target's
|
|
50
|
+
48 recurrent DeltaNet caches cannot roll back rejected verify rows,
|
|
51
|
+
while the shared speculative loop requires exactly that operation.
|
|
52
|
+
The initial implementation therefore never reached a draft round.
|
|
53
|
+
- MTP artifacts are detected and refused at startup with the exact reason,
|
|
54
|
+
before the 20 GB target is opened. Shipping a switch that silently disables
|
|
55
|
+
itself—or corrupts recurrent state when forced—would be worse than a clear
|
|
56
|
+
deferral. The follow-up needs recurrent-state snapshot/restore or a verify
|
|
57
|
+
schedule that never advances state beyond the accepted prefix.
|
|
58
|
+
|
|
59
|
+
## GLM-5.2 client compatibility
|
|
60
|
+
|
|
61
|
+
- Fixed-context GLM serving now treats request `max_tokens` as an upper bound:
|
|
62
|
+
when a client sends a family-wide value larger than the planned remaining
|
|
63
|
+
context, the server caps it instead of rejecting an otherwise valid first
|
|
64
|
+
prompt. The reported 2,788-prompt + 8,192-cap failure now admits a 1,308-token
|
|
65
|
+
completion ceiling within the 4,096-token plan. Prompts that consume the
|
|
66
|
+
whole context remain rejected before generation.
|
|
67
|
+
|
|
68
|
+
## Also in this release
|
|
69
|
+
|
|
70
|
+
- The parity harness's step-0 check now covers the full prefill logit
|
|
71
|
+
grid for all Qwen targets — masking/position bugs can no longer hide
|
|
72
|
+
behind a last-position comparison.
|
|
73
|
+
- A GPU command-buffer failure mode on memory-saturated machines was
|
|
74
|
+
root-caused (Metal completion-thread exception, uncatchable by
|
|
75
|
+
design) and documented in PLAN 14g, along with the finding that some
|
|
76
|
+
mlx-c paths surface C++ errors as process panics instead of
|
|
77
|
+
catchable errors (hardening item).
|
package/docs/reference/cli.md
CHANGED
|
@@ -26,6 +26,7 @@ mlx-bun serve # default model, http://localhost:808
|
|
|
26
26
|
mlx-bun serve e4b # pick a model by substring
|
|
27
27
|
mlx-bun serve gemma --memory-budget 18 # ...with admission control (GB)
|
|
28
28
|
mlx-bun serve e4b --no-open # don't open the browser chat UI
|
|
29
|
+
mlx-bun serve GLM-5.2 --context-length 4096 # bounded Colibri runtime, native MTP
|
|
29
30
|
```
|
|
30
31
|
|
|
31
32
|
Common flags (full list in [server-config.md](server-config.md)):
|
|
@@ -51,8 +52,10 @@ Common flags (full list in [server-config.md](server-config.md)):
|
|
|
51
52
|
| `--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
53
|
| `--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
54
|
| `--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) |
|
|
55
|
+
| `--mtp on\|off` | GLM-5.2 checkpoint-native MTP (default on). Native MTP uses the exact serial verify lane; `off` enables ordinary continuous batching (batched per-row MTP is post-release) |
|
|
56
|
+
| `--context-length <n>` | GLM-5.2 context reserved by the header-only resource equation (default 4096) |
|
|
54
57
|
| `--batch <n>` | Continuous-batched serving cap, mlx-lm B=N parity (default 8; `--batch 1` pins the serial path) |
|
|
55
|
-
| `--temperature` / `--top-p` / `--top-k` / `--max-tokens` | Server-wide sampling defaults (per-request fields still win) |
|
|
58
|
+
| `--temperature` / `--top-p` / `--top-k` / `--max-tokens` | Server-wide sampling defaults (per-request fields still win; GLM-5.2 defaults to the planned 128 generated tokens) |
|
|
56
59
|
| `--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
60
|
| `--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) |
|
|
58
61
|
| `--no-open` | Don't auto-open the chat UI |
|
|
@@ -96,6 +99,7 @@ decode-path levers mirror `serve` (`--temperature`, `--seed`, `--l1/--l2`,
|
|
|
96
99
|
```sh
|
|
97
100
|
mlx-bun generate gemma "a haiku about metal shaders"
|
|
98
101
|
mlx-bun gen e4b --prompt "…" --max-tokens 512 --seed 42
|
|
102
|
+
mlx-bun generate GLM-5.2 --prompt "Explain DSA" --max-tokens 128
|
|
99
103
|
```
|
|
100
104
|
|
|
101
105
|
### `embed` — text embeddings
|
|
@@ -118,13 +122,21 @@ Full guide: [models.md](models.md).
|
|
|
118
122
|
### `get` — download a model
|
|
119
123
|
|
|
120
124
|
Resumable, checksum-verified download into the standard Hugging Face cache
|
|
121
|
-
(plain HTTPS, no Xet — no 0% stalls).
|
|
125
|
+
(plain HTTPS, no Xet — no 0% stalls). Before payload transfer, the downloader
|
|
126
|
+
credits complete blobs and partial prefixes, then requires enough free space
|
|
127
|
+
for the exact remainder plus a fixed 1 GiB reserve.
|
|
122
128
|
|
|
123
129
|
```sh
|
|
124
130
|
mlx-bun get mlx-community/gemma-4-12B-it-OptiQ-4bit
|
|
125
131
|
mlx-bun get 12B # no "/" = registry query; re-gets/refreshes the match
|
|
132
|
+
mlx-bun get mateogrgic/GLM-5.2-colibri-int4-with-int8-mtp \
|
|
133
|
+
--revision 3cc8db99b1b13fc79325d987ba3c1c430766b3b8
|
|
126
134
|
```
|
|
127
135
|
|
|
136
|
+
The GLM artifact is roughly 357 GiB; select `HF_HUB_CACHE` on a sufficiently
|
|
137
|
+
large fast volume before starting. Rerunning the same command resumes verified
|
|
138
|
+
`.incomplete` prefixes. See the [32 GB GLM quickstart](models.md#glm-52-on-a-32-gb-mac).
|
|
139
|
+
|
|
128
140
|
### `scan` — index your cache
|
|
129
141
|
|
|
130
142
|
Re-index the HF cache into the registry (config + safetensors headers only,
|
|
@@ -165,6 +177,20 @@ mlx-bun fit gemma --ctx 32768 # for this machine
|
|
|
165
177
|
mlx-bun fit gemma --ctx 8192 --skus # across the Apple Silicon lineup
|
|
166
178
|
```
|
|
167
179
|
|
|
180
|
+
The direct Colibri GLM-5.2 artifact is handled by its streamed-runtime
|
|
181
|
+
contract, not by the generic resident-weights estimator. `fit GLM-5.2`
|
|
182
|
+
defaults to the supported 4,096-token / 128-generation-token plan and reports
|
|
183
|
+
the artifact's disk footprint separately from resident weights, the main and
|
|
184
|
+
MTP expert slabs, KV, reserves, and the 25 GiB process ceiling. Its throughput
|
|
185
|
+
line is the measured warm quality-preserving result; the direct Colibri oracle
|
|
186
|
+
and the 2 tok/s aspiration are labeled separately. `--skus` explains that the
|
|
187
|
+
generic resident-model matrix does not apply to this streamed artifact.
|
|
188
|
+
|
|
189
|
+
```sh
|
|
190
|
+
mlx-bun fit GLM-5.2
|
|
191
|
+
mlx-bun fit GLM-5.2 --ctx 4096
|
|
192
|
+
```
|
|
193
|
+
|
|
168
194
|
## Training & model creation
|
|
169
195
|
|
|
170
196
|
Full reference: [training.md](training.md); guided walkthrough:
|
|
@@ -14,6 +14,7 @@ tarball (~73 MB compressed, ~228 MB installed):
|
|
|
14
14
|
|---|---|
|
|
15
15
|
| `mlx-bun` | the CLI/server (`bun build --compile`), ~61 MB |
|
|
16
16
|
| `libmlxc.dylib`, `libmlx.dylib`, `libjaccl.dylib` | MLX native runtime |
|
|
17
|
+
| `libmlx_bun_expert_io.dylib` | bounded native expert-streaming helper required by direct Colibri GLM-5.2 |
|
|
17
18
|
| `mlx.metallib` | Metal kernels (~150 MB — the bulk) |
|
|
18
19
|
| pi assets | `photon_rs_bg.wasm`, `theme/`, `assets/`, `export-html/`, `native/`, `package.json`, `CHANGELOG.md` |
|
|
19
20
|
|
|
@@ -171,7 +172,8 @@ mlx-bun --version
|
|
|
171
172
|
The npm package is a thin launcher (no postinstall hook): it imports
|
|
172
173
|
`src/cli.ts` under Bun, which fetches the small (~52 MB compressed,
|
|
173
174
|
sha256-verified) native runtime pack — `libmlxc`/`libmlx`/`libjaccl`/
|
|
174
|
-
`mlx.metallib` — into
|
|
175
|
+
`mlx.metallib` plus `libmlx_bun_expert_io.dylib` — into
|
|
176
|
+
`~/Library/Caches/mlx-bun/` on first invocation if
|
|
175
177
|
no copy is already resolvable (env / beside the binary / cache /
|
|
176
178
|
Homebrew). This is the same npm/sidecar mechanism described above, not
|
|
177
179
|
the signed/notarized Homebrew bundle. `bun publish` is already run
|
|
@@ -182,3 +184,25 @@ fallback/retry:
|
|
|
182
184
|
```sh
|
|
183
185
|
bun publish # manual retry; package.json version must already be bumped
|
|
184
186
|
```
|
|
187
|
+
|
|
188
|
+
### Publishing the first-run native pack
|
|
189
|
+
|
|
190
|
+
The npm/bunx path has an independent, versioned release asset. Whenever its
|
|
191
|
+
file manifest changes, build and publish it before shipping code that names the
|
|
192
|
+
new `NATIVE_PACK_VERSION`:
|
|
193
|
+
|
|
194
|
+
```sh
|
|
195
|
+
sh scripts/build-native-pack.sh 0.2.0 dist-native
|
|
196
|
+
gh release create native-v0.2.0 \
|
|
197
|
+
dist-native/mlx-bun-native-v0.2.0-arm64.tar.gz \
|
|
198
|
+
dist-native/mlx-bun-native-v0.2.0-arm64.tar.gz.sha256 \
|
|
199
|
+
--title "mlx-bun native runtime v0.2.0" \
|
|
200
|
+
--notes "Adds the bounded native expert-I/O helper required by direct Colibri GLM-5.2."
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
For v0.2.0 the arm64 archive is 52,307,647 bytes with SHA-256
|
|
204
|
+
`9bd3795c5ea8f52b18413501f2d68c32c264a20751302300a08dc04cd67df97c`.
|
|
205
|
+
It contains `libmlxc.dylib`, `libmlx.dylib`, `libjaccl.dylib`,
|
|
206
|
+
`mlx.metallib`, and `libmlx_bun_expert_io.dylib`. These values must match
|
|
207
|
+
`src/native-pack.ts`; a fresh-cache extraction plus real MLX dlopen and native
|
|
208
|
+
expert read is the pre-publish smoke.
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
Ship local inference inside a Mac app (Tauri, Electron, or anything
|
|
9
9
|
that can spawn a process) with zero user-visible dependencies: one
|
|
10
|
-
executable +
|
|
10
|
+
executable + four native libraries, dropped into your app's resources.
|
|
11
11
|
|
|
12
12
|
## Build the bundle
|
|
13
13
|
|
|
@@ -23,6 +23,7 @@ Produces a relocatable directory:
|
|
|
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
|
+
| `libmlx_bun_expert_io.dylib` | bounded streamed-expert I/O used by direct Colibri GLM-5.2 | ~0.03 MB |
|
|
26
27
|
| `mlx.metallib` | Metal kernels — libmlx loads it from its own directory | ~150 MB |
|
|
27
28
|
| `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
29
|
|
|
@@ -44,7 +45,9 @@ cache (`~/Library/Caches/mlx-bun/native-v<ver>-<arch>/`, populated on
|
|
|
44
45
|
first run when no sidecar or homebrew install is found) → homebrew
|
|
45
46
|
(`/opt/homebrew/lib`, `/usr/local/lib`). The whole directory can be
|
|
46
47
|
renamed/moved; nothing references absolute paths after the build
|
|
47
|
-
script's `install_name_tool` fixups.
|
|
48
|
+
script's `install_name_tool` fixups. The expert helper independently resolves
|
|
49
|
+
`MLX_BUN_EXPERT_IO_DYLIB`, then the executable directory, then the same
|
|
50
|
+
native-pack cache.
|
|
48
51
|
|
|
49
52
|
## Embedded pi web chat (`/ws/chat`)
|
|
50
53
|
|