/** * Anthropic subscription "slow mode" (Claude Code's `/low-priority`). * * After a Claude subscription account hits its 5-hour session limit, Anthropic * may offer to keep serving it on spare capacity. A request opts in with * `anthropic-usage-limit: slow`; the server reports the lane state back in * `anthropic-ratelimit-unified-slow-*` response headers, and answers "no spare * capacity right now" with a 429 `slot_busy` or a 529 overload that the client * retries after the server-stated interval. * * Before the slow lane, the server may grant a small wrap-up allowance (drawn * from the weekly limit) past the session limit: 2xx responses then carry * `anthropic-ratelimit-unified-grace-{5h,7d}-utilization` above zero. * * This module owns the wire contract only (header names, parsing). The mode's * state machine lives with the caller, which plugs into the Anthropic provider * through {@link AnthropicSlowModeHooks}. */ import type { HeadersLike } from "../utils/retry-after.js"; /** Request header that opts a first-party OAuth request into the slow lane. */ export declare const ANTHROPIC_USAGE_LIMIT_HEADER = "anthropic-usage-limit"; /** {@link ANTHROPIC_USAGE_LIMIT_HEADER} value selecting the slow lane. */ export declare const ANTHROPIC_SLOW_USAGE_LIMIT = "slow"; /** Server-side experiment arm; only `treatment` accounts may enter the slow lane. */ export type AnthropicSlowOffer = "treatment" | "control"; /** `anthropic-ratelimit-unified-slow-status` values; unknown strings map to `unrecognized`. */ export type AnthropicSlowStatus = "active" | "not_needed" | "slot_busy" | "weekly_limit" | "budget_exhausted" | "ineligible" | "off" | "unrecognized"; /** Slow-lane facts carried by one Anthropic response (success or error). */ export interface AnthropicSlowModeSignal { offer?: AnthropicSlowOffer; status?: AnthropicSlowStatus; /** Server-stated interval between capacity retries. */ retryAfterMs?: number; /** Server-stated ceiling on total time spent waiting for capacity. */ maxWaitMs?: number; /** Fraction (0..1) of the weekly slow-lane allowance already used. */ budgetUtilization?: number; /** Epoch seconds when the slow-lane allowance resets. */ budgetResetAtSec?: number; /** Epoch seconds of `anthropic-ratelimit-unified-reset` (the limit that was hit). */ unifiedResetAtSec?: number; /** Epoch seconds of the 5-hour window reset. */ fiveHourResetAtSec?: number; /** Epoch seconds of the weekly window reset. */ weeklyResetAtSec?: number; /** True when the response carries unified usage-limit claim headers (a limit wall). */ unifiedLimitClaim: boolean; /** True when extra usage (overage) is serving this account. */ overageInUse: boolean; /** * Wrap-up allowance usage (0..1) past the 5-hour and weekly limits; any * value above zero means the request ran on the allowance. Present only on * responses carrying `anthropic-ratelimit-unified-status`. */ graceUtilization?: { fiveHour: number; sevenDay: number; }; /** True when `anthropic-ratelimit-unified-overage-status` lets extra usage serve requests. */ overageAllowed?: boolean; } /** One pre-content failure the provider hands to {@link AnthropicSlowModeHooks.onFailure}. */ export interface AnthropicSlowModeFailure { /** Account lane of the failed request (see {@link AnthropicSlowModeHooks}). */ lane: string; httpStatus?: number; /** 529 or an `overloaded_error` envelope. */ overloaded: boolean; signal?: AnthropicSlowModeSignal; /** Whether the failed request carried `anthropic-usage-limit: slow`. */ sentSlow: boolean; /** Milliseconds this request has already spent waiting for slow-lane capacity. */ waitedMs: number; /** Capacity waits already taken by this request. */ attempts: number; } /** Retry decision returned by {@link AnthropicSlowModeHooks.onFailure}. */ export interface AnthropicSlowModeRetry { /** Delay before resending; `0` resends immediately. */ delayMs: number; /** True when the delay is a capacity wait (counts toward the max-wait budget). */ capacityWait: boolean; } /** * Caller-owned slow-mode state machine. The Anthropic provider only consults * it for first-party OAuth requests (`api.anthropic.com` with a subscription * bearer); every other route ignores it. * * Slow-lane state belongs to one Claude account, so every call carries a * `lane` key identifying the credential that served the request: `cred:` * for a stored credential, else `key:` of the bearer. */ export interface AnthropicSlowModeHooks { /** Whether the next request on `lane` should carry `anthropic-usage-limit: slow`. */ isActive(lane: string): boolean; /** Observe the slow-lane headers of a successful (2xx) response on `lane`. */ observe(signal: AnthropicSlowModeSignal, lane: string): void; /** * Decide how to react to a failure that arrived before any content. Return * a retry to resend the request (with or without the slow header, per * {@link isActive}), or `undefined` to let normal error handling run. */ onFailure(failure: AnthropicSlowModeFailure): AnthropicSlowModeRetry | undefined | Promise; } /** * Parse the slow-lane and unified-limit headers relevant to slow mode. * Returns `undefined` when the response carries none of them. */ export declare function parseAnthropicSlowModeHeaders(headers: HeadersLike): AnthropicSlowModeSignal | undefined;