From d3670736355290ff79088490885b0f7d5c2c9e12 Mon Sep 17 00:00:00 2001 From: qer Date: Wed, 22 Jul 2026 18:19:52 +0800 Subject: [PATCH] feat(tui): show user-facing status when rate-limited (429) or retrying MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a provider returns 429 or any other retryable error, the CLI previously spun silently with no user feedback. This change surfaces a warning status message in the TUI so users know why the system is waiting. - 429: "Rate limited (429), retrying in Xs… (Y/Z)" - Other: "Request failed, retrying in Xs… (Y/Z)" Fixes #2025 --- .../tui/controllers/session-event-handler.ts | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/apps/kimi-code/src/tui/controllers/session-event-handler.ts b/apps/kimi-code/src/tui/controllers/session-event-handler.ts index 3a8b5ada3d..6ce603944f 100644 --- a/apps/kimi-code/src/tui/controllers/session-event-handler.ts +++ b/apps/kimi-code/src/tui/controllers/session-event-handler.ts @@ -27,6 +27,7 @@ import type { TurnStartedEvent, TurnStepCompletedEvent, TurnStepInterruptedEvent, + TurnStepRetryingEvent, TurnStepStartedEvent, WarningEvent, } from '@moonshot-ai/kimi-code-sdk'; @@ -245,7 +246,7 @@ export class SessionEventHandler { case 'turn.step.started': this.handleStepBegin(event); break; case 'turn.step.interrupted': this.handleStepInterrupted(event); break; case 'turn.step.completed': this.handleStepCompleted(event); break; - case 'turn.step.retrying': break; + case 'turn.step.retrying': this.handleStepRetrying(event); break; case 'tool.progress': this.handleToolProgress(event); break; case 'shell.output': this.host.handleShellOutput(event); break; case 'shell.started': this.host.handleShellStarted(event); break; @@ -367,6 +368,23 @@ export class SessionEventHandler { }); } + private handleStepRetrying(event: TurnStepRetryingEvent): void { + const { failedAttempt, nextAttempt, maxAttempts, delayMs, statusCode } = event; + const delaySec = Math.round(delayMs / 1000); + const attemptLabel = `(${nextAttempt}/${maxAttempts})`; + if (statusCode === 429) { + this.host.showStatus( + `Rate limited (429), retrying in ${delaySec}s… ${attemptLabel}`, + 'warning', + ); + } else { + this.host.showStatus( + `Request failed, retrying in ${delaySec}s… ${attemptLabel}`, + 'warning', + ); + } + } + private handleStepCompleted(event: TurnStepCompletedEvent): void { this.host.streamingUI.flushNow(); this.maybeShowDebugTiming(event);