Merge pull request #329 from kolbytn/isolate-modes

remove external obj references from bot.modes
This commit is contained in:
Max Robinson 2024-11-18 23:40:48 -06:00 committed by GitHub
commit 29c6654dbb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -23,7 +23,7 @@ async function say(agent, message) {
// the order of this list matters! first modes will be prioritized // the order of this list matters! first modes will be prioritized
// while update functions are async, they should *not* be awaited longer than ~100ms as it will block the update loop // while update functions are async, they should *not* be awaited longer than ~100ms as it will block the update loop
// to perform longer actions, use the execute function which won't block the update loop // to perform longer actions, use the execute function which won't block the update loop
const modes = [ const modes_list = [
{ {
name: 'self_preservation', name: 'self_preservation',
description: 'Respond to drowning, burning, and damage at low health. Interrupts all actions.', description: 'Respond to drowning, burning, and damage at low health. Interrupts all actions.',
@ -267,39 +267,45 @@ async function execute(mode, agent, func, timeout=-1) {
console.log(`Mode ${mode.name} finished executing, code_return: ${code_return.message}`); console.log(`Mode ${mode.name} finished executing, code_return: ${code_return.message}`);
} }
class ModeController { let _agent = null;
constructor(agent) { const modes_map = {};
this.agent = agent; for (let mode of modes_list) {
this.modes_list = modes; modes_map[mode.name] = mode;
this.modes_map = {};
this.behavior_log = '';
for (let mode of this.modes_list) {
this.modes_map[mode.name] = mode;
} }
class ModeController {
/*
SECURITY WARNING:
ModesController must be 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 can be used to expose sensitive information by malicious human prompters.
*/
constructor() {
this.behavior_log = '';
} }
exists(mode_name) { exists(mode_name) {
return this.modes_map[mode_name] != null; return modes_map[mode_name] != null;
} }
setOn(mode_name, on) { setOn(mode_name, on) {
this.modes_map[mode_name].on = on; modes_map[mode_name].on = on;
} }
isOn(mode_name) { isOn(mode_name) {
return this.modes_map[mode_name].on; return modes_map[mode_name].on;
} }
pause(mode_name) { pause(mode_name) {
this.modes_map[mode_name].paused = true; modes_map[mode_name].paused = true;
} }
unpause(mode_name) { unpause(mode_name) {
this.modes_map[mode_name].paused = false; modes_map[mode_name].paused = false;
} }
unPauseAll() { unPauseAll() {
for (let mode of this.modes_list) { for (let mode of modes_list) {
if (mode.paused) console.log(`Unpausing mode ${mode.name}`); if (mode.paused) console.log(`Unpausing mode ${mode.name}`);
mode.paused = false; mode.paused = false;
} }
@ -307,7 +313,7 @@ class ModeController {
getMiniDocs() { // no descriptions getMiniDocs() { // no descriptions
let res = 'Agent Modes:'; let res = 'Agent Modes:';
for (let mode of this.modes_list) { for (let mode of modes_list) {
let on = mode.on ? 'ON' : 'OFF'; let on = mode.on ? 'ON' : 'OFF';
res += `\n- ${mode.name}(${on})`; res += `\n- ${mode.name}(${on})`;
} }
@ -316,7 +322,7 @@ class ModeController {
getDocs() { getDocs() {
let res = 'Agent Modes:'; let res = 'Agent Modes:';
for (let mode of this.modes_list) { for (let mode of modes_list) {
let on = mode.on ? 'ON' : 'OFF'; let on = mode.on ? 'ON' : 'OFF';
res += `\n- ${mode.name}(${on}): ${mode.description}`; res += `\n- ${mode.name}(${on}): ${mode.description}`;
} }
@ -324,13 +330,13 @@ class ModeController {
} }
async update() { async update() {
if (this.agent.isIdle()) { if (_agent.isIdle()) {
this.unPauseAll(); this.unPauseAll();
} }
for (let mode of this.modes_list) { for (let mode of modes_list) {
let interruptible = mode.interrupts.some(i => i === 'all') || mode.interrupts.some(i => i === this.agent.actions.currentActionLabel); let interruptible = mode.interrupts.some(i => i === 'all') || mode.interrupts.some(i => i === _agent.actions.currentActionLabel);
if (mode.on && !mode.paused && !mode.active && (this.agent.isIdle() || interruptible)) { if (mode.on && !mode.paused && !mode.active && (_agent.isIdle() || interruptible)) {
await mode.update(this.agent); await mode.update(_agent);
} }
if (mode.active) break; if (mode.active) break;
} }
@ -344,14 +350,14 @@ class ModeController {
getJson() { getJson() {
let res = {}; let res = {};
for (let mode of this.modes_list) { for (let mode of modes_list) {
res[mode.name] = mode.on; res[mode.name] = mode.on;
} }
return res; return res;
} }
loadJson(json) { loadJson(json) {
for (let mode of this.modes_list) { for (let mode of modes_list) {
if (json[mode.name] != undefined) { if (json[mode.name] != undefined) {
mode.on = json[mode.name]; mode.on = json[mode.name];
} }
@ -360,10 +366,11 @@ class ModeController {
} }
export function initModes(agent) { export function initModes(agent) {
_agent = agent;
// the mode controller is added to the bot object so it is accessible from anywhere the bot is used // the mode controller is added to the bot object so it is accessible from anywhere the bot is used
agent.bot.modes = new ModeController(agent); agent.bot.modes = new ModeController();
let modes = agent.prompter.getInitModes(); let modes_json = agent.prompter.getInitModes();
if (modes) { if (modes_json) {
agent.bot.modes.loadJson(modes); agent.bot.modes.loadJson(modes_json);
} }
} }