-
Notifications
You must be signed in to change notification settings - Fork 1.4k
fix(site/src/pages/AgentsPage): suppress duplicate streaming tool-result row for pending calls #28063
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
fix(site/src/pages/AgentsPage): suppress duplicate streaming tool-result row for pending calls #28063
Changes from all commits
536a0bf
64e6939
d55db27
d6e89c9
5e34550
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -234,6 +234,64 @@ const getStreamToolStatus = ( | |
| return result.isError ? "error" : "completed"; | ||
| }; | ||
|
|
||
| /** | ||
| * Drops result-only stream entries whose tool call is already rendered as | ||
| * pending in the durable transcript, so the live tail does not show a | ||
| * duplicate row before the tool step commits. Still-streaming results are | ||
| * kept so progressive output keeps rendering, and a state left with no | ||
| * visible content becomes null so the tail renders nothing. See the | ||
| * filterPendingStreamState tests for the full behavior contract. | ||
| */ | ||
| export const filterPendingStreamState = ( | ||
| streamState: StreamState | null, | ||
| pendingToolCallIDs: ReadonlySet<string> | undefined, | ||
| ): StreamState | null => { | ||
| if (!streamState || !pendingToolCallIDs || pendingToolCallIDs.size === 0) { | ||
| return streamState; | ||
| } | ||
| const toolResults: StreamState["toolResults"] = {}; | ||
| let dropped = false; | ||
| for (const [id, result] of Object.entries(streamState.toolResults)) { | ||
| // Still-streaming results stay visible while they accumulate; the | ||
| // duplicate is only suppressed once the final result arrives. | ||
| if ( | ||
| pendingToolCallIDs.has(id) && | ||
| !streamState.toolCalls[id] && | ||
| !result.isStreaming | ||
|
Comment on lines
+258
to
+260
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When an AGENTS.md reference: site/AGENTS.md:L9-L10 Useful? React with 👍 / 👎. |
||
| ) { | ||
| dropped = true; | ||
| continue; | ||
| } | ||
| toolResults[id] = result; | ||
| } | ||
| if (!dropped) { | ||
| return streamState; | ||
| } | ||
| const blocks = streamState.blocks.filter( | ||
| (block) => | ||
| block.type !== "tool" || | ||
| !( | ||
| pendingToolCallIDs.has(block.id) && | ||
| !streamState.toolCalls[block.id] && | ||
| !streamState.toolResults[block.id]?.isStreaming | ||
| ), | ||
| ); | ||
| // Nothing visible remains. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The AGENTS.md reference: site/AGENTS.md:L15-L15 Useful? React with 👍 / 👎. |
||
| if ( | ||
| blocks.length === 0 && | ||
| Object.keys(streamState.toolCalls).length === 0 && | ||
| Object.keys(toolResults).length === 0 && | ||
| streamState.sources.length === 0 | ||
| ) { | ||
| return null; | ||
| } | ||
| return { | ||
| ...streamState, | ||
| blocks, | ||
| toolResults, | ||
| }; | ||
| }; | ||
|
|
||
| export const buildStreamTools = ( | ||
| toolCalls: StreamState["toolCalls"] | null | undefined, | ||
| toolResults: StreamState["toolResults"] | null | undefined, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a durable pending tool call and a result-only stream entry share an ID, this changes user-visible rendering through
ChatPageTimelineandLiveStreamTail, but the added unit tests exercise only the pure filter helper. Add a Storybook story with aplayassertion proving that only the durable row remains while a parallel call with a different ID stays visible; otherwise the prop wiring, live-status derivation, and rendered timeline behavior remain untested.AGENTS.md reference: site/AGENTS.md:L9-L10
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 64e6939. Added the story
StreamedResultForPendingToolDoesNotDuplicateinChatPageContent.stories.tsx, which rendersChatPageTimelinewith a real chat store: a durable pendingread_filecall (tc-1) plus its streamed result-only part, and a parallel in-stream call (tc-2). Theplayfunction asserts both sides of the invariant: tc-1 renders exactly once as the durable pending row with the duplicate suppressed, and the tc-2 row stays visible. Verified in chromium via the storybook test project.