mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-10 14:10:37 -07:00
refactor(core): improve API response error logging when retry (#21784)
This commit is contained in:
@@ -1154,6 +1154,7 @@ describe('GeminiChat', () => {
|
|||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
expect(mockLogContentRetry).not.toHaveBeenCalled();
|
expect(mockLogContentRetry).not.toHaveBeenCalled();
|
||||||
|
expect(mockLogContentRetryFailure).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should yield a RETRY event when an invalid stream is encountered', async () => {
|
it('should yield a RETRY event when an invalid stream is encountered', async () => {
|
||||||
|
|||||||
@@ -344,8 +344,6 @@ export class GeminiChat {
|
|||||||
this: GeminiChat,
|
this: GeminiChat,
|
||||||
): AsyncGenerator<StreamEvent, void, void> {
|
): AsyncGenerator<StreamEvent, void, void> {
|
||||||
try {
|
try {
|
||||||
let lastError: unknown = new Error('Request failed after all retries.');
|
|
||||||
|
|
||||||
const maxAttempts = INVALID_CONTENT_RETRY_OPTIONS.maxAttempts;
|
const maxAttempts = INVALID_CONTENT_RETRY_OPTIONS.maxAttempts;
|
||||||
|
|
||||||
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
||||||
@@ -374,15 +372,13 @@ export class GeminiChat {
|
|||||||
yield { type: StreamEventType.CHUNK, value: chunk };
|
yield { type: StreamEventType.CHUNK, value: chunk };
|
||||||
}
|
}
|
||||||
|
|
||||||
lastError = null;
|
return;
|
||||||
break;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof AgentExecutionStoppedError) {
|
if (error instanceof AgentExecutionStoppedError) {
|
||||||
yield {
|
yield {
|
||||||
type: StreamEventType.AGENT_EXECUTION_STOPPED,
|
type: StreamEventType.AGENT_EXECUTION_STOPPED,
|
||||||
reason: error.reason,
|
reason: error.reason,
|
||||||
};
|
};
|
||||||
lastError = null; // Clear error as this is an expected stop
|
|
||||||
return; // Stop the generator
|
return; // Stop the generator
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -397,7 +393,6 @@ export class GeminiChat {
|
|||||||
value: error.syntheticResponse,
|
value: error.syntheticResponse,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
lastError = null; // Clear error as this is an expected stop
|
|
||||||
return; // Stop the generator
|
return; // Stop the generator
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -415,8 +410,9 @@ export class GeminiChat {
|
|||||||
}
|
}
|
||||||
// Fall through to retry logic for retryable connection errors
|
// Fall through to retry logic for retryable connection errors
|
||||||
}
|
}
|
||||||
lastError = error;
|
|
||||||
const isContentError = error instanceof InvalidStreamError;
|
const isContentError = error instanceof InvalidStreamError;
|
||||||
|
const errorType = isContentError ? error.type : 'NETWORK_ERROR';
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(isContentError && isGemini2Model(model)) ||
|
(isContentError && isGemini2Model(model)) ||
|
||||||
@@ -425,11 +421,10 @@ export class GeminiChat {
|
|||||||
// Check if we have more attempts left.
|
// Check if we have more attempts left.
|
||||||
if (attempt < maxAttempts - 1) {
|
if (attempt < maxAttempts - 1) {
|
||||||
const delayMs = INVALID_CONTENT_RETRY_OPTIONS.initialDelayMs;
|
const delayMs = INVALID_CONTENT_RETRY_OPTIONS.initialDelayMs;
|
||||||
const retryType = isContentError ? error.type : 'NETWORK_ERROR';
|
|
||||||
|
|
||||||
logContentRetry(
|
logContentRetry(
|
||||||
this.config,
|
this.config,
|
||||||
new ContentRetryEvent(attempt, retryType, delayMs, model),
|
new ContentRetryEvent(attempt, errorType, delayMs, model),
|
||||||
);
|
);
|
||||||
coreEvents.emitRetryAttempt({
|
coreEvents.emitRetryAttempt({
|
||||||
attempt: attempt + 1,
|
attempt: attempt + 1,
|
||||||
@@ -444,21 +439,19 @@ export class GeminiChat {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastError) {
|
// If we've aborted, we throw without logging a failure.
|
||||||
if (
|
if (signal.aborted) {
|
||||||
lastError instanceof InvalidStreamError &&
|
throw error;
|
||||||
isGemini2Model(model)
|
}
|
||||||
) {
|
|
||||||
logContentRetryFailure(
|
logContentRetryFailure(
|
||||||
this.config,
|
this.config,
|
||||||
new ContentRetryFailureEvent(maxAttempts, lastError.type, model),
|
new ContentRetryFailureEvent(attempt + 1, errorType, model),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
throw lastError;
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
streamDoneResolver!();
|
streamDoneResolver!();
|
||||||
|
|||||||
@@ -401,6 +401,7 @@ describe('GeminiChat Network Retries', () => {
|
|||||||
|
|
||||||
// Should only be called once (no retry)
|
// Should only be called once (no retry)
|
||||||
expect(mockContentGenerator.generateContentStream).toHaveBeenCalledTimes(1);
|
expect(mockContentGenerator.generateContentStream).toHaveBeenCalledTimes(1);
|
||||||
|
expect(mockLogContentRetryFailure).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should retry on SSL error during stream iteration (mid-stream failure)', async () => {
|
it('should retry on SSL error during stream iteration (mid-stream failure)', async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user