feat(antigravity): quota-aware routing with reset-aware fallback
On a 409/429 from Antigravity, fetch live quota to learn the exact per-model resetAt instead of guessing a backoff, then skip only the exhausted account/model pair until that time. - antigravityQuota.js: in-memory quota cache, coalesced concurrent refreshes, 30s throttle per connection (applied to failures too), keeps known cache when upstream returns 401/403 error payloads - auth.js: pre-filter exhausted account/model pairs; report the earliest quota reset when every account is blocked; skip the 30-minute cooldown cap so the upstream resetAt is not truncated - chat.js: antigravity 409/429 falls back on the RAM cache only, no persistent modelLock_* for this path - Logs identify accounts by id prefix, never email or name Closes #3561
This commit is contained in:
1 parent
f0a6d35818
commit
1a3db1efae
4 files changed
+314
-5
No files matched your search
@@ -7,6 +7,7 @@ import {
|
||||
extractApiKey,
|
||||
isValidApiKey,
|
||||
} from "../services/auth.js";
|
||||
import { handleAntigravityQuotaError } from "../services/antigravityQuota.js";
|
||||
import { getSettings } from "@/lib/localDb";
|
||||
import { getModelInfo, getComboModels } from "../services/model.js";
|
||||
import { handleChatCore } from "open-sse/handlers/chatCore.js";
|
||||
@@ -300,8 +301,22 @@ async function handleSingleModelChat(body, modelStr, clientRawRequest = null, re
|
||||
|
||||
if (result.success) return result.response;
|
||||
|
||||
// Mark account unavailable (auto-calculates cooldown with exponential backoff, or precise resetsAtMs)
|
||||
const { shouldFallback } = await markAccountUnavailable(credentials.connectionId, result.status, result.error, provider, model, result.resetsAtMs);
|
||||
// Antigravity 409/429: refresh live quota to get exact resetAt before locking
|
||||
let quotaResetMs = null;
|
||||
let resetsAtMs = result.resetsAtMs;
|
||||
if (provider === "antigravity" && (result.status === 409 || result.status === 429)) {
|
||||
quotaResetMs = await handleAntigravityQuotaError(
|
||||
credentials.connectionId, result.status, model,
|
||||
refreshedCredentials.accessToken, credentials.providerSpecificData
|
||||
);
|
||||
if (quotaResetMs) resetsAtMs = quotaResetMs;
|
||||
}
|
||||
|
||||
// Exhausted Antigravity model is blocked only in RAM cache until upstream resetAt.
|
||||
// Do not persist a modelLock_* for this path.
|
||||
const shouldFallback = provider === "antigravity" && quotaResetMs
|
||||
? true
|
||||
: (await markAccountUnavailable(credentials.connectionId, result.status, result.error, provider, model, resetsAtMs)).shouldFallback;
|
||||
|
||||
if (shouldFallback) {
|
||||
log.warn("FALLBACK", `⇄ ACC:${credentials.connectionName} UNAVAILABLE (${result.status}) → NEXT ACCOUNT`);
|
||||
|
||||
Reference in new issue
Block a user