mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 04:11:10 -05:00
Add optional rate limiting between API calls
This commit is contained in:
@@ -96,6 +96,7 @@ export class Cline {
|
||||
didFinishAborting = false
|
||||
abandoned = false
|
||||
private diffViewProvider: DiffViewProvider
|
||||
private lastApiRequestTime?: number
|
||||
|
||||
// streaming
|
||||
private currentStreamingContentIndex = 0
|
||||
@@ -796,9 +797,40 @@ export class Cline {
|
||||
async *attemptApiRequest(previousApiReqIndex: number, retryAttempt: number = 0): ApiStream {
|
||||
let mcpHub: McpHub | undefined
|
||||
|
||||
const { mcpEnabled, alwaysApproveResubmit, requestDelaySeconds } =
|
||||
const { mcpEnabled, alwaysApproveResubmit, requestDelaySeconds, rateLimitSeconds } =
|
||||
(await this.providerRef.deref()?.getState()) ?? {}
|
||||
|
||||
let finalDelay = 0
|
||||
|
||||
// Only apply rate limiting if this isn't the first request
|
||||
if (this.lastApiRequestTime) {
|
||||
const now = Date.now()
|
||||
const timeSinceLastRequest = now - this.lastApiRequestTime
|
||||
const rateLimit = rateLimitSeconds || 0
|
||||
const rateLimitDelay = Math.max(0, rateLimit * 1000 - timeSinceLastRequest)
|
||||
finalDelay = rateLimitDelay
|
||||
}
|
||||
|
||||
// Add exponential backoff delay for retries
|
||||
if (retryAttempt > 0) {
|
||||
const baseDelay = requestDelaySeconds || 5
|
||||
const exponentialDelay = Math.ceil(baseDelay * Math.pow(2, retryAttempt)) * 1000
|
||||
finalDelay = Math.max(finalDelay, exponentialDelay)
|
||||
}
|
||||
|
||||
if (finalDelay > 0) {
|
||||
// Show countdown timer
|
||||
for (let i = Math.ceil(finalDelay / 1000); i > 0; i--) {
|
||||
const delayMessage =
|
||||
retryAttempt > 0 ? `Retrying in ${i} seconds...` : `Rate limiting for ${i} seconds...`
|
||||
await this.say("api_req_retry_delayed", delayMessage, undefined, true)
|
||||
await delay(1000)
|
||||
}
|
||||
}
|
||||
|
||||
// Update last request time before making the request
|
||||
this.lastApiRequestTime = Date.now()
|
||||
|
||||
if (mcpEnabled ?? true) {
|
||||
mcpHub = this.providerRef.deref()?.mcpHub
|
||||
if (!mcpHub) {
|
||||
|
||||
@@ -750,8 +750,11 @@ describe("Cline", () => {
|
||||
false,
|
||||
)
|
||||
|
||||
// Verify delay was called correctly
|
||||
expect(mockDelay).toHaveBeenCalledTimes(baseDelay)
|
||||
// Calculate expected delay calls based on exponential backoff
|
||||
const exponentialDelay = Math.ceil(baseDelay * Math.pow(2, 1)) // retryAttempt = 1
|
||||
const rateLimitDelay = baseDelay // Initial rate limit delay
|
||||
const totalExpectedDelays = exponentialDelay + rateLimitDelay
|
||||
expect(mockDelay).toHaveBeenCalledTimes(totalExpectedDelays)
|
||||
expect(mockDelay).toHaveBeenCalledWith(1000)
|
||||
|
||||
// Verify error message content
|
||||
|
||||
@@ -112,6 +112,7 @@ type GlobalStateKey =
|
||||
| "mcpEnabled"
|
||||
| "alwaysApproveResubmit"
|
||||
| "requestDelaySeconds"
|
||||
| "rateLimitSeconds"
|
||||
| "currentApiConfigName"
|
||||
| "listApiConfigMeta"
|
||||
| "vsCodeLmModelSelector"
|
||||
@@ -886,6 +887,10 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
await this.updateGlobalState("requestDelaySeconds", message.value ?? 5)
|
||||
await this.postStateToWebview()
|
||||
break
|
||||
case "rateLimitSeconds":
|
||||
await this.updateGlobalState("rateLimitSeconds", message.value ?? 0)
|
||||
await this.postStateToWebview()
|
||||
break
|
||||
case "preferredLanguage":
|
||||
await this.updateGlobalState("preferredLanguage", message.text)
|
||||
await this.postStateToWebview()
|
||||
@@ -1997,6 +2002,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
mcpEnabled,
|
||||
alwaysApproveResubmit,
|
||||
requestDelaySeconds,
|
||||
rateLimitSeconds,
|
||||
currentApiConfigName,
|
||||
listApiConfigMeta,
|
||||
mode,
|
||||
@@ -2038,6 +2044,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
mcpEnabled: mcpEnabled ?? true,
|
||||
alwaysApproveResubmit: alwaysApproveResubmit ?? false,
|
||||
requestDelaySeconds: requestDelaySeconds ?? 10,
|
||||
rateLimitSeconds: rateLimitSeconds ?? 0,
|
||||
currentApiConfigName: currentApiConfigName ?? "default",
|
||||
listApiConfigMeta: listApiConfigMeta ?? [],
|
||||
mode: mode ?? defaultModeSlug,
|
||||
@@ -2161,6 +2168,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
mcpEnabled,
|
||||
alwaysApproveResubmit,
|
||||
requestDelaySeconds,
|
||||
rateLimitSeconds,
|
||||
currentApiConfigName,
|
||||
listApiConfigMeta,
|
||||
vsCodeLmModelSelector,
|
||||
@@ -2233,6 +2241,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
this.getGlobalState("mcpEnabled") as Promise<boolean | undefined>,
|
||||
this.getGlobalState("alwaysApproveResubmit") as Promise<boolean | undefined>,
|
||||
this.getGlobalState("requestDelaySeconds") as Promise<number | undefined>,
|
||||
this.getGlobalState("rateLimitSeconds") as Promise<number | undefined>,
|
||||
this.getGlobalState("currentApiConfigName") as Promise<string | undefined>,
|
||||
this.getGlobalState("listApiConfigMeta") as Promise<ApiConfigMeta[] | undefined>,
|
||||
this.getGlobalState("vsCodeLmModelSelector") as Promise<vscode.LanguageModelChatSelector | undefined>,
|
||||
@@ -2355,6 +2364,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
mcpEnabled: mcpEnabled ?? true,
|
||||
alwaysApproveResubmit: alwaysApproveResubmit ?? false,
|
||||
requestDelaySeconds: Math.max(5, requestDelaySeconds ?? 10),
|
||||
rateLimitSeconds: rateLimitSeconds ?? 0,
|
||||
currentApiConfigName: currentApiConfigName ?? "default",
|
||||
listApiConfigMeta: listApiConfigMeta ?? [],
|
||||
modeApiConfigs: modeApiConfigs ?? ({} as Record<Mode, string>),
|
||||
|
||||
@@ -324,6 +324,7 @@ describe("ClineProvider", () => {
|
||||
fuzzyMatchThreshold: 1.0,
|
||||
mcpEnabled: true,
|
||||
requestDelaySeconds: 5,
|
||||
rateLimitSeconds: 0,
|
||||
mode: defaultModeSlug,
|
||||
customModes: [],
|
||||
experiments: experimentDefault,
|
||||
|
||||
Reference in New Issue
Block a user