perf(webui): reduce repeated work and bound history rendering - #5703
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Long conversations and tool-heavy responses repeatedly scan prompt DOM nodes, search earlier activity rows, render hidden details, and retain replay data. This change reduces that repeated work and bounds the expensive rendering and caching paths.
Changes
Index prompt elements once per measurement and coalesce measurements into one animation frame. Index tool activity by call ID and turn while preserving legacy and cross-turn matching behavior.
Mount activity details on first expansion and memoize stable timelines so timer ticks do not rerender diffs. Recycle offscreen historical answer/activity contents with measured-height placeholders, retaining prompt anchors and interacted content.
Cache ANSI detection and clean copy text, and avoid splitting plain code into lines when line numbers are disabled. Code blocks retain full-content rendering and highlighting without pagination.
Apply compatible consecutive stream deltas together, cache immutable history projections, and use background update frequency while settings hide the chat. Flush buffered text on return.
Split ThreadShell, consolidate translations by locale, and keep Markdown, syntax highlighting, and math dependencies outside the cold-start import graph. Load mathematical rendering when needed.
Window session search to 24 rows with keyboard navigation, coalesce session update notifications over 250 ms, and reuse unchanged session objects. Limit replay caching to 12 sessions / an estimated 16 MiB, with temporary chats pinned because they have no disk history.
Keep reasoning from explicit length continuations with the stitched Markdown answer in both live streaming and replay. Start a separate buffer for recovery turns so they preserve the interrupted answer and display their own reasoning before their answer.
Measurements
Local isolated benchmarks against
104917aaec8b351edcbbc87a64fa6b71eb6e096b; timings use 3 warmups and the median of 15 runs with one test worker. These measure individual hot paths, not end-to-end frame rate.Fresh paired tests (8 warmups, 41 alternating before/after pairs) measured ANSI copy-handler processing at 0.220 → 0.054 ms for approximately 64 KiB and 1.876 → 0.028 ms for approximately 1 MiB. These exclude operating-system clipboard I/O. Plain-text copying and stream delivery showed no reliable latency gain. Replay buffer initialization runs only when a buffer is needed; its implementation remains the previously verified continuation/recovery fold.
In the production browser run, 356 of 540 display units released their contents after loading 180 turns. Search over 1,000 matching sessions mounted 24 rows. A fresh Chinese-language browser context requested two locale chunks and no Markdown, syntax-highlighting, or KaTeX resources. The entry JS is 412.23 kB (122.27 kB gzip); ThreadShell remains a separate load when displaying chat.
Validation
Current candidate after integrating main: all 1,225 WebUI tests across 78 files passed with coverage; build and lint passed; 65 transcript tests passed. Real isolated gateway/browser checks passed for full 1,200-line code rendering and copying, math, lazy details, history recycling, windowed search, and refresh persistence. Both diff display modes kept edits visible while reasoning folds were expanded or collapsed, with correct replay ordering. CI regression tests now expand deferred details before checking their content order.
Earlier validation, before the pagination removal:
bun run test src/tests --maxWorkers=4 --minWorkers=1: 1,205 tests passed across 78 files.bun run buildandbun run lint: passed; production static import closures checked./modelcommand replayed through the HTTP history endpoint with identical messages after refresh. Owned browser/gateway processes and temporary runtime data were cleaned up.nanobot-gatesimplify, verification, and candidate review passed.Historical prompt anchors, the latest content, interacted details, and unpersisted temporary chats remain retained intentionally. The cache budget estimates payload size rather than the entire browser heap, and session refreshes still use the full-list API.