Skip to content

[Task] Optimize long session timeline rendering to prevent streaming flicker #397

@Astro-Han

Description

@Astro-Han

Goal

Long-running session conversations should remain visually stable and responsive while a new response is streaming. Sending or streaming a new turn in a long session should not cause visible flicker, scroll jitter, or unnecessary whole-timeline work.

Scope

In scope:

  • Investigate and optimize the session timeline render path for long conversations.
  • Keep DOM work bounded for long-lived sessions, not only initial history loads.
  • Reduce per-turn work so streaming updates affect only the active/current turn where possible.
  • Review the current use of content-visibility: auto / contain-intrinsic-size and avoid height-estimation jitter near the active/bottom turns.
  • Preserve existing scroll behavior: stay pinned when the user is near the bottom, but do not pull the user down when they are reading older history.

Out of scope:

  • Redesigning the session UI.
  • Changing model/runtime behavior.
  • Rewriting vendored agent runtime code under packages/opencode/ unless investigation proves it is required.

Relevant files or context

Observed code paths:

  • packages/app/src/pages/session.tsx
  • packages/app/src/pages/session/message-timeline.tsx
  • packages/app/src/pages/session/use-session-timeline-data.ts
  • packages/app/src/pages/session/use-session-history-window.ts
  • packages/app/src/pages/session/use-session-timeline-interaction.ts
  • packages/ui/src/components/session-turn.tsx
  • packages/ui/src/components/message-part.tsx
  • packages/ui/src/components/message-part.css
  • packages/ui/src/components/session-turn.css
  • packages/app/src/context/renderer-diagnostics.ts

Current likely causes from inspection:

  • Long-lived sessions can keep accumulating rendered turns after the initial history window, so DOM size grows over time.
  • Each SessionTurn receives the full messages array and derives its assistant messages by scanning/slicing/filtering the full list, causing repeated work as the conversation grows.
  • content-visibility: auto with estimated intrinsic sizes can reduce paint cost, but it does not reduce DOM node count and can contribute to scroll/height jitter when estimates differ from real message heights.
  • Existing diagnostics already track related incidents such as scroll jumps, timeline remounts, visible message clears, layout shift, and jank bursts.

Performance best-practice direction:

  • Prefer a virtualized/windowed message list for large histories, with dynamic height measurement/caching and overscan.
  • Normalize timeline data by IDs so list order changes separately from per-message content updates.
  • During streaming, update only the active/current row and avoid making sibling turns recompute.
  • Treat content-visibility as a supplemental optimization, not a substitute for virtualization.

Verification

  • Add or update targeted tests around the session history/windowing behavior so long-lived sessions remain bounded.
  • Add focused tests for timeline derivation to ensure assistant messages can be resolved without each turn scanning the full message list.
  • Manually verify a long session while streaming a response:
    • no visible flicker near the bottom,
    • no scroll jump to top,
    • jump-to-latest behavior still works,
    • user scroll position is respected when reading older messages.
  • Use existing renderer diagnostics to confirm no new incident.session_scroll_jump_to_top, incident.session_timeline_remount, incident.session_visible_messages_cleared, incident.session_layout_shift, or incident.session_jank_burst appears during the repro path.

Execution mode

Agent should investigate and propose a plan first.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium priorityappApplication behavior and product flowstaskNarrow execution, audit, spike, migration, tracking, or upstream follow-up workuiDesign system and user interface

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions