/** * Multi-provider auxiliary fallback chain for CLEO LLM auxiliary calls. * * When the configured provider's credential pool is exhausted (all credentials * on cooldown due to 401/429/connection errors), {@link runAuxiliaryWithFallback} * advances to the next provider in the chain and retries. This prevents auxiliary * calls (context compression, brain dream cycles, hygiene scans) from failing * silently when the primary provider is temporarily unavailable. * * ## Configuration * * Set via `cleo config set llm.auxiliaryFallback "anthropic,openrouter,groq"`. * * The default chain when no config is present: `['anthropic', 'openrouter', 'groq']`. * * @module llm/auxiliary-fallback * @task T9319 * @epic T9261 T-LLM-CRED-CENTRALIZATION */ import type { SendOptions } from '@cleocode/contracts/llm/interfaces.js'; import type { NormalizedResponse, TransportMessage } from '@cleocode/contracts/llm/normalized-response.js'; import type { ModelTransport } from './types-config.js'; /** * Default auxiliary fallback chain used when `llm.auxiliaryFallback` is not * configured. Anthropic first (most capable for auxiliary tasks), then * OpenRouter (aggregates many providers), then Groq (fast inference). */ export declare const DEFAULT_AUXILIARY_FALLBACK_CHAIN: readonly AuxiliaryFallbackEntry[]; /** * A single entry in an {@link AuxiliaryFallbackChain}. * * @task T9319 */ export interface AuxiliaryFallbackEntry { /** Provider transport identifier. */ readonly provider: ModelTransport; /** * Optional model override for this provider. * * When omitted, the session factory resolves the model from config * (via role-resolver's implicit-fallback chain). */ readonly model?: string; } /** * Ordered list of providers to try for auxiliary LLM calls. * * The chain is tried front-to-back. The first provider whose credential pool * yields a successful response wins. The chain short-circuits immediately on * success — if provider 1 succeeds, providers 2..N are never contacted. * * @task T9319 */ export type AuxiliaryFallbackChain = readonly AuxiliaryFallbackEntry[]; /** * Successful result returned by {@link runAuxiliaryWithFallback}. * * Extends {@link NormalizedResponse} with `meta.fallbackChain` that records * which providers were tried (in order) and which one ultimately succeeded. * * @task T9319 */ export interface AuxiliaryFallbackResult extends NormalizedResponse { /** * Fallback metadata populated when at least one provider was attempted. * * Stored in `providerData['__fallbackMeta']` on the response so the shape * is preserved through existing NormalizedResponse consumers. Access via the * `.meta` shortcut on this interface. */ readonly meta: AuxiliaryFallbackMeta; } /** * Fallback path metadata attached to {@link AuxiliaryFallbackResult}. * * @task T9319 */ export interface AuxiliaryFallbackMeta { /** * Ordered list of all providers in the chain that were tried. * * Includes both failed providers (pool-exhausted) and the final successful * provider. The last entry is always the one that produced the response. */ readonly fallbackChain: readonly FallbackChainStep[]; } /** * A single step in the recorded fallback chain. * * @task T9319 */ export interface FallbackChainStep { /** Provider transport identifier. */ readonly provider: ModelTransport; /** Outcome for this provider attempt. */ readonly outcome: 'success' | 'pool_exhausted' | 'error'; /** * Human-readable error message when `outcome !== 'success'`. * * Omitted on success to avoid leaking unnecessary detail. */ readonly errorMessage?: string; } /** * Thrown by {@link runAuxiliaryWithFallback} when every provider in the chain * has been tried and all have exhausted their credential pools or returned errors. * * `steps` records the full fallback path taken so callers can surface a * structured diagnostic to the user or log it for analysis. * * @task T9319 */ export declare class AllProvidersExhaustedError extends Error { readonly steps: readonly FallbackChainStep[]; /** Stable LAFS error code. */ readonly code = "E_LLM_ALL_PROVIDERS_EXHAUSTED"; /** * @param steps - Ordered record of every provider attempt made, with outcome. */ constructor(steps: readonly FallbackChainStep[]); } /** * Function signature for providing a single-turn auxiliary response from a * specific provider. * * Production code uses the DefaultLlmSessionFactory-based implementation. * Tests inject a mock to control per-provider behaviour. * * @internal */ export type AuxiliaryProvider = (entry: AuxiliaryFallbackEntry, messages: TransportMessage[], opts: SendOptions | undefined) => Promise; /** * Execute an auxiliary LLM call with multi-provider fallback. * * Iterates through `chain` front-to-back: * 1. Tries provider N's full credential pool (via `provider` fn). * 2. If the pool is exhausted or the call returns a fallback-triggering error, * records the step as `'pool_exhausted'` and advances to N+1. * 3. On non-exhaustion error (network blip, 500, timeout), records as `'error'` * and also advances — auxiliary calls are best-effort. * 4. Returns on the first success, attaching `meta.fallbackChain` to the result. * 5. When all providers are tried, throws {@link AllProvidersExhaustedError}. * * @param chain - Ordered list of providers to try. * @param messages - Messages to pass to the LLM. * @param opts - Per-call send options forwarded as-is to each provider. * @param provider - Injectable provider function (defaults to session-factory impl). * @returns The first successful {@link AuxiliaryFallbackResult}. * @throws {AllProvidersExhaustedError} When every provider in the chain fails. * * @task T9319 */ export declare function runAuxiliaryWithFallback(chain: AuxiliaryFallbackChain, messages: TransportMessage[], opts?: SendOptions, provider?: AuxiliaryProvider): Promise; /** * Parse a comma-separated provider string (as stored in `llm.auxiliaryFallback`) * into an {@link AuxiliaryFallbackChain}. * * Invalid/empty entries are silently dropped. If parsing results in an empty * array, returns {@link DEFAULT_AUXILIARY_FALLBACK_CHAIN} as a safety fallback. * * Supports optional `provider:model` syntax per entry (e.g. * `"anthropic:claude-haiku-4-5-20251001,openrouter,groq:llama-3.1-8b"`) * for callers that want to pin specific models per provider. * * @param raw - Raw config string from `llm.auxiliaryFallback`. * @returns Parsed chain, or the default chain when `raw` is empty/invalid. * * @task T9319 */ export declare function parseAuxiliaryFallbackChain(raw: string): AuxiliaryFallbackChain; /** * Resolve the active auxiliary fallback chain from project config. * * Reads `llm.auxiliaryFallback` from the CLEO config. Falls back to * {@link DEFAULT_AUXILIARY_FALLBACK_CHAIN} when the key is absent. * * @param projectRoot - Optional project root for config resolution. * @returns The resolved chain (never empty — always at least the default). * * @task T9319 */ export declare function resolveAuxiliaryFallbackChain(projectRoot?: string): Promise; //# sourceMappingURL=auxiliary-fallback.d.ts.map