"use strict"; // Node 20 includes native fetch support var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Bot = void 0; // AI Client for Groq with Failover Support // Fallback shims for Probot runtime /* eslint-disable no-console */ const chatgpt_1 = require("chatgpt"); const p_retry_1 = __importDefault(require("p-retry")); const options_1 = require("./options"); const limits_1 = require("./limits"); const logInfo = console.log; const logWarning = console.warn; const logError = console.error; /* eslint-enable no-console */ const setFailed = (msg) => { console.error(msg); process.exit(1); }; class Bot { api = null; options; aiOptions; currentModel; fallbackModels; constructor(options, aiOptions) { this.options = options; this.aiOptions = aiOptions; this.currentModel = aiOptions.model; // Setup fallback chain based on tier if (options_1.Options.HEAVY_MODELS.includes(this.currentModel)) { this.fallbackModels = [...options_1.Options.HEAVY_MODELS]; } else { this.fallbackModels = [...options_1.Options.LIGHT_MODELS]; } // Remove current model from fallbacks to avoid immediate repeat this.fallbackModels = this.fallbackModels.filter(m => m !== this.currentModel); this.initClient(); } initClient() { const apiKey = process.env.GROQ_API_KEY || process.env.AI_API_KEY; if (apiKey) { const currentDate = new Date().toISOString().split('T')[0]; const limits = new limits_1.TokenLimits(this.currentModel); const systemMessage = `${this.options.systemMessage} Knowledge cutoff: ${limits.knowledgeCutOff} Current date: ${currentDate} IMPORTANT: Entire response must be in ISO code: ${this.options.language} `; this.api = new chatgpt_1.ChatGPTAPI({ apiBaseUrl: this.options.apiBaseUrl, systemMessage, apiKey, apiOrg: process.env.AI_API_ORG || undefined, debug: this.options.debug, maxModelTokens: limits.maxTokens, maxResponseTokens: limits.responseTokens, completionParams: { temperature: this.options.modelTemperature, model: this.currentModel } }); logInfo(`Initialized AI client with model: ${this.currentModel}`); } else { throw new Error("Missing 'GROQ_API_KEY' or 'AI_API_KEY'"); } } chat = async (message, ids) => { let res = ['', {}]; try { res = await this.chat_(message, ids); return res; } catch (e) { if (e instanceof chatgpt_1.ChatGPTError) { logWarning(`AI communication error: ${e.message}`); } return res; } }; chat_ = async (message, ids) => { const start = Date.now(); if (!message) return ['', {}]; let response; if (this.api != null) { const opts = { timeoutMs: this.options.timeoutMS }; if (ids.parentMessageId) { opts.parentMessageId = ids.parentMessageId; } try { response = await (0, p_retry_1.default)(async (attemptState) => { try { const result = await this.api.sendMessage(message, opts); return result; } catch (e) { if (e?.status === 429 && this.fallbackModels.length > 0) { const nextModel = this.fallbackModels.shift(); if (nextModel) { logWarning(`Rate limit (429) hit for ${this.currentModel}. Switching to fallback: ${nextModel}`); this.currentModel = nextModel; this.initClient(); } } throw e; } }, { retries: this.options.retries, onFailedAttempt: (err) => { logInfo(`Attempt ${err.attemptNumber} failed. ${err.retriesLeft} retries left.`); const errorResponse = err.response || err.status; if (errorResponse === 429 && this.fallbackModels.length > 0) { const nextModel = this.fallbackModels.shift(); if (nextModel) { logWarning(`Proactive switch to fallback model: ${nextModel} due to 429`); this.currentModel = nextModel; this.initClient(); } } } }); } catch (e) { if (e instanceof chatgpt_1.ChatGPTError) { logInfo(`AI Error: ${e.message} (Last model used: ${this.currentModel})`); } } const end = Date.now(); logInfo(`AI response time: ${end - start} ms`); } else { setFailed('AI client is not initialized'); } let responseText = ''; if (response != null) { responseText = response.text; } const newIds = { parentMessageId: response?.id, conversationId: response?.conversationId }; return [responseText, newIds]; }; } exports.Bot = Bot; //# sourceMappingURL=bot.js.map