Skip to content

Conversation

@paulbettner
Copy link

Summary

  • Motivation: Full-backlog reflows during streaming/shimmer caused UI jank in large histories. Render time scaled with total messages instead of visible rows.
  • Approach: Virtualize chat message blocks and add a fast path so work scales with the viewport.

Changes

  • Virtualized rendering:

    • Build per-block caches once in the slow path:
      • blockContents: rendered string per block
      • blockHeights: pre-measured line heights
      • blockPrefix: start line per block (includes leading blank + inter-block blanks)
    • Use sort.Search to find the first visible block and only synthesize visible rows.
    • Cache per-block line splits (blockLineCache) to avoid repeated strings.Split.
  • Incremental indexing:

    • blockIndexByPartID maps part IDs to block indices (foundation for targeted per-part updates).
    • streamingReasoningID ensures shimmer applies only to the last in-flight reasoning block.
  • Header optimization:

    • Cache the header; rebuild only when width changes (lastHeaderWidth, headerDirty).
  • Shimmer gating:

    • Animate only when an assistant/tool is in-flight, re-render only when at bottom and backlog ≤ 2000 lines to avoid pathological repaint loops.
  • Selection overlay correctness:

    • Disable the fast path when selection is active to preserve copy/highlighting fidelity.

Impact

  • Streaming remains smooth on large histories; rendering work scales with the viewport, not the backlog.
  • Lower CPU usage and fewer jank frames during token streaming and shimmer.

Non-goals

  • No changes to message semantics, event ingestion, or UI look-and-feel.
  • No new deps, flags, or config.

Testing

  • Go TUI builds and runs (darwin/arm64 local).
  • Manual checks:
    • Scrolling and streaming stay responsive with large histories.
    • Selection overlay still highlights accurately and copies cleanly.
    • Header stable; only recomputes on width changes.

Future Work (optional)

  • Apply per-part incremental updates on MessagePartUpdated by adjusting only affected blocks and local prefix/height entries.
  • Add a debug toggle to force-disable virtualization for repros.

Files

  • packages/tui/internal/components/chat/messages.go

Notes for reviewers

  • Fast path only engages when caches are warm and no selection overlay is active.
  • Cache invalidation on resize/theme/session transitions is explicit to avoid stale layouts.

…uring streaming\n\n- Introduce block virtualization with binary search on visible region\n- Cache per-block line splits and heights; reuse in fast path\n- Cache header with width tracking to avoid repeated rebuilds\n- Gated shimmer updates and bottom-follow to reduce repaint churn\n- Preserve selection overlay correctness; disable fast path when active\n\nResult: streaming stays smooth on large histories; work scales with the viewport, not the backlog.
@rekram1-node
Copy link
Collaborator

We are rewriting the tui and it will ship this week, it should address all these performance issues

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants