diff --git a/.changeset/six-guests-admire.md b/.changeset/six-guests-admire.md new file mode 100644 index 00000000000..4ddbf49d4ed --- /dev/null +++ b/.changeset/six-guests-admire.md @@ -0,0 +1,5 @@ +--- +"kilo-code": minor +--- + +feat(retry): implement configurable delay and max retries diff --git a/packages/types/src/global-settings.ts b/packages/types/src/global-settings.ts index e4aa01c322e..b8f6131e3fe 100644 --- a/packages/types/src/global-settings.ts +++ b/packages/types/src/global-settings.ts @@ -83,7 +83,9 @@ export const globalSettingsSchema = z.object({ alwaysAllowDelete: z.boolean().optional(), // kilocode_change writeDelayMs: z.number().min(0).optional(), alwaysAllowBrowser: z.boolean().optional(), + alwaysApproveResubmit: z.boolean().optional(), // kilocode_change requestDelaySeconds: z.number().optional(), + requestRetryMax: z.number().min(0).optional(), // kilocode_change alwaysAllowMcp: z.boolean().optional(), alwaysAllowModeSwitch: z.boolean().optional(), alwaysAllowSubtasks: z.boolean().optional(), @@ -370,7 +372,9 @@ export const EVALS_SETTINGS: RooCodeSettings = { alwaysAllowDelete: true, // kilocode_change writeDelayMs: 1000, alwaysAllowBrowser: true, + alwaysApproveResubmit: true, // kilocode_change requestDelaySeconds: 10, + requestRetryMax: 0, // kilocode_change alwaysAllowMcp: true, alwaysAllowModeSwitch: true, alwaysAllowSubtasks: true, diff --git a/packages/types/src/vscode-extension-host.ts b/packages/types/src/vscode-extension-host.ts index 118a266f85f..7f621081ff7 100644 --- a/packages/types/src/vscode-extension-host.ts +++ b/packages/types/src/vscode-extension-host.ts @@ -493,6 +493,7 @@ export type ExtensionState = Pick< | "alwaysAllowModeSwitch" | "alwaysAllowSubtasks" | "alwaysAllowFollowupQuestions" + | "alwaysApproveResubmit" // kilocode_change | "alwaysAllowExecute" | "followupAutoApproveTimeoutMs" | "allowedCommands" @@ -568,6 +569,7 @@ export type ExtensionState = Pick< | "includeCurrentCost" | "maxGitStatusFiles" | "requestDelaySeconds" + | "requestRetryMax" // kilocode_change | "selectedMicrophoneDevice" // kilocode_change: Selected microphone device for STT > & { version: string diff --git a/src/core/auto-approval/index.ts b/src/core/auto-approval/index.ts index 3ded6bf2a05..1695b28189d 100644 --- a/src/core/auto-approval/index.ts +++ b/src/core/auto-approval/index.ts @@ -24,6 +24,7 @@ export type AutoApprovalState = | "alwaysAllowSubtasks" | "alwaysAllowExecute" | "alwaysAllowFollowupQuestions" + | "alwaysApproveResubmit" // kilocode_change // Some of these actions have additional settings associated with them. export type AutoApprovalStateOptions = diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index e6523f6fc98..b67195dc132 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -162,7 +162,6 @@ import { MessageManager } from "../message-manager" import { validateAndFixToolResultIds } from "./validateToolResultIds" import { deduplicateToolUseBlocks } from "./deduplicateToolUseBlocks" -const MAX_EXPONENTIAL_BACKOFF_SECONDS = 600 // 10 minutes const DEFAULT_USAGE_COLLECTION_TIMEOUT_MS = 5000 // 5 seconds const FORCED_CONTEXT_REDUCTION_PERCENT = 75 // Keep 75% of context (remove 25%) on context window errors const MAX_CONTEXT_WINDOW_RETRIES = 3 // Maximum retries for context window errors @@ -3595,9 +3594,14 @@ export class Task extends EventEmitter implements TaskLike { `[Task#${this.taskId}.${this.instanceId}] Stream failed, will retry: ${streamingFailedMessage}`, ) - // Apply exponential backoff similar to first-chunk errors when auto-resubmit is enabled + // Apply backoff similar to first-chunk errors when auto-resubmit is enabled const stateForBackoff = await this.providerRef.deref()?.getState() - if (stateForBackoff?.autoApprovalEnabled) { + const retryMax = stateForBackoff?.requestRetryMax ?? 0 + if ( + stateForBackoff?.autoApprovalEnabled && + stateForBackoff?.alwaysApproveResubmit && // kilocode_change + (retryMax === 0 || (currentItem.retryAttempt ?? 0) < retryMax) + ) { await this.backoffAndAnnounce(currentItem.retryAttempt ?? 0, error) // Check if task was aborted during the backoff @@ -3925,7 +3929,12 @@ export class Task extends EventEmitter implements TaskLike { // Check if we should auto-retry or prompt the user // Reuse the state variable from above - if (state?.autoApprovalEnabled) { + const retryMax = state?.requestRetryMax ?? 0 + if ( + state?.autoApprovalEnabled && + state?.alwaysApproveResubmit && // kilocode_change + (retryMax === 0 || (currentItem.retryAttempt ?? 0) < retryMax) + ) { // Auto-retry with backoff - don't persist failure message when retrying await this.backoffAndAnnounce( currentItem.retryAttempt ?? 0, @@ -4801,8 +4810,9 @@ export class Task extends EventEmitter implements TaskLike { } // kilocode_change end // note that this api_req_failed ask is unique in that we only present this option if the api hasn't streamed any content yet (ie it fails on the first chunk due), as it would allow them to hit a retry button. However if the api failed mid-stream, it could be in any arbitrary state where some tools may have executed, so that error is handled differently and requires cancelling the task entirely. - if (autoApprovalEnabled) { - // Apply shared exponential backoff and countdown UX + const retryMax = state?.requestRetryMax ?? 0 // kilocode_change + if (autoApprovalEnabled && state?.alwaysApproveResubmit && (retryMax === 0 || retryAttempt < retryMax)) { + // Apply shared backoff and countdown UX await this.backoffAndAnnounce(retryAttempt, error) // CRITICAL: Check if task was aborted during the backoff countdown @@ -4866,16 +4876,11 @@ export class Task extends EventEmitter implements TaskLike { // kilocode_change end } - // Shared exponential backoff for retries (first-chunk and mid-stream) + // Shared backoff for retries (first-chunk and mid-stream) private async backoffAndAnnounce(retryAttempt: number, error: any): Promise { try { const state = await this.providerRef.deref()?.getState() - const baseDelay = state?.requestDelaySeconds || 5 - - let exponentialDelay = Math.min( - Math.ceil(baseDelay * Math.pow(2, retryAttempt)), - MAX_EXPONENTIAL_BACKOFF_SECONDS, - ) + let requestDelaySeconds = state?.requestDelaySeconds ?? 10 // Respect provider rate limit window let rateLimitDelay = 0 @@ -4892,11 +4897,11 @@ export class Task extends EventEmitter implements TaskLike { ) const match = retryInfo?.retryDelay?.match?.(/^(\d+)s$/) if (match) { - exponentialDelay = Number(match[1]) + 1 + requestDelaySeconds = Number(match[1]) + 1 } } - const finalDelay = Math.max(exponentialDelay, rateLimitDelay) + const finalDelay = Math.max(requestDelaySeconds, rateLimitDelay) if (finalDelay <= 0) { return } diff --git a/src/core/task/__tests__/auto-retry.spec.ts b/src/core/task/__tests__/auto-retry.spec.ts new file mode 100644 index 00000000000..4cc74b0bfdd --- /dev/null +++ b/src/core/task/__tests__/auto-retry.spec.ts @@ -0,0 +1,125 @@ +import * as os from "os" +import * as path from "path" +import * as vscode from "vscode" +import { Task } from "../Task" + +// Mock dependencies +vi.mock("delay", () => ({ + __esModule: true, + default: vi.fn().mockResolvedValue(undefined), +})) + +vi.mock("p-wait-for", () => ({ + default: vi.fn().mockImplementation(async () => Promise.resolve()), +})) + +vi.mock("vscode", () => { + return { + workspace: { + getConfiguration: vi.fn(() => ({ get: vi.fn() })), + }, + env: { + uriScheme: "vscode", + language: "en", + }, + EventEmitter: vi.fn().mockImplementation(() => ({ + event: vi.fn(), + fire: vi.fn(), + })), + } +}) + +describe("Auto-Retry Logic", () => { + let mockProvider: any + let mockApiConfig: any + let mockExtensionContext: any + + beforeEach(() => { + mockExtensionContext = { + globalState: { + get: vi.fn(), + update: vi.fn(), + keys: vi.fn().mockReturnValue([]), + }, + globalStorageUri: { fsPath: path.join(os.tmpdir(), "test-storage") }, + secrets: { + get: vi.fn().mockResolvedValue(undefined), + store: vi.fn().mockResolvedValue(undefined), + }, + extensionUri: { fsPath: "/mock/path" }, + extension: { packageJSON: { version: "1.0.0" } }, + } + + mockProvider = { + getState: vi.fn().mockResolvedValue({ + autoApprovalEnabled: true, + requestDelaySeconds: 1, + requestRetryMax: 3, + }), + postMessageToWebview: vi.fn().mockResolvedValue(undefined), + postStateToWebview: vi.fn().mockResolvedValue(undefined), + } + + mockApiConfig = { + apiProvider: "anthropic", + apiModelId: "claude-3-5-sonnet-20241022", + } + }) + + it("should calculate correct delay", async () => { + const task = new Task({ + context: mockExtensionContext, + provider: mockProvider, + apiConfiguration: mockApiConfig, + task: "test", + startTask: false, + }) + + const delay = (task as any).backoffAndAnnounce(1, new Error("test")) + // We can't easily await this because it has a loop with delay() + // but we can check the internal logic if we expose it or mock delay better + }) + + it("should respect requestRetryMax and alwaysApproveResubmit", async () => { + const state = { + autoApprovalEnabled: true, + alwaysApproveResubmit: true, + requestRetryMax: 2 + } + + const shouldRetry = (attempt: number) => + state.autoApprovalEnabled && + state.alwaysApproveResubmit && + (state.requestRetryMax === 0 || attempt < state.requestRetryMax) + + // retryAttempt 0 < 2 -> should retry + expect(shouldRetry(0)).toBe(true) + // retryAttempt 1 < 2 -> should retry + expect(shouldRetry(1)).toBe(true) + // retryAttempt 2 == 2 -> should NOT retry + expect(shouldRetry(2)).toBe(false) + + // If alwaysApproveResubmit is false, should NOT retry + state.alwaysApproveResubmit = false + expect(shouldRetry(0)).toBe(false) + }) + + it("should handle unlimited retries when requestRetryMax is 0", async () => { + const state = { + autoApprovalEnabled: true, + alwaysApproveResubmit: true, + requestRetryMax: 0 + } + + const shouldRetry = (attempt: number) => + state.autoApprovalEnabled && + state.alwaysApproveResubmit && + (state.requestRetryMax === 0 || attempt < state.requestRetryMax) + + expect(shouldRetry(100)).toBe(true) + + // If alwaysApproveResubmit is false, should NOT retry even with unlimited retries + state.alwaysApproveResubmit = false + expect(shouldRetry(100)).toBe(false) + }) +}) diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index c0ffd855266..803e69a15ae 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -2251,6 +2251,7 @@ export class ClineProvider enhancementApiConfigId, commitMessageApiConfigId, // kilocode_change terminalCommandApiConfigId, // kilocode_change + requestRetryMax, // kilocode_change autoApprovalEnabled, customModes, experiments, @@ -2291,6 +2292,7 @@ export class ClineProvider dismissedNotificationIds, // kilocode_change morphApiKey, // kilocode_change fastApplyModel, // kilocode_change: Fast Apply model selection + alwaysApproveResubmit, // kilocode_change fastApplyApiProvider, // kilocode_change: Fast Apply model api base url alwaysAllowFollowupQuestions, followupAutoApproveTimeoutMs, @@ -2380,6 +2382,7 @@ export class ClineProvider alwaysAllowMcp: alwaysAllowMcp ?? false, alwaysAllowModeSwitch: alwaysAllowModeSwitch ?? false, alwaysAllowSubtasks: alwaysAllowSubtasks ?? false, + alwaysApproveResubmit: alwaysApproveResubmit ?? true, // kilocode_change isBrowserSessionActive, yoloMode: yoloMode ?? false, // kilocode_change allowedMaxRequests, @@ -2527,6 +2530,8 @@ export class ClineProvider includeCurrentTime: includeCurrentTime ?? true, includeCurrentCost: includeCurrentCost ?? true, maxGitStatusFiles: maxGitStatusFiles ?? 0, + requestDelaySeconds: requestDelaySeconds ?? 10, // kilocode_change + requestRetryMax: requestRetryMax ?? 0, // kilocode_change taskSyncEnabled, remoteControlEnabled, imageGenerationProvider, @@ -2703,6 +2708,9 @@ export class ClineProvider alwaysAllowModeSwitch: stateValues.alwaysAllowModeSwitch ?? true, alwaysAllowSubtasks: stateValues.alwaysAllowSubtasks ?? true, alwaysAllowFollowupQuestions: stateValues.alwaysAllowFollowupQuestions ?? false, + alwaysApproveResubmit: stateValues.alwaysApproveResubmit ?? true, // kilocode_change + requestDelaySeconds: stateValues.requestDelaySeconds ?? 10, // kilocode_change + requestRetryMax: stateValues.requestRetryMax ?? 0, // kilocode_change isBrowserSessionActive, yoloMode: stateValues.yoloMode ?? false, // kilocode_change followupAutoApproveTimeoutMs: stateValues.followupAutoApproveTimeoutMs ?? 60000, diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index 1e8531c41b7..0121f26b157 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -722,6 +722,12 @@ export const webviewMessageHandler = async ( if (!value) { continue } + } else if ( + key === "alwaysApproveResubmit" || + key === "requestRetryMax" || + key === "requestDelaySeconds" + ) { + newValue = value } await provider.contextProxy.setValue(key as keyof RooCodeSettings, newValue) diff --git a/webview-ui/src/components/settings/AutoApproveSettings.tsx b/webview-ui/src/components/settings/AutoApproveSettings.tsx index 8fc999c8b9f..99815085283 100644 --- a/webview-ui/src/components/settings/AutoApproveSettings.tsx +++ b/webview-ui/src/components/settings/AutoApproveSettings.tsx @@ -29,6 +29,7 @@ type AutoApproveSettingsProps = HTMLAttributes & { alwaysAllowMcp?: boolean alwaysAllowModeSwitch?: boolean alwaysAllowSubtasks?: boolean + alwaysApproveResubmit?: boolean // kilocode_change alwaysAllowExecute?: boolean alwaysAllowFollowupQuestions?: boolean followupAutoApproveTimeoutMs?: number @@ -50,6 +51,7 @@ type AutoApproveSettingsProps = HTMLAttributes & { | "alwaysAllowMcp" | "alwaysAllowModeSwitch" | "alwaysAllowSubtasks" + | "alwaysApproveResubmit" // kilocode_change | "alwaysAllowExecute" | "alwaysAllowFollowupQuestions" | "followupAutoApproveTimeoutMs" @@ -74,6 +76,7 @@ export const AutoApproveSettings = ({ alwaysAllowMcp, alwaysAllowModeSwitch, alwaysAllowSubtasks, + alwaysApproveResubmit, // kilocode_change alwaysAllowExecute, alwaysAllowFollowupQuestions, followupAutoApproveTimeoutMs = 60000, @@ -90,7 +93,16 @@ export const AutoApproveSettings = ({ const { t } = useAppTranslation() const [commandInput, setCommandInput] = useState("") const [deniedCommandInput, setDeniedCommandInput] = useState("") - const { autoApprovalEnabled, setAutoApprovalEnabled, listApiConfigMeta } = useExtensionState() // kilocode_change: Add listApiConfigMeta for gatekeeper + const { + autoApprovalEnabled, + setAutoApprovalEnabled, + alwaysApproveResubmit: alwaysApproveResubmitState, // kilocode_change + listApiConfigMeta, + requestDelaySeconds, + requestRetryMax, + setRequestRetryMax, + setRequestDelaySeconds, + } = useExtensionState() // kilocode_change: Add listApiConfigMeta for gatekeeper const toggles = useAutoApprovalToggles() @@ -199,6 +211,7 @@ export const AutoApproveSettings = ({ alwaysAllowMcp={alwaysAllowMcp} alwaysAllowModeSwitch={alwaysAllowModeSwitch} alwaysAllowSubtasks={alwaysAllowSubtasks} + alwaysApproveResubmit={alwaysApproveResubmit ?? alwaysApproveResubmitState} // kilocode_change alwaysAllowExecute={alwaysAllowExecute} alwaysAllowFollowupQuestions={alwaysAllowFollowupQuestions} onToggle={(key, value) => setCachedStateField(key, value)} @@ -314,6 +327,71 @@ export const AutoApproveSettings = ({ )} + {/* kilocode_change start */} + {(alwaysApproveResubmit ?? alwaysApproveResubmitState) && ( +
+
+ +
{t("settings:autoApprove.retry.label")}
+
+
+
+
+
+ { + setRequestDelaySeconds(value) + vscode.postMessage({ + type: "updateSettings", + updatedSettings: { requestDelaySeconds: value }, + }) + }} + /> + {requestDelaySeconds ?? 10}s +
+
+ {t("settings:autoApprove.retry.delayLabel")} +
+
+ +
+
+ { + setRequestRetryMax(value) + vscode.postMessage({ + type: "updateSettings", + updatedSettings: { requestRetryMax: value }, + }) + }} + /> + + {requestRetryMax === 0 || requestRetryMax === undefined + ? "∞" + : requestRetryMax} + +
+
+ {t("settings:autoApprove.retry.retriesLabel")} +
+
+
+ +
+
+ )} + {/* kilocode_change end */} + {alwaysAllowExecute && (
diff --git a/webview-ui/src/components/settings/AutoApproveToggle.tsx b/webview-ui/src/components/settings/AutoApproveToggle.tsx index 6bdc12bc715..dbfab13ba83 100644 --- a/webview-ui/src/components/settings/AutoApproveToggle.tsx +++ b/webview-ui/src/components/settings/AutoApproveToggle.tsx @@ -13,6 +13,7 @@ type AutoApproveToggles = Pick< | "alwaysAllowMcp" | "alwaysAllowModeSwitch" | "alwaysAllowSubtasks" + | "alwaysApproveResubmit" // kilocode_change | "alwaysAllowExecute" | "alwaysAllowFollowupQuestions" > @@ -79,6 +80,15 @@ export const autoApproveSettingsConfig: Record((props, ref) alwaysAllowMcp, alwaysAllowModeSwitch, alwaysAllowSubtasks, + alwaysApproveResubmit, // kilocode_change + requestDelaySeconds, // kilocode_change + requestRetryMax, // kilocode_change alwaysAllowWrite, alwaysAllowWriteOutsideWorkspace, alwaysAllowWriteProtected, @@ -544,6 +547,9 @@ const SettingsView = forwardRef((props, ref) alwaysAllowBrowser: alwaysAllowBrowser ?? undefined, alwaysAllowMcp, alwaysAllowModeSwitch, + alwaysApproveResubmit, // kilocode_change + requestDelaySeconds, // kilocode_change + requestRetryMax, // kilocode_change allowedCommands: allowedCommands ?? [], deniedCommands: deniedCommands ?? [], // Note that we use `null` instead of `undefined` since `JSON.stringify` @@ -1125,6 +1131,7 @@ const SettingsView = forwardRef((props, ref) alwaysAllowMcp={alwaysAllowMcp} alwaysAllowModeSwitch={alwaysAllowModeSwitch} alwaysAllowSubtasks={alwaysAllowSubtasks} + alwaysApproveResubmit={alwaysApproveResubmit} // kilocode_change alwaysAllowExecute={alwaysAllowExecute} alwaysAllowFollowupQuestions={alwaysAllowFollowupQuestions} followupAutoApproveTimeoutMs={followupAutoApproveTimeoutMs} diff --git a/webview-ui/src/components/settings/__tests__/AutoApproveToggle.spec.tsx b/webview-ui/src/components/settings/__tests__/AutoApproveToggle.spec.tsx index bd423e7bf56..bedf1c91566 100644 --- a/webview-ui/src/components/settings/__tests__/AutoApproveToggle.spec.tsx +++ b/webview-ui/src/components/settings/__tests__/AutoApproveToggle.spec.tsx @@ -24,6 +24,7 @@ describe("AutoApproveToggle", () => { alwaysAllowMcp: false, alwaysAllowModeSwitch: true, alwaysAllowSubtasks: false, + alwaysApproveResubmit: false, // kilocode_change alwaysAllowExecute: true, alwaysAllowFollowupQuestions: false, onToggle: mockOnToggle, diff --git a/webview-ui/src/context/ExtensionStateContext.tsx b/webview-ui/src/context/ExtensionStateContext.tsx index fa79612efb0..f3127b83e42 100644 --- a/webview-ui/src/context/ExtensionStateContext.tsx +++ b/webview-ui/src/context/ExtensionStateContext.tsx @@ -46,6 +46,8 @@ export interface ExtensionStateContextType extends ExtensionState { setShowDiffStats: (value: boolean) => void // kilocode_change hideCostBelowThreshold?: number // kilocode_change setHideCostBelowThreshold: (value: number) => void // kilocode_change + requestRetryMax?: number // kilocode_change + setRequestRetryMax: (value: number) => void // kilocode_change hoveringTaskTimeline?: boolean // kilocode_change setHoveringTaskTimeline: (value: boolean) => void // kilocode_change systemNotificationsEnabled?: boolean // kilocode_change @@ -124,6 +126,8 @@ export interface ExtensionStateContextType extends ExtensionState { setAlwaysAllowMcp: (value: boolean) => void setAlwaysAllowModeSwitch: (value: boolean) => void setAlwaysAllowSubtasks: (value: boolean) => void + alwaysApproveResubmit: boolean // kilocode_change + setAlwaysApproveResubmit: (value: boolean) => void // kilocode_change setBrowserToolEnabled: (value: boolean) => void setShowRooIgnoredFiles: (value: boolean) => void setShowAutoApproveMenu: (value: boolean) => void // kilocode_change @@ -133,6 +137,7 @@ export interface ExtensionStateContextType extends ExtensionState { setDeniedCommands: (value: string[]) => void setAllowedMaxRequests: (value: number | undefined) => void setAllowedMaxCost: (value: number | undefined) => void + setRequestDelaySeconds: (value: number) => void // kilocode_change setSoundEnabled: (value: boolean) => void setSoundVolume: (value: number) => void terminalShellIntegrationTimeout?: number @@ -280,7 +285,9 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode alwaysAllowWrite: true, // kilocode_change alwaysAllowReadOnly: true, // kilocode_change alwaysAllowDelete: false, // kilocode_change - requestDelaySeconds: 5, + alwaysApproveResubmit: true, // kilocode_change + requestDelaySeconds: 10, + requestRetryMax: 0, // kilocode_change currentApiConfigName: "default", listApiConfigMeta: [], mode: defaultModeSlug, @@ -393,6 +400,11 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode const [prevCloudIsAuthenticated, setPrevCloudIsAuthenticated] = useState(false) const [includeCurrentTime, setIncludeCurrentTime] = useState(true) const [includeCurrentCost, setIncludeCurrentCost] = useState(true) + // kilocode_change start + const [alwaysApproveResubmit, setAlwaysApproveResubmit] = useState(true) + const [requestDelaySeconds, setRequestDelaySeconds] = useState(10) + const [requestRetryMax, setRequestRetryMax] = useState(0) + // kilocode_change end const setListApiConfigMeta = useCallback( (value: ProviderSettingsEntry[]) => setState((prevState) => ({ ...prevState, listApiConfigMeta: value })), @@ -438,6 +450,17 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode if ((newState as any).includeCurrentCost !== undefined) { setIncludeCurrentCost((newState as any).includeCurrentCost) } + // kilocode_change start + if (newState.alwaysApproveResubmit !== undefined) { + setAlwaysApproveResubmit(newState.alwaysApproveResubmit) + } + if (newState.requestDelaySeconds !== undefined) { + setRequestDelaySeconds(newState.requestDelaySeconds) + } + if (newState.requestRetryMax !== undefined) { + setRequestRetryMax(newState.requestRetryMax) + } + // kilocode_change end // Handle marketplace data if present in state message if (newState.marketplaceItems !== undefined) { setMarketplaceItems(newState.marketplaceItems) @@ -609,6 +632,8 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode setAlwaysAllowMcp: (value) => setState((prevState) => ({ ...prevState, alwaysAllowMcp: value })), setAlwaysAllowModeSwitch: (value) => setState((prevState) => ({ ...prevState, alwaysAllowModeSwitch: value })), setAlwaysAllowSubtasks: (value) => setState((prevState) => ({ ...prevState, alwaysAllowSubtasks: value })), + alwaysApproveResubmit, // kilocode_change + setAlwaysApproveResubmit, // kilocode_change setAlwaysAllowFollowupQuestions, setFollowupAutoApproveTimeoutMs: (value) => setState((prevState) => ({ ...prevState, followupAutoApproveTimeoutMs: value })), @@ -617,6 +642,8 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode setDeniedCommands: (value) => setState((prevState) => ({ ...prevState, deniedCommands: value })), setAllowedMaxRequests: (value) => setState((prevState) => ({ ...prevState, allowedMaxRequests: value })), setAllowedMaxCost: (value) => setState((prevState) => ({ ...prevState, allowedMaxCost: value })), + requestDelaySeconds, // kilocode_change + setRequestDelaySeconds, // kilocode_change setSoundEnabled: (value) => setState((prevState) => ({ ...prevState, soundEnabled: value })), setSoundVolume: (value) => setState((prevState) => ({ ...prevState, soundVolume: value })), setTtsEnabled: (value) => setState((prevState) => ({ ...prevState, ttsEnabled: value })), @@ -669,6 +696,8 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode setSendMessageOnEnter: (value) => setState((prevState) => ({ ...prevState, sendMessageOnEnter: value })), // kilocode_change setHideCostBelowThreshold: (value) => setState((prevState) => ({ ...prevState, hideCostBelowThreshold: value })), + requestRetryMax, // kilocode_change + setRequestRetryMax, // kilocode_change setHoveringTaskTimeline: (value) => setState((prevState) => ({ ...prevState, hoveringTaskTimeline: value })), setShowTimestamps: (value) => setState((prevState) => ({ ...prevState, showTimestamps: value })), setShowDiffStats: (value) => setState((prevState) => ({ ...prevState, showDiffStats: value })), // kilocode_change diff --git a/webview-ui/src/hooks/useAutoApprovalToggles.ts b/webview-ui/src/hooks/useAutoApprovalToggles.ts index d52ad373b69..f262187dd36 100644 --- a/webview-ui/src/hooks/useAutoApprovalToggles.ts +++ b/webview-ui/src/hooks/useAutoApprovalToggles.ts @@ -16,6 +16,7 @@ export function useAutoApprovalToggles() { alwaysAllowModeSwitch, alwaysAllowSubtasks, alwaysAllowFollowupQuestions, + alwaysApproveResubmit, // kilocode_change } = useExtensionState() const toggles = useMemo( @@ -29,6 +30,7 @@ export function useAutoApprovalToggles() { alwaysAllowModeSwitch, alwaysAllowSubtasks, alwaysAllowFollowupQuestions, + alwaysApproveResubmit, // kilocode_change }), [ alwaysAllowReadOnly, @@ -40,6 +42,7 @@ export function useAutoApprovalToggles() { alwaysAllowModeSwitch, alwaysAllowSubtasks, alwaysAllowFollowupQuestions, + alwaysApproveResubmit, // kilocode_change ], ) diff --git a/webview-ui/src/i18n/locales/ar/settings.json b/webview-ui/src/i18n/locales/ar/settings.json index f4c283452e9..de3b55ac9f6 100644 --- a/webview-ui/src/i18n/locales/ar/settings.json +++ b/webview-ui/src/i18n/locales/ar/settings.json @@ -259,7 +259,8 @@ "retry": { "label": "إعادة المحاولة", "description": "إعادة محاولة طلبات API الفاشلة تلقائيًا", - "delayLabel": "تأخير قبل الإعادة" + "delayLabel": "تأخير قبل الإعادة", + "retriesLabel": "الحد الأقصى لعدد مرات إعادة المحاولة التلقائية لطلبات API" }, "mcp": { "label": "MCP", diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index d8c71a5932b..96a28826b7d 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -226,6 +226,12 @@ "label": "Navegador", "description": "Realitzar accions del navegador automàticament sense requerir aprovació. Nota: Només s'aplica quan el model admet l'ús de l'ordinador" }, + "retry": { + "label": "Reintentar", + "description": "Torna a provar automàticament les sol·licituds quan el model no proporciona una resposta o quan s'assoleix un límit de taxa.", + "delayLabel": "Retard base entre reintents (segons)", + "retriesLabel": "Nombre màxim de reintents automàtics per a sol·licituds d'API" + }, "mcp": { "label": "MCP", "description": "Habilitar l'aprovació automàtica d'eines MCP individuals a la vista de Servidors MCP (requereix tant aquesta configuració com la casella \"Permetre sempre\" de l'eina)" diff --git a/webview-ui/src/i18n/locales/cs/settings.json b/webview-ui/src/i18n/locales/cs/settings.json index 2e3950f6c88..aec3c0c1f1c 100644 --- a/webview-ui/src/i18n/locales/cs/settings.json +++ b/webview-ui/src/i18n/locales/cs/settings.json @@ -244,8 +244,9 @@ }, "retry": { "label": "Zkusit znovu", - "description": "Automaticky opakovat neúspěšné požadavky API, když server vrátí chybovou odpověď", - "delayLabel": "Zpoždění před opakováním požadavku" + "description": "Automaticky opakovat požadavky, když model neposkytne odpověď nebo když je dosaženo limitu sazeb.", + "delayLabel": "Základní zpoždění mezi pokusy (sekundy)", + "retriesLabel": "Maximální počet automatických opakování pro požadavky API" }, "mcp": { "label": "MCP", diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index d1f7bd2a6fc..f9440abdfc8 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -226,6 +226,12 @@ "label": "Browser", "description": "Browser-Aktionen automatisch ohne Genehmigung durchführen. Hinweis: Gilt nur, wenn das Modell Computer-Nutzung unterstützt" }, + "retry": { + "label": "Wiederholen", + "description": "Anfragen automatisch wiederholen, wenn das Modell keine Antwort liefert oder wenn ein Ratenlimit erreicht wird.", + "delayLabel": "Basisverzögerung zwischen Wiederholungsversuchen (Sekunden)", + "retriesLabel": "Maximale automatische Wiederholungsversuche für API-Anfragen" + }, "mcp": { "label": "MCP", "description": "Automatische Genehmigung einzelner MCP-Tools in der MCP-Server-Ansicht aktivieren (erfordert sowohl diese Einstellung als auch das 'Immer erlauben'-Kontrollkästchen des Tools)" diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 435e7ae4b8e..9018ace85fc 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -255,6 +255,12 @@ "description": "Automatically select the first suggested answer for follow-up questions after the configured timeout", "timeoutLabel": "Time to wait before auto-selecting the first answer" }, + "retry": { + "label": "Retry", + "description": "Automatically retry requests when the model fails to provide a response or when a rate limit is reached.", + "delayLabel": "Base delay between retries (seconds)", + "retriesLabel": "Maximum auto-retries for API requests" + }, "execute": { "label": "Execute", "description": "Automatically execute allowed terminal commands without requiring approval", diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index 329c6f18fe7..e0dcc2f01ff 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -230,6 +230,12 @@ "label": "Navegador", "description": "Realizar acciones del navegador automáticamente sin requerir aprobación. Nota: Solo se aplica cuando el modelo admite el uso del ordenador" }, + "retry": { + "label": "Reintentar", + "description": "Reintentar automáticamente las solicitudes cuando el modelo no proporciona una respuesta o cuando se alcanza un límite de tasa.", + "delayLabel": "Retraso base entre reintentos (segundos)", + "retriesLabel": "Máximo de reintentos automáticos para solicitudes de API" + }, "mcp": { "label": "MCP", "description": "Habilitar la aprobación automática de herramientas MCP individuales en la vista de Servidores MCP (requiere tanto esta configuración como la casilla \"Permitir siempre\" de la herramienta)" diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 61cac44349c..1493d271e87 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -227,6 +227,12 @@ "label": "Navigateur", "description": "Effectuer automatiquement des actions du navigateur sans nécessiter d'approbation. Remarque : S'applique uniquement lorsque le modèle prend en charge l'utilisation de l'ordinateur" }, + "retry": { + "label": "Réessayer", + "description": "Réessayer automatiquement les requêtes lorsque le modèle ne fournit pas de réponse ou lorsqu'une limite de débit est atteinte.", + "delayLabel": "Délai de base entre les tentatives (secondes)", + "retriesLabel": "Nombre maximal de tentatives automatiques pour les requêtes API" + }, "mcp": { "label": "MCP", "description": "Activer l'approbation automatique des outils MCP individuels dans la vue des serveurs MCP (nécessite à la fois ce paramètre et la case à cocher \"Toujours autoriser\" de l'outil)" diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index 52e8dc9e086..8ba134bb543 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -226,6 +226,12 @@ "label": "हटाएं", "description": "अनुमोदन की आवश्यकता के बिना स्वचालित रूप से फाइलें और निर्देशिकाएं हटाएं" }, + "retry": { + "label": "पुनः प्रयास करें", + "description": "जब मॉडल प्रतिक्रिया देने में विफल रहता है या जब दर सीमा तक पहुँच जाती है तो स्वचालित रूप से अनुरोधों का पुनः प्रयास करें।", + "delayLabel": "पुनः प्रयासों के बीच आधार विलंब (सेकंड)", + "retriesLabel": "API अनुरोधों के लिए अधिकतम स्वतः-पुनः प्रयास" + }, "browser": { "label": "ब्राउज़र", "description": "अनुमोदन की आवश्यकता के बिना स्वचालित रूप से ब्राउज़र क्रियाएँ करें — नोट: केवल तभी लागू होता है जब मॉडल कंप्यूटर उपयोग का समर्थन करता है" diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index 26eba087466..db101e417ce 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -230,6 +230,12 @@ "label": "Browser", "description": "Secara otomatis melakukan aksi browser tanpa memerlukan persetujuan. Catatan: Hanya berlaku ketika model mendukung computer use" }, + "retry": { + "label": "Coba Lagi", + "description": "Secara otomatis mencoba kembali permintaan saat model gagal memberikan respons atau saat batas laju tercapai.", + "delayLabel": "Penundaan dasar antar percobaan ulang (detik)", + "retriesLabel": "Maksimum percobaan ulang otomatis untuk permintaan API" + }, "mcp": { "label": "MCP", "description": "Aktifkan auto-approval tool MCP individual di tampilan Server MCP (memerlukan pengaturan ini dan checkbox \"Selalu izinkan\" tool tersebut)" diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 0bf0869132e..ef16d00da7c 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -232,8 +232,9 @@ }, "retry": { "label": "Riprova", - "description": "Riprova automaticamente le richieste API fallite quando il server restituisce una risposta di errore", - "delayLabel": "Ritardo prima di riprovare la richiesta" + "description": "Riprova automaticamente le richieste quando il modello non fornisce una risposta o quando viene raggiunto un limite di frequenza.", + "delayLabel": "Ritardo di base tra i tentativi (secondi)", + "retriesLabel": "Numero massimo di tentativi automatici per le richieste API" }, "mcp": { "label": "MCP", diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index c4aa5de4ba0..fb11cffa7f2 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -232,8 +232,9 @@ }, "retry": { "label": "再試行", - "description": "サーバーがエラーレスポンスを返した場合、自動的に失敗したAPIリクエストを再試行", - "delayLabel": "リクエスト再試行前の遅延" + "description": "モデルが応答を返さない場合や、レート制限に達した場合に、リクエストを自動的に再試行します。", + "delayLabel": "再試行間の基本遅延(秒)", + "retriesLabel": "APIリクエストの最大自動再試行回数" }, "mcp": { "label": "MCP", diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index c896d0398de..0a28fdfe619 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -226,6 +226,12 @@ "label": "브라우저", "description": "승인 없이 자동으로 브라우저 작업 수행 — 참고: 모델이 컴퓨터 사용을 지원할 때만 적용됩니다" }, + "retry": { + "label": "재시도", + "description": "모델이 응답을 제공하지 못하거나 속도 제한에 도달했을 때 요청을 자동으로 재시도합니다.", + "delayLabel": "재시도 간 기본 지연 시간(초)", + "retriesLabel": "API 요청에 대한 최대 자동 재시도 횟수" + }, "mcp": { "label": "MCP", "description": "MCP 서버 보기에서 개별 MCP 도구의 자동 승인 활성화(이 설정과 도구의 \"항상 허용\" 체크박스 모두 필요)" diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index a4957230d06..c26a43269c1 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -230,6 +230,12 @@ "label": "Browser", "description": "Automatisch browseracties uitvoeren zonder goedkeuring. Let op: geldt alleen als het model computergebruik ondersteunt." }, + "retry": { + "label": "Opnieuw proberen", + "description": "Aanvragen automatisch opnieuw proberen wanneer het model geen antwoord geeft of wanneer een snelheidslimiet is bereikt.", + "delayLabel": "Basisvertraging tussen pogingen (seconden)", + "retriesLabel": "Maximaal aantal automatische herpogingen voor API-aanvragen" + }, "mcp": { "label": "MCP", "description": "Automatische goedkeuring van individuele MCP-tools in het MCP-serversoverzicht inschakelen (vereist zowel deze instelling als het selectievakje 'Altijd toestaan' bij de tool)" diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index 52c1bdb3438..0971eb63136 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -230,6 +230,12 @@ "label": "Przeglądarka", "description": "Automatycznie wykonuj akcje przeglądarki bez konieczności zatwierdzania. Uwaga: Dotyczy tylko gdy model obsługuje używanie komputera" }, + "retry": { + "label": "Ponów", + "description": "Automatycznie ponawiaj żądania, gdy model nie dostarczy odpowiedzi lub gdy zostanie osiągnięty limit szybkości.", + "delayLabel": "Podstawowe opóźnienie między próbami (sekundy)", + "retriesLabel": "Maksymalna liczba automatycznych powtórzeń dla żądań API" + }, "mcp": { "label": "MCP", "description": "Włącz automatyczne zatwierdzanie poszczególnych narzędzi MCP w widoku Serwerów MCP (wymaga zarówno tego ustawienia, jak i pola wyboru \"Zawsze zezwalaj\" narzędzia)" diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index 35957aee465..0acca471739 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -230,6 +230,12 @@ "label": "Navegador", "description": "Realizar ações do navegador automaticamente sem exigir aprovação. Nota: Aplica-se apenas quando o modelo suporta uso do computador" }, + "retry": { + "label": "Repetir", + "description": "Repetir solicitações automaticamente quando o modelo falha em fornecer uma resposta ou quando um limite de taxa é atingido.", + "delayLabel": "Atraso base entre repetições (segundos)", + "retriesLabel": "Máximo de repetições automáticas para solicitações de API" + }, "mcp": { "label": "MCP", "description": "Ativar aprovação automática de ferramentas MCP individuais na visualização de Servidores MCP (requer tanto esta configuração quanto a caixa de seleção \"Permitir sempre\" da ferramenta)" diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index 7adf4c5e0ab..d5ffbd13a2e 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -230,6 +230,12 @@ "label": "Браузер", "description": "Автоматически выполнять действия в браузере без необходимости одобрения. Применяется только, если модель поддерживает использование компьютера" }, + "retry": { + "label": "Повторить", + "description": "Автоматически повторять запросы, если модель не дает ответа или достигнут лимит частоты запросов.", + "delayLabel": "Базовая задержка между повторами (секунды)", + "retriesLabel": "Максимальное количество автоповторов для API-запросов" + }, "mcp": { "label": "MCP", "description": "Включить автоодобрение отдельных инструментов MCP в представлении MCP Servers (требуется включить как этот параметр, так и индивидуальный чекбокс инструмента \"Всегда разрешать\")" diff --git a/webview-ui/src/i18n/locales/th/settings.json b/webview-ui/src/i18n/locales/th/settings.json index e84e8630ddd..3be54f68474 100644 --- a/webview-ui/src/i18n/locales/th/settings.json +++ b/webview-ui/src/i18n/locales/th/settings.json @@ -258,8 +258,9 @@ }, "retry": { "label": "ลองใหม่", - "description": "ลองส่งคำขอ API ที่ล้มเหลวอีกครั้งโดยอัตโนมัติเมื่อเซิร์ฟเวอร์ส่งคืนการตอบสนองที่ผิดพลาด", - "delayLabel": "หน่วงเวลาก่อนลองส่งคำขออีกครั้ง" + "description": "ลองส่งคำขอโดยอัตโนมัติเมื่อโมเดลไม่ตอบสนองหรือเมื่อถึงขีดจำกัดอัตรา", + "delayLabel": "การหน่วงเวลาพื้นฐานระหว่างการลองใหม่ (วินาที)", + "retriesLabel": "จำนวนการลองใหม่อัตโนมัติสูงสุดสำหรับคำขอ API" }, "mcp": { "label": "MCP", diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index 79c8641d998..04fa86cb415 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -230,6 +230,12 @@ "label": "Tarayıcı", "description": "Onay gerektirmeden otomatik olarak tarayıcı eylemleri gerçekleştir. Not: Yalnızca model bilgisayar kullanımını desteklediğinde geçerlidir" }, + "retry": { + "label": "Yeniden Dene", + "description": "Model yanıt vermediğinde veya bir hız sınırına ulaşıldığında istekleri otomatik olarak yeniden deneyin.", + "delayLabel": "Yeniden denemeler arasındaki temel gecikme (saniye)", + "retriesLabel": "API istekleri için maksimum otomatik yeniden deneme sayısı" + }, "mcp": { "label": "MCP", "description": "MCP Sunucuları görünümünde bireysel MCP araçlarının otomatik onayını etkinleştir (hem bu ayar hem de aracın \"Her zaman izin ver\" onay kutusu gerekir)" diff --git a/webview-ui/src/i18n/locales/uk/settings.json b/webview-ui/src/i18n/locales/uk/settings.json index f8e50810ae5..d6b02cf68f1 100644 --- a/webview-ui/src/i18n/locales/uk/settings.json +++ b/webview-ui/src/i18n/locales/uk/settings.json @@ -264,8 +264,9 @@ }, "retry": { "label": "Повторити", - "description": "Автоматично повторювати невдалі запити API, коли сервер повертає відповідь про помилку", - "delayLabel": "Затримка перед повторним запитом" + "description": "Автоматично повторювати запити, коли модель не надає відповідь або коли досягнуто ліміту частоти запитів.", + "delayLabel": "Базова затримка між спробами (секунди)", + "retriesLabel": "Максимальна кількість автоматичних повторів для запитів API" }, "mcp": { "label": "MCP", diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index eeb4d033261..c3a0b819a21 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -230,6 +230,12 @@ "label": "Trình duyệt", "description": "Tự động thực hiện các hành động trình duyệt mà không cần phê duyệt. Lưu ý: Chỉ áp dụng khi mô hình hỗ trợ sử dụng máy tính" }, + "retry": { + "label": "Thử lại", + "description": "Tự động thử lại các yêu cầu khi mô hình không cung cấp phản hồi hoặc khi đạt đến giới hạn tốc độ.", + "delayLabel": "Độ trễ cơ bản giữa các lần thử lại (giây)", + "retriesLabel": "Số lần tự động thử lại tối đa cho các yêu cầu API" + }, "mcp": { "label": "MCP", "description": "Bật tự động phê duyệt các công cụ MCP riêng lẻ trong chế độ xem Máy chủ MCP (yêu cầu cả cài đặt này và hộp kiểm \"Luôn cho phép\" của công cụ)" diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index 852e754f953..f0b834aae24 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -230,6 +230,12 @@ "label": "浏览器", "description": "自动执行浏览器操作而无需批准 — 注意:仅当模型支持计算机功能调用时适用" }, + "retry": { + "label": "重试", + "description": "当模型未能提供响应或达到速率限制时,自动重试请求。", + "delayLabel": "重试之间的基础延迟(秒)", + "retriesLabel": "API 请求的最大自动重试次数" + }, "mcp": { "label": "MCP", "description": "允许自动调用MCP服务而无需批准" diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index 7a4634c3761..8a10bc1d6b5 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -234,6 +234,12 @@ "label": "瀏覽器", "description": "無需核准即可自動執行瀏覽器動作。注意:僅適用於支援電腦操作的模型。" }, + "retry": { + "label": "重試", + "description": "當模型未能提供回應或達到速率限制時,自動重試請求。", + "delayLabel": "重試之間的基礎延遲(秒)", + "retriesLabel": "API 請求的最大自動重試次數" + }, "mcp": { "label": "MCP", "description": "啟用 MCP 伺服器檢視中個別 MCP 工具的自動核准(需同時啟用此設定與該工具的「始終允許」核取方塊)"