Merge pull request #4245 from MoerAI/fix/runtime-fallback-zai-limit-exhausted
fix(runtime-fallback): match ZAI 'Limit Exhausted' quota errors (fixes #4207)
This commit is contained in:
@@ -30,6 +30,7 @@ export const RETRYABLE_ERROR_PATTERNS = [
|
|||||||
/exceeded.*quota/i,
|
/exceeded.*quota/i,
|
||||||
/usage\s*quota/i,
|
/usage\s*quota/i,
|
||||||
/exhausted\s+your\s+capacity/i,
|
/exhausted\s+your\s+capacity/i,
|
||||||
|
/limit\s+exhausted/i,
|
||||||
/all\s+credentials\s+for\s+model/i,
|
/all\s+credentials\s+for\s+model/i,
|
||||||
/cool(?:ing)?\s+down/i,
|
/cool(?:ing)?\s+down/i,
|
||||||
/model.{0,20}?not.{0,10}?supported/i,
|
/model.{0,20}?not.{0,10}?supported/i,
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ export function classifyErrorType(error: unknown): string | undefined {
|
|||||||
/payment.?required/i.test(message) ||
|
/payment.?required/i.test(message) ||
|
||||||
/usage\s+limit/i.test(message) ||
|
/usage\s+limit/i.test(message) ||
|
||||||
/credit\s+balance.*too\s+low/i.test(message) ||
|
/credit\s+balance.*too\s+low/i.test(message) ||
|
||||||
|
/limit\s+exhausted/i.test(message) ||
|
||||||
/使用上限/.test(message) ||
|
/使用上限/.test(message) ||
|
||||||
/达到.*限制/.test(message) ||
|
/达到.*限制/.test(message) ||
|
||||||
/额度.*不足/.test(message) ||
|
/额度.*不足/.test(message) ||
|
||||||
|
|||||||
@@ -143,4 +143,43 @@ describe("runtime-fallback quota error regressions", () => {
|
|||||||
expect(errorType).toBe("quota_exceeded")
|
expect(errorType).toBe("quota_exceeded")
|
||||||
expect(retryable).toBe(true)
|
expect(retryable).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("classifies ZAI weekly/monthly Limit Exhausted as quota_exceeded and triggers fallback", () => {
|
||||||
|
//#given
|
||||||
|
// ZAI (Zhipu) emits this exact message for both weekly and monthly quota
|
||||||
|
// exhaustion on the coding-plan subscription. The capitalization, the
|
||||||
|
// 'Limit Exhausted' phrasing, and the 'limit will reset at' suffix do not
|
||||||
|
// match any of the existing quota regex patterns, so the runtime-fallback
|
||||||
|
// never fires and the user is stuck on the dead model.
|
||||||
|
const error = {
|
||||||
|
message:
|
||||||
|
"Weekly/Monthly Limit Exhausted. Your limit will reset at 2026-05-20 15:43:27",
|
||||||
|
}
|
||||||
|
|
||||||
|
//#when
|
||||||
|
const errorType = classifyErrorType(error)
|
||||||
|
const retryable = isRetryableError(error, [429, 500, 502, 503, 504])
|
||||||
|
|
||||||
|
//#then
|
||||||
|
expect(errorType).toBe("quota_exceeded")
|
||||||
|
expect(retryable).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("classifies ZAI weekly-only Limit Exhausted variant as quota_exceeded", () => {
|
||||||
|
//#given
|
||||||
|
// Weekly-only variant uses the same phrasing minus the slash; the regex
|
||||||
|
// must not require the literal `Weekly/Monthly` prefix.
|
||||||
|
const error = {
|
||||||
|
message:
|
||||||
|
"Weekly Limit Exhausted. Your limit will reset at 2026-05-28 10:30:00",
|
||||||
|
}
|
||||||
|
|
||||||
|
//#when
|
||||||
|
const errorType = classifyErrorType(error)
|
||||||
|
const retryable = isRetryableError(error, [429, 500, 502, 503, 504])
|
||||||
|
|
||||||
|
//#then
|
||||||
|
expect(errorType).toBe("quota_exceeded")
|
||||||
|
expect(retryable).toBe(true)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user