Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions packages/core/src/core/geminiChat.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4729,7 +4729,7 @@ describe('GeminiChat', async () => {
}
});

it('should retry protocol tag leaks four times', async () => {
it('should keep protocol tag leak retries at the existing budget', async () => {
vi.useFakeTimers();
try {
vi.mocked(
Expand Down Expand Up @@ -4762,12 +4762,12 @@ describe('GeminiChat', async () => {

expect(
mockContentGenerator.generateContentStream,
).toHaveBeenCalledTimes(5);
expect(mockLogContentRetry).toHaveBeenCalledTimes(4);
).toHaveBeenCalledTimes(3);
expect(mockLogContentRetry).toHaveBeenCalledTimes(2);
expect(mockLogContentRetryFailure).toHaveBeenCalledWith(
mockConfig,
expect.objectContaining({
total_attempts: 5,
total_attempts: 3,
final_error_type: 'PROTOCOL_TAG_LEAK',
model: 'test-model',
}),
Expand Down Expand Up @@ -9925,12 +9925,12 @@ describe('GeminiChat', async () => {

expect(
mockContentGenerator.generateContentStream,
).toHaveBeenCalledTimes(7);
expect(mockLogContentRetry).toHaveBeenCalledTimes(4);
).toHaveBeenCalledTimes(5);
expect(mockLogContentRetry).toHaveBeenCalledTimes(2);
expect(mockLogContentRetry).toHaveBeenLastCalledWith(
mockConfig,
expect.objectContaining({
attempt_number: 3,
attempt_number: 1,
error_type: 'PROTOCOL_TAG_LEAK',
}),
);
Expand Down
33 changes: 27 additions & 6 deletions packages/core/src/core/geminiChat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,6 @@ import {
collectToolCallIdsFromHistory,
normalizeModelToolCallIds,
} from './toolCallIdUtils.js';
import { InvalidStreamError } from './invalid-stream-error.js';

export { InvalidStreamError };

const debugLogger = createDebugLogger('QWEN_CODE_CHAT');

Expand Down Expand Up @@ -346,7 +343,10 @@ const INVALID_CONTENT_RETRY_OPTIONS: ContentRetryOptions = {
// reason. All are retried with an independent budget (similar to rate-limit
// retries) so they do not consume each other's retry budgets.
const INVALID_STREAM_RETRY_CONFIG = {
maxRetries: 4,
transientMaxRetries: 4,
// Protocol-tag leaks are model-output validation failures, not the
// provider-side empty/truncated streams covered by issue #6670.
protocolTagLeakMaxRetries: 2,
initialDelayMs: 2000,
};

Expand Down Expand Up @@ -1041,6 +1041,23 @@ function stripThoughtPartsFromContent(content: Content): Content | null {
};
}

/**
* Custom error to signal that a stream completed with invalid content,
* which should trigger a retry.
*/
export class InvalidStreamError extends Error {
readonly type: 'NO_FINISH_REASON' | 'NO_RESPONSE_TEXT' | 'PROTOCOL_TAG_LEAK';

constructor(
message: string,
type: 'NO_FINISH_REASON' | 'NO_RESPONSE_TEXT' | 'PROTOCOL_TAG_LEAK',
) {
super(message);
this.name = 'InvalidStreamError';
this.type = type;
}
}

const PROTOCOL_TAG_PREFIXES = [
'<analysis',
'</analysis',
Expand Down Expand Up @@ -2505,7 +2522,9 @@ export class GeminiChat {
// not consume the content retry budget.
const isInvalidStreamError = error instanceof InvalidStreamError;
const maxInvalidStreamRetries =
INVALID_STREAM_RETRY_CONFIG.maxRetries;
isInvalidStreamError && error.type === 'PROTOCOL_TAG_LEAK'
? INVALID_STREAM_RETRY_CONFIG.protocolTagLeakMaxRetries
: INVALID_STREAM_RETRY_CONFIG.transientMaxRetries;
const invalidStreamRetryCount =
isInvalidStreamError && error.type === 'PROTOCOL_TAG_LEAK'
? protocolTagLeakRetryCount
Expand Down Expand Up @@ -2662,7 +2681,9 @@ export class GeminiChat {

attemptState.rollback();
const maxContinuationRetries =
INVALID_STREAM_RETRY_CONFIG.maxRetries;
error.type === 'PROTOCOL_TAG_LEAK'
? INVALID_STREAM_RETRY_CONFIG.protocolTagLeakMaxRetries
: INVALID_STREAM_RETRY_CONFIG.transientMaxRetries;
const continuationRetryCount =
error.type === 'PROTOCOL_TAG_LEAK'
? protocolTagLeakRetryCount
Expand Down
16 changes: 0 additions & 16 deletions packages/core/src/core/invalid-stream-error.ts

This file was deleted.

Loading
Loading