mlx-bun 0.4.0 → 0.5.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/README.md +57 -32
- package/docs/README.md +55 -42
- package/docs/archive/investigations/benchmark-ledger-through-v0.4.0.md +3617 -0
- package/docs/archive/planning/release-notes-v0.5.0.md +37 -0
- package/docs/design/batching.md +220 -7
- package/docs/design/decode-speed-program.md +121 -66
- package/docs/design/generic-model-support.md +116 -0
- package/docs/design/kv-cache.md +380 -211
- package/docs/design/speculative-decoding.md +165 -26
- package/docs/design/turboquant.md +20 -7
- package/docs/design/unified-engine-frontier-plan.md +120 -13
- package/docs/planning/PRODUCT_ROADMAP.md +5 -6
- package/docs/planning/public-readiness-handoff.md +244 -0
- package/docs/planning/public-readiness.md +149 -0
- package/docs/reference/benchmarks.md +3463 -3489
- package/docs/reference/cli.md +62 -1
- package/docs/reference/distribution.md +29 -4
- package/docs/reference/environment.md +104 -8
- package/docs/reference/library-api.md +18 -4
- package/docs/reference/memory.md +1 -1
- package/docs/reference/models.md +17 -5
- package/docs/reference/server-api.md +181 -11
- package/docs/reference/server-config.md +232 -105
- package/package.json +2 -2
- package/src/audio/audiotoolbox.ts +112 -0
- package/src/audio/conformer.ts +8 -0
- package/src/audio/mic-capture.ts +98 -0
- package/src/audio/silero-vad.ts +379 -0
- package/src/audio/whisper-decode.ts +774 -0
- package/src/audio/whisper-fast.ts +732 -0
- package/src/audio/whisper-format.ts +73 -0
- package/src/audio/whisper-mel.ts +185 -0
- package/src/audio/whisper-timing.ts +274 -0
- package/src/audio/whisper-tokenizer.ts +239 -0
- package/src/audio/whisper-transcribe.ts +410 -0
- package/src/backends/mlx/autoregressive.ts +22 -1
- package/src/backends/mlx/batch-group.ts +111 -27
- package/src/backends/mlx/cache-layout.ts +3 -3
- package/src/backends/mlx/continuation-persistence.ts +5 -4
- package/src/backends/mlx/encoder-cache.ts +25 -0
- package/src/backends/mlx/fill-append.ts +21 -8
- package/src/backends/mlx/fill-group.ts +497 -0
- package/src/backends/mlx/gateway-binding.ts +56 -12
- package/src/backends/mlx/kv-maintenance.ts +30 -2
- package/src/backends/mlx/mixed-iteration.ts +62 -0
- package/src/backends/mlx/model-prompt.ts +46 -32
- package/src/backends/mlx/model-serving.ts +4 -3
- package/src/backends/mlx/paged-cache-codec.ts +27 -0
- package/src/backends/mlx/prefill-cohort.ts +15 -4
- package/src/backends/mlx/prefill-policy.ts +26 -0
- package/src/backends/mlx/prefill-rows.ts +57 -13
- package/src/backends/mlx/prompt-input.ts +29 -0
- package/src/backends/mlx/qwen-prompt-input.ts +40 -0
- package/src/backends/mlx/request-state-policy.ts +18 -5
- package/src/backends/mlx/rollback.ts +6 -3
- package/src/backends/mlx/serial-executor.ts +16 -7
- package/src/backends/mlx/speculative-group.ts +105 -26
- package/src/backends/mlx/speculative.ts +24 -7
- package/src/backends/mlx/target-layout-capability.ts +1 -1
- package/src/backends/mlx/transitioning-kv-rows.ts +8 -0
- package/src/cli.ts +322 -0
- package/src/contracts/execution.ts +10 -0
- package/src/contracts/object-cache.ts +8 -0
- package/src/contracts/pi-provider.ts +1 -1
- package/src/contracts/pi.ts +3 -1
- package/src/contracts/prefix-cache.ts +13 -3
- package/src/contracts/scheduling.ts +9 -0
- package/src/engine/execution-plan.ts +23 -12
- package/src/engine/execution-tasks.ts +44 -0
- package/src/engine/namespaced-cache.ts +13 -0
- package/src/engine/scheduler.ts +22 -2
- package/src/fill/fill-session.ts +14 -3
- package/src/generate.ts +28 -22
- package/src/grammar.ts +13 -0
- package/src/inference/prefill.ts +6 -0
- package/src/kv-scheme.ts +22 -0
- package/src/kv-store.ts +115 -79
- package/src/lab/README.md +5 -1
- package/src/lab/paged-kv/paged-attention.ts +117 -0
- package/src/lab/paged-kv/paged-kv-rows.ts +33 -5
- package/src/lab/paged-kv/paged-kv.ts +108 -42
- package/src/md-modules.d.ts +5 -0
- package/src/mlx/array.ts +37 -0
- package/src/mlx/ffi.ts +19 -0
- package/src/mlx/normalized-argmax.ts +116 -0
- package/src/mlx/ops.ts +97 -10
- package/src/model/batched-turboquant-kv.ts +6 -5
- package/src/model/delayed-quantized-kv.ts +3 -3
- package/src/model/delayed-rotating-quantized-kv.ts +1 -1
- package/src/model/delayed-turboquant-kv.ts +6 -4
- package/src/model/factory.ts +26 -0
- package/src/model/fingerprint.ts +12 -0
- package/src/model/full-prefill-row.ts +1 -1
- package/src/model/gemma4-base.ts +25 -6
- package/src/model/gemma4.ts +82 -2
- package/src/model/kv-attention-view.ts +4 -1
- package/src/model/profile.ts +29 -4
- package/src/model/quantized-append-attention.ts +31 -0
- package/src/model/qwen3-mrope.ts +7 -9
- package/src/model/qwen3_5.ts +99 -37
- package/src/model/support.ts +8 -0
- package/src/model/token-groups.ts +66 -0
- package/src/model/trellis-linear.ts +2 -2
- package/src/model/turboquant-codec.ts +6 -0
- package/src/model/whisper.ts +435 -0
- package/src/native/mic_capture.swift +92 -0
- package/src/native-pack.ts +6 -5
- package/src/pi-web.ts +9 -1
- package/src/prompt-cache.ts +265 -43
- package/src/runtime-config.ts +1 -5
- package/src/safetensors.ts +9 -2
- package/src/sampler.ts +5 -4
- package/src/serve/audio-routes.ts +323 -0
- package/src/serve/chat-request.ts +2 -0
- package/src/serve/chat-stage.ts +17 -12
- package/src/serve/completion-executor.ts +9 -1
- package/src/serve/discovery-routes.ts +17 -1
- package/src/serve/generated-token-history.ts +57 -0
- package/src/serve/generation-gateway.ts +52 -11
- package/src/serve/model-binding.ts +7 -1
- package/src/serve/preparation.ts +3 -3
- package/src/serve/prompt-response-trace.ts +14 -0
- package/src/serve/request-plan.ts +2 -0
- package/src/serve/request-prep.ts +38 -21
- package/src/serve/transcription-server.ts +64 -0
- package/src/serve/transcription-service.ts +502 -0
- package/src/server.ts +132 -164
- package/src/spec/assistant-rows.ts +1 -0
- package/src/spec/deepspec-rows.ts +1 -1
- package/src/spec/dflash-source.ts +1 -1
- package/src/spec/glm52-mtp-source.ts +1 -0
- package/src/spec/ngram-source.ts +27 -5
- package/src/spec/projected-draft-rows.ts +2 -2
- package/src/spec/qwen-mtp-rows.ts +11 -0
- package/src/spec/qwen-mtp-source.ts +3 -0
- package/src/spec/serve-loop.ts +5 -3
- package/src/spec/source.ts +14 -1
- package/src/spec/two-model-rows.ts +1 -0
- package/src/spec/two-model.ts +2 -2
- package/src/ssd-cache.ts +76 -17
- package/src/ssd-durability.ts +20 -22
- package/src/storage/host-buffer.ts +24 -0
- package/src/storage/kv-writer.ts +83 -0
- package/src/storage/kv-writer.worker.js +264 -0
- package/src/storage/retention-policy.ts +37 -0
- package/src/tiered-prompt-cache.ts +45 -0
- package/src/vision/embedder.ts +8 -0
- package/src/vision/prompt.ts +101 -65
- package/src/vision/qwen3vl-prompt.ts +101 -64
- package/src/vision/qwen3vl-tower.ts +11 -0
- package/src/vision/siglip.ts +8 -0
- package/src/web/app.html +12 -0
- package/src/web/app.js +160 -0
- package/src/web/src/chat.ts +4 -1
- package/src/web/src/composer.ts +3 -0
- package/src/web/src/voice.ts +141 -0
- package/src/web/sw.js +1 -1
- /package/docs/{planning → archive/planning}/release-notes-v0.4.0.md +0 -0
|
@@ -30,6 +30,10 @@ every other path is unique. Unmatched paths return
|
|
|
30
30
|
| POST | `/v1/messages` | [Anthropic Messages](#post-v1messages-anthropic-messages-api) |
|
|
31
31
|
| POST | `/v1/responses` | [OpenAI Responses](#post-v1responses-openai-responses-api) |
|
|
32
32
|
| POST | `/v1/embeddings` | [Embeddings](#post-v1embeddings-openai-embeddings-api) |
|
|
33
|
+
| POST | `/v1/audio/transcriptions`, `/v1/audio/translations` | [Audio transcription](#post-v1audiotranscriptions--post-v1audiotranslations-speech-to-text) |
|
|
34
|
+
| POST | `/v1/audio/sessions`, `/v1/audio/sessions/<id>/audio`, `/v1/audio/sessions/<id>/finish` | [Streaming sessions](#streaming-transcription-sessions-v1audiosessions) |
|
|
35
|
+
| DELETE | `/v1/audio/sessions/<id>` | [Streaming sessions](#streaming-transcription-sessions-v1audiosessions) |
|
|
36
|
+
| POST | `/admin/transcription/unload` | [Audio transcription](#post-v1audiotranscriptions--post-v1audiotranslations-speech-to-text) |
|
|
33
37
|
| GET | `/v1` | [API index](#get-v1) |
|
|
34
38
|
| GET | `/v1/models`, `/v1/models/<id>` | [Models](#get-v1models) |
|
|
35
39
|
| GET / POST | `/v1/adapters` | [Adapters](#adapters-lora-hot-swap) |
|
|
@@ -40,6 +44,7 @@ every other path is unique. Unmatched paths return
|
|
|
40
44
|
| GET | `/fit` | [Fit](#get-fit) |
|
|
41
45
|
| GET | `/library` | [Library](#get-library) |
|
|
42
46
|
| GET | `/downloads` | [Downloads](#get-downloads) |
|
|
47
|
+
| POST | `/admin/cache/session/close` | [Close cache session](#post-admincachesessionclose) |
|
|
43
48
|
| POST | `/admin/cache/flush` | [SSD cache flush](#post-admincacheflush) |
|
|
44
49
|
| GET | `/api/jobs`, `/api/jobs/<id>`, `/api/jobs/<id>/stream` | [Jobs](#jobs-apijobs) |
|
|
45
50
|
| POST | `/api/finetune/submit`, `/inspect-dataset`, `/merge`, `/export` | [Fine-tune](#fine-tune-apifinetune) |
|
|
@@ -370,15 +375,15 @@ or the model-free `serve --draft-kind ngram`, which mounts no draft
|
|
|
370
375
|
model); there is no per-request draft field. The `speculation` usage
|
|
371
376
|
extension appears on chat and text completions alike, non-streaming and on
|
|
372
377
|
the final stream chunk. Spec-eligible requests are text-only on base weights.
|
|
373
|
-
In the
|
|
378
|
+
In the shared executor, Qwen grouped MTP, prompt lookup and standalone drafting support logprobs and
|
|
374
379
|
bf16, uniform KV4/KV8 or per-layer affine KV, or TurboQuant. Qwen MTP and prompt lookup also support
|
|
375
380
|
positive library conversion thresholds for uniform KV4/KV8. Per-layer mixed KV and
|
|
376
381
|
adapters remain incompatible with speculation. Strict legacy serial execution
|
|
377
382
|
retains its narrower bf16/KV4 policy. The KV4 compatibility control is
|
|
378
383
|
`MLX_BUN_QWEN_SPEC_KV4=0`.
|
|
379
384
|
Ineligible requests decode normally and omit the field. Qwen MTP reuses paired
|
|
380
|
-
target/draft prefill and completed decode state through the shared RAM/SSD
|
|
381
|
-
|
|
385
|
+
target/draft prefill and completed decode state through the shared RAM/SSD
|
|
386
|
+
cache by default in v0.4.0, reported in `cached_tokens`. Configured SSD persistence
|
|
382
387
|
supports reuse after restart; `MLX_BUN_MTP_PROMPT_CACHE=0` disables reuse.
|
|
383
388
|
Generated checkpoints cover processed tokens and use queued SSD persistence.
|
|
384
389
|
Long-conversation performance acceptance remains open. Qwen prompt lookup also
|
|
@@ -406,19 +411,38 @@ using its qualified append chunk size, then resumes sampling
|
|
|
406
411
|
(design: [speculative-decoding.md](../design/speculative-decoding.md) §"Token
|
|
407
412
|
fast-forwarding"). Injected tokens are billed in `completion_tokens` like any
|
|
408
413
|
other generated token; `decodeSteps` counts ordinary sampling steps, so
|
|
409
|
-
`injected / (injected + decodeSteps)` is the share
|
|
414
|
+
`injected / (injected + decodeSteps)` is the share emitted through fill.
|
|
415
|
+
Strict spans bypass sampling; echo spans still undergo sampled verification.
|
|
410
416
|
Injected positions still run through the model layers. The field is absent when the feature is off or the
|
|
411
|
-
request's shape
|
|
412
|
-
|
|
417
|
+
request's shape excludes it, including `logprobs`, structured output or media.
|
|
418
|
+
Strict shared fill supports bf16, affine KV and
|
|
419
|
+
TurboQuant layouts and retains absolute sampling positions for explicit seeds.
|
|
420
|
+
Its `usage.fill` statistics use the same fields as explicit serial execution.
|
|
421
|
+
Known tokens still advance model state. All-known steps skip intermediate
|
|
422
|
+
vocabulary heads and use the model-qualified append geometry, including the
|
|
423
|
+
specialized Qwen B1 append. Wider Qwen rows retain one-position arithmetic. Compiled
|
|
424
|
+
replay, paging and interruption checkpoints remain outside this shared method.
|
|
425
|
+
Explicit serial fill still excludes user-fixed seeds.
|
|
413
426
|
|
|
414
427
|
Under `MLX_BUN_FILL=echo` a second, weaker source joins: spans copied from
|
|
415
428
|
earlier in the same session, carried under policy `verify`. Those ride the same
|
|
416
|
-
single forward, are checked
|
|
429
|
+
single forward, are checked by the request's sampler on its logits, and have
|
|
417
430
|
their rejected tail rewound — so `verifyAccepted + verifyRejected` is what the
|
|
418
431
|
echo index proposed and `injected` is what survived. `wastedSamples` counts
|
|
419
432
|
only ASSERT fills (a verify fill consumes the in-flight sample as its first
|
|
420
433
|
position's check instead of discarding it).
|
|
421
434
|
|
|
435
|
+
Qwen MTP can alternate learned draft rounds with verified echo rounds. The
|
|
436
|
+
provider consumes accepted copied tokens and target context before drafting
|
|
437
|
+
again. Its asserted template spans remain ordinary sampled output. Learned
|
|
438
|
+
draft counts, acceptance histograms and `speculation.rounds` exclude echo;
|
|
439
|
+
`targetCalls`, `tokensPerForward` and `forwardsSaved` cover both round types.
|
|
440
|
+
Echo activity remains in `usage.fill`, including matching prefixes established
|
|
441
|
+
by ordinary MTP samples, so it is not additive with learned-draft counts.
|
|
442
|
+
A request fully served by echoes can
|
|
443
|
+
have zero learned drafts. Other mounted providers do not yet support this
|
|
444
|
+
combination.
|
|
445
|
+
|
|
422
446
|
An explicit `seed` controls a request-local random stream and can use
|
|
423
447
|
continuous execution. Repeating a request reproduces sampling at the same
|
|
424
448
|
model arithmetic and batch composition. Different batch shapes can change
|
|
@@ -764,6 +788,97 @@ curl localhost:8080/v1/embeddings -H 'content-type: application/json' \
|
|
|
764
788
|
-d '{"input": ["the cat sat on the mat", "a kitten by the window"]}'
|
|
765
789
|
```
|
|
766
790
|
|
|
791
|
+
## POST /v1/audio/transcriptions · POST /v1/audio/translations (speech-to-text)
|
|
792
|
+
|
|
793
|
+
OpenAI-compatible Whisper transcription (`translations` = the same route with
|
|
794
|
+
task `translate`, English output). Served by every `mlx-bun serve` beside the
|
|
795
|
+
chat model — the Whisper checkpoint (`--whisper-model`, default: the first
|
|
796
|
+
downloaded `whisper` model) loads for each take and is released right after
|
|
797
|
+
it unless `--whisper-idle-unload`/`--whisper-resident` say otherwise — and by the transcription-only server that
|
|
798
|
+
`serve <whisper checkpoint>` starts ([server-config.md](server-config.md)).
|
|
799
|
+
Model support and the parity contract: [models.md](models.md#supported-models);
|
|
800
|
+
CLI equivalent: [`mlx-bun transcribe`](cli.md#transcribe--speech-to-text).
|
|
801
|
+
|
|
802
|
+
**Request** — `multipart/form-data` (OpenAI's shape) or JSON:
|
|
803
|
+
|
|
804
|
+
| Field | Meaning |
|
|
805
|
+
| --- | --- |
|
|
806
|
+
| `file` | audio upload (multipart) or base64 / `data:` URL string (JSON; `input_audio.data` and `audio` are accepted aliases). WAV decodes through the exact PCM parser; any other CoreAudio-readable container (mp3/m4a/aac/flac/ogg/aiff/caf, mp4/mov audio tracks…) decodes in-process through AudioToolbox (`src/audio/audiotoolbox.ts`, 3.7 ms for an 11 s mp3). Undecodable bytes are a `400`. |
|
|
807
|
+
| `model` | ignored — the configured Whisper checkpoint is used |
|
|
808
|
+
| `language` | ISO code or name; omitted / `auto` detects from the first 30 s |
|
|
809
|
+
| `prompt` | initial prompt (vocabulary, style); the last 223 tokens are kept |
|
|
810
|
+
| `response_format` | `json` (default) · `verbose_json` · `text` · `srt` · `vtt` |
|
|
811
|
+
| `temperature` | one temperature in [0, 1]; omitted = mlx-whisper's `(0, 0.2, …, 1.0)` fallback ladder |
|
|
812
|
+
| `stream` | `true` → server-sent events (below) |
|
|
813
|
+
| `timestamp_granularities[]` | `segment` (default); `word` adds `words` (`word, start, end, probability`) to `verbose_json` segments via cross-attention DTW on the checkpoint's alignment heads — one extra decoder pass per window |
|
|
814
|
+
| `beam_size` | **non-standard**: beam search width (default greedy); requires temperature 0 |
|
|
815
|
+
| `vocabulary` | **non-standard**: array (JSON) or comma-separated (multipart) recognition hints, fitted whole-term into the 223-token prompt budget after `prompt`; usage is reported |
|
|
816
|
+
| `condition_on_previous_text` | **non-standard**, default `true` |
|
|
817
|
+
| `no_speech_threshold`, `without_timestamps` | **non-standard** mlx-whisper decode options |
|
|
818
|
+
| `vad`, `vad_threshold`, `vad_min_speech_ms`, `vad_trim` | **non-standard**: Silero VAD gate (v6.2, `ggml-org/whisper-vad` weights in the HF cache). No detected speech → `{"text": ""}` with `mlx_bun.vad.speech = false` and Whisper never runs (≈25 ms for 11 s). `vad_trim` crops to the speech span ± 0.5 s first; timestamps stay clip-relative. Segments are reported in `mlx_bun.vad.segments` (seconds). Defaults: threshold 0.5, min speech 250 ms |
|
|
819
|
+
| `faithful` | **non-standard**: `true` runs the oracle-parity graph instead of the fast path (fused attention, compiled decoder step); same tokens up to documented near-ties, slower |
|
|
820
|
+
| `audio_ctx` | **non-standard, Lab**: encode only the first n of 1500 encoder positions (whisper.cpp `-ac`). Cheaper for short clips; measured hallucinated repeats below ~1024 on the fixture clips — off unless set |
|
|
821
|
+
|
|
822
|
+
**Response** — `json`: `{ "text": "…", "mlx_bun": { "model", "language",
|
|
823
|
+
"duration", "timings": { "load_ms", "transcribe_ms", "total_ms" },
|
|
824
|
+
"vocabulary"?: { "included", "omitted", "token_count", "token_budget" } } }`.
|
|
825
|
+
`verbose_json` adds `task`, `language`, `duration` and openai-whisper's
|
|
826
|
+
`segments` (`id, seek, start, end, text, tokens, temperature, avg_logprob,
|
|
827
|
+
compression_ratio, no_speech_prob`). `text`/`srt`/`vtt` return the bare body
|
|
828
|
+
(`text/plain`, `application/x-subrip`, `text/vtt`) with `x-mlx-bun-language`
|
|
829
|
+
and `x-mlx-bun-timings` headers. `load_ms` is non-zero exactly when the
|
|
830
|
+
request paged the weights in.
|
|
831
|
+
|
|
832
|
+
**Streaming** (`stream=true`): `text/event-stream` with `transcript.text.delta`
|
|
833
|
+
`{ "delta": "<segment text>", "segment": { "id", "start", "end" } }` per
|
|
834
|
+
finalized segment, `transcript.progress` `{ "done", "total" }` (mel frames),
|
|
835
|
+
and a final `transcript.text.done` carrying the non-streaming body.
|
|
836
|
+
|
|
837
|
+
**Errors**: `400 invalid_request_error` (fields, undecodable audio, clips
|
|
838
|
+
shorter than 0.1 s), `415` (content type), `499` on client cancel, and
|
|
839
|
+
`503 model_unavailable` when no Whisper checkpoint is on disk (the message
|
|
840
|
+
carries the `mlx-bun get` command).
|
|
841
|
+
|
|
842
|
+
`POST /admin/transcription/unload` pages the weights out now and returns
|
|
843
|
+
`{ "unloaded": bool, "resident", "loads", "unloads", "requests",
|
|
844
|
+
"last_load_ms", "idle_unload_sec" }` — the same block `/health` and
|
|
845
|
+
`/stats` report as `transcription` on the transcription-only server.
|
|
846
|
+
Transcriptions run one at a time and never overlap chat generation on the
|
|
847
|
+
GPU (the generation gateway's exclusive lock).
|
|
848
|
+
|
|
849
|
+
```sh
|
|
850
|
+
curl localhost:8080/v1/audio/transcriptions -F file=@meeting.m4a -F language=en -F response_format=srt
|
|
851
|
+
curl localhost:8080/v1/audio/transcriptions -H 'content-type: application/json' \
|
|
852
|
+
-d '{"file":"<base64 wav>","beam_size":5,"vocabulary":["Sotto","SwiftUI","Metal"]}'
|
|
853
|
+
```
|
|
854
|
+
|
|
855
|
+
## Streaming transcription sessions (`/v1/audio/sessions`)
|
|
856
|
+
|
|
857
|
+
For audio that is being recorded while it is sent (dictation). Every
|
|
858
|
+
completed 30 s window is transcribed as soon as it exists, under the same
|
|
859
|
+
exclusive lock as everything else, so `finish` costs one window regardless
|
|
860
|
+
of take length (measured: a 62 s take that needs 1165 ms in batch returns
|
|
861
|
+
327 ms after its last chunk, identical text — M1 Max). With `vad: true` the
|
|
862
|
+
Silero gate runs on the stream: nothing is transcribed until speech has
|
|
863
|
+
been seen, and a take with no speech finishes as `{"text": ""}` without
|
|
864
|
+
ever running Whisper. The one-shot parameters (`language`, `prompt`,
|
|
865
|
+
`vocabulary`, `beam_size`, `temperature`, `vad*`, `timestamp_granularities`,
|
|
866
|
+
`faithful`) apply; `response_format` is `json` or `verbose_json`.
|
|
867
|
+
|
|
868
|
+
| Route | Body / response |
|
|
869
|
+
| --- | --- |
|
|
870
|
+
| `POST /v1/audio/sessions` | JSON params → `{ "id", "model", "vocabulary" }` (the weights load here if they were paged out) |
|
|
871
|
+
| `POST /v1/audio/sessions/<id>/audio` | one chunk: `content-type: audio/pcm;rate=16000` raw little-endian float32 mono (sotto's format, no decode), or any CoreAudio container. → `{ "samples", "duration", "speech", "segments": [...] }` with every segment finalized so far |
|
|
872
|
+
| `POST /v1/audio/sessions/<id>/finish` | → the one-shot response body (`json`/`verbose_json` with `mlx_bun`), closes the session |
|
|
873
|
+
| `DELETE /v1/audio/sessions/<id>` | discard, `204` |
|
|
874
|
+
|
|
875
|
+
Chunk order is the caller's responsibility (send sequentially and await
|
|
876
|
+
each receipt). Unknown ids are `404`; a finished session is `409`; at most
|
|
877
|
+
64 sessions are open at once (`429`). Windows fed early are normalized
|
|
878
|
+
against the audio received so far (the log-mel clamp is relative to the
|
|
879
|
+
clip maximum), which can differ from a batch transcription in near-silent
|
|
880
|
+
mel bins — the fixture takes decode identically.
|
|
881
|
+
|
|
767
882
|
## GET /v1
|
|
768
883
|
|
|
769
884
|
API index for discovery tooling:
|
|
@@ -771,7 +886,8 @@ API index for discovery tooling:
|
|
|
771
886
|
```jsonc
|
|
772
887
|
{ "name": "mlx-bun", "version": "<package version>", "model": "<served model id>",
|
|
773
888
|
"endpoints": ["POST /v1/chat/completions", "POST /v1/completions", "POST /v1/messages",
|
|
774
|
-
"POST /v1/responses", "POST /v1/embeddings", "
|
|
889
|
+
"POST /v1/responses", "POST /v1/embeddings", "POST /v1/audio/transcriptions",
|
|
890
|
+
"POST /v1/audio/translations", "GET /v1/models",
|
|
775
891
|
"GET/POST/DELETE /v1/adapters", "GET /health", "GET /stats", "GET /fit",
|
|
776
892
|
"GET /library", "GET /downloads"] }
|
|
777
893
|
```
|
|
@@ -863,11 +979,11 @@ vision/audio, adapters, and training are not emulated by the serving port.
|
|
|
863
979
|
```jsonc
|
|
864
980
|
{
|
|
865
981
|
"server": { "owner": "serve" | "pi-session" | "embedded", "model": "...", "started_at": 0 },
|
|
866
|
-
"prompt_cache": { "entries": 0, "bytes": 0, "max_bytes": 0, "hits": 0, "misses": 0 },
|
|
982
|
+
"prompt_cache": { "entries": 0, "bytes": 0, "max_bytes": 0, "hits": 0, "misses": 0, "object_hits": 0, "object_misses": 0, "object_restores": 0 },
|
|
867
983
|
"response_store": { "entries": 0, "bytes": 0, "max_bytes": 33554432, "ttl_ms": 3600000 },
|
|
868
984
|
"kv_quant": { "mode": "bf16" | "uniform-kv8" | "turbo k8v3" | "mixed (kv_config.json)",
|
|
869
985
|
"layers": { "kv4": 8, "bf16": 40 }, // turbo: { "turbo-k8v3": 8, "bf16": 40 }
|
|
870
|
-
"attention": { "global": 10, "sliding_window": 38 } },
|
|
986
|
+
"attention": { "global": 10, "sliding_window": 38 }, "recurrent_layers": 0 },
|
|
871
987
|
// present only when --ssd-cache is on:
|
|
872
988
|
"ssd_cache": { "dir": "...", "entries": 0, "bytes": 0, "max_bytes": 0,
|
|
873
989
|
"restores": 0, "spills": 0, "restore_ms_last": 0, "demotions": 0,
|
|
@@ -926,6 +1042,12 @@ appears only when `--kv-quant config` was passed explicitly and the
|
|
|
926
1042
|
checkpoint ships a per-layer `kv_config.json` — per-layer KV quantization
|
|
927
1043
|
is never selected automatically.
|
|
928
1044
|
|
|
1045
|
+
`kv_quant.layers` counts configured attention KV codecs; `attention` separates
|
|
1046
|
+
full and sliding attention. `recurrent_layers` counts linear/recurrent layers
|
|
1047
|
+
whose convolution and recurrent state retain their own precision. They do not
|
|
1048
|
+
count as bf16 or quantized attention KV. These are model/policy counts, not
|
|
1049
|
+
live allocation measurements or a per-request conversion-progress report.
|
|
1050
|
+
|
|
929
1051
|
`pending_snapshots` counts prompt-cache entries scheduled for persistence but
|
|
930
1052
|
not yet confirmed by the atomic SSD store. `longest_durable_prefix_tokens` is
|
|
931
1053
|
the longest prefix already present in the SSD index, not merely queued.
|
|
@@ -1030,6 +1152,50 @@ makes it the default for requests that send no `adapter` field; an
|
|
|
1030
1152
|
explicit `adapter` (including `"none"`) always wins, and hot-swap via
|
|
1031
1153
|
these endpoints is unchanged.
|
|
1032
1154
|
|
|
1155
|
+
## Cache session affinity
|
|
1156
|
+
|
|
1157
|
+
Completion requests may supply `session_id` or `prompt_cache_key` in the JSON
|
|
1158
|
+
body, or `x-session-affinity` / `session_id` in a header. Precedence is body
|
|
1159
|
+
`session_id`, body `prompt_cache_key`, `x-session-affinity`, then `session_id`.
|
|
1160
|
+
This applies to chat completions, text completions, Responses and Messages.
|
|
1161
|
+
The shared mlx-bun Pi provider sends session-affinity headers automatically.
|
|
1162
|
+
|
|
1163
|
+
A session indexes its latest published checkpoint within each numerical cache
|
|
1164
|
+
namespace. Compatible continuations use that checkpoint directly; edited,
|
|
1165
|
+
branched or missing histories use ordinary prefix matching. The full intended
|
|
1166
|
+
input is still required: a session label does not append omitted messages,
|
|
1167
|
+
isolate access, change model settings or bypass token compatibility.
|
|
1168
|
+
|
|
1169
|
+
The cache prefers session-referenced checkpoints when choosing RAM residents,
|
|
1170
|
+
but can evict them when required. SSD persistence remains independent. Session
|
|
1171
|
+
indexes are process-local; after restart, the first request uses ordinary SSD
|
|
1172
|
+
lookup and re-establishes the association. Entries remain shareable across
|
|
1173
|
+
sessions and requests without session metadata. `MLX_BUN_SESSION_CACHE` provides
|
|
1174
|
+
the A/B control described in server-config.md.
|
|
1175
|
+
|
|
1176
|
+
`GET /stats` adds `prompt_cache.session_hits`, `session_misses` and
|
|
1177
|
+
`prefix_scans`. A session hit counts direct RAM checkpoint selection, including
|
|
1178
|
+
state prepared from SSD before execution. A session miss counts execution
|
|
1179
|
+
lookups with session metadata that need ordinary candidate search. Prefix scans
|
|
1180
|
+
count ordinary execution searches, not tokenization or preparation probes.
|
|
1181
|
+
|
|
1182
|
+
|
|
1183
|
+
Qwen image/video encoder reuse reports `prompt_cache.object_hits`,
|
|
1184
|
+
`object_misses` and `object_restores`. A hit borrows an exact RAM tensor object;
|
|
1185
|
+
a miss may restore from SSD or recompute. Object entries and bytes are included
|
|
1186
|
+
in the existing cache totals and share its RAM budget and persistence queue.
|
|
1187
|
+
These counters do not count language-model KV prefix hits. Media prompt KV
|
|
1188
|
+
reuse remains disabled because token IDs alone do not identify media contents.
|
|
1189
|
+
|
|
1190
|
+
|
|
1191
|
+
## POST /admin/cache/session/close
|
|
1192
|
+
|
|
1193
|
+
Send `{ "session_id": "agent-42" }` to remove that session's cache association
|
|
1194
|
+
and retention preference. Returns `{ "closed": true }` when an ID is supplied,
|
|
1195
|
+
or `{ "closed": false }` otherwise. Closing does not delete checkpoints from
|
|
1196
|
+
RAM or SSD. Applications can close idle or completed sessions; a later request
|
|
1197
|
+
with the same ID establishes a new association.
|
|
1198
|
+
|
|
1033
1199
|
## POST /admin/cache/flush
|
|
1034
1200
|
|
|
1035
1201
|
Forces every pending SSD prompt-cache snapshot through the serial write queue
|
|
@@ -1653,7 +1819,11 @@ repetition_context_size?, presence_penalty?, frequency_penalty?, seed?}`
|
|
|
1653
1819
|
`delete_session {path}`, `regenerate`, `edit_resend {text}`,
|
|
1654
1820
|
`switch_sibling {entryId}`, `context {context}` (app-aware assistant, below).
|
|
1655
1821
|
|
|
1656
|
-
Server → client: `ready {model, vision, audio, thinking, genDefaults}
|
|
1822
|
+
Server → client: `ready {model, vision, audio, thinking, genDefaults, transcription}`
|
|
1823
|
+
(`transcription` is true when a Whisper checkpoint serves [`/v1/audio/sessions`](#streaming-transcription-sessions-v1audiosessions);
|
|
1824
|
+
the web composer then shows a hold-to-talk mic that streams 16 kHz float32
|
|
1825
|
+
into a session and inserts the transcript into the message box — voice
|
|
1826
|
+
input for any chat model),
|
|
1657
1827
|
`turn_start`, `text_delta {delta}`, `thinking_delta {delta}`, `tool_start
|
|
1658
1828
|
{callId, tool, args}`, `tool_approval_request {callId, tool, args}`,
|
|
1659
1829
|
`tool_update {callId, chunk}`, `tool_end {callId, ok, result}`, `turn_end
|