Until now, speculative decoding was a single-user feature: the moment two requests hit the daemon at once, everyone fell back to plain autoregressive batching and lost the MTP speedup. 2.6.0 removes that trade-off. This release also brings embedding and reranking endpoints, LiquidAI LFM2 support, and a real correctness fix to temperature-0 decoding.
--scheduler-mode mtp_batch)The new scheduler serves independent requests through fixed-width MTP cohorts. Each row owns its own state and sampling decisions, drafts are verified in one batched target forward, and rows join and leave mid-flight without disturbing their neighbours. Two cohort widths (three-wide and eight-wide) install side by side and the scheduler seals each cohort at the narrowest width that fits, so two concurrent agents don't pay for eight lanes of padding.
Measured on Qwen3.6-35B-A3B on an M5 Max: the three-wide lane holds 1.7-1.8x the per-request decode of the padded eight-lane shape, and against the previous production ar_batch route the same concurrent agent workloads decode at 1.6-2.25x per lane, sampled at the model's shipped settings.
Honesty controls ship with it: --mtp-batch-numerics picks between
throughput, balanced, and b1-exact profiles with documented
trade-offs and an install-time self-check, and per-request stats report
each row's own truth (its own accepted-depth histogram, cohort width, and
restore provenance) instead of cohort averages.
The session bank composes with the cohorts: a request whose prefix is banked restores it at cohort admission, prefills only its uncovered suffix, and commits its own prompt boundary before the merge — agent fleets with a shared system prompt keep warm time-to-first-token under concurrency. The plain ar_batch lane learned the same trick.
This work is by David Tai (@davidtai): the scheduler contract, the row-owned decode, the cohort serving, the numerics profiles, and the docs. The width-3 bucket, session-bank composite, and live QA came out of the joint hardening passes on top.
/v1/embeddings, /v1/rerank)Contributed by @Cyb3rb1ade (PR #212). The daemon can now serve embedding
and reranker models beside chat, so a retrieval-backed setup doesn't need a
second inference server. OpenAI-shape embeddings (including the
dimensions Matryoshka truncation), Cohere/Jina-shape rerank, opt-in
per-model flags, lazy loading, an LRU resident cap, and idle release under
memory pressure. /v1/models stays chat-only by default so model pickers
never offer an embedder as a chat target; retrieval-only ids answer chat
requests with a clear 400. Checkpoints that ship their own Python code are
refused unless you explicitly pass --retrieval-trust-remote-code.
By David Tai (@davidtai). The LFM2 family serves natively with a bit-exact ShortConv decode fast-path and a verified think/tool grammar (parser stamp, native tool prompt, pythonic streaming dialect). IQuest-Coder checkpoints serve target-only AR through the same registry honesty: recognized, served without MTP claims, refused cleanly when the quantization can't execute.
The speculative lane's cold prefill fed the whole prompt through the model in one window while plain decoding splits it into body plus a final single-token step. The two shapes round differently in the last bit, so the speculative lane started from a cache one ulp apart from the plain lane's — enough to flip greedy argmax at a near-tie and break the "temperature 0 matches plain decoding" contract. Every cold-prefill path now partitions the prompt identically. The Optimized Speed V2 artifact, which surfaced the flip, passes its greedy exactness gate at every depth again.
delta.content (#249).mtplx serve --no-auth actually parses (#235 follow-through) — 2.5.4
promised it, the public CLI rejected it.--reasoning-parser is authoritative; the backend codec no longer
silently overrides an operator-typed parser.dimensions honored on /v1/embeddings; out-of-range values are a
clear 400.mtplx serve from
a clean wheel install (streamed think and content, 64-70 tok/s) and the
macOS app driven end-to-end (chat round trip, 52.5 tok/s reported by
the app, clean stop and quit).