mirror of https://github.com/openclaw/openclaw.git
fix(failover): classify ZenMux quota-refresh 402 as rate_limit (#43917)
Merged via squash.
Prepared head SHA: 1d58a36a77
Co-authored-by: bwjoke <1284814+bwjoke@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
This commit is contained in:
parent
d93db0fc13
commit
fd568c4f74
|
|
@ -188,6 +188,7 @@ Docs: https://docs.openclaw.ai
|
|||
- Status/context windows: normalize provider-qualified override cache keys so `/status` resolves the active provider's configured context window even when `models.providers` keys use mixed case or surrounding whitespace. (#36389) Thanks @haoruilee.
|
||||
- ACP/main session aliases: canonicalize `main` before ACP session lookup so restarted ACP main sessions rehydrate instead of failing closed with `Session is not ACP-enabled: main`. (#43285, fixes #25692)
|
||||
- Agents/embedded runner: recover canonical allowlisted tool names from malformed `toolCallId` and malformed non-blank tool-name variants before dispatch, while failing closed on ambiguous matches. (#34485) thanks @yuweuii.
|
||||
- Agents/failover: classify ZenMux quota-refresh `402` responses as `rate_limit` so model fallback retries continue instead of stopping on a temporary subscription window. (#43917) thanks @bwjoke.
|
||||
|
||||
## 2026.3.8
|
||||
|
||||
|
|
|
|||
|
|
@ -204,6 +204,13 @@ describe("failover-error", () => {
|
|||
message: "Workspace spend limit reached. Contact your admin.",
|
||||
}),
|
||||
).toBe("rate_limit");
|
||||
expect(
|
||||
resolveFailoverReasonFromError({
|
||||
status: 402,
|
||||
message:
|
||||
"You have reached your subscription quota limit. Please wait for automatic quota refresh in the rolling time window, upgrade to a higher plan, or use a Pay-As-You-Go API Key for unlimited access. Learn more: https://zenmux.ai/docs/guide/subscription.html",
|
||||
}),
|
||||
).toBe("rate_limit");
|
||||
expect(
|
||||
resolveFailoverReasonFromError({
|
||||
status: 402,
|
||||
|
|
|
|||
|
|
@ -288,6 +288,13 @@ function hasExplicit402BillingSignal(text: string): boolean {
|
|||
);
|
||||
}
|
||||
|
||||
function hasQuotaRefreshWindowSignal(text: string): boolean {
|
||||
return (
|
||||
text.includes("subscription quota limit") &&
|
||||
(text.includes("automatic quota refresh") || text.includes("rolling time window"))
|
||||
);
|
||||
}
|
||||
|
||||
function hasRetryable402TransientSignal(text: string): boolean {
|
||||
const hasPeriodicHint = includesAnyHint(text, PERIODIC_402_HINTS);
|
||||
const hasSpendLimit = text.includes("spend limit") || text.includes("spending limit");
|
||||
|
|
@ -313,6 +320,10 @@ function classify402Message(message: string): PaymentRequiredFailoverReason {
|
|||
return "billing";
|
||||
}
|
||||
|
||||
if (hasQuotaRefreshWindowSignal(normalized)) {
|
||||
return "rate_limit";
|
||||
}
|
||||
|
||||
if (hasExplicit402BillingSignal(normalized)) {
|
||||
return "billing";
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue