fix(desktop): stop the model picker overriding the configured effort

Selecting a model applied 'preset.effort ?? medium', so a user running
agent.reasoning_effort: high was silently downgraded to medium on every
model switch and every new chat that inherited the pick. The Thinking
toggle and the effort radio group defaulted to the same literal.

Resolve all of them from the profile default instead, falling back to
DEFAULT_REASONING_EFFORT only when config has not loaded.
This commit is contained in:
Brooklyn Nicholson 2026-07-25 20:37:09 -05:00
parent 58f5a05655
commit e2122f22b8
2 changed files with 21 additions and 12 deletions

View file

@ -16,7 +16,13 @@ import { useI18n } from '@/i18n'
import { normalize } from '@/lib/text'
import { setModelPreset } from '@/store/model-presets'
import { notifyError } from '@/store/notifications'
import { markComposerSelectionManual, setCurrentFastMode, setCurrentReasoningEffort } from '@/store/session'
import {
$defaultReasoningEffort,
DEFAULT_REASONING_EFFORT,
markComposerSelectionManual,
setCurrentFastMode,
setCurrentReasoningEffort
} from '@/store/session'
import { sessionTileDelegate } from '@/store/session-states'
// Hermes' real reasoning levels (see VALID_REASONING_EFFORTS); `none` is owned
@ -111,8 +117,9 @@ export function ModelEditSubmenu({
const activeSessionId = useStore(view.$runtimeId)
const touchesPrimary = view.kind === 'primary'
const effortValue = normalizeEffort(effort)
const thinkingOn = isThinkingEnabled(effort)
const defaultEffort = useStore($defaultReasoningEffort) || DEFAULT_REASONING_EFFORT
const effortValue = normalizeEffort(effort, defaultEffort)
const thinkingOn = isThinkingEnabled(effort, defaultEffort)
// Editing always records the model's global preset (keyed by provider::model,
// not per-surface — a tile edit re-applies to that model everywhere); the
@ -224,7 +231,7 @@ export function ModelEditSubmenu({
<Switch
checked={thinkingOn}
className="ml-auto"
onCheckedChange={checked => void patchReasoning(checked ? effortValue || 'medium' : 'none')}
onCheckedChange={checked => void patchReasoning(checked ? effortValue || defaultEffort : 'none')}
size="xs"
/>
</DropdownMenuItem>
@ -259,18 +266,18 @@ export function ModelEditSubmenu({
)
}
function isThinkingEnabled(effort: string): boolean {
// Empty = Hermes default (medium) = on; only an explicit "none" is off.
return normalize(effort || 'medium') !== 'none'
function isThinkingEnabled(effort: string, fallback: string): boolean {
// Empty = the profile default = on; only an explicit "none" is off.
return normalize(effort || fallback) !== 'none'
}
function normalizeEffort(effort: string): string {
const value = normalize(effort || 'medium')
function normalizeEffort(effort: string, fallback: string): string {
const value = normalize(effort || fallback)
// Thinking off → no effort selected in the radio group.
if (value === 'none') {
return ''
}
return EFFORT_OPTIONS.some(option => option.value === value) ? value : 'medium'
return EFFORT_OPTIONS.some(option => option.value === value) ? value : DEFAULT_REASONING_EFFORT
}

View file

@ -39,6 +39,7 @@ import {
setModelVisibilityOpen
} from '@/store/model-visibility'
import { $collapsedProviders, toggleCollapsedProvider } from '@/store/provider-collapse'
import { $defaultReasoningEffort, DEFAULT_REASONING_EFFORT } from '@/store/session'
import type { ModelOptionProvider, ModelOptionsResponse } from '@/types/hermes'
import { ModelEditSubmenu, resolveFastControl } from './model-edit-submenu'
@ -84,6 +85,7 @@ export function ModelMenuPanel({ gateway, onSelectModel, profile = 'default', re
const currentProvider = useStore(view.$provider)
const currentReasoningEffort = useStore(view.$reasoningEffort)
const modelPresets = useStore($modelPresets)
const defaultEffort = useStore($defaultReasoningEffort) || DEFAULT_REASONING_EFFORT
const visibleModels = useStore($visibleModels)
const collapsedProviders = useStore($collapsedProviders)
@ -181,7 +183,7 @@ export function ModelMenuPanel({ gateway, onSelectModel, profile = 'default', re
await applyModelPreset(
{
effort: (caps?.reasoning ?? true) ? (preset.effort ?? 'medium') : undefined,
effort: (caps?.reasoning ?? true) ? (preset.effort ?? defaultEffort) : undefined,
fast: (caps?.fast ?? false) ? (preset.fast ?? false) : undefined
},
{
@ -300,7 +302,7 @@ export function ModelMenuPanel({ gateway, onSelectModel, profile = 'default', re
const meta = [
fastControl.kind !== 'none' && fastControl.on ? copy.fast : null,
(caps?.reasoning ?? true) ? reasoningEffortLabel(effEffort) || copy.medium : null
(caps?.reasoning ?? true) ? reasoningEffortLabel(effEffort || defaultEffort) : null
]
.filter(Boolean)
.join(' ')