Skip to content

sessions: fix PR status icon flicker on session list updates#319219

Draft
roblourens wants to merge 2 commits into
mainfrom
agents/vsckb-implement-when-the-session-list-is-updatin-b4978713
Draft

sessions: fix PR status icon flicker on session list updates#319219
roblourens wants to merge 2 commits into
mainfrom
agents/vsckb-implement-when-the-session-list-is-updatin-b4978713

Conversation

@roblourens
Copy link
Copy Markdown
Member

@roblourens roblourens commented May 31, 2026

Fixes #319221

Problem

When the session list in the Agents window updates, the GitHub PR status icons flicker. The list renderer cross-fades icons whenever the icon's CSS selector changes, and on each update the PR icon was being transiently reset to the read/unread fallback dot, producing a visible flicker.

A follow-up issue was also found: the PR icon could disappear entirely (downgrade to the fallback dot) when clicking away from an agent host session.

Root cause

Flicker

The gitHubInfo derived in both session providers acquired the ref-counted PR model via reader.store. The observable framework disposes reader.store before each recompute. Because the PR model is ref-counted (ReferenceCollection), releasing the reference dropped the refcount to 0 and disposed the cached model. The freshly re-acquired model starts with pullRequest === undefined, so livePR momentarily read undefined, the icon fell back to the dot, and the renderer cross-faded back and forth. In the copilot-chat provider this recompute fired on every unrelated update() (title/status/time/etc.), because _baseGitHubInfo was reset with a fresh object each time.

Disappearing icon (agent host)

The agent host adapter resolves its PR number asynchronously, so the per-session polling contribution never starts for it (it reads gitHubInfo.pullRequest at session-add time, when it is still undefined). The shared PR model is therefore only kept alive by the session list rows. When a session goes inactive, the active-session refresh stops updating its model, and the list re-splice that updates selection briefly unobserves the row's gitHubInfo derived, releasing the last reference. The model is disposed and re-acquired in an unpopulated state, so livePR reads undefined and the icon downgrades to the fallback it disappeared when clicking away. Unlike copilot-chat (which has a static fallback icon from session metadata), the agent host adapter had no fallback.dot

Fix

  • Use reader.delayedStore (disposed after recompute) instead of reader.store to hold the PR model reference, so the cached, ref-counted model survives recomputations (the documented delayedStore + ref-counting pattern).
  • Add equalsFn: gitHubInfoEqual to the gitHubInfo derived (both providers) and to _baseGitHubInfo, so structurally-unchanged GitHub info no longer recomputes/re-notifies on unrelated list updates.
  • Latch the last-known PR icon in the agent host adapter, keyed by the full PR identity (owner/repo/number). When the live model is transiently unpopulated, the previous icon is reused instead of falling back to the dot. The latch updates promptly whenever the live model reports a new state, and never reuses an icon across a different PR.
  • Widen derivedOpts's computeFn reader type to IReaderWithStore so callers can use store/delayedStore, matching derived (which already exposes them).

Files

  • src/vs/sessions/contrib/providers/copilotChatSessions/browser/copilotChatSessionsProvider.ts
  • src/vs/sessions/contrib/providers/agentHost/browser/baseAgentHostSessionsProvider.ts
  • src/vs/base/common/observableInternal/observables/derived.ts

Validation

  • npm run compile-check-ts-native passes clean
  • ESLint passes on the changed files
  • Pre-commit hygiene hook passes
  • The latch lifecycle (hold icon when the live model is transiently unpopulated, refresh on new state, never reuse across a different PR) was validated against the real compiled observable module.

Note: the Electron unit suite could not be run in this worktree (the Electron test runner fails at startup with an unrelated app.setPath error). Manual verification on a running dev build is recommended.

(Written by Copilot)

The GitHub PR status icons in the Agents window session list flickered
whenever the list updated. The renderer cross-fades icons when the icon
selector changes, and the icon was being transiently reset to the
read/unread fallback dot on every recompute.

Root cause: the `gitHubInfo` derived in both session providers acquired
the ref-counted PR model via `reader.store`, which the observable
framework disposes *before* each recompute. Releasing the reference
dropped the refcount to 0, disposing the cached model; the freshly
re-acquired model starts with `pullRequest === undefined`, so `livePR`
momentarily read `undefined` and the icon fell back to the dot,
triggering a cross-fade. In the copilot-chat provider this recompute
fired on every unrelated `update()` because `_baseGitHubInfo` was reset
with a fresh object each time.

Fix:
- Acquire the PR model reference via `reader.delayedStore` (disposed
  *after* recompute) so the cached, ref-counted model survives the
  recompute and `livePR` never blips to `undefined`.
- Add `equalsFn: gitHubInfoEqual` to the `gitHubInfo` derived (both
  providers) and to `_baseGitHubInfo` so structurally-unchanged GitHub
  info no longer recomputes/re-notifies on unrelated list updates.
- Widen `derivedOpts`'s computeFn reader type to `IReaderWithStore` so
  callers can use `store`/`delayedStore`, matching `derived`.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 31, 2026 21:04
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes GitHub PR status icon flicker in the Agents window session list by preventing transient fallback-icon states during observable recomputation, and by reducing unnecessary recomputation/notifications when GitHub info hasn’t structurally changed.

Changes:

  • Keep ref-counted PR model references alive across derived recomputations by using reader.delayedStore (avoids brief pullRequest === undefined states that trigger cross-fade flicker).
  • Add structural equality (equalsFn: gitHubInfoEqual) to GitHub info observables/deriveds to avoid churn on unrelated session updates.
  • Update derivedOpts’s computeFn reader type to IReaderWithStore so callers can safely use store/delayedStore.
Show a summary per file
File Description
src/vs/sessions/contrib/providers/copilotChatSessions/browser/copilotChatSessionsProvider.ts Uses delayedStore for PR model refs and adds gitHubInfoEqual-based equality to prevent flicker and recompute churn.
src/vs/sessions/contrib/providers/agentHost/browser/baseAgentHostSessionsProvider.ts Applies the same delayedStore ref-holding pattern and gitHubInfoEqual equality for PR icon stability.
src/vs/base/common/observableInternal/observables/derived.ts Types derivedOpts compute reader as IReaderWithStore to enable store/delayedStore usage.

Copilot's findings

  • Files reviewed: 3/3 changed files
  • Comments generated: 0

The agent host session adapter resolves its PR number asynchronously, so
per-session polling never starts (it reads gitHubInfo.pullRequest at
session-add time, when it is still undefined). The shared, ref-counted PR
model is therefore only kept alive by the session list rows. When a session
goes inactive, the active-session refresh stops updating its model, and the
list re-splice that updates selection briefly unobserves the row's gitHubInfo
derived, releasing the last reference. The model is disposed and re-acquired
in an unpopulated state, so livePR reads undefined and the icon downgraded to
the fallback dot -- it disappeared when clicking away from a session.

Latch the last known icon keyed by the full PR identity (owner/repo/number)
and reuse it whenever livePR is transiently undefined for the same PR. This
also prevents the original flicker on list updates, while still updating
promptly when the live model reports a new state.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

Fllickering icons in sessions list

2 participants