Skip to content

Commit b7ad7e1

Browse files
fix(patch): cherry-pick 07e597d to release/v0.23.0-preview.3-pr-15684 [CONFLICTS] (#15734)
Co-authored-by: Sehoon Shon <[email protected]>
1 parent dbcad90 commit b7ad7e1

File tree

3 files changed

+26
-18
lines changed

3 files changed

+26
-18
lines changed

packages/core/src/utils/googleQuotaErrors.test.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ describe('classifyGoogleError', () => {
342342
const result = classifyGoogleError(originalError);
343343
expect(result).toBeInstanceOf(RetryableQuotaError);
344344
if (result instanceof RetryableQuotaError) {
345-
expect(result.retryDelayMs).toBe(5000);
345+
expect(result.retryDelayMs).toBeUndefined();
346346
}
347347
});
348348

@@ -393,7 +393,7 @@ describe('classifyGoogleError', () => {
393393
}
394394
});
395395

396-
it('should return RetryableQuotaError with 5s fallback for generic 429 without specific message', () => {
396+
it('should return RetryableQuotaError without delay time for generic 429 without specific message', () => {
397397
const generic429 = {
398398
status: 429,
399399
message: 'Resource exhausted. No specific retry info.',
@@ -403,11 +403,11 @@ describe('classifyGoogleError', () => {
403403

404404
expect(result).toBeInstanceOf(RetryableQuotaError);
405405
if (result instanceof RetryableQuotaError) {
406-
expect(result.retryDelayMs).toBe(5000);
406+
expect(result.retryDelayMs).toBeUndefined();
407407
}
408408
});
409409

410-
it('should return RetryableQuotaError with 5s fallback for 429 with empty details and no regex match', () => {
410+
it('should return RetryableQuotaError without delay time for 429 with empty details and no regex match', () => {
411411
const errorWithEmptyDetails = {
412412
error: {
413413
code: 429,
@@ -420,11 +420,11 @@ describe('classifyGoogleError', () => {
420420

421421
expect(result).toBeInstanceOf(RetryableQuotaError);
422422
if (result instanceof RetryableQuotaError) {
423-
expect(result.retryDelayMs).toBe(5000);
423+
expect(result.retryDelayMs).toBeUndefined();
424424
}
425425
});
426426

427-
it('should return RetryableQuotaError with 5s fallback for 429 with some detail', () => {
427+
it('should return RetryableQuotaError without delay time for 429 with some detail', () => {
428428
const errorWithEmptyDetails = {
429429
error: {
430430
code: 429,
@@ -446,7 +446,7 @@ describe('classifyGoogleError', () => {
446446

447447
expect(result).toBeInstanceOf(RetryableQuotaError);
448448
if (result instanceof RetryableQuotaError) {
449-
expect(result.retryDelayMs).toBe(5000);
449+
expect(result.retryDelayMs).toBeUndefined();
450450
}
451451
});
452452
});

packages/core/src/utils/googleQuotaErrors.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ import type {
1313
import { parseGoogleApiError } from './googleErrors.js';
1414
import { getErrorStatus, ModelNotFoundError } from './httpErrors.js';
1515

16-
const DEFAULT_RETRYABLE_DELAY_SECOND = 5;
17-
1816
/**
1917
* A non-retryable error indicating a hard quota limit has been reached (e.g., daily limit).
2018
*/
@@ -24,28 +22,32 @@ export class TerminalQuotaError extends Error {
2422
constructor(
2523
message: string,
2624
override readonly cause: GoogleApiError,
27-
retryDelayMs?: number,
25+
retryDelaySeconds?: number,
2826
) {
2927
super(message);
3028
this.name = 'TerminalQuotaError';
31-
this.retryDelayMs = retryDelayMs ? retryDelayMs * 1000 : undefined;
29+
this.retryDelayMs = retryDelaySeconds
30+
? retryDelaySeconds * 1000
31+
: undefined;
3232
}
3333
}
3434

3535
/**
3636
* A retryable error indicating a temporary quota issue (e.g., per-minute limit).
3737
*/
3838
export class RetryableQuotaError extends Error {
39-
retryDelayMs: number;
39+
retryDelayMs?: number;
4040

4141
constructor(
4242
message: string,
4343
override readonly cause: GoogleApiError,
44-
retryDelaySeconds: number,
44+
retryDelaySeconds?: number,
4545
) {
4646
super(message);
4747
this.name = 'RetryableQuotaError';
48-
this.retryDelayMs = retryDelaySeconds * 1000;
48+
this.retryDelayMs = retryDelaySeconds
49+
? retryDelaySeconds * 1000
50+
: undefined;
4951
}
5052
}
5153

@@ -124,7 +126,6 @@ export function classifyGoogleError(error: unknown): unknown {
124126
message: errorMessage,
125127
details: [],
126128
},
127-
DEFAULT_RETRYABLE_DELAY_SECOND,
128129
);
129130
}
130131

@@ -259,7 +260,6 @@ export function classifyGoogleError(error: unknown): unknown {
259260
message: errorMessage,
260261
details: [],
261262
},
262-
DEFAULT_RETRYABLE_DELAY_SECOND,
263263
);
264264
}
265265
return error; // Fallback to original error if no specific classification fits.

packages/core/src/utils/retry.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,11 @@ export async function retryWithBackoff<T>(
220220

221221
if (classifiedError instanceof RetryableQuotaError || is500) {
222222
if (attempt >= maxAttempts) {
223+
const errorMessage =
224+
classifiedError instanceof Error ? classifiedError.message : '';
225+
debugLogger.warn(
226+
`Attempt ${attempt} failed${errorMessage ? `: ${errorMessage}` : ''}. Max attempts reached`,
227+
);
223228
if (onPersistent429) {
224229
try {
225230
const fallbackModel = await onPersistent429(
@@ -240,8 +245,11 @@ export async function retryWithBackoff<T>(
240245
: error;
241246
}
242247

243-
if (classifiedError instanceof RetryableQuotaError) {
244-
console.warn(
248+
if (
249+
classifiedError instanceof RetryableQuotaError &&
250+
classifiedError.retryDelayMs !== undefined
251+
) {
252+
debugLogger.warn(
245253
`Attempt ${attempt} failed: ${classifiedError.message}. Retrying after ${classifiedError.retryDelayMs}ms...`,
246254
);
247255
await delay(classifiedError.retryDelayMs, signal);

0 commit comments

Comments
 (0)