From 41d4f59f5e55602d6cad7c02dcd43570fb247acd Mon Sep 17 00:00:00 2001 From: Sri Pasumarthi <111310667+sripasg@users.noreply.github.com> Date: Wed, 11 Mar 2026 22:57:37 -0700 Subject: [PATCH] feat: Display pending and confirming tool calls (#22106) Co-authored-by: Spencer --- ...ternateBufferQuittingDisplay.test.tsx.snap | 12 +++++++++ .../messages/ThinkingMessage.test.tsx | 18 +++++++++++++ .../components/messages/ThinkingMessage.tsx | 26 ++++++++++++------- .../messages/ToolGroupMessage.test.tsx | 15 ++++++----- .../components/messages/ToolGroupMessage.tsx | 9 ++++--- ...out-progress-dots-and-empty-lines.snap.svg | 14 ++++++++++ .../ThinkingMessage.test.tsx.snap | 15 +++++++++++ .../ToolGroupMessage.test.tsx.snap | 8 ++++++ 8 files changed, 96 insertions(+), 21 deletions(-) create mode 100644 packages/cli/src/ui/components/messages/__snapshots__/ThinkingMessage-ThinkingMessage-filters-out-progress-dots-and-empty-lines.snap.svg diff --git a/packages/cli/src/ui/components/__snapshots__/AlternateBufferQuittingDisplay.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/AlternateBufferQuittingDisplay.test.tsx.snap index ec8712ebc1..b4f2bc919c 100644 --- a/packages/cli/src/ui/components/__snapshots__/AlternateBufferQuittingDisplay.test.tsx.snap +++ b/packages/cli/src/ui/components/__snapshots__/AlternateBufferQuittingDisplay.test.tsx.snap @@ -13,6 +13,10 @@ Tips for getting started: 2. /help for more information 3. Ask coding questions, edit code or run commands 4. Be specific for the best results +╭──────────────────────────────────────────────────────────────────────────╮ +│ ? confirming_tool Confirming tool description │ +│ │ +╰──────────────────────────────────────────────────────────────────────────╯ Action Required (was prompted): @@ -41,6 +45,10 @@ Tips for getting started: │ ✓ tool2 Description for tool 2 │ │ │ ╰──────────────────────────────────────────────────────────────────────────╯ +╭──────────────────────────────────────────────────────────────────────────╮ +│ o tool3 Description for tool 3 │ +│ │ +╰──────────────────────────────────────────────────────────────────────────╯ " `; @@ -97,6 +105,10 @@ Tips for getting started: 2. /help for more information 3. Ask coding questions, edit code or run commands 4. Be specific for the best results +╭──────────────────────────────────────────────────────────────────────────╮ +│ o tool3 Description for tool 3 │ +│ │ +╰──────────────────────────────────────────────────────────────────────────╯ " `; diff --git a/packages/cli/src/ui/components/messages/ThinkingMessage.test.tsx b/packages/cli/src/ui/components/messages/ThinkingMessage.test.tsx index 1499d285f7..f6d57da251 100644 --- a/packages/cli/src/ui/components/messages/ThinkingMessage.test.tsx +++ b/packages/cli/src/ui/components/messages/ThinkingMessage.test.tsx @@ -159,4 +159,22 @@ describe('ThinkingMessage', () => { await expect(renderResult).toMatchSvgSnapshot(); renderResult.unmount(); }); + + it('filters out progress dots and empty lines', async () => { + const renderResult = renderWithProviders( + , + ); + await renderResult.waitUntilReady(); + + const output = renderResult.lastFrame(); + expect(output).toContain('Thinking'); + expect(output).toContain('Done'); + expect(renderResult.lastFrame()).toMatchSnapshot(); + await expect(renderResult).toMatchSvgSnapshot(); + renderResult.unmount(); + }); }); diff --git a/packages/cli/src/ui/components/messages/ThinkingMessage.tsx b/packages/cli/src/ui/components/messages/ThinkingMessage.tsx index 9591989774..990456bd05 100644 --- a/packages/cli/src/ui/components/messages/ThinkingMessage.tsx +++ b/packages/cli/src/ui/components/messages/ThinkingMessage.tsx @@ -23,20 +23,26 @@ function normalizeThoughtLines(thought: ThoughtSummary): string[] { const subject = normalizeEscapedNewlines(thought.subject).trim(); const description = normalizeEscapedNewlines(thought.description).trim(); - if (!subject && !description) { - return []; + const isNoise = (text: string) => { + const trimmed = text.trim(); + return !trimmed || /^\.+$/.test(trimmed); + }; + + const lines: string[] = []; + + if (subject && !isNoise(subject)) { + lines.push(subject); } - if (!subject) { - return description.split('\n'); + if (description) { + const descriptionLines = description + .split('\n') + .map((line) => line.trim()) + .filter((line) => !isNoise(line)); + lines.push(...descriptionLines); } - if (!description) { - return [subject]; - } - - const bodyLines = description.split('\n'); - return [subject, ...bodyLines]; + return lines; } /** diff --git a/packages/cli/src/ui/components/messages/ToolGroupMessage.test.tsx b/packages/cli/src/ui/components/messages/ToolGroupMessage.test.tsx index d5cbdabe60..b38f76aa04 100644 --- a/packages/cli/src/ui/components/messages/ToolGroupMessage.test.tsx +++ b/packages/cli/src/ui/components/messages/ToolGroupMessage.test.tsx @@ -118,9 +118,10 @@ describe('', () => { { config: baseMockConfig, settings: fullVerbositySettings }, ); - // Should render nothing because all tools in the group are confirming + // Should now render confirming tools await waitUntilReady(); - expect(lastFrame({ allowEmpty: true })).toBe(''); + const output = lastFrame(); + expect(output).toContain('test-tool'); unmount(); }); @@ -162,11 +163,11 @@ describe('', () => { }, }, ); - // pending-tool should be hidden + // pending-tool should now be visible await waitUntilReady(); const output = lastFrame(); expect(output).toContain('successful-tool'); - expect(output).not.toContain('pending-tool'); + expect(output).toContain('pending-tool'); expect(output).toContain('error-tool'); expect(output).toMatchSnapshot(); unmount(); @@ -280,12 +281,12 @@ describe('', () => { }, }, ); - // write_file (Pending) should be hidden + // write_file (Pending) should now be visible await waitUntilReady(); const output = lastFrame(); expect(output).toContain('read_file'); expect(output).toContain('run_shell_command'); - expect(output).not.toContain('write_file'); + expect(output).toContain('write_file'); expect(output).toMatchSnapshot(); unmount(); }); @@ -841,7 +842,7 @@ describe('', () => { ); await waitUntilReady(); - expect(lastFrame({ allowEmpty: true })).toBe(''); + expect(lastFrame({ allowEmpty: true })).not.toBe(''); unmount(); }); diff --git a/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx b/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx index 01cec31727..e22d3c6313 100644 --- a/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx +++ b/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx @@ -110,10 +110,11 @@ export const ToolGroupMessage: React.FC = ({ () => toolCalls.filter((t) => { const displayStatus = mapCoreStatusToDisplayStatus(t.status); - return ( - displayStatus !== ToolCallStatus.Pending && - displayStatus !== ToolCallStatus.Confirming - ); + // We used to filter out Pending and Confirming statuses here to avoid + // duplication with the Global Queue, but this causes tools to appear to + // "vanish" from the context after approval. + // We now allow them to be visible here as well. + return displayStatus !== ToolCallStatus.Canceled; }), [toolCalls], diff --git a/packages/cli/src/ui/components/messages/__snapshots__/ThinkingMessage-ThinkingMessage-filters-out-progress-dots-and-empty-lines.snap.svg b/packages/cli/src/ui/components/messages/__snapshots__/ThinkingMessage-ThinkingMessage-filters-out-progress-dots-and-empty-lines.snap.svg new file mode 100644 index 0000000000..e7cdbd5960 --- /dev/null +++ b/packages/cli/src/ui/components/messages/__snapshots__/ThinkingMessage-ThinkingMessage-filters-out-progress-dots-and-empty-lines.snap.svg @@ -0,0 +1,14 @@ + + + + + Thinking... + + + Thinking + + Done + + \ No newline at end of file diff --git a/packages/cli/src/ui/components/messages/__snapshots__/ThinkingMessage.test.tsx.snap b/packages/cli/src/ui/components/messages/__snapshots__/ThinkingMessage.test.tsx.snap index da33a2a14c..f9eea8fb0a 100644 --- a/packages/cli/src/ui/components/messages/__snapshots__/ThinkingMessage.test.tsx.snap +++ b/packages/cli/src/ui/components/messages/__snapshots__/ThinkingMessage.test.tsx.snap @@ -1,5 +1,20 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +exports[`ThinkingMessage > filters out progress dots and empty lines 1`] = ` +" Thinking... + │ + │ Thinking + │ Done +" +`; + +exports[`ThinkingMessage > filters out progress dots and empty lines 2`] = ` +" Thinking... + │ + │ Thinking + │ Done" +`; + exports[`ThinkingMessage > normalizes escaped newline tokens 1`] = ` " Thinking... │ diff --git a/packages/cli/src/ui/components/messages/__snapshots__/ToolGroupMessage.test.tsx.snap b/packages/cli/src/ui/components/messages/__snapshots__/ToolGroupMessage.test.tsx.snap index 29da4d5860..c1ea071bc5 100644 --- a/packages/cli/src/ui/components/messages/__snapshots__/ToolGroupMessage.test.tsx.snap +++ b/packages/cli/src/ui/components/messages/__snapshots__/ToolGroupMessage.test.tsx.snap @@ -74,6 +74,10 @@ exports[` > Golden Snapshots > renders mixed tool calls incl │ ⊶ run_shell_command Run command │ │ │ │ Test result │ +│ │ +│ o write_file Write to file │ +│ │ +│ Test result │ ╰──────────────────────────────────────────────────────────────────────────╯ " `; @@ -84,6 +88,10 @@ exports[` > Golden Snapshots > renders multiple tool calls w │ │ │ Test result │ │ │ +│ o pending-tool This tool is pending │ +│ │ +│ Test result │ +│ │ │ x error-tool This tool failed │ │ │ │ Test result │