diff --git a/crates/agent-gateway/web/src/lib/chat/uiMessages.ts b/crates/agent-gateway/web/src/lib/chat/uiMessages.ts index e94893b4..4145daed 100644 --- a/crates/agent-gateway/web/src/lib/chat/uiMessages.ts +++ b/crates/agent-gateway/web/src/lib/chat/uiMessages.ts @@ -143,9 +143,10 @@ function summarizeBashTimeout(value: unknown) { export function summarizeToolCall( toolCall: ToolCall, - options?: { includeName?: boolean }, + options?: { includeName?: boolean; includeManagerAction?: boolean }, ) { const includeName = options?.includeName ?? true; + const includeManagerAction = options?.includeManagerAction ?? true; const args = toolCall.arguments || {}; const name = toolCall.name; const path = summarizeToolArg(args.path); @@ -207,7 +208,9 @@ export function summarizeToolCall( ] : name === "SkillsManager" ? [ - typeof args.action === "string" ? `action=${args.action}` : null, + includeManagerAction && typeof args.action === "string" + ? `action=${args.action}` + : null, path ? `path=${path}` : null, typeof args.offset === "number" ? `start=${args.offset + 1}` : null, typeof args.length === "number" ? `limit=${args.length}` : null, @@ -215,9 +218,20 @@ export function summarizeToolCall( typeof args.name === "string" ? `name=${summarizeToolArg(args.name)}` : null, typeof args.conflict === "string" ? `conflict=${summarizeToolArg(args.conflict)}` : null, ] + : name === "CronTaskManager" + ? [ + includeManagerAction && typeof args.action === "string" + ? `action=${args.action}` + : null, + typeof args.task_id === "string" ? `task=${summarizeToolArg(args.task_id)}` : null, + typeof args.name === "string" ? `name=${summarizeToolArg(args.name)}` : null, + typeof args.type === "string" ? `type=${summarizeToolArg(args.type)}` : null, + ] : name === "MemoryManager" ? [ - typeof args.action === "string" ? `action=${args.action}` : null, + includeManagerAction && typeof args.action === "string" + ? `action=${args.action}` + : null, typeof args.slug === "string" ? `slug=${summarizeToolArg(args.slug)}` : null, typeof args.scope === "string" ? `scope=${summarizeToolArg(args.scope)}` : null, typeof args.type === "string" ? `type=${summarizeToolArg(args.type)}` : null, @@ -225,12 +239,41 @@ export function summarizeToolCall( ] : name === "McpManager" ? [ - typeof args.action === "string" ? `action=${args.action}` : null, + includeManagerAction && typeof args.action === "string" + ? `action=${args.action}` + : null, typeof args.server_id === "string" ? `server=${summarizeToolArg(args.server_id)}` : null, Array.isArray(args.server_ids) ? `servers=${args.server_ids.length}` : null, typeof args.conflict === "string" ? `conflict=${summarizeToolArg(args.conflict)}` : null, args.include_schema === true ? "includeSchema=true" : null, ] + : name === "TunnelManager" + ? [ + includeManagerAction && typeof args.action === "string" + ? `action=${args.action}` + : null, + typeof args.targetUrl === "string" + ? `target=${summarizeToolArg(args.targetUrl)}` + : null, + typeof args.slug === "string" ? `slug=${summarizeToolArg(args.slug)}` : null, + typeof args.id === "string" ? `id=${summarizeToolArg(args.id)}` : null, + ] + : name === "SSHManager" || name === "SshManager" + ? [ + includeManagerAction && typeof args.action === "string" + ? `action=${args.action}` + : null, + typeof args.host_id === "string" + ? `host=${summarizeToolArg(args.host_id)}` + : null, + typeof args.session_id === "string" + ? `session=${summarizeToolArg(args.session_id)}` + : null, + typeof args.path === "string" ? `path=${path}` : null, + typeof args.command === "string" + ? `command=${summarizeToolArg(args.command)}` + : null, + ] : name === "Agent" ? [ typeof args.agent_id === "string" ? `agent=${summarizeToolArg(args.agent_id)}` : null, diff --git a/crates/agent-gateway/web/src/pages/chat/AssistantBubble.tsx b/crates/agent-gateway/web/src/pages/chat/AssistantBubble.tsx index e27f01bb..a2d4a2f0 100644 --- a/crates/agent-gateway/web/src/pages/chat/AssistantBubble.tsx +++ b/crates/agent-gateway/web/src/pages/chat/AssistantBubble.tsx @@ -3,6 +3,7 @@ import type { ImageContent, ToolResultMessage, Usage } from "../../lib/agentType import { Bot, Brain, + Clock3, ChevronRight, Eye, ImageIcon, @@ -11,6 +12,7 @@ import { FilePenLine, FolderTree, Loader2, + Link2, Plug, Search, Server, @@ -488,8 +490,10 @@ function getToolMeta(name: string): { Icon: IconComponent; accent: string; categ case "Read": return { Icon: Eye, accent: "var(--tool-file-accent)", category: "file" }; case "Image": return { Icon: ImageIcon, accent: "var(--tool-file-accent)", category: "file" }; case "SkillsManager": return { Icon: Eye, accent: "var(--tool-file-accent)", category: "file" }; + case "CronTaskManager": return { Icon: Clock3, accent: "var(--tool-list-accent)", category: "system" }; case "MemoryManager": return { Icon: Brain, accent: "var(--tool-list-accent)", category: "system" }; case "McpManager": return { Icon: Plug, accent: "var(--tool-list-accent)", category: "mcp" }; + case "TunnelManager": return { Icon: Link2, accent: "var(--tool-list-accent)", category: "system" }; case "SSHManager": case "SshManager": return { Icon: Server, accent: "var(--tool-bash-accent)", category: "terminal" }; case "Agent": return { Icon: Bot, accent: "var(--tool-list-accent)", category: "system" }; @@ -667,6 +671,39 @@ function getToolDisplayName(name: string) { return name; } +const TOOL_CARD_ACTION_NAMES = new Set([ + "SkillsManager", + "CronTaskManager", + "McpManager", + "MemoryManager", + "TunnelManager", + "SSHManager", +]); + +function getManagerToolActionName(toolCall: { + name: string; + arguments?: Record; +}) { + const name = getToolDisplayName(toolCall.name); + if (!TOOL_CARD_ACTION_NAMES.has(name)) return ""; + const args = toolCall.arguments || {}; + const action = displayString(args.action); + if (action) return action; + if (name === "SkillsManager") { + return displayString(args.path) ? "read" : "list"; + } + return ""; +} + +function getToolDisplayTitle(toolCall: { + name: string; + arguments?: Record; +}) { + const name = getToolDisplayName(toolCall.name); + const action = getManagerToolActionName(toolCall); + return { name, action }; +} + function groupRoundBlocks(blocks: UiRound["blocks"]): GroupedRoundBlock[] { const groupedBlocks: GroupedRoundBlock[] = []; let pendingTools: ToolTraceItem[] = []; @@ -2355,6 +2392,7 @@ function isBuiltinShareToolName(name: string) { "SkillsManager", "SSHManager", "SshManager", + "TunnelManager", "Write", ].includes(trimmed); } @@ -2393,9 +2431,15 @@ function ToolCallItem({ ? "" : isDelegateAgentCard ? getDelegateAgentInlineSummary(item) - : summarizeToolCall(item.toolCall, { includeName: false }); + : summarizeToolCall(item.toolCall, { + includeName: false, + includeManagerAction: false, + }); const meta = getToolMeta(item.toolCall.name); const ToolIcon = meta.Icon; + const title = isRedactedToolContent + ? { name: getToolDisplayName(item.toolCall.name), action: "" } + : getToolDisplayTitle(item.toolCall); const dotClass = isRunning ? "bg-[hsl(var(--chat-running))] animate-pulse" @@ -2449,7 +2493,13 @@ function ToolCallItem({
- {getToolDisplayName(item.toolCall.name)} + {title.name} + {title.action ? ( + + {" · "} + {title.action} + + ) : null} {isBash && firstLine ? ( diff --git a/crates/agent-gui/src/lib/chat/messages/uiMessages.ts b/crates/agent-gui/src/lib/chat/messages/uiMessages.ts index 6cd7a6ba..2dcfc28a 100644 --- a/crates/agent-gui/src/lib/chat/messages/uiMessages.ts +++ b/crates/agent-gui/src/lib/chat/messages/uiMessages.ts @@ -136,8 +136,12 @@ function summarizeBashTimeout(value: unknown) { : `timeout_ms=${effective} (requested ${requested})`; } -export function summarizeToolCall(toolCall: ToolCall, options?: { includeName?: boolean }) { +export function summarizeToolCall( + toolCall: ToolCall, + options?: { includeName?: boolean; includeManagerAction?: boolean }, +) { const includeName = options?.includeName ?? true; + const includeManagerAction = options?.includeManagerAction ?? true; const args = toolCall.arguments || {}; const name = toolCall.name; const path = summarizeToolArg(args.path); @@ -200,7 +204,9 @@ export function summarizeToolCall(toolCall: ToolCall, options?: { includeName?: ] : name === "SkillsManager" ? [ - typeof args.action === "string" ? `action=${args.action}` : null, + includeManagerAction && typeof args.action === "string" + ? `action=${args.action}` + : null, path ? `path=${path}` : null, typeof args.offset === "number" ? `start=${args.offset + 1}` : null, typeof args.length === "number" ? `limit=${args.length}` : null, @@ -210,138 +216,192 @@ export function summarizeToolCall(toolCall: ToolCall, options?: { includeName?: ? `conflict=${summarizeToolArg(args.conflict)}` : null, ] - : name === "MemoryManager" + : name === "CronTaskManager" ? [ - typeof args.action === "string" ? `action=${args.action}` : null, - typeof args.slug === "string" ? `slug=${summarizeToolArg(args.slug)}` : null, - typeof args.scope === "string" ? `scope=${summarizeToolArg(args.scope)}` : null, + includeManagerAction && typeof args.action === "string" + ? `action=${args.action}` + : null, + typeof args.task_id === "string" ? `task=${summarizeToolArg(args.task_id)}` : null, + typeof args.name === "string" ? `name=${summarizeToolArg(args.name)}` : null, typeof args.type === "string" ? `type=${summarizeToolArg(args.type)}` : null, - typeof args.query === "string" ? `query=${summarizeToolArg(args.query)}` : null, ] - : name === "McpManager" + : name === "MemoryManager" ? [ - typeof args.action === "string" ? `action=${args.action}` : null, - typeof args.server_id === "string" - ? `server=${summarizeToolArg(args.server_id)}` + includeManagerAction && typeof args.action === "string" + ? `action=${args.action}` : null, - Array.isArray(args.server_ids) ? `servers=${args.server_ids.length}` : null, - typeof args.conflict === "string" - ? `conflict=${summarizeToolArg(args.conflict)}` - : null, - args.include_schema === true ? "includeSchema=true" : null, + typeof args.slug === "string" ? `slug=${summarizeToolArg(args.slug)}` : null, + typeof args.scope === "string" ? `scope=${summarizeToolArg(args.scope)}` : null, + typeof args.type === "string" ? `type=${summarizeToolArg(args.type)}` : null, + typeof args.query === "string" ? `query=${summarizeToolArg(args.query)}` : null, ] - : name === "Agent" + : name === "McpManager" ? [ - typeof args.agent_id === "string" - ? `agent=${summarizeToolArg(args.agent_id)}` + includeManagerAction && typeof args.action === "string" + ? `action=${args.action}` : null, - typeof args.name === "string" ? `name=${summarizeToolArg(args.name)}` : null, - typeof args.prompt === "string" - ? `prompt=${summarizeToolArg(args.prompt)}` + typeof args.server_id === "string" + ? `server=${summarizeToolArg(args.server_id)}` : null, - typeof args.agent_spec === "string" - ? `agentSpecChars=${args.agent_spec.length}` + Array.isArray(args.server_ids) ? `servers=${args.server_ids.length}` : null, + typeof args.conflict === "string" + ? `conflict=${summarizeToolArg(args.conflict)}` : null, - typeof args.mode === "string" ? `mode=${summarizeToolArg(args.mode)}` : null, - typeof args.concurrency === "number" ? `concurrency=${args.concurrency}` : null, + args.include_schema === true ? "includeSchema=true" : null, ] - : name === "SendMessage" + : name === "TunnelManager" ? [ - typeof args.to === "string" ? `to=${summarizeToolArg(args.to)}` : null, - typeof args.channel === "string" - ? `channel=${summarizeToolArg(args.channel)}` - : null, - typeof args.subject === "string" - ? `subject=${summarizeToolArg(args.subject)}` + includeManagerAction && typeof args.action === "string" + ? `action=${args.action}` : null, - typeof args.summary === "string" && typeof args.subject !== "string" - ? `summary=${summarizeToolArg(args.summary)}` - : null, - typeof args.message === "string" - ? `messageChars=${args.message.length}` + typeof args.targetUrl === "string" + ? `target=${summarizeToolArg(args.targetUrl)}` : null, + typeof args.slug === "string" ? `slug=${summarizeToolArg(args.slug)}` : null, + typeof args.id === "string" ? `id=${summarizeToolArg(args.id)}` : null, ] - : name === "Write" + : name === "SSHManager" || name === "SshManager" ? [ - root, - path ? `path=${path}` : null, - "mode=rewrite", - typeof args.content === "string" - ? `contentChars=${args.content.length}` + includeManagerAction && typeof args.action === "string" + ? `action=${args.action}` + : null, + typeof args.host_id === "string" + ? `host=${summarizeToolArg(args.host_id)}` + : null, + typeof args.session_id === "string" + ? `session=${summarizeToolArg(args.session_id)}` + : null, + typeof args.path === "string" ? `path=${path}` : null, + typeof args.command === "string" + ? `command=${summarizeToolArg(args.command)}` : null, ] - : name === "Edit" + : name === "Agent" ? [ - root, - path ? `path=${path}` : null, - typeof args.expected_replacements === "number" - ? `expected=${args.expected_replacements}` + typeof args.agent_id === "string" + ? `agent=${summarizeToolArg(args.agent_id)}` : null, - args.replace_all === true ? "replaceAll=true" : null, - typeof args.old_string === "string" - ? `oldChars=${args.old_string.length}` + typeof args.name === "string" + ? `name=${summarizeToolArg(args.name)}` : null, - typeof args.new_string === "string" - ? `newChars=${args.new_string.length}` + typeof args.prompt === "string" + ? `prompt=${summarizeToolArg(args.prompt)}` + : null, + typeof args.agent_spec === "string" + ? `agentSpecChars=${args.agent_spec.length}` + : null, + typeof args.mode === "string" + ? `mode=${summarizeToolArg(args.mode)}` + : null, + typeof args.concurrency === "number" + ? `concurrency=${args.concurrency}` : null, ] - : name === "List" + : name === "SendMessage" ? [ - root, - path ? `path=${path}` : rootPath, - typeof args.depth === "number" ? `depth=${args.depth}` : null, - typeof args.offset === "number" ? `offset=${args.offset}` : null, - typeof args.max_results === "number" ? `max=${args.max_results}` : null, + typeof args.to === "string" ? `to=${summarizeToolArg(args.to)}` : null, + typeof args.channel === "string" + ? `channel=${summarizeToolArg(args.channel)}` + : null, + typeof args.subject === "string" + ? `subject=${summarizeToolArg(args.subject)}` + : null, + typeof args.summary === "string" && typeof args.subject !== "string" + ? `summary=${summarizeToolArg(args.summary)}` + : null, + typeof args.message === "string" + ? `messageChars=${args.message.length}` + : null, ] - : name === "Glob" + : name === "Write" ? [ root, - typeof args.pattern === "string" - ? `pattern=${summarizeToolArg(args.pattern)}` - : null, - path ? `path=${path}` : rootPath, - typeof args.offset === "number" ? `offset=${args.offset}` : null, - typeof args.max_results === "number" - ? `max=${args.max_results}` + path ? `path=${path}` : null, + "mode=rewrite", + typeof args.content === "string" + ? `contentChars=${args.content.length}` : null, ] - : name === "Grep" + : name === "Edit" ? [ root, - typeof args.pattern === "string" - ? `pattern=${summarizeToolArg(args.pattern)}` + path ? `path=${path}` : null, + typeof args.expected_replacements === "number" + ? `expected=${args.expected_replacements}` : null, - path ? `path=${path}` : rootPath, - typeof args.file_pattern === "string" - ? `filePattern=${summarizeToolArg(args.file_pattern)}` + args.replace_all === true ? "replaceAll=true" : null, + typeof args.old_string === "string" + ? `oldChars=${args.old_string.length}` : null, - typeof args.output_mode === "string" - ? `mode=${args.output_mode}` + typeof args.new_string === "string" + ? `newChars=${args.new_string.length}` : null, - typeof args.ignore_case === "boolean" - ? `ignoreCase=${args.ignore_case}` - : null, - typeof args.context === "number" ? `context=${args.context}` : null, - typeof args.head_limit === "number" - ? `head=${args.head_limit}` - : null, - args.multiline === true ? "multiline=true" : null, - typeof args.offset === "number" ? `offset=${args.offset}` : null, ] - : name === "Delete" - ? [root, path ? `path=${path}` : null] - : name === "Bash" + : name === "List" + ? [ + root, + path ? `path=${path}` : rootPath, + typeof args.depth === "number" ? `depth=${args.depth}` : null, + typeof args.offset === "number" ? `offset=${args.offset}` : null, + typeof args.max_results === "number" + ? `max=${args.max_results}` + : null, + ] + : name === "Glob" ? [ root, - typeof args.cwd === "string" - ? `cwd=${summarizeToolArg(args.cwd)}` - : rootPath, - summarizeBashTimeout(args.timeout_ms), - typeof args.command === "string" - ? `command=${summarizeToolArg(args.command)}` + typeof args.pattern === "string" + ? `pattern=${summarizeToolArg(args.pattern)}` + : null, + path ? `path=${path}` : rootPath, + typeof args.offset === "number" + ? `offset=${args.offset}` + : null, + typeof args.max_results === "number" + ? `max=${args.max_results}` : null, ] - : []; + : name === "Grep" + ? [ + root, + typeof args.pattern === "string" + ? `pattern=${summarizeToolArg(args.pattern)}` + : null, + path ? `path=${path}` : rootPath, + typeof args.file_pattern === "string" + ? `filePattern=${summarizeToolArg(args.file_pattern)}` + : null, + typeof args.output_mode === "string" + ? `mode=${args.output_mode}` + : null, + typeof args.ignore_case === "boolean" + ? `ignoreCase=${args.ignore_case}` + : null, + typeof args.context === "number" + ? `context=${args.context}` + : null, + typeof args.head_limit === "number" + ? `head=${args.head_limit}` + : null, + args.multiline === true ? "multiline=true" : null, + typeof args.offset === "number" + ? `offset=${args.offset}` + : null, + ] + : name === "Delete" + ? [root, path ? `path=${path}` : null] + : name === "Bash" + ? [ + root, + typeof args.cwd === "string" + ? `cwd=${summarizeToolArg(args.cwd)}` + : rootPath, + summarizeBashTimeout(args.timeout_ms), + typeof args.command === "string" + ? `command=${summarizeToolArg(args.command)}` + : null, + ] + : []; const summary = parts.filter(Boolean).join(" "); if (!summary) return includeName ? name : ""; diff --git a/crates/agent-gui/src/pages/chat/components/assistant-bubble/ToolCallItem.tsx b/crates/agent-gui/src/pages/chat/components/assistant-bubble/ToolCallItem.tsx index 06fec7a0..9d272c14 100644 --- a/crates/agent-gui/src/pages/chat/components/assistant-bubble/ToolCallItem.tsx +++ b/crates/agent-gui/src/pages/chat/components/assistant-bubble/ToolCallItem.tsx @@ -17,7 +17,7 @@ import { displayString, getBuiltinResultKind, getDelegateAgentInlineSummary, - getToolDisplayName, + getToolDisplayTitle, getToolMeta, isDelegateAgentCardToolCall, type MetaTag, @@ -293,9 +293,13 @@ function ToolCallItem({ ? "" : isDelegateAgentCard ? getDelegateAgentInlineSummary(item) - : summarizeToolCall(item.toolCall, { includeName: false }); + : summarizeToolCall(item.toolCall, { + includeName: false, + includeManagerAction: false, + }); const meta = getToolMeta(item.toolCall.name); const ToolIcon = meta.Icon; + const title = getToolDisplayTitle(item.toolCall); const dotClass = isRunning ? "bg-[hsl(var(--chat-running))] animate-pulse" @@ -377,7 +381,13 @@ function ToolCallItem({ {/* Tool name + inline summary on same line */}
- {getToolDisplayName(item.toolCall.name)} + {title.name} + {title.action ? ( + + {" · "} + {title.action} + + ) : null} {/* Inline summary — truncated */} diff --git a/crates/agent-gui/src/pages/chat/components/assistant-bubble/assistantBubbleUtils.ts b/crates/agent-gui/src/pages/chat/components/assistant-bubble/assistantBubbleUtils.ts index 3f277690..0a06560b 100644 --- a/crates/agent-gui/src/pages/chat/components/assistant-bubble/assistantBubbleUtils.ts +++ b/crates/agent-gui/src/pages/chat/components/assistant-bubble/assistantBubbleUtils.ts @@ -4,11 +4,13 @@ import type { IconComponent } from "../../../../components/icons"; import { Bot, Brain, + Clock3, Eye, FilePenLine, FileText, FolderTree, ImageIcon, + Link2, Plug, Search, Server, @@ -40,10 +42,14 @@ export function getToolMeta(name: string): { return { Icon: ImageIcon, accent: "var(--tool-file-accent)", category: "file" }; case "SkillsManager": return { Icon: Eye, accent: "var(--tool-file-accent)", category: "file" }; + case "CronTaskManager": + return { Icon: Clock3, accent: "var(--tool-list-accent)", category: "system" }; case "MemoryManager": return { Icon: Brain, accent: "var(--tool-list-accent)", category: "system" }; case "McpManager": return { Icon: Plug, accent: "var(--tool-list-accent)", category: "mcp" }; + case "TunnelManager": + return { Icon: Link2, accent: "var(--tool-list-accent)", category: "system" }; case "SSHManager": case "SshManager": return { Icon: Server, accent: "var(--tool-bash-accent)", category: "terminal" }; @@ -232,6 +238,39 @@ export function getToolDisplayName(name: string) { return name; } +const TOOL_CARD_ACTION_NAMES = new Set([ + "SkillsManager", + "CronTaskManager", + "McpManager", + "MemoryManager", + "TunnelManager", + "SSHManager", +]); + +export function getManagerToolActionName(toolCall: { + name: string; + arguments?: Record; +}) { + const name = getToolDisplayName(toolCall.name); + if (!TOOL_CARD_ACTION_NAMES.has(name)) return ""; + const args = toolCall.arguments || {}; + const action = displayString(args.action); + if (action) return action; + if (name === "SkillsManager") { + return displayString(args.path) ? "read" : "list"; + } + return ""; +} + +export function getToolDisplayTitle(toolCall: { + name: string; + arguments?: Record; +}) { + const name = getToolDisplayName(toolCall.name); + const action = getManagerToolActionName(toolCall); + return { name, action }; +} + export function groupRoundBlocks(blocks: UiRound["blocks"]): GroupedRoundBlock[] { const groupedBlocks: GroupedRoundBlock[] = []; let pendingTools: ToolTraceItem[] = [];