Conversation
|
The following comment was made by an LLM, it may be inaccurate: Related PR Found (Not Duplicate)PR #48432: fix(session-ui): grow markdown live tail in place This is a related but separate PR, not a duplicate. According to the description:
No duplicate PRs found for PR #48431 itself. |
Why this mattersPer-delta TUI store writes on long streams freeze the UI (#36043). Coalescing before apply is the leaf. EvidenceTip
Confirms scope. Happy to help land as-is. Ask (design, light) — prospective
|
TUI-only in symptom. The web path already collapses same-tick bursts in server-sdk.tsx (consecutive same-part deltas merge pre-store), and Solid's fine-grained updates are cheaper than opentui's whole-part re-render — so the identical per-event writes in server-session.ts / event-reducer.ts don't freeze there. Headless surfaces need write-elimination, not timers. No blanket change planned; web gets a timer only if its timeline perf harness flags it.
Per-surface timers — flush cadence is renderer-specific (opentui ~30fps vs browser vs headless-none), and sharing one couples three release cadences. What's shareable is the pure key/concat logic (now in three places: the buffer, currentDeltaKey/Fragment); I'd extract that to @opencode-ai/ui when a second consumer needs it. Until then, single-use-helper rule says keep the buffer TUI-local. |
Issue for this PR
Closes #36043 — jointly with the markdown-live-relex PR. Each applies
independently (different layer, no shared code, merge in either order);
only together do they remove O(n²) from both client-side stages of the
stream path and fully close the freeze. Supersedes #41472, which was
closed unmerged — this reworks that approach for the current
sync.tsxwiring (32 ms timer instead of per-frame, plus dropping deltas superseded
by authoritative events).
Type of change
What does this PR do?
Every
message.part.deltawas applied to the TUI store immediately,re-rendering the whole growing part per token — O(n²) over the stream,
which freezes the TUI on fast reasoning streams. Deltas now accumulate per
part in a small buffer (
delta-buffer.ts) and flush to the store on a32 ms timer, capping renders around 30fps regardless of token rate.
Authoritative events (
part.updated/part.removed/message.removed)discard buffered deltas for the part they replace, and the buffer drains on
cleanup so
*.endedhandlers still see the final text. Themarkdown-live-relex PR covers the other stage: growing the open markdown
tail in place instead of re-lexing per delta.
How did you verify your code works?
From
packages/tui:bun test src/context/delta-buffer.test.tsNew
delta-buffer.test.ts(7 tests: same-part coalescing, part/kindisolation, immediate drain, stale-flush no-op, single schedule across 100
pushes, drop by part and by message) — all passing. Also streamed a
reasoning-heavy session in the live TUI: no freeze, trailing text intact
once the stream ends.
Screenshots / recordings
N/A — no visual change, streaming-perf fix.
Checklist
Tracking: #48430