{props.report.agentType}
+ {props.report.model && (
+ <>
+
·
+
+
+
+ >
+ )}
+ {props.report.thinkingLevel != null && (
+ <>
+
·
+
+ thinking: {getThinkingOptionLabel(props.report.thinkingLevel, props.report.model)}
+
+ >
+ )}
·
(
+
+
+
+ ),
+ play: async ({ canvasElement }) => {
+ const canvas = within(canvasElement);
+ canvas.getByText("task").click();
+ await waitFor(() => {
+ if (!canvasElement.querySelector("[data-task-ai-settings]")) {
+ throw new Error("task AI settings did not render after expanding");
+ }
+ });
+ const container = canvasElement.querySelector('[data-testid="narrow-task-card"]');
+ if (!(container instanceof HTMLElement)) {
+ throw new Error("narrow task card container not found");
+ }
+ await new Promise((resolve) =>
+ requestAnimationFrame(() => requestAnimationFrame(() => resolve()))
+ );
+ const containerRight = container.getBoundingClientRect().right;
+ const settings = container.querySelector("[data-task-ai-settings]");
+ const settingsRight = settings?.getBoundingClientRect().right ?? Number.POSITIVE_INFINITY;
+ // Right-edge containment, not scrollWidth: ancestors clip overflow, which would
+ // hide a too-wide settings row from scrollWidth-based checks.
+ if (settingsRight > containerRight + 1) {
+ throw new Error(
+ `task AI settings overflowed the ${container.clientWidth}px card by ` +
+ `${Math.round(settingsRight - containerRight)}px`
+ );
+ }
+ },
+};
+
/** task_apply_git_patch states: executing, dry-run, success, and failure */
export const TaskApplyGitPatchStates: Story = {
render: () => (
diff --git a/src/browser/features/Tools/TaskToolCall.test.tsx b/src/browser/features/Tools/TaskToolCall.test.tsx
index ffc6fe7b83..ca4f63fd13 100644
--- a/src/browser/features/Tools/TaskToolCall.test.tsx
+++ b/src/browser/features/Tools/TaskToolCall.test.tsx
@@ -137,6 +137,132 @@ describe("TaskToolCall", () => {
expect(setSelectedWorkspace).toHaveBeenCalledTimes(1);
expect(setSelectedWorkspace.mock.calls[0][0]).toEqual(workspace);
});
+
+ test("prefers live workspace settings over the result snapshot", () => {
+ // A plan child's auto-handoff to exec rewrites live metadata after launch; the
+ // result snapshot keeps the stale plan-phase settings.
+ const workspace = createWorkspaceMetadata({
+ id: "task-child-1",
+ taskModelString: "anthropic:claude-opus-5",
+ taskThinkingLevel: "high",
+ });
+ workspaceContextMock = {
+ workspaceMetadata: new Map([[workspace.id, workspace]]),
+ };
+
+ const agentTaskArgs = {
+ subagent_type: "plan",
+ prompt: "Plan then implement.",
+ title: "Plan task",
+ run_in_background: true,
+ };
+ const AgentTaskToolCall = getToolComponent("task", agentTaskArgs);
+ const view = render(
+
+
+
+ );
+
+ fireEvent.click(view.getByText("task"));
+
+ const settings = view.container.querySelector("[data-task-ai-settings]");
+ expect(settings?.textContent).toContain("Opus 5");
+ expect(settings?.textContent).toContain("thinking: high");
+ expect(settings?.textContent).not.toContain("thinking: low");
+ });
+
+ test("prefers linked report settings over the spawn snapshot after cleanup", () => {
+ // Workspace already cleaned up; the task_await-linked report carries the exec
+ // settings while the spawn result kept the stale plan-phase ones.
+ workspaceContextMock = { workspaceMetadata: new Map() };
+
+ const agentTaskArgs = {
+ subagent_type: "plan",
+ prompt: "Plan then implement.",
+ title: "Plan task",
+ run_in_background: true,
+ };
+ const AgentTaskToolCall = getToolComponent("task", agentTaskArgs);
+ const view = render(
+
+
+
+ );
+
+ fireEvent.click(view.getByText("task"));
+
+ const settings = view.container.querySelector("[data-task-ai-settings]");
+ expect(settings?.textContent).toContain("Opus 5");
+ expect(settings?.textContent).toContain("thinking: high");
+ expect(settings?.textContent).not.toContain("thinking: low");
+ });
+
+ test("falls back to result-carried settings after workspace cleanup", () => {
+ workspaceContextMock = { workspaceMetadata: new Map() };
+
+ const agentTaskArgs = {
+ subagent_type: "explore",
+ prompt: "Look around.",
+ title: "Explore task",
+ run_in_background: true,
+ };
+ const AgentTaskToolCall = getToolComponent("task", agentTaskArgs);
+ const view = render(
+
+
+
+ );
+
+ fireEvent.click(view.getByText("task"));
+
+ const settings = view.container.querySelector("[data-task-ai-settings]");
+ expect(settings?.textContent).toContain("thinking: low");
+ });
});
describe("TaskAwaitToolCall", () => {
diff --git a/src/browser/features/Tools/TaskToolCall.tsx b/src/browser/features/Tools/TaskToolCall.tsx
index 63f5a88993..6aeadcd03d 100644
--- a/src/browser/features/Tools/TaskToolCall.tsx
+++ b/src/browser/features/Tools/TaskToolCall.tsx
@@ -60,6 +60,8 @@ import {
import { resolvePersistedAgentId } from "@/common/utils/agentIds";
import { formatDuration } from "@/common/utils/formatDuration";
import { ElapsedTimeDisplay } from "./Shared/ElapsedTimeDisplay";
+import { ModelDisplay } from "../Messages/ModelDisplay";
+import { getThinkingOptionLabel, type ThinkingLevel } from "@/common/types/thinking";
/**
* Clean SVG icon for task tools - represents spawning/branching work
@@ -449,8 +451,43 @@ interface TaskToolDisplayEntry {
openWorkspaceId?: string;
groupKind?: TaskGroupKind;
label?: string;
+ modelString?: string;
+ thinkingLevel?: ThinkingLevel;
}
+interface TaskAiSettingsInfo {
+ modelString?: string;
+ thinkingLevel?: ThinkingLevel;
+}
+
+const TaskAiSettingsDisplay: React.FC = (props) => {
+ if (!props.modelString && props.thinkingLevel == null) {
+ return null;
+ }
+ return (
+ // min-w-0 at both flex levels + break-words let long custom model IDs wrap inside
+ // narrow cards instead of forcing right-edge overflow.
+
+ {props.modelString && (
+
+
+
+ )}
+ {props.thinkingLevel != null && (
+
+ thinking: {getThinkingOptionLabel(props.thinkingLevel, props.modelString)}
+
+ )}
+
+ );
+};
+
interface TaskToolOwnReport {
reportMarkdown: string;
title?: string;
@@ -654,12 +691,14 @@ function collectTaskToolResultDisplayData(result: TaskToolSuccessResult | null):
ownReportsByTaskId: Map;
taskGroupsByTaskId: Map;
workspaceIdByTaskId: Map;
+ aiSettingsByTaskId: Map;
} {
const taskIds = new Set();
const statusByTaskId = new Map();
const ownReportsByTaskId = new Map();
const taskGroupsByTaskId = new Map();
const workspaceIdByTaskId = new Map();
+ const aiSettingsByTaskId = new Map();
if (!result) {
return {
taskIds: [],
@@ -667,6 +706,7 @@ function collectTaskToolResultDisplayData(result: TaskToolSuccessResult | null):
ownReportsByTaskId,
taskGroupsByTaskId,
workspaceIdByTaskId,
+ aiSettingsByTaskId,
};
}
@@ -699,10 +739,23 @@ function collectTaskToolResultDisplayData(result: TaskToolSuccessResult | null):
}
};
+ const rememberAiSettings = (taskId: string, settings: TaskAiSettingsInfo): void => {
+ const modelString = trimToNonEmptyString(settings.modelString) ?? undefined;
+ if (!modelString && settings.thinkingLevel == null) {
+ return;
+ }
+ const existing = aiSettingsByTaskId.get(taskId);
+ aiSettingsByTaskId.set(taskId, {
+ modelString: existing?.modelString ?? modelString,
+ thinkingLevel: existing?.thinkingLevel ?? settings.thinkingLevel,
+ });
+ };
+
const taskStatuses = "tasks" in result && Array.isArray(result.tasks) ? result.tasks : undefined;
const singleTaskId = rememberTaskId(result.taskId);
if (singleTaskId) {
rememberWorkspace(singleTaskId, result.workspaceId);
+ rememberAiSettings(singleTaskId, result);
}
if (singleTaskId && result.status === "completed" && typeof result.reportMarkdown === "string") {
ownReportsByTaskId.set(singleTaskId, {
@@ -724,6 +777,7 @@ function collectTaskToolResultDisplayData(result: TaskToolSuccessResult | null):
statusByTaskId.set(taskId, task.status);
rememberWorkspace(taskId, task.workspaceId);
rememberTaskGroup(taskId, { groupKind: task.groupKind, label: task.label });
+ rememberAiSettings(taskId, task);
}
}
}
@@ -740,6 +794,7 @@ function collectTaskToolResultDisplayData(result: TaskToolSuccessResult | null):
});
rememberWorkspace(taskId, report.workspaceId);
rememberTaskGroup(taskId, { groupKind: report.groupKind, label: report.label });
+ rememberAiSettings(taskId, report);
}
}
}
@@ -757,6 +812,7 @@ function collectTaskToolResultDisplayData(result: TaskToolSuccessResult | null):
ownReportsByTaskId,
taskGroupsByTaskId,
workspaceIdByTaskId,
+ aiSettingsByTaskId,
};
}
@@ -808,6 +864,11 @@ const TaskToolCandidateCard: React.FC<{
{entry.title && (
{entry.title}
)}
+
{canViewTranscript && (