Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 35 additions & 20 deletions packages/web-shell/client/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,14 @@ const COMPACT_MODE_SETTING_KEY = 'ui.compactMode';
const HIDE_TIPS_SETTING_KEY = 'ui.hideTips';
const HIDDEN_COMPOSER_MODEL_IDS = new Set(['coder-model(qwen-oauth)']);

/** Maps each ModelDialogMode to its i18n title key — single source of truth. */
const MODE_TITLE_KEY: Record<ModelDialogMode, string> = {
main: 'model.select',
fast: 'model.setFast',
voice: 'model.setVoice',
vision: 'model.setVision',
};

function isVisibleComposerModel(model: { id: string }): boolean {
return !HIDDEN_COMPOSER_MODEL_IDS.has(model.id);
}
Expand Down Expand Up @@ -1650,6 +1658,12 @@ export function App({
)?.values.effective;
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
})();
const currentVisionModel = (() => {
const value = workspaceSettings.find(
(setting) => setting.key === 'visionModel',
)?.values.effective;
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
})();
const shellOutputMaxLines = resolveShellOutputMaxLines(workspaceSettings);
const [compactMode, setCompactMode] = useState(false);
const compactModeRef = useRef(compactMode);
Expand Down Expand Up @@ -3315,7 +3329,11 @@ export function App({

const handleVisionModelSelect = useCallback(
(modelId: string) => {
setWorkspaceSetting('workspace', 'visionModel', modelId).catch(
// Model IDs from the picker arrive in ACP format: `modelId(authType)`.
// Core's resolveVisionModelSelection() expects `authType:modelId`.
const match = modelId.match(/^(.+)\(([^()]+)\)$/);
const encoded = match ? `${match[2]}:${match[1]}` : modelId;
setWorkspaceSetting('workspace', 'visionModel', encoded).catch(
(error: unknown) => reportError(error, t('model.setVision')),
);
},
Expand Down Expand Up @@ -3456,34 +3474,31 @@ export function App({
)}
{modelDialogMode && (
<DialogShell
title={
modelDialogMode === 'fast'
? t('model.setFast')
: modelDialogMode === 'voice'
? t('model.setVoice')
: modelDialogMode === 'vision'
? t('model.setVision')
: t('model.select')
}
title={t(MODE_TITLE_KEY[modelDialogMode])}
size="lg"
onClose={() => setModelDialogMode(null)}
>
<ModelDialog
mode={modelDialogMode}
models={modelDialogMode === 'voice' ? voiceModels : undefined}
currentModelId={
modelDialogMode === 'voice' ? currentVoiceModel : undefined
modelDialogMode === 'voice'
? currentVoiceModel

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] The currentModelId ternary has no 'fast' branch. When modelDialogMode === 'fast', it falls through to undefined, and ModelDialog falls back to connection.currentModel (the main chat model) — highlighting the wrong model in the fast picker.

This PR added currentVisionModel (great!) but missed currentFastModel. Consider adding it following the same derivation pattern.

— qwen3.7-max via Qwen Code /review

: modelDialogMode === 'vision'
? currentVisionModel
: undefined
}
onSelect={(modelId) => {
if (modelDialogMode === 'fast') {
handleFastModelSelect(modelId);
} else if (modelDialogMode === 'voice') {
handleVoiceModelSelect(modelId);
} else if (modelDialogMode === 'vision') {
handleVisionModelSelect(modelId);
} else {
handleModelSelect(modelId);
}
const handlers: Record<
ModelDialogMode,
(id: string) => void
> = {
main: handleModelSelect,
fast: handleFastModelSelect,
voice: handleVoiceModelSelect,
vision: handleVisionModelSelect,
};
handlers[modelDialogMode ?? 'main'](modelId);
setModelDialogMode(null);
}}
/>
Expand Down
6 changes: 6 additions & 0 deletions packages/web-shell/client/i18n.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1209,6 +1209,9 @@ const EN: Messages = {
'Frontend-only chat content width. Stored in this browser.',
'settings.option.ui.chatWidth.1000': 'Regular',
'settings.option.ui.chatWidth.wide': 'Ultra wide',
'settings.label.visionModel': 'Vision Model',
'settings.description.visionModel':
'Image-capable model used as the vision bridge. Leave empty to auto-select.',
'welcome.changeModel': '(/model to change)',
'welcome.defaultModel': 'unknown model',
'welcome.modeHint': 'Shift+Tab or /approval-mode',
Expand Down Expand Up @@ -2442,6 +2445,9 @@ const ZH: Messages = {
'settings.label.fastModel': '快速模型',
'settings.description.fastModel':
'用于生成提示建议和推测执行的模型。留空则使用主模型。较小/更快的模型(例如 qwen3-coder-flash)可以降低延迟和成本。',
'settings.label.visionModel': '视觉模型',
'settings.description.visionModel':
'用于视觉桥接的图像能力模型。留空则自动选择。',
'settings.label.context.fileFiltering.respectGitIgnore': '遵守 .gitignore',
'settings.description.context.fileFiltering.respectGitIgnore':
'搜索时遵守 .gitignore 文件。',
Expand Down
Loading