diff --git a/webview-ui/src/components/chat/RetryStatusRow.tsx b/webview-ui/src/components/chat/RetryStatusRow.tsx index d5c47731f1..177d3de45d 100644 --- a/webview-ui/src/components/chat/RetryStatusRow.tsx +++ b/webview-ui/src/components/chat/RetryStatusRow.tsx @@ -37,7 +37,7 @@ export const RetryStatusRow = ({ metadata }: RetryStatusRowProps) => { const isRateLimit = metadata.cause === "rate_limit" if (metadata.status === "retrying") { - return isRateLimit ? t("chat:retryStatus.rateLimit.retrying") : t("chat:retryStatus.backoff.retrying") + return isRateLimit ? t("chat:retryStatus.rateLimit.proceeding") : t("chat:retryStatus.backoff.retrying") } if (metadata.status === "cancelled") { @@ -46,25 +46,8 @@ export const RetryStatusRow = ({ metadata }: RetryStatusRowProps) => { if (typeof metadata.remainingSeconds === "number") { if (isRateLimit) { - // Rate limit: handle attempt/maxAttempts like backoff case - const baseKey = "chat:retryStatus.rateLimit" - - if (metadata.attempt && metadata.maxAttempts) { - return t(`${baseKey}.waitingWithAttemptMax`, { - seconds: metadata.remainingSeconds, - attempt: metadata.attempt, - maxAttempts: metadata.maxAttempts, - }) - } - - if (metadata.attempt) { - return t(`${baseKey}.waitingWithAttempt`, { - seconds: metadata.remainingSeconds, - attempt: metadata.attempt, - }) - } - - return t(`${baseKey}.waiting`, { seconds: metadata.remainingSeconds }) + // Rate limit: always use simple waiting message (no attempt numbers) + return t("chat:retryStatus.rateLimit.waiting", { seconds: metadata.remainingSeconds }) } else { // Retry: "Trying in 22s (attempt #2)" const baseKey = "chat:retryStatus.backoff" diff --git a/webview-ui/src/components/chat/__tests__/RetryStatusRow.spec.tsx b/webview-ui/src/components/chat/__tests__/RetryStatusRow.spec.tsx index 9e8891368f..61826e3efd 100644 --- a/webview-ui/src/components/chat/__tests__/RetryStatusRow.spec.tsx +++ b/webview-ui/src/components/chat/__tests__/RetryStatusRow.spec.tsx @@ -19,7 +19,7 @@ vi.mock("@/i18n/TranslationContext", () => ({ // rendering a single live status row: spinner + per‑second countdown, // then "Retrying now..." at zero. Input remains disabled during the wait. describe("RetryStatusRow", () => { - it("renders waiting countdown with attempt and max attempts for rate limit cause", () => { + it("renders waiting countdown for rate limit cause", () => { const metadata: RetryStatusMetadata = { type: "retry_status", status: "waiting", @@ -32,7 +32,7 @@ describe("RetryStatusRow", () => { render() - expect(screen.getByText("chat:retryStatus.rateLimit.waitingWithAttemptMax")).toBeInTheDocument() + expect(screen.getByText("chat:retryStatus.rateLimit.waiting")).toBeInTheDocument() expect(screen.getByText("chat:retryStatus.rateLimit.title")).toBeInTheDocument() }) @@ -49,6 +49,19 @@ describe("RetryStatusRow", () => { expect(screen.getByText("chat:retryStatus.backoff.retrying")).toBeInTheDocument() }) + it("renders proceeding state for rate limit cause", () => { + const metadata: RetryStatusMetadata = { + type: "retry_status", + status: "retrying", + origin: "retry_attempt", + cause: "rate_limit", + } + + render() + + expect(screen.getByText("chat:retryStatus.rateLimit.proceeding")).toBeInTheDocument() + }) + it("renders cancelled state (neutral)", () => { const metadata: RetryStatusMetadata = { type: "retry_status", @@ -117,7 +130,7 @@ describe("RetryStatusRow", () => { const { rerender } = render() // Initial countdown - expect(screen.getByText("chat:retryStatus.rateLimit.waitingWithAttemptMax")).toBeInTheDocument() + expect(screen.getByText("chat:retryStatus.rateLimit.waiting")).toBeInTheDocument() // Update countdown const metadata2: RetryStatusMetadata = { @@ -128,6 +141,6 @@ describe("RetryStatusRow", () => { rerender() // Should still show the same text key but with updated seconds - expect(screen.getByText("chat:retryStatus.rateLimit.waitingWithAttemptMax")).toBeInTheDocument() + expect(screen.getByText("chat:retryStatus.rateLimit.waiting")).toBeInTheDocument() }) }) diff --git a/webview-ui/src/i18n/locales/hi/chat.json b/webview-ui/src/i18n/locales/hi/chat.json index 04741c2ff0..909247012f 100644 --- a/webview-ui/src/i18n/locales/hi/chat.json +++ b/webview-ui/src/i18n/locales/hi/chat.json @@ -152,11 +152,11 @@ }, "backoff": { "title": "अनुरोध विफल", - "waiting": "{{seconds}} सेकंड में पुन: प्रयास कर रहा है", - "waitingWithAttempt": "{{seconds}} सेकंड में पुन: प्रयास कर रहा है (प्रयास #{{attempt}})", - "waitingWithAttemptMax": "{{seconds}} सेकंड में पुन: प्रयास कर रहा है (प्रयास #{{attempt}}/{{maxAttempts}})", + "waiting": "{{seconds}} सेकंड में पुनः प्रयास कर रहा है", + "waitingWithAttempt": "{{seconds}} सेकंड में पुनः प्रयास कर रहा है (प्रयास #{{attempt}})", + "waitingWithAttemptMax": "{{seconds}} सेकंड में पुनः प्रयास कर रहा है (प्रयास #{{attempt}}/{{maxAttempts}})", "retrying": "अब कोशिश कर रहा हूँ...", - "cancelled": "पुन: प्रयास रद्द" + "cancelled": "पुनः प्रयास रद्द" } }, "rateLimitRetry": { diff --git a/webview-ui/src/i18n/locales/vi/chat.json b/webview-ui/src/i18n/locales/vi/chat.json index 6d37a8bac8..72e69d59e8 100644 --- a/webview-ui/src/i18n/locales/vi/chat.json +++ b/webview-ui/src/i18n/locales/vi/chat.json @@ -161,9 +161,9 @@ }, "rateLimitRetry": { "title": "Đã đạt giới hạn tốc độ — vui lòng đợi.", - "waiting": "Đang thử lại sau {{seconds}}s", - "waitingWithAttempt": "Đang thử lại sau {{seconds}}s (thử lại lần {{attempt}})", - "waitingWithAttemptMax": "Đang thử lại sau {{seconds}}s (thử lại lần {{attempt}}/{{maxAttempts}})", + "waiting": "Đang thử lại sau {{seconds}} giây", + "waitingWithAttempt": "Đang thử lại sau {{seconds}} giây (thử lại lần {{attempt}})", + "waitingWithAttemptMax": "Đang thử lại sau {{seconds}} giây (thử lại lần {{attempt}}/{{maxAttempts}})", "retrying": "Đang thử lại ngay…", "cancelled": "Đã hủy thử lại" },