@yuchida-tamu/podcast-gen
Version:
AI-Powered Monologue Podcast Generator
75 lines • 3.14 kB
JavaScript
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