diff --git a/src/main/AryxAppService.ts b/src/main/AryxAppService.ts index cd489ed..ded71d3 100644 --- a/src/main/AryxAppService.ts +++ b/src/main/AryxAppService.ts @@ -2944,9 +2944,16 @@ export class AryxAppService extends EventEmitter { let didChange = false; const agents = pattern.agents.map((agent) => { - const reasoningEffort = resolvedModel - ? resolveReasoningEffort(resolvedModel, agent.reasoningEffort) - : agent.reasoningEffort; + // When overriding the model, re-normalize reasoning effort for the target model. + // If the target model's reasoning capabilities are unknown (supportedReasoningEfforts + // is undefined — common for dynamically-discovered models), strip reasoning effort + // entirely to avoid sending it to a model that may not support it. + let reasoningEffort: ReasoningEffort | undefined; + if (resolvedModel?.supportedReasoningEfforts) { + reasoningEffort = resolveReasoningEffort(resolvedModel, agent.reasoningEffort); + } else { + reasoningEffort = undefined; + } if (agent.model === effectiveModelId && agent.reasoningEffort === reasoningEffort) { return agent; diff --git a/src/renderer/components/ChatPane.tsx b/src/renderer/components/ChatPane.tsx index 872aa97..6e0b550 100644 --- a/src/renderer/components/ChatPane.tsx +++ b/src/renderer/components/ChatPane.tsx @@ -195,6 +195,30 @@ export function ChatPane({ const promptFiles = useMemo(() => project.customization?.promptFiles ?? [], [project.customization?.promptFiles]); const [armedPrompt, setArmedPrompt] = useState(null); + // Map assistant message IDs to the actual model that executed the run, but only + // when it differs from the session's primary agent model (i.e. a prompt override). + const modelOverrideByMessageId = useMemo(() => { + const runsByTrigger = new Map(session.runs.map((r) => [r.triggerMessageId, r])); + const map = new Map(); + let activeOverrideModel: string | undefined; + + for (const message of session.messages) { + if (message.role === 'user') { + const run = runsByTrigger.get(message.id); + const runModel = run?.agents[0]?.model; + if (runModel && runModel !== primaryAgent?.model) { + const resolved = findModel(runModel, availableModels); + activeOverrideModel = resolved?.name ?? runModel; + } else { + activeOverrideModel = undefined; + } + } else if (activeOverrideModel && message.messageKind !== 'thinking') { + map.set(message.id, activeOverrideModel); + } + } + return map; + }, [session.messages, session.runs, primaryAgent?.model, availableModels]); + const toolSelection = useMemo(() => resolveSessionToolingSelection(session), [session]); const mcpServers = toolingSettings.mcpServers; const lspProfiles = toolingSettings.lspProfiles; @@ -469,6 +493,7 @@ export function ChatPane({ : 'border-[var(--color-status-success)]/20 bg-[var(--color-status-success)]/10 text-[var(--color-status-success)]'; const phaseLabel = phase === 'thinking' ? 'Thinking' : phase === 'final' ? 'Final' : undefined; + const modelOverride = !isUser ? modelOverrideByMessageId.get(message.id) : undefined; const showActions = !isSessionBusy && !message.pending; return ( @@ -495,6 +520,11 @@ export function ChatPane({ {phaseLabel} )} + {modelOverride && ( + + {modelOverride} + + )} {showActions && (