diff options
Diffstat (limited to 'packages/cli')
| -rw-r--r-- | packages/cli/src/ui/App.tsx | 7 | ||||
| -rw-r--r-- | packages/cli/src/ui/components/LoadingIndicator.test.tsx | 52 | ||||
| -rw-r--r-- | packages/cli/src/ui/components/LoadingIndicator.tsx | 42 | ||||
| -rw-r--r-- | packages/cli/src/ui/hooks/useGeminiStream.ts | 6 |
4 files changed, 90 insertions, 17 deletions
diff --git a/packages/cli/src/ui/App.tsx b/packages/cli/src/ui/App.tsx index 52c286dc..9a4ecbd3 100644 --- a/packages/cli/src/ui/App.tsx +++ b/packages/cli/src/ui/App.tsx @@ -300,6 +300,7 @@ const App = ({ config, settings, startupWarnings = [] }: AppProps) => { submitQuery, initError, pendingHistoryItems: pendingGeminiHistoryItems, + thought, } = useGeminiStream( config.getGeminiClient(), history, @@ -542,6 +543,12 @@ const App = ({ config, settings, startupWarnings = [] }: AppProps) => { ) : ( <> <LoadingIndicator + thought={ + streamingState === StreamingState.WaitingForConfirmation || + config.getAccessibility()?.disableLoadingPhrases + ? undefined + : thought + } currentLoadingPhrase={ config.getAccessibility()?.disableLoadingPhrases ? undefined diff --git a/packages/cli/src/ui/components/LoadingIndicator.test.tsx b/packages/cli/src/ui/components/LoadingIndicator.test.tsx index 3d31818b..ba161062 100644 --- a/packages/cli/src/ui/components/LoadingIndicator.test.tsx +++ b/packages/cli/src/ui/components/LoadingIndicator.test.tsx @@ -159,4 +159,56 @@ describe('<LoadingIndicator />', () => { ); expect(lastFrame()).toBe(''); }); + + it('should display fallback phrase if thought is empty', () => { + const props = { + thought: null, + currentLoadingPhrase: 'Loading...', + elapsedTime: 5, + }; + const { lastFrame } = renderWithContext( + <LoadingIndicator {...props} />, + StreamingState.Responding, + ); + const output = lastFrame(); + expect(output).toContain('Loading...'); + }); + + it('should display the subject of a thought', () => { + const props = { + thought: { + subject: 'Thinking about something...', + description: 'and other stuff.', + }, + elapsedTime: 5, + }; + const { lastFrame } = renderWithContext( + <LoadingIndicator {...props} />, + StreamingState.Responding, + ); + const output = lastFrame(); + expect(output).toBeDefined(); + if (output) { + expect(output).toContain('Thinking about something...'); + expect(output).not.toContain('and other stuff.'); + } + }); + + it('should prioritize thought.subject over currentLoadingPhrase', () => { + const props = { + thought: { + subject: 'This should be displayed', + description: 'A description', + }, + currentLoadingPhrase: 'This should not be displayed', + elapsedTime: 5, + }; + const { lastFrame } = renderWithContext( + <LoadingIndicator {...props} />, + StreamingState.Responding, + ); + const output = lastFrame(); + expect(output).toContain('This should be displayed'); + expect(output).not.toContain('This should not be displayed'); + }); }); diff --git a/packages/cli/src/ui/components/LoadingIndicator.tsx b/packages/cli/src/ui/components/LoadingIndicator.tsx index 61b74b89..855894e6 100644 --- a/packages/cli/src/ui/components/LoadingIndicator.tsx +++ b/packages/cli/src/ui/components/LoadingIndicator.tsx @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { ThoughtSummary } from '@gemini-cli/core'; import React from 'react'; import { Box, Text } from 'ink'; import { Colors } from '../colors.js'; @@ -15,12 +16,14 @@ interface LoadingIndicatorProps { currentLoadingPhrase?: string; elapsedTime: number; rightContent?: React.ReactNode; + thought?: ThoughtSummary | null; } export const LoadingIndicator: React.FC<LoadingIndicatorProps> = ({ currentLoadingPhrase, elapsedTime, rightContent, + thought, }) => { const streamingState = useStreamingContext(); @@ -28,25 +31,30 @@ export const LoadingIndicator: React.FC<LoadingIndicatorProps> = ({ return null; } + const primaryText = thought?.subject || currentLoadingPhrase; + return ( - <Box marginTop={1} paddingLeft={0}> - <Box marginRight={1}> - <GeminiRespondingSpinner - nonRespondingDisplay={ - streamingState === StreamingState.WaitingForConfirmation ? '⠏' : '' - } - /> + <Box marginTop={1} paddingLeft={0} flexDirection="column"> + {/* Main loading line */} + <Box> + <Box marginRight={1}> + <GeminiRespondingSpinner + nonRespondingDisplay={ + streamingState === StreamingState.WaitingForConfirmation + ? '⠏' + : '' + } + /> + </Box> + {primaryText && <Text color={Colors.AccentPurple}>{primaryText}</Text>} + <Text color={Colors.Gray}> + {streamingState === StreamingState.WaitingForConfirmation + ? '' + : ` (esc to cancel, ${elapsedTime}s)`} + </Text> + <Box flexGrow={1}>{/* Spacer */}</Box> + {rightContent && <Box>{rightContent}</Box>} </Box> - {currentLoadingPhrase && ( - <Text color={Colors.AccentPurple}>{currentLoadingPhrase}</Text> - )} - <Text color={Colors.Gray}> - {streamingState === StreamingState.WaitingForConfirmation - ? '' - : ` (esc to cancel, ${elapsedTime}s)`} - </Text> - <Box flexGrow={1}>{/* Spacer */}</Box> - {rightContent && <Box>{rightContent}</Box>} </Box> ); }; diff --git a/packages/cli/src/ui/hooks/useGeminiStream.ts b/packages/cli/src/ui/hooks/useGeminiStream.ts index bff38a2b..51d32506 100644 --- a/packages/cli/src/ui/hooks/useGeminiStream.ts +++ b/packages/cli/src/ui/hooks/useGeminiStream.ts @@ -21,6 +21,7 @@ import { logUserPrompt, GitService, EditorType, + ThoughtSummary, } from '@gemini-cli/core'; import { type Part, type PartListUnion } from '@google/genai'; import { @@ -90,6 +91,7 @@ export const useGeminiStream = ( const [initError, setInitError] = useState<string | null>(null); const abortControllerRef = useRef<AbortController | null>(null); const [isResponding, setIsResponding] = useState<boolean>(false); + const [thought, setThought] = useState<ThoughtSummary | null>(null); const [pendingHistoryItemRef, setPendingHistoryItem] = useStateAndRef<HistoryItemWithoutId | null>(null); const logger = useLogger(); @@ -393,6 +395,9 @@ export const useGeminiStream = ( const toolCallRequests: ToolCallRequestInfo[] = []; for await (const event of stream) { switch (event.type) { + case ServerGeminiEventType.Thought: + setThought(event.value); + break; case ServerGeminiEventType.Content: geminiMessageBuffer = handleContentEvent( event.value, @@ -730,5 +735,6 @@ export const useGeminiStream = ( submitQuery, initError, pendingHistoryItems, + thought, }; }; |
