/** * Shared classification + bounded-retry policy for AI-credential mint failures. * The single place that decides transient (`backend-error`) vs terminal * (`revoked` / `not-configured` / `provider-error`), consumed by both the * reactive 401 path and the proactive scheduler so they never drift. Rationale * (shared-seat non-amplification) in `runner/CLAUDE.md` ยง AI Credential Mediation. * * @docLink packages/runner/dev-guide#ai-credential-mediation */ import type { CredentialMint, CredentialRejection } from "@skaile/workspaces/types"; /** The discriminated failure codes a {@link CredentialMint} can carry. */ export type MintFailureCode = Extract["code"]; /** * Maximum total mint attempts (initial try + retries) on the transient path. * Three attempts spanning the backoff below ride out a ~7s backend redeploy. */ export declare const MINT_RETRY_MAX_ATTEMPTS = 3; /** * Whether a failed mint should be retried. Only `backend-error` (internal * mediator outage) is transient; `not-configured`, `revoked`, and * `provider-error` are terminal credential/account states where a retry * cannot help. */ export declare function isTransientMintFailure(code: MintFailureCode): boolean; /** * Backoff before the Nth retry (`retryNumber = 1` is the delay before the 2nd * attempt). Exponential from a 2s base, capped at 5s, so three attempts span * roughly 6s โ€” enough to ride a backend redeploy without unbounded waiting. */ export declare function mintRetryDelayMs(retryNumber: number): number; /** * Run `attempt` up to {@link MINT_RETRY_MAX_ATTEMPTS} times, sleeping * {@link mintRetryDelayMs} between tries, stopping early on success or a * terminal failure. Returns the final mint: ok, a terminal failure, or the * last transient failure once the cap is reached. `sleep` is injected so tests * stay deterministic. */ export declare function retryTransientMint(attempt: () => Promise, deps: { sleep: (ms: number) => Promise; maxAttempts?: number; onRetry?: (info: { attempt: number; nextDelayMs: number; code: MintFailureCode; }) => void; }): Promise; /** * Truncated SHA-256 of the just-rejected access token. Sent as the OPTIONAL * `rejectedFingerprint` on a retry-401 `host.refresh_credential` so the platform * can coalesce concurrent rotations of the same dead token (single-flight). It * is non-reversible and carries no secret material (16 hex chars = 64 bits, * collision-safe for coalescing). Returns `undefined` for an empty/missing * token so the field is simply omitted. */ export declare function computeRejectedFingerprint(accessToken: string | null | undefined): string | undefined; /** The wire input for a `host.refresh_credential` invocation (ai-credentials). */ export interface RefreshCredentialInput { kind: "ai-credentials"; id: string; reason: "refresh" | "retry-401"; /** Truncated fingerprint of the just-rejected token; only on retry-401. */ rejectedFingerprint?: string; /** * Which rejection drove this retry-401 โ€” auth vs seat exhaustion. Only on * retry-401, and only from a call site that actually classified the failure. */ rejection?: CredentialRejection; } /** * Build the `host.refresh_credential` input. Two optional fields ride the * `retry-401` path only, and each is omitted rather than sent `undefined`: * * - `rejectedFingerprint`, when a current token is on disk to fingerprint โ€” * on a proactive `refresh` there is no rejected token. The platform's * single-flight mediator uses it to coalesce concurrent rotations of the * same dead token. * - `rejection`, when the caller classified *why* the credential was * retried. `retry-401` alone collapses an auth rejection and a usage-limit * block, which the platform must tell apart to re-resolve a limit-blocked * seat (skaile-ai/platform#3562). Callers that classify nothing leave it * unset and emit exactly the previous bytes. * * Today's platform ignores both unknown fields. */ export declare function buildRefreshCredentialInput(args: { configId: string; reason: "refresh" | "retry-401"; rejectedToken?: string | null; rejection?: CredentialRejection; }): RefreshCredentialInput; //# sourceMappingURL=ai-credential-retry.d.ts.map