Skip to content

feat: batch consecutive tool calls in chat UI with shared utility#11245

Open
hannesrudolph wants to merge 8 commits intomainfrom
feat/batch-list-files-ui
Open

feat: batch consecutive tool calls in chat UI with shared utility#11245
hannesrudolph wants to merge 8 commits intomainfrom
feat/batch-list-files-ui

Conversation

@hannesrudolph
Copy link
Collaborator

@hannesrudolph hannesrudolph commented Feb 6, 2026

Closes #11246

After
image

Summary

Consolidates consecutive list_files, read_file, and file-edit tool ask messages into single grouped UI blocks in the chat — reducing visual clutter when the agent performs multiple similar operations in sequence.

Before: Multiple consecutive list_files calls each render their own "Roo wants to view the top level files in this directory" block with repeated headers. Same for consecutive file edits.

After: They collapse into a single block with all paths listed together.

Changes

New files

  • webview-ui/src/utils/batchConsecutive.ts — Generic utility that walks a message array and batches consecutive matches into synthetic messages. Used for all three batching passes (read_file, list_files, file-edits).
  • webview-ui/src/utils/__tests__/batchConsecutive.spec.ts — 11 test cases covering empty input, passthrough, batching, mixed sequences, generic typing, immutability, and edge cases.

Modified files

  • packages/types/src/vscode-extension-host.ts — Added batchDirs property to ClineSayTool interface
  • webview-ui/src/components/chat/ChatView.tsx — Replaced three near-identical batching while-loops (~170 lines) with three batchConsecutive() calls (~70 lines). Added batch button text for listFilesTopLevel/listFilesRecursive and edit-file batches ("Save All"/"Deny All"). Added JSON.parse defense-in-depth in all three synthesizers.
  • webview-ui/src/components/chat/ChatRow.tsx — Merged listFilesTopLevel/listFilesRecursive cases; added batch detection for BatchListFilesPermission; normalized language prop to "shellsession"; moved batchDiffs check before switch for all file-edit tool types. Fixed mixed list_files batch icon to default to FolderTree.
  • webview-ui/src/components/chat/BatchListFilesPermission.tsx — New component for grouped directory listing UI. Fixed React key to include array index.
  • webview-ui/src/components/chat/BatchFilePermission.tsx — Fixed React key to include array index.
  • webview-ui/src/components/chat/BatchDiffApproval.tsx — Fixed React key to include array index.
  • webview-ui/src/components/chat/__tests__/BatchListFilesPermission.spec.tsx — 5 tests covering rendering, empty state, re-render, container structure, and batch icon fallback.
  • webview-ui/src/i18n/locales/en/chat.json — Added wantsToViewMultipleDirectories, dedicated list-batch/edit-batch i18n keys (stop reusing read-batch keys).
  • 17 other locale chat.json files — Added wantsToViewMultipleDirectories; removed unused didViewMultipleDirectories

Audit improvements

The following quality fixes were applied during code review:

  • Generic batchConsecutive() — Refactored from ClineMessage-specific to a fully generic <T> utility, improving reusability and type safety.
  • Edit-batch button text — Added batch-aware "Save All" / "Deny All" button labels for file-edit batches (previously missing).
  • Dedicated i18n keys — Added list-batch.* and edit-batch.* i18n key namespaces instead of reusing read-batch keys for different tool types.
  • JSON.parse defense-in-depth — Wrapped all three batch synthesizers with try/catch around JSON.parse calls to prevent runtime crashes on malformed message content.
  • Mixed list_files batch icon — Fixed icon for batches mixing listFilesTopLevel and listFilesRecursive to default to FolderTree instead of rendering incorrectly.
  • +6 new test cases — Added tests for all-match batching, immutability guarantees, spy-based verification, single-directory edge case, and batch icon fallback.

Footnote — Minor out-of-scope cleanup:
These changes are unrelated to the batch tool-call feature but were discovered during code review and cleaned up while in the area:

  • Trimmed unused recursive/isOutsideWorkspace fields from DirPermissionItem interface in BatchListFilesPermission.tsx (the upstream type in vscode-extension-host.ts retains them)
  • Removed 4 pre-existing as any casts in ChatView.tsx — replaced with proper types (ClineMessage, inline window type, direct bracket access, correct debounce API)

Design rationale — which tools are batched and why

This PR batches only homogeneous, low-context tool calls where the meaningful information is a file/directory path:

Tool type Batched? Reason
list_files ✅ Yes Output is a directory path — multiple listings collapse naturally into a path list
read_file ✅ Yes Output is a file path — multiple reads collapse into a file list with per-file approval
File edits (editedExistingFile, appliedDiff, newFileCreated, insertContent, searchAndReplace) ✅ Yes Output is a diff — multiple edits collapse into expandable per-file diffs
codebaseSearch ❌ No Each search has a unique query returning 20–30 ranked results with scores and code snippets. Batching would lose the query→result mapping.
searchFiles ❌ No Each regex search returns different result counts and patterns. Per-query context is essential.
execute_command ❌ No Commands have different risk profiles. Users must see and approve each one individually (security concern).

Guiding principle: Batch when the per-call output is a simple path or diff. Don't batch when each result has rich, query-specific content that would be lost in a combined view.

Consolidate consecutive listFilesTopLevel/listFilesRecursive ask messages
into a single 'Roo wants to view multiple directories' block, matching the
existing read_file batching pattern.
@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. UI/UX UI/UX related or focused labels Feb 6, 2026
@roomote
Copy link
Contributor

roomote bot commented Feb 6, 2026

Oroocle Clock   See task

The latest commit (c15377e) adds list-batch and edit-batch i18n translations across all 17 non-English locale files. Structure is consistent with the English source and all locales properly differentiate "Approve All" vs "Save All" labels. No new issues found.

  • Consolidate the duplicate batch-handling blocks in ChatRow.tsx for listFilesTopLevel and listFilesRecursive into a single combined case
Previous reviews

Mention @roomote in a comment to request specific changes to this pull request or fix all unresolved issues.

@hannesrudolph hannesrudolph force-pushed the feat/batch-list-files-ui branch from db94d81 to 0160847 Compare February 6, 2026 05:21
…atRow

Merge the separate listFilesTopLevel and listFilesRecursive case blocks
into a single combined case with shared batch-detection logic, selecting
the icon and translation key based on the tool type. This removes the
duplicated isBatchDirRequest check and BatchListFilesPermission render.
Add edit-file batching in ChatView groupedMessages that consolidates
consecutive editedExistingFile, appliedDiff, newFileCreated,
insertContent, and searchAndReplace asks into a single BatchDiffApproval
block. Move batchDiffs detection in ChatRow above the switch statement
so it applies to any file-edit tool type.
- Extract generic batchConsecutive() utility from 3 identical while-loops
- Fix React key collisions in BatchListFilesPermission, BatchFilePermission, BatchDiffApproval
- Normalize language prop to "shellsession" (was "shell-session" for top-level)
- Remove unused _batchedMessages property from synthetic messages
- Remove dead didViewMultipleDirectories i18n key from all 18 locale files
- Add batch button text for listFilesTopLevel/listFilesRecursive
- Add batchConsecutive utility tests (6 cases)
@dosubot dosubot bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels Feb 6, 2026
@hannesrudolph hannesrudolph changed the title feat: group consecutive list_files tool calls into single UI block feat: batch consecutive tool calls in chat UI with shared utility Feb 6, 2026
- Make batchConsecutive() generic instead of ClineMessage-specific
- Add batch-aware button text for edit-file batches ("Save All"/"Deny All")
- Add dedicated list-batch/edit-batch i18n keys (stop reusing read-batch)
- Add JSON.parse defense-in-depth in all three synthesizers
- Fix mixed list_files batch icon to default to FolderTree
- Add 6 missing test cases (all-match, immutability, spy, single-dir)
- Trim unused recursive/isOutsideWorkspace from DirPermissionItem interface
- Remove 4 pre-existing `as any` casts in ChatView.tsx:
  - window cast → precise inline type
  - checkpoint bracket access → removed unnecessary casts
  - condensing message → `as ClineMessage`
  - debounce cancel → `.clear()` (correct API)
- Update BatchListFilesPermission test data to match trimmed interface
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL This PR changes 500-999 lines, ignoring generated files. UI/UX UI/UX related or focused

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Parallel list_files tool calls render as repetitive separate blocks

1 participant