/** * Rate limit reason classification and backoff calculation utilities. * Ported from opencode-antigravity-auth plugin for consistency. */ export type RateLimitReason = "QUOTA_EXHAUSTED" | "RATE_LIMIT_EXCEEDED" | "MODEL_CAPACITY_EXHAUSTED" | "SERVER_ERROR" | "UNKNOWN"; /** * Classify a rate-limit error message into a reason category. * Priority order: QUOTA (Antigravity "quota will reset") > MODEL_CAPACITY > QUOTA (account) > * RATE_LIMIT > QUOTA (generic) > SERVER_ERROR > UNKNOWN. * * "resource exhausted" maps to MODEL_CAPACITY (transient, short wait) * "quota exceeded" / "quota will reset" maps to QUOTA_EXHAUSTED (long wait, switch account) */ export declare function parseRateLimitReason(errorMessage: string): RateLimitReason; /** * Calculate backoff delay in ms for a given rate limit reason. * MODEL_CAPACITY gets jitter to prevent thundering herd. */ export declare function calculateRateLimitBackoffMs(reason: RateLimitReason): number; /** * HTTP status codes that, absent richer body classification, represent an * account-local usage cap rather than a bad credential or a transient blip. * Always combine with {@link isUsageLimitOutcome} when a message is available * — a 429 carrying transient rate-limit wording is NOT a usage cap. */ export declare function isUsageLimitStatus(status: number | undefined): boolean; /** * Returns true for failures that should burn one credential and rotate to a * sibling account. Decision tree: * * 1. Body matches {@link isUsageLimitError} (Codex `usage_limit_reached`, * Anthropic account rate-limit, Google `resource_exhausted`, OpenAI * `insufficient_quota`, …) → rotate. * 2. Status is not 429 → backoff (caller's domain). * 3. Body is absent or {@link isOpaqueStatusBody opaque} (just the status, * empty JSON, HTTP framing only) → rotate conservatively: the server * gave us nothing else to go on. * 4. Body has content → defer to {@link parseRateLimitReason}. Only * `QUOTA_EXHAUSTED` rotates; `RATE_LIMIT_EXCEEDED` (`Too many requests`, * per-minute caps), `MODEL_CAPACITY_EXHAUSTED` (`Service overloaded`), * `SERVER_ERROR`, and `UNKNOWN` (`Please retry in 5s`) stay in the * provider's own backoff layer so transient 429s don't burn sibling * credentials. */ export declare function isUsageLimitOutcome(status: number | undefined, message: string | undefined): boolean; /** * A 429 body is opaque when it carries no signal beyond the status itself — * empty, whitespace-only, the status digits with HTTP/JSON framing, or * generic punctuation. Anything else (retry hints, capacity wording, error * descriptions) is informative enough to defer to the classifier. */ export declare function isOpaqueStatusBody(message: string): boolean; /** * Internal text matcher for usage/quota-limit phrasing. NOT part of the public * API — callers classify through {@link import("./flags").isUsageLimit} (the * flag accessor). `flags.ts` consumes this to populate `Flag.UsageLimit`, and * {@link isUsageLimitOutcome} uses it for the account-rotation decision. */ export declare function matchesUsageLimitText(errorMessage: string): boolean;