Files
locode/src/ui/toolSummary.ts
T
kimandClaude f347c150a4 v0.6.0: sub-agent orchestration, plan mode, memory, and the Claude-Code feature gap
Closes the gap to Claude Code across four upgrade rounds (all verified
green: typecheck, 388 tests, build 313 KB).

Sub-agent orchestration:
- Resumable sub-agents (send_message) + MaxIterations "continue" path
- Configurable multi-depth sub-agent nesting
- Parallel fan-out for pure agent/agent__* batches, each writable delegation
  in its own throwaway git worktree (no file collisions)
- Named specialist fleet: explore, code-reviewer, planner, debugger,
  test-writer (read-only types skip worktree isolation)
- Named teammates: agent tool `name` arg + list_teammates + send_message
  by name (synchronous, addressable handle — not true async background)

Plan mode:
- True in-turn pause/resume on approval (no synthetic proceed turn)
- exit_plan_mode tool + side-by-side diff rendering (/diff)

Persistent memory:
- Typed file-per-fact memory under config dir, index folded into the
  system prompt (bounded), memory + memory_write tools, /memory command

Toolset + UI:
- multi_edit, notebook_edit, web_search/web_fetch, workflow orchestration
  primitive (agent/parallel/pipeline/phase/log + worktree isolation +
  best-effort structured output with recursive schema validation)
- Structured task system (task_create/list/get/update with dependency
  graph + ownership) replacing flat todo_write
- Cron/scheduled tasks (cron_create/list/delete, schedule_wakeup) with
  durable persistence and idle-gated ticking
- Interactive worktree session (enter_worktree/exit_worktree) with a
  live-cwd UI switch that survives /model changes
- AskUserQuestion tool + QuestionPrompt UI
- Permission rule granularity + user/project settings merge
- Color diffs, sub-agent activity panel, /undo, dashboard refinements

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-16 11:35:05 +09:00

85 lines
3.7 KiB
TypeScript

export function formatCallLabel(name: string, args: unknown): string {
const a = (args && typeof args === "object" ? args : {}) as Record<string, unknown>;
switch (name) {
case "read_file":
return `Read(${a.path ?? ""})`;
case "list_files":
return `List(${a.pattern ?? ""})`;
case "grep":
return `Grep(${a.pattern ?? ""})`;
case "web_search":
return `WebSearch(${a.query ?? ""})`;
case "web_fetch":
return `WebFetch(${a.url ?? ""})`;
case "agent":
return `Agent(${a.description ?? ""})`;
case "ask_user_question":
return `Ask(${(a.questions as any[])?.map((q) => q.header).join("/") ?? ""})`;
case "git_status":
case "git_commit":
return `Git(${a.operation ?? ""})`;
case "write_file":
return `Write(${a.path ?? ""})`;
case "edit_file":
return `Edit(${a.path ?? ""})`;
case "bash":
return `Bash(${a.command ?? ""})`;
default:
return `${name}(${JSON.stringify(args)})`;
}
}
export function summarizeToolResult(toolName: string, result: unknown): string {
if (result && typeof result === "object" && "error" in result) {
return String((result as { error: unknown }).error);
}
if (!result || typeof result !== "object") {
return "done";
}
const r = result as Record<string, unknown>;
switch (toolName) {
case "read_file":
if (r.image === true) {
const kb = typeof r.bytes === "number" ? `${(r.bytes / 1024).toFixed(0)} KB` : "";
return `Read image${r.mimeType ? ` (${r.mimeType}${kb ? `, ${kb}` : ""})` : ""}`;
}
if (r.truncated === true && typeof r.nextOffset === "number" && typeof r.totalLines === "number") {
return `Read ${r.nextOffset - 1} of ${r.totalLines} lines (truncated, next at offset ${r.nextOffset})`;
}
return typeof r.totalLines === "number" ? `Read ${r.totalLines} lines` : "Read file";
case "list_files":
return Array.isArray(r.matches) ? `Found ${r.matches.length} file(s)` : "Listed files";
case "grep":
return Array.isArray(r.matches) ? `Found ${r.matches.length} match(es)` : "Searched";
case "web_search":
return Array.isArray(r.results) ? `Found ${r.results.length} result(s)` : "Searched web";
case "web_fetch":
return typeof r.status === "number" ? `Fetched (HTTP ${r.status})` : "Fetched page";
case "agent":
return typeof r.result === "string" ? `Sub-agent finished (${r.result.length} chars)` : "Sub-agent finished";
case "ask_user_question": {
const ans = Array.isArray(r.answers) ? (r.answers as { question?: string; selected?: string[]; custom?: string }[]) : [];
const parts = ans.map((a) => {
const sel = a.custom ? `"${a.custom}"` : (a.selected ?? []).join(", ");
return `${a.question ?? "??"}: ${sel || "(none)"}`;
});
return parts.length ? `Answered — ${parts.join("; ")}` : "No answer";
}
case "git_status":
return typeof r.output === "string" ? `${r.output.split("\n").filter(Boolean).length} line(s)` : "Ran git query";
case "git_commit":
if (Array.isArray(r.staged)) return `Staged ${r.staged.length} path(s)`;
if (typeof r.created === "string") return `Created branch "${r.created}"`;
if (typeof r.switchedTo === "string") return `Switched to "${r.switchedTo}"`;
return "Done";
case "write_file":
return typeof r.bytesWritten === "number" ? `Wrote ${r.bytesWritten} bytes` : "Wrote file";
case "edit_file":
return typeof r.replacements === "number" ? `Applied ${r.replacements} replacement(s)` : "Edited file";
case "bash":
return typeof r.exitCode === "number" ? `Exit code ${r.exitCode}` : "Ran command";
default:
return "done";
}
}