Files
mc-bot-town/nodejs/controller/ai.js
2026-01-31 18:49:08 -05:00

145 lines
3.5 KiB
JavaScript

'use strict';
const conf = require('../conf');
const {sleep} = require('../utils');
const { ProviderFactory } = require('./ai/providers');
class Ai{
constructor(args){
this.bot = args.bot;
this.promptName = args.promptName;
this.prompCustom = args.prompCustom || '';
this.intervalLength = args.intervalLength || 30;
this.intervalStop;
this.messageListener;
this.provider = null;
// Bot-specific AI config (overrides global config)
this.botConfig = args.botConfig || {};
}
// Get merged config: bot-specific settings override global settings
__getConfig() {
return {
...conf.ai, // Global defaults
...this.botConfig, // Bot-specific overrides
};
}
async init(){
this.bot.on('onReady', async (argument)=>{
try{
await this.start();
let messages = [''];
this.messageListener = this.bot.on('message', (message, type)=>{
if(type === 'game_info') return;
if(message.toString().startsWith('<') && message.toString().split('>')[0].includes(this.bot.bot.entity.username)){
console.log('message blocked from message array')
return;
}
console.log(`Message ${type}: ${message.toString()}`)
messages.push('>', message.toString());
});
this.intervalStop = setInterval(async ()=>{
let result;
try{
result = await this.chat(JSON.stringify({
messages, currentTime:Date.now()+1}
));
}catch(error){
console.log('error AI API', error, result);
messages = [];
return ;
}
try{
messages = [''];
if(!this.provider.getResponse(result)) return;
for(let message of JSON.parse(this.provider.getResponse(result))){
console.log('toSay', message.delay, message.text);
if(message.text === '___') return;
setTimeout(async (message)=>{
await this.bot.sayAiSafe(message.text);
}, message.delay*1000, message);
}
}catch(error){
console.log('Error in AI message loop', error, result);
try {
if(result && this.provider.getResponse(result)){
console.log(this.provider.getResponse(result))
}
} catch(e) {
// Ignore
}
}
}, this.intervalLength*1000);
}catch(error){
console.log('error in onReady', error);
}
});
}
async unload(){
if(this.intervalStop){
clearInterval(this.intervalStop);
this.intervalStop = undefined;
}
if(this.messageListener){
this.messageListener();
}
if(this.provider){
await this.provider.close();
}
return true;
}
async start(history){
const config = this.__getConfig();
let bulbaItems = {};
console.log(`${this.bot.name} AI config:`, {
provider: config.provider,
model: config.model,
promptName: this.promptName,
baseUrl: config.baseUrl,
});
const prompt = conf.ai.prompts[this.promptName](
this.bot.bot.entity.username,
config.interval,
Object.values(this.bot.getPlayers()).map(player=>`<[${player.lvl}] ${player.username}>`).join('\n'),
bulbaItems,
this.prompCustom,
);
// Create the provider instance with merged config and prompt
this.provider = ProviderFactory.create({
...config,
prompt: prompt,
});
await this.provider.start(history);
console.log(`${this.bot.name} AI ${config.provider} provider started (model: ${config.model})`);
}
async chat(message, retryCount=0){
console.log(`chat ${this.bot.name}`, retryCount)
try{
let result = await this.provider.chat(message);
return result
}catch(error){
console.log('AI chat error', error)
throw error;
}
}
}
module.exports = Ai;