Skip to content

feat: add directional model and reasoning shortcuts - #1247

Open
smsunarto wants to merge 4 commits into
get-bb:mainfrom
smsunarto:feat/model-picker-directional-shortcuts
Open

feat: add directional model and reasoning shortcuts#1247
smsunarto wants to merge 4 commits into
get-bb:mainfrom
smsunarto:feat/model-picker-directional-shortcuts

Conversation

@smsunarto

Copy link
Copy Markdown
Contributor

Summary

Cycling was the only way to move through models and reasoning efforts, so reaching the previous entry meant wrapping all the way around. This adds explicit directional commands, and a provider cycle that works on every platform.

Area Command Default
Composer Cycle model Alt+M
Composer Cycle provider Alt+P
Composer Cycle reasoning effort Alt+T
Composer Previous / next model Mod+← / Mod+→
Composer Decrease / increase reasoning Mod+↓ / Mod+↑

The two existing chords keep their keys and are relabelled to say what they do: "Next model" becomes "Cycle model", "Next reasoning level" becomes "Cycle reasoning effort".

Models wrap at either end; reasoning effort clamps. The cycle chords also work while the picker popover is open, since the popover is itself modal and would otherwise block them.

macOS composes Option+<letter> into another character, so the Alt chords match on the physical key. For the same reason an in-scope cycle chord always claims the key, even with nowhere to rotate — otherwise the composed character lands in the prompt.

Commits

  • feat(app): add directional model and reasoning shortcuts — the five new commands and their bindings
  • fix: cycle providers with a cross-platform chord — replaces the macOS-only Command+Right Option with Alt+P and drops the right-Option handling it needed
  • refactor: dedupe model picker keybinding scopes — one named open-picker scope, one ownership helper, one cycle-direction policy
  • test(server): compact app keybinding chord assertions

Test plan

  • turbo run typecheck test lint over @bb/app, @bb/server, @bb/domain: 505 test files pass, 0 lint errors
  • Each commit verified green on its own

🤖 Generated with Claude Code

smsunarto and others added 4 commits August 9, 2026 22:15
Cycling was the only way to move through models and reasoning efforts, so
reaching the previous entry meant wrapping all the way around. Add five
commands with explicit direction:

  modelPicker.previousModel      Mod+ArrowLeft
  modelPicker.nextModel          Mod+ArrowRight
  modelPicker.decreaseReasoning  Mod+ArrowDown
  modelPicker.increaseReasoning  Mod+ArrowUp
  modelPicker.cycleProvider      Command+Right Option (macOS)

Distinguishing the provider chord needs the physical side of the Option
key, which `key` reports as "Alt" for both; `normalizeAppShortcutInputKey`
now falls back to `code` for AltRight.

The two existing commands keep their chords and are relabelled to say what
they do: "Next model" becomes "Cycle model", "Next reasoning level" becomes
"Cycle reasoning effort". The repeated composer activation context is
extracted to `composerWithoutModal`.

Bundled SDK types and templates are regenerated for the new command ids.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The provider chord was Command+Right Option, which only macOS can produce,
so Windows and Linux had no way to reach it. Move it to Alt+P, completing
the Alt+M / Alt+P / Alt+T cycle family, and drop the right-Option handling
that existed solely for the old chord — the shortcut recorder rejects
modifier-only keys, so no user could bind it anyway.

An Option chord that reaches the browser inserts a composed character, so
the handler now claims the chord whenever it is in scope and no-ops when
there is nowhere to rotate. It also owns the chord while the popover is
open, matching the model and reasoning cycles.

Group the cycle commands ahead of the directional ones in the picker, the
default bindings, and Settings → Keyboard, and move the directional chords
from prose into the shortcut table.
Three copies of the open-picker context literal, three copies of the
cycle-chord ownership expression, and a hand-rolled reverse of
`nextCycleValue` had accumulated across the model picker keybindings.

Name the open-picker scope once as `pickerOpenOnly`, add `ownsCycleChord`
beside the existing `ownsClosedNavigationChord`, and derive
`previousCycleValue` from `nextCycleValue` over the reversed list so both
directions share one policy for wrapping and absent values.

No behavior change.
The expected-binding array spelled out all six shortcut fields six times
and repeated both `when` shapes verbatim, so the Alt chord table was
around ninety lines of near-identical literals.

Hoist the two scopes, add an `altChord` builder, and fold the navigation
`when` check into the tuple assertion beside it. Every field is still
asserted; only the spelling is shorter. The scopes stay test-local
literals rather than imports so the assertions cannot go circular.
@smsunarto
smsunarto marked this pull request as ready for review August 10, 2026 07:13
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.

1 participant