MTPLX 2.4.1
The smooth-streaming release: the chat window stops stuttering, and the
text inside it starts looking like it was meant to be read.
Streaming that doesn't freeze, bounce, or vomit
If long answers ever made the app freeze for a beat and then dump a wall
of text — or made the streaming bubble visibly bounce while it grew —
this release is for you. None of it was the engine (decode was flat the
whole time); all of it was the app's render path, and each cause is now
fixed rather than papered over:
- Old finalized lines fold into multi-line segments as they scroll past,
so a long answer no longer accumulates hundreds of live text views.
The measured failure mode — UI updates sinking from ~10 to ~6 per
second with 250–800 ms stalls on a perfectly healthy engine — is gone.
- The bottom-pin scroll correction now runs in the same display cycle as
the layout pass that grew the content. The ±34 px bounce some of you
could see six times a second can no longer be presented on screen.
- A per-display-cycle window-sizing walk that put a flat ~50 ms floor
under every update has been switched off (
MTPLX_APP_SIZING_TUNER=0
restores the old behavior if you ever need it).
- New text reveals with typewriter pacing: a few characters per frame at
steady state, geometric catch-up after a stall, and a hard drain bound
so it can never fall behind (
MTPLX_STREAM_TYPEWRITER=0 restores
reveal-everything-at-once).
- The live tok/s chip now reports a sliding ~5-second window instead of
a cumulative average that read high once a long answer slowed down.
Markdown grew up
- Code blocks get real syntax coloring — twelve languages plus a
generic fallback — from a freeze-time lexer that colors each line
exactly once, when it stops changing. Streaming cost is O(new text),
never O(document).
- A code block that is still streaming now renders as a live code card
with colored lines, and flips once to its exact settled form when the
fence closes.
- Pipe tables render as actual tables.
- Math renders as actual notation:
x^2 becomes x², matrices stack as
real grids between tall delimiters, fractions stack numerator over
denominator, and inline expressions like $(0,0,0)$ convert instead
of leaking literal dollar signs. Currency stays text.
- Performance mode is now a true kill switch: enabling it turns off
markdown, cards, and coloring through both the streaming and settled
paths, for people who want maximum-throughput plain text.
Fixes
- 2.4.0 short-turn regression: the compiled-verify path could
reserve KV budget above the configured ceiling, which taxed short
requests with setup work they never used. The reserve is now clamped
to the env ceiling. If short turns felt slower on 2.4.0 than 2.3.0,
this was why.
- Warming prefills now yield to real traffic within one small chunk, so
a background warm-up can no longer delay the request you just sent.
- A derivative model artifact whose folder name extends a first-party
name (say, a local fine-tune ending in
-Speed-something) is now
served under its own id instead of the flagship's. The health payload,
the OpenAI model field, and the app's model chip all tell the truth
about what is actually loaded.
For the debugging-inclined
All off by default, all opt-in via env:
MTPLX_REQUEST_CAPTURE_DIR=<dir> persists every request's exact
reproduction envelope (post-encoding token ids, sampler, seed, mode,
session identity) at dispatch time, so a turn that hangs or dies still
leaves everything needed to replay it bit-exactly. This is the third
layer of the #196/#197 work.
MTPLX_UI_PERF=1 (with MTPLX_UI_PERF_HUD=1 for an on-screen HUD)
turns on the frontend stream-performance probe: main-thread stall
census, per-flush ledger, and a per-turn JSONL trace joinable to
engine stats by request id.
--adaptive-policy cost adds a cost-model speculative-depth policy,
and MTPLX_GDN_BLOCKED_PREFILL=1 enables an experimental
blocked-sequential GDN prefill route. Both are experiments; defaults
are unchanged.
Upgrading
- App: Sparkle will offer 2.4.1 (build 24100), or grab the DMG.
- CLI:
pip install -U mtplx or brew upgrade mtplx.