diff --git a/cli/src/claude/utils/getToolName.ts b/cli/src/claude/utils/getToolName.ts index cb877645..38d6b55b 100644 --- a/cli/src/claude/utils/getToolName.ts +++ b/cli/src/claude/utils/getToolName.ts @@ -28,6 +28,7 @@ const STANDARD_TOOLS: Record = { 'TodoWrite': 'Update Tasks', 'TodoRead': 'Read Tasks', 'Task': 'Launch Agent', + 'Agent': 'Launch Agent', // Team management 'TeamCreate': 'Create Team', diff --git a/hub/src/telegram/sessionView.ts b/hub/src/telegram/sessionView.ts index 678870f8..391aae11 100644 --- a/hub/src/telegram/sessionView.ts +++ b/hub/src/telegram/sessionView.ts @@ -101,6 +101,7 @@ function formatToolArgumentsDetailed(tool: string, args: any): string { return `Command: ${truncate(cmd, MAX_TOOL_ARGS_LENGTH)}` } + case 'Agent': case 'Task': { const desc = args.description || args.prompt || '' return `Task: ${truncate(desc, MAX_TOOL_ARGS_LENGTH)}` diff --git a/web/src/chat/reducerTimeline.test.ts b/web/src/chat/reducerTimeline.test.ts index 96fd09dd..cbc9df43 100644 --- a/web/src/chat/reducerTimeline.test.ts +++ b/web/src/chat/reducerTimeline.test.ts @@ -324,6 +324,88 @@ describe('reduceTimeline', () => { expect(toolBlock.invokedAt).toBe(1_700_000_000_500) }) + it('populates block.children for Agent tool (same as Task)', () => { + // Agent tool_use message with a sidechain group + const agentToolMsg: TracedMessage = { + id: 'msg-agent', + localId: null, + createdAt: 1_700_000_000_000, + role: 'agent', + content: [{ + type: 'tool-call', + id: 'tc-agent-1', + name: 'Agent', + input: { prompt: 'explore stuff', subagent_type: 'general-purpose' }, + description: null, + uuid: 'u-agent', + parentUUID: null + }], + isSidechain: false + } as TracedMessage + + // Sidechain child message that would be in the group for msg-agent + const sidechainChild: TracedMessage = { + id: 'sc-msg-1', + localId: null, + createdAt: 1_700_000_001_000, + role: 'agent', + content: [{ + type: 'tool-call', + id: 'tc-glob-1', + name: 'Glob', + input: { pattern: '**/*.ts' }, + description: null, + uuid: 'u-sc-1', + parentUUID: null + }], + isSidechain: true, + sidechainId: 'msg-agent' + } as TracedMessage + + // Build groups map the way the real pipeline does it + const groups = new Map() + groups.set('msg-agent', [sidechainChild]) + + const ctx = { ...makeContext(), groups } + const { blocks } = reduceTimeline([agentToolMsg], ctx) + + const agentBlock = blocks.find(b => b.kind === 'tool-call') as any + expect(agentBlock).toBeDefined() + // block.children must be populated for Agent (was broken before fix) + expect(agentBlock.children.length).toBeGreaterThan(0) + }) + + it('suppresses prompt-text duplicate for Agent tool (same as Task)', () => { + // When an agent message contains an Agent tool_use, Claude often writes + // the prompt as a text block before the tool_use. The reducer must skip + // that duplicate text just like it does for Task. + const prompt = 'explore the repository structure' + const agentMsg: TracedMessage = { + id: 'msg-agent-dup', + localId: null, + createdAt: 1_700_000_000_000, + role: 'agent', + content: [ + { type: 'text', text: prompt, uuid: 'u-text', parentUUID: null }, + { + type: 'tool-call', + id: 'tc-agent-2', + name: 'Agent', + input: { prompt, subagent_type: 'Explore' }, + description: null, + uuid: 'u-agent', + parentUUID: null + } + ], + isSidechain: false + } as TracedMessage + + const { blocks } = reduceTimeline([agentMsg], makeContext()) + // text block with same content as Agent.input.prompt must be suppressed + const textBlocks = blocks.filter(b => b.kind === 'agent-text') + expect(textBlocks).toHaveLength(0) + }) + it('keeps toolBlocksById reference identity when applying turn-duration to a tool-call', () => { const toolCallMsg: TracedMessage = { id: 'msg-tool', diff --git a/web/src/chat/reducerTimeline.ts b/web/src/chat/reducerTimeline.ts index fcd432e7..256d786c 100644 --- a/web/src/chat/reducerTimeline.ts +++ b/web/src/chat/reducerTimeline.ts @@ -3,6 +3,7 @@ import type { TracedMessage } from '@/chat/tracer' import { createCliOutputBlock, isCliOutputText, mergeCliOutputBlocks } from '@/chat/reducerCliOutput' import { parseMessageAsEvent } from '@/chat/reducerEvents' import { ensureToolBlock, extractTitleFromChangeTitleInput, isChangeTitleToolName, type PermissionEntry } from '@/chat/reducerTools' +import { isSubagentToolName } from '@/chat/subagentTool' export function reduceTimeline( messages: TracedMessage[], @@ -124,11 +125,11 @@ export function reduceTimeline( } if (msg.role === 'agent') { - // When the message contains a Task tool_use, Claude often writes the - // prompt as a text block before the tool_use block. We only want to + // When the message contains a Task/Agent tool_use, Claude often writes + // the prompt as a text block before the tool_use block. We only want to // suppress that exact prompt text — not every text block in the message. const taskToolCall = msg.content.find( - (c) => c.type === 'tool-call' && c.name === 'Task' + (c) => c.type === 'tool-call' && isSubagentToolName(c.name) ) const taskPromptText: string | null = (() => { if (!taskToolCall || taskToolCall.type !== 'tool-call') return null @@ -259,7 +260,7 @@ export function reduceTimeline( block.tool.startedAt = msg.createdAt } - if (c.name === 'Task' && !context.consumedGroupIds.has(msg.id)) { + if (isSubagentToolName(c.name) && !context.consumedGroupIds.has(msg.id)) { const sidechain = context.groups.get(msg.id) ?? null if (sidechain && sidechain.length > 0) { context.consumedGroupIds.add(msg.id) diff --git a/web/src/chat/subagentTool.ts b/web/src/chat/subagentTool.ts new file mode 100644 index 00000000..a18c60d7 --- /dev/null +++ b/web/src/chat/subagentTool.ts @@ -0,0 +1,14 @@ +/** + * Returns true when the tool name identifies a subagent invocation. + * + * The Claude Code SDK has used two names for the same concept: + * - 'Task' — earlier SDK releases + * - 'Agent' — later SDK releases (OPUS 4.7+ environment) + * + * Both share the same input shape: { prompt: string, subagent_type: string }. + * The tracer, reducer, and UI surfaces must treat them identically. + * Keeping both ensures sessions recorded under either name continue to work. + */ +export function isSubagentToolName(name: string): boolean { + return name === 'Task' || name === 'Agent' +} diff --git a/web/src/chat/tracer.test.ts b/web/src/chat/tracer.test.ts new file mode 100644 index 00000000..f57c321f --- /dev/null +++ b/web/src/chat/tracer.test.ts @@ -0,0 +1,131 @@ +/** + * Tests for traceMessages — verifies that both Task and Agent tool names + * are indexed and matched when grouping sidechain messages. + */ +import { describe, expect, it } from 'vitest' +import type { NormalizedMessage } from '@/chat/types' +import { traceMessages } from '@/chat/tracer' + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +function makeAgentMsg(overrides: Partial & { id: string }): NormalizedMessage { + const { id, ...rest } = overrides + return { + id, + localId: null, + createdAt: 1_700_000_000_000, + role: 'agent', + isSidechain: false, + content: [], + ...rest, + } as NormalizedMessage +} + +function makeToolCallMsg( + id: string, + toolName: 'Task' | 'Agent', + prompt: string, +): NormalizedMessage { + return makeAgentMsg({ + id, + content: [ + { + type: 'tool-call', + id: `tc-${id}`, + name: toolName, + input: { prompt, subagent_type: 'general-purpose' }, + description: null, + uuid: `uuid-${id}`, + parentUUID: null, + }, + ], + }) +} + +function makeSidechainRootMsg(id: string, prompt: string): NormalizedMessage { + return { + id, + localId: null, + createdAt: 1_700_000_001_000, + role: 'agent', + isSidechain: true, + content: [ + { + type: 'sidechain', + uuid: `uuid-sc-${id}`, + prompt, + }, + ], + } as NormalizedMessage +} + +// --------------------------------------------------------------------------- +// Task — existing behaviour preserved +// --------------------------------------------------------------------------- + +describe('traceMessages — Task tool name (preserved)', () => { + it('matches sidechain root to a Task tool_use message', () => { + const prompt = 'list .ts files' + const taskMsg = makeToolCallMsg('msg-task', 'Task', prompt) + const sidechainRoot = makeSidechainRootMsg('sc-root', prompt) + + const result = traceMessages([taskMsg, sidechainRoot]) + const sc = result.find(m => m.id === 'sc-root') + expect(sc).toBeDefined() + expect(sc!.sidechainId).toBe('msg-task') + }) + + it('does not assign sidechainId when prompt does not match', () => { + const taskMsg = makeToolCallMsg('msg-task', 'Task', 'original prompt') + const sidechainRoot = makeSidechainRootMsg('sc-root', 'different prompt') + + const result = traceMessages([taskMsg, sidechainRoot]) + const sc = result.find(m => m.id === 'sc-root') + expect(sc).toBeDefined() + expect(sc!.sidechainId).toBeUndefined() + }) +}) + +// --------------------------------------------------------------------------- +// Agent — new SDK tool name (regression fix) +// --------------------------------------------------------------------------- + +describe('traceMessages — Agent tool name (regression fix)', () => { + it('indexes Agent prompt and matches sidechain root to the Agent message', () => { + const prompt = 'explore the repo structure' + const agentMsg = makeToolCallMsg('msg-agent', 'Agent', prompt) + const sidechainRoot = makeSidechainRootMsg('sc-root', prompt) + + const result = traceMessages([agentMsg, sidechainRoot]) + const sc = result.find(m => m.id === 'sc-root') + expect(sc).toBeDefined() + // Before fix: sidechainId would be undefined because 'Agent' was not indexed + expect(sc!.sidechainId).toBe('msg-agent') + }) + + it('does not assign sidechainId when Agent prompt does not match', () => { + const agentMsg = makeToolCallMsg('msg-agent', 'Agent', 'original prompt') + const sidechainRoot = makeSidechainRootMsg('sc-root', 'different prompt') + + const result = traceMessages([agentMsg, sidechainRoot]) + const sc = result.find(m => m.id === 'sc-root') + expect(sc!.sidechainId).toBeUndefined() + }) + + it('handles both Task and Agent in the same message list', () => { + const taskPrompt = 'task prompt' + const agentPrompt = 'agent prompt' + const taskMsg = makeToolCallMsg('msg-task', 'Task', taskPrompt) + const agentMsg = makeToolCallMsg('msg-agent', 'Agent', agentPrompt) + const scForTask = makeSidechainRootMsg('sc-task', taskPrompt) + const scForAgent = makeSidechainRootMsg('sc-agent', agentPrompt) + + const result = traceMessages([taskMsg, agentMsg, scForTask, scForAgent]) + const scTaskResult = result.find(m => m.id === 'sc-task') + const scAgentResult = result.find(m => m.id === 'sc-agent') + expect(scTaskResult!.sidechainId).toBe('msg-task') + expect(scAgentResult!.sidechainId).toBe('msg-agent') + }) +}) diff --git a/web/src/chat/tracer.ts b/web/src/chat/tracer.ts index db3981c8..41c7523b 100644 --- a/web/src/chat/tracer.ts +++ b/web/src/chat/tracer.ts @@ -1,5 +1,6 @@ import type { NormalizedMessage } from '@/chat/types' import { isObject } from '@hapi/protocol' +import { isSubagentToolName } from '@/chat/subagentTool' export type TracedMessage = NormalizedMessage & { sidechainId?: string @@ -58,11 +59,11 @@ export function traceMessages(messages: NormalizedMessage[]): TracedMessage[] { const results: TracedMessage[] = [] - // Index Task prompts (including those inside sidechains). + // Index Task/Agent prompts (including those inside sidechains). for (const message of messages) { if (message.role !== 'agent') continue for (const content of message.content) { - if (content.type !== 'tool-call' || content.name !== 'Task') continue + if (content.type !== 'tool-call' || !isSubagentToolName(content.name)) continue const input = content.input if (!isObject(input) || typeof input.prompt !== 'string') continue state.promptToTaskId.set(input.prompt, message.id) diff --git a/web/src/components/AssistantChat/messages/ToolMessage.tsx b/web/src/components/AssistantChat/messages/ToolMessage.tsx index 7a260ab4..680c6c7f 100644 --- a/web/src/components/AssistantChat/messages/ToolMessage.tsx +++ b/web/src/components/AssistantChat/messages/ToolMessage.tsx @@ -2,6 +2,7 @@ import type { ToolCallMessagePartProps } from '@assistant-ui/react' import type { ChatBlock } from '@/chat/types' import type { ToolCallBlock } from '@/chat/types' import { isObject, safeStringify } from '@hapi/protocol' +import { isSubagentToolName } from '@/chat/subagentTool' import { getEventPresentation } from '@/chat/presentation' import { CodeBlock } from '@/components/CodeBlock' import { MarkdownRenderer } from '@/components/MarkdownRenderer' @@ -109,7 +110,7 @@ function HappyNestedBlockList(props: { } if (block.kind === 'tool-call') { - const isTask = block.tool.name === 'Task' + const isTask = isSubagentToolName(block.tool.name) const taskChildren = isTask ? splitTaskChildren(block) : null return ( @@ -199,7 +200,7 @@ export function HappyToolMessage(props: ToolCallMessagePartProps) { } const block = artifact - const isTask = block.tool.name === 'Task' + const isTask = isSubagentToolName(block.tool.name) const taskChildren = isTask ? splitTaskChildren(block) : null return ( diff --git a/web/src/components/ToolCard/ToolCard.tsx b/web/src/components/ToolCard/ToolCard.tsx index 302fa742..43ec77de 100644 --- a/web/src/components/ToolCard/ToolCard.tsx +++ b/web/src/components/ToolCard/ToolCard.tsx @@ -22,6 +22,7 @@ import { getInputString, getInputStringAny, truncate } from '@/lib/toolInputUtil import { cn } from '@/lib/utils' import { useTranslation } from '@/lib/use-translation' import { TraceSection } from '@/components/ToolCard/trace' +import { isSubagentToolName } from '@/chat/subagentTool' const ELAPSED_INTERVAL_MS = 1000 @@ -47,7 +48,7 @@ function ElapsedView(props: { from: number; active: boolean }) { } function getTaskSummaryChildren(block: ToolCallBlock): { visible: ToolCallBlock[]; remaining: number } | null { - if (block.tool.name !== 'Task') return null + if (!isSubagentToolName(block.tool.name)) return null const children = block.children .filter((child): child is ToolCallBlock => child.kind === 'tool-call') @@ -126,7 +127,7 @@ function renderToolInput(block: ToolCallBlock, surface: 'inline' | 'dialog' = 'i const toolName = block.tool.name const input = block.tool.input - if (toolName === 'Task' && isObject(input) && typeof input.prompt === 'string') { + if (isSubagentToolName(toolName) && isObject(input) && typeof input.prompt === 'string') { return } @@ -287,7 +288,7 @@ function ToolCardInner(props: ToolCardProps) { const subtitle = presentation.subtitle ?? props.block.tool.description const taskSummary = renderTaskSummary(props.block, props.metadata, t) const runningFrom = props.block.tool.startedAt ?? props.block.tool.createdAt - const showInline = !presentation.minimal && toolName !== 'Task' + const showInline = !presentation.minimal && !isSubagentToolName(toolName) const CompactToolView = showInline ? getToolViewComponent(toolName) : null const FullToolView = getToolFullViewComponent(toolName) const ResultToolView = getToolResultViewComponent(toolName) diff --git a/web/src/components/ToolCard/knownTools.tsx b/web/src/components/ToolCard/knownTools.tsx index 22e25f0e..f7aaa546 100644 --- a/web/src/components/ToolCard/knownTools.tsx +++ b/web/src/components/ToolCard/knownTools.tsx @@ -294,13 +294,16 @@ export const knownTools: Record , title: (opts) => { const description = getInputStringAny(opts.input, ['description']) - return description ?? 'Agent' + return description ?? 'Launch Agent' }, subtitle: (opts) => { + // Subagent invocation: show prompt preview (same as Task) + const prompt = getInputStringAny(opts.input, ['prompt']) + if (prompt) return truncate(prompt, 120) const model = getInputStringAny(opts.input, ['subagent_type']) return model ?? null }, - minimal: true + minimal: (opts) => opts.childrenCount === 0 }, CodexReasoning: { icon: () => , diff --git a/web/src/components/ToolCard/trace.test.tsx b/web/src/components/ToolCard/trace.test.tsx index aca29034..a9928849 100644 --- a/web/src/components/ToolCard/trace.test.tsx +++ b/web/src/components/ToolCard/trace.test.tsx @@ -95,6 +95,31 @@ function makeTaskBlock( } } +function makeAgentBlock( + children: ToolCallBlock[], + state: ToolCallBlock['tool']['state'] = 'completed', + result: unknown = null, +): ToolCallBlock { + return { + kind: 'tool-call', + id: 'agent-1', + localId: null, + createdAt: 1000, + tool: { + id: 'agent-1', + name: 'Agent', + state, + input: { prompt: 'do stuff', subagent_type: 'general-purpose' }, + createdAt: 1000, + startedAt: 1000, + completedAt: 2000, + description: null, + result, + }, + children, + } +} + // --------------------------------------------------------------------------- // getTaskTraceChildren // --------------------------------------------------------------------------- @@ -139,6 +164,22 @@ describe('getTaskTraceChildren', () => { } expect(getTaskTraceChildren(block)).toBeNull() }) + + // Agent tool name (new SDK name for subagent invocations) + it('returns children for Agent blocks (same as Task)', () => { + const block = makeAgentBlock([ + makeChild('c1', 'Glob'), + makeChild('c2', 'Grep'), + ]) + const result = getTaskTraceChildren(block) + expect(result).not.toBeNull() + expect(result!.length).toBe(2) + }) + + it('returns null for Agent block with no tool-call children', () => { + const block = makeAgentBlock([]) + expect(getTaskTraceChildren(block)).toBeNull() + }) }) // --------------------------------------------------------------------------- @@ -267,4 +308,29 @@ describe('TraceSection', () => { // Result section label must also be present expect(screen.getByText('Result')).toBeInTheDocument() }) + + // Agent tool name — same Trace UX as Task + it('renders Trace header for Agent blocks', () => { + const block = makeAgentBlock([makeChild('c1', 'Glob'), makeChild('c2', 'Grep')]) + const { container } = render() + // TraceSection must mount (non-null) for Agent blocks + expect(container.firstChild).not.toBeNull() + // header button with aria-expanded attribute must exist + const btn = container.querySelector('button[aria-expanded]') + expect(btn).not.toBeNull() + }) + + it('renders nothing for Agent block with no children', () => { + const block = makeAgentBlock([]) + const { container } = render() + expect(container.firstChild).toBeNull() + }) + + it('expands Agent trace by default when running', () => { + const block = makeAgentBlock([makeChild('c1', 'Read')], 'running') + const { container } = render() + const headerBtn = container.querySelector('button[aria-expanded="true"]') + expect(headerBtn).not.toBeNull() + expect(container.querySelector('.border-l')).not.toBeNull() + }) }) diff --git a/web/src/components/ToolCard/trace.tsx b/web/src/components/ToolCard/trace.tsx index ad433861..54fd6639 100644 --- a/web/src/components/ToolCard/trace.tsx +++ b/web/src/components/ToolCard/trace.tsx @@ -1,5 +1,5 @@ /** - * TraceSection — shows child tool calls inside a Task tool dialog. + * TraceSection — shows child tool calls inside a Task/Agent tool dialog. * Placed between Input and Result sections. */ import { useState } from 'react' @@ -11,6 +11,7 @@ import { getToolResultViewComponent } from '@/components/ToolCard/views/_results import { formatTaskChildLabel, TaskStateIcon } from '@/components/ToolCard/helpers' import { CodeBlock } from '@/components/CodeBlock' import { useTranslation } from '@/lib/use-translation' +import { isSubagentToolName } from '@/chat/subagentTool' // --------------------------------------------------------------------------- // Result type narrowing (trace.tsx-internal; do NOT move to shared protocol) @@ -46,10 +47,10 @@ type _TaskToolResultSummary = TaskToolResultSummary // --------------------------------------------------------------------------- /** - * Returns tool-call children of the given Task block, or null if none exist. + * Returns tool-call children of the given Task/Agent block, or null if none exist. */ export function getTaskTraceChildren(block: ToolCallBlock): ToolCallBlock[] | null { - if (block.tool.name !== 'Task') return null + if (!isSubagentToolName(block.tool.name)) return null const children = block.children.filter( (c): c is ToolCallBlock => c.kind === 'tool-call', ) diff --git a/web/src/components/ToolCard/views/_all.tsx b/web/src/components/ToolCard/views/_all.tsx index f4fd73d2..ed8c2148 100644 --- a/web/src/components/ToolCard/views/_all.tsx +++ b/web/src/components/ToolCard/views/_all.tsx @@ -11,7 +11,6 @@ import { MultiEditFullView, MultiEditView } from '@/components/ToolCard/views/Mu import { TodoWriteView } from '@/components/ToolCard/views/TodoWriteView' import { UpdatePlanView } from '@/components/ToolCard/views/UpdatePlanView' import { WriteView } from '@/components/ToolCard/views/WriteView' -import { isObject } from '@hapi/protocol' import { getInputStringAny } from '@/lib/toolInputUtils' export type ToolViewProps = { @@ -31,25 +30,6 @@ const SkillFullView: ToolViewComponent = ({ block }: ToolViewProps) => { ) } -const AgentFullView: ToolViewComponent = ({ block }: ToolViewProps) => { - const input = block.tool.input - const description = getInputStringAny(input, ['description']) - const subagentType = getInputStringAny(input, ['subagent_type']) - const runInBackground = isObject(input) && input.run_in_background === true - - return ( -
- {description && ( -
{description}
- )} -
- {subagentType && Type: {subagentType}} - {runInBackground && Background} -
-
- ) -} - export const toolViewRegistry: Record = { Edit: EditView, MultiEdit: MultiEditView, @@ -71,7 +51,6 @@ export const toolFullViewRegistry: Record = { CodexDiff: CodexDiffFullView, CodexPatch: CodexPatchView, Skill: SkillFullView, - Agent: AgentFullView, AskUserQuestion: AskUserQuestionView, ExitPlanMode: ExitPlanModeView, ask_user_question: AskUserQuestionView, diff --git a/web/src/components/ToolCard/views/_results.test.tsx b/web/src/components/ToolCard/views/_results.test.tsx index fcf44912..d2259cb5 100644 --- a/web/src/components/ToolCard/views/_results.test.tsx +++ b/web/src/components/ToolCard/views/_results.test.tsx @@ -138,6 +138,12 @@ describe('getToolResultViewComponent registry', () => { it('uses a dedicated result view for CodexBash', () => { expect(getToolResultViewComponent('CodexBash')).not.toBe(getToolResultViewComponent('SomeUnknownTool')) }) + + it('Agent falls back to GenericResultView (no dedicated view — view layer must not filter content)', () => { + const agentView = getToolResultViewComponent('Agent') + const genericView = getToolResultViewComponent('SomeUnknownTool') + expect(agentView).toBe(genericView) + }) }) describe('dialog result formatting', () => { diff --git a/web/src/components/ToolCard/views/_results.tsx b/web/src/components/ToolCard/views/_results.tsx index 03239cbc..a3148252 100644 --- a/web/src/components/ToolCard/views/_results.tsx +++ b/web/src/components/ToolCard/views/_results.tsx @@ -751,46 +751,6 @@ const TodoWriteResultView: ToolViewComponent = (props: ToolViewProps) => { return } -const AgentResultView: ToolViewComponent = (props: ToolViewProps) => { - const { state, result } = props.block.tool - - if (result === undefined || result === null) { - return - } - - // For errors, show the error text - if (state === 'error') { - const text = extractTextFromResult(result) - return ( -
- {text?.trim() ? text : 'Agent failed'} -
- ) - } - - const text = extractTextFromResult(result) - if (!text) { - return - } - - // Detect internal launch metadata. Check structurally first (result object - // may carry agentId/output_file keys), then fall back to a strict text - // pattern that is unlikely to appear in normal agent prose. - const isInternalMeta = isObject(result) && ('agentId' in result || 'output_file' in result) - || (text.startsWith('Async agent launched successfully.') && text.includes('agentId:')) - - if (isInternalMeta) { - return - } - - return ( - <> - {renderResultBody(renderMarkdown(text, props.surface), props.surface)} - - - ) -} - const SkillResultView: ToolViewComponent = (props: ToolViewProps) => { const { state, result, input } = props.block.tool @@ -889,7 +849,6 @@ export const toolResultViewRegistry: Record = { CodexPatch: CodexPatchResultView, CodexDiff: CodexDiffResultView, Skill: SkillResultView, - Agent: AgentResultView, AskUserQuestion: AskUserQuestionResultView, ExitPlanMode: MarkdownResultView, ask_user_question: AskUserQuestionResultView,