From 613606b07d21d7d36a19ee67362981fa59c9f975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Catriel=20M=C3=BCller?= Date: Mon, 6 Apr 2026 16:30:59 -0300 Subject: [PATCH] feat(vscode): add exponential backoff retry with cancel button for rate 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 --- packages/kilo-vscode/src/KiloProvider.ts | 137 ++++++++++++++---- packages/kilo-vscode/src/util/retry.ts | 70 +++++++++ .../components/shared/WorkingIndicator.tsx | 25 +++- .../webview-ui/src/context/session.tsx | 4 + .../kilo-vscode/webview-ui/src/i18n/ar.ts | 4 + .../kilo-vscode/webview-ui/src/i18n/br.ts | 4 + .../kilo-vscode/webview-ui/src/i18n/bs.ts | 4 + .../kilo-vscode/webview-ui/src/i18n/da.ts | 4 + .../kilo-vscode/webview-ui/src/i18n/de.ts | 4 + .../kilo-vscode/webview-ui/src/i18n/en.ts | 4 + .../kilo-vscode/webview-ui/src/i18n/es.ts | 4 + .../kilo-vscode/webview-ui/src/i18n/fr.ts | 4 + .../kilo-vscode/webview-ui/src/i18n/ja.ts | 4 + .../kilo-vscode/webview-ui/src/i18n/ko.ts | 4 + .../kilo-vscode/webview-ui/src/i18n/nl.ts | 4 + .../kilo-vscode/webview-ui/src/i18n/no.ts | 4 + .../kilo-vscode/webview-ui/src/i18n/pl.ts | 4 + .../kilo-vscode/webview-ui/src/i18n/ru.ts | 4 + .../kilo-vscode/webview-ui/src/i18n/th.ts | 4 + .../kilo-vscode/webview-ui/src/i18n/tr.ts | 4 + .../kilo-vscode/webview-ui/src/i18n/uk.ts | 4 + .../kilo-vscode/webview-ui/src/i18n/zh.ts | 4 + .../kilo-vscode/webview-ui/src/i18n/zht.ts | 4 + 23 files changed, 286 insertions(+), 26 deletions(-) create mode 100644 packages/kilo-vscode/src/util/retry.ts diff --git a/packages/kilo-vscode/src/KiloProvider.ts b/packages/kilo-vscode/src/KiloProvider.ts index 372d076d5c4..d8ad6804f26 100644 --- a/packages/kilo-vscode/src/KiloProvider.ts +++ b/packages/kilo-vscode/src/KiloProvider.ts @@ -40,6 +40,7 @@ import { resolveProjectDirectory } from "./project-directory" import { getBusySessionCount, seedSessionStatuses } from "./session-status" import { slimPart, slimParts } from "./kilo-provider/slim-metadata" import { matchFollowup, recordFollowup, type Followup } from "./kilo-provider/followup-session" +import { retryable, backoff, MAX_RETRIES } from "./util/retry" // legacy-migration start import { checkAndShowMigrationWizard, @@ -523,6 +524,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper break } case "abort": + this.cancelRetry(message.sessionID ?? "") await this.handleAbort(message.sessionID) break case "revertSession": @@ -2125,6 +2127,85 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper return { sid, dir } } + /** Abort controllers for active retry loops, keyed by session ID */ + private retryAbortControllers = new Map() + + /** + * Execute an SDK call with exponential backoff on HTTP errors. + * Retries on 429, 5xx, and other retryable status codes. + * When the response includes `Retry-After` / `Retry-After-MS` headers, + * the delay honours that value (capped at 5 min). Otherwise uses the + * predefined backoff schedule: 5s -> 10s -> 30s -> 60s -> 300s. + * + * After MAX_RETRIES (5) attempts, automatically throws the error. + * Users can cancel via the cancel button in the UI which sends an abort + * message — this interrupts the backoff delay and stops the retry loop. + * + * The webview receives `sessionStatus` messages with a countdown so the + * user can see that a retry is in progress. + */ + private async withRetry(fn: () => Promise<{ error?: unknown; response: Response }>, sid: string): Promise { + const abortController = new AbortController() + this.retryAbortControllers.set(sid, abortController) + + try { + for (let attempt = 1; ; attempt++) { + if (abortController.signal.aborted) { + // User cancelled — return normally without triggering sendMessageFailed + return + } + + const result = await fn() + if (!result.error) return + + const status = result.response?.status ?? 0 + + // Non-retryable status codes fail immediately without retry + if (!retryable(status)) { + this.postMessage({ type: "sessionStatus", sessionID: sid, status: "idle" }) + throw result.error + } + + // Stop retrying after MAX_RETRIES attempts + if (attempt >= MAX_RETRIES) { + this.postMessage({ type: "sessionStatus", sessionID: sid, status: "idle" }) + throw result.error + } + + const delay = backoff(attempt, result.response?.headers) + console.log(`[Kilo New] KiloProvider: Retry on ${status}, attempt ${attempt}/${MAX_RETRIES}, delay ${delay}ms`) + + this.postMessage({ + type: "sessionStatus", + sessionID: sid, + status: "retry", + attempt, + message: `Error (${status}). Retrying...`, + next: Date.now() + delay, + }) + + // Wait for delay or until aborted + await new Promise((resolve) => { + const timer = setTimeout(resolve, delay) + abortController.signal.addEventListener("abort", () => { + clearTimeout(timer) + }) + }) + } + } finally { + this.retryAbortControllers.delete(sid) + } + } + + /** Cancel an active retry loop for a session */ + private cancelRetry(sid: string): void { + const controller = this.retryAbortControllers.get(sid) + if (controller) { + controller.abort() + this.postMessage({ type: "sessionStatus", sessionID: sid, status: "idle" }) + } + } + private async handleSendMessage( text: string, messageID?: string, @@ -2167,18 +2248,21 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper this.connectionService.recordMessageSessionId(messageID, resolved!.sid) } - await this.client.session.promptAsync( - { - sessionID: resolved!.sid, - directory: resolved!.dir, - messageID, - parts, - model: providerID && modelID ? { providerID, modelID } : undefined, - agent, - variant, - editorContext, - }, - { throwOnError: true }, + const sid = resolved!.sid + const dir = resolved!.dir + await this.withRetry( + () => + this.client!.session.promptAsync({ + sessionID: sid, + directory: dir, + messageID, + parts, + model: providerID && modelID ? { providerID, modelID } : undefined, + agent, + variant, + editorContext, + }), + sid, ) } catch (error) { console.error("[Kilo New] KiloProvider: Failed to send message:", error) @@ -2229,19 +2313,22 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper const parts = files?.map((f) => ({ type: "file" as const, mime: f.mime, url: f.url })) - await this.client.session.command( - { - sessionID: resolved!.sid, - directory: resolved!.dir, - command, - arguments: args, - messageID, - model: providerID && modelID ? `${providerID}/${modelID}` : undefined, - agent, - variant, - parts, - }, - { throwOnError: true }, + const sid = resolved!.sid + const dir = resolved!.dir + await this.withRetry( + () => + this.client!.session.command({ + sessionID: sid, + directory: dir, + command, + arguments: args, + messageID, + model: providerID && modelID ? `${providerID}/${modelID}` : undefined, + agent, + variant, + parts, + }), + sid, ) } catch (error) { console.error("[Kilo New] KiloProvider: Failed to send command:", error) diff --git a/packages/kilo-vscode/src/util/retry.ts b/packages/kilo-vscode/src/util/retry.ts new file mode 100644 index 00000000000..5c35542821c --- /dev/null +++ b/packages/kilo-vscode/src/util/retry.ts @@ -0,0 +1,70 @@ +/** + * Exponential backoff retry utilities for rate-limited API calls. + * + * When the CLI backend (or the upstream AI provider it proxies) returns + * HTTP 429, retries are scheduled with exponential backoff. The delay + * respects `Retry-After` / `Retry-After-MS` headers when present. + */ + +/** Backoff delays per attempt: 5s -> 10s -> 30s -> 60s -> 300s */ +const BACKOFF_DELAYS_MS = [5_000, 10_000, 30_000, 60_000, 300_000] + +/** Maximum backoff delay in ms (5 minutes) */ +const MAX_MS = 300_000 + +/** Maximum number of retry attempts */ +const MAX_RETRIES = BACKOFF_DELAYS_MS.length + +/** HTTP status codes that are safe to retry */ +const RETRYABLE = new Set([408, 409, 425, 429, 500, 502, 503, 504]) + +/** + * Whether an HTTP status code is retryable. + */ +export function retryable(status: number): boolean { + if (RETRYABLE.has(status)) return true + return status >= 500 +} + +/** + * Extract a retry delay (in ms) from standard response headers. + * + * Checks `retry-after-ms` first (milliseconds), then `retry-after` + * (seconds or HTTP-date). Returns `null` when no usable header is found. + */ +export function headerDelay(headers: Headers): number | null { + const ms = headers.get("retry-after-ms") + if (ms) { + const parsed = Number.parseFloat(ms) + if (!Number.isNaN(parsed) && parsed > 0) return parsed + } + + const after = headers.get("retry-after") + if (after) { + const seconds = Number.parseFloat(after) + if (!Number.isNaN(seconds) && seconds > 0) return Math.ceil(seconds * 1000) + // Try HTTP-date format + const date = Date.parse(after) - Date.now() + if (!Number.isNaN(date) && date > 0) return Math.ceil(date) + } + + return null +} + +/** + * Calculate backoff delay for a given attempt. + * + * If `headers` are provided and contain a `Retry-After` value, that + * value is used (capped at MAX_MS). Otherwise uses the predefined + * backoff schedule: 5s, 10s, 30s, 60s, 300s. + */ +export function backoff(attempt: number, headers?: Headers): number { + if (headers) { + const fromHeader = headerDelay(headers) + if (fromHeader !== null) return Math.min(fromHeader, MAX_MS) + } + const index = Math.min(attempt - 1, BACKOFF_DELAYS_MS.length - 1) + return BACKOFF_DELAYS_MS[index] ?? MAX_MS +} + +export { MAX_RETRIES, MAX_MS } diff --git a/packages/kilo-vscode/webview-ui/src/components/shared/WorkingIndicator.tsx b/packages/kilo-vscode/webview-ui/src/components/shared/WorkingIndicator.tsx index 6d35fed0344..9585b87bf86 100644 --- a/packages/kilo-vscode/webview-ui/src/components/shared/WorkingIndicator.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/shared/WorkingIndicator.tsx @@ -4,14 +4,17 @@ * Matches the v1.0.25 working indicator UX. */ -import { Component, Show, createSignal, createEffect, onCleanup } from "solid-js" +import { type Component, Show, createSignal, createEffect, onCleanup } from "solid-js" import { Spinner } from "@kilocode/kilo-ui/spinner" +import { Button } from "@kilocode/kilo-ui/button" import { useSession } from "../../context/session" import { useLanguage } from "../../context/language" +import { useVSCode } from "../../context/vscode" export const WorkingIndicator: Component = () => { const session = useSession() const language = useLanguage() + const vscode = useVSCode() const [elapsed, setElapsed] = createSignal(0) const [retryCountdown, setRetryCountdown] = createSignal(0) @@ -80,6 +83,15 @@ export const WorkingIndicator: Component = () => { return perms.length > 0 || questions.length > 0 } + const isRetrying = () => session.statusInfo().type === "retry" + + const handleCancelRetry = () => { + const sid = session.currentSessionID() + if (sid) { + vscode.postMessage({ type: "abort", sessionID: sid }) + } + } + return (
@@ -88,6 +100,17 @@ export const WorkingIndicator: Component = () => { 0}> {formatElapsed()} + + +
) diff --git a/packages/kilo-vscode/webview-ui/src/context/session.tsx b/packages/kilo-vscode/webview-ui/src/context/session.tsx index 6e5959e0169..bd80bfc704f 100644 --- a/packages/kilo-vscode/webview-ui/src/context/session.tsx +++ b/packages/kilo-vscode/webview-ui/src/context/session.tsx @@ -411,6 +411,10 @@ export const SessionProvider: ParentComponent = (props) => { function selectModel(providerID: string, modelID: string) { applyModel(selectedAgentName(), { providerID, modelID }) + const sid = currentSessionID() + if (sid) { + setStore("messages", sid, (msgs = []) => msgs.filter((m) => !m.error)) + } } /** The config/default model for the current mode (what settings says). */ diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts index 801c067983e..0f7e11508e6 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts @@ -935,6 +935,10 @@ export const dict = { "session.status.retrying": "...إعادة المحاولة (المحاولة {{ attempt }})… {{ message }}", "session.status.working": "...جارٍ العمل", + "ui.sessionTurn.cancel": "إلغاء", + "ui.sessionTurn.status.thinking": "...جارٍ التفكير", + "ui.sessionTurn.status.consideringNextSteps": "...جارٍ التفكير في الخطوات التالية", + "dialog.model.noProviders": "لا يوجد موفرون", "prompt.placeholder.connecting": "جارٍ الاتصال بالخادم...", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/br.ts b/packages/kilo-vscode/webview-ui/src/i18n/br.ts index 54184cd4122..cca0626f221 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/br.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/br.ts @@ -943,6 +943,10 @@ export const dict = { "session.status.retrying": "Tentando novamente (tentativa {{ attempt }})… {{ message }}", "session.status.working": "Trabalhando…", + "ui.sessionTurn.cancel": "Cancelar", + "ui.sessionTurn.status.thinking": "Pensando...", + "ui.sessionTurn.status.consideringNextSteps": "Considerando próximos passos...", + "dialog.model.noProviders": "Nenhum provedor", "prompt.placeholder.connecting": "Conectando ao servidor...", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts index e17c8c4b917..8087d2dd8cf 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts @@ -948,6 +948,10 @@ export const dict = { "session.status.retrying": "Ponovni pokušaj (pokušaj {{ attempt }})… {{ message }}", "session.status.working": "Radim…", + "ui.sessionTurn.cancel": "Otkaži", + "ui.sessionTurn.status.thinking": "Razmišljam...", + "ui.sessionTurn.status.consideringNextSteps": "Razmatram sljedeće korake...", + "dialog.model.noProviders": "Nema pružatelja", "prompt.placeholder.connecting": "Povezivanje na server...", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/da.ts b/packages/kilo-vscode/webview-ui/src/i18n/da.ts index e82c786f017..4bbf0dc1a0b 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/da.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/da.ts @@ -941,6 +941,10 @@ export const dict = { "session.status.retrying": "Prøver igen (forsøg {{ attempt }})… {{ message }}", "session.status.working": "Arbejder…", + "ui.sessionTurn.cancel": "Annuller", + "ui.sessionTurn.status.thinking": "Tænker...", + "ui.sessionTurn.status.consideringNextSteps": "Overvejer næste trin...", + "dialog.model.noProviders": "Ingen udbydere", "prompt.placeholder.connecting": "Opretter forbindelse til server...", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/de.ts b/packages/kilo-vscode/webview-ui/src/i18n/de.ts index f77dedaff6c..127c2e29c19 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/de.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/de.ts @@ -953,6 +953,10 @@ export const dict = { "session.status.retrying": "Erneuter Versuch ({{ attempt }})… {{ message }}", "session.status.working": "Wird bearbeitet…", + "ui.sessionTurn.cancel": "Abbrechen", + "ui.sessionTurn.status.thinking": "Denke nach...", + "ui.sessionTurn.status.consideringNextSteps": "Überlege nächste Schritte...", + "dialog.model.noProviders": "Keine Anbieter", "prompt.placeholder.connecting": "Verbindung zum Server wird hergestellt...", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/en.ts b/packages/kilo-vscode/webview-ui/src/i18n/en.ts index 63125949253..485968d1157 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/en.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/en.ts @@ -941,6 +941,10 @@ export const dict = { "session.status.retrying": "Retrying (attempt {{ attempt }})… {{ message }}", "session.status.working": "Working...", + "ui.sessionTurn.cancel": "Cancel", + "ui.sessionTurn.status.thinking": "Thinking...", + "ui.sessionTurn.status.consideringNextSteps": "Considering next steps...", + "dialog.model.noProviders": "No providers", "prompt.placeholder.connecting": "Connecting to server...", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/es.ts b/packages/kilo-vscode/webview-ui/src/i18n/es.ts index be87b6b6e01..02de604b81a 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/es.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/es.ts @@ -949,6 +949,10 @@ export const dict = { "session.status.retrying": "Reintentando (intento {{ attempt }})… {{ message }}", "session.status.working": "Trabajando…", + "ui.sessionTurn.cancel": "Cancelar", + "ui.sessionTurn.status.thinking": "Pensando...", + "ui.sessionTurn.status.consideringNextSteps": "Considerando siguientes pasos...", + "dialog.model.noProviders": "Sin proveedores", "prompt.placeholder.connecting": "Conectando al servidor...", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts index c46f4c5f4bc..0ec675b0a96 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts @@ -955,6 +955,10 @@ export const dict = { "session.status.retrying": "Nouvelle tentative (essai {{ attempt }})… {{ message }}", "session.status.working": "En cours…", + "ui.sessionTurn.cancel": "Annuler", + "ui.sessionTurn.status.thinking": "Réflexion...", + "ui.sessionTurn.status.consideringNextSteps": "Envisage les prochaines étapes...", + "dialog.model.noProviders": "Aucun fournisseur", "prompt.placeholder.connecting": "Connexion au serveur...", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts index 8e5275e3a82..1525ee90d98 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts @@ -940,6 +940,10 @@ export const dict = { "session.status.retrying": "再試行中({{ attempt }}回目)… {{ message }}", "session.status.working": "作業中…", + "ui.sessionTurn.cancel": "キャンセル", + "ui.sessionTurn.status.thinking": "考え中...", + "ui.sessionTurn.status.consideringNextSteps": "次のステップを検討中...", + "dialog.model.noProviders": "プロバイダーなし", "prompt.placeholder.connecting": "サーバーに接続中...", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts index 65a11e1936a..26200bf20dc 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts @@ -940,6 +940,10 @@ export const dict = { "session.status.retrying": "재시도 중 ({{ attempt }}번째 시도)… {{ message }}", "session.status.working": "작업 중...", + "ui.sessionTurn.cancel": "취소", + "ui.sessionTurn.status.thinking": "생각 중...", + "ui.sessionTurn.status.consideringNextSteps": "다음 단계 고려 중...", + "dialog.model.noProviders": "공급자 없음", "prompt.placeholder.connecting": "서버에 연결 중...", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/nl.ts b/packages/kilo-vscode/webview-ui/src/i18n/nl.ts index 9f3f77c9f0d..879c43a577e 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/nl.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/nl.ts @@ -942,6 +942,10 @@ export const dict = { "session.status.retrying": "Opnieuw proberen (poging {{ attempt }})... {{ message }}", "session.status.working": "Bezig...", + "ui.sessionTurn.cancel": "Annuleren", + "ui.sessionTurn.status.thinking": "Denken...", + "ui.sessionTurn.status.consideringNextSteps": "Volgende stappen overwegen...", + "dialog.model.noProviders": "Geen providers", "prompt.placeholder.connecting": "Verbinden met server...", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/no.ts b/packages/kilo-vscode/webview-ui/src/i18n/no.ts index 1d783ea1a89..fe311454170 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/no.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/no.ts @@ -945,6 +945,10 @@ export const dict = { "session.status.retrying": "Prøver på nytt (forsøk {{ attempt }})… {{ message }}", "session.status.working": "Arbeider…", + "ui.sessionTurn.cancel": "Avbryt", + "ui.sessionTurn.status.thinking": "Tenker...", + "ui.sessionTurn.status.consideringNextSteps": "Vurderer neste steg...", + "dialog.model.noProviders": "Ingen leverandører", "prompt.placeholder.connecting": "Kobler til server...", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts index c45d4612ddd..ffa85fb3012 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts @@ -945,6 +945,10 @@ export const dict = { "session.status.retrying": "Ponawiam próbę ({{ attempt }})… {{ message }}", "session.status.working": "Pracuję…", + "ui.sessionTurn.cancel": "Anuluj", + "ui.sessionTurn.status.thinking": "Myślę...", + "ui.sessionTurn.status.consideringNextSteps": "Rozważam następne kroki...", + "dialog.model.noProviders": "Brak dostawców", "prompt.placeholder.connecting": "Łączenie z serwerem...", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts index 29690a2d705..118acae5858 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts @@ -948,6 +948,10 @@ export const dict = { "session.status.retrying": "Повторная попытка ({{ attempt }})… {{ message }}", "session.status.working": "Работаю…", + "ui.sessionTurn.cancel": "Отмена", + "ui.sessionTurn.status.thinking": "Думаю...", + "ui.sessionTurn.status.consideringNextSteps": "Продумываю следующие шаги...", + "dialog.model.noProviders": "Нет провайдеров", "prompt.placeholder.connecting": "Подключение к серверу...", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/th.ts b/packages/kilo-vscode/webview-ui/src/i18n/th.ts index 8d9c11fb50a..1fbcfe6a6be 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/th.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/th.ts @@ -936,6 +936,10 @@ export const dict = { "session.status.retrying": "กำลังลองใหม่ (ครั้งที่ {{ attempt }})… {{ message }}", "session.status.working": "กำลังทำงาน...", + "ui.sessionTurn.cancel": "ยกเลิก", + "ui.sessionTurn.status.thinking": "กำลังคิด...", + "ui.sessionTurn.status.consideringNextSteps": "กำลังพิจารณาขั้นตอนถัดไป...", + "dialog.model.noProviders": "ไม่มีผู้ให้บริการ", "prompt.placeholder.connecting": "กำลังเชื่อมต่อกับเซิร์ฟเวอร์...", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/tr.ts b/packages/kilo-vscode/webview-ui/src/i18n/tr.ts index 62e46cdd179..080a3a0d2ea 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/tr.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/tr.ts @@ -944,6 +944,10 @@ export const dict = { "session.status.retrying": "Yeniden deneniyor (deneme {{ attempt }})… {{ message }}", "session.status.working": "Çalışıyor...", + "ui.sessionTurn.cancel": "İptal", + "ui.sessionTurn.status.thinking": "Düşünüyor...", + "ui.sessionTurn.status.consideringNextSteps": "Sonraki adımları değerlendiriyor...", + "dialog.model.noProviders": "Sağlayıcı yok", "prompt.placeholder.connecting": "Sunucuya bağlanılıyor...", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/uk.ts b/packages/kilo-vscode/webview-ui/src/i18n/uk.ts index 38c9bea9857..072294be09b 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/uk.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/uk.ts @@ -945,6 +945,10 @@ export const dict = { "session.status.retrying": "Повторна спроба (спроба {{ attempt }})… {{ message }}", "session.status.working": "Працює...", + "ui.sessionTurn.cancel": "Скасувати", + "ui.sessionTurn.status.thinking": "Думаю...", + "ui.sessionTurn.status.consideringNextSteps": "Обдумую наступні кроки...", + "dialog.model.noProviders": "Немає провайдерів", "prompt.placeholder.connecting": "Підключення до сервера...", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts index 33a831a0c0d..16339616557 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts @@ -928,6 +928,10 @@ export const dict = { "session.status.retrying": "正在重试(第 {{ attempt }} 次)… {{ message }}", "session.status.working": "处理中…", + "ui.sessionTurn.cancel": "取消", + "ui.sessionTurn.status.thinking": "思考中...", + "ui.sessionTurn.status.consideringNextSteps": "正在考虑下一步...", + "dialog.model.noProviders": "无供应商", "prompt.placeholder.connecting": "正在连接服务器...", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts index 6c6f3e8cae0..b545ffccb19 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts @@ -930,6 +930,10 @@ export const dict = { "session.status.retrying": "正在重試(第 {{ attempt }} 次)… {{ message }}", "session.status.working": "處理中…", + "ui.sessionTurn.cancel": "取消", + "ui.sessionTurn.status.thinking": "思考中...", + "ui.sessionTurn.status.consideringNextSteps": "正在考慮下一步...", + "dialog.model.noProviders": "沒有供應商", "prompt.placeholder.connecting": "正在連線至伺服器...",