feat(core/ui): enhance retry mechanism and UX (#16489)

This commit is contained in:
Sehoon Shon
2026-01-13 23:03:19 -05:00
committed by GitHub
parent 428e602882
commit 4afd3741df
9 changed files with 200 additions and 26 deletions
@@ -34,6 +34,8 @@ import {
ToolConfirmationOutcome,
tokenLimit,
debugLogger,
coreEvents,
CoreEvent,
} from '@google/gemini-cli-core';
import type { Part, PartListUnion } from '@google/genai';
import type { UseHistoryManagerReturn } from './useHistoryManager.js';
@@ -1333,6 +1335,66 @@ describe('useGeminiStream', () => {
});
});
describe('Retry Handling', () => {
it('should update retryStatus when CoreEvent.RetryAttempt is emitted', async () => {
const { result } = renderHookWithDefaults();
const retryPayload = {
model: 'gemini-2.5-pro',
attempt: 2,
maxAttempts: 3,
delayMs: 1000,
};
await act(async () => {
coreEvents.emit(CoreEvent.RetryAttempt, retryPayload);
});
expect(result.current.retryStatus).toEqual(retryPayload);
});
it('should reset retryStatus when isResponding becomes false', async () => {
const { result } = renderTestHook();
const retryPayload = {
model: 'gemini-2.5-pro',
attempt: 2,
maxAttempts: 3,
delayMs: 1000,
};
// Start a query to make isResponding true
const mockStream = (async function* () {
yield { type: ServerGeminiEventType.Content, value: 'Part 1' };
await new Promise(() => {}); // Keep stream open
})();
mockSendMessageStream.mockReturnValue(mockStream);
await act(async () => {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
result.current.submitQuery('test query');
});
await waitFor(() => {
expect(result.current.streamingState).toBe(StreamingState.Responding);
});
// Emit retry event
await act(async () => {
coreEvents.emit(CoreEvent.RetryAttempt, retryPayload);
});
expect(result.current.retryStatus).toEqual(retryPayload);
// Cancel to make isResponding false
await act(async () => {
result.current.cancelOngoingRequest();
});
expect(result.current.retryStatus).toBeNull();
});
});
describe('Slash Command Handling', () => {
it('should schedule a tool call when the command processor returns a schedule_tool action', async () => {
const clientToolRequest: SlashCommandProcessorResult = {