From e2aad3df9c830a3eb3d146cf01476006bd887d61 Mon Sep 17 00:00:00 2001 From: MaxRobinsonTheGreat Date: Fri, 8 Dec 2023 16:18:20 -0600 Subject: [PATCH] added parent process + crash restarts --- agent.js | 6 ++---- controller.js | 32 ++++++++++++++++++++++++++++++++ init_agent.js | 22 ++++++++++++++++++++++ main.js | 4 ---- package.json | 3 ++- utils/coder.js | 12 ++++++++---- utils/skills.js | 5 +++-- 7 files changed, 69 insertions(+), 15 deletions(-) create mode 100644 controller.js create mode 100644 init_agent.js delete mode 100644 main.js diff --git a/agent.js b/agent.js index 46f7937..f1c6bdb 100644 --- a/agent.js +++ b/agent.js @@ -69,12 +69,10 @@ export class Agent { this.coder.queueCode(code); let code_return = await this.coder.execute(); let message = code_return.message; - if (code_return.timedout) - message += "\n Code ran for a while and was stopped."; - else if (code_return.interrupted) + if (code_return.interrupted && !code_return.timedout) break; // when interupted but not timed out, we were interupted by another conversation. end this one. if (!code_return.success) { - message += "\n Write code to fix the problem and try again."; + message += "\nWrite code to fix the problem and try again."; } console.log('code return:', message); this.history.add('system', message); diff --git a/controller.js b/controller.js new file mode 100644 index 0000000..9db3a83 --- /dev/null +++ b/controller.js @@ -0,0 +1,32 @@ +import { spawn } from 'child_process'; + +class AgentController { + constructor(name) { + this.name = name; + } + async start(restart_memory=false) { + let args = ['init_agent.js', this.name]; + if (restart_memory) + args.push('-r'); + const agentProcess = spawn('node', args, { + stdio: 'inherit', + stderr: 'inherit', + }); + + agentProcess.on('exit', (code, signal) => { + console.log(`Agent process exited with code ${code} and signal ${signal}`); + + // Restart the agent if it exited due to an error + if (code !== 0) { + console.log('Restarting agent...'); + this.start(); + } + }); + + agentProcess.on('error', (err) => { + console.error('Failed to start agent process:', err); + }); + } +} + +new AgentController('andy').start(); \ No newline at end of file diff --git a/init_agent.js b/init_agent.js new file mode 100644 index 0000000..43a0615 --- /dev/null +++ b/init_agent.js @@ -0,0 +1,22 @@ +import { Agent } from './agent.js'; +import yargs from 'yargs'; + +const args = process.argv.slice(2); +if (args.length < 1) { + console.log('Usage: node init_agent.js [options]'); + process.exit(1); +} + +const argv = yargs(args) + .option('restart_memory', { + alias: 'r', + type: 'boolean', + description: 'restart memory from scratch' + }).argv; + +const name = argv._[0]; +const restart_memory = !!argv.restart_memory; +const save_path = './bots/'+name+'.json'; + +let agent = new Agent(name, save_path, restart_memory); +agent.start(); diff --git a/main.js b/main.js deleted file mode 100644 index 7d56f81..0000000 --- a/main.js +++ /dev/null @@ -1,4 +0,0 @@ -import { Agent } from './agent.js'; - -let agent = new Agent('andy', './bots/andy.json', true); -agent.start(); diff --git a/package.json b/package.json index 401e918..39ea3ce 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "mineflayer-pathfinder": "^2.4.4", "mineflayer-pvp": "^1.3.2", "openai": "^4.4.0", - "patch-package": "^8.0.0" + "patch-package": "^8.0.0", + "yargs": "^17.7.2" } } diff --git a/utils/coder.js b/utils/coder.js index e13e417..5bc029c 100644 --- a/utils/coder.js +++ b/utils/coder.js @@ -48,7 +48,7 @@ export class Coder { } - // returns {success: bool, message: string, interrupted: bool} + // returns {success: bool, message: string, interrupted: bool, timedout: false} async execute() { if (!this.queued_code) return {success: false, message: "No code to execute.", interrupted: false, timedout: false}; if (!this.code_template) return {success: false, message: "Code template not loaded.", interrupted: false, timedout: false}; @@ -114,7 +114,7 @@ export class Coder { } formatOutput(bot) { - if (bot.interrupt_code) return ''; + if (bot.interrupt_code && !this.timedout) return ''; let output = bot.output; const MAX_OUT = 1000; if (output.length > MAX_OUT) { @@ -151,11 +151,15 @@ export class Coder { return setTimeout(async () => { console.warn(`Code execution timed out after ${TIMEOUT_MINS} minutes. Attempting force stop.`); this.timedout = true; + this.agent.bot.output += `\nAction performed for ${TIMEOUT_MINS} minutes and then timed out and stopped. You may want to continue or do something else.`; this.stop(); // last attempt to stop - await new Promise(resolve => setTimeout(resolve, 5 * 1000)); + await new Promise(resolve => setTimeout(resolve, 5 * 1000)); // wait 5 seconds if (this.executing) { console.error(`Failed to stop. Killing process. Goodbye.`); - // TODO: force save memories + this.agent.bot.output += `\nForce stop failed! Killing bot.`; + let output = this.formatOutput(this.agent.bot); + this.agent.history.add('system', output); + this.agent.history.save(); process.exit(1); // force exit program } console.log('Code execution stopped successfully.'); diff --git a/utils/skills.js b/utils/skills.js index 8b10953..9d97a0d 100644 --- a/utils/skills.js +++ b/utils/skills.js @@ -259,7 +259,9 @@ export async function collectBlock(bot, blockType, num=1) { log(bot, `Failed to collect ${blockType}: ${err}.`); continue; } - } + } + if (bot.interrupt_code) + break; } log(bot, `Collected ${collected} ${blockType}.`); return true; @@ -569,7 +571,6 @@ export async function followPlayer(bot, username) { log(bot, `You are now actively following player ${username}.`); while (!bot.interrupt_code) { - console.log('followPlayer waiting for interrupt...', bot.interrupt_code); await new Promise(resolve => setTimeout(resolve, 1000)); }