llmforge
Version:
One API, every AI model, instant switching. Change from GPT-4 to Gemini to local models with a single config update. LLMForge is the lightweight, TypeScript-first solution for multi-provider AI applications with zero vendor lock-in.
85 lines • 3.74 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.RetryHandler = void 0;
const logger_1 = require("../../utils/logger");
const types_1 = require("../../types");
class RetryHandler {
constructor(config = {}) {
this.config = {
maxRetries: config.maxRetries || 3,
retryDelay: config.retryDelay || 1000,
exponentialBackoff: config.exponentialBackoff !== false,
retryableStatusCodes: config.retryableStatusCodes || [429, 500, 502, 503, 504],
};
}
async executeWithRetry(operation, context = 'operation') {
var _a, _b, _c, _d;
let lastError;
for (let attempt = 0; attempt <= ((_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.maxRetries) !== null && _b !== void 0 ? _b : 1); attempt++) {
try {
const result = await operation();
if (attempt > 0) {
logger_1.logger.info(`${context} succeeded on attempt ${attempt + 1}`);
}
return result;
}
catch (error) {
lastError = error;
if (attempt === ((_c = this.config) === null || _c === void 0 ? void 0 : _c.maxRetries)) {
logger_1.logger.error(`${context} failed after ${((_d = this.config) === null || _d === void 0 ? void 0 : _d.maxRetries) + 1} attempts:`, lastError);
break;
}
if (!this.isRetryableError(error)) {
throw error;
}
const delay = this.calculateDelay(attempt);
logger_1.logger.warn(`${context} failed on attempt ${attempt + 1}, retrying in ${delay}ms:`, lastError.message);
await this.sleep(delay);
}
}
throw lastError;
}
isRetryableError(error) {
var _a, _b;
// Check for specific error types
if (error instanceof types_1.NonRetryableError) {
return false;
}
if (error instanceof types_1.RetryableError) {
return true;
}
if (error.name === 'TypeError' && error.message.includes('fetch')) {
return true;
}
if (error.name === 'AbortError' || error.message.includes('timeout')) {
return true;
}
// Check for HTTP status codes
if (error.status || error.code) {
const statusCode = error.status || error.code;
return ((_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.retryableStatusCodes) === null || _b === void 0 ? void 0 : _b.includes(statusCode)) ? true : false;
}
// Default to non-retryable for unknown errors
return false;
}
calculateDelay(attempt) {
var _a, _b, _c, _d, _e;
if (!((_a = this.config) === null || _a === void 0 ? void 0 : _a.exponentialBackoff)) {
return (_c = (_b = this.config) === null || _b === void 0 ? void 0 : _b.retryDelay) !== null && _c !== void 0 ? _c : 1000; // Default to a fixed delay if exponential backoff is not enabled
}
const baseDelay = (_e = (_d = this.config) === null || _d === void 0 ? void 0 : _d.retryDelay) !== null && _e !== void 0 ? _e : 1000 * Math.pow(2, attempt);
const jitter = Math.random() * 0.1 * baseDelay;
return Math.floor(baseDelay + jitter);
}
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
updateConfig(newConfig) {
this.config = { ...this.config, ...newConfig };
}
getConfig() {
return { ...this.config };
}
}
exports.RetryHandler = RetryHandler;
//# sourceMappingURL=expo.js.map