From 4893629ff5ff8938c129c322d6328dd183023095 Mon Sep 17 00:00:00 2001 From: "paseo-bot[bot]" <266920839+paseo-bot[bot]@users.noreply.github.com> Date: Thu, 1 Oct 2026 02:55:22 +0200 Subject: [PATCH] Show the thinking level an agent runs on in its composer (#5804) The composer picked the thinking level from what was chosen at launch and fell back to the model's catalog default when nothing was chosen. A Pi agent started without a thinking level runs on Pi's own configured default, so the composer showed Medium while the agent ran on High. The composer now prefers the level the running agent reports when it is one of the model's options, the same way it already prefers the running model. Fixes #5800 Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com> --- .../app/src/composer/agent-controls/index.tsx | 3 + .../src/composer/agent-controls/utils.test.ts | 55 +++++++++++++++++++ .../app/src/composer/agent-controls/utils.ts | 22 +++++++- 3 files changed, 78 insertions(+), 2 deletions(-) diff --git a/packages/app/src/composer/agent-controls/index.tsx b/packages/app/src/composer/agent-controls/index.tsx index 8dadeec217..d5f09dc77f 100644 --- a/packages/app/src/composer/agent-controls/index.tsx +++ b/packages/app/src/composer/agent-controls/index.tsx @@ -394,6 +394,7 @@ type AgentControlsSlice = { runtimeModelId: string | null; model: string | null | undefined; features: AgentFeature[] | undefined; + runtimeThinkingOptionId: string | null; thinkingOptionId: string | null | undefined; lastUsage: unknown; } | null; @@ -413,6 +414,7 @@ function selectAgentControlsSlice( runtimeModelId: currentAgent.runtimeInfo?.model ?? null, model: currentAgent.model, features: currentAgent.features, + runtimeThinkingOptionId: currentAgent.runtimeInfo?.thinkingOptionId ?? null, thinkingOptionId: currentAgent.thinkingOptionId, lastUsage: currentAgent.lastUsage, }; @@ -1594,6 +1596,7 @@ export const AgentControls = memo(function AgentControls({ models, runtimeModelId: agent?.runtimeModelId, configuredModelId: agent?.model, + runtimeThinkingOptionId: agent?.runtimeThinkingOptionId, explicitThinkingOptionId: agent?.thinkingOptionId, }); diff --git a/packages/app/src/composer/agent-controls/utils.test.ts b/packages/app/src/composer/agent-controls/utils.test.ts index 993e21f0c9..1c91d8ce79 100644 --- a/packages/app/src/composer/agent-controls/utils.test.ts +++ b/packages/app/src/composer/agent-controls/utils.test.ts @@ -67,6 +67,7 @@ describe("resolveAgentModelSelection", () => { ], runtimeModelId: null, configuredModelId: "claude-fable-5[1m]", + runtimeThinkingOptionId: null, explicitThinkingOptionId: null, }); @@ -88,6 +89,7 @@ describe("resolveAgentModelSelection", () => { ], runtimeModelId: "a", configuredModelId: "b", + runtimeThinkingOptionId: null, explicitThinkingOptionId: null, }); @@ -112,6 +114,7 @@ describe("resolveAgentModelSelection", () => { ], runtimeModelId: "a", configuredModelId: null, + runtimeThinkingOptionId: null, explicitThinkingOptionId: "high", }); @@ -119,6 +122,54 @@ describe("resolveAgentModelSelection", () => { expect(selection.displayThinking).toBe("High"); }); + it("shows the thinking level the agent runs on when none was chosen", () => { + const selection = resolveAgentModelSelection({ + models: [ + { + id: "openrouter/google/gemini-3.6-flash", + provider: "pi", + label: "Gemini 3.6 Flash", + thinkingOptions: [ + { id: "low", label: "Low" }, + { id: "medium", label: "Medium", isDefault: true }, + { id: "high", label: "High" }, + ], + defaultThinkingOptionId: "medium", + }, + ], + runtimeModelId: "openrouter/google/gemini-3.6-flash", + configuredModelId: null, + runtimeThinkingOptionId: "high", + explicitThinkingOptionId: null, + }); + + expect(selection.selectedThinkingId).toBe("high"); + expect(selection.displayThinking).toBe("High"); + }); + + it("falls back to the chosen thinking level when the runtime level is not a model option", () => { + const selection = resolveAgentModelSelection({ + models: [ + { + id: "a", + provider: "codex", + label: "Model A", + thinkingOptions: [ + { id: "low", label: "Low" }, + { id: "high", label: "High" }, + ], + defaultThinkingOptionId: "low", + }, + ], + runtimeModelId: "a", + configuredModelId: null, + runtimeThinkingOptionId: "xhigh", + explicitThinkingOptionId: "high", + }); + + expect(selection.selectedThinkingId).toBe("high"); + }); + it("formats raw thinking labels in the selected model display", () => { const selection = resolveAgentModelSelection({ models: [ @@ -134,6 +185,7 @@ describe("resolveAgentModelSelection", () => { ], runtimeModelId: "a", configuredModelId: null, + runtimeThinkingOptionId: null, explicitThinkingOptionId: "xhigh", }); @@ -155,6 +207,7 @@ describe("resolveAgentModelSelection", () => { ], runtimeModelId: null, configuredModelId: null, + runtimeThinkingOptionId: null, explicitThinkingOptionId: null, }); @@ -178,6 +231,7 @@ describe("resolveAgentModelSelection", () => { ], runtimeModelId: "claude-sonnet-4-6-20260101", configuredModelId: "default", + runtimeThinkingOptionId: null, explicitThinkingOptionId: null, }); @@ -204,6 +258,7 @@ describe("resolveAgentModelSelection", () => { ], runtimeModelId: "gpt-6.1-sol", configuredModelId: "gpt-6.1-sol", + runtimeThinkingOptionId: null, explicitThinkingOptionId: "max", }); diff --git a/packages/app/src/composer/agent-controls/utils.ts b/packages/app/src/composer/agent-controls/utils.ts index 56f9bcd49f..631b55753e 100644 --- a/packages/app/src/composer/agent-controls/utils.ts +++ b/packages/app/src/composer/agent-controls/utils.ts @@ -86,9 +86,16 @@ function pickSelectedModel( } function resolveThinkingId( + runtimeThinkingOptionId: string | null | undefined, explicitThinkingOptionId: string | null | undefined, selectedModel: AgentModelDefinition | null, ): string | null { + const runtimeThinkingOption = selectedModel?.thinkingOptions?.find( + (option) => option.id === runtimeThinkingOptionId, + ); + if (runtimeThinkingOption) { + return runtimeThinkingOption.id; + } if (explicitThinkingOptionId && explicitThinkingOptionId !== "default") { return explicitThinkingOptionId; } @@ -139,9 +146,16 @@ export function resolveAgentModelSelection(input: { models: AgentModelDefinition[] | null; runtimeModelId: string | null | undefined; configuredModelId: string | null | undefined; + runtimeThinkingOptionId: string | null | undefined; explicitThinkingOptionId: string | null | undefined; }) { - const { models, runtimeModelId, configuredModelId, explicitThinkingOptionId } = input; + const { + models, + runtimeModelId, + configuredModelId, + runtimeThinkingOptionId, + explicitThinkingOptionId, + } = input; const normalizedRuntimeModelId = normalizeModelId(runtimeModelId); const normalizedConfiguredModelId = normalizeModelId(configuredModelId); @@ -162,7 +176,11 @@ export function resolveAgentModelSelection(input: { ); const thinkingOptions = selectedModel?.thinkingOptions ?? null; - const resolvedThinkingId = resolveThinkingId(explicitThinkingOptionId, selectedModel); + const resolvedThinkingId = resolveThinkingId( + runtimeThinkingOptionId, + explicitThinkingOptionId, + selectedModel, + ); const effectiveThinking = resolveEffectiveThinking(thinkingOptions, resolvedThinkingId); const selectedThinkingId = effectiveThinking?.id ?? resolvedThinkingId; const displayThinking = resolveThinkingDisplay(