refactored examples/startup

This commit is contained in:
MaxRobinsonTheGreat 2024-01-15 11:04:50 -06:00
parent 193f794f3d
commit 2f4ecfada3
7 changed files with 123 additions and 119 deletions

View file

@ -1,26 +1,31 @@
import { initBot } from '../utils/mcdata.js'; import { initBot } from '../utils/mcdata.js';
import { sendRequest } from '../utils/gpt.js'; import { sendRequest } from '../utils/gpt.js';
import { History } from './history.js'; import { History } from './history.js';
import { Examples } from './examples.js';
import { Coder } from './coder.js'; import { Coder } from './coder.js';
import { containsCommand, commandExists, executeCommand } from './commands.js'; import { containsCommand, commandExists, executeCommand } from './commands.js';
import { Events } from './events.js'; import { Events } from './events.js';
export class Agent { export class Agent {
constructor(name, profile=null, init_message=null) { async start(name, profile=null, init_message=null) {
this.name = name; this.name = name;
this.bot = initBot(name); this.examples = new Examples();
this.history = new History(this); this.history = new History(this);
this.coder = new Coder(this); this.coder = new Coder(this);
this.history.load(profile); this.history.load(profile);
await this.examples.load('./src/examples.json');
await this.coder.load();
this.bot = initBot(name);
this.events = new Events(this, this.history.events) this.events = new Events(this, this.history.events)
this.bot.on('login', async () => { this.bot.on('login', async () => {
await this.history.loadExamples();
console.log(`${this.name} logged in.`); console.log(`${this.name} logged in.`);
this.coder.clear();
const ignore_messages = [ const ignore_messages = [
"Set own game mode to", "Set own game mode to",
@ -76,7 +81,8 @@ export class Agent {
} }
for (let i=0; i<5; i++) { for (let i=0; i<5; i++) {
let res = await sendRequest(this.history.getHistory(), this.history.getSystemMessage()); let history = await this.history.getHistory(this.examples);
let res = await sendRequest(history, this.history.getSystemMessage());
this.history.add(this.name, res); this.history.add(this.name, res);
let command_name = containsCommand(res); let command_name = containsCommand(res);
@ -85,6 +91,7 @@ export class Agent {
console.log('Command message:', res); console.log('Command message:', res);
if (!commandExists(command_name)) { if (!commandExists(command_name)) {
this.history.add('system', `Command ${command_name} does not exist. Use !newAction to perform custom actions.`); this.history.add('system', `Command ${command_name} does not exist. Use !newAction to perform custom actions.`);
console.log('Agent hallucinated command:', command_name)
continue; continue;
} }

View file

@ -1,7 +1,7 @@
import { writeFile, readFile, mkdirSync } from 'fs'; import { writeFile, readFile, mkdirSync } from 'fs';
import { sendRequest, embed, cosineSimilarity } from '../utils/gpt.js'; import { sendRequest } from '../utils/gpt.js';
import { stringifyTurns } from '../utils/text.js';
import { getSkillDocs } from './skill-library.js'; import { getSkillDocs } from './skill-library.js';
import { Examples } from './examples.js';
export class Coder { export class Coder {
@ -11,13 +11,14 @@ export class Coder {
this.current_code = ''; this.current_code = '';
this.file_counter = 0; this.file_counter = 0;
this.fp = '/bots/'+agent.name+'/action-code/'; this.fp = '/bots/'+agent.name+'/action-code/';
this.agent.bot.interrupt_code = false;
this.executing = false; this.executing = false;
this.agent.bot.output = '';
this.code_template = ''; this.code_template = '';
this.timedout = false; this.timedout = false;
this.fewshot = 3; }
this.examples = [];
async load() {
this.examples = new Examples();
await this.examples.load('./src/examples_coder.json');
readFile('./bots/template.js', 'utf8', (err, data) => { readFile('./bots/template.js', 'utf8', (err, data) => {
if (err) throw err; if (err) throw err;
@ -62,7 +63,7 @@ export class Coder {
system_message += "\n\nExamples:\nUser zZZn98: come here \nAssistant: I am going to navigate to zZZn98. ```\nawait skills.goToPlayer(bot, 'zZZn98');```\nSystem: Code execution finished successfully.\nAssistant: Done."; system_message += "\n\nExamples:\nUser zZZn98: come here \nAssistant: I am going to navigate to zZZn98. ```\nawait skills.goToPlayer(bot, 'zZZn98');```\nSystem: Code execution finished successfully.\nAssistant: Done.";
let messages = agent_history.getHistory(false); let messages = await agent_history.getHistory(this.examples);
let code_return = null; let code_return = null;
let failures = 0; let failures = 0;

View file

@ -18,7 +18,7 @@ const argRegex = /(?:"[^"]*"|'[^']*'|[^,])+/g;
export function containsCommand(message) { export function containsCommand(message) {
const commandMatch = message.match(commandRegex); const commandMatch = message.match(commandRegex);
if (commandMatch) if (commandMatch)
return commandName; return "!" + commandMatch[1];
return null; return null;
} }

64
src/agent/examples.js Normal file
View file

@ -0,0 +1,64 @@
import { readFileSync } from 'fs';
import { embed, cosineSimilarity } from '../utils/gpt.js';
import { stringifyTurns } from '../utils/text.js';
export class Examples {
constructor(select_num=3) {
this.examples = [];
this.select_num = select_num;
}
async load(path) {
let examples = [];
try {
const data = readFileSync(path, 'utf8');
examples = JSON.parse(data);
} catch (err) {
console.error('Examples failed to load!', err);
}
this.examples = [];
for (let example of examples) {
let messages = '';
for (let turn of example) {
if (turn.role != 'assistant')
messages += turn.content.substring(turn.content.indexOf(':')+1).trim() + '\n';
}
messages = messages.trim();
const embedding = await embed(messages);
this.examples.push({'embedding': embedding, 'turns': example});
}
}
async getRelevant(turns) {
let messages = '';
for (let turn of turns) {
if (turn.role != 'assistant')
messages += turn.content.substring(turn.content.indexOf(':')+1).trim() + '\n';
}
messages = messages.trim();
const embedding = await embed(messages);
this.examples.sort((a, b) => {
return cosineSimilarity(b.embedding, embedding) - cosineSimilarity(a.embedding, embedding);
});
let selected = this.examples.slice(0, this.select_num);
return JSON.parse(JSON.stringify(selected)); // deep copy
}
async createExampleMessage(turns) {
let selected_examples = await this.getRelevant(turns);
console.log('selected examples:');
for (let example of selected_examples) {
console.log(example.turns[0])
}
let msg = 'Here are some examples of how to respond:\n';
for (let i=0; i<selected_examples.length; i++) {
let example = selected_examples[i];
msg += `Example ${i+1}:\n${stringifyTurns(example.turns)}\n\n`;
}
return [{'role': 'system', 'content': msg}];
}
}

View file

@ -1,6 +1,6 @@
import { writeFileSync, readFileSync, mkdirSync } from 'fs'; import { writeFileSync, readFileSync, mkdirSync } from 'fs';
import { getCommandDocs } from './commands.js'; import { getCommandDocs } from './commands.js';
import { sendRequest, embed, cosineSimilarity } from '../utils/gpt.js'; import { sendRequest } from '../utils/gpt.js';
import { stringifyTurns } from '../utils/text.js'; import { stringifyTurns } from '../utils/text.js';
@ -19,21 +19,15 @@ export class History {
// Variables for controlling the agent's memory and knowledge // Variables for controlling the agent's memory and knowledge
this.max_messages = 20; this.max_messages = 20;
this.fewshot = 5;
this.examples = [];
this.selected_examples = [];
} }
getHistory(include_examples=true) { async getHistory(examples=null) { // expects an Examples object
// return deep copy of history
let turns = JSON.parse(JSON.stringify(this.turns)); let turns = JSON.parse(JSON.stringify(this.turns));
if (include_examples && this.selected_examples.length > 0) { if (examples) {
let example_messages = 'Here are some examples of how to respond:\n'; let examples_msg = await examples.createExampleMessage(turns);
for (let example of this.selected_examples) { turns = examples_msg.concat(turns);
example_messages += 'Example:\n' + stringifyTurns(example.turns) + '\n';
}
return [{'role': 'system', 'content': example_messages}].concat(turns);
} }
return turns; return turns;
} }
@ -69,47 +63,6 @@ export class History {
this.memory = await sendRequest(memory_turns, this.getSystemMessage()); this.memory = await sendRequest(memory_turns, this.getSystemMessage());
} }
async loadExamples() {
let examples = [];
try {
const data = readFileSync('./src/examples.json', 'utf8');
examples = JSON.parse(data);
} catch (err) {
console.log('No history examples found.');
}
this.examples = [];
for (let example of examples) {
let messages = '';
for (let turn of example) {
if (turn.role != 'assistant')
messages += turn.content.substring(turn.content.indexOf(':')+1).trim() + '\n';
}
messages = messages.trim();
const embedding = await embed(messages);
this.examples.push({'embedding': embedding, 'turns': example});
}
await this.setExamples();
}
async setExamples() {
let messages = '';
for (let turn of this.turns) {
if (turn.role != 'assistant')
messages += turn.content.substring(turn.content.indexOf(':')+1).trim() + '\n';
}
messages = messages.trim();
const embedding = await embed(messages);
this.examples.sort((a, b) => {
return cosineSimilarity(a.embedding, embedding) - cosineSimilarity(b.embedding, embedding);
});
this.selected_examples = this.examples.slice(-this.fewshot);
for (let example of this.selected_examples) {
console.log('selected example: ', example.turns[0].content);
}
}
async add(name, content) { async add(name, content) {
let role = 'assistant'; let role = 'assistant';
if (name === 'system') { if (name === 'system') {
@ -129,9 +82,6 @@ export class History {
to_summarize.push(this.turns.shift()); to_summarize.push(this.turns.shift());
await this.storeMemories(to_summarize); await this.storeMemories(to_summarize);
} }
if (role != 'assistant')
await this.setExamples();
} }
save() { save() {

View file

@ -1,52 +1,34 @@
[ [
{ [
"conversation": [ {"role": "user", "content": "greg: Collect 10 wood"},
{"role": "user", "content": "greg: Collect 10 wood"}, {"role": "assistant", "content": "```await skills.collectBlock(bot, 'oak_log', 10);\n```"},
{"role": "assistant", "content": "Let me see what's nearby... !blocks"}, {"role": "system", "content": "Successfully collected 9 wood."},
{"role": "system", "content": "NEARBY_BLOCKS\n- oak_log\n- dirt\n- cobblestone"} {"role": "assistant", "content": "I collected 9 oak logs, what next?"}
], ],
"coder": [ [
{"role": "assistant", "content": "I see some oak logs, dirt, and cobblestone. I'll collect oak logs.\n```\n// I am going to collect 10 oak_log.\nawait skills.collectBlock(bot, 'oak_log', 10);\n```"}, {"role": "user", "content": "bobby: Craft a plank"},
{"role": "user", "content": "Code execution finished successfully."}, {"role": "assistant", "content": "```\nawait skills.craftRecipe(bot, 'spruce_planks');\n```"},
{"role": "assistant", "content": "DONE"} {"role": "system", "content": "Successfully crafted 4 spruce_planks."},
] {"role": "assistant", "content": "I crafted 4 spruce planks!"}
}, ],
[
{ {"role": "user", "content": "zZZn98: come here"},
"conversation": [ {"role": "assistant", "content": "```await skills.goToPlayer(bot, 'zZZn98');\n```"},
{"role": "user", "content": "bobby: Craft a plank"}, {"role": "system", "content": "Code execution finished successfully."},
{"role": "assistant", "content": "Okay! !craftable"}, {"role": "assistant", "content": "Here!"}
{"role": "system", "content": "CRAFTABLE_ITEMS\n- spruce_planks\n- spruce_wood\n- ladder"} ],
], [
"coder": [ {"role": "user", "content": "maya: go to the nearest oak log"},
{"role": "assistant", "content": "```\n// I am going to craft a spruce_planks.\nawait skills.craftRecipe(bot, 'spruce_planks');\n```"}, {"role": "assistant", "content": "```await skills.goToPosition(bot, nearestOakLog.x, nearestOakLog.y, nearestOakLog.z);\n```"},
{"role": "user", "content": "Code execution finished successfully."}, {"role": "system", "content": "Code output:\n!!Code threw exception!! Error: ReferenceError: nearestOakLog is not defined\n Write code to fix the problem and try again."},
{"role": "assistant", "content": "DONE"} {"role": "assistant", "content": "Apologies, I made an error. Let me try that again.```\n// I am navigating to the nearest oak log.\nlet position = world.getNearestBlock(bot, 'oak_log', 20);\nawait skills.goToPosition(bot, position.x, position.y, position.z);\n```"},
] {"role": "system", "content": "Arrived at location."},
}, {"role": "assistant", "content": "I found an oak log and I am now standing next to it. What next?"}
],
{ [
"conversation": [ {"role": "user", "content": "234jeb: build a little tower"},
{"role": "user", "content": "zZZn98: come here"} {"role": "assistant", "content": "```let pos = bot.entity.position;\nfor (let i = 0; i < 5; i++) {\n await skills.placeBlock(bot, 'dirt', pos.x, pos.y + i, pos.z);\n}\n```"},
], {"role": "system", "content": "Successfully placed 5 dirt."},
"coder": [ {"role": "assistant", "content": "I built a little tower!"}
{"role": "assistant", "content": "```\n// I am going to navigate to zZZn98.\nawait skills.goToPlayer(bot, 'zZZn98');\n```"}, ]
{"role": "user", "content": "Code execution finished successfully."},
{"role": "assistant", "content": "DONE"}
]
},
{
"conversation": [
{"role": "user", "content": "maya: go to the nearest oak log"}
],
"coder": [
{"role": "assistant", "content": "```\n// I am navigating to the nearest oak log.\nawait skills.goToPosition(bot, nearestOakLog.x, nearestOakLog.y, nearestOakLog.z);\n```"},
{"role": "system", "content": "Code output:\n!!Code threw exception!! Error: ReferenceError: nearestOakLog is not defined\n Write code to fix the problem and try again."},
{"role": "assistant", "content": "Apologies, I made an error. Let me try that again.```\n// I am navigating to the nearest oak log.\nlet position = world.getNearestBlock(bot, 'oak_log', 20);\nawait skills.goToPosition(bot, position.x, position.y, position.z);\n```"},
{"role": "user", "content": "Code execution finished successfully."},
{"role": "assistant", "content": "DONE"}
]
}
] ]

View file

@ -20,4 +20,4 @@ const argv = yargs(args)
}).argv }).argv
const name = args[0]; const name = args[0];
new Agent(name, argv.profile, argv.init_message); new Agent().start(name, argv.profile, argv.init_message);