anomalyco / anomalyco/opencode

perf(tui): make session switching independent of transcript length

Open
#39,380 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

2.0
Dominant language
TypeScript
Stars
209k
Forks
27.5k
PR merge metrics
PR metrics pending

Description

Problem

Switching between pinned sessions with Ctrl-1/2/3 has a noticeable pause, especially once the sessions have long transcripts. That undermines the quick-switch flow: the shortcut changes the route immediately, but the destination is not immediately usable.

This is a performance follow-up to #36193, not another session-navigation proposal.

What the V2 TUI does today

Checked against origin/v2 at 27e7b0558a:

  • session.quick_switch.N resolves the pinned slot and immediately navigates to the destination session (packages/tui/src/context/local.tsx).
  • On every session ID change, createSessionRows synchronously reduces the destination's cached transcript into render rows, then reconciles those rows (packages/tui/src/routes/session/rows.ts).
  • Session hydration requests the newest 200 messages in one page and keeps them in the shared data store (packages/tui/src/context/data.tsx). A message can expand into many rendered rows because assistant content/tool parts are embedded in it.
  • The session view mounts a SessionRowView for every reduced row in the loaded transcript (packages/tui/src/routes/session/index.tsx). There is no viewport window or incremental transcript mounting on the switch path.
  • The message API itself already supports bounded, cursor-based pagination (packages/server/src/handlers/message.ts and packages/core/src/session.ts), so the missing piece is mainly TUI-side loading/rendering policy rather than a new storage primitive.

This explains why repeatedly switching among already-known sessions can still lag: route lookup is cheap, but transcript reduction/reconciliation/layout work scales with the loaded transcript and its parts.

Desired behavior

Quick-switch latency should be effectively independent of total session length. Switching to an already-open/pinned session should paint the destination chrome and newest visible transcript promptly, while older history loads or mounts only when needed.

Scope

  • Measure the switch path separately: route navigation, transcript fetch/cache lookup, row reduction/reconciliation, and terminal layout/render.
  • Bound work performed before the first destination frame (for example, a recent/visible window rather than all 200 loaded messages and all nested parts).
  • Use the existing cursor pagination to load older history when the user scrolls upward, or otherwise virtualize/window mounted transcript rows.
  • Preserve live updates, sticky-bottom behavior, message navigation, revert boundaries, and full transcript export.
  • Add a representative long-session performance regression check or timing fixture so this does not drift back.

Acceptance criteria

  • Back-to-back Ctrl-1/2/3 switches among long pinned sessions no longer have transcript-length-dependent pauses.
  • The destination's header/composer and newest visible messages appear before older history is fetched or mounted.
  • Scrolling upward can still reach the complete transcript without losing ordering or live event updates.
  • The issue includes before/after timings from a repeatable long-session fixture.

Source discussion: https://slack.com/archives/C0BFMFJ5FJS/p1785255726318509

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by measuring the switch path through packages/tui/src/context/local.tsx, packages/tui/src/routes/session/rows.ts, packages/tui/src/context/data.tsx, and packages/tui/src/routes/session/index.tsx. Read the existing pagination in packages/server/src/handlers/message.ts and packages/core/src/session.ts, then establish a repeatable long-session timing fixture. Done means quick switching shows the destination promptly, older history remains reachable, live updates and navigation are preserved, and before/after timings are recorded.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
cli, performance
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.