import type { Dispatcher } from '../audit-runner.js'; export interface BuildFallbackDispatcherOptions { /** Tried first for every prompt. */ primary: Dispatcher; /** Tried only when the primary throws. */ secondary: Dispatcher; /** Provider name for log/error messages (e.g. 'zai'). */ primaryName: string; /** Provider name for log/error messages (e.g. 'deepseek'). */ secondaryName: string; } /** * Compose two dispatchers into a primary→secondary fallback chain. * * Fallback is PER-CALL: each prompt independently tries the primary first * and only drops to the secondary when that specific call throws. There is * no cross-call latch — if the primary recovers, the next call uses it * again. This matches the audit's per-entry process model (each candidate * is a fresh `audit-run-entry` invocation). * * Fallback triggers on TRANSIENT dispatcher-level failures: transport * errors, timeouts, malformed/empty responses, and transient HTTP statuses * (429, 5xx, 408). It deliberately does NOT fall back on a PERMANENT primary * failure — a `DispatcherError` with `retryable: false` (bad/missing key → * 401/403, malformed request → 400). Those indicate the primary is * misconfigured; silently failing over would hide that and let the cron run * entirely on the fallback, never using the intended primary. Such errors are * re-thrown so the run fails loudly and the operator fixes the primary. * * Any non-`DispatcherError` (an unanticipated throw) is treated as retryable * so we never lose the safety net on an error shape we didn't classify. * Content-quality / verdict parsing happens downstream in the runner and is * out of scope by design. */ export declare function buildFallbackDispatcher(opts: BuildFallbackDispatcherOptions): Dispatcher; //# sourceMappingURL=fallback.d.ts.map