Skip to content

perf(vscode): open model, mode, and variant selectors instantly - #11774

Merged
marius-kilocode merged 2 commits into
mainfrom
dog-shovel
Jun 29, 2026
Merged

perf(vscode): open model, mode, and variant selectors instantly#11774
marius-kilocode merged 2 commits into
mainfrom
dog-shovel

Conversation

@marius-kilocode

Copy link
Copy Markdown
Collaborator

Problem

Opening the chat model selector had a visible delay before the popup appeared, and the mode and variant pickers also felt sluggish to open. Each selector was slow for a different reason.

Model selector — real main-thread work

The popup rendered the entire model catalog eagerly on open. With the live Kilo Gateway catalog (~630 models) that meant a large synchronous burst of work on click, before the popup could paint:

  • ~6,000 popup DOM elements and ~11,300 transient nodes created in one shot. Each model row is not one node: row wrapper, item, name spans, provider/auto/free/BYOK/data badges, tooltips, and a star button. Multiplied across hundreds of rows, that is a large tree mounted synchronously.
  • Element creation, style recalculation, and layout for that whole tree blocked the main thread in a single long task.
  • A smaller contributor: activeModel() was a plain function, so every consumer re-scanned the model list with find() on each reactive read instead of computing once.

Mode and variant selectors — artificial latency, not CPU

These have only a handful of options and were always cheap to build (~4–5 ms to mount). Their perceived lag came from two non-JS sources:

  1. The shared kilo-ui popover ran a ~150 ms CSS enter animation, so even though the DOM was ready in a few ms you watched it animate in.
  2. Focus was scheduled in a requestAnimationFrame after open, adding a frame of latency and a second focus pass.

Changes

  • Virtualize the model catalog (Virtua). Only the visible window mounts; group headers, the clear row, and model rows render through one recycled renderer that preserves keyboard nav, search, favorites, group collapse, and the active-descendant a11y contract.
  • Memoize activeModel so the lookup runs once per change instead of on every reactive read.
  • Anchor scroll restoration to virtual item offsets. Favorite toggles previously anchored to a DOM ref that no longer exists once the row is virtualized out; anchoring now uses getItemOffset so the list does not jump when the anchored row is offscreen. The now-dead per-row ref map was removed.
  • Disable the popover open animation for these selectors and focus the selected option during initial mount (data-autofocus) instead of a deferred frame, so mode and variant open without the animation/focus latency.

Before / after

Measured in the VS Code self-test harness against the live ~630-model catalog (model picker) and the real chat pickers (mode/variant). Model timings are from CPU/trace profiles; mode/variant DOM-mount timings were already in the single-digit-ms range, so the meaningful win there is the removed animation and focus frame.

Metric Before After Change
Model: time to list mounted 308.6 ms 24.2 ms ~92% faster
Model: time to settled (post-paint) 427.1 ms 41.4 ms ~90% faster
Model: popup DOM elements 6,011 247 ~96% fewer
Model: transient nodes created 11,316 707 ~94% fewer
Model: mounted tree treeitems full catalog < 50 (visible window) bounded
Mode: time to list mounted 4.0 ms 4.0 ms unchanged (already fast)
Mode: open animation ~150 ms 0 (disabled) removed
Mode: focus deferred 1 rAF during initial mount 1 frame removed
Variant: time to list mounted 5.0 ms 4.9 ms unchanged (already fast)
Variant: open animation ~150 ms 0 (disabled) removed
Variant: focus deferred 1 rAF during initial mount 1 frame removed

Net: the model selector is fixed by doing far less work (virtualization + memoization); the mode and variant selectors are fixed by removing artificial latency (animation + deferred focus). Post-fix the model picker mounts a bounded window regardless of catalog size, so timings no longer scale with the number of models.

Tests

  • Added a 600-model Storybook fixture and coverage that the rendered tree stays bounded (< 50 items) while a distant model remains reachable via search.
  • Added coverage that the mode and variant pickers focus the selected option as they open, and that a slash-command-opened mode picker returns focus to the prompt on dismiss.
  • Existing model-selector accessibility, favorites, search, collapse, and focus-restoration tests continue to pass.

Virtualize the model catalog so opening the picker mounts only the
visible window instead of the entire model list, and remove artificial
open latency from the mode and variant pickers.

The model selector built every catalog row up front (~6k DOM elements,
~11k transient nodes for a ~630-model catalog), blocking the main thread
on element creation, style recalculation, and layout before first paint.
The active-model lookup also re-scanned the list on every reactive read.
The mode and variant pickers were cheap to build but felt slow because of
the shared popover enter animation and a deferred focus frame.

Render the catalog through a virtualizer, memoize the active-model
lookup, anchor scroll restoration to virtual item offsets so favorite
toggles no longer jump when the anchored row is virtualized out, disable
the popover open animation for these selectors, and focus the selected
option during initial mount instead of a later frame.
@kilo-code-bot

kilo-code-bot Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (9 files)
  • .changeset/open-model-selector-faster.md
  • packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/shared/model-selector-large-catalog-chromium-linux.png
  • packages/kilo-vscode/tests/model-selector-accessibility.spec.ts
  • packages/kilo-vscode/webview-ui/src/components/shared/ModeSwitcher.tsx
  • packages/kilo-vscode/webview-ui/src/components/shared/ModelSelector.tsx
  • packages/kilo-vscode/webview-ui/src/components/shared/PopupSelector.tsx
  • packages/kilo-vscode/webview-ui/src/components/shared/ThinkingSelector.tsx
  • packages/kilo-vscode/webview-ui/src/stories/shared.stories.tsx
  • packages/kilo-vscode/webview-ui/src/styles/model-selector.css

Reviewed by gpt-5.4-20260305 · Input: 92.1K · Output: 15.6K · Cached: 704.3K

Review guidance: REVIEW.md from base branch main

@marius-kilocode
marius-kilocode merged commit 76ad88c into main Jun 29, 2026
23 checks passed
@marius-kilocode
marius-kilocode deleted the dog-shovel branch June 29, 2026 08:50
t7tran pushed a commit to t7tran/kilocode that referenced this pull request Aug 14, 2026
perf(vscode): open model, mode, and variant selectors instantly
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