feat(vscode): exponential backoff retry with cancel button for rate limiting#8435
Conversation
| const status = result.response?.status ?? 0 | ||
|
|
||
| // Check for non-retryable status codes — fail immediately without retry | ||
| if (!retryable(status) && attempt > 1) { |
There was a problem hiding this comment.
WARNING: Non-retryable errors still retry once
The immediate-fail guard is gated on attempt > 1, so a 400/401/403 response on the first call falls through to the backoff path and gets retried anyway. That adds an unnecessary second request for errors the user must fix locally.
Code Review SummaryStatus: 1 Issue Found | Recommendation: Address before merge Overview
Fix these issues in Kilo Cloud Issue Details (click to expand)WARNING
Other Observations (not in diff)Previously reported issues in Previously reported model-switch crash in Files Reviewed (2 files)
Reviewed by gpt-5.4-20260305 · 325,004 tokens |
65fb86d to
7d2fbad
Compare
| const timer = setTimeout(resolve, delay) | ||
| abortController.signal.addEventListener("abort", () => { | ||
| clearTimeout(timer) | ||
| reject(new Error("Retry cancelled")) |
There was a problem hiding this comment.
WARNING: Cancelling a retry is surfaced as a send failure
This Error("Retry cancelled") bubbles into handleSendMessage() / handleSendCommand(), which then emits sendMessageFailed. The result is that clicking Cancel shows a failure toast and restores the prompt back into the composer even though the request was already accepted by the server; cancellation should follow the abort path instead of the generic send-failed path.
| applyModel(selectedAgentName(), { providerID, modelID }) | ||
| const sid = currentSessionID() | ||
| if (sid) { | ||
| setStore("messages", sid, (msgs) => msgs.filter((m) => !m.error)) |
There was a problem hiding this comment.
WARNING: Switching models can throw before messages finish loading
selectSession() sets currentSessionID before loadMessages populates store.messages[sid], so if the user changes models during that loading window msgs is still undefined here and .filter(...) crashes the webview.
| setStore("messages", sid, (msgs) => msgs.filter((m) => !m.error)) | |
| setStore("messages", sid, (msgs = []) => msgs.filter((m) => !m.error)) |
…te limiting Implement retry with exponential backoff when the extension encounters rate limiting (HTTP 429) or server errors. Retries on: 5s -> 10s -> 30s -> 60s -> 300s, with a maximum of 5 attempts. - Add retry utility module (retry.ts) with backoff calculation - Add withRetry() wrapper for SDK calls in KiloProvider - Add Cancel button to WorkingIndicator during retry status - Clear error messages when model changes (issue #8203) - Add i18n translations for cancel button (18 languages) Users can manually cancel via the cancel button or the retry loop automatically stops after 5 failed attempts. Issues: #8333, #8203
7d2fbad to
613606b
Compare
| }) | ||
|
|
||
| // Wait for delay or until aborted | ||
| await new Promise((resolve) => { |
There was a problem hiding this comment.
WARNING: Cancelling during backoff leaves the retry stuck
If abort fires while this sleep is pending, the handler only clears the timeout; it never resolves or rejects the surrounding promise. withRetry() then never reaches the next loop iteration or the finally block, so the cancelled send hangs indefinitely and the abort-controller entry is never cleaned up for that session.
There was a problem hiding this comment.
imho it sounds like it makes sense
There was a problem hiding this comment.
Isn't this already implemented here? https://github.com/Kilo-Org/kilocode/blob/main/packages/opencode/src/session/retry.ts
There was a problem hiding this comment.
Yes, it's similar but works at different levels.
There was a problem hiding this comment.
and we need it at multiple levels?
There was a problem hiding this comment.
The new file handle the errors between the VSCode Backend HTTP Client and the CLI Backend Server . The opencode/src/session/retry.ts handle the errors from the AI SDK Providers.
feat(vscode): exponential backoff retry with cancel button for rate limiting
Context
Implement exponential backoff retry with a cancel button for rate limiting (HTTP 429) and server errors in the VSCode extension. When the extension encounters rate limiting, it now automatically retries with increasing delays, and users can manually cancel the retry loop at any time.
This also addresses issue #8203 by clearing error messages when the user changes to a different model.
Implementation
Retry utility (
packages/kilo-vscode/src/util/retry.ts): New module with backoff calculation functionsretryable(): Checks if HTTP status should be retried (429, 5xx, etc.)backoff(): Calculates delay (5s -> 10s -> 30s -> 60s -> 300s)headerDelay(): Extracts Retry-After headersKiloProvider (
packages/kilo-vscode/src/KiloProvider.ts):withRetry()wrapper for SDK callssessionStatusmessages with retry countdownWorkingIndicator (
packages/kilo-vscode/webview-ui/src/components/shared/WorkingIndicator.tsx):Session context (
packages/kilo-vscode/webview-ui/src/context/session.tsx):selectModel()now clears error messages when model changesi18n: Added translations for 18 languages
Screenshots
How to Test