← Back to PRs

#16020: perf(ui): virtualize chat message list for large conversations

by fagemx open 2026-02-14 05:28 View on GitHub →
app: web-ui size: XS
## Summary - Replace `repeat()` with `virtualize()` from `@lit-labs/virtualizer` in chat thread rendering - Only visible messages (+ small buffer) are rendered in the DOM, keeping memory and render time constant regardless of history size - Remove the previous 200-message render limit — virtualization handles unlimited messages efficiently - Net -11 lines of code ## Why The Control UI renders all messages as DOM nodes, which causes the browser tab to freeze or crash with long chat histories (~6 MB+ transcripts). Virtualization solves this at the rendering layer by only mounting elements in or near the viewport. Prior art: PR #5743 attempted the same approach but went stale. ## Test plan - [x] Build passes (`pnpm build`) - [x] Lint clean - [x] Tested with large conversation histories — smooth scrolling, no freezes Ref #15992 lobster-biscuit > 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- greptile_comment --> <h3>Greptile Summary</h3> Replaces Lit's `repeat()` directive with `virtualize()` from `@lit-labs/virtualizer` in the chat thread, so only visible messages (plus a small buffer) are rendered in the DOM. This eliminates the previous 200-message hard cap and keeps rendering performance constant regardless of conversation length. - **New dependency**: `@lit-labs/virtualizer@^2.1.1` added to `ui/package.json`; compatible with the existing `lit@^3.3.2`. - **Render limit removed**: The `CHAT_HISTORY_RENDER_LIMIT = 200` constant and the "showing last N messages" system notice are deleted; virtualization handles unlimited messages efficiently. - **Type fix**: A follow-up commit correctly changes the `renderItem` fallback from `nothing` to `` html`​` `` since `virtualize()` expects a `TemplateResult`, not Lit's `nothing` symbol. - **Scroll concern**: `virtualize({scroller: true})` takes over scroll management of `.chat-thread`, while `app-scroll.ts` (`scheduleChatScroll`) independently manipulates `scrollTop`/`scrollHeight` on the same element. With variable-height messages (markdown, images, tool cards), the virtualizer's estimated scroll height shifts as items are measured, which could cause the auto-scroll-to-bottom behavior to be unreliable. Worth validating with conversations containing very different message heights. <h3>Confidence Score: 3/5</h3> - Likely safe for most cases, but the dual scroll management between the virtualizer and existing auto-scroll logic needs targeted manual testing with variable-height messages. - The core change (repeat → virtualize) is a well-motivated performance improvement with a clean implementation (-11 lines net). The type compatibility fix is correct. However, the interaction between the virtualizer's internal scroll management and the existing app-scroll.ts scroll-to-bottom logic has not been verified to work reliably with variable-height chat items, and could cause scroll jank or missed auto-scroll in edge cases. - Pay close attention to `ui/src/ui/views/chat.ts` — specifically the interaction between `virtualize({scroller: true})` and the scroll management in `ui/src/ui/app-scroll.ts`. <sub>Last reviewed commit: 86328cc</sub> <!-- greptile_other_comments_section --> <!-- /greptile_comment -->

Most Similar PRs