UNPKG

@yuchida-tamu/podcast-gen

Version:

AI-Powered Monologue Podcast Generator

75 lines 3.14 kB
import { LLMAuthenticationError, LLMError, LLMNetworkError, LLMRateLimitError, } from '../types/index.js'; export class APIClient { config; constructor(config) { this.config = { retries: 3, timeout: 30000, baseDelay: 1000, maxDelay: 10000, ...config, }; } async executeWithRetry(request) { const maxRetries = this.config.retries; const errorHandler = this.createStandardErrorHandler(); for (let attempt = 0; attempt < maxRetries; attempt++) { try { return await this.fetch(request); } catch (error) { const wrappedError = errorHandler(error); // Handle authentication errors immediately - don't retry if (wrappedError instanceof LLMAuthenticationError) { throw wrappedError; } // Retry on retryable errors if (wrappedError.retryable && attempt < maxRetries - 1) { const delay = this.calculateDelay(attempt); await this.sleep(delay); continue; } // Throw error if not retryable or max retries reached throw wrappedError; } } throw new LLMNetworkError('Failed to get response after all retries'); } calculateDelay(attempt) { // Exponential backoff with jitter const exponentialDelay = this.config.baseDelay * Math.pow(2, attempt); const jitter = Math.random() * 0.1 * exponentialDelay; // 10% jitter return Math.min(exponentialDelay + jitter, this.config.maxDelay); } sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } createStandardErrorHandler() { return (error) => { // Handle null/undefined errors if (!error) { return new LLMError('Unknown API error', 'UNKNOWN_ERROR', false); } // HTTP status code based error handling if (error.status === 401 || error.message?.includes('authentication_error')) { return new LLMAuthenticationError(error.message || 'Authentication failed'); } if (error.status === 429 || error.message?.includes('rate_limit')) { return new LLMRateLimitError(error.message || 'Rate limit exceeded'); } if (error.status >= 500 || error.code === 'ECONNRESET' || error.code === 'ETIMEDOUT') { return new LLMNetworkError(error.message || 'Network error'); } // Generic network errors if (error.code === 'ENOTFOUND' || error.code === 'ECONNREFUSED') { return new LLMNetworkError(error.message || 'Network connection failed'); } // Default to non-retryable error return new LLMError(error.message || 'Unknown API error', 'UNKNOWN_ERROR', false); }; } } //# sourceMappingURL=APIClient.js.map