diff --git a/packages/cli/src/ui/components/Composer.test.tsx b/packages/cli/src/ui/components/Composer.test.tsx index 77c8812812..4c97255529 100644 --- a/packages/cli/src/ui/components/Composer.test.tsx +++ b/packages/cli/src/ui/components/Composer.test.tsx @@ -385,7 +385,7 @@ describe('Composer', () => { const { lastFrame } = await renderComposer(uiState, settings); const output = lastFrame(); - expect(output).toContain('LoadingIndicator: Thinking about code'); + expect(output).toContain('LoadingIndicator: Thinking...'); }); it('hides shortcuts hint while loading', async () => { diff --git a/packages/cli/src/ui/components/Composer.tsx b/packages/cli/src/ui/components/Composer.tsx index d8cc8d162c..d30f52dddf 100644 --- a/packages/cli/src/ui/components/Composer.tsx +++ b/packages/cli/src/ui/components/Composer.tsx @@ -238,7 +238,9 @@ export const Composer = ({ isFocused = true }: { isFocused?: boolean }) => { ? undefined : uiState.currentLoadingPhrase } - thoughtLabel={undefined} + thoughtLabel={ + inlineThinkingMode === 'full' ? 'Thinking...' : undefined + } elapsedTime={uiState.elapsedTime} /> )} @@ -280,7 +282,7 @@ export const Composer = ({ isFocused = true }: { isFocused?: boolean }) => { : uiState.currentLoadingPhrase } thoughtLabel={ - inlineThinkingMode === 'full' ? 'Thinking ...' : undefined + inlineThinkingMode === 'full' ? 'Thinking...' : undefined } elapsedTime={uiState.elapsedTime} /> @@ -388,7 +390,7 @@ export const Composer = ({ isFocused = true }: { isFocused?: boolean }) => { marginTop={ (showApprovalIndicator || uiState.shellModeActive) && - isNarrow + !isNarrow ? 1 : 0 } diff --git a/packages/cli/src/ui/components/LoadingIndicator.test.tsx b/packages/cli/src/ui/components/LoadingIndicator.test.tsx index fca56afd38..4c4e3053ef 100644 --- a/packages/cli/src/ui/components/LoadingIndicator.test.tsx +++ b/packages/cli/src/ui/components/LoadingIndicator.test.tsx @@ -258,13 +258,32 @@ describe('', () => { const output = lastFrame(); expect(output).toBeDefined(); if (output) { - expect(output).toContain('Thinking... '); + // Should NOT contain "Thinking... " prefix because the subject already starts with "Thinking" + expect(output).not.toContain('Thinking... Thinking'); expect(output).toContain('Thinking about something...'); expect(output).not.toContain('and other stuff.'); } unmount(); }); + it('should prepend "Thinking... " if the subject does not start with "Thinking"', async () => { + const props = { + thought: { + subject: 'Planning the response...', + description: 'details', + }, + elapsedTime: 5, + }; + const { lastFrame, unmount, waitUntilReady } = renderWithContext( + , + StreamingState.Responding, + ); + await waitUntilReady(); + const output = lastFrame(); + expect(output).toContain('Thinking... Planning the response...'); + unmount(); + }); + it('should prioritize thought.subject over currentLoadingPhrase', async () => { const props = { thought: { diff --git a/packages/cli/src/ui/components/LoadingIndicator.tsx b/packages/cli/src/ui/components/LoadingIndicator.tsx index 4cb49d5750..7aea32a249 100644 --- a/packages/cli/src/ui/components/LoadingIndicator.tsx +++ b/packages/cli/src/ui/components/LoadingIndicator.tsx @@ -58,7 +58,11 @@ export const LoadingIndicator: React.FC = ({ const hasThoughtIndicator = currentLoadingPhrase !== INTERACTIVE_SHELL_WAITING_PHRASE && Boolean(thought?.subject?.trim()); - const thinkingIndicator = hasThoughtIndicator ? 'Thinking... ' : ''; + // Avoid "Thinking... Thinking..." duplication if primaryText already starts with "Thinking" + const thinkingIndicator = + hasThoughtIndicator && !primaryText?.startsWith('Thinking') + ? 'Thinking... ' + : ''; const cancelAndTimerContent = showCancelAndTimer &&