Skip to content

Commit 13c0384

Browse files
authored
🤖 feat: improve task tool output styling with dedicated components (#1256)
## Summary Improves the styling of task tool outputs (task, task_await, task_list, task_terminate) with dedicated React components and a cohesive visual design. ## Changes ### New Components - **TaskToolCall.tsx** - Dedicated components for all task-related tools with: - Teal/cyan color theme distinct from plan (blue) and exec (purple) modes - Status badges with color-coded states (completed, running, queued, terminated, error) - Agent type badges (explore/exec) - Task ID display with monospace styling - Markdown rendering for task reports - Collapsible details with prompt preview when collapsed ### Styling - New CSS variables: `--color-task-mode`, `--surface-task-*` - New utility classes: `task-surface`, `task-divider` ### Storybook Coverage - **App.task.stories.tsx** with visual tests for: - Completed tasks with reports - Background/queued tasks - Multiple parallel tasks - Task await with mixed statuses - Task list with hierarchy - Task termination (success and error states) ## Testing - `make static-check` passes - `make storybook-build` succeeds - All type exports added to `src/common/types/tools.ts` --- _Generated with `mux` • Model: `anthropic:claude-opus-4-5` • Thinking: `high`_
1 parent 0bdefe1 commit 13c0384

File tree

6 files changed

+1044
-0
lines changed

6 files changed

+1044
-0
lines changed

‎src/browser/components/Messages/ToolMessage.tsx‎

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ import { BashBackgroundListToolCall } from "../tools/BashBackgroundListToolCall"
1414
import { BashBackgroundTerminateToolCall } from "../tools/BashBackgroundTerminateToolCall";
1515
import { BashOutputToolCall } from "../tools/BashOutputToolCall";
1616
import { CodeExecutionToolCall } from "../tools/CodeExecutionToolCall";
17+
import {
18+
TaskToolCall,
19+
TaskAwaitToolCall,
20+
TaskListToolCall,
21+
TaskTerminateToolCall,
22+
} from "../tools/TaskToolCall";
1723
import type {
1824
BashToolArgs,
1925
BashToolResult,
@@ -41,6 +47,14 @@ import type {
4147
StatusSetToolResult,
4248
WebFetchToolArgs,
4349
WebFetchToolResult,
50+
TaskToolArgs,
51+
TaskToolSuccessResult,
52+
TaskAwaitToolArgs,
53+
TaskAwaitToolSuccessResult,
54+
TaskListToolArgs,
55+
TaskListToolSuccessResult,
56+
TaskTerminateToolArgs,
57+
TaskTerminateToolSuccessResult,
4458
} from "@/common/types/tools";
4559
import type { ReviewNoteData } from "@/common/types/review";
4660
import type { BashOutputGroupInfo } from "@/browser/utils/messages/messageUtils";
@@ -146,6 +160,26 @@ function isCodeExecutionTool(toolName: string, args: unknown): args is CodeExecu
146160
return TOOL_DEFINITIONS.code_execution.schema.safeParse(args).success;
147161
}
148162

163+
function isTaskTool(toolName: string, args: unknown): args is TaskToolArgs {
164+
if (toolName !== "task") return false;
165+
return TOOL_DEFINITIONS.task.schema.safeParse(args).success;
166+
}
167+
168+
function isTaskAwaitTool(toolName: string, args: unknown): args is TaskAwaitToolArgs {
169+
if (toolName !== "task_await") return false;
170+
return TOOL_DEFINITIONS.task_await.schema.safeParse(args).success;
171+
}
172+
173+
function isTaskListTool(toolName: string, args: unknown): args is TaskListToolArgs {
174+
if (toolName !== "task_list") return false;
175+
return TOOL_DEFINITIONS.task_list.schema.safeParse(args).success;
176+
}
177+
178+
function isTaskTerminateTool(toolName: string, args: unknown): args is TaskTerminateToolArgs {
179+
if (toolName !== "task_terminate") return false;
180+
return TOOL_DEFINITIONS.task_terminate.schema.safeParse(args).success;
181+
}
182+
149183
export const ToolMessage: React.FC<ToolMessageProps> = ({
150184
message,
151185
className,
@@ -354,6 +388,54 @@ export const ToolMessage: React.FC<ToolMessageProps> = ({
354388
);
355389
}
356390

391+
if (isTaskTool(message.toolName, message.args)) {
392+
return (
393+
<div className={className}>
394+
<TaskToolCall
395+
args={message.args}
396+
result={message.result as TaskToolSuccessResult | undefined}
397+
status={message.status}
398+
/>
399+
</div>
400+
);
401+
}
402+
403+
if (isTaskAwaitTool(message.toolName, message.args)) {
404+
return (
405+
<div className={className}>
406+
<TaskAwaitToolCall
407+
args={message.args}
408+
result={message.result as TaskAwaitToolSuccessResult | undefined}
409+
status={message.status}
410+
/>
411+
</div>
412+
);
413+
}
414+
415+
if (isTaskListTool(message.toolName, message.args)) {
416+
return (
417+
<div className={className}>
418+
<TaskListToolCall
419+
args={message.args}
420+
result={message.result as TaskListToolSuccessResult | undefined}
421+
status={message.status}
422+
/>
423+
</div>
424+
);
425+
}
426+
427+
if (isTaskTerminateTool(message.toolName, message.args)) {
428+
return (
429+
<div className={className}>
430+
<TaskTerminateToolCall
431+
args={message.args}
432+
result={message.result as TaskTerminateToolSuccessResult | undefined}
433+
status={message.status}
434+
/>
435+
</div>
436+
);
437+
}
438+
357439
// Fallback to generic tool call
358440
return (
359441
<div className={className}>

0 commit comments

Comments
 (0)