From 957f5639ba782f6d74188f3537f8c2e0aa05641f Mon Sep 17 00:00:00 2001
From: Jarrod Whelan <150866123+jwhelangoog@users.noreply.github.com>
Date: Tue, 7 Apr 2026 13:43:20 -0700
Subject: [PATCH] limit turning off message suppression to the current turn
only
---
.../src/ui/components/MainContent.test.tsx | 76 +++++++++++++++++++
.../cli/src/ui/components/MainContent.tsx | 11 ++-
2 files changed, 85 insertions(+), 2 deletions(-)
diff --git a/packages/cli/src/ui/components/MainContent.test.tsx b/packages/cli/src/ui/components/MainContent.test.tsx
index 2be3a0ac8b..3fda3d5793 100644
--- a/packages/cli/src/ui/components/MainContent.test.tsx
+++ b/packages/cli/src/ui/components/MainContent.test.tsx
@@ -882,6 +882,82 @@ describe('MainContent', () => {
expect(output).toContain('Here is your answer.');
unmount();
});
+
+ it('bypasses suppression for the current turn during confirmation, but keeps old turns suppressed', async () => {
+ const { useConfirmingTool } = await import(
+ '../hooks/useConfirmingTool.js'
+ );
+ vi.mocked(useConfirmingTool).mockReturnValue({
+ tool: {
+ callId: 'call-1',
+ name: 'some_tool',
+ status: CoreToolCallStatus.AwaitingApproval,
+ confirmationDetails: {
+ type: 'confirm_shell_command' as const,
+ command: 'echo "hello"',
+ },
+ },
+ index: 0,
+ total: 1,
+ } as unknown as ConfirmingToolState);
+
+ mockUseSettings.mockReturnValue(settingsWithNarration);
+ const uiState = {
+ ...defaultMockUiState,
+ history: [
+ // Previous turn: should remain suppressed
+ { id: 10, type: 'user' as const, text: 'Old Turn' },
+ { id: 11, type: 'gemini' as const, text: 'Old narration' },
+ {
+ id: 12,
+ type: 'tool_group' as const,
+ tools: [
+ {
+ callId: 'old',
+ name: 'ls',
+ status: CoreToolCallStatus.Success,
+ description: '',
+ resultDisplay: '',
+ confirmationDetails: undefined,
+ } as IndividualToolCallDisplay,
+ ],
+ },
+ // Current turn: should be bypassed (shown)
+ { id: 20, type: 'user' as const, text: 'Current Turn' },
+ { id: 21, type: 'gemini' as const, text: 'Current narration' },
+ ],
+ pendingHistoryItems: [
+ {
+ type: 'tool_group' as const,
+ tools: [
+ {
+ callId: 'call-1',
+ name: 'some_tool',
+ status: CoreToolCallStatus.AwaitingApproval,
+ description: '',
+ resultDisplay: '',
+ confirmationDetails: undefined,
+ } as IndividualToolCallDisplay,
+ ],
+ },
+ ],
+ };
+
+ const { lastFrame, unmount } = await renderWithProviders(
+ ,
+ {
+ uiState: uiState as Partial,
+ settings: settingsWithNarration,
+ },
+ );
+
+ const output = lastFrame();
+ // Old narration should STILL be suppressed
+ expect(output).not.toContain('Old narration');
+ // Current narration should be VISIBLE because of the bypass
+ expect(output).toContain('Current narration');
+ unmount();
+ });
});
it('renders multiple thinking messages sequentially correctly', async () => {
diff --git a/packages/cli/src/ui/components/MainContent.tsx b/packages/cli/src/ui/components/MainContent.tsx
index d0b7e1284e..8ad4a1dda0 100644
--- a/packages/cli/src/ui/components/MainContent.tsx
+++ b/packages/cli/src/ui/components/MainContent.tsx
@@ -123,13 +123,19 @@ export const MainContent = () => {
// Rule 2: Suppress text in intermediate turns (turns containing non-topic
// tools) to hide mechanical narration.
- if (turnIsIntermediate && !showConfirmationQueue) {
+
+ const isCurrentTurn = i > lastUserPromptIndex;
+ // Scoping the bypass to the current turn prevents old narration from reappearing.
+ // This logic affects the rendered height of the history list by conditionally hiding turns.
+ const bypassSuppression = isCurrentTurn && showConfirmationQueue;
+
+ if (turnIsIntermediate && !bypassSuppression) {
flags[i] = true;
}
// Rule 3: Suppress text that precedes a topic tool in the same turn,
// as the topic tool "replaces" it.
- if (hasTopicToolInTurn && !showConfirmationQueue) {
+ if (hasTopicToolInTurn && !bypassSuppression) {
flags[i] = true;
}
}
@@ -141,6 +147,7 @@ export const MainContent = () => {
pendingHistoryItems,
topicUpdateNarrationEnabled,
showConfirmationQueue,
+ lastUserPromptIndex,
]);
const augmentedHistory = useMemo(