mindcraft/src/agent/self_prompter.js
2025-02-20 18:17:06 -06:00

146 lines
No EOL
4.3 KiB
JavaScript

const STOPPED = 0
const ACTIVE = 1
const PAUSED = 2
export class SelfPrompter {
constructor(agent) {
this.agent = agent;
this.state = STOPPED;
this.loop_active = false;
this.interrupt = false;
this.prompt = '';
this.idle_time = 0;
this.cooldown = 2000;
}
start(prompt) {
console.log('Self-prompting started.');
if (!prompt) {
if (!this.prompt)
return 'No prompt specified. Ignoring request.';
prompt = this.prompt;
}
this.state = ACTIVE;
this.prompt = prompt;
this.startLoop();
}
isActive() {
return this.state === ACTIVE;
}
isStopped() {
return this.state === STOPPED;
}
isPaused() {
return this.state === PAUSED;
}
async handleLoad(prompt, state) {
if (state == undefined)
state = STOPPED;
this.state = state;
this.prompt = prompt;
if (state !== STOPPED && !prompt)
throw new Error('No prompt loaded when self-prompting is active');
if (state === ACTIVE) {
await this.start(prompt);
}
}
setPromptPaused(prompt) {
this.prompt = prompt;
this.state = PAUSED;
}
async startLoop() {
if (this.loop_active) {
console.warn('Self-prompt loop is already active. Ignoring request.');
return;
}
console.log('starting self-prompt loop')
this.loop_active = true;
let no_command_count = 0;
const MAX_NO_COMMAND = 3;
while (!this.interrupt) {
const msg = `You are self-prompting with the goal: '${this.prompt}'. Your next response MUST contain a command with this syntax: !commandName. Respond:`;
let used_command = await this.agent.handleMessage('system', msg, -1);
if (!used_command) {
no_command_count++;
if (no_command_count >= MAX_NO_COMMAND) {
let out = `Agent did not use command in the last ${MAX_NO_COMMAND} auto-prompts. Stopping auto-prompting.`;
this.agent.openChat(out);
console.warn(out);
this.state = STOPPED;
break;
}
}
else {
no_command_count = 0;
await new Promise(r => setTimeout(r, this.cooldown));
}
}
console.log('self prompt loop stopped')
this.loop_active = false;
this.interrupt = false;
}
update(delta) {
// automatically restarts loop
if (this.state === ACTIVE && !this.loop_active && !this.interrupt) {
if (this.agent.isIdle())
this.idle_time += delta;
else
this.idle_time = 0;
if (this.idle_time >= this.cooldown) {
console.log('Restarting self-prompting...');
this.startLoop();
this.idle_time = 0;
}
}
else {
this.idle_time = 0;
}
}
async stopLoop() {
// you can call this without await if you don't need to wait for it to finish
if (this.interrupt)
return;
console.log('stopping self-prompt loop')
this.interrupt = true;
while (this.loop_active) {
await new Promise(r => setTimeout(r, 500));
}
this.interrupt = false;
}
async stop(stop_action=true) {
this.interrupt = true;
if (stop_action)
await this.agent.actions.stop();
this.stopLoop();
this.state = STOPPED;
}
async pause() {
this.interrupt = true;
await this.agent.actions.stop();
this.stopLoop();
this.state = PAUSED;
}
shouldInterrupt(is_self_prompt) { // to be called from handleMessage
return is_self_prompt && (this.state === ACTIVE || this.state === PAUSED) && this.interrupt;
}
handleUserPromptedCmd(is_self_prompt, is_action) {
// if a user messages and the bot responds with an action, stop the self-prompt loop
if (!is_self_prompt && is_action) {
this.stopLoop();
// this stops it from responding from the handlemessage loop and the self-prompt loop at the same time
}
}
}