'use strict'; const conf = require('../conf'); /** * Ai plugin — thin shim. * * The real work (LLM provider, poll timer, tool registry, response processing) * lives in AiManager. This class exists only for compatibility with CJbot's * plugin system: pluginAdd/pluginLoad/pluginUnload, the .ai chat command, * and the trade plugin's _expectingTradeWindow flag. * * Only ONE bot should load this plugin. The config key `ai.faceBot` names it. */ class Ai { constructor(args) { this.bot = args.bot; // Extract config — same destructure as the old Ai class const { bot: _bot, promptName, prompCustom, intervalLength, interval, ...configProps } = args; this.promptName = promptName; this.prompCustom = prompCustom || ''; this.botConfig = args.botConfig || configProps || {}; } async init() { const { getInstance } = require('./ai/manager'); const manager = getInstance(); // If manager is already active on another bot, that's a config conflict if (manager.isActive && manager.faceBotName !== this.bot.name) { console.warn(`Ai: manager already running on ${manager.faceBotName} — ignoring init on ${this.bot.name}`); console.warn(`Ai: shutdown the existing Ai plugin first, or change ai.faceBot in config`); return; } // If already active on THIS bot, this is a reload (e.g. .ai command) if (manager.isActive && manager.faceBotName === this.bot.name) { await manager.reloadPrompt(this.promptName, this.prompCustom); return; } // Fresh init await manager.init(this.bot, this._getConfig()); this.bot._aiControlsTrade = true; console.log(`Ai: ${this.bot.name} is the face bot`); } async unload() { const { getInstance } = require('./ai/manager'); const manager = getInstance(); if (manager.faceBotName === this.bot.name) { await manager.shutdown(); } delete this.bot._aiControlsTrade; console.log(`Ai: unloaded from ${this.bot.name}`); return true; } _getConfig() { return { ...conf.ai, ...this.botConfig }; } // ======================================== // Backward-compat proxies // These are accessed by trade.js and the web UI // ======================================== get _expectingTradeWindow() { const { getInstance } = require('./ai/manager'); return getInstance()._expectingTradeWindow; } set _expectingTradeWindow(val) { const { getInstance } = require('./ai/manager'); getInstance()._expectingTradeWindow = val; } get _active() { const { getInstance } = require('./ai/manager'); return getInstance().isActive; } get memoryDB() { const { getInstance } = require('./ai/manager'); return getInstance()._memoryDB; } get intervalLength() { return this._getConfig().interval || 10; } get provider() { const { getInstance } = require('./ai/manager'); return getInstance()._provider; } } // Web UI support — unchanged pattern, but routes now use the manager internally const AiWeb = require('./ai/web'); Ai.createRouter = AiWeb.createRouter; Ai.webUI = AiWeb.webUI; module.exports = Ai;