Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 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
2 changes: 0 additions & 2 deletions .roo/rules/rules.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Code Quality Rules

1. Test Coverage:

- Before attempting completion, always make sure that any code changes have test coverage
- Ensure all tests pass before submitting changes
- The vitest framework is used for testing; the `describe`, `test`, `it`, etc functions are defined by default in `tsconfig.json` and therefore don't need to be imported
Expand All @@ -14,7 +13,6 @@
- Example: For `src/tests/user.test.ts`, run `cd src && npx vitest tests/user.test.ts` NOT `npx vitest src/tests/user.test.ts`

2. Lint Rules:

- Never disable any lint rules without explicit user approval

3. Styling Guidelines:
Expand Down
74 changes: 38 additions & 36 deletions locales/ca/README.md

Large diffs are not rendered by default.

74 changes: 38 additions & 36 deletions locales/de/README.md

Large diffs are not rendered by default.

74 changes: 38 additions & 36 deletions locales/es/README.md

Large diffs are not rendered by default.

74 changes: 38 additions & 36 deletions locales/fr/README.md

Large diffs are not rendered by default.

74 changes: 38 additions & 36 deletions locales/hi/README.md

Large diffs are not rendered by default.

74 changes: 38 additions & 36 deletions locales/id/README.md

Large diffs are not rendered by default.

74 changes: 38 additions & 36 deletions locales/it/README.md

Large diffs are not rendered by default.

74 changes: 38 additions & 36 deletions locales/ja/README.md

Large diffs are not rendered by default.

74 changes: 38 additions & 36 deletions locales/ko/README.md

Large diffs are not rendered by default.

74 changes: 38 additions & 36 deletions locales/nl/README.md

Large diffs are not rendered by default.

74 changes: 38 additions & 36 deletions locales/pl/README.md

Large diffs are not rendered by default.

74 changes: 38 additions & 36 deletions locales/pt-BR/README.md

Large diffs are not rendered by default.

74 changes: 38 additions & 36 deletions locales/ru/README.md

Large diffs are not rendered by default.

74 changes: 38 additions & 36 deletions locales/tr/README.md

Large diffs are not rendered by default.

74 changes: 38 additions & 36 deletions locales/vi/README.md

Large diffs are not rendered by default.

74 changes: 38 additions & 36 deletions locales/zh-CN/README.md

Large diffs are not rendered by default.

74 changes: 38 additions & 36 deletions locales/zh-TW/README.md

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion packages/types/src/global-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const globalSettingsSchema = z.object({
alwaysAllowBrowser: z.boolean().optional(),
alwaysApproveResubmit: z.boolean().optional(),
requestDelaySeconds: z.number().optional(),
maxRequestDelaySeconds: z.number().optional(),
alwaysAllowMcp: z.boolean().optional(),
alwaysAllowModeSwitch: z.boolean().optional(),
alwaysAllowSubtasks: z.boolean().optional(),
Expand Down Expand Up @@ -188,7 +189,8 @@ export const EVALS_SETTINGS: RooCodeSettings = {
writeDelayMs: 1000,
alwaysAllowBrowser: true,
alwaysApproveResubmit: true,
requestDelaySeconds: 10,
requestDelaySeconds: 5,
maxRequestDelaySeconds: 600,
alwaysAllowMcp: true,
alwaysAllowModeSwitch: true,
alwaysAllowSubtasks: true,
Expand Down
16 changes: 10 additions & 6 deletions src/core/task/Task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1648,6 +1648,7 @@ export class Task extends EventEmitter<ClineEvents> {
autoApprovalEnabled,
alwaysApproveResubmit,
requestDelaySeconds,
maxRequestDelaySeconds,
mode,
autoCondenseContext = true,
autoCondenseContextPercent = 100,
Expand Down Expand Up @@ -1716,7 +1717,9 @@ export class Task extends EventEmitter<ClineEvents> {

const contextWindow = modelInfo.contextWindow

const currentProfileId = state?.listApiConfigMeta.find((profile) => profile.name === state?.currentApiConfigName)?.id ?? "default";
const currentProfileId =
state?.listApiConfigMeta.find((profile) => profile.name === state?.currentApiConfigName)?.id ??
"default"

const truncateResult = await truncateConversationIfNeeded({
messages: this.apiConversationHistory,
Expand Down Expand Up @@ -1801,11 +1804,12 @@ export class Task extends EventEmitter<ClineEvents> {
errorMsg = "Unknown error"
}

const baseDelay = requestDelaySeconds || 5
let exponentialDelay = Math.min(
Math.ceil(baseDelay * Math.pow(2, retryAttempt)),
MAX_EXPONENTIAL_BACKOFF_SECONDS,
)
const minDelay = requestDelaySeconds ?? 5
const maxDelay = maxRequestDelaySeconds ?? MAX_EXPONENTIAL_BACKOFF_SECONDS

let exponentialDelay = Math.ceil(minDelay * Math.pow(2, retryAttempt))

exponentialDelay = Math.max(minDelay, Math.min(exponentialDelay, maxDelay))

// If the error is a 429, and the error details contain a retry delay, use that delay instead of exponential backoff
if (error.status === 429) {
Expand Down
7 changes: 5 additions & 2 deletions src/core/webview/ClineProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1382,6 +1382,7 @@ export class ClineProvider
enableMcpServerCreation,
alwaysApproveResubmit,
requestDelaySeconds,
maxRequestDelaySeconds,
currentApiConfigName,
listApiConfigMeta,
pinnedApiConfigs,
Expand Down Expand Up @@ -1477,7 +1478,8 @@ export class ClineProvider
mcpEnabled: mcpEnabled ?? true,
enableMcpServerCreation: enableMcpServerCreation ?? true,
alwaysApproveResubmit: alwaysApproveResubmit ?? false,
requestDelaySeconds: requestDelaySeconds ?? 10,
requestDelaySeconds: requestDelaySeconds ?? 5,
maxRequestDelaySeconds: maxRequestDelaySeconds ?? 600,
currentApiConfigName: currentApiConfigName ?? "default",
listApiConfigMeta: listApiConfigMeta ?? [],
pinnedApiConfigs: pinnedApiConfigs ?? {},
Expand Down Expand Up @@ -1641,7 +1643,8 @@ export class ClineProvider
mcpEnabled: stateValues.mcpEnabled ?? true,
enableMcpServerCreation: stateValues.enableMcpServerCreation ?? true,
alwaysApproveResubmit: stateValues.alwaysApproveResubmit ?? false,
requestDelaySeconds: Math.max(5, stateValues.requestDelaySeconds ?? 10),
requestDelaySeconds: Math.max(1, stateValues.requestDelaySeconds ?? 5),
maxRequestDelaySeconds: Math.min(600, stateValues.maxRequestDelaySeconds ?? 600),
currentApiConfigName: stateValues.currentApiConfigName ?? "default",
listApiConfigMeta: stateValues.listApiConfigMeta ?? [],
pinnedApiConfigs: stateValues.pinnedApiConfigs ?? {},
Expand Down
27 changes: 23 additions & 4 deletions src/core/webview/__tests__/ClineProvider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,7 @@ describe("ClineProvider", () => {
mcpEnabled: true,
enableMcpServerCreation: false,
requestDelaySeconds: 5,
maxRequestDelaySeconds: 600,
mode: defaultModeSlug,
customModes: [],
experiments: experimentDefault,
Expand Down Expand Up @@ -800,7 +801,7 @@ describe("ClineProvider", () => {
expect(mockPostMessage).toHaveBeenCalled()
})

test("requestDelaySeconds defaults to 10 seconds", async () => {
test("requestDelaySeconds defaults to 5 seconds", async () => {
// Mock globalState.get to return undefined for requestDelaySeconds
;(mockContext.globalState.get as any).mockImplementation((key: string) => {
if (key === "requestDelaySeconds") {
Expand All @@ -810,7 +811,20 @@ describe("ClineProvider", () => {
})

const state = await provider.getState()
expect(state.requestDelaySeconds).toBe(10)
expect(state.requestDelaySeconds).toBe(5)
})

test("maxRequestDelaySeconds defaults to 600 seconds", async () => {
// Mock globalState.get to return undefined for requestDelaySeconds
;(mockContext.globalState.get as any).mockImplementation((key: string) => {
if (key === "maxRequestDelaySeconds") {
return undefined
}
return null
})

const state = await provider.getState()
expect(state.maxRequestDelaySeconds).toBe(600)
})

test("alwaysApproveResubmit defaults to false", async () => {
Expand Down Expand Up @@ -1002,8 +1016,13 @@ describe("ClineProvider", () => {
expect(mockPostMessage).toHaveBeenCalled()

// Test requestDelaySeconds
await messageHandler({ type: "requestDelaySeconds", value: 10 })
expect(mockContext.globalState.update).toHaveBeenCalledWith("requestDelaySeconds", 10)
await messageHandler({ type: "requestDelaySeconds", value: 5 })
expect(mockContext.globalState.update).toHaveBeenCalledWith("requestDelaySeconds", 5)
expect(mockPostMessage).toHaveBeenCalled()

// Test maxRequestDelaySeconds
await messageHandler({ type: "maxRequestDelaySeconds", value: 600 })
expect(mockContext.globalState.update).toHaveBeenCalledWith("maxRequestDelaySeconds", 600)
expect(mockPostMessage).toHaveBeenCalled()
})

Expand Down
4 changes: 4 additions & 0 deletions src/core/webview/webviewMessageHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,10 @@ export const webviewMessageHandler = async (
await updateGlobalState("requestDelaySeconds", message.value ?? 5)
await provider.postStateToWebview()
break
case "maxRequestDelaySeconds":
await updateGlobalState("maxRequestDelaySeconds", Math.max(1, message.value ?? 600))
await provider.postStateToWebview()
break
case "writeDelayMs":
await updateGlobalState("writeDelayMs", message.value)
await provider.postStateToWebview()
Expand Down
1 change: 1 addition & 0 deletions src/shared/ExtensionMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ export type ExtensionState = Pick<

writeDelayMs: number
requestDelaySeconds: number
maxRequestDelaySeconds: number

enableCheckpoints: boolean
maxOpenTabsContext: number // Maximum number of VSCode open tabs to include in context (0-500)
Expand Down
1 change: 1 addition & 0 deletions src/shared/WebviewMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ export interface WebviewMessage {
| "searchCommits"
| "alwaysApproveResubmit"
| "requestDelaySeconds"
| "maxRequestDelaySeconds"
| "setApiConfigPassword"
| "mode"
| "updatePrompt"
Expand Down
25 changes: 18 additions & 7 deletions webview-ui/src/components/settings/AutoApproveSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type AutoApproveSettingsProps = HTMLAttributes<HTMLDivElement> & {
alwaysAllowBrowser?: boolean
alwaysApproveResubmit?: boolean
requestDelaySeconds: number
maxRequestDelaySeconds: number
alwaysAllowMcp?: boolean
alwaysAllowModeSwitch?: boolean
alwaysAllowSubtasks?: boolean
Expand All @@ -38,6 +39,7 @@ type AutoApproveSettingsProps = HTMLAttributes<HTMLDivElement> & {
| "alwaysAllowBrowser"
| "alwaysApproveResubmit"
| "requestDelaySeconds"
| "maxRequestDelaySeconds"
| "alwaysAllowMcp"
| "alwaysAllowModeSwitch"
| "alwaysAllowSubtasks"
Expand All @@ -58,6 +60,7 @@ export const AutoApproveSettings = ({
alwaysAllowBrowser,
alwaysApproveResubmit,
requestDelaySeconds,
maxRequestDelaySeconds,
alwaysAllowMcp,
alwaysAllowModeSwitch,
alwaysAllowSubtasks,
Expand Down Expand Up @@ -193,17 +196,25 @@ export const AutoApproveSettings = ({
<div>
<div className="flex items-center gap-2">
<Slider
min={5}
max={100}
min={1}
max={600}
step={1}
value={[requestDelaySeconds]}
onValueChange={([value]) => setCachedStateField("requestDelaySeconds", value)}
data-testid="request-delay-slider"
value={[requestDelaySeconds, maxRequestDelaySeconds]}
onValueChange={([min, max]) => {
// Ensure min <= max
const actualMin = Math.min(min, max)
const actualMax = Math.max(min, max)
setCachedStateField("requestDelaySeconds", actualMin)
setCachedStateField("maxRequestDelaySeconds", actualMax)
}}
data-testid="retry-delay-range-slider"
/>
<span className="w-20">{requestDelaySeconds}s</span>
<span className="w-20">
{requestDelaySeconds}s - {maxRequestDelaySeconds}s
</span>
</div>
<div className="text-vscode-descriptionForeground text-sm mt-1">
{t("settings:autoApprove.retry.delayLabel")}
{t("settings:autoApprove.retry.rangeLabel")}
</div>
</div>
</div>
Expand Down
3 changes: 3 additions & 0 deletions webview-ui/src/components/settings/SettingsView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
maxWorkspaceFiles,
mcpEnabled,
requestDelaySeconds,
maxRequestDelaySeconds,
remoteBrowserHost,
screenshotQuality,
soundEnabled,
Expand Down Expand Up @@ -304,6 +305,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
vscode.postMessage({ type: "mcpEnabled", bool: mcpEnabled })
vscode.postMessage({ type: "alwaysApproveResubmit", bool: alwaysApproveResubmit })
vscode.postMessage({ type: "requestDelaySeconds", value: requestDelaySeconds })
vscode.postMessage({ type: "maxRequestDelaySeconds", value: maxRequestDelaySeconds })
vscode.postMessage({ type: "maxOpenTabsContext", value: maxOpenTabsContext })
vscode.postMessage({ type: "maxWorkspaceFiles", value: maxWorkspaceFiles ?? 200 })
vscode.postMessage({ type: "showRooIgnoredFiles", bool: showRooIgnoredFiles })
Expand Down Expand Up @@ -599,6 +601,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
alwaysAllowBrowser={alwaysAllowBrowser}
alwaysApproveResubmit={alwaysApproveResubmit}
requestDelaySeconds={requestDelaySeconds}
maxRequestDelaySeconds={maxRequestDelaySeconds}
alwaysAllowMcp={alwaysAllowMcp}
alwaysAllowModeSwitch={alwaysAllowModeSwitch}
alwaysAllowSubtasks={alwaysAllowSubtasks}
Expand Down
11 changes: 10 additions & 1 deletion webview-ui/src/components/ui/slider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,16 @@ const Slider = React.forwardRef<
<SliderPrimitive.Track className="relative w-full h-[8px] grow overflow-hidden bg-accent rounded-sm border">
<SliderPrimitive.Range className="absolute h-full bg-vscode-button-background" />
</SliderPrimitive.Track>
<SliderPrimitive.Thumb className="block h-3 w-3 rounded-full border border-primary/50 bg-vscode-button-background transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" />
{Array.isArray(props.value) ? (
props.value.map((_, i) => (
<SliderPrimitive.Thumb
key={i}
className="block h-3 w-3 rounded-full border border-primary/50 bg-vscode-button-background transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50"
/>
))
) : (
<SliderPrimitive.Thumb className="block h-3 w-3 rounded-full border border-primary/50 bg-vscode-button-background transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" />
)}
</SliderPrimitive.Root>
))
Slider.displayName = SliderPrimitive.Root.displayName
Expand Down
5 changes: 5 additions & 0 deletions webview-ui/src/context/ExtensionStateContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ export interface ExtensionStateContextType extends ExtensionState {
alwaysApproveResubmit?: boolean
setAlwaysApproveResubmit: (value: boolean) => void
requestDelaySeconds: number
maxRequestDelaySeconds: number
setRequestDelaySeconds: (value: number) => void
setMaxRequestDelaySeconds: (value: number) => void
setCurrentApiConfigName: (value: string) => void
setListApiConfigMeta: (value: ProviderSettingsEntry[]) => void
mode: Mode
Expand Down Expand Up @@ -177,6 +179,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
enableMcpServerCreation: false,
alwaysApproveResubmit: false,
requestDelaySeconds: 5,
maxRequestDelaySeconds: 600,
currentApiConfigName: "default",
listApiConfigMeta: [],
mode: defaultModeSlug,
Expand Down Expand Up @@ -412,6 +415,8 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
setState((prevState) => ({ ...prevState, enableMcpServerCreation: value })),
setAlwaysApproveResubmit: (value) => setState((prevState) => ({ ...prevState, alwaysApproveResubmit: value })),
setRequestDelaySeconds: (value) => setState((prevState) => ({ ...prevState, requestDelaySeconds: value })),
setMaxRequestDelaySeconds: (value) =>
setState((prevState) => ({ ...prevState, maxRequestDelaySeconds: value })),
setCurrentApiConfigName: (value) => setState((prevState) => ({ ...prevState, currentApiConfigName: value })),
setListApiConfigMeta,
setMode: (value: Mode) => setState((prevState) => ({ ...prevState, mode: value })),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ describe("mergeExtensionState", () => {
enableCheckpoints: true,
writeDelayMs: 1000,
requestDelaySeconds: 5,
maxRequestDelaySeconds: 600,
mode: "default",
experiments: {} as Record<ExperimentId, boolean>,
customModes: [],
Expand Down
2 changes: 1 addition & 1 deletion webview-ui/src/i18n/locales/ca/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
"retry": {
"label": "Reintentar",
"description": "Tornar a intentar sol·licituds d'API fallides automàticament quan el servidor retorna una resposta d'error",
"delayLabel": "Retard abans de tornar a intentar la sol·licitud"
"rangeLabel": "Rang de retard de reintent (min - màx segons)"
},
"mcp": {
"label": "MCP",
Expand Down
2 changes: 1 addition & 1 deletion webview-ui/src/i18n/locales/de/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
"retry": {
"label": "Wiederholung",
"description": "Fehlgeschlagene API-Anfragen automatisch wiederholen, wenn der Server eine Fehlerantwort zurückgibt",
"delayLabel": "Verzögerung vor dem Wiederholen der Anfrage"
"rangeLabel": "Wiederholungsverzögerungsbereich (min - max Sekunden)"
},
"mcp": {
"label": "MCP",
Expand Down
2 changes: 1 addition & 1 deletion webview-ui/src/i18n/locales/en/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
"retry": {
"label": "Retry",
"description": "Automatically retry failed API requests when server returns an error response",
"delayLabel": "Delay before retrying the request"
"rangeLabel": "Retry delay range (min - max seconds)"
},
"mcp": {
"label": "MCP",
Expand Down
2 changes: 1 addition & 1 deletion webview-ui/src/i18n/locales/es/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
"retry": {
"label": "Reintentar",
"description": "Reintentar automáticamente solicitudes de API fallidas cuando el servidor devuelve una respuesta de error",
"delayLabel": "Retraso antes de reintentar la solicitud"
"rangeLabel": "Rango de retraso de reintento (min - máx segundos)"
},
"mcp": {
"label": "MCP",
Expand Down
2 changes: 1 addition & 1 deletion webview-ui/src/i18n/locales/fr/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
"retry": {
"label": "Réessayer",
"description": "Réessayer automatiquement les requêtes API échouées lorsque le serveur renvoie une réponse d'erreur",
"delayLabel": "Délai avant de réessayer la requête"
"rangeLabel": "Plage de délai de nouvelle tentative (min - max secondes)"
},
"mcp": {
"label": "MCP",
Expand Down
2 changes: 1 addition & 1 deletion webview-ui/src/i18n/locales/hi/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
"retry": {
"label": "पुनः प्रयास",
"description": "जब सर्वर त्रुटि प्रतिक्रिया देता है तो स्वचालित रूप से विफल API अनुरोधों को पुनः प्रयास करें",
"delayLabel": "अनुरोध को पुनः प्रयास करने से पहले विलंब"
"rangeLabel": "पुनः प्रयास विलंब सीमा (न्यूनतम - अधिकतम सेकंड)"
},
"mcp": {
"label": "MCP",
Expand Down
2 changes: 1 addition & 1 deletion webview-ui/src/i18n/locales/id/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
"retry": {
"label": "Coba Lagi",
"description": "Secara otomatis mencoba ulang permintaan API yang gagal ketika server mengembalikan respons error",
"delayLabel": "Delay sebelum mencoba ulang permintaan"
"rangeLabel": "Rentang delay percobaan ulang (min - maks detik)"
},
"mcp": {
"label": "MCP",
Expand Down
2 changes: 1 addition & 1 deletion webview-ui/src/i18n/locales/it/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
"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"
"rangeLabel": "Intervallo di ritardo per i tentativi (min - max secondi)"
},
"mcp": {
"label": "MCP",
Expand Down
2 changes: 1 addition & 1 deletion webview-ui/src/i18n/locales/ja/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
"retry": {
"label": "再試行",
"description": "サーバーがエラーレスポンスを返した場合、自動的に失敗したAPIリクエストを再試行",
"delayLabel": "リクエスト再試行前の遅延"
"rangeLabel": "再試行遅延範囲(最小 - 最大秒)"
},
"mcp": {
"label": "MCP",
Expand Down
Loading