/** * ModelPool runtime — multi-provider failover with per-member cooldown. * * This module is PURE (no provider imports, no circular dependencies). * It works exclusively with provider NAMES + (provider, model, region) tuples; * the existing AIProviderFactory creates actual provider instances. * * Usage: * const pool = new ModelPool({ members: [...], strategy: "round-robin" }); * const member = pool.selectNext(); * try { * await callProvider(member); * pool.recordSuccess(member); * } catch (err) { * pool.recordFailure(member, classifyProviderError(err)); * // try next member ... * } */ import type { ModelPoolConfig, ModelPoolMember, ProviderErrorClass } from "../types/index.js"; /** * Classify a provider error into a coarse `ProviderErrorClass`. * * Rules (checked in order): * 1. HTTP 429 or message pattern → "rate_limit" * 2. HTTP 401/403, access-denied pattern, or auth keywords → "auth" * 3. Context-window / token-limit message → "context_window" * 4. HTTP 5xx or server-error message → "server" * 5. Network connectivity error → "network" * 6. Everything else → "unknown" */ export declare function classifyProviderError(error: unknown): ProviderErrorClass; /** * Multi-provider pool with per-member cooldown and strategy-based selection. * * All state (cooldowns, cursor) is instance-local and resets on construction. * Thread safety is not required — Node.js is single-threaded for async work. */ export declare class ModelPool { private readonly config; private readonly strategy; private readonly cooldownMs; private readonly state; private cursor; private readonly now; constructor(config: ModelPoolConfig, injectors?: { now?: () => number; }); /** * The maximum number of attempts per call (pool config value or member count). * Used by callers that drive the retry loop externally. */ get maxAttempts(): number; /** * Returns a stable string key for a pool member. * Format: `${provider}:${model ?? "*"}:${region ?? "*"}` */ memberKey(member: ModelPoolMember): string; /** Returns members whose cooldown has expired (or were never cooled). */ availableMembers(): ModelPoolMember[]; /** * Selects the next member to try according to the configured strategy. * * @param excludedKeys — keys of members already attempted this call. * @returns the chosen member, or undefined when all members are exhausted. */ selectNext(excludedKeys?: Set): ModelPoolMember | undefined; /** * Records a provider failure, setting a cooldown appropriate for the error class. * * - Retryable classes (rate_limit, server, network, unknown): timed cooldown * for `cooldownMs` so the member can recover and be retried later. * - Non-retryable classes (auth, context_window): permanent cooldown for the * lifetime of this ModelPool instance, because these errors are structural * and will not resolve between calls (wrong credentials, model not available * in team whitelist, payload exceeds the model's context window). */ recordFailure(member: ModelPoolMember, errorClass: ProviderErrorClass): void; /** * Records a successful response, clearing any existing cooldown for this member * so it remains fully available. */ recordSuccess(member: ModelPoolMember): void; }