diff --git a/packages/cli/src/ui/components/MainContent.test.tsx b/packages/cli/src/ui/components/MainContent.test.tsx
index ec75573d75..2bc6ee27bc 100644
--- a/packages/cli/src/ui/components/MainContent.test.tsx
+++ b/packages/cli/src/ui/components/MainContent.test.tsx
@@ -6,11 +6,7 @@
import { renderWithProviders } from '../../test-utils/render.js';
import { createMockSettings } from '../../test-utils/settings.js';
-import {
- makeFakeConfig,
- CoreToolCallStatus,
- UPDATE_TOPIC_TOOL_NAME,
-} from '@google/gemini-cli-core';
+import { makeFakeConfig, CoreToolCallStatus } from '@google/gemini-cli-core';
import { waitFor } from '../../test-utils/async.js';
import { MainContent } from './MainContent.js';
import { getToolGroupBorderAppearance } from '../utils/borderStyles.js';
@@ -732,158 +728,6 @@ describe('MainContent', () => {
unmount();
});
- describe('Narration Suppression', () => {
- const settingsWithNarration = createMockSettings({
- merged: {
- ui: { inlineThinkingMode: 'expanded' },
- experimental: { topicUpdateNarration: true },
- },
- });
-
- it('suppresses thinking ALWAYS when narration is enabled', async () => {
- mockUseSettings.mockReturnValue(settingsWithNarration);
- const uiState = {
- ...defaultMockUiState,
- history: [
- { id: 1, type: 'user' as const, text: 'Hello' },
- {
- id: 2,
- type: 'thinking' as const,
- thought: {
- subject: 'Thinking...',
- description: 'Thinking about hello',
- },
- },
- { id: 3, type: 'gemini' as const, text: 'I am helping.' },
- ],
- };
-
- const { lastFrame, unmount } = await renderWithProviders(
- ,
- {
- uiState: uiState as Partial,
- settings: settingsWithNarration,
- },
- );
-
- const output = lastFrame();
- expect(output).not.toContain('Thinking...');
- expect(output).toContain('I am helping.');
- unmount();
- });
-
- it('suppresses text in intermediate turns (contains non-topic tools)', async () => {
- mockUseSettings.mockReturnValue(settingsWithNarration);
- const uiState = {
- ...defaultMockUiState,
- history: [
- { id: 100, type: 'user' as const, text: 'Search' },
- {
- id: 101,
- type: 'gemini' as const,
- text: 'I will now search the files.',
- },
- {
- id: 102,
- type: 'tool_group' as const,
- tools: [
- {
- callId: '1',
- name: 'ls',
- args: { path: '.' },
- status: CoreToolCallStatus.Success,
- },
- ],
- },
- ],
- };
-
- const { lastFrame, unmount } = await renderWithProviders(
- ,
- {
- uiState: uiState as Partial,
- settings: settingsWithNarration,
- },
- );
-
- const output = lastFrame();
- expect(output).not.toContain('I will now search the files.');
- unmount();
- });
-
- it('suppresses text that precedes a topic tool in the same turn', async () => {
- mockUseSettings.mockReturnValue(settingsWithNarration);
- const uiState = {
- ...defaultMockUiState,
- history: [
- { id: 200, type: 'user' as const, text: 'Hello' },
- { id: 201, type: 'gemini' as const, text: 'I will now help you.' },
- {
- id: 202,
- type: 'tool_group' as const,
- tools: [
- {
- callId: '1',
- name: UPDATE_TOPIC_TOOL_NAME,
- args: { title: 'Helping', summary: 'Helping the user' },
- status: CoreToolCallStatus.Success,
- },
- ],
- },
- ],
- };
-
- const { lastFrame, unmount } = await renderWithProviders(
- ,
- {
- uiState: uiState as Partial,
- settings: settingsWithNarration,
- },
- );
-
- const output = lastFrame();
- expect(output).not.toContain('I will now help you.');
- expect(output).toContain('Helping');
- expect(output).toContain('Helping the user');
- unmount();
- });
-
- it('shows text in the final turn if it comes AFTER the topic tool', async () => {
- mockUseSettings.mockReturnValue(settingsWithNarration);
- const uiState = {
- ...defaultMockUiState,
- history: [
- { id: 300, type: 'user' as const, text: 'Hello' },
- {
- id: 301,
- type: 'tool_group' as const,
- tools: [
- {
- callId: '1',
- name: UPDATE_TOPIC_TOOL_NAME,
- args: { title: 'Final Answer', summary: 'I have finished' },
- status: CoreToolCallStatus.Success,
- },
- ],
- },
- { id: 302, type: 'gemini' as const, text: 'Here is your answer.' },
- ],
- };
-
- const { lastFrame, unmount } = await renderWithProviders(
- ,
- {
- uiState: uiState as Partial,
- settings: settingsWithNarration,
- },
- );
-
- const output = lastFrame();
- expect(output).toContain('Here is your answer.');
- unmount();
- });
- });
-
it('renders multiple thinking messages sequentially correctly', async () => {
mockUseSettings.mockReturnValue({
merged: {
diff --git a/packages/cli/src/ui/components/MainContent.tsx b/packages/cli/src/ui/components/MainContent.tsx
index 527462be28..b46af4965b 100644
--- a/packages/cli/src/ui/components/MainContent.tsx
+++ b/packages/cli/src/ui/components/MainContent.tsx
@@ -91,47 +91,20 @@ export const MainContent = () => {
const flags = new Array(combinedHistory.length).fill(false);
if (topicUpdateNarrationEnabled) {
- let turnIsIntermediate = false;
- let hasTopicToolInTurn = false;
-
+ let toolGroupInTurn = false;
for (let i = combinedHistory.length - 1; i >= 0; i--) {
const item = combinedHistory[i];
if (item.type === 'user' || item.type === 'user_shell') {
- turnIsIntermediate = false;
- hasTopicToolInTurn = false;
+ toolGroupInTurn = false;
} else if (item.type === 'tool_group') {
- const hasTopic = item.tools.some((t) => isTopicTool(t.name));
- const hasNonTopic = item.tools.some((t) => !isTopicTool(t.name));
- if (hasTopic) {
- hasTopicToolInTurn = true;
- }
- if (hasNonTopic) {
- turnIsIntermediate = true;
- }
+ toolGroupInTurn = item.tools.some((t) => isTopicTool(t.name));
} else if (
- item.type === 'thinking' ||
- item.type === 'gemini' ||
- item.type === 'gemini_content'
+ (item.type === 'thinking' ||
+ item.type === 'gemini' ||
+ item.type === 'gemini_content') &&
+ toolGroupInTurn
) {
- // Rule 1: Always suppress thinking when narration is enabled to avoid
- // "flashing" as the model starts its response, and because the Topic
- // UI provides the necessary high-level intent.
- if (item.type === 'thinking') {
- flags[i] = true;
- continue;
- }
-
- // Rule 2: Suppress text in intermediate turns (turns containing non-topic
- // tools) to hide mechanical narration.
- if (turnIsIntermediate) {
- flags[i] = true;
- }
-
- // Rule 3: Suppress text that precedes a topic tool in the same turn,
- // as the topic tool "replaces" it.
- if (hasTopicToolInTurn) {
- flags[i] = true;
- }
+ flags[i] = true;
}
}
}