mirror of
https://github.com/kolbytn/mindcraft.git
synced 2025-07-01 06:05:19 +02:00
feat: more safely evaluate llm generated code in a SES Compartment
This commit is contained in:
parent
e8e3cb7116
commit
7a253c9108
4 changed files with 55 additions and 14 deletions
|
@ -1,10 +1,6 @@
|
||||||
import * as skills from '../../../src/agent/library/skills.js';
|
(async (bot) => {
|
||||||
import * as world from '../../../src/agent/library/world.js';
|
|
||||||
import Vec3 from 'vec3';
|
|
||||||
|
|
||||||
const log = skills.log;
|
/* CODE HERE */
|
||||||
|
log(bot, 'Code finished.');
|
||||||
|
|
||||||
export async function main(bot) {
|
})
|
||||||
/* CODE HERE */
|
|
||||||
log(bot, 'Code finished.');
|
|
||||||
}
|
|
|
@ -18,6 +18,7 @@
|
||||||
"prismarine-item": "^1.14.0",
|
"prismarine-item": "^1.14.0",
|
||||||
"prismarine-viewer": "^1.28.0",
|
"prismarine-viewer": "^1.28.0",
|
||||||
"replicate": "^0.29.4",
|
"replicate": "^0.29.4",
|
||||||
|
"ses": "^1.9.1",
|
||||||
"vec3": "^0.1.10",
|
"vec3": "^0.1.10",
|
||||||
"yargs": "^17.7.2"
|
"yargs": "^17.7.2"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
import { writeFile, readFile, mkdirSync } from 'fs';
|
import { writeFile, readFile, mkdirSync } from 'fs';
|
||||||
import { checkSafe } from '../utils/safety.js';
|
import { checkSafe } from '../utils/safety.js';
|
||||||
import settings from '../../settings.js';
|
import settings from '../../settings.js';
|
||||||
|
import { makeCompartment } from './library/lockdown.js';
|
||||||
|
import * as skills from './library/skills.js';
|
||||||
|
import * as world from './library/world.js';
|
||||||
|
import { Vec3 } from 'vec3';
|
||||||
|
|
||||||
export class Coder {
|
export class Coder {
|
||||||
constructor(agent) {
|
constructor(agent) {
|
||||||
|
@ -21,7 +25,7 @@ export class Coder {
|
||||||
mkdirSync('.' + this.fp, { recursive: true });
|
mkdirSync('.' + this.fp, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
// write custom code to file and import it
|
// write custom code to file and prepare for evaluation
|
||||||
async stageCode(code) {
|
async stageCode(code) {
|
||||||
code = this.sanitizeCode(code);
|
code = this.sanitizeCode(code);
|
||||||
let src = '';
|
let src = '';
|
||||||
|
@ -47,13 +51,24 @@ export class Coder {
|
||||||
// } commented for now, useful to keep files for debugging
|
// } commented for now, useful to keep files for debugging
|
||||||
this.file_counter++;
|
this.file_counter++;
|
||||||
|
|
||||||
let write_result = await this.writeFilePromise('.' + this.fp + filename, src)
|
let write_result = await this.writeFilePromise('.' + this.fp + filename, src);
|
||||||
|
// This is where we determine the environment the agent's code should be exposed to.
|
||||||
|
// It will only have access to these things, (in addition to basic javascript objects like Array, Object, etc.)
|
||||||
|
// Note that the code may be able to modify the exposed objects.
|
||||||
|
const compartment = makeCompartment({
|
||||||
|
skills,
|
||||||
|
log: skills.log,
|
||||||
|
world,
|
||||||
|
Vec3,
|
||||||
|
});
|
||||||
|
const mainFn = compartment.evaluate(src);
|
||||||
|
|
||||||
if (write_result) {
|
if (write_result) {
|
||||||
console.error('Error writing code execution file: ' + result);
|
console.error('Error writing code execution file: ' + result);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return await import('../..' + this.fp + filename);
|
|
||||||
|
return { main: mainFn };
|
||||||
}
|
}
|
||||||
|
|
||||||
sanitizeCode(code) {
|
sanitizeCode(code) {
|
||||||
|
@ -137,14 +152,17 @@ export class Coder {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const execution_file = await this.stageCode(code);
|
let codeStagingResult;
|
||||||
if (!execution_file) {
|
try {
|
||||||
|
codeStagingResult = await this.stageCode(code);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error staging code:', err);
|
||||||
agent_history.add('system', 'Failed to stage code, something is wrong.');
|
agent_history.add('system', 'Failed to stage code, something is wrong.');
|
||||||
return {success: false, message: null, interrupted: false, timedout: false};
|
return {success: false, message: null, interrupted: false, timedout: false};
|
||||||
}
|
}
|
||||||
|
|
||||||
code_return = await this.execute(async ()=>{
|
code_return = await this.execute(async ()=>{
|
||||||
return await execution_file.main(this.agent.bot);
|
return await codeStagingResult.main(this.agent.bot);
|
||||||
}, settings.code_timeout_mins);
|
}, settings.code_timeout_mins);
|
||||||
if (code_return.interrupted && !code_return.timedout)
|
if (code_return.interrupted && !code_return.timedout)
|
||||||
return {success: false, message: null, interrupted: true, timedout: false};
|
return {success: false, message: null, interrupted: true, timedout: false};
|
||||||
|
|
26
src/agent/library/lockdown.js
Normal file
26
src/agent/library/lockdown.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import 'ses';
|
||||||
|
|
||||||
|
// This sets up the secure environment
|
||||||
|
// We disable some of the taming to allow for more flexibility
|
||||||
|
|
||||||
|
// For configuration, see https://github.com/endojs/endo/blob/master/packages/ses/docs/lockdown.md
|
||||||
|
lockdown({
|
||||||
|
// basic devex and quality of life improvements
|
||||||
|
localeTaming: 'unsafe',
|
||||||
|
consoleTaming: 'unsafe',
|
||||||
|
errorTaming: 'unsafe',
|
||||||
|
stackFiltering: 'verbose',
|
||||||
|
// allow eval outside of created compartments
|
||||||
|
// (mineflayer dep "protodef" uses eval)
|
||||||
|
evalTaming: 'unsafeEval',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const makeCompartment = (endowments = {}) => {
|
||||||
|
return new Compartment({
|
||||||
|
// provide untamed Math, Date, etc
|
||||||
|
Math,
|
||||||
|
Date,
|
||||||
|
// standard endowments
|
||||||
|
...endowments
|
||||||
|
});
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue