MTPLX 2.6.0 — concurrency

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.

Concurrent speculative 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.

Embeddings and reranking (/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.

LiquidAI LFM2 / LFM2.5

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.

Temperature-0 output is token-identical again

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.

Fixes

QA (this release)

Credits