feat(site/src/pages/AgentsPage/components): collapse sequential read file events - #25075
Conversation
|
/coder-agents-review |
There was a problem hiding this comment.
Clean, well-scoped PR. Two-pass grouping (message-level then block-level) is the right architecture for the persisted transcript shape, and the approach to keep grouping as a render-time derivation rather than a new block type was a good call.
Nice detail: the data-tool-call wrapper on ReadFilesTool preserving inter-block spacing, and the self-correction in the plan where the agent discovered block-level grouping alone was insufficient for real transcripts.
"Shall I show you how that breaks? ♥" (Hisoka, on the message/parsed divergence)
Severity breakdown: 2 P2, 6 P3, 1 P4, 4 Nit, 1 Note.
The two P2s are a real UI bug (error groups are locked shut) and a structural invariant violation (merged entry's raw message disagrees with parsed data). The P3s cover streaming UX, test coverage gaps, naming honesty, and a subtle behavioral change in how user messages are filtered.
🤖 This review was automatically generated with Coder Agents.
Thanks for the review. I will address the actionable comments inline and keep the scope focused on the read_file grouping UI. |
|
/coder-agents-review |
There was a problem hiding this comment.
R1 findings addressed thoroughly: 10 of 14 fixed in 2402bf0, 3 contested findings resolved by the panel, 1 acknowledged.
The DEREM-3 fix (expansion state persistence across single-to-group streaming transition) is well-designed. Lifting expansion state into ReadFileTimelineBlock with stable keying by the first tool ID is the right React pattern. The SequentialReadFilesExpansionPersistsAcrossGrouping story validates the transition end-to-end.
Contested findings closed: DEREM-5 (6/6 panel accept: old code already rendered hidden user messages as empty DOM), DEREM-8 (defense valid at N=2; N=3 tracked as DEREM-17), DEREM-10 (7/7 accept: inference sufficient).
Severity breakdown for new R2 findings: 4 P3, 1 P4.
DEREM-17 (third copy of read_file extraction) is the main open item. The author's R1 defense ("premature abstraction") was reasonable at N=2. The fix commit itself created N=3, which several panel members noted weakens the defense. A ~10-line shared helper would eliminate all three copies.
"Self-awareness without behavior change: the agent articulated why duplication is acceptable at N=2, then created N=3 in its own follow-up without self-correcting." (Mafu-san)
🤖 This review was automatically generated with Coder Agents.
Thanks for the follow-up review. I will address the new R2 items inline. |
|
Hopefully this comment gets in coder-agents-review[bot]'s context... I've attempted to "trim the fat" on this PR as the diff got too large. |
|
/coder-agents-review |
There was a problem hiding this comment.
All P2 and P3 findings resolved across 3 rounds (17 fixed, 3 contested and panel-closed, 1 acknowledged, 3 dropped). Two minor P4s remain.
R2 fixes verified clean by Netero and panel: getReadFileToolData eliminated the extraction duplication (DEREM-17), guard branch tests close coverage gaps (DEREM-18), all four merged arrays asserted (DEREM-19), redundant shouldHide removed from computeLastInChainFlags (DEREM-20), empty-file groups expandable (DEREM-21).
The design is solid: two-layer grouping (message then block), stable keying via first tool ID for streaming transitions, shared getReadFileToolData as single extraction point, and controlled/uncontrolled expansion via ReadFileTimelineBlock. Test coverage is thorough across both unit tests and interactive Storybook stories.
🤖 This review was automatically generated with Coder Agents.
Thanks for the final pass. I addressed the remaining low-risk test coverage note in 74eb7f1 and kept the change scoped to the existing message grouping tests. |
|
/coder-agents-review |
There was a problem hiding this comment.
DEREM-23 addressed in 74eb7f1 (user message breaking a read_file group test added). DEREM-24 (P4, running-state story removed in trim commit 348599c) has no author response. The finding was posted as a reply to the DEREM-7 thread, which GitHub shows as [Resolved, Outdated], so it may have been missed.
DEREM-24 is low-risk (the rendering is isRunning ? "Reading N files..." : "Read N files" plus a spinner icon). A brief acknowledgment, a re-added story, or an explicit "leaving as-is" would close it.
Further review is paused until the author responds to or addresses DEREM-24.
🤖 This review was automatically generated with Coder Agents.
74eb7f1 to
b99960f
Compare
Rebased on |
|
/coder-agents-review |
There was a problem hiding this comment.
All 24 findings resolved across 5 rounds. Zero open items.
19 fixed by the author, 3 contested and panel-closed, 1 acknowledged, 3 dropped by orchestrator. The author addressed every finding substantively, including the R4 BLOCKED round where DEREM-24 (running-state story) was restored after being trimmed.
The final codebase is clean: shared getReadFileToolData extraction, two-layer grouping with stable keying, comprehensive test coverage (unit tests with parameterized guard branches, Storybook stories with play functions covering happy path, error states, running state, empty files, and expansion persistence across streaming transitions).
"The code fought well." (Hisoka)
🤖 This review was automatically generated with Coder Agents.
b99960f to
ff13eb5
Compare
e6ece2e to
83d2ee4
Compare
Note
🤖 This PR was written by Coder Agent on behalf of Danielle Maywood
Collapses sequential
read_filetool activity in the Agents chat timeline into a single UI event while leaving the tool API and persisted transcript shape unchanged.The grouping handles both multiple tool blocks within one assistant message and the real persisted shape where
read_filecalls are split across adjacent assistant and tool-result messages. Refs CODAGT-337.Implementation plan
Collapse Sequential Read File Events Implementation Plan
Goal: Collapse consecutive
read_filetool calls into a single conversation timeline UI entry such asRead 3 fileswhile keeping each tool call singular.Architecture: This is a render-time frontend grouping change.
BlockListwill derive a grouped view from existingRenderBlock[]andMergedTool[], leaving message parsing, streaming state, persisted transcript shape, and theread_filetool protocol unchanged. A new grouped read-file component will reuse the same file viewer behavior asReadFileToolso expanded groups still expose every file read.Tech Stack: React, TypeScript, Vite, Vitest, Storybook interaction tests, Biome formatting, pnpm commands from
site/.Requirements
read_filecollapse into one UI event.read_fileblocks continue to render as the existing single-fileReadFileTool.read_fileblocks do not collapse across text, reasoning, source, file, or other tool blocks.read_filetool API stays singular. Do not change tool schemas or backend code.Read N filesand can expand to show each file's content.File Map
site/src/pages/AgentsPage/components/ChatConversation/blockUtils.tssite/src/pages/AgentsPage/components/ChatConversation/blockUtils.test.tssite/src/pages/AgentsPage/components/ChatConversation/ConversationTimeline.tsxBlockList, account for grouped IDs in remaining-tool filtering, and render grouped read files.site/src/pages/AgentsPage/components/ChatElements/tools/ReadFilesTool.tsxread_filecalls usingToolCollapsibleand file viewers.site/src/pages/AgentsPage/components/ChatElements/tools/ReadFileTool.tsxReadFilesTool.site/src/pages/AgentsPage/components/ChatConversation/ConversationTimeline.stories.tsxNo database, generated API, backend, or docs changes are expected.
Implementation Details
Grouping model
Do not add a persisted
RenderBlockunion member. Keep grouping as a local render derivation so other code that consumes parsed blocks does not need to understand grouped reads.Add these types and helpers to
blockUtils.ts:groupSequentialReadFileBlocksshould:toolByID = new Map(tools.map((tool) => [tool.id, tool])).blocksin order.block.type === "tool", resolve the tool fromtoolByID.tool.name === "read_file".{ type: "tool-group", toolName: "read_file", ids }block when the run length is greater than 1.Grouped component behavior
Create
ReadFilesTool.tsxwith props:Inside
ReadFilesTool:parseArgs,asRecord, andasString, matchingReadFileRendererinTool.tsx.path || "file"as the display path fallback.asString(rec.content).trim()for content to match existing single-file behavior.status === "running",isError,Reading ${tools.length} files…when running,Read ${tools.length} filesotherwise.hasContentis true if any grouped item has non-empty content.ToolCollapsiblewithclassName="w-full".To avoid duplicating file viewer setup, extract a small exported component from
ReadFileTool.tsx:Then
ReadFileToolrenders<ReadFileContent path={path} content={content} />, andReadFilesToolreuses it for each file.BlockListintegrationIn
ConversationTimeline.tsx:getToolIDsForBlock,groupSequentialReadFileBlocks, andReadFilesTool.toolByIDcreation.const displayBlocks = groupSequentialReadFileBlocks(blocks, tools);aftertoolByID.blockToolIDsfromdisplayBlocks.flatMap(getToolIDsForBlock)and retain the existing streaming check behavior for unresolved single tool placeholders.displayBlocks.mapinstead ofblocks.map.case "tool-group"beforecase "tool":lastBlockIsThinking, continue using the originalblocksinput because grouping only affects tool blocks.Tasks
Task 1: Add pure grouping helper tests
Files:
Test:
site/src/pages/AgentsPage/components/ChatConversation/blockUtils.test.tsModify later:
site/src/pages/AgentsPage/components/ChatConversation/blockUtils.tsStep 1: Add failing tests for grouped read blocks.
Add
MergedToolto the type imports and add a new suite afterappendTextBlock:Expected: Vitest fails because
groupSequentialReadFileBlocksis not exported fromblockUtils.ts.Task 2: Implement grouping helpers
Files:
Modify:
site/src/pages/AgentsPage/components/ChatConversation/blockUtils.tsTest:
site/src/pages/AgentsPage/components/ChatConversation/blockUtils.test.tsStep 1: Add the helper types and implementation.
Update imports:
Add the types and helpers after
appendTextBlock:Update the
blockUtils.test.tsimport to includegroupSequentialReadFileBlocksand importMergedTool:Expected: the new grouping tests pass.
Expected: all
blockUtils.test.tstests pass.Task 3: Add grouped read-file component with reusable file viewer body
Files:
Modify:
site/src/pages/AgentsPage/components/ChatElements/tools/ReadFileTool.tsxCreate:
site/src/pages/AgentsPage/components/ChatElements/tools/ReadFilesTool.tsxStep 1: Extract
ReadFileContentfromReadFileTool.tsx.Add this exported component before
ReadFileTool:Then replace the existing inline
ScrollAreainReadFileToolwith:ReadFilesTool.tsx.Use this shape:
Expected: no TypeScript errors from the new component and extracted viewer body.
Task 4: Integrate grouped blocks into
BlockListFiles:
Modify:
site/src/pages/AgentsPage/components/ChatConversation/ConversationTimeline.tsxStep 1: Import the helper and grouped component.
Add
ReadFilesToolnear the existing tool imports:Update the block utility import:
If
ConversationTimeline.tsxalready imports fromblockUtils, merge these names into that import instead of adding a duplicate.displayBlocksand update remaining-tool filtering.In
BlockList, aftertoolByID:Replace the existing
blockToolIDscomputation with:This keeps unresolved streaming placeholders eligible for single-tool rendering while also excluding grouped tool IDs from
remainingTools.displayBlocksand add the grouped case.Change:
to:
Add this switch case before
case "tool":Expected: tests pass and TypeScript accepts the new
TimelineRenderBlockswitch case.Task 5: Add Storybook coverage for sequential reads
Files:
Modify:
site/src/pages/AgentsPage/components/ChatConversation/ConversationTimeline.stories.tsxStep 1: Add a story with play assertions.
Add a story near the other tool/rendering regression stories:
The exact text queries for code contents may need adjustment because
@pierre/diffs/reactmay split code into decorated spans. Prefer asserting visible file paths and the group button.If Task 4 is complete, this should pass. If running this before Task 4, expected failure is that
Read 3 filesis not found.Expected: the story passes and confirms one grouped UI event.
Task 6: Format and verify the frontend change
Files:
All modified frontend files from previous tasks.
Step 1: Format frontend files.
Expected: Biome formats changed files.
Expected: all block utility tests pass.
Expected: the sequential read-file story passes.
Expected: no TypeScript errors.
Expected: the diff only contains grouping helpers, grouped UI, integration, and tests for CODAGT-337.
Follow-up: Real transcript shape fix
After manual testing showed the initial implementation did not collapse reads in
real chats, the reproduced transcript shape was updated to match persisted chat
messages: each
read_filetool call can appear in its own assistant message,with a hidden
toolrole result message between calls. The originalblock-level grouping only handled multiple tool blocks inside one assistant
message, so those real sequential reads stayed separate.
Additional changes:
groupSequentialReadFileMessagesinmessageHelpers.tsto collapseadjacent read-file-only assistant messages before rendering the timeline.
omitted from the rendered timeline.
visible tools still break a read-file group.
SequentialReadFilesCollapsedto use the real multi-message shape.messageHelpers.test.tscoverage for cross-message grouping.