Skip to content

feat(chat): unified tool execution rendering for agents - #4192

Open
kylexu88 wants to merge 31 commits into
iOfficeAI:mainfrom
kylexu88:feature/refactor-tool-execution-ui
Open

feat(chat): unified tool execution rendering for agents#4192
kylexu88 wants to merge 31 commits into
iOfficeAI:mainfrom
kylexu88:feature/refactor-tool-execution-ui

Conversation

@kylexu88

Copy link
Copy Markdown

Description

Unify tool execution rendering across all agent backends (claude, codex, aionrs, opencode, gemini-acp, …).

The old three components (MessageToolCall / MessageAcpToolCall / MessageToolGroup) each rendered tool calls with their own visual language and were incompatible with multi-agent grouping. This PR replaces them with a single UnifiedToolBlock pipeline:

  • Normalize tool_call / acp_tool_call / tool_group frames into one UnifiedToolBlock shape
  • Category cards (read/edit/bash/generic/task/todo) with per-tool icons and i18n titles
  • Parent partitioning + segment grouping so subagent steps nest under their launching Task
  • Collapsible bodies with status dots
  • Description display fix: prefer the model-authored description in ACP summaries, and fall back to the truncated command in bash headers when no description exists

Backed by unit + DOM tests (normalization, per-block rendering, grouping, truncation).

Related Issues

N/A

Type of Change

  • feat — New feature (non-breaking change which adds functionality)

Atomic PR Checklist (Rule 1)

  • This PR contains exactly one feature or bug fix that cannot be further decomposed
  • The PR title follows Conventional Commit format: <type>(<scope>): <subject> (English)

Local Checks (Rule 3)

  • bun run format — formatting passes
  • bun run lint — no lint errors
  • bunx tsc --noEmit — no type errors
  • bunx vitest run — tests pass (4866 tests)
  • i18n validated (bun run i18n:types + node scripts/check-i18n.js)
  • New/changed user-facing text uses i18n keys (no hardcoded strings)

Runtime Verification

  • Verified on macOS
  • Verified on Windows
  • Verified on Linux
  • I have performed a self-review of my own code

Additional Context

Real-agent manual regression (claude/codex/aionrs/opencode) not yet done — requires Electron interaction.

Introduce ToolCategory and helpers for the unified tool-execution render
pipeline (Task 1 of the refactor plan):

- categorizeToolName maps agent tool names (Edit/Bash/Read/Grep/Task/...)
  case-insensitively to a shared category, falling back to `generic` so
  new agents always have a render path.
- mapAcpKindToCategory maps ACP update.kind values to the same category
  set (backend already normalizes the kind).
- TOOL_BLOCK_META provides the i18n title key and icon-park icon name
  for each category; icon names are placeholders to be verified in Task 5.

Also extend vitest.config.ts to discover colocated node tests under
packages/desktop/src/**/*.test.ts (and dom variants under the dom
project), so the plan's `bunx vitest run <colocated file>` workflow
works. This also unblocks two existing colocated tests that were
previously outside the include globs.
Known categories (bash/read/edit/task/todo) now show the translated
action title in the header, matching the reference design; only generic
tools keep the raw tool name. Bash timeline rows prefer description
over command, and title/summary/icon colors follow the reference
hierarchy (secondary/tertiary/primary, icon 16px).
ACP tool titles are natural-language descriptions that can equal the
summary extracted from rawInput, rendering the same text twice in the
header. The summary now only renders when it differs from the title.
Tool block headers now show a human tool name like the reference
project: known tool names map to specific action titles (write file,
replace string, apply patch, glob -> file match, web fetch...), generic
command tools are classified by what the command does (cat -> read
file, ls -> list files, grep -> search), and unknown names are
prettified (snake_case/CamelCase -> spaced words). Adds the 15 new
title keys across all 13 languages.
Tool blocks now pick icons by tool name like the reference design:
write gets a pencil, glob a folder, web fetch a globe, delete a trash
bin, todo/plan a checklist, read an eye. Generic command tools refine
the icon by what the command does (cat -> eye, ls -> folder, grep ->
search); the dedicated bash block keeps its fixed terminal icon.
Agent tool names like ReadFile/ListDirectory/SearchText/RunCommand
(gemini/codex style, no underscores) previously missed the exact-match
tables and fell back to the generic toolkit icon. Both the title and
icon tables now cover these variants.
Claude-style backends put the natural-language tool description into
the tool_call name field (e.g. name="查看主进程各模块文件" with
args={command,...}), so name-based categorization always fell back to
the generic toolkit block. When the name does not match a known tool,
the category is now inferred from the raw arg signature
(command->bash, file_path->read, old_string/edits/content->edit,
url/pattern/query->search, todos->todo, subagent_type->task). The same
fallback covers ACP calls whose kind was narrowed away by the
backend.
Expanded tool bodies previously showed only the output; the reference
layout renders the executed command above the output. The bash
timeline rows, task step rows now render the command block too, and
command-only steps became expandable.
Consecutive read/edit/search blocks previously merged into one mixed
list segment labeled "文件操作" with a fixed read icon. Lists now
group by category so each segment header names the action (读取文件 /
编辑文件 / 搜索) with the matching icon, and consecutive task blocks
render as individual subagent cards instead of list rows. Drops the
now-unused fileOpsTitle key.
Grouped segments always hold 2+ blocks, so their headers switch from
single-action wording ("read file") to the reference project's batch
wording ("batch read files", "batch run commands").
The task icon key came from the raw tool name, which for claude is a
natural-language description, so the block fell back to the generic
toolkit icon. Subagent steps rendered as compact rows instead of the
same full blocks used for top-level tool calls.
When a bash call has no description, the header summary fell back to the
full command line, which got hard-clipped in narrow nested contexts. The
command now lives only in the expanded body, matching the reference layout.
The grid 0fr collapse left the inner row at its min-content height
because the grid item lacked min-height: 0, so a sliver of the body
leaked through below the header. The separator border now only renders
when open.
…d in bash headers

ACP-path tool blocks ignored a model-authored description in rawInput for
non-task categories, so agents sending one rendered a bare operand instead.
Align the acp_tool_call summary extraction with the tool_call path by
preferring description. Bash blocks whose agent provides no description
(codex, aionrs) now fall back to a truncated command in the header so it is
never empty.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant