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
|
@@ -414,12 +414,12 @@ satisfy, with the state of `GenerationGateway.#supportsContinuous` as read on
|
|
|
414
414
|
| layer | today (src) | end state |
|
|
415
415
|
|---|---|---|
|
|
416
416
|
| dedicated per-model graph | both mechanisms (profile-routed) | unchanged |
|
|
417
|
-
| mixed-precision KV (`affine-config`) |
|
|
418
|
-
| LoRA adapters |
|
|
419
|
-
| speculative decoding (two-model · assistant · dspark · deepspec · native MTP · ngram) |
|
|
417
|
+
| mixed-precision KV (`affine-config`) | supported per-layer and uniform affine KV use continuous groups; incompatible layouts remain open | one active scheme per server, any B |
|
|
418
|
+
| LoRA adapters | compatible ordered adapter sets share a group; context and cache identity bind under the execution lease | per-slot adapter state (vLLM Punica/SGMV pattern: every row runs the adapter math, non-adapter rows at scale 0) |
|
|
419
|
+
| speculative decoding (two-model · assistant · dspark · deepspec · native MTP · ngram) | actual speculation uses the serial verifier; supported ordinary requests can batch with a mounted draft | per-slot drafting behind the `DraftSource` seam |
|
|
420
420
|
| structured output (grammar) | both (per-row matchers; `MLX_BUN_GRAMMAR_BATCH=0` forces serial) | unchanged; keep the conformance gate |
|
|
421
|
-
| sampling (temp/top-p/top-k/min-p/XTC/penalties/HLG/seed) | per-row
|
|
422
|
-
| logprobs capture |
|
|
421
|
+
| sampling (temp/top-p/top-k/min-p/XTC/penalties/HLG/seed) | per-row sampling sessions, including explicit seeds, repetition penalty and logits extras | fully per-row, seeds included |
|
|
422
|
+
| logprobs capture | shared row sampling and readback in continuous groups | preserve method composition |
|
|
423
423
|
| vision / audio media prompts | serial only (`shape.hasVision`; embeddings-prefill bypasses the prompt cache) | batched media prefill |
|
|
424
424
|
| prompt cache / SSD tier | both: scheduler joiners `take()` the longest usable prefix at admission, never-merged rows `put()` back on finish; the cold tier restores inside `take()` | block-granular sharing across rows |
|
|
425
425
|
| paged KV (`--paged-kv`) | serial only, Gemma4 bf16, refuses `--batch N>1`, `--kv-quant`, `--draft-model`; bypasses the prompt cache | block-level CoW prefix sharing (vLLM oracle) |
|
|
@@ -472,132 +472,13 @@ entries so a caller cannot mutate conversion or accounting after resolution.
|
|
|
472
472
|
`BatchScheduler.#prefillChunk` in `src/serve/batch-scheduler.ts` (the same
|
|
473
473
|
conventions re-implemented over `PrefillState` for interleaved admission).
|
|
474
474
|
Both are gated bit-exact, but a convention change must land in two places.
|
|
475
|
-
2. **
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
not
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
(`finalLane` in the executor). Resolving this means lifting the eligibility
|
|
483
|
-
predicate into `RequestShape` so placement and the lane label are decided
|
|
484
|
-
once.
|
|
485
|
-
|
|
486
|
-
Other seams worth knowing: `runGeneration` also decides the prompt-cache
|
|
487
|
-
bypass (media, paged) and the adapter cache namespace; `--isolate` wraps the
|
|
488
|
-
ENTIRE server as an engine child behind a proxy (`src/serve/isolate.ts`,
|
|
489
|
-
`ModelPool` for `--model-pool` LRU residency and model switching by the
|
|
490
|
-
request's `model` field) — the inter-process API is the /v1 surface itself, no
|
|
491
|
-
second protocol.
|
|
492
|
-
|
|
493
|
-
## 7. The flag surface (src truth, grouped by layer)
|
|
494
|
-
|
|
495
|
-
Read from `SERVER_FLAGS` and `applyDecodeRoute` in `src/cli.ts`. Every
|
|
496
|
-
`MLX_BUN_*` value is read through the immutable runtime snapshot
|
|
497
|
-
(`src/runtime-config.ts` `runtimeValue/runtimeFlag`, `src/flags.ts` `flagOn`);
|
|
498
|
-
feature code never reads `process.env`, and the CLI installs tier/fork
|
|
499
|
-
overrides with `configureRuntime()` before model modules load.
|
|
500
|
-
|
|
501
|
-
**Parity tier (aliases):** `--l1` (default) · `--l2`. `--l3` hard-errors with a
|
|
502
|
-
pointer to this doc.
|
|
503
|
-
|
|
504
|
-
**L2 — quantization:** `--kv-quant config|off|4|8|turbo[:k<bits>v<bits>]`
|
|
505
|
-
(default off). An older draft of this doc listed only `config|4|8|off`; the
|
|
506
|
-
`turbo` axis is real and mutually exclusive with the affine modes.
|
|
507
|
-
|
|
508
|
-
**L3 — scheduler / decode policy:** `--batch <n>` (default 8;
|
|
509
|
-
`--decode-concurrency` alias) · `--kv-budget <GB>` · `--draft-model <query>` ·
|
|
510
|
-
`--draft-kind two-model|assistant|dspark|deepspec|mtp|ngram` ·
|
|
511
|
-
`--num-draft-tokens` · `--ngram-max` / `--ngram-min` · `--mtp on|off`
|
|
512
|
-
(GLM-5.2 native MTP, on by default) · `--context-length` (GLM-5.2 reservation)
|
|
513
|
-
· `--paged-kv` / `--paged-kv-block-size` (env `MLX_BUN_PAGED_KV=1`).
|
|
514
|
-
|
|
515
|
-
**L4 — serving surface:** `--model` · `--host` · `--port` · `--memory-budget`
|
|
516
|
-
· `--prompt-cache <GB>` · `--ssd-cache <dir>` · `--ssd-cache-max` ·
|
|
517
|
-
`--ssd-demote-idle` · `--ssd-cache-verify` · `--isolate` · `--model-pool` ·
|
|
518
|
-
`--unix` (internal) · `--no-open` · `--allow-private-media` · `--adapter`
|
|
519
|
-
(`--adapter-path` alias) · `--thinking` · `--temperature`/`--temp` · `--top-p`
|
|
520
|
-
· `--top-k` · `--max-tokens` · the HLG sampler family (`--hlg-sampling`,
|
|
521
|
-
`--hlg-width`, `--hlg-shoulder`, `--hlg-toe`, `--hlg-pivot-offset`).
|
|
522
|
-
|
|
523
|
-
**Kill switches (bit-exact A/B levers, each selects a slower same-parity
|
|
524
|
-
path):** `--compiled-decode on|off` (`MLX_BUN_COMPILED_DECODE`) ·
|
|
525
|
-
`--compiled-activations on|off` (`MLX_BUN_COMPILED_GEGLU` +
|
|
526
|
-
`MLX_BUN_COMPILED_SWIGLU`; only gemma geglu and MiniCPM5 swiglu have an
|
|
527
|
-
uncompiled form — qwen3/qwen3.5/universal compile unconditionally) ·
|
|
528
|
-
`--fused-sdpa on|off` (`MLX_BUN_NO_FUSED_SDPA`, inverted; default follows
|
|
529
|
-
`--kv-quant`) · `--force-wire` (`MLX_BUN_FORCE_WIRE`) · `--expert-offload`
|
|
530
|
-
(`MLX_BUN_EXPERT_OFFLOAD`). An older draft said these were env-only; the three
|
|
531
|
-
decode kill switches are CLI flags as well.
|
|
532
|
-
|
|
533
|
-
**Lab / diagnostic env flags (no CLI flag; live with a bench and an expiry):**
|
|
534
|
-
`MLX_BUN_GRAMMAR_JUMP=1` (jump-forward decoding, serial non-spec loop),
|
|
535
|
-
`MLX_BUN_GRAMMAR_BATCH=0` (grammar back to serial), `MLX_BUN_BATCH_SSM=0`
|
|
536
|
-
(SSM caches back to serial), `MLX_BUN_BATCH_NO_PIPELINE`,
|
|
537
|
-
`MLX_BUN_BATCH_STEP_TRACE`, `MLX_BUN_BATCH_VEC_SAMPLE`, `MLX_BUN_BATCH_EXTEND`,
|
|
538
|
-
`MLX_BUN_PREFILL_TAIL_SPLIT`, `MLX_BUN_FLASH_MIN_M`, the `MLX_BUN_CCE_*`
|
|
539
|
-
training-kernel switches, and the memory/trace loggers. Anything
|
|
540
|
-
output-changing is Lab by definition.
|
|
541
|
-
|
|
542
|
-
**Deleted (2026-07-05, §11):** `--fused-decode`, `--fused-gelu`,
|
|
543
|
-
`--perf-kernel`, `--l3`, and their env twins. None exist in `src/`.
|
|
544
|
-
|
|
545
|
-
## 8. Design invariants proven en route (durable, not changelog)
|
|
546
|
-
|
|
547
|
-
- **Readbacks in a pipelined loop must not create ops.** `toFloat32()` on the
|
|
548
|
-
int token array enqueued a cast BEHIND the next dispatched step, stalling the
|
|
549
|
-
"overlapped" read a full GPU step per token. Use `MlxArray.toIntTokens()`.
|
|
550
|
-
- **A lone row keeps bare serial-class caches.** `KVCache.makeMask(1)` is the
|
|
551
|
-
empty mask and scalar rope; the batched step then dispatches the same graph
|
|
552
|
-
the serial loop builds. The per-layer `BatchedDecodeMaskCache` wrapper is
|
|
553
|
-
only for padded batches.
|
|
554
|
-
- **Rope-array step-stability contract.** A batched cache's `ropeOffsetArr`
|
|
555
|
-
must be stable within a decode step and refresh only at `releaseRopeArr()`;
|
|
556
|
-
re-reading it mid-update ropes K and Q one position apart.
|
|
557
|
-
- **Generated-file guards accept batched subclasses.** The generated forwards'
|
|
558
|
-
per-layer `instanceof` guards pass any batched cache that subclasses a
|
|
559
|
-
serial class, so an all-quant gemma batch decodes through the generated
|
|
560
|
-
fast path — a feature (B=1 proved bit-exact) but a contract: batched caches
|
|
561
|
-
must behave serially under re-reads. Test with FULL configs; one bf16 layer
|
|
562
|
-
anywhere fails the guard and drops to the monolith.
|
|
563
|
-
- **Quantization packs along HEAD_DIM**, so token-axis batch surgery over
|
|
564
|
-
(packed, scales, biases) triples is byte-safe; solo rows convert at serial
|
|
565
|
-
chunk boundaries (bit-exact by construction).
|
|
566
|
-
- **A scheme-less path must refuse, never silently drop quantization.** The
|
|
567
|
-
gateway only threads a `KvScheme` to the scheduler when it is batchable; the
|
|
568
|
-
scheduler refuses an unsupported scheme at construction.
|
|
569
|
-
- **Prefix sharing is non-consuming.** `PromptCache.take()` serves zero-copy
|
|
570
|
-
clones (ref-counted retain so a demoted donor never unmaps pages a clone
|
|
571
|
-
reads); the donor stays put; `put()` supersedes same-namespace prefix
|
|
572
|
-
ancestors when the new entry is trimmable. Kills the cannibalization flaw
|
|
573
|
-
(agent B consuming agent A's entry). v1 shares COMPUTE and durability;
|
|
574
|
-
concurrent rows still hold separate physical KV — one shared physical prefix
|
|
575
|
-
across rows is the block-KV frontier item, and whole-entry duplication in
|
|
576
|
-
the disk tier is the block-granularity revisit trigger.
|
|
577
|
-
- **Prompt-boundary snapshot.** The prompt+generation entry is untrimmable
|
|
578
|
-
past a wrapped ring or under quantized KV, so every substantial request also
|
|
579
|
-
snapshots a strict prompt prefix (cap `len-1`), the mlx-lm
|
|
580
|
-
`insert_segments` invariant; a re-rendered next turn always matches.
|
|
581
|
-
- **Never a JS callback as an mlx buffer destructor** — last-ref `Data` dtors
|
|
582
|
-
run on the Metal completion thread (native `dlsym(free)` dtor, process-pinned
|
|
583
|
-
mmaps).
|
|
584
|
-
- **Isolation proxies the whole server**, not the gateway: grammar WASM,
|
|
585
|
-
vision arrays, and sampler closures don't serialize; the /v1 surface is the
|
|
586
|
-
IPC.
|
|
587
|
-
|
|
588
|
-
## 9. The frontier program (order matters)
|
|
589
|
-
|
|
590
|
-
Ranked by expected frontier shift (memory ↓ / intelligence ↑ first, then
|
|
591
|
-
speed). Each item is a Lab program with its own doc; `decode-speed-program.md`
|
|
592
|
-
ranks the speed levers and is the only doc that does.
|
|
593
|
-
|
|
594
|
-
1. **Mixed-precision weights** — knapsack `--target-bpw` (ours; OptiQ-style
|
|
595
|
-
sensitivity port in `src/quantize/sensitivity.ts`) and rotation-folded
|
|
596
|
-
quantization (`docs/design/turboquant.md`, `--rotate-weights`). Gate:
|
|
597
|
-
perplexity + frozen 6-task eval at equal bpw.
|
|
598
|
-
2. **TurboQuant KV** (`docs/design/turboquant.md`, landed v1) — orthogonal to
|
|
599
|
-
allocation: mixed precision is the ALLOCATION axis, TurboQuant the
|
|
600
|
-
QUANTIZER axis; they compose. Solo-only in v1.
|
|
475
|
+
2. **Method selection now precedes placement.** `resolveExecution` selects
|
|
476
|
+
speculative or ordinary decoding from the actual request and backend
|
|
477
|
+
capabilities. Configuring a draft no longer forces supported ordinary work
|
|
478
|
+
into the serial executor. The final design has one shared executor; changing
|
|
479
|
+
method must not select a retired execution path. Concurrent speculation is
|
|
480
|
+
still an implementation gap, tracked in batching.md.
|
|
481
|
+
|
|
601
482
|
3. **Speculative decoding depth** — DFlash/DSpark, native MTP, behind the
|
|
602
483
|
`DraftSource` seam (`docs/design/speculative-decoding.md`).
|
|
603
484
|
4. **Per-model graph work from the baseline** — unroll a model's flat DAG,
|
|
@@ -833,8 +714,11 @@ Small stateless ports may be implemented by functions or object literals.
|
|
|
833
714
|
| Interface | Owns | Must not own |
|
|
834
715
|
|---|---|---|
|
|
835
716
|
| `CompletionClient` | Semantic completion request, event stream, terminal result, cancellation | Tensor/state handles, model class selection |
|
|
836
|
-
| `PromptPreparer` |
|
|
837
|
-
| `
|
|
717
|
+
| `PromptPreparer` | Coordinate renderer, tokenizer and media preparation; produce token IDs and a stable-prefix boundary | Template syntax, tokenizer algorithms, GPU scheduling or request-global model mutation |
|
|
718
|
+
| `RequestPolicyResolver` | Resolve defaults and explicit overrides once into immutable policy | Executing model work or resampling defaults inside a token loop |
|
|
719
|
+
| `ChatTemplateRenderer` | Render messages, tools and reasoning markers; identify stable rendered boundaries | Tokenizer algorithms, scheduling or cache retention |
|
|
720
|
+
| `Tokenizer` | Encode/decode, token metadata and incremental encoding | Chat-template policy, sampling or scheduling |
|
|
721
|
+
| `ExecutionPlanner` | Effective immutable policy, implementation selection, capability negotiation, declared implementation choices, plan identity | Starting generation or inventing new feature support |
|
|
838
722
|
| `InferenceEngine` | Session creation, runtime coordination, shutdown | Per-family forward math |
|
|
839
723
|
| `GenerationSession` | Lifecycle, committed output, result, cancellation and close | Token-at-a-time assumption, KV offsets, concrete method branches |
|
|
840
724
|
| `InferenceMethod` | AR/speculative/diffusion algorithm and private per-run state | HTTP framing or application sessions |
|
|
@@ -1010,14 +894,20 @@ inside forward/decode after binding. Experiment commands construct separate
|
|
|
1010
894
|
bindings with explicit snapshots. Diagnostics may observe a running request
|
|
1011
895
|
but cannot change its numeric policy halfway through execution.
|
|
1012
896
|
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
897
|
+
Configuration follows ownership: scheduling owns concurrency and queue policy;
|
|
898
|
+
methods own sampling, speculation and stopping; backends own kernels and state
|
|
899
|
+
layouts; storage owns cache budgets, tiers and persistence. The application
|
|
900
|
+
composition root binds these interfaces. A single-request caller supplies the
|
|
901
|
+
same method configuration as a batched caller. Consolidate duplicate controls
|
|
902
|
+
as implementations migrate, retaining documented CLI aliases where needed.
|
|
903
|
+
|
|
904
|
+
Default memory estimates are advisory by Josh's instruction. Attempt the
|
|
905
|
+
requested work without predicted-memory refusals or automatic token clamping.
|
|
906
|
+
Explicit user limits and actual layout requirements still apply. Account for
|
|
907
|
+
shared weights once, live state, draft resources, preparation transients and
|
|
908
|
+
retained/write-behind buffers. Release actual resources on failure; a
|
|
909
|
+
conservative estimate does not establish that execution is impossible. This
|
|
910
|
+
supersedes the earlier mandatory reservation-before-preparation design.
|
|
1021
911
|
|
|
1022
912
|
### 12.6 State, ownership, and persistence
|
|
1023
913
|
|
|
@@ -1074,11 +964,35 @@ and define read-old/write-new compatibility or explicit invalidation per change.
|
|
|
1074
964
|
### 12.7 Scheduling and inference methods
|
|
1075
965
|
|
|
1076
966
|
Keep policy independent from mechanics. Scheduler chooses eligible work,
|
|
1077
|
-
fairness, queue bounds
|
|
967
|
+
fairness, queue bounds and active-row limits. A method's
|
|
1078
968
|
scheduling adapter creates execution groups and implements join/leave/advance
|
|
1079
969
|
over its own state. Native batch merge and filter stay inside the MLX adapter.
|
|
1080
970
|
Scheduler must not import KV classes or perform a per-layer tensor loop.
|
|
1081
971
|
|
|
972
|
+
The consolidation target is single-request execution as a batch of one through
|
|
973
|
+
these same contracts. Methods publish reusable checkpoints through the shared
|
|
974
|
+
cache interface at completed boundaries. The cache owns prefix selection,
|
|
975
|
+
retention and RAM/SSD placement; scheduling does not choose a storage tier, and
|
|
976
|
+
decode does not inspect the request queue. Model/method codecs describe the
|
|
977
|
+
state needed to restore a prefix, including draft state when applicable.
|
|
978
|
+
Prefill and generated tokens populate the same cache. R17 in the decode-speed
|
|
979
|
+
program owns the current implementation and acceptance work.
|
|
980
|
+
|
|
981
|
+
Full batch feature parity is required, including speculation. The current
|
|
982
|
+
serial exclusions are migration work, not the target architecture. Keep an
|
|
983
|
+
explicit feature matrix in the batching design and retire duplicate request
|
|
984
|
+
lifecycles only after the batched implementation covers every serial feature
|
|
985
|
+
and equals or beats serial performance in matched measurements. B=1 latency
|
|
986
|
+
and feature-specific costs must pass independently of aggregate throughput.
|
|
987
|
+
The optimized kernels already built remain behind the backend interface;
|
|
988
|
+
scheduling policy does not choose or reimplement their arithmetic. Continue
|
|
989
|
+
building faster specializations, fusing operations, removing work and avoiding
|
|
990
|
+
materialization. Interfaces must permit complete fused work units rather than
|
|
991
|
+
force one call or intermediate tensor per logical operation. Measure kernel
|
|
992
|
+
changes separately from composition refactors so their effects are attributable. Interface
|
|
993
|
+
extraction must not force tensor copies, materialization, synchronization or
|
|
994
|
+
additional dispatches; compare B=1 latency and B>1 throughput at fixed settings.
|
|
995
|
+
|
|
1082
996
|
An advancement is a bounded safe unit, not necessarily a token: one prefill
|
|
1083
997
|
chunk, a pipelined decode step, one verify round, or one denoising iteration.
|
|
1084
998
|
Budgets describe admitted resources and work hints separately. A synchronous
|
|
@@ -1876,3 +1790,91 @@ existing placement and numerical defaults. Their independent experiment programs
|
|
|
1876
1790
|
still own promotion/deletion decisions. Quiet performance, exact target quants,
|
|
1877
1791
|
unavailable oracle/drafter fixtures and the second machine remain acceptance
|
|
1878
1792
|
work, not missing interface code. No frontier advance is claimed by this refactor.
|
|
1793
|
+
|
|
1794
|
+
### 12.14 Request flow and interface ownership
|
|
1795
|
+
|
|
1796
|
+
This is the target responsibility map for Phase 6/18. A request carries one
|
|
1797
|
+
resolved policy: measured defaults plus explicit user overrides. Each component
|
|
1798
|
+
consumes its own part of that policy. The table below distinguishes existing
|
|
1799
|
+
contracts from implementation and migration work still in progress.
|
|
1800
|
+
|
|
1801
|
+
```mermaid
|
|
1802
|
+
flowchart TB
|
|
1803
|
+
client["Client: chat, Pi, API or library"]
|
|
1804
|
+
server["Server adapter<br/>receive requests and send responses"]
|
|
1805
|
+
policy["Request policy interface<br/>resolve defaults and user overrides once"]
|
|
1806
|
+
template["Chat template interface<br/>messages and tools → rendered prompt"]
|
|
1807
|
+
tokenizer["Tokenizer interface<br/>rendered prompt → token IDs"]
|
|
1808
|
+
session["InferenceEngine / GenerationSession<br/>own request lifecycle and cancellation"]
|
|
1809
|
+
scheduler["Scheduler / ExecutionGroup<br/>choose when ready work runs"]
|
|
1810
|
+
method["InferenceMethod<br/>ordinary decode or MTP proposal / verification"]
|
|
1811
|
+
graph["Model graph interface<br/>prefill, forward passes and specialized kernels"]
|
|
1812
|
+
sampler["SamplingSession<br/>apply settings and grammar; select tokens"]
|
|
1813
|
+
output["Response interface<br/>decode committed tokens; emit text and tool events"]
|
|
1814
|
+
state["Active state interface<br/>target KV, recurrent state, draft state and positions"]
|
|
1815
|
+
cache["PrefixCache interface<br/>restore and retain aligned token / state checkpoints"]
|
|
1816
|
+
ram["RAM cache<br/>retain reusable checkpoints"]
|
|
1817
|
+
persistence["Persistence interface<br/>queue background writes and restore from SSD"]
|
|
1818
|
+
|
|
1819
|
+
client --> server --> policy --> template --> tokenizer --> session
|
|
1820
|
+
session -->|ready work| scheduler
|
|
1821
|
+
scheduler -->|admit and advance a batch of 1 or more| method
|
|
1822
|
+
method -->|inputs and state| graph
|
|
1823
|
+
graph -->|device logits| sampler
|
|
1824
|
+
sampler -->|selected tokens or proposals| method
|
|
1825
|
+
method -->|committed tokens only| output
|
|
1826
|
+
output -->|response events| server
|
|
1827
|
+
method <-->|borrow, update, snapshot, rollback| state
|
|
1828
|
+
session <-->|restore / publish prefill checkpoint| cache
|
|
1829
|
+
method -.->|publish generated checkpoint: still open| cache
|
|
1830
|
+
cache <-->|fast reuse| ram
|
|
1831
|
+
ram <-->|spill and restore when needed| persistence
|
|
1832
|
+
```
|
|
1833
|
+
|
|
1834
|
+
The scheduler chooses **when** work runs and which requests are active. The
|
|
1835
|
+
inference method chooses **what numerical work** advances them. A batch of one
|
|
1836
|
+
uses the same method and state contracts as a larger batch. The final design
|
|
1837
|
+
has one shared executor and no separate serial executor to fall back to.
|
|
1838
|
+
|
|
1839
|
+
The model graph returns logits to the sampler. The sampler applies temperature,
|
|
1840
|
+
penalties, grammar, sampling filters and RNG policy, and returns selected tokens
|
|
1841
|
+
with requested logprobs. MTP keeps proposals private until verification commits
|
|
1842
|
+
them. The response formatter sees committed tokens only.
|
|
1843
|
+
|
|
1844
|
+
Live KV is working state for the current computation. A reusable checkpoint
|
|
1845
|
+
contains token IDs plus the corresponding target, recurrent and optional draft
|
|
1846
|
+
state. Both prefill and generated output must feed the same cache interface.
|
|
1847
|
+
Only an exact, rendered-stable token boundary can be published for state that
|
|
1848
|
+
cannot be trimmed. RAM retention, eviction, asynchronous SSD writes and restart
|
|
1849
|
+
restore belong behind that interface. Scheduling does not wait for an ordinary
|
|
1850
|
+
SSD spill; an explicit durability flush can wait for persistence.
|
|
1851
|
+
|
|
1852
|
+
| Piece | Current code or contract | Remaining work |
|
|
1853
|
+
|---|---|---|
|
|
1854
|
+
| Server / response adapters | `CompletionEngine`, `CompletionSink`, `GenerationOutput` | Preserve the same semantics through the final shared-executor cutover. |
|
|
1855
|
+
| Request policy | `RequestPlan`, request preparation and execution planning | Consolidate configuration into one resolved policy; choose measured defaults for typical multi-turn use and retain user overrides. |
|
|
1856
|
+
| Chat template | `ChatTemplate.render` | Expose the renderer as its own narrow port instead of requiring a concrete serving context. Record rendered-stable boundaries for generated checkpoint alignment. |
|
|
1857
|
+
| Tokenizer | `LoadedTokenizer` | Reuse the same encode/decode contract across preparation, caching and output. Keep incremental encoding inside this component. |
|
|
1858
|
+
| Session / scheduling | `InferenceEngine`, `GenerationSession`, `ExecutionGroup`, `SchedulingClock` | Close all feature and performance gaps before deleting the remaining serial executor. |
|
|
1859
|
+
| Inference method | `InferenceMethod`; shared MTP method in the isolated candidate | Complete every shared-method composition and acceptance gate. Draft depth belongs here, independently of queue policy. |
|
|
1860
|
+
| Numerical graph / kernels | `AutoregressiveGraph`, `GraphFactory`, backend bindings | Continue hardware-specific fusion and kernel optimization behind these contracts. |
|
|
1861
|
+
| Sampler | `SamplingSession` | Retain one set of sampling/history/logprob semantics for ordinary and speculative execution. |
|
|
1862
|
+
| Active state / codec | `Cache`, `KvAttentionState` / `KvAttentionView`, row layouts, `SpeculativeTransaction`, checkpoint attachments | Appending and attending are separate operations. One captured view can serve multiple model layers while retaining pre-write positions and tensor ownership. Delayed rotating affine and broader model/layout composition remain open. |
|
|
1863
|
+
| Reusable cache | `PrefixCache.take/put`, shared `PromptCache` | Generated-output checkpoints and next-request token alignment remain open. Prefill reuse is already implemented. |
|
|
1864
|
+
| Persistence | `ColdTier`, `SpillSink`, `SsdCacheStore`, `SsdDurabilityCoordinator` | Complete combined M4 pressure/restart acceptance. RAM and SSD remain interchangeable retention tiers behind cache operations. |
|
|
1865
|
+
|
|
1866
|
+
An interface boundary does not require copying tensors, downloading logits,
|
|
1867
|
+
or adding an RPC or synchronization per token. Device handles can stay lazy;
|
|
1868
|
+
the backend may fuse compatible graph and sampling operations while preserving
|
|
1869
|
+
policy, ownership and observable results. Each component can improve its own
|
|
1870
|
+
implementation without adding model, cache or sampling decisions to scheduling.
|
|
1871
|
+
|
|
1872
|
+
Contract sources: [generation](../../src/contracts/generation.ts),
|
|
1873
|
+
[scheduling](../../src/contracts/scheduling.ts),
|
|
1874
|
+
[sampling](../../src/contracts/sampling.ts),
|
|
1875
|
+
[prefix cache](../../src/contracts/prefix-cache.ts),
|
|
1876
|
+
[graph](../../src/inference/graph.ts),
|
|
1877
|
+
[tokenizer](../../src/tokenizer.ts),
|
|
1878
|
+
[cache tiers](../../src/prompt-cache.ts).
|
|
1879
|
+
Performance evidence and default selection live in
|
|
1880
|
+
[benchmarks.md](../reference/benchmarks.md); open acceptance remains in Phase 6/18.
|
|
@@ -6,6 +6,22 @@ the evolving UI/UX/DX north star.
|
|
|
6
6
|
|
|
7
7
|
## Product north star
|
|
8
8
|
|
|
9
|
+
Josh's guiding principle for the entire project is "The absolute BEST local
|
|
10
|
+
AI experience on a mac". This governs installation, application development,
|
|
11
|
+
everyday use and inference performance.
|
|
12
|
+
|
|
13
|
+
Offer multiple simple installation methods without asking users to manage
|
|
14
|
+
a Python virtual environment. Let developers import local AI into their
|
|
15
|
+
applications without managing a separate inference sidecar. Make JavaScript
|
|
16
|
+
and TypeScript first-class ways to build with local AI, without requiring
|
|
17
|
+
Python. Make more capable models practical on the same Mac and reduce the
|
|
18
|
+
time users wait for successful results.
|
|
19
|
+
|
|
20
|
+
Every workstream must serve that experience. Evaluate engineering choices
|
|
21
|
+
by the setup, integration and operating burden they remove, as well as the
|
|
22
|
+
quality, reliability, speed and hardware efficiency they deliver. Research
|
|
23
|
+
and publication can support the project; user benefit determines priority.
|
|
24
|
+
|
|
9
25
|
Make the answer to "what is the best way to use local AI on my Mac?"
|
|
10
26
|
boringly simple:
|
|
11
27
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# mlx-bun v0.4.0
|
|
2
|
+
|
|
3
|
+
This release brings shared batched decode, generated-history cache reuse and
|
|
4
|
+
resumable generation together through separate scheduling, inference, sampling
|
|
5
|
+
and persistence interfaces.
|
|
6
|
+
|
|
7
|
+
- Shared ordinary and speculative execution supports Qwen MTP, prompt lookup,
|
|
8
|
+
standalone, assistant, DeepSpec and DSpark/DFlash providers on qualified
|
|
9
|
+
model/request combinations. Single requests run at B=1 through the scheduler.
|
|
10
|
+
- Full and rotating affine/TurboQuant cache layouts compose with delayed and
|
|
11
|
+
per-layer precision, speculative rollback and generated target/draft state.
|
|
12
|
+
- Completed decode populates the shared RAM/SSD cache so later turns can reuse
|
|
13
|
+
generated history. SSD persistence is queued and runs during idle ownership.
|
|
14
|
+
- Ordinary interrupted-generation resume now works through shared execution,
|
|
15
|
+
including compatible adapters and quantized caches. Restored sampler history,
|
|
16
|
+
pending tokens and usage accounting preserve the continuation contract.
|
|
17
|
+
- Ordinary paged storage and adapter-qualified prompt lookup use the same state
|
|
18
|
+
and execution interfaces. GLM native MTP gains shared cache transactions and
|
|
19
|
+
row state; final real-artifact testing remains deferred.
|
|
20
|
+
- Measured Trellis v13 is selected by default, and eligible Qwen KV4 speculation
|
|
21
|
+
is enabled. Workload-dependent lookup and other experimental settings remain
|
|
22
|
+
opt-in. Memory fit estimates are advisory unless users choose explicit limits.
|
|
23
|
+
- Benchmark reporting retains request/source identities, paired comparisons,
|
|
24
|
+
failures and configuration differences. CI and the release build use Bun 1.4.2.
|
|
25
|
+
|
|
26
|
+
Serving keeps its existing `--batch 8` default. A lone eligible request starts
|
|
27
|
+
immediately at B=1; the cap does not wait for eight requests. `--batch 1` retains
|
|
28
|
+
the serial executor, and unsupported compositions can still use it. Removing
|
|
29
|
+
serial and completing every feature combination are follow-up work.
|
|
30
|
+
|
|
31
|
+
Checkpoint capture is eventually persistent: queued snapshots can remain in RAM
|
|
32
|
+
during uninterrupted traffic. A successful explicit flush is the durability
|
|
33
|
+
boundary. Media, fill/grammar-jump and direct paged-attention work remain tracked.
|
|
34
|
+
No DSpark/DFlash checkpoint has been trained for this campaign; execution fixtures
|
|
35
|
+
do not establish trained-drafter performance.
|
|
36
|
+
|
|
37
|
+
Measured performance and its workload limits are in the
|
|
38
|
+
[benchmark record](https://github.com/joshuarossi/mlx-bun/blob/v0.4.0/docs/reference/benchmarks.md).
|
|
39
|
+
This release does not claim a matched full-task Kanban speedup or completion of
|
|
40
|
+
the entire optimization program. Supported settings are documented in the
|
|
41
|
+
[server configuration reference](https://github.com/joshuarossi/mlx-bun/blob/v0.4.0/docs/reference/server-config.md).
|
|
42
|
+
|
|
43
|
+
Requires Apple Silicon and macOS 14 or later. npm installs require Bun 1.4.0 or
|
|
44
|
+
later; Bun 1.4.2 is the tested version. The existing native runtime pack 0.4.0
|
|
45
|
+
provides MLX 0.32.2 and its matching C API.
|