mirror of
https://github.com/kolbytn/mindcraft.git
synced 2025-03-28 14:56:24 +01:00
retrieved fewshot examples
This commit is contained in:
parent
3e61d45ace
commit
0ddad8ab65
5 changed files with 172 additions and 62 deletions
16
agent.js
16
agent.js
|
@ -10,23 +10,25 @@ export class Agent {
|
|||
constructor(name, save_path) {
|
||||
this.name = name;
|
||||
this.bot = initBot(name);
|
||||
this.history = new History(this);
|
||||
this.history = new History(this, save_path);
|
||||
this.coder = new Coder(this);
|
||||
if (save_path != null)
|
||||
this.history.load(save_path);
|
||||
|
||||
this.history.load();
|
||||
|
||||
this.bot.on('login', () => {
|
||||
this.bot.chat('Hello world! I am ' + this.name);
|
||||
console.log(`${this.name} logged in.`);
|
||||
});
|
||||
}
|
||||
|
||||
async start() {
|
||||
await this.history.loadExamples();
|
||||
|
||||
this.bot.on('chat', (username, message) => {
|
||||
if (username === this.name) return;
|
||||
console.log('received message from', username, ':', message);
|
||||
|
||||
this.respond(username, message);
|
||||
if (save_path != null)
|
||||
this.history.save(save_path);
|
||||
this.history.save();
|
||||
});
|
||||
|
||||
this.bot.on('finished_executing', () => {
|
||||
|
@ -39,7 +41,7 @@ export class Agent {
|
|||
}
|
||||
|
||||
async respond(username, message) {
|
||||
this.history.add(username, message);
|
||||
await this.history.add(username, message);
|
||||
for (let i=0; i<5; i++) {
|
||||
let res = await sendRequest(this.history.getHistory(), this.history.getSystemMessage());
|
||||
this.history.add(this.name, res);
|
||||
|
|
3
main.js
3
main.js
|
@ -1,3 +1,4 @@
|
|||
import { Agent } from './agent.js';
|
||||
|
||||
new Agent('andy', 'bots/andy.json');
|
||||
let agent = new Agent('andy', 'bots/andy.json');
|
||||
agent.start();
|
||||
|
|
49
utils/examples.json
Normal file
49
utils/examples.json
Normal file
|
@ -0,0 +1,49 @@
|
|||
[
|
||||
[
|
||||
{"role": "user", "content": "miner_32: Hey! What are you up to?"},
|
||||
{"role": "assistant", "content": "Nothing much miner_32, what do you need?"}
|
||||
],
|
||||
|
||||
[
|
||||
{"role": "user", "content": "grombo_Xx: What do you see?"},
|
||||
{"role": "assistant", "content": "Let me see... !blocks"},
|
||||
{"role": "system", "content": "NEARBY_BLOCKS\n- oak_log\n- dirt\n- cobblestone"},
|
||||
{"role": "assistant", "content": "I see some oak logs, dirt, and cobblestone."}
|
||||
],
|
||||
|
||||
[
|
||||
{"role": "user", "content": "zZZn98: come here"},
|
||||
{"role": "assistant", "content": "```\n// I am going to navigate to zZZn98.\nawait skills.goToPlayer(bot, 'zZZn98');\n```"},
|
||||
{"role": "system", "content": "Code execution finished successfully."},
|
||||
{"role": "assistant", "content": "Here!"}
|
||||
],
|
||||
|
||||
[
|
||||
{"role": "user", "content": "hanky: collect some sand for me please"},
|
||||
{"role": "assistant", "content": "Collecting sand...\n```\n// I am going to collect 3 sand and give to hanky.\nawait skills.collectBlock(bot, 'sand');\nawait skills.giveToPlayer(bot, 'sand', 'hanky');\n```"},
|
||||
{"role": "system", "content": "Code Output:\nYou have reached player hanky.\nCode execution finished successfully."},
|
||||
{"role": "assistant", "content": "Here!"}
|
||||
],
|
||||
|
||||
[
|
||||
{"role": "user", "content": "sarah_O.o: can you fly up in the air?"},
|
||||
{"role": "assistant", "content": "I can't do that."}
|
||||
],
|
||||
|
||||
[
|
||||
{"role": "user", "content": "joe: Follow me!"},
|
||||
{"role": "assistant", "content": "Sure!\n```\n// I am going to follow joe.\nawait skills.followPlayer(bot, 'joe');\n```"}
|
||||
],
|
||||
|
||||
[
|
||||
{"role": "user", "content": "hanky: kill that zombie!"},
|
||||
{"role": "assistant", "content": "I'm attacking!\n```\n//I'm going to attack the nearest zombie.\nawait skills.attackMob(bot, 'zombie');\n```"},
|
||||
{"role": "system", "content": "Code Output:\nNo zombie nearby\nCode execution failed!"},
|
||||
{"role": "assistant", "content": "I could not find a zombie nearby."}
|
||||
],
|
||||
|
||||
[
|
||||
{"role": "user", "content": "billybob: stop"},
|
||||
{"role": "assistant", "content": "```\n// I am going to write empty code to stop whatever I am doing\n```"}
|
||||
]
|
||||
]
|
10
utils/gpt.js
10
utils/gpt.js
|
@ -39,3 +39,13 @@ export async function sendRequest(turns, systemMessage, stop_seq='***') {
|
|||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
export async function embed(text) {
|
||||
const embedding = await openai.embeddings.create({
|
||||
model: "text-embedding-ada-002",
|
||||
input: text,
|
||||
encoding_format: "float",
|
||||
});
|
||||
return embedding.data[0].embedding;
|
||||
}
|
||||
|
|
156
utils/history.js
156
utils/history.js
|
@ -1,53 +1,24 @@
|
|||
import { writeFileSync, readFileSync, mkdirSync } from 'fs';
|
||||
import { getQueryDocs } from './queries.js';
|
||||
import { getSkillDocs } from './skill_library.js';
|
||||
import { sendRequest } from './gpt.js';
|
||||
import { sendRequest, embed } from './gpt.js';
|
||||
|
||||
|
||||
let history_examples = [
|
||||
{'role': 'user', 'content': 'miner_32: Hey! What are you up to?'},
|
||||
{'role': 'assistant', 'content': 'Nothing much miner_32, what do you need?'},
|
||||
|
||||
{'role': 'user', 'content': 'grombo_Xx: What do you see?'},
|
||||
{'role': 'assistant', 'content': 'Let me see... !blocks'},
|
||||
{'role': 'system', 'content': 'NEARBY_BLOCKS\n- oak_log\n- dirt\n- cobblestone'},
|
||||
{'role': 'assistant', 'content': 'I see some oak logs, dirt, and cobblestone.'},
|
||||
|
||||
{'role': 'user', 'content': 'zZZn98: come here'},
|
||||
{'role': 'assistant', 'content': '```// I am going to navigate to zZZn98.\nawait skills.goToPlayer(bot, "zZZn98");```'},
|
||||
{'role': 'system', 'content': 'Code execution finished successfully.'},
|
||||
{'role': 'assistant', 'content': 'Here!'},
|
||||
|
||||
{'role': 'user', 'content': 'hanky: collect some sand for me please'},
|
||||
{'role': 'assistant', 'content': 'Collecting sand...```// I am going to collect 3 sand and give to hanky.\n\
|
||||
await skills.collectBlock(bot, "sand");\nawait skills.giveToPlayer(bot, "sand", "hanky");```'},
|
||||
{'role': 'system', 'content': 'Code Output:\nYou have reached player hanky.\nCode execution finished successfully.'},
|
||||
{'role': 'assistant', 'content': 'Here!'},
|
||||
|
||||
{'role': 'user', 'content': 'sarah_O.o: can you fly up in the air?'},
|
||||
{'role': 'assistant', 'content': "I can't do that."},
|
||||
|
||||
{'role': 'user', 'content': 'hanky: kill that zombie!'},
|
||||
{'role': 'assistant', 'content': "I'm attacking! ```//I'm going to attack the nearest zombie.\n\
|
||||
await skills.attackMob(bot, 'zombie');```"},
|
||||
{'role': 'system', 'content': 'Code Output:\nNo zombie nearby\nCode execution failed!'},
|
||||
{'role': 'assistant', 'content': 'I could not find a zombie nearby.'},
|
||||
|
||||
{'role': 'user', 'content': 'billybob: stop'},
|
||||
{'role': 'assistant', 'content': '```// I am going to write empty code to stop whatever I am doing\n```'}
|
||||
]
|
||||
|
||||
export class History {
|
||||
constructor(agent) {
|
||||
constructor(agent, save_path) {
|
||||
this.name = agent.name;
|
||||
this.turns = history_examples;
|
||||
this.save_path = save_path;
|
||||
this.turns = [];
|
||||
|
||||
// These define an agent's long term memory
|
||||
this.bio = '';
|
||||
this.memory = '';
|
||||
|
||||
// Variables for controlling how often we summarize the agent's memory and knowledge
|
||||
// Variables for controlling the agent's memory and knowledge
|
||||
this.max_messages = 20;
|
||||
this.fewshot = 5;
|
||||
this.examples = [];
|
||||
this.selected_examples = [];
|
||||
}
|
||||
|
||||
getHistory() {
|
||||
|
@ -59,15 +30,34 @@ export class History {
|
|||
Act human-like as if you were a typical Minecraft player, rather than an AI. Be brief in your responses, omit needless words, and do not give instructions unless asked.`;
|
||||
system_message += getQueryDocs();
|
||||
system_message += getSkillDocs();
|
||||
if (this.bio != '') {
|
||||
system_message = system_message + '\n\nBio:\n' + this.bio;
|
||||
}
|
||||
if (this.memory != '') {
|
||||
system_message = system_message + '\n\nMemory:\n' + this.memory;
|
||||
if (this.bio != '')
|
||||
system_message += '\n\nBio:\n' + this.bio;
|
||||
if (this.memory != '')
|
||||
system_message += '\n\nMemory:\n' + this.memory;
|
||||
if (this.selected_examples.length > 0) {
|
||||
for (let i = 0; i < this.selected_examples.length; i++) {
|
||||
system_message += '\n\nExample ' + (i+1) + ':\n\n';
|
||||
system_message += this.stringifyTurns(this.selected_examples[i].turns);
|
||||
}
|
||||
}
|
||||
return system_message;
|
||||
}
|
||||
|
||||
stringifyTurns(turns) {
|
||||
let res = '';
|
||||
for (let turn of turns) {
|
||||
if (turn.role === 'assistant') {
|
||||
res += `\n\nYour output:\n${turn.content}`;
|
||||
} else if (turn.role === 'system') {
|
||||
res += `\n\nSystem output: ${turn.content}`;
|
||||
} else {
|
||||
res += `\n\nUser input: ${turn.content}`;
|
||||
|
||||
}
|
||||
}
|
||||
return res.trim();
|
||||
}
|
||||
|
||||
async storeMemories(turns) {
|
||||
let memory_prompt = 'Update your "Memory" with the following conversation. Your "Memory" is for storing information that will help you improve as a Minecraft bot. Include details about your interactions with other players that you may need to remember for later. Also include things that you have learned through player feedback or by executing code. Do not include information found in your Docs or that you got right on the first try.';
|
||||
if (this.memory != '') {
|
||||
|
@ -77,17 +67,64 @@ export class History {
|
|||
memory_prompt += '- When the player... output...\n';
|
||||
memory_prompt += '- I learned that player [name]...\n';
|
||||
|
||||
for (let turn of turns) {
|
||||
if (turn.role === 'assistant') {
|
||||
memory_prompt += `\n\nYou: ${turn.content}`;
|
||||
} else {
|
||||
memory_prompt += `\n\n${turn.content}`;
|
||||
}
|
||||
}
|
||||
memory_prompt += this.stringifyTurns(turns);
|
||||
let memory_turns = [{'role': 'user', 'content': memory_prompt}]
|
||||
this.memory = await sendRequest(memory_turns, this.getSystemMessage());
|
||||
}
|
||||
|
||||
cosineSimilarity(a, b) {
|
||||
let dotProduct = 0;
|
||||
let magnitudeA = 0;
|
||||
let magnitudeB = 0;
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
dotProduct += a[i] * b[i]; // calculate dot product
|
||||
magnitudeA += Math.pow(a[i], 2); // calculate magnitude of a
|
||||
magnitudeB += Math.pow(b[i], 2); // calculate magnitude of b
|
||||
}
|
||||
magnitudeA = Math.sqrt(magnitudeA);
|
||||
magnitudeB = Math.sqrt(magnitudeB);
|
||||
return dotProduct / (magnitudeA * magnitudeB); // calculate cosine similarity
|
||||
}
|
||||
|
||||
async loadExamples() {
|
||||
let examples = [];
|
||||
try {
|
||||
const data = readFileSync('utils/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 == 'user')
|
||||
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 setExamples() {
|
||||
let messages = '';
|
||||
for (let turn of this.turns) {
|
||||
if (turn.role == 'user')
|
||||
messages += turn.content.substring(turn.content.indexOf(':')+1).trim() + '\n';
|
||||
}
|
||||
messages = messages.trim();
|
||||
const embedding = await embed(messages);
|
||||
this.examples.sort((a, b) => {
|
||||
return this.cosineSimilarity(a.embedding, embedding) - this.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) {
|
||||
let role = 'assistant';
|
||||
if (name === 'system') {
|
||||
|
@ -106,13 +143,23 @@ export class History {
|
|||
to_summarize.push(this.turns.shift());
|
||||
await this.storeMemories(to_summarize);
|
||||
}
|
||||
|
||||
if (role === 'user')
|
||||
await this.setExamples();
|
||||
}
|
||||
|
||||
save(save_path) {
|
||||
save() {
|
||||
if (this.save_path === '' || this.save_path == null) return;
|
||||
// save history object to json file
|
||||
mkdirSync('bots', { recursive: true });
|
||||
const data = JSON.stringify(this, null, 4);
|
||||
writeFileSync(save_path, data, (err) => {
|
||||
let data = {
|
||||
'name': this.name,
|
||||
'bio': this.bio,
|
||||
'memory': this.memory,
|
||||
'turns': this.turns
|
||||
};
|
||||
const json_data = JSON.stringify(data, null, 4);
|
||||
writeFileSync(this.save_path, json_data, (err) => {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
@ -120,10 +167,11 @@ export class History {
|
|||
});
|
||||
}
|
||||
|
||||
load(save_path) {
|
||||
load() {
|
||||
if (this.save_path === '' || this.save_path == null) return;
|
||||
try {
|
||||
// load history object from json file
|
||||
const data = readFileSync(save_path, 'utf8');
|
||||
const data = readFileSync(this.save_path, 'utf8');
|
||||
const obj = JSON.parse(data);
|
||||
this.turns = obj.turns;
|
||||
this.bio = obj.bio;
|
||||
|
|
Loading…
Add table
Reference in a new issue