fix(core): handle AbortError thrown during processTurn (#21296)

Co-authored-by: Gaurav <39389231+gsquared94@users.noreply.github.com>
This commit is contained in:
MumuTW
2026-03-06 15:29:56 +09:00
committed by GitHub
parent 35c1999341
commit 6691fac50e
2 changed files with 24 additions and 1 deletions

View File

@@ -728,6 +728,23 @@ describe('Gemini Client (client.ts)', () => {
);
});
it('yields UserCancelled when processTurn throws AbortError', async () => {
const abortError = new Error('Aborted');
abortError.name = 'AbortError';
vi.spyOn(client['loopDetector'], 'turnStarted').mockRejectedValueOnce(
abortError,
);
const stream = client.sendMessageStream(
[{ text: 'Hi' }],
new AbortController().signal,
'prompt-id-abort-error',
);
const events = await fromAsync(stream);
expect(events).toEqual([{ type: GeminiEventType.UserCancelled }]);
});
it.each([
{
compressionStatus:

View File

@@ -34,7 +34,7 @@ import {
type RetryAvailabilityContext,
} from '../utils/retry.js';
import type { ValidationRequiredError } from '../utils/googleQuotaErrors.js';
import { getErrorMessage } from '../utils/errors.js';
import { getErrorMessage, isAbortError } from '../utils/errors.js';
import { tokenLimit } from './tokenLimits.js';
import type {
ChatRecordingService,
@@ -957,6 +957,12 @@ export class GeminiClient {
);
}
}
} catch (error) {
if (signal?.aborted || isAbortError(error)) {
yield { type: GeminiEventType.UserCancelled };
return turn;
}
throw error;
} finally {
const hookState = this.hookStateMap.get(prompt_id);
if (hookState) {