/**
 * withRetry — provider decorator that retries failed calls.
 *
 * Pattern: Decorator (GoF) — wraps an `LLMProvider` and adds retry
 *          policy without changing its interface.
 * Role:    Outer ring (Hexagonal). Composable: `withRetry(withFallback(...))`.
 *
 * Retries `complete()` on transient failures with exponential backoff.
 * `stream()` is retried under the SAME policy, but only until its first
 * chunk arrives: a stream that fails before it has produced anything
 * (HTTP 429, a 5xx, a reset at connect) is exactly as safe to re-open as a
 * `complete()` is to re-send. Once the first chunk is in hand the stream is
 * committed — the rest is plain delegation with no retry anywhere around it
 * (`openStream` owns the only retry loop and returns WITH that chunk), so a
 * mid-stream failure surfaces exactly as it did before: re-sending would
 * replay tokens the caller has already shown.
 *
 * Default policy:
 *   • maxAttempts: 3 (initial + 2 retries)
 *   • backoff:     exponential — 200ms, 400ms, 800ms
 *   • stated wait: when the failure says how long to wait (`retryAfterMs`,
 *                  or `retryAfterSeconds` — see statedWait.ts), the wait is
 *                  max(the schedule's delay, the stated wait), capped at
 *                  `maxDelayMs` so a hostile header cannot stall a run. The
 *                  adapter that knows its wire reads the header or the
 *                  gateway's wording; this decorator never parses prose.
 *   • shouldRetry: rejects 4xx-class errors (client mistakes don't
 *                  benefit from retry), AbortError, and any error that
 *                  declares `retryable: false`; retries 5xx, network
 *                  errors, and unknown shapes.
 *
 * **Status: contract-shaped and tested — independently reproduced against a
 * local harness, 2026-08-13.** Somebody who is not this library's author ran
 * the behaviour end to end and it held: this decorator absorbed two HTTP
 * 503-shaped failures and recovered on call three, with both
 * `agentfootprint.error.retried` and `agentfootprint.error.recovered` on the
 * typed stream, and it made exactly ONE streaming attempt — the limit as it
 * was then designed; a stream is now retried before its first chunk (see
 * above), still never after. What was exercised was a SCRIPTED failing provider — the trial's
 * own note is that those tests *"were local and deterministic, so they consumed
 * no GCP credit"*. **No live provider outage has been retried from this
 * repository**, so this is not the field-validated rung: a real 503 from a real
 * vendor, with a real Retry-After and real latency, remains unexercised.
 */
import type { LLMProvider } from '../provider-contract/types.js';
export interface WithRetryOptions {
    /** Total attempts including the first. Default 3. Must be >= 1. */
    readonly maxAttempts?: number;
    /** Initial delay in ms before the first retry. Default 200. */
    readonly initialDelayMs?: number;
    /** Multiplier between attempts. Default 2 (200ms → 400ms → 800ms). */
    readonly backoffFactor?: number;
    /**
     * Maximum delay cap in ms. Default 10_000. Caps a STATED wait too: a failure
     * that says "retry after 60 s" waits `maxDelayMs` at most. Raise it to honour
     * longer stated waits.
     */
    readonly maxDelayMs?: number;
    /**
     * Predicate to decide whether an error is worth retrying. Default
     * skips AbortError, HTTP 4xx (except 429) and an error that declares
     * `retryable: false`; retries everything else. Override
     * to add provider-specific signals. (A stated wait — Retry-After — needs no
     * predicate: it sets how long to wait, see the policy notes above.)
     */
    readonly shouldRetry?: (error: unknown, attempt: number) => boolean;
    /**
     * Hook invoked before each retry. Useful for logging in standalone
     * (non-agentfootprint) use. Receives the attempt number that's about
     * to start (so attempt 2 = first retry).
     *
     * You do NOT need this to get retry telemetry inside a run: since v7.8
     * the in-run LLM call sites hand this decorator an `LLMCallHooks` and
     * translate its reports into `agentfootprint.error.retried` /
     * `agentfootprint.error.recovered` events, stamped with the real
     * `runId`/`runtimeStageId`. This hook is the consumer-owned escape
     * hatch and its contract is unchanged.
     */
    readonly onRetry?: (error: unknown, attempt: number, delayMs: number) => void;
}
/**
 * Wrap a provider so its `complete()` — and its `stream()`, up to the first
 * chunk — retries transient failures.
 *
 * @example
 *   import { withRetry } from 'agentfootprint/resilience';
 *   import { anthropic } from 'agentfootprint/providers';
 *
 *   const robust = withRetry(anthropic({ apiKey }), {
 *     maxAttempts: 5,
 *     onRetry: (err, attempt, ms) => console.warn(`retry ${attempt} in ${ms}ms`, err),
 *   });
 */
export declare function withRetry(provider: LLMProvider, options?: WithRetryOptions): LLMProvider;
/**
 * Skip retry for AbortError, 4xx-class errors, and an error that declares
 * `retryable: false`. Retry on everything else (network errors, 5xx,
 * unknown shapes). Provider adapters that surface HTTP status should set
 * `error.status` for this to work; the predicate falls back to retrying
 * when status is unknown (better to retry once than to surface a flaky
 * failure).
 *
 * `retryable: false` is how an adapter says a failure with no HTTP status
 * cannot recover by asking again — a refusal raised before any request
 * (no key, no model), or a 2xx answer it could not read, where a re-send
 * may run and bill the model a second time. Only the literal `false` is
 * read: an error that does not declare the field is judged exactly as
 * before, and `retryable: true` does not override a 4xx status.
 *
 * Exported (module-level, NOT on the resilience barrel) as the single
 * source of truth for the decorators' transience policy — shared by
 * `withCredentialRetry` (identity) so "what counts as transient" never
 * drifts between the LLM and credential retry wrappers.
 */
export declare function defaultShouldRetry(err: unknown, _attempt: number): boolean;
//# sourceMappingURL=withRetry.d.ts.map