Compare commits

...

6 Commits

10 changed files with 30 additions and 29 deletions
@@ -76,7 +76,7 @@ export const DetailedMessagesDisplay: React.FC<
>
<Box marginBottom={1}>
<Text bold color={theme.text.primary}>
Debug Console <Text color={theme.text.secondary}>(F12 to close)</Text>
Debug console <Text color={theme.text.secondary}>(F12 to close)</Text>
</Text>
</Box>
<Box height={maxHeight} width={width - borderAndPadding}>
@@ -120,7 +120,7 @@ describe('<LoadingIndicator />', () => {
unmount();
});
it('should display the elapsedTime correctly in human-readable format', async () => {
it('should display the elapsedTime correctly in minutes and OMIT seconds for > 1m', async () => {
const props = {
currentLoadingPhrase: 'Thinking...',
elapsedTime: 125,
@@ -130,7 +130,9 @@ describe('<LoadingIndicator />', () => {
StreamingState.Responding,
);
await waitUntilReady();
expect(lastFrame()).toContain('(esc to cancel, 2m 5s)');
const output = lastFrame();
expect(output).toContain('(esc to cancel, 2m)');
expect(output).not.toContain('5s');
unmount();
});
@@ -258,15 +260,13 @@ describe('<LoadingIndicator />', () => {
const output = lastFrame();
expect(output).toBeDefined();
if (output) {
// Should NOT contain "Thinking... " prefix because the subject already starts with "Thinking"
expect(output).not.toContain('Thinking... Thinking');
expect(output).not.toContain('Gemini is thinking');
expect(output).toContain('Thinking about something...');
expect(output).not.toContain('and other stuff.');
}
unmount();
});
it('should NOT prepend "Thinking... " even if the subject does not start with "Thinking"', async () => {
it('should NOT prepend "Thinking... " if a subject is provided', async () => {
const props = {
thought: {
subject: 'Planning the response...',
@@ -11,7 +11,6 @@ import { theme } from '../semantic-colors.js';
import { useStreamingContext } from '../contexts/StreamingContext.js';
import { StreamingState } from '../types.js';
import { GeminiRespondingSpinner } from './GeminiRespondingSpinner.js';
import { formatDuration } from '../utils/formatters.js';
import { useTerminalSize } from '../hooks/useTerminalSize.js';
import { isNarrowWidth } from '../utils/isNarrowWidth.js';
import { INTERACTIVE_SHELL_WAITING_PHRASE } from '../hooks/usePhraseCycler.js';
@@ -74,7 +73,11 @@ export const LoadingIndicator: React.FC<LoadingIndicatorProps> = ({
const cancelAndTimerContent =
showCancelAndTimer &&
streamingState !== StreamingState.WaitingForConfirmation
? `(esc to cancel, ${elapsedTime < 60 ? `${elapsedTime}s` : formatDuration(elapsedTime * 1000)})`
? `(esc to cancel, ${
elapsedTime < 60
? `${elapsedTime}s`
: `${Math.floor(elapsedTime / 60)}m`
})`
: null;
const wittyPhraseNode =
@@ -3,7 +3,7 @@
exports[`DetailedMessagesDisplay > renders message counts 1`] = `
"
╭──────────────────────────────────────────────────────────────────────────────╮
│ Debug Console (F12 to close) │
│ Debug console (F12 to close) │
│ │
Repeated message (x5) │
│ │
@@ -18,7 +18,7 @@ exports[`DetailedMessagesDisplay > renders message counts 1`] = `
exports[`DetailedMessagesDisplay > renders messages correctly 1`] = `
"
╭──────────────────────────────────────────────────────────────────────────────╮
│ Debug Console (F12 to close) │
│ Debug console (F12 to close) │
│ │
Log message │
│ ⚠ Warning message │
@@ -1048,7 +1048,7 @@ describe('useGeminiStream', () => {
).toBe(false);
expect(
infoTexts.some((text) =>
text.includes('This request failed. Press F12 for diagnostics'),
text.includes('Request failed. Press F12 for diagnostics'),
),
).toBe(false);
});
@@ -1108,15 +1108,13 @@ describe('useGeminiStream', () => {
([item]) => (item as { text?: string }).text ?? '',
);
const noteIndex = infoTexts.findIndex((text) =>
text.includes(
'Some internal tool attempts failed before this final error',
),
text.includes('Previous tool attempts failed'),
);
const stopIndex = infoTexts.findIndex((text) =>
text.includes('Agent execution stopped: Stop reason from hook'),
);
const failureHintIndex = infoTexts.findIndex((text) =>
text.includes('This request failed. Press F12 for diagnostics'),
text.includes('Request failed. Press F12 for diagnostics'),
);
expect(noteIndex).toBeGreaterThanOrEqual(0);
expect(stopIndex).toBeGreaterThanOrEqual(0);
+2 -2
View File
@@ -110,9 +110,9 @@ enum StreamProcessingStatus {
}
const SUPPRESSED_TOOL_ERRORS_NOTE =
'Some internal tool attempts failed before this final error. Press F12 for diagnostics, or run /settings and change "Error Verbosity" to full for details.';
'Previous tool attempts failed. Press F12 for diagnostics or set ui.errorVerbosity=full for details';
const LOW_VERBOSITY_FAILURE_NOTE =
'This request failed. Press F12 for diagnostics, or run /settings and change "Error Verbosity" to full for full details.';
'Request failed. Press F12 for diagnostics or set ui.errorVerbosity=full for details';
function getBackgroundedToolInfo(
toolCall: TrackedCompletedToolCall | TrackedCancelledToolCall,
@@ -237,7 +237,7 @@ describe('useLoadingIndicator', () => {
retryStatus,
);
expect(result.current.currentLoadingPhrase).toContain('Trying to reach');
expect(result.current.currentLoadingPhrase).toContain('Retrying');
expect(result.current.currentLoadingPhrase).toContain('Attempt 3/3');
});
@@ -258,7 +258,7 @@ describe('useLoadingIndicator', () => {
);
expect(result.current.currentLoadingPhrase).not.toBe(
"This is taking a bit longer, we're still on it.",
'System busy. Retrying...',
);
});
@@ -279,7 +279,7 @@ describe('useLoadingIndicator', () => {
);
expect(result.current.currentLoadingPhrase).toBe(
"This is taking a bit longer, we're still on it.",
'System busy. Retrying...',
);
});
@@ -82,9 +82,9 @@ export const useLoadingIndicator = ({
const retryPhrase = retryStatus
? errorVerbosity === 'low'
? retryStatus.attempt >= LOW_VERBOSITY_RETRY_HINT_ATTEMPT_THRESHOLD
? "This is taking a bit longer, we're still on it."
? 'System busy. Retrying...'
: null
: `Trying to reach ${getDisplayString(retryStatus.model)} (Attempt ${retryStatus.attempt + 1}/${retryStatus.maxAttempts})`
: `Retrying ${getDisplayString(retryStatus.model)} (Attempt ${retryStatus.attempt + 1}/${retryStatus.maxAttempts})`
: null;
return {
+3 -3
View File
@@ -11,8 +11,8 @@ import { AuthType } from '../core/contentGenerator.js';
import type { StructuredError } from '../core/turn.js';
describe('parseAndFormatApiError', () => {
const vertexMessage = 'request a quota increase through Vertex';
const geminiMessage = 'request a quota increase through AI Studio';
const vertexMessage = 'request a quota increase in Vertex';
const geminiMessage = 'request a quota increase in AI Studio';
it('should format a valid API error JSON', () => {
const errorMessage =
@@ -34,7 +34,7 @@ describe('parseAndFormatApiError', () => {
);
expect(result).toContain('[API Error: Rate limit exceeded');
expect(result).toContain(
'Possible quota limitations in place or slow response times detected. Switching to the gemini-2.5-flash model',
'System busy or quota limit reached. Switching to gemini-2.5-flash for the rest of this session.',
);
});
+3 -3
View File
@@ -10,13 +10,13 @@ import type { UserTierId } from '../code_assist/types.js';
import { AuthType } from '../core/contentGenerator.js';
const RATE_LIMIT_ERROR_MESSAGE_USE_GEMINI =
'\nPlease wait and try again later. To increase your limits, request a quota increase through AI Studio, or switch to another /auth method';
'\nRate limit reached. Try again later, request a quota increase in AI Studio, or switch /auth method';
const RATE_LIMIT_ERROR_MESSAGE_VERTEX =
'\nPlease wait and try again later. To increase your limits, request a quota increase through Vertex, or switch to another /auth method';
'\nRate limit reached. Try again later, request a quota increase in Vertex, or switch /auth method';
const getRateLimitErrorMessageDefault = (
fallbackModel: string = DEFAULT_GEMINI_FLASH_MODEL,
) =>
`\nPossible quota limitations in place or slow response times detected. Switching to the ${fallbackModel} model for the rest of this session.`;
`\nSystem busy or quota limit reached. Switching to ${fallbackModel} for the rest of this session.`;
function getRateLimitMessage(
authType?: AuthType,