| 31 | |
| 32 | /** One-line human summary of a tool call, shown in the UI. */ |
| 33 | export function describeToolCall(toolName: string, args: Record<string, unknown>): string { |
| 34 | switch (toolName) { |
| 35 | case "read_file": |
| 36 | return String(args.file_path ?? "") |
| 37 | case "file_write": |
| 38 | return String(args.file_path ?? "") |
| 39 | case "file_edit": |
| 40 | return String(args.file_path ?? "") |
| 41 | case "multi_file_edit": { |
| 42 | const edits = Array.isArray(args.edits) ? args.edits : [] |
| 43 | const files = [...new Set(edits.map((e: { file_path?: string }) => e.file_path ?? ""))] |
| 44 | return `${edits.length} edits in ${files.length} file${files.length === 1 ? "" : "s"}` |
| 45 | } |
| 46 | case "execute_command": |
| 47 | return String(args.command ?? "") |
| 48 | case "list_files": |
| 49 | return `${args.path ?? "."}${args.recursive ? " (recursive)" : ""}` |
| 50 | case "search_files": |
| 51 | return `/${args.regex ?? ""}/ in ${args.path ?? "."}${args.file_pattern ? ` (${args.file_pattern})` : ""}` |
| 52 | case "web_search": |
| 53 | return String(args.query ?? "") |
| 54 | case "web_fetch": |
| 55 | return String(args.url ?? "") |
| 56 | case "update_todo_list": |
| 57 | return "updating tasks" |
| 58 | case "use_skill": |
| 59 | return String(args.skill_name ?? "") |
| 60 | case "ask_followup_question": |
| 61 | return String(args.question ?? "") |
| 62 | case "attempt_completion": |
| 63 | return "task complete" |
| 64 | default: |
| 65 | // MCP tools (mcp__<server>__<tool>) — show the server + tool name. |
| 66 | if (/^mcp__/.test(toolName)) { |
| 67 | const match = /^mcp__([^_]+)__(.+)$/.exec(toolName) |
| 68 | return match ? `${match[2]} (${match[1]})` : toolName |
| 69 | } |
| 70 | return toolName |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | const executors: Record<string, (args: Record<string, unknown>, context: ToolContext) => Promise<ToolResult>> = { |
| 75 | read_file: readFile, |