/** * Provider Health Tracker * * Tracks the health status of LLM providers to enable intelligent failover. * Monitors success/failure rates, latency, rate limits, and manages cooldown periods. */ import type { Logger } from '../observability/logger.js'; /** * Health status of a provider. */ export type ProviderHealthStatus = 'healthy' | 'degraded' | 'unhealthy'; /** * Rate limit information extracted from provider response headers. */ export interface RateLimitInfo { /** Total requests allowed in period */ limit: number; /** Remaining requests in period */ remaining: number; /** When the period resets (Unix timestamp in ms) */ resetAt: number; /** Tokens remaining (for token-based limits) */ tokensRemaining?: number; /** Token limit */ tokenLimit?: number; } /** * Health information for a single provider. */ export interface ProviderHealth { /** Provider name */ provider: string; /** Current health status */ status: ProviderHealthStatus; /** Timestamp of last health check */ lastCheck: Date; /** Timestamp of last successful request */ lastSuccess: Date | null; /** Last error details */ lastError: { code: number | undefined; message: string; timestamp: Date; } | null; /** Number of consecutive failures */ consecutiveFailures: number; /** Cooldown end time (provider should not be used until this time) */ cooldownUntil: Date | null; /** Rolling average latency in ms */ latencyMs: number; /** Total successful requests */ successCount: number; /** Total failed requests */ failureCount: number; /** Current rate limit info (if available) */ rateLimit: RateLimitInfo | null; /** Percentage of rate limit used (0-100) */ rateLimitUsedPercentage: number; /** Is rate limit warning active (above threshold) */ rateLimitWarning: boolean; } /** * Configuration for the health tracker. */ export interface HealthTrackerConfig { /** Number of consecutive failures before marking unhealthy (default: 3) */ failureThreshold?: number; /** Number of consecutive failures before marking degraded (default: 1) */ degradedThreshold?: number; /** Cooldown duration in ms after marking unhealthy (default: 300000 = 5 min) */ cooldownMs?: number; /** How often to run health checks in ms (default: 60000 = 1 min) */ healthCheckIntervalMs?: number; /** Window size for rolling latency average (default: 10) */ latencyWindowSize?: number; /** Threshold to trigger rate limit warning (0-1, default 0.7 = 70% used) */ rateLimitWarningThreshold?: number; /** Callback when rate limit warning triggers */ onRateLimitWarning?: (provider: string, info: RateLimitInfo) => void; } /** * Tracks provider health for intelligent failover decisions. * * Features: * - Tracks success/failure rates per provider * - Manages cooldown periods for unhealthy providers * - Provides rolling average latency metrics * - Supports periodic health check callbacks * * @example * ```typescript * const tracker = new ProviderHealthTracker(logger); * * // Record outcomes * tracker.markSuccess('openai', 150); * tracker.markFailure('deepseek', new Error('Rate limited'), 429); * * // Check before using * if (tracker.isHealthy('openai')) { * // Safe to use * } * * // Get cooldown info * const remaining = tracker.getCooldownRemaining('deepseek'); * ``` */ export declare class ProviderHealthTracker { private readonly health; private readonly latencyHistory; private readonly config; private readonly logger; private healthCheckInterval; private healthCheckCallback; constructor(logger: Logger, config?: HealthTrackerConfig); /** * Record a successful request for a provider. */ markSuccess(provider: string, latencyMs: number): void; /** * Record a failed request for a provider. */ markFailure(provider: string, error: Error, statusCode?: number): void; /** * Check if a provider is healthy and not in cooldown. */ isHealthy(provider: string): boolean; /** * Check if a provider is available (healthy or degraded, not in cooldown). */ isAvailable(provider: string): boolean; /** * Get remaining cooldown time in ms (0 if not in cooldown). */ getCooldownRemaining(provider: string): number; /** * Get health info for a provider. */ getHealth(provider: string): ProviderHealth | undefined; /** * Get health info for all tracked providers. */ getAllHealth(): Map; /** * Get providers sorted by health and latency (best first). */ getHealthyProviders(providerNames: string[]): string[]; /** * Reset health for a provider (e.g., after config change). */ resetHealth(provider: string): void; /** * Clear all health tracking data. */ clear(): void; /** * Start periodic health checks. */ startHealthCheckLoop(callback: (provider: string) => Promise): void; /** * Stop periodic health checks. */ stopHealthCheckLoop(): void; /** * Update rate limit info from response headers. * * Parses rate limit headers from various providers and updates the health state. * Triggers warning callback if rate limit usage exceeds threshold. */ updateRateLimits(provider: string, headers: Record): void; /** * Parse rate limit headers from various provider formats. * * Supports: * - OpenAI: x-ratelimit-limit-requests, x-ratelimit-remaining-requests, etc. * - Anthropic: anthropic-ratelimit-requests-limit, etc. * - Generic: x-ratelimit-limit, ratelimit-limit, etc. */ parseRateLimitHeaders(headers: Record): RateLimitInfo | null; /** * Check if provider is approaching rate limit (above warning threshold). */ isApproachingRateLimit(provider: string): boolean; /** * Get time until rate limit resets (in ms). * Returns 0 if no rate limit info or already reset. */ getRateLimitResetTime(provider: string): number; /** * Get all providers with active rate limit warnings. */ getProvidersWithRateLimitWarnings(): string[]; /** * Parse various reset time formats to Unix timestamp (ms). */ private parseResetTime; /** * Serialized rate limit info for persistence. */ private serializeRateLimitInfo; /** * Serialize health state for persistence. */ serialize(): Array<{ provider: string; status: ProviderHealthStatus; consecutiveFailures: number; cooldownUntil: number | null; latencyMs: number; successCount: number; failureCount: number; lastSuccessAt: number | null; lastErrorAt: number | null; lastErrorMessage: string | null; lastErrorCode: number | null; rateLimit: { limit: number; remaining: number; resetAt: number; tokensRemaining: number | null; tokenLimit: number | null; } | null; rateLimitUsedPercentage: number; rateLimitWarning: boolean; }>; /** * Restore health state from persistence. */ restore(data: Array<{ provider: string; status: ProviderHealthStatus; consecutiveFailures: number; cooldownUntil: number | null; latencyMs: number; successCount: number; failureCount: number; lastSuccessAt: number | null; lastErrorAt: number | null; lastErrorMessage: string | null; lastErrorCode: number | null; rateLimit?: { limit: number; remaining: number; resetAt: number; tokensRemaining: number | null; tokenLimit: number | null; } | null; rateLimitUsedPercentage?: number; rateLimitWarning?: boolean; }>): void; private getOrCreateHealth; private updateLatency; private getAverageLatency; private runHealthChecks; } //# sourceMappingURL=health-tracker.d.ts.map