mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-13 13:22:35 -07:00
fix(core): retry on ERR_STREAM_PREMATURE_CLOSE errors (#26519)
This commit is contained in:
@@ -587,4 +587,66 @@ describe('GeminiChat Network Retries', () => {
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should retry on premature stream closure (ERR_STREAM_PREMATURE_CLOSE)', async () => {
|
||||
mockConfig.getRetryFetchErrors = vi.fn().mockReturnValue(true);
|
||||
|
||||
const prematureCloseError = new Error('Premature close');
|
||||
Object.defineProperty(prematureCloseError, 'code', {
|
||||
value: 'ERR_STREAM_PREMATURE_CLOSE',
|
||||
});
|
||||
|
||||
vi.mocked(mockContentGenerator.generateContentStream)
|
||||
.mockResolvedValueOnce(
|
||||
(async function* () {
|
||||
yield {
|
||||
candidates: [{ content: { parts: [{ text: 'Incomplete part' }] } }],
|
||||
} as unknown as GenerateContentResponse;
|
||||
throw prematureCloseError;
|
||||
})(),
|
||||
)
|
||||
.mockResolvedValueOnce(
|
||||
(async function* () {
|
||||
yield {
|
||||
candidates: [
|
||||
{
|
||||
content: { parts: [{ text: 'Complete response after retry' }] },
|
||||
finishReason: 'STOP',
|
||||
},
|
||||
],
|
||||
} as unknown as GenerateContentResponse;
|
||||
})(),
|
||||
);
|
||||
|
||||
const stream = await chat.sendMessageStream(
|
||||
{ model: 'test-model' },
|
||||
'test message',
|
||||
'prompt-id-premature-close',
|
||||
new AbortController().signal,
|
||||
LlmRole.MAIN,
|
||||
);
|
||||
|
||||
const events: StreamEvent[] = [];
|
||||
for await (const event of stream) {
|
||||
events.push(event);
|
||||
}
|
||||
|
||||
const retryEvent = events.find((e) => e.type === StreamEventType.RETRY);
|
||||
expect(retryEvent).toBeDefined();
|
||||
|
||||
const successChunk = events.find(
|
||||
(e) =>
|
||||
e.type === StreamEventType.CHUNK &&
|
||||
e.value.candidates?.[0]?.content?.parts?.[0]?.text ===
|
||||
'Complete response after retry',
|
||||
);
|
||||
expect(successChunk).toBeDefined();
|
||||
|
||||
expect(mockLogNetworkRetryAttempt).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
expect.objectContaining({
|
||||
error_type: 'ERR_STREAM_PREMATURE_CLOSE',
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -58,6 +58,7 @@ const RETRYABLE_NETWORK_CODES = [
|
||||
'UND_ERR_HEADERS_TIMEOUT',
|
||||
'UND_ERR_BODY_TIMEOUT',
|
||||
'UND_ERR_CONNECT_TIMEOUT',
|
||||
'ERR_STREAM_PREMATURE_CLOSE',
|
||||
];
|
||||
|
||||
// Node.js builds SSL error codes by prepending ERR_SSL_ to the uppercased
|
||||
|
||||
Reference in New Issue
Block a user