From 3773e370ec278cfb551e3246b4b698484549f09c Mon Sep 17 00:00:00 2001 From: MoerAI Date: Fri, 20 Mar 2026 11:00:00 +0900 Subject: [PATCH] fix(runtime-fallback): detect bare 429 rate-limit signals (fixes #2677) --- .../runtime-fallback/error-classifier.test.ts | 14 ++++++++++ .../runtime-fallback/error-classifier.ts | 2 +- .../message-update-handler.test.ts | 26 +++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/hooks/runtime-fallback/error-classifier.test.ts b/src/hooks/runtime-fallback/error-classifier.test.ts index 954e28758..5dd772e2b 100644 --- a/src/hooks/runtime-fallback/error-classifier.test.ts +++ b/src/hooks/runtime-fallback/error-classifier.test.ts @@ -31,6 +31,20 @@ describe("runtime-fallback error classifier", () => { expect(signal).toBeDefined() }) + test("detects too-many-requests auto-retry status signals without countdown text", () => { + //#given + const info = { + status: + "Too Many Requests: Sorry, you've exhausted this model's rate limit. Please try a different model.", + } + + //#when + const signal = extractAutoRetrySignal(info) + + //#then + expect(signal).toBeDefined() + }) + test("treats cooling-down retry messages as retryable", () => { //#given const error = { diff --git a/src/hooks/runtime-fallback/error-classifier.ts b/src/hooks/runtime-fallback/error-classifier.ts index e581f3fb8..cd7aa41f7 100644 --- a/src/hooks/runtime-fallback/error-classifier.ts +++ b/src/hooks/runtime-fallback/error-classifier.ts @@ -145,7 +145,7 @@ export function extractAutoRetrySignal(info: Record | undefined const combined = candidates.join("\n") if (!combined) return undefined - const isAutoRetry = AUTO_RETRY_PATTERNS.every((test) => test(combined)) + const isAutoRetry = AUTO_RETRY_PATTERNS.some((test) => test(combined)) if (isAutoRetry) { return { signal: combined } } diff --git a/src/hooks/runtime-fallback/message-update-handler.test.ts b/src/hooks/runtime-fallback/message-update-handler.test.ts index 7a3142e68..52a91abbe 100644 --- a/src/hooks/runtime-fallback/message-update-handler.test.ts +++ b/src/hooks/runtime-fallback/message-update-handler.test.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from "bun:test" import type { RuntimeFallbackPluginInput } from "./types" import { hasVisibleAssistantResponse } from "./visible-assistant-response" +import { extractAutoRetrySignal } from "./error-classifier" function createContext(messagesResponse: unknown): RuntimeFallbackPluginInput { return { @@ -53,4 +54,29 @@ describe("hasVisibleAssistantResponse", () => { // then expect(result).toBe(true) }) + + it("#given a too-many-requests assistant reply #when visibility is checked #then it is treated as an auto-retry signal", async () => { + // given + const checkVisibleResponse = hasVisibleAssistantResponse(extractAutoRetrySignal) + const ctx = createContext({ + data: [ + { info: { role: "user" }, parts: [{ type: "text", text: "latest question" }] }, + { + info: { role: "assistant" }, + parts: [ + { + type: "text", + text: "Too Many Requests: Sorry, you've exhausted this model's rate limit. Please try a different model.", + }, + ], + }, + ], + }) + + // when + const result = await checkVisibleResponse(ctx, "session-rate-limit", undefined) + + // then + expect(result).toBe(false) + }) })