feat: replace text input with model picker for Fast Model in /settings (#3120)

The Fast Model setting in the settings dialog previously used a plain text
input, making it hard for users to discover available models. This replaces
it with the same model picker dialog used by `/model --fast`, adds a `▸`
visual indicator for sub-dialog settings, and supports right arrow to open
and left arrow to return.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Shaojin Wen 2026-04-11 10:38:02 +08:00 committed by GitHub
parent fb91acdf25
commit a7771bbb93
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 63 additions and 29 deletions

View file

@ -2054,6 +2054,7 @@ export const AppContainer = (props: AppContainerProps) => {
exitEditorDialog,
closeSettingsDialog,
closeModelDialog,
openModelDialog,
openArenaDialog,
closeArenaDialog,
handleArenaModelsSelected,
@ -2112,6 +2113,7 @@ export const AppContainer = (props: AppContainerProps) => {
exitEditorDialog,
closeSettingsDialog,
closeModelDialog,
openModelDialog,
openArenaDialog,
closeArenaDialog,
handleArenaModelsSelected,

View file

@ -202,6 +202,14 @@ export const DialogManager = ({
</Box>
);
}
if (uiState.isModelDialogOpen) {
return (
<ModelDialog
onClose={uiActions.closeModelDialog}
isFastModelMode={uiState.isFastModelMode}
/>
);
}
if (uiState.isSettingsDialogOpen) {
return (
<Box flexDirection="column">
@ -216,6 +224,10 @@ export const DialogManager = ({
uiActions.openEditorDialog();
return;
}
if (settingName === 'fastModel') {
uiActions.openModelDialog({ fastModelMode: true });
return;
}
uiActions.closeSettingsDialog();
}}
onRestartRequest={() => process.exit(0)}
@ -240,14 +252,6 @@ export const DialogManager = ({
</Box>
);
}
if (uiState.isModelDialogOpen) {
return (
<ModelDialog
onClose={uiActions.closeModelDialog}
isFastModelMode={uiState.isFastModelMode}
/>
);
}
if (uiState.activeArenaDialog === 'start') {
return (
<ArenaStartDialog

View file

@ -266,7 +266,7 @@ export function ModelDialog({
useKeypress(
(key) => {
if (key.name === 'escape') {
if (key.name === 'escape' || (key.name === 'left' && isFastModelMode)) {
onClose();
}
},

View file

@ -567,6 +567,12 @@ export function SettingsDialog({
}
return;
}
if (currentItem?.value === 'fastModel') {
if (name === 'return') {
onSelect('fastModel', selectedScope);
}
return;
}
if (
currentItem?.type === 'number' ||
currentItem?.type === 'string'
@ -575,6 +581,16 @@ export function SettingsDialog({
} else {
currentItem?.toggle();
}
} else if (name === 'right') {
// Right arrow opens sub-dialog settings (like a sub-menu)
const currentItem = items[activeSettingIndex];
if (
currentItem?.value === 'ui.theme' ||
currentItem?.value === 'general.preferredEditor' ||
currentItem?.value === 'fastModel'
) {
onSelect(currentItem.value, selectedScope);
}
} else if (/^[0-9]$/.test(key.sequence || '') && !editingKey) {
const currentItem = items[activeSettingIndex];
if (currentItem?.type === 'number') {
@ -786,6 +802,12 @@ export function SettingsDialog({
displayValue = editBuffer;
}
} else if (item.type === 'number' || item.type === 'string') {
// Settings that open a sub-dialog on Enter
const isSubDialogSetting =
item.value === 'ui.theme' ||
item.value === 'general.preferredEditor' ||
item.value === 'fastModel';
// For numbers/strings, get the actual current value from pending settings
const path = item.value.split('.');
const currentValue = getNestedValue(pendingSettings, path);
@ -813,6 +835,11 @@ export function SettingsDialog({
if (isDifferentFromDefault || isModified) {
displayValue += '*';
}
// Append ▸ for sub-dialog settings to hint Enter opens a picker
if (isSubDialogSetting) {
displayValue = displayValue ? displayValue + ' ▸' : '▸';
}
} else {
// For booleans and other types, use existing logic
displayValue = getDisplayValue(

View file

@ -9,10 +9,10 @@ exports[`SettingsDialog > Snapshot Tests > should render default state correctly
│ ● Tool Approval Mode Default │
│ Language: UI Auto (detect from system) │
│ Language: Model auto │
│ Theme Qwen Dark │
│ Theme Qwen Dark
│ Vim Mode false │
│ Interactive Shell (PTY) true │
│ Preferred Editor
│ Preferred Editor
│ Auto-connect to IDE false │
│ ▼ │
│ │
@ -30,10 +30,10 @@ exports[`SettingsDialog > Snapshot Tests > should render focused on scope select
│ ● Tool Approval Mode Default │
│ Language: UI Auto (detect from system) │
│ Language: Model auto │
│ Theme Qwen Dark │
│ Theme Qwen Dark
│ Vim Mode false │
│ Interactive Shell (PTY) true │
│ Preferred Editor
│ Preferred Editor
│ Auto-connect to IDE false │
│ ▼ │
│ │
@ -51,10 +51,10 @@ exports[`SettingsDialog > Snapshot Tests > should render with accessibility sett
│ ● Tool Approval Mode Default │
│ Language: UI Auto (detect from system) │
│ Language: Model auto │
│ Theme Qwen Dark │
│ Theme Qwen Dark
│ Vim Mode true* │
│ Interactive Shell (PTY) true │
│ Preferred Editor
│ Preferred Editor
│ Auto-connect to IDE false │
│ ▼ │
│ │
@ -72,10 +72,10 @@ exports[`SettingsDialog > Snapshot Tests > should render with all boolean settin
│ ● Tool Approval Mode Default │
│ Language: UI Auto (detect from system) │
│ Language: Model auto │
│ Theme Qwen Dark │
│ Theme Qwen Dark
│ Vim Mode false* │
│ Interactive Shell (PTY) true │
│ Preferred Editor
│ Preferred Editor
│ Auto-connect to IDE false* │
│ ▼ │
│ │
@ -93,10 +93,10 @@ exports[`SettingsDialog > Snapshot Tests > should render with different scope se
│ ● Tool Approval Mode Default │
│ Language: UI Auto (detect from system) │
│ Language: Model auto │
│ Theme Qwen Dark │
│ Theme Qwen Dark
│ Vim Mode (Modified in System) false │
│ Interactive Shell (PTY) true │
│ Preferred Editor
│ Preferred Editor
│ Auto-connect to IDE false │
│ ▼ │
│ │
@ -114,10 +114,10 @@ exports[`SettingsDialog > Snapshot Tests > should render with different scope se
│ ● Tool Approval Mode Default │
│ Language: UI Auto (detect from system) │
│ Language: Model auto │
│ Theme Qwen Dark │
│ Theme Qwen Dark
│ Vim Mode (Modified in Workspace) false │
│ Interactive Shell (PTY) true │
│ Preferred Editor
│ Preferred Editor
│ Auto-connect to IDE false │
│ ▼ │
│ │
@ -135,10 +135,10 @@ exports[`SettingsDialog > Snapshot Tests > should render with file filtering set
│ ● Tool Approval Mode Default │
│ Language: UI Auto (detect from system) │
│ Language: Model auto │
│ Theme Qwen Dark │
│ Theme Qwen Dark
│ Vim Mode false │
│ Interactive Shell (PTY) true │
│ Preferred Editor
│ Preferred Editor
│ Auto-connect to IDE false │
│ ▼ │
│ │
@ -156,10 +156,10 @@ exports[`SettingsDialog > Snapshot Tests > should render with mixed boolean and
│ ● Tool Approval Mode Default │
│ Language: UI Auto (detect from system) │
│ Language: Model auto │
│ Theme Qwen Dark │
│ Theme Qwen Dark
│ Vim Mode false* │
│ Interactive Shell (PTY) true │
│ Preferred Editor
│ Preferred Editor
│ Auto-connect to IDE false │
│ ▼ │
│ │
@ -177,10 +177,10 @@ exports[`SettingsDialog > Snapshot Tests > should render with tools and security
│ ● Tool Approval Mode Default │
│ Language: UI Auto (detect from system) │
│ Language: Model auto │
│ Theme Qwen Dark │
│ Theme Qwen Dark
│ Vim Mode false │
│ Interactive Shell (PTY) true │
│ Preferred Editor
│ Preferred Editor
│ Auto-connect to IDE false │
│ ▼ │
│ │
@ -198,10 +198,10 @@ exports[`SettingsDialog > Snapshot Tests > should render with various boolean se
│ ● Tool Approval Mode Default │
│ Language: UI Auto (detect from system) │
│ Language: Model auto │
│ Theme Qwen Dark │
│ Theme Qwen Dark
│ Vim Mode true* │
│ Interactive Shell (PTY) true │
│ Preferred Editor
│ Preferred Editor
│ Auto-connect to IDE true* │
│ ▼ │
│ │

View file

@ -61,6 +61,7 @@ export interface UIActions {
exitEditorDialog: () => void;
closeSettingsDialog: () => void;
closeModelDialog: () => void;
openModelDialog: (options?: { fastModelMode?: boolean }) => void;
openArenaDialog: (type: Exclude<ArenaDialogType, null>) => void;
closeArenaDialog: () => void;
handleArenaModelsSelected?: (models: string[]) => void;