2024-11-05 12:17:10 -06:00
|
|
|
import settings from '../../settings.js';
|
|
|
|
import { readFileSync } from 'fs';
|
|
|
|
import { containsCommand } from './commands/index.js';
|
2024-11-18 23:02:37 -06:00
|
|
|
import { sendBotChatToServer } from './server_proxy.js';
|
2024-11-05 12:17:10 -06:00
|
|
|
|
|
|
|
let agent;
|
2024-11-19 22:21:17 -06:00
|
|
|
let agent_names = settings.profiles.map((p) => JSON.parse(readFileSync(p, 'utf8')).name);
|
2024-11-05 12:17:10 -06:00
|
|
|
|
2024-11-21 23:32:25 -06:00
|
|
|
let self_prompter_paused = false;
|
2024-11-05 12:17:10 -06:00
|
|
|
|
|
|
|
export function isOtherAgent(name) {
|
|
|
|
return agent_names.some((n) => n === name);
|
|
|
|
}
|
|
|
|
|
2024-11-19 22:21:17 -06:00
|
|
|
export function updateAgents(names) {
|
|
|
|
agent_names = names;
|
|
|
|
}
|
|
|
|
|
2024-11-05 12:17:10 -06:00
|
|
|
export function initConversationManager(a) {
|
|
|
|
agent = a;
|
|
|
|
}
|
|
|
|
|
2024-11-21 23:32:25 -06:00
|
|
|
export function inConversation() {
|
|
|
|
return Object.values(convos).some(c => c.active);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function endConversation(sender) {
|
|
|
|
if (convos[sender]) {
|
|
|
|
convos[sender].end();
|
|
|
|
if (self_prompter_paused && !inConversation()) {
|
|
|
|
_resumeSelfPrompter();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function endAllChats() {
|
|
|
|
for (const sender in convos) {
|
|
|
|
convos[sender].end();
|
|
|
|
}
|
|
|
|
if (self_prompter_paused) {
|
|
|
|
_resumeSelfPrompter();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function scheduleSelfPrompter() {
|
|
|
|
self_prompter_paused = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function cancelSelfPrompter() {
|
|
|
|
self_prompter_paused = false;
|
|
|
|
}
|
|
|
|
|
2024-11-05 12:17:10 -06:00
|
|
|
class Conversation {
|
|
|
|
constructor(name) {
|
|
|
|
this.name = name;
|
2024-11-21 23:32:25 -06:00
|
|
|
this.active = false;
|
2024-11-05 12:17:10 -06:00
|
|
|
this.ignore_until_start = false;
|
|
|
|
this.blocked = false;
|
|
|
|
this.in_queue = [];
|
2024-11-21 23:32:25 -06:00
|
|
|
this.inMessageTimer = null;
|
2024-11-05 12:17:10 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
reset() {
|
2024-11-21 23:32:25 -06:00
|
|
|
this.active = false;
|
2024-11-05 12:17:10 -06:00
|
|
|
this.ignore_until_start = false;
|
|
|
|
this.in_queue = [];
|
2024-11-21 23:32:25 -06:00
|
|
|
this.inMessageTimer = null;
|
2024-11-05 12:17:10 -06:00
|
|
|
}
|
|
|
|
|
2024-11-21 23:32:25 -06:00
|
|
|
end() {
|
|
|
|
this.active = false;
|
|
|
|
this.ignore_until_start = true;
|
2024-11-05 12:17:10 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
queue(message) {
|
|
|
|
this.in_queue.push(message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const convos = {};
|
|
|
|
|
|
|
|
function _getConvo(name) {
|
|
|
|
if (!convos[name])
|
|
|
|
convos[name] = new Conversation(name);
|
|
|
|
return convos[name];
|
|
|
|
}
|
|
|
|
|
2024-11-21 23:32:25 -06:00
|
|
|
export async function startConversation(send_to, message) {
|
2024-11-05 12:17:10 -06:00
|
|
|
const convo = _getConvo(send_to);
|
|
|
|
convo.reset();
|
2024-11-21 23:32:25 -06:00
|
|
|
|
|
|
|
if (agent.self_prompter.on) {
|
|
|
|
await agent.self_prompter.stop();
|
|
|
|
self_prompter_paused = true;
|
|
|
|
}
|
|
|
|
convo.active = true;
|
2024-11-05 12:17:10 -06:00
|
|
|
sendToBot(send_to, message, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function sendToBot(send_to, message, start=false) {
|
2024-11-21 23:32:25 -06:00
|
|
|
if (settings.chat_bot_messages)
|
|
|
|
agent.bot.chat(`(To ${send_to}) ${message}`);
|
2024-11-05 12:17:10 -06:00
|
|
|
if (!isOtherAgent(send_to)) {
|
|
|
|
agent.bot.whisper(send_to, message);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const convo = _getConvo(send_to);
|
|
|
|
if (convo.ignore_until_start)
|
|
|
|
return;
|
2024-11-22 14:53:25 -06:00
|
|
|
convo.active = true;
|
|
|
|
|
2024-11-21 23:32:25 -06:00
|
|
|
const end = message.includes('!endConversation');
|
2024-11-05 12:17:10 -06:00
|
|
|
const json = {
|
|
|
|
'message': message,
|
|
|
|
start,
|
|
|
|
end,
|
|
|
|
};
|
|
|
|
|
2024-11-18 23:02:37 -06:00
|
|
|
// agent.bot.whisper(send_to, JSON.stringify(json));
|
|
|
|
sendBotChatToServer(send_to, JSON.stringify(json));
|
2024-11-05 12:17:10 -06:00
|
|
|
}
|
|
|
|
|
2024-11-21 23:32:25 -06:00
|
|
|
export async function recieveFromBot(sender, json) {
|
2024-11-05 12:17:10 -06:00
|
|
|
const convo = _getConvo(sender);
|
|
|
|
console.log(`decoding **${json}**`);
|
|
|
|
const recieved = JSON.parse(json);
|
|
|
|
if (recieved.start) {
|
|
|
|
convo.reset();
|
|
|
|
}
|
|
|
|
if (convo.ignore_until_start)
|
|
|
|
return;
|
|
|
|
|
|
|
|
convo.queue(recieved);
|
2024-11-18 23:02:37 -06:00
|
|
|
|
|
|
|
// responding to conversation takes priority over self prompting
|
2024-11-21 23:32:25 -06:00
|
|
|
if (agent.self_prompter.on){
|
|
|
|
await agent.self_prompter.stopLoop();
|
|
|
|
self_prompter_paused = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
_scheduleProcessInMessage(sender, recieved, convo);
|
|
|
|
}
|
2024-11-05 12:17:10 -06:00
|
|
|
|
2024-11-22 14:53:25 -06:00
|
|
|
// returns true if the other bot has a scheduled response
|
|
|
|
export function responseScheduledFor(sender) {
|
|
|
|
if (!isOtherAgent(sender))
|
|
|
|
return false;
|
|
|
|
const convo = _getConvo(sender);
|
|
|
|
return !!convo.inMessageTimer;
|
|
|
|
}
|
|
|
|
|
2024-11-21 23:32:25 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
This function controls conversation flow by deciding when the bot responds.
|
|
|
|
The logic is as follows:
|
|
|
|
- If neither bot is busy, respond quickly with a small delay.
|
|
|
|
- If only the other bot is busy, respond with a long delay to allow it to finish short actions (ex check inventory)
|
|
|
|
- If I'm busy but other bot isn't, let LLM decide whether to respond
|
|
|
|
- If both bots are busy, don't respond until someone is done, excluding a few actions that allow fast responses
|
|
|
|
- New messages recieved during the delay will reset the delay following this logic, and be queued to respond in bulk
|
|
|
|
*/
|
2024-11-22 14:53:25 -06:00
|
|
|
const talkOverActions = ['stay', 'followPlayer', 'mode:']; // all mode actions
|
2024-11-21 23:32:25 -06:00
|
|
|
const fastDelay = 200;
|
|
|
|
const longDelay = 5000;
|
|
|
|
async function _scheduleProcessInMessage(sender, recieved, convo) {
|
|
|
|
if (convo.inMessageTimer)
|
|
|
|
clearTimeout(convo.inMessageTimer);
|
|
|
|
let otherAgentBusy = containsCommand(recieved.message);
|
|
|
|
|
|
|
|
const scheduleResponse = (delay) => convo.inMessageTimer = setTimeout(() => _processInMessageQueue(sender), delay);
|
|
|
|
|
|
|
|
if (!agent.isIdle() && otherAgentBusy) {
|
|
|
|
// both are busy
|
|
|
|
let canTalkOver = talkOverActions.some(a => agent.actions.currentActionLabel.includes(a));
|
|
|
|
if (canTalkOver)
|
|
|
|
scheduleResponse(fastDelay)
|
|
|
|
// otherwise don't respond
|
|
|
|
}
|
|
|
|
else if (otherAgentBusy)
|
|
|
|
// other bot is busy but I'm not
|
|
|
|
scheduleResponse(longDelay);
|
|
|
|
else if (!agent.isIdle()) {
|
|
|
|
// I'm busy but other bot isn't
|
2024-11-22 14:53:25 -06:00
|
|
|
let canTalkOver = talkOverActions.some(a => agent.actions.currentActionLabel.includes(a));
|
|
|
|
if (canTalkOver) {
|
2024-11-21 23:32:25 -06:00
|
|
|
scheduleResponse(fastDelay);
|
2024-11-22 14:53:25 -06:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
let shouldRespond = await agent.prompter.promptShouldRespondToBot(recieved.message);
|
|
|
|
console.log(`${agent.name} decided to ${shouldRespond?'respond':'not respond'} to ${sender}`);
|
|
|
|
if (shouldRespond)
|
|
|
|
scheduleResponse(fastDelay);
|
|
|
|
}
|
2024-11-21 23:32:25 -06:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// neither are busy
|
|
|
|
scheduleResponse(fastDelay);
|
|
|
|
}
|
2024-11-05 12:17:10 -06:00
|
|
|
}
|
|
|
|
|
2024-11-22 14:53:25 -06:00
|
|
|
function _processInMessageQueue(name) {
|
2024-11-05 12:17:10 -06:00
|
|
|
const convo = _getConvo(name);
|
|
|
|
let pack = null;
|
|
|
|
let full_message = '';
|
|
|
|
while (convo.in_queue.length > 0) {
|
|
|
|
pack = convo.in_queue.shift();
|
|
|
|
full_message += pack.message;
|
|
|
|
}
|
|
|
|
pack.message = full_message;
|
|
|
|
_handleFullInMessage(name, pack);
|
|
|
|
}
|
|
|
|
|
2024-11-22 14:53:25 -06:00
|
|
|
function _handleFullInMessage(sender, recieved) {
|
2024-11-18 23:02:37 -06:00
|
|
|
console.log(`responding to **${JSON.stringify(recieved)}**`);
|
2024-11-05 12:17:10 -06:00
|
|
|
|
|
|
|
const convo = _getConvo(sender);
|
2024-11-22 14:53:25 -06:00
|
|
|
convo.active = true;
|
2024-11-05 12:17:10 -06:00
|
|
|
|
|
|
|
const message = _tagMessage(recieved.message);
|
2024-11-21 23:32:25 -06:00
|
|
|
if (recieved.end) {
|
|
|
|
convo.end();
|
|
|
|
// if end signal from other bot, add to history but don't respond
|
2024-11-05 12:17:10 -06:00
|
|
|
agent.history.add(sender, message);
|
|
|
|
return;
|
|
|
|
}
|
2024-11-18 23:02:37 -06:00
|
|
|
if (recieved.start)
|
|
|
|
agent.shut_up = false;
|
2024-11-22 14:53:25 -06:00
|
|
|
convo.inMessageTimer = null;
|
2024-11-05 12:17:10 -06:00
|
|
|
agent.handleMessage(sender, message);
|
|
|
|
}
|
|
|
|
|
2024-11-18 23:02:37 -06:00
|
|
|
|
2024-11-05 12:17:10 -06:00
|
|
|
function _tagMessage(message) {
|
|
|
|
return "(FROM OTHER BOT)" + message;
|
|
|
|
}
|
2024-11-21 23:32:25 -06:00
|
|
|
|
|
|
|
async function _resumeSelfPrompter() {
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
|
|
self_prompter_paused = false;
|
|
|
|
agent.self_prompter.start();
|
|
|
|
}
|