From be1edef5ce93a55ce94cb4843cfa50b408205358 Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Sat, 25 Jul 2026 20:37:13 -0500 Subject: [PATCH] fix(desktop): show the real effort on the composer pill The pill hardcoded 'Med' whenever the surface had no explicit effort, so a profile configured for high advertised a level the agent would not use. Take the profile default as a fallback and drop the now-unused shell.modelMenu.medium key across the locales. --- apps/desktop/src/app/chat/composer/model-pill.tsx | 7 +++++-- apps/desktop/src/i18n/ar.ts | 3 +-- apps/desktop/src/i18n/en.ts | 3 +-- apps/desktop/src/i18n/ja.ts | 3 +-- apps/desktop/src/i18n/types.ts | 1 - apps/desktop/src/i18n/zh-hant.ts | 3 +-- apps/desktop/src/i18n/zh.ts | 3 +-- apps/desktop/src/lib/model-status-label.test.ts | 9 ++++++++- apps/desktop/src/lib/model-status-label.ts | 12 +++++++----- 9 files changed, 25 insertions(+), 19 deletions(-) diff --git a/apps/desktop/src/app/chat/composer/model-pill.tsx b/apps/desktop/src/app/chat/composer/model-pill.tsx index b5a6e976805b..2a26db4094c9 100644 --- a/apps/desktop/src/app/chat/composer/model-pill.tsx +++ b/apps/desktop/src/app/chat/composer/model-pill.tsx @@ -11,7 +11,7 @@ import { useI18n } from '@/i18n' import { ChevronDown } from '@/lib/icons' import { formatModelStatusLabel } from '@/lib/model-status-label' import { cn } from '@/lib/utils' -import { $currentModelSource, setModelPickerOpen } from '@/store/session' +import { $currentModelSource, $defaultReasoningEffort, setModelPickerOpen } from '@/store/session' import type { ChatBarState } from './types' @@ -48,6 +48,7 @@ export function ModelPill({ const fastMode = useStore(view.$fast) const reasoningEffort = useStore(view.$reasoningEffort) const modelSource = useStore($currentModelSource) + const defaultEffort = useStore($defaultReasoningEffort) const runtimeId = useStore(view.$runtimeId) const [open, setOpen] = useState(false) @@ -68,7 +69,9 @@ export function ModelPill({ ) : ( <> {currentModel.trim() ? ( - {formatModelStatusLabel(currentModel, { fastMode, reasoningEffort })} + + {formatModelStatusLabel(currentModel, { defaultEffort, fastMode, reasoningEffort })} + ) : ( )} diff --git a/apps/desktop/src/i18n/ar.ts b/apps/desktop/src/i18n/ar.ts index 2d61c399998f..01f018d65936 100644 --- a/apps/desktop/src/i18n/ar.ts +++ b/apps/desktop/src/i18n/ar.ts @@ -1986,8 +1986,7 @@ export const ar = defineLocale({ noModels: 'لا توجد نماذج', editModels: 'تحرير النماذج', refreshModels: 'تحديث النماذج', - fast: 'سريع', - medium: 'متوسط' + fast: 'سريع' }, modelOptions: { noOptions: 'لا توجد خيارات لهذا النموذج', diff --git a/apps/desktop/src/i18n/en.ts b/apps/desktop/src/i18n/en.ts index 12d15e9657c4..25a6fa82fb61 100644 --- a/apps/desktop/src/i18n/en.ts +++ b/apps/desktop/src/i18n/en.ts @@ -2306,8 +2306,7 @@ export const en: Translations = { noModels: 'No models found', editModels: 'Edit Models…', refreshModels: 'Refresh Models', - fast: 'Fast', - medium: 'Med' + fast: 'Fast' }, modelOptions: { noOptions: 'No options for this model', diff --git a/apps/desktop/src/i18n/ja.ts b/apps/desktop/src/i18n/ja.ts index 90d65ad5901a..75cfe0feaf8a 100644 --- a/apps/desktop/src/i18n/ja.ts +++ b/apps/desktop/src/i18n/ja.ts @@ -2178,8 +2178,7 @@ export const ja = defineLocale({ noModels: 'モデルが見つかりません', editModels: 'モデルを編集…', refreshModels: 'モデルを更新', - fast: '高速', - medium: '中' + fast: '高速' }, modelOptions: { noOptions: 'このモデルにはオプションがありません', diff --git a/apps/desktop/src/i18n/types.ts b/apps/desktop/src/i18n/types.ts index 41417a4cf338..928493ec05a4 100644 --- a/apps/desktop/src/i18n/types.ts +++ b/apps/desktop/src/i18n/types.ts @@ -1915,7 +1915,6 @@ export interface Translations { editModels: string refreshModels: string fast: string - medium: string } modelOptions: { noOptions: string diff --git a/apps/desktop/src/i18n/zh-hant.ts b/apps/desktop/src/i18n/zh-hant.ts index 2772852eee51..90240c358a0e 100644 --- a/apps/desktop/src/i18n/zh-hant.ts +++ b/apps/desktop/src/i18n/zh-hant.ts @@ -2105,8 +2105,7 @@ export const zhHant = defineLocale({ noModels: '找不到模型', editModels: '編輯模型…', refreshModels: '重新整理模型', - fast: '快速', - medium: '中' + fast: '快速' }, modelOptions: { noOptions: '此模型沒有可用選項', diff --git a/apps/desktop/src/i18n/zh.ts b/apps/desktop/src/i18n/zh.ts index 68cbbb77ad4a..f9f4c92a7748 100644 --- a/apps/desktop/src/i18n/zh.ts +++ b/apps/desktop/src/i18n/zh.ts @@ -2483,8 +2483,7 @@ export const zh: Translations = { noModels: '未找到模型', editModels: '编辑模型…', refreshModels: '刷新模型', - fast: '快速', - medium: '中' + fast: '快速' }, modelOptions: { noOptions: '此模型没有可用选项', diff --git a/apps/desktop/src/lib/model-status-label.test.ts b/apps/desktop/src/lib/model-status-label.test.ts index cc499c86d565..c0a1f867c22e 100644 --- a/apps/desktop/src/lib/model-status-label.test.ts +++ b/apps/desktop/src/lib/model-status-label.test.ts @@ -34,9 +34,16 @@ describe('model-status-label', () => { ) }) - it('always surfaces the effort (default medium) so the level is visible', () => { + it('falls back to the profile default effort, then to medium', () => { expect(formatModelStatusLabel('openai/gpt-5.5', { reasoningEffort: 'medium' })).toBe('GPT-5.5 · Med') expect(formatModelStatusLabel('openai/gpt-5.5')).toBe('GPT-5.5 · Med') + // No session-level effort → the configured profile default is advertised, + // not Hermes' built-in medium. + expect(formatModelStatusLabel('openai/gpt-5.5', { defaultEffort: 'high' })).toBe('GPT-5.5 · High') + // An explicit session effort still wins over the profile default. + expect(formatModelStatusLabel('openai/gpt-5.5', { defaultEffort: 'high', reasoningEffort: 'low' })).toBe( + 'GPT-5.5 · Low' + ) }) it('returns just the placeholder name when there is no model', () => { diff --git a/apps/desktop/src/lib/model-status-label.ts b/apps/desktop/src/lib/model-status-label.ts index a1b28b8a4c58..1c6a7850dc12 100644 --- a/apps/desktop/src/lib/model-status-label.ts +++ b/apps/desktop/src/lib/model-status-label.ts @@ -99,10 +99,12 @@ export function displayModelName(model: string): string { return modelDisplayParts(model).name } -/** Status bar trigger label — model name plus the live session state (effort/fast). */ +/** Status bar trigger label — model name plus the live session state (effort/fast). + * `defaultEffort` is the profile's configured level, used when the surface has + * no explicit effort so the label never advertises a default the agent won't use. */ export function formatModelStatusLabel( model: string, - options?: { fastMode?: boolean; reasoningEffort?: string } + options?: { defaultEffort?: string; fastMode?: boolean; reasoningEffort?: string } ): string { const name = displayModelName(model) @@ -118,9 +120,9 @@ export function formatModelStatusLabel( parts.push('Fast') } - // Always surface the effort (empty = Hermes default of medium) so the - // current reasoning level is visible at a glance, not just when non-default. - parts.push(reasoningEffortLabel(options?.reasoningEffort ?? '') || 'Med') + // Always surface the effort so the current reasoning level is visible at a + // glance, not just when non-default. + parts.push(reasoningEffortLabel(options?.reasoningEffort || options?.defaultEffort || 'medium')) return `${name} · ${parts.join(' ')}` }