mlx-bun 0.0.9 → 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.
Files changed (179) hide show
  1. package/README.md +66 -21
  2. package/THIRD_PARTY_LICENSES.md +1 -0
  3. package/docs/archive/mlx-bun-lab-report.html +275 -0
  4. package/docs/archive/wwdc-mlx-bun.html +848 -0
  5. package/docs/design/audio-input-plan.md +356 -0
  6. package/docs/design/batching-perf-path.md +255 -0
  7. package/docs/design/batching-v2-plan.md +23 -9
  8. package/docs/design/bucketing-stage.md +2 -1
  9. package/docs/design/compat-cli-surface-design.md +4 -3
  10. package/docs/design/decode-speed-program.md +172 -0
  11. package/docs/design/docs-reorg-plan.md +1 -1
  12. package/docs/design/dspark-serving-program.md +371 -0
  13. package/docs/design/dspark-speculative-decoding.md +167 -5
  14. package/docs/design/faithful-l1-consolidation.md +310 -0
  15. package/docs/design/generic-model-support.md +8 -5
  16. package/docs/design/grammar-spec-batching-integration.md +301 -0
  17. package/docs/design/minicpm5-decode-megakernel.md +16 -11
  18. package/docs/design/mlx-lm-tool-parity-plan.md +11 -1
  19. package/docs/design/omlx-adoption-map.md +98 -0
  20. package/docs/design/orpo-training.md +34 -30
  21. package/docs/design/paged-kv-cache.md +214 -0
  22. package/docs/design/parallel-slots.md +82 -49
  23. package/docs/design/parity-tier-dag.md +43 -33
  24. package/docs/design/repo-cleanup-plan.md +189 -0
  25. package/docs/design/runtime-isolation.md +19 -3
  26. package/docs/design/segmented-backward-training.md +18 -2
  27. package/docs/design/ssd-kv-cold-tier.md +288 -0
  28. package/docs/design/structured-output.md +484 -0
  29. package/docs/design/the-dreaming-master-plan.md +2 -3
  30. package/docs/design/turboquant-kv.md +235 -0
  31. package/docs/design/unified-engine-frontier-plan.md +774 -0
  32. package/docs/design/web-chat-beat-matrix.md +315 -0
  33. package/docs/design/web-chat-redesign.md +1112 -0
  34. package/docs/investigations/decode-roofline-lookagain.md +92 -6
  35. package/docs/investigations/dspark-handoff.md +182 -16
  36. package/docs/investigations/kernel-perf-review-2026-07.md +105 -26
  37. package/docs/investigations/lab-build-journal.md +2 -2
  38. package/docs/investigations/openwiki-evaluation.md +249 -0
  39. package/docs/planning/IDEAS.md +14 -0
  40. package/docs/planning/PRODUCT_ROADMAP.md +2 -3
  41. package/docs/planning/chat-ui-vision-memory-first.md +199 -0
  42. package/docs/planning/chat-ui-vision.md +50 -0
  43. package/docs/planning/memory-docs-and-dag-plan.md +15 -6
  44. package/docs/planning/release-notes-v0.0.10.md +57 -0
  45. package/docs/planning/release-notes-v0.0.11.md +239 -0
  46. package/docs/reference/cli.md +35 -16
  47. package/docs/reference/distribution.md +13 -6
  48. package/docs/reference/embedding.md +35 -14
  49. package/docs/reference/features-matrix.md +97 -0
  50. package/docs/reference/library-api.md +30 -9
  51. package/docs/reference/memory.md +26 -6
  52. package/docs/reference/models.md +11 -1
  53. package/docs/reference/orpo-quickstart.md +3 -4
  54. package/docs/reference/server-api.md +634 -22
  55. package/docs/reference/server-config.md +251 -119
  56. package/docs/reference/training.md +20 -16
  57. package/package.json +5 -3
  58. package/src/anthropic.ts +13 -0
  59. package/src/audio/conformer.ts +647 -0
  60. package/src/audio/decode.ts +133 -0
  61. package/src/audio/features.ts +202 -0
  62. package/src/audio/transcode.ts +67 -0
  63. package/src/cli.ts +402 -107
  64. package/src/config.ts +49 -2
  65. package/src/download.ts +40 -0
  66. package/src/eval/README.md +7 -6
  67. package/src/eval/kl.ts +59 -3
  68. package/src/eval/quality-db.ts +2 -2
  69. package/src/eval/runner.ts +3 -3
  70. package/src/expert-offload.ts +15 -2
  71. package/src/flags.ts +13 -0
  72. package/src/generate.ts +330 -16
  73. package/src/grammar.ts +585 -0
  74. package/src/hub-rest.ts +242 -0
  75. package/src/kv-store.ts +618 -122
  76. package/src/lora.ts +8 -0
  77. package/src/md-modules.d.ts +42 -0
  78. package/src/media-fetch.ts +284 -0
  79. package/src/memory/rest.ts +245 -0
  80. package/src/memory/vault.ts +74 -0
  81. package/src/mlx/array.ts +127 -19
  82. package/src/mlx/autograd.ts +2 -2
  83. package/src/mlx/ffi.ts +27 -3
  84. package/src/mlx/metal-kernel.ts +7 -4
  85. package/src/mlx/ops.ts +179 -23
  86. package/src/mlx/turboquant-ops.ts +831 -0
  87. package/src/mlx/turboquant-tables.ts +237 -0
  88. package/src/model/batched-mask.ts +62 -1
  89. package/src/model/batched-quant.ts +206 -0
  90. package/src/model/batched-rotating-quant.ts +346 -0
  91. package/src/model/batched-rotating.ts +46 -1
  92. package/src/model/compiled-decode.ts +4 -15
  93. package/src/model/factory.ts +10 -4
  94. package/src/model/gemma4-base.ts +391 -34
  95. package/src/model/gemma4.ts +122 -33
  96. package/src/model/generated/gemma4-12b.ts +9 -13
  97. package/src/model/generated/gemma4-26b.ts +10 -5
  98. package/src/model/generated/gemma4-e4b.ts +14 -9
  99. package/src/model/minicpm5.ts +58 -102
  100. package/src/model/paged-kv.ts +253 -0
  101. package/src/model/qwen3-delta.ts +123 -15
  102. package/src/model/qwen3-moe.ts +404 -0
  103. package/src/model/qwen3.ts +9 -8
  104. package/src/model/qwen3_5.ts +99 -25
  105. package/src/model/support.ts +12 -1
  106. package/src/model/universal/dense.ts +40 -5
  107. package/src/model/universal/rope.ts +36 -21
  108. package/src/pi-web.ts +1299 -82
  109. package/src/preflight.ts +27 -8
  110. package/src/prompt-cache.ts +338 -32
  111. package/src/quantize/quantizer.ts +16 -1
  112. package/src/registry.ts +61 -3
  113. package/src/serve/batch-scheduler.ts +1001 -76
  114. package/src/serve/generation-gateway.ts +292 -30
  115. package/src/serve/isolate.ts +417 -0
  116. package/src/serve/lane-registry.ts +44 -0
  117. package/src/serve/session-search.ts +326 -0
  118. package/src/server.ts +1460 -105
  119. package/src/spec/assistant-source.ts +150 -0
  120. package/src/spec/deepspec-source.ts +143 -0
  121. package/src/spec/dflash-source.ts +124 -0
  122. package/src/spec/dspark/ab-stats.ts +136 -0
  123. package/src/spec/dspark/calibration.ts +112 -0
  124. package/src/spec/dspark/deepspec-module.ts +801 -0
  125. package/src/spec/dspark/generate-dflash.ts +72 -20
  126. package/src/spec/dspark/loader.ts +23 -0
  127. package/src/spec/dspark/module-dflash.ts +278 -36
  128. package/src/spec/dspark/quantize-drafter.ts +91 -0
  129. package/src/spec/generate.ts +59 -25
  130. package/src/spec/ngram-source.ts +132 -0
  131. package/src/spec/serve-loop.ts +536 -0
  132. package/src/spec/source.ts +93 -0
  133. package/src/spec/two-model.ts +171 -0
  134. package/src/ssd-cache.ts +285 -0
  135. package/src/tokenizer.ts +288 -2
  136. package/src/tool-approvals.ts +131 -0
  137. package/src/tool-call.ts +408 -20
  138. package/src/train/flash-cce.ts +29 -26
  139. package/src/train/job.ts +0 -2
  140. package/src/train/loss.ts +53 -11
  141. package/src/train/prefix-shared.ts +30 -7
  142. package/src/train/segmented.ts +150 -46
  143. package/src/train/trainer.ts +22 -15
  144. package/src/vision/prompt.ts +217 -48
  145. package/src/web/app.html +1184 -1789
  146. package/src/web/app.js +5667 -0
  147. package/src/web/icon.svg +13 -0
  148. package/src/web/manifest.webmanifest +24 -0
  149. package/src/web/src/adapters-panel.ts +288 -0
  150. package/src/web/src/api.ts +57 -0
  151. package/src/web/src/assistant.ts +485 -0
  152. package/src/web/src/chat.ts +1050 -0
  153. package/src/web/src/composer.ts +959 -0
  154. package/src/web/src/dataset.ts +132 -0
  155. package/src/web/src/finetune.ts +267 -0
  156. package/src/web/src/hub.ts +428 -0
  157. package/src/web/src/main.ts +98 -0
  158. package/src/web/src/markdown.ts +0 -0
  159. package/src/web/src/memory-panel.ts +572 -0
  160. package/src/web/src/model-picker.ts +159 -0
  161. package/src/web/src/palette.ts +346 -0
  162. package/src/web/src/protocol.ts +62 -0
  163. package/src/web/src/quantize.ts +167 -0
  164. package/src/web/src/rag.ts +274 -0
  165. package/src/web/src/sessions.ts +469 -0
  166. package/src/web/src/shell.ts +804 -0
  167. package/src/web/src/status.ts +252 -0
  168. package/src/web/src/ui-catalog.ts +92 -0
  169. package/src/web/sw.js +71 -0
  170. package/src/web/vendor/README.md +61 -0
  171. package/src/web/vendor/hljs-LICENSE +29 -0
  172. package/src/web/vendor/hljs-theme.css +59 -0
  173. package/src/web/vendor/hljs.js +26 -0
  174. package/src/model/fused-decode-kernel.ts +0 -312
  175. package/src/model/fused-geglu-kernel.ts +0 -198
  176. package/src/model/fused-mlp-kernel.ts +0 -169
  177. package/src/model/fused-swiglu-kernel.ts +0 -240
  178. package/src/model/steel-linear-kernel.ts +0 -96
  179. package/src/status-page.html +0 -497
@@ -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 (0.0.4); `bunx mlx-bun` works out of the box, or
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
- batch=1). The server serializes through a queue; do the same.
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/qwen35" in-repo.
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 as Gemma4Model);
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 is typed to accept Gemma4Model, but only uses model.layers.length
142
- // at runtime — a cast from RuntimeModel is safe for any model that has a layers array.
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).
@@ -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
- - `memory_search`
48
- - `memory_read`
49
- - `memory_toc`
50
- - `memory_section`
51
- - `memory_links`
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
@@ -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/L3 paths) vs `supported (generic)` (Tier-0 universal module).
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 command **auto-detects e4b/Gemma** and sets its required training env flags
18
- (`MLX_BUN_PERF_KERNEL=0`, `MLX_BUN_FUSED_GELU=0`) before loading the model — you don't
19
- set them yourself. The full stack (flash head + prefix-share + segmented) is on by default.
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 |