mirror of
https://github.com/kolbytn/mindcraft.git
synced 2025-03-28 14:56:24 +01:00
add state to self prompter for pausing
This commit is contained in:
parent
7d9257036c
commit
b23f4776b1
10 changed files with 68 additions and 50 deletions
|
@ -44,6 +44,7 @@
|
||||||
},
|
},
|
||||||
"multiagent_techtree_1_stone_pickaxe": {
|
"multiagent_techtree_1_stone_pickaxe": {
|
||||||
"conversation": "Let's collaborate to build a stone pickaxe",
|
"conversation": "Let's collaborate to build a stone pickaxe",
|
||||||
|
"goal": "Build a stone pickaxe",
|
||||||
"agent_count": 2,
|
"agent_count": 2,
|
||||||
"initial_inventory": {
|
"initial_inventory": {
|
||||||
"0": {
|
"0": {
|
||||||
|
|
|
@ -46,7 +46,7 @@ export class ActionManager {
|
||||||
assert(actionLabel != null, 'actionLabel is required for new resume');
|
assert(actionLabel != null, 'actionLabel is required for new resume');
|
||||||
this.resume_name = actionLabel;
|
this.resume_name = actionLabel;
|
||||||
}
|
}
|
||||||
if (this.resume_func != null && (this.agent.isIdle() || new_resume) && (!this.agent.self_prompter.on || new_resume)) {
|
if (this.resume_func != null && (this.agent.isIdle() || new_resume) && (!this.agent.self_prompter.isActive() || new_resume)) {
|
||||||
this.currentActionLabel = this.resume_name;
|
this.currentActionLabel = this.resume_name;
|
||||||
let res = await this._executeAction(this.resume_name, this.resume_func, timeout);
|
let res = await this._executeAction(this.resume_name, this.resume_func, timeout);
|
||||||
this.currentActionLabel = '';
|
this.currentActionLabel = '';
|
||||||
|
|
|
@ -156,10 +156,10 @@ export class Agent {
|
||||||
};
|
};
|
||||||
|
|
||||||
if (save_data?.self_prompt) {
|
if (save_data?.self_prompt) {
|
||||||
let prompt = save_data.self_prompt;
|
if (init_message) {
|
||||||
// add initial message to history
|
this.history.add('system', init_message);
|
||||||
this.history.add('system', prompt);
|
}
|
||||||
await this.self_prompter.start(prompt);
|
await this.self_prompter.handleLoad(save_data.self_prompt, save_data.self_prompting_state);
|
||||||
}
|
}
|
||||||
if (save_data?.last_sender) {
|
if (save_data?.last_sender) {
|
||||||
this.last_sender = save_data.last_sender;
|
this.last_sender = save_data.last_sender;
|
||||||
|
@ -193,7 +193,7 @@ export class Agent {
|
||||||
|
|
||||||
shutUp() {
|
shutUp() {
|
||||||
this.shut_up = true;
|
this.shut_up = true;
|
||||||
if (this.self_prompter.on) {
|
if (this.self_prompter.isActive()) {
|
||||||
this.self_prompter.stop(false);
|
this.self_prompter.stop(false);
|
||||||
}
|
}
|
||||||
convoManager.endAllConversations();
|
convoManager.endAllConversations();
|
||||||
|
@ -259,7 +259,7 @@ export class Agent {
|
||||||
await this.history.add(source, message);
|
await this.history.add(source, message);
|
||||||
this.history.save();
|
this.history.save();
|
||||||
|
|
||||||
if (!self_prompt && this.self_prompter.on) // message is from user during self-prompting
|
if (!self_prompt && this.self_prompter.isActive()) // message is from user during self-prompting
|
||||||
max_responses = 1; // force only respond to this message, then let self-prompting take over
|
max_responses = 1; // force only respond to this message, then let self-prompting take over
|
||||||
for (let i=0; i<max_responses; i++) {
|
for (let i=0; i<max_responses; i++) {
|
||||||
if (checkInterrupt()) break;
|
if (checkInterrupt()) break;
|
||||||
|
|
|
@ -49,7 +49,7 @@ export const actionsList = [
|
||||||
agent.actions.cancelResume();
|
agent.actions.cancelResume();
|
||||||
agent.bot.emit('idle');
|
agent.bot.emit('idle');
|
||||||
let msg = 'Agent stopped.';
|
let msg = 'Agent stopped.';
|
||||||
if (agent.self_prompter.on)
|
if (agent.self_prompter.isActive())
|
||||||
msg += ' Self-prompting still active.';
|
msg += ' Self-prompting still active.';
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
@ -362,8 +362,7 @@ export const actionsList = [
|
||||||
},
|
},
|
||||||
perform: async function (agent, prompt) {
|
perform: async function (agent, prompt) {
|
||||||
if (convoManager.inConversation()) {
|
if (convoManager.inConversation()) {
|
||||||
agent.self_prompter.setPrompt(prompt);
|
agent.self_prompter.setPromptPaused(prompt);
|
||||||
convoManager.scheduleSelfPrompter();
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
agent.self_prompter.start(prompt);
|
agent.self_prompter.start(prompt);
|
||||||
|
@ -375,7 +374,6 @@ export const actionsList = [
|
||||||
description: 'Call when you have accomplished your goal. It will stop self-prompting and the current action. ',
|
description: 'Call when you have accomplished your goal. It will stop self-prompting and the current action. ',
|
||||||
perform: async function (agent) {
|
perform: async function (agent) {
|
||||||
agent.self_prompter.stop();
|
agent.self_prompter.stop();
|
||||||
convoManager.cancelSelfPrompter();
|
|
||||||
return 'Self-prompting stopped.';
|
return 'Self-prompting stopped.';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,8 +7,6 @@ let agent;
|
||||||
let agent_names = settings.profiles.map((p) => JSON.parse(readFileSync(p, 'utf8')).name);
|
let agent_names = settings.profiles.map((p) => JSON.parse(readFileSync(p, 'utf8')).name);
|
||||||
let agents_in_game = [];
|
let agents_in_game = [];
|
||||||
|
|
||||||
let self_prompter_paused = false;
|
|
||||||
|
|
||||||
class Conversation {
|
class Conversation {
|
||||||
constructor(name) {
|
constructor(name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
@ -97,7 +95,7 @@ class ConversationManager {
|
||||||
this._clearMonitorTimeouts();
|
this._clearMonitorTimeouts();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!self_prompter_paused) {
|
if (!agent.self_prompter.isPaused()) {
|
||||||
this.endConversation(convo_partner);
|
this.endConversation(convo_partner);
|
||||||
agent.handleMessage('system', `${convo_partner} disconnected, conversation has ended.`);
|
agent.handleMessage('system', `${convo_partner} disconnected, conversation has ended.`);
|
||||||
}
|
}
|
||||||
|
@ -125,9 +123,8 @@ class ConversationManager {
|
||||||
const convo = this._getConvo(send_to);
|
const convo = this._getConvo(send_to);
|
||||||
convo.reset();
|
convo.reset();
|
||||||
|
|
||||||
if (agent.self_prompter.on) {
|
if (agent.self_prompter.isActive()) {
|
||||||
await agent.self_prompter.stop();
|
await agent.self_prompter.pause();
|
||||||
self_prompter_paused = true;
|
|
||||||
}
|
}
|
||||||
if (convo.active)
|
if (convo.active)
|
||||||
return;
|
return;
|
||||||
|
@ -191,9 +188,8 @@ class ConversationManager {
|
||||||
convo.queue(received);
|
convo.queue(received);
|
||||||
|
|
||||||
// responding to conversation takes priority over self prompting
|
// responding to conversation takes priority over self prompting
|
||||||
if (agent.self_prompter.on){
|
if (agent.self_prompter.isActive()){
|
||||||
await agent.self_prompter.stopLoop();
|
await agent.self_prompter.pause();
|
||||||
self_prompter_paused = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_scheduleProcessInMessage(sender, received, convo);
|
_scheduleProcessInMessage(sender, received, convo);
|
||||||
|
@ -235,7 +231,7 @@ class ConversationManager {
|
||||||
if (this.activeConversation.name === sender) {
|
if (this.activeConversation.name === sender) {
|
||||||
this._stopMonitor();
|
this._stopMonitor();
|
||||||
this.activeConversation = null;
|
this.activeConversation = null;
|
||||||
if (self_prompter_paused && !this.inConversation()) {
|
if (agent.self_prompter.isPaused() && !this.inConversation()) {
|
||||||
_resumeSelfPrompter();
|
_resumeSelfPrompter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -246,7 +242,7 @@ class ConversationManager {
|
||||||
for (const sender in this.convos) {
|
for (const sender in this.convos) {
|
||||||
this.endConversation(sender);
|
this.endConversation(sender);
|
||||||
}
|
}
|
||||||
if (self_prompter_paused) {
|
if (agent.self_prompter.isPaused()) {
|
||||||
_resumeSelfPrompter();
|
_resumeSelfPrompter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -258,14 +254,6 @@ class ConversationManager {
|
||||||
this.endConversation(sender);
|
this.endConversation(sender);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduleSelfPrompter() {
|
|
||||||
self_prompter_paused = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cancelSelfPrompter() {
|
|
||||||
self_prompter_paused = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const convoManager = new ConversationManager();
|
const convoManager = new ConversationManager();
|
||||||
|
@ -360,8 +348,7 @@ function _tagMessage(message) {
|
||||||
|
|
||||||
async function _resumeSelfPrompter() {
|
async function _resumeSelfPrompter() {
|
||||||
await new Promise(resolve => setTimeout(resolve, 5000));
|
await new Promise(resolve => setTimeout(resolve, 5000));
|
||||||
if (self_prompter_paused && !convoManager.inConversation()) {
|
if (agent.self_prompter.isPaused() && !convoManager.inConversation()) {
|
||||||
self_prompter_paused = false;
|
|
||||||
agent.self_prompter.start();
|
agent.self_prompter.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,8 @@ export class History {
|
||||||
const data = {
|
const data = {
|
||||||
memory: this.memory,
|
memory: this.memory,
|
||||||
turns: this.turns,
|
turns: this.turns,
|
||||||
self_prompt: this.agent.self_prompter.on ? this.agent.self_prompter.prompt : null,
|
self_prompting_state: this.agent.self_prompter.state,
|
||||||
|
self_prompt: this.agent.self_prompter.isStopped() ? null : this.agent.self_prompter.prompt,
|
||||||
last_sender: this.agent.last_sender
|
last_sender: this.agent.last_sender
|
||||||
};
|
};
|
||||||
writeFileSync(this.memory_fp, JSON.stringify(data, null, 2));
|
writeFileSync(this.memory_fp, JSON.stringify(data, null, 2));
|
||||||
|
|
|
@ -277,7 +277,7 @@ const modes_list = [
|
||||||
];
|
];
|
||||||
|
|
||||||
async function execute(mode, agent, func, timeout=-1) {
|
async function execute(mode, agent, func, timeout=-1) {
|
||||||
if (agent.self_prompter.on)
|
if (agent.self_prompter.isActive())
|
||||||
agent.self_prompter.stopLoop();
|
agent.self_prompter.stopLoop();
|
||||||
let interrupted_action = agent.actions.currentActionLabel;
|
let interrupted_action = agent.actions.currentActionLabel;
|
||||||
mode.active = true;
|
mode.active = true;
|
||||||
|
@ -290,7 +290,7 @@ async function execute(mode, agent, func, timeout=-1) {
|
||||||
let should_reprompt =
|
let should_reprompt =
|
||||||
interrupted_action && // it interrupted a previous action
|
interrupted_action && // it interrupted a previous action
|
||||||
!agent.actions.resume_func && // there is no resume function
|
!agent.actions.resume_func && // there is no resume function
|
||||||
!agent.self_prompter.on && // self prompting is not on
|
!agent.self_prompter.isActive() && // self prompting is not on
|
||||||
!code_return.interrupted; // this mode action was not interrupted by something else
|
!code_return.interrupted; // this mode action was not interrupted by something else
|
||||||
|
|
||||||
if (should_reprompt) {
|
if (should_reprompt) {
|
||||||
|
@ -311,9 +311,9 @@ for (let mode of modes_list) {
|
||||||
class ModeController {
|
class ModeController {
|
||||||
/*
|
/*
|
||||||
SECURITY WARNING:
|
SECURITY WARNING:
|
||||||
ModesController must be isolated. Do not store references to external objects like `agent`.
|
ModesController must be reference isolated. Do not store references to external objects like `agent`.
|
||||||
This object is accessible by LLM generated code, so any stored references are also accessible.
|
This object is accessible by LLM generated code, so any stored references are also accessible.
|
||||||
This can be used to expose sensitive information by malicious human prompters.
|
This can be used to expose sensitive information by malicious prompters.
|
||||||
*/
|
*/
|
||||||
constructor() {
|
constructor() {
|
||||||
this.behavior_log = '';
|
this.behavior_log = '';
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
|
const STOPPED = 0
|
||||||
|
const ACTIVE = 1
|
||||||
|
const PAUSED = 2
|
||||||
export class SelfPrompter {
|
export class SelfPrompter {
|
||||||
constructor(agent) {
|
constructor(agent) {
|
||||||
this.agent = agent;
|
this.agent = agent;
|
||||||
this.on = false;
|
this.state = STOPPED;
|
||||||
this.loop_active = false;
|
this.loop_active = false;
|
||||||
this.interrupt = false;
|
this.interrupt = false;
|
||||||
this.prompt = '';
|
this.prompt = '';
|
||||||
|
@ -16,16 +19,38 @@ export class SelfPrompter {
|
||||||
return 'No prompt specified. Ignoring request.';
|
return 'No prompt specified. Ignoring request.';
|
||||||
prompt = this.prompt;
|
prompt = this.prompt;
|
||||||
}
|
}
|
||||||
if (this.on) {
|
this.state = ACTIVE;
|
||||||
this.prompt = prompt;
|
|
||||||
}
|
|
||||||
this.on = true;
|
|
||||||
this.prompt = prompt;
|
this.prompt = prompt;
|
||||||
this.startLoop();
|
this.startLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
setPrompt(prompt) {
|
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;
|
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() {
|
async startLoop() {
|
||||||
|
@ -47,7 +72,7 @@ export class SelfPrompter {
|
||||||
let out = `Agent did not use command in the last ${MAX_NO_COMMAND} auto-prompts. Stopping auto-prompting.`;
|
let out = `Agent did not use command in the last ${MAX_NO_COMMAND} auto-prompts. Stopping auto-prompting.`;
|
||||||
this.agent.openChat(out);
|
this.agent.openChat(out);
|
||||||
console.warn(out);
|
console.warn(out);
|
||||||
this.on = false;
|
this.state = STOPPED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +88,7 @@ export class SelfPrompter {
|
||||||
|
|
||||||
update(delta) {
|
update(delta) {
|
||||||
// automatically restarts loop
|
// automatically restarts loop
|
||||||
if (this.on && !this.loop_active && !this.interrupt) {
|
if (this.state === ACTIVE && !this.loop_active && !this.interrupt) {
|
||||||
if (this.agent.isIdle())
|
if (this.agent.isIdle())
|
||||||
this.idle_time += delta;
|
this.idle_time += delta;
|
||||||
else
|
else
|
||||||
|
@ -96,12 +121,17 @@ export class SelfPrompter {
|
||||||
this.interrupt = true;
|
this.interrupt = true;
|
||||||
if (stop_action)
|
if (stop_action)
|
||||||
await this.agent.actions.stop();
|
await this.agent.actions.stop();
|
||||||
await this.stopLoop();
|
this.stopLoop();
|
||||||
this.on = false;
|
this.state = STOPPED;
|
||||||
|
}
|
||||||
|
|
||||||
|
async pause() {
|
||||||
|
this.interrupt = true;
|
||||||
|
this.state = PAUSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldInterrupt(is_self_prompt) { // to be called from handleMessage
|
shouldInterrupt(is_self_prompt) { // to be called from handleMessage
|
||||||
return is_self_prompt && this.on && this.interrupt;
|
return is_self_prompt && this.state === ACTIVE && this.interrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleUserPromptedCmd(is_self_prompt, is_action) {
|
handleUserPromptedCmd(is_self_prompt, is_action) {
|
||||||
|
|
|
@ -82,7 +82,7 @@ export class Task {
|
||||||
if (this.validator && this.validator.validate())
|
if (this.validator && this.validator.validate())
|
||||||
return {"message": 'Task successful', "code": 2};
|
return {"message": 'Task successful', "code": 2};
|
||||||
// TODO check for other terminal conditions
|
// TODO check for other terminal conditions
|
||||||
// if (this.task.goal && !this.self_prompter.on)
|
// if (this.task.goal && !this.self_prompter.isActive())
|
||||||
// return {"message": 'Agent ended goal', "code": 3};
|
// return {"message": 'Agent ended goal', "code": 3};
|
||||||
// if (this.task.conversation && !inConversation())
|
// if (this.task.conversation && !inConversation())
|
||||||
// return {"message": 'Agent ended conversation', "code": 3};
|
// return {"message": 'Agent ended conversation', "code": 3};
|
||||||
|
|
|
@ -257,7 +257,8 @@ export class Prompter {
|
||||||
if (prompt.includes('$CONVO'))
|
if (prompt.includes('$CONVO'))
|
||||||
prompt = prompt.replaceAll('$CONVO', 'Recent conversation:\n' + stringifyTurns(messages));
|
prompt = prompt.replaceAll('$CONVO', 'Recent conversation:\n' + stringifyTurns(messages));
|
||||||
if (prompt.includes('$SELF_PROMPT')) {
|
if (prompt.includes('$SELF_PROMPT')) {
|
||||||
let self_prompt = this.agent.self_prompter.on ? `YOUR CURRENT ASSIGNED GOAL: "${this.agent.self_prompter.prompt}"\n` : '';
|
// if active or paused, show the current goal
|
||||||
|
let self_prompt = !this.agent.self_prompter.isStopped() ? `YOUR CURRENT ASSIGNED GOAL: "${this.agent.self_prompter.prompt}"\n` : '';
|
||||||
prompt = prompt.replaceAll('$SELF_PROMPT', self_prompt);
|
prompt = prompt.replaceAll('$SELF_PROMPT', self_prompt);
|
||||||
}
|
}
|
||||||
if (prompt.includes('$LAST_GOALS')) {
|
if (prompt.includes('$LAST_GOALS')) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue