From 775a94e441acc094226d2df8c44776477dc25488 Mon Sep 17 00:00:00 2001 From: Ryan Albrecht Date: Mon, 21 Sep 2026 15:57:23 -0700 Subject: [PATCH] fix(seer): Stop drawing an empty reasoning box while Seer works MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While a response is in flight but has reported nothing yet — most visibly when the agent is off running an autofix — the Explorer drew a bordered but empty card under the "Thinking..." header, which reads as a broken or stuck panel. `ThinkingBlock` opens that card only when it is given children, but `ResponseGroup` handed it `group.map(...)`. An array is truthy even when every `Fragment` inside it renders nothing, so the guard never fired. The blocks are now gated on `hasTrace`, the predicate that already decides whether any reasoning, narration, or tool row will actually appear, so the header stands alone until there is something to put under it. The block itself still renders throughout, so the live title, the Seer spinner, and the elapsed timer are unchanged. --- .../seerExplorer/components/chat/responseGroup.spec.tsx | 5 ++++- .../app/views/seerExplorer/components/chat/responseGroup.tsx | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/static/app/views/seerExplorer/components/chat/responseGroup.spec.tsx b/static/app/views/seerExplorer/components/chat/responseGroup.spec.tsx index 81e2902782c3..c8262b904080 100644 --- a/static/app/views/seerExplorer/components/chat/responseGroup.spec.tsx +++ b/static/app/views/seerExplorer/components/chat/responseGroup.spec.tsx @@ -1,6 +1,6 @@ import {OrganizationFixture} from 'sentry-fixture/organization'; -import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary'; +import {render, screen, userEvent, within} from 'sentry-test/reactTestingLibrary'; import type {Block} from 'sentry/views/seerExplorer/types'; @@ -318,6 +318,9 @@ describe('ResponseGroup', () => { ); expect(queryReasoningBox(container)).toBeInTheDocument(); + // Title only. The panel is the bordered card, so opening it around nothing draws an + // empty box under "Thinking..." for as long as the agent takes to report anything. + expect(within(reasoningBox(container)).queryByRole('group')).not.toBeInTheDocument(); }); it('gates thinking prose on the showThinking toggle but keeps tool calls', async () => { diff --git a/static/app/views/seerExplorer/components/chat/responseGroup.tsx b/static/app/views/seerExplorer/components/chat/responseGroup.tsx index fdf00e7b9cf8..49301d5506e9 100644 --- a/static/app/views/seerExplorer/components/chat/responseGroup.tsx +++ b/static/app/views/seerExplorer/components/chat/responseGroup.tsx @@ -205,7 +205,10 @@ export function ResponseGroup({ startTime={startTime} endTime={endTime} > - {active || hasTrace + {/* `hasTrace`, not `active`: an active response with nothing to show yet still + maps to a non-empty array of blocks that each render nothing, and an array is + truthy, so ThinkingBlock would open its bordered panel around no content. */} + {hasTrace ? group.map((block, i) => { const isAnswer = block === answer; // A block's own tool calls render after its thinking, so they count as