Skip to content

Effort picker no longer jumps to a level when you type its first letter #31371

Open

Description

@santos-404

What happened

I used to set effort from the keyboard by pressing Cmd+Shift+E, typing l, and pressing Enter. Typing l moved to Low.

Since the combined model and effort picker, typing a letter in the effort column does nothing. The only way to reach a level from the keyboard is with the arrow keys.

Diagnosis

No app code for this was deleted. The behavior came from the UI library, and #28057 stopped using that library component for the effort levels.

Before #28057: the levels were Base UI MenuRadioItems in a Menu (TraitsPicker.tsx at 94a53a2). Base UI's Menu has built-in typeahead (useTypeahead in MenuRoot, @base-ui/react 1.9.0): typing a letter highlights the next item whose label starts with it.

Since #28057: the levels are plain <button role="radio"> rows in a role="radiogroup" inside the model picker's popup (ColumnRow). The column's only key handler is moveBetweenRows, which handles ArrowUp and ArrowDown. No other code handles letter keys, so the typeahead was dropped when the component changed.

Nothing else blocks it. Cmd+Shift+E already focuses the current level in this column (focusEffort in ProviderModelPicker.tsx), so letter keys reach the column. They just have no handler. #28057's description covers arrow keys and Left/Right between the search and the levels, but doesn't mention typing a letter. That suggests the loss wasn't intended.

Possible fix: handle printable keys next to the arrow keys in moveBetweenRows. Focus the next enabled [data-effort-row] whose level label starts with the typed letter, wrapping around. Pressing a letter again should cycle through levels that share it, like Codex's Minimal / Medium / Max. Match on the level label, not the row's whole textContent, because some rows also show "Default". A browser test in ComposerModelEffort.browser.test.tsx can type l and expect focus on Low.

Steps to reproduce

  1. In the desktop app, open a thread whose model has effort levels (e.g. Claude or Codex).
  2. Press Cmd+Shift+E. The picker opens with focus on the current effort level.
  3. Type l.

Expected: focus moves to Low, as it did before #28057. Enter then applies it.
Actual: nothing happens. Only ArrowUp/ArrowDown move between levels.

Version

0.1.7-nightly.20261103.4119 (desktop app, local server; commit cefb544)

Environment

macOS 27.2 (darwin arm64), Node v24.22.1

Evidence

# Before #28057: TraitsPicker.tsx @ 94a53a2 (Base UI Menu, typeahead built in)
<MenuRadioGroup value={selectedValue} onValueChange={...}>
  <MenuRadioItem key={option.id} value={option.id} hideIndicator closeOnClick ...>

# @base-ui/react 1.9.0, menu/root/MenuRoot: typeahead is part of every Menu
const typeahead = useTypeahead(floatingRootContext, {
  enabled: !disabled && !virtualFocus,
  listRef: store.context.itemLabels, ...

# Now: ComposerModelEffort.tsx @ cefb544, the column's only key handler
function moveBetweenRows(event: KeyboardEvent<HTMLElement>) {
  if (event.key !== "ArrowDown" && event.key !== "ArrowUp") return;
  ...

Related issues

Regression from #28057. Not a duplicate of #29219 (picker stays open over Settings). Enter no longer closing the picker (#28076) is intended, so it is being raised separately in Ideas.

Fix applied or workaround

None applied. Workaround: use ArrowUp/ArrowDown to reach the level.

Filed by

Claude Code (Claude Opus 5.5, claude-opus-5-5) via T3 Code triage

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions