From e3806c338d290ca6276ea996e9d336923be2b501 Mon Sep 17 00:00:00 2001 From: Marco Beretta <81851188+berry-13@users.noreply.github.com> Date: Sun, 6 Sep 2026 03:40:46 +0200 Subject: [PATCH] Scope grouped background verdicts by execution step --- .../Chat/Messages/Content/ToolCallGroup.tsx | 8 +++- .../Content/__tests__/ToolCallGroup.test.tsx | 48 +++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/client/src/components/Chat/Messages/Content/ToolCallGroup.tsx b/client/src/components/Chat/Messages/Content/ToolCallGroup.tsx index 38f89956a9..043a20ed70 100644 --- a/client/src/components/Chat/Messages/Content/ToolCallGroup.tsx +++ b/client/src/components/Chat/Messages/Content/ToolCallGroup.tsx @@ -149,11 +149,15 @@ function getToolMeta( * folds that marker in as `extraError`, so without it here the group * reported no failed action beside a card showing failure. Correlated the * same way the child is, since provider tool-call ids repeat across agents - * in handoff responses. */ + * and execution steps in handoff responses. */ const backgroundFailed = parseBackgroundHandle(tc.output) != null && splitBackgroundAttachments( - filterAttachmentsForPart(attachmentsByToolCallId?.[tc.id ?? ''], tc.agentId), + filterAttachmentsForPart( + attachmentsByToolCallId?.[tc.id ?? ''], + tc.agentId, + toolCall.stepId, + ), tc.id, ).backgroundStatus === 'error'; return { diff --git a/client/src/components/Chat/Messages/Content/__tests__/ToolCallGroup.test.tsx b/client/src/components/Chat/Messages/Content/__tests__/ToolCallGroup.test.tsx index 0856191d19..405ea28194 100644 --- a/client/src/components/Chat/Messages/Content/__tests__/ToolCallGroup.test.tsx +++ b/client/src/components/Chat/Messages/Content/__tests__/ToolCallGroup.test.tsx @@ -824,6 +824,54 @@ describe('ToolCallGroup image hoisting', () => { ).toBeInTheDocument(); }); + it('counts background failures per step when provider call IDs repeat', () => { + const executions = [ + { stepId: 'step-success', status: 'completed' }, + { stepId: 'step-failure', status: 'error' }, + ]; + const groupAttachments = executions.map(({ stepId, status }) => ({ + type: 'background_task_status', + messageId: 'message-1', + toolCallId: 'call_0', + agentId: 'agent-a', + stepId, + status, + })) as unknown as TAttachment[]; + const props = { + ...baseProps, + groupAttachments, + parts: executions.map(({ stepId }, idx) => ({ + idx, + part: { + type: ContentTypes.TOOL_CALL, + [ContentTypes.TOOL_CALL]: { + id: 'call_0', + name: 'execute_code', + args: '{}', + agentId: 'agent-a', + stepId, + runStepStatus: 'completed', + output: JSON.stringify({ + background_task_id: stepId, + tool: 'execute_code', + status: 'running', + message: 'Use check_background_task to poll.', + }), + }, + } as unknown as TMessageContentParts, + })), + }; + const { rerender } = renderGroup(props); + expect(screen.getByRole('button', { name: /· 1 failed$/ })).toBeInTheDocument(); + + rerender( + + + , + ); + expect(screen.getByRole('button', { name: /· 1 failed$/ })).toBeInTheDocument(); + }); + it('honors a terminal failed run step whose output reads as benign', () => { const closedFailure = { type: ContentTypes.TOOL_CALL,