Add new setting to configure maxRetries (#20064)

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This commit is contained in:
kevinjwang1
2026-02-23 15:57:16 -08:00
committed by GitHub
parent 1ad26adb2b
commit 2ff7738b5d
10 changed files with 90 additions and 34 deletions
+1
View File
@@ -29,6 +29,7 @@ they appear in the UI.
| Enable Auto Update | `general.enableAutoUpdate` | Enable automatic updates. | `true` | | Enable Auto Update | `general.enableAutoUpdate` | Enable automatic updates. | `true` |
| Enable Notifications | `general.enableNotifications` | Enable run-event notifications for action-required prompts and session completion. Currently macOS only. | `false` | | Enable Notifications | `general.enableNotifications` | Enable run-event notifications for action-required prompts and session completion. Currently macOS only. | `false` |
| Plan Directory | `general.plan.directory` | The directory where planning artifacts are stored. If not specified, defaults to the system temporary directory. | `undefined` | | Plan Directory | `general.plan.directory` | The directory where planning artifacts are stored. If not specified, defaults to the system temporary directory. | `undefined` |
| Max Chat Model Attempts | `general.maxAttempts` | Maximum number of attempts for requests to the main chat model. Cannot exceed 10. | `10` |
| Debug Keystroke Logging | `general.debugKeystrokeLogging` | Enable debug logging of keystrokes to the console. | `false` | | Debug Keystroke Logging | `general.debugKeystrokeLogging` | Enable debug logging of keystrokes to the console. | `false` |
| Enable Session Cleanup | `general.sessionRetention.enabled` | Enable automatic session cleanup | `false` | | Enable Session Cleanup | `general.sessionRetention.enabled` | Enable automatic session cleanup | `false` |
| Keep chat history | `general.sessionRetention.maxAge` | Automatically delete chats older than this time period (e.g., "30d", "7d", "24h", "1w") | `undefined` | | Keep chat history | `general.sessionRetention.maxAge` | Automatically delete chats older than this time period (e.g., "30d", "7d", "24h", "1w") | `undefined` |
+5
View File
@@ -142,6 +142,11 @@ their corresponding top-level category object in your `settings.json` file.
request" errors. request" errors.
- **Default:** `false` - **Default:** `false`
- **`general.maxAttempts`** (number):
- **Description:** Maximum number of attempts for requests to the main chat
model. Cannot exceed 10.
- **Default:** `10`
- **`general.debugKeystrokeLogging`** (boolean): - **`general.debugKeystrokeLogging`** (boolean):
- **Description:** Enable debug logging of keystrokes to the console. - **Description:** Enable debug logging of keystrokes to the console.
- **Default:** `false` - **Default:** `false`
+10
View File
@@ -297,6 +297,16 @@ const SETTINGS_SCHEMA = {
'Retry on "exception TypeError: fetch failed sending request" errors.', 'Retry on "exception TypeError: fetch failed sending request" errors.',
showInDialog: false, showInDialog: false,
}, },
maxAttempts: {
type: 'number',
label: 'Max Chat Model Attempts',
category: 'General',
requiresRestart: false,
default: 10,
description:
'Maximum number of attempts for requests to the main chat model. Cannot exceed 10.',
showInDialog: true,
},
debugKeystrokeLogging: { debugKeystrokeLogging: {
type: 'boolean', type: 'boolean',
label: 'Debug Keystroke Logging', label: 'Debug Keystroke Logging',
@@ -25,15 +25,15 @@ exports[`SettingsDialog > Initial Rendering > should render settings list with v
│ Plan Directory undefined │ │ Plan Directory undefined │
│ The directory where planning artifacts are stored. If not specified, defaults t… │ │ The directory where planning artifacts are stored. If not specified, defaults t… │
│ │ │ │
│ Max Chat Model Attempts 10 │
│ Maximum number of attempts for requests to the main chat model. Cannot exceed 10. │
│ │
│ Debug Keystroke Logging false │ │ Debug Keystroke Logging false │
│ Enable debug logging of keystrokes to the console. │ │ Enable debug logging of keystrokes to the console. │
│ │ │ │
│ Enable Session Cleanup false │ │ Enable Session Cleanup false │
│ Enable automatic session cleanup │ │ Enable automatic session cleanup │
│ │ │ │
│ Keep chat history undefined │
│ Automatically delete chats older than this time period (e.g., "30d", "7d", "24h… │
│ │
│ ▼ │ │ ▼ │
│ │ │ │
│ Apply To │ │ Apply To │
@@ -72,15 +72,15 @@ exports[`SettingsDialog > Snapshot Tests > should render 'accessibility settings
│ Plan Directory undefined │ │ Plan Directory undefined │
│ The directory where planning artifacts are stored. If not specified, defaults t… │ │ The directory where planning artifacts are stored. If not specified, defaults t… │
│ │ │ │
│ Max Chat Model Attempts 10 │
│ Maximum number of attempts for requests to the main chat model. Cannot exceed 10. │
│ │
│ Debug Keystroke Logging false │ │ Debug Keystroke Logging false │
│ Enable debug logging of keystrokes to the console. │ │ Enable debug logging of keystrokes to the console. │
│ │ │ │
│ Enable Session Cleanup false │ │ Enable Session Cleanup false │
│ Enable automatic session cleanup │ │ Enable automatic session cleanup │
│ │ │ │
│ Keep chat history undefined │
│ Automatically delete chats older than this time period (e.g., "30d", "7d", "24h… │
│ │
│ ▼ │ │ ▼ │
│ │ │ │
│ Apply To │ │ Apply To │
@@ -119,15 +119,15 @@ exports[`SettingsDialog > Snapshot Tests > should render 'all boolean settings d
│ Plan Directory undefined │ │ Plan Directory undefined │
│ The directory where planning artifacts are stored. If not specified, defaults t… │ │ The directory where planning artifacts are stored. If not specified, defaults t… │
│ │ │ │
│ Max Chat Model Attempts 10 │
│ Maximum number of attempts for requests to the main chat model. Cannot exceed 10. │
│ │
│ Debug Keystroke Logging false* │ │ Debug Keystroke Logging false* │
│ Enable debug logging of keystrokes to the console. │ │ Enable debug logging of keystrokes to the console. │
│ │ │ │
│ Enable Session Cleanup false │ │ Enable Session Cleanup false │
│ Enable automatic session cleanup │ │ Enable automatic session cleanup │
│ │ │ │
│ Keep chat history undefined │
│ Automatically delete chats older than this time period (e.g., "30d", "7d", "24h… │
│ │
│ ▼ │ │ ▼ │
│ │ │ │
│ Apply To │ │ Apply To │
@@ -166,15 +166,15 @@ exports[`SettingsDialog > Snapshot Tests > should render 'default state' correct
│ Plan Directory undefined │ │ Plan Directory undefined │
│ The directory where planning artifacts are stored. If not specified, defaults t… │ │ The directory where planning artifacts are stored. If not specified, defaults t… │
│ │ │ │
│ Max Chat Model Attempts 10 │
│ Maximum number of attempts for requests to the main chat model. Cannot exceed 10. │
│ │
│ Debug Keystroke Logging false │ │ Debug Keystroke Logging false │
│ Enable debug logging of keystrokes to the console. │ │ Enable debug logging of keystrokes to the console. │
│ │ │ │
│ Enable Session Cleanup false │ │ Enable Session Cleanup false │
│ Enable automatic session cleanup │ │ Enable automatic session cleanup │
│ │ │ │
│ Keep chat history undefined │
│ Automatically delete chats older than this time period (e.g., "30d", "7d", "24h… │
│ │
│ ▼ │ │ ▼ │
│ │ │ │
│ Apply To │ │ Apply To │
@@ -213,15 +213,15 @@ exports[`SettingsDialog > Snapshot Tests > should render 'file filtering setting
│ Plan Directory undefined │ │ Plan Directory undefined │
│ The directory where planning artifacts are stored. If not specified, defaults t… │ │ The directory where planning artifacts are stored. If not specified, defaults t… │
│ │ │ │
│ Max Chat Model Attempts 10 │
│ Maximum number of attempts for requests to the main chat model. Cannot exceed 10. │
│ │
│ Debug Keystroke Logging false │ │ Debug Keystroke Logging false │
│ Enable debug logging of keystrokes to the console. │ │ Enable debug logging of keystrokes to the console. │
│ │ │ │
│ Enable Session Cleanup false │ │ Enable Session Cleanup false │
│ Enable automatic session cleanup │ │ Enable automatic session cleanup │
│ │ │ │
│ Keep chat history undefined │
│ Automatically delete chats older than this time period (e.g., "30d", "7d", "24h… │
│ │
│ ▼ │ │ ▼ │
│ │ │ │
│ Apply To │ │ Apply To │
@@ -260,15 +260,15 @@ exports[`SettingsDialog > Snapshot Tests > should render 'focused on scope selec
│ Plan Directory undefined │ │ Plan Directory undefined │
│ The directory where planning artifacts are stored. If not specified, defaults t… │ │ The directory where planning artifacts are stored. If not specified, defaults t… │
│ │ │ │
│ Max Chat Model Attempts 10 │
│ Maximum number of attempts for requests to the main chat model. Cannot exceed 10. │
│ │
│ Debug Keystroke Logging false │ │ Debug Keystroke Logging false │
│ Enable debug logging of keystrokes to the console. │ │ Enable debug logging of keystrokes to the console. │
│ │ │ │
│ Enable Session Cleanup false │ │ Enable Session Cleanup false │
│ Enable automatic session cleanup │ │ Enable automatic session cleanup │
│ │ │ │
│ Keep chat history undefined │
│ Automatically delete chats older than this time period (e.g., "30d", "7d", "24h… │
│ │
│ ▼ │ │ ▼ │
│ │ │ │
│ > Apply To │ │ > Apply To │
@@ -307,15 +307,15 @@ exports[`SettingsDialog > Snapshot Tests > should render 'mixed boolean and numb
│ Plan Directory undefined │ │ Plan Directory undefined │
│ The directory where planning artifacts are stored. If not specified, defaults t… │ │ The directory where planning artifacts are stored. If not specified, defaults t… │
│ │ │ │
│ Max Chat Model Attempts 10 │
│ Maximum number of attempts for requests to the main chat model. Cannot exceed 10. │
│ │
│ Debug Keystroke Logging false │ │ Debug Keystroke Logging false │
│ Enable debug logging of keystrokes to the console. │ │ Enable debug logging of keystrokes to the console. │
│ │ │ │
│ Enable Session Cleanup false │ │ Enable Session Cleanup false │
│ Enable automatic session cleanup │ │ Enable automatic session cleanup │
│ │ │ │
│ Keep chat history undefined │
│ Automatically delete chats older than this time period (e.g., "30d", "7d", "24h… │
│ │
│ ▼ │ │ ▼ │
│ │ │ │
│ Apply To │ │ Apply To │
@@ -354,15 +354,15 @@ exports[`SettingsDialog > Snapshot Tests > should render 'tools and security set
│ Plan Directory undefined │ │ Plan Directory undefined │
│ The directory where planning artifacts are stored. If not specified, defaults t… │ │ The directory where planning artifacts are stored. If not specified, defaults t… │
│ │ │ │
│ Max Chat Model Attempts 10 │
│ Maximum number of attempts for requests to the main chat model. Cannot exceed 10. │
│ │
│ Debug Keystroke Logging false │ │ Debug Keystroke Logging false │
│ Enable debug logging of keystrokes to the console. │ │ Enable debug logging of keystrokes to the console. │
│ │ │ │
│ Enable Session Cleanup false │ │ Enable Session Cleanup false │
│ Enable automatic session cleanup │ │ Enable automatic session cleanup │
│ │ │ │
│ Keep chat history undefined │
│ Automatically delete chats older than this time period (e.g., "30d", "7d", "24h… │
│ │
│ ▼ │ │ ▼ │
│ │ │ │
│ Apply To │ │ Apply To │
@@ -401,15 +401,15 @@ exports[`SettingsDialog > Snapshot Tests > should render 'various boolean settin
│ Plan Directory undefined │ │ Plan Directory undefined │
│ The directory where planning artifacts are stored. If not specified, defaults t… │ │ The directory where planning artifacts are stored. If not specified, defaults t… │
│ │ │ │
│ Max Chat Model Attempts 10 │
│ Maximum number of attempts for requests to the main chat model. Cannot exceed 10. │
│ │
│ Debug Keystroke Logging true* │ │ Debug Keystroke Logging true* │
│ Enable debug logging of keystrokes to the console. │ │ Enable debug logging of keystrokes to the console. │
│ │ │ │
│ Enable Session Cleanup false │ │ Enable Session Cleanup false │
│ Enable automatic session cleanup │ │ Enable automatic session cleanup │
│ │ │ │
│ Keep chat history undefined │
│ Automatically delete chats older than this time period (e.g., "30d", "7d", "24h… │
│ │
│ ▼ │ │ ▼ │
│ │ │ │
│ Apply To │ │ Apply To │
+24
View File
@@ -8,6 +8,7 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import type { Mock } from 'vitest'; import type { Mock } from 'vitest';
import type { ConfigParameters, SandboxConfig } from './config.js'; import type { ConfigParameters, SandboxConfig } from './config.js';
import { Config, DEFAULT_FILE_FILTERING_OPTIONS } from './config.js'; import { Config, DEFAULT_FILE_FILTERING_OPTIONS } from './config.js';
import { DEFAULT_MAX_ATTEMPTS } from '../utils/retry.js';
import { ExperimentFlags } from '../code_assist/experiments/flagNames.js'; import { ExperimentFlags } from '../code_assist/experiments/flagNames.js';
import { debugLogger } from '../utils/debugLogger.js'; import { debugLogger } from '../utils/debugLogger.js';
import { ApprovalMode } from '../policy/types.js'; import { ApprovalMode } from '../policy/types.js';
@@ -259,6 +260,29 @@ describe('Server Config (config.ts)', () => {
usageStatisticsEnabled: false, usageStatisticsEnabled: false,
}; };
describe('maxAttempts', () => {
it('should default to DEFAULT_MAX_ATTEMPTS', () => {
const config = new Config(baseParams);
expect(config.getMaxAttempts()).toBe(DEFAULT_MAX_ATTEMPTS);
});
it('should use provided maxAttempts if <= DEFAULT_MAX_ATTEMPTS', () => {
const config = new Config({
...baseParams,
maxAttempts: 5,
});
expect(config.getMaxAttempts()).toBe(5);
});
it('should cap maxAttempts at DEFAULT_MAX_ATTEMPTS', () => {
const config = new Config({
...baseParams,
maxAttempts: 20,
});
expect(config.getMaxAttempts()).toBe(DEFAULT_MAX_ATTEMPTS);
});
});
beforeEach(() => { beforeEach(() => {
// Reset mocks if necessary // Reset mocks if necessary
vi.clearAllMocks(); vi.clearAllMocks();
+11
View File
@@ -291,6 +291,7 @@ export interface ExtensionInstallMetadata {
allowPreRelease?: boolean; allowPreRelease?: boolean;
} }
import { DEFAULT_MAX_ATTEMPTS } from '../utils/retry.js';
import type { FileFilteringOptions } from './constants.js'; import type { FileFilteringOptions } from './constants.js';
import { import {
DEFAULT_FILE_FILTERING_OPTIONS, DEFAULT_FILE_FILTERING_OPTIONS,
@@ -476,6 +477,7 @@ export interface ConfigParameters {
disableModelRouterForAuth?: AuthType[]; disableModelRouterForAuth?: AuthType[];
continueOnFailedApiCall?: boolean; continueOnFailedApiCall?: boolean;
retryFetchErrors?: boolean; retryFetchErrors?: boolean;
maxAttempts?: number;
enableShellOutputEfficiency?: boolean; enableShellOutputEfficiency?: boolean;
shellToolInactivityTimeout?: number; shellToolInactivityTimeout?: number;
fakeResponses?: string; fakeResponses?: string;
@@ -657,6 +659,7 @@ export class Config {
private readonly outputSettings: OutputSettings; private readonly outputSettings: OutputSettings;
private readonly continueOnFailedApiCall: boolean; private readonly continueOnFailedApiCall: boolean;
private readonly retryFetchErrors: boolean; private readonly retryFetchErrors: boolean;
private readonly maxAttempts: number;
private readonly enableShellOutputEfficiency: boolean; private readonly enableShellOutputEfficiency: boolean;
private readonly shellToolInactivityTimeout: number; private readonly shellToolInactivityTimeout: number;
readonly fakeResponses?: string; readonly fakeResponses?: string;
@@ -879,6 +882,10 @@ export class Config {
format: params.output?.format ?? OutputFormat.TEXT, format: params.output?.format ?? OutputFormat.TEXT,
}; };
this.retryFetchErrors = params.retryFetchErrors ?? false; this.retryFetchErrors = params.retryFetchErrors ?? false;
this.maxAttempts = Math.min(
params.maxAttempts ?? DEFAULT_MAX_ATTEMPTS,
DEFAULT_MAX_ATTEMPTS,
);
this.disableYoloMode = params.disableYoloMode ?? false; this.disableYoloMode = params.disableYoloMode ?? false;
this.rawOutput = params.rawOutput ?? false; this.rawOutput = params.rawOutput ?? false;
this.acceptRawOutputRisk = params.acceptRawOutputRisk ?? false; this.acceptRawOutputRisk = params.acceptRawOutputRisk ?? false;
@@ -2415,6 +2422,10 @@ export class Config {
return this.retryFetchErrors; return this.retryFetchErrors;
} }
getMaxAttempts(): number {
return this.maxAttempts;
}
getEnableShellOutputEfficiency(): boolean { getEnableShellOutputEfficiency(): boolean {
return this.enableShellOutputEfficiency; return this.enableShellOutputEfficiency;
} }
@@ -153,6 +153,7 @@ describe('GeminiChat', () => {
}), }),
getContentGenerator: vi.fn().mockReturnValue(mockContentGenerator), getContentGenerator: vi.fn().mockReturnValue(mockContentGenerator),
getRetryFetchErrors: vi.fn().mockReturnValue(false), getRetryFetchErrors: vi.fn().mockReturnValue(false),
getMaxAttempts: vi.fn().mockReturnValue(10),
getUserTier: vi.fn().mockReturnValue(undefined), getUserTier: vi.fn().mockReturnValue(undefined),
modelConfigService: { modelConfigService: {
getResolvedConfig: vi.fn().mockImplementation((modelConfigKey) => { getResolvedConfig: vi.fn().mockImplementation((modelConfigKey) => {
+3 -7
View File
@@ -18,11 +18,7 @@ import type {
} from '@google/genai'; } from '@google/genai';
import { toParts } from '../code_assist/converter.js'; import { toParts } from '../code_assist/converter.js';
import { createUserContent, FinishReason } from '@google/genai'; import { createUserContent, FinishReason } from '@google/genai';
import { import { retryWithBackoff, isRetryableError } from '../utils/retry.js';
retryWithBackoff,
isRetryableError,
DEFAULT_MAX_ATTEMPTS,
} from '../utils/retry.js';
import type { ValidationRequiredError } from '../utils/googleQuotaErrors.js'; import type { ValidationRequiredError } from '../utils/googleQuotaErrors.js';
import type { Config } from '../config/config.js'; import type { Config } from '../config/config.js';
import { import {
@@ -635,12 +631,12 @@ export class GeminiChat {
authType: this.config.getContentGeneratorConfig()?.authType, authType: this.config.getContentGeneratorConfig()?.authType,
retryFetchErrors: this.config.getRetryFetchErrors(), retryFetchErrors: this.config.getRetryFetchErrors(),
signal: abortSignal, signal: abortSignal,
maxAttempts: availabilityMaxAttempts, maxAttempts: availabilityMaxAttempts ?? this.config.getMaxAttempts(),
getAvailabilityContext, getAvailabilityContext,
onRetry: (attempt, error, delayMs) => { onRetry: (attempt, error, delayMs) => {
coreEvents.emitRetryAttempt({ coreEvents.emitRetryAttempt({
attempt, attempt,
maxAttempts: availabilityMaxAttempts ?? DEFAULT_MAX_ATTEMPTS, maxAttempts: availabilityMaxAttempts ?? this.config.getMaxAttempts(),
delayMs, delayMs,
error: error instanceof Error ? error.message : String(error), error: error instanceof Error ? error.message : String(error),
model: lastModelToUse, model: lastModelToUse,
@@ -94,6 +94,7 @@ describe('GeminiChat Network Retries', () => {
getToolRegistry: vi.fn().mockReturnValue({ getTool: vi.fn() }), getToolRegistry: vi.fn().mockReturnValue({ getTool: vi.fn() }),
getContentGenerator: vi.fn().mockReturnValue(mockContentGenerator), getContentGenerator: vi.fn().mockReturnValue(mockContentGenerator),
getRetryFetchErrors: vi.fn().mockReturnValue(false), // Default false getRetryFetchErrors: vi.fn().mockReturnValue(false), // Default false
getMaxAttempts: vi.fn().mockReturnValue(10),
modelConfigService: { modelConfigService: {
getResolvedConfig: vi.fn().mockImplementation((modelConfigKey) => ({ getResolvedConfig: vi.fn().mockImplementation((modelConfigKey) => ({
model: modelConfigKey.model, model: modelConfigKey.model,
+7
View File
@@ -128,6 +128,13 @@
"default": false, "default": false,
"type": "boolean" "type": "boolean"
}, },
"maxAttempts": {
"title": "Max Chat Model Attempts",
"description": "Maximum number of attempts for requests to the main chat model. Cannot exceed 10.",
"markdownDescription": "Maximum number of attempts for requests to the main chat model. Cannot exceed 10.\n\n- Category: `General`\n- Requires restart: `no`\n- Default: `10`",
"default": 10,
"type": "number"
},
"debugKeystrokeLogging": { "debugKeystrokeLogging": {
"title": "Debug Keystroke Logging", "title": "Debug Keystroke Logging",
"description": "Enable debug logging of keystrokes to the console.", "description": "Enable debug logging of keystrokes to the console.",