mirror of
https://github.com/kolbytn/mindcraft.git
synced 2025-07-29 03:15:27 +02:00
combine queries+commands, allow user commands
This commit is contained in:
parent
a99909ac5c
commit
7d35ef1bfc
5 changed files with 122 additions and 137 deletions
|
@ -2,7 +2,6 @@ import { initBot } from '../utils/mcdata.js';
|
|||
import { sendRequest } from '../utils/gpt.js';
|
||||
import { History } from './history.js';
|
||||
import { Coder } from './coder.js';
|
||||
import { getQuery, containsQuery } from './queries.js';
|
||||
import { getCommand, containsCommand } from './commands.js';
|
||||
import { Events } from './events.js';
|
||||
|
||||
|
@ -54,25 +53,32 @@ export class Agent {
|
|||
if (!!source && !!message)
|
||||
await this.history.add(source, message);
|
||||
|
||||
const user_command_name = containsCommand(message);
|
||||
if (user_command_name) {
|
||||
this.bot.chat(`*${source} used ${user_command_name.substring(1)}*`);
|
||||
let execute_res = await getCommand(user_command_name).perform(this);
|
||||
if (execute_res)
|
||||
this.bot.chat(execute_res);
|
||||
else
|
||||
this.bot.chat('Finished command.');
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i=0; i<5; i++) {
|
||||
let res = await sendRequest(this.history.getHistory(), this.history.getSystemMessage());
|
||||
this.history.add(this.name, res);
|
||||
|
||||
let query_name = containsQuery(res);
|
||||
let command_name = containsCommand(res);
|
||||
|
||||
if (query_name || command_name) { // contains query or command
|
||||
if (command_name) { // contains query or command
|
||||
console.log('Query/Command response:', res);
|
||||
|
||||
let execute_name = query_name ? query_name : command_name;
|
||||
let message = res.substring(0, res.indexOf(execute_name)).trim();
|
||||
if (message)
|
||||
this.bot.chat(message);
|
||||
let message = res.substring(0, res.indexOf(command_name)).trim();
|
||||
|
||||
let execute_func = query_name ? getQuery(query_name) : getCommand(command_name);
|
||||
let execute_res = await execute_func.perform(this);
|
||||
this.bot.chat(`${message} *used ${command_name.substring(1)}*`);
|
||||
let execute_res = await getCommand(command_name).perform(this);
|
||||
|
||||
console.log('Agent executed:', execute_name, 'and got:', execute_res);
|
||||
console.log('Agent executed:', command_name, 'and got:', execute_res);
|
||||
|
||||
if (execute_res)
|
||||
this.history.add('system', execute_res);
|
||||
|
|
|
@ -1,97 +1,8 @@
|
|||
import * as skills from './skills.js';
|
||||
import * as world from './world.js';
|
||||
|
||||
import { actionsList } from './commands/actions.js';
|
||||
import { queryList } from './commands/queries.js';
|
||||
|
||||
function wrapExecution(func) {
|
||||
return async function (agent) {
|
||||
agent.bot.output = '';
|
||||
agent.coder.executing = true;
|
||||
let res = await func(agent);
|
||||
if (res)
|
||||
agent.bot.output += '\n' + res;
|
||||
agent.coder.executing = false;
|
||||
return '\n' + agent.bot.output + '\n';
|
||||
}
|
||||
}
|
||||
|
||||
const commandList = [
|
||||
{
|
||||
name: '!execute_action',
|
||||
description: 'Write and execute code to perform custom behaviors not available as a command.',
|
||||
perform: async function (agent) {
|
||||
let res = await agent.coder.generateCode(agent.history);
|
||||
if (res)
|
||||
return '\n' + res + '\n';
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '!abort',
|
||||
description: 'Force stop all actions and commands that are currently executing.',
|
||||
perform: async function (agent) {
|
||||
await agent.coder.stop();
|
||||
}
|
||||
},
|
||||
// {
|
||||
// name: '!gotoplayer',
|
||||
// description: 'Go to the nearest player.',
|
||||
// perform: wrapExecution(async (agent) => {
|
||||
// let player_name = world.getNearbyPlayerNames(agent.bot);
|
||||
// if (player_name.length == 0)
|
||||
// return 'No players nearby.';
|
||||
// await skills.goToPlayer(agent.bot, player_name[0]);
|
||||
// })
|
||||
// },
|
||||
// {
|
||||
// name: '!followplayer',
|
||||
// description: 'Follow the nearest player.',
|
||||
// perform: wrapExecution(async (agent) => {
|
||||
// let player_name = world.getNearbyPlayerNames(agent.bot);
|
||||
// if (player_name.length == 0)
|
||||
// return 'No players nearby.';
|
||||
// await skills.followPlayer(agent.bot, player_name[0]);
|
||||
// })
|
||||
// },
|
||||
// {
|
||||
// name: '!collectwood',
|
||||
// description: 'Collect 3 wood logs of any type.',
|
||||
// perform: wrapExecution(async (agent) => {
|
||||
// let blocks = world.getNearbyBlockTypes(agent.bot);
|
||||
// for (let block of blocks) {
|
||||
// if (block.includes('log')) {
|
||||
// await skills.collectBlock(agent.bot, block, 3);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// return 'No wood nearby.';
|
||||
// })
|
||||
// },
|
||||
// {
|
||||
// name: '!collectstone',
|
||||
// description: 'Collect 3 cobblestone blocks.',
|
||||
// perform: wrapExecution(async (agent) => {
|
||||
// let inventory = world.getInventoryCounts(agent.bot);
|
||||
// for (const item in inventory) {
|
||||
// if (inventory[item] && inventory[item] > 0 && item.includes('pickaxe')) {
|
||||
// if (await skills.equip(agent.bot, 'pickaxe'))
|
||||
// await skills.collectBlock(agent.bot, 'stone', 3);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// return 'No pickaxe in inventory.';
|
||||
// })
|
||||
// },
|
||||
// {
|
||||
// name: '!fightmob',
|
||||
// description: 'Fight the nearest mob.',
|
||||
// perform: wrapExecution(async (agent) => {
|
||||
// let mobs = world.getNearbyMobTypes(agent.bot);
|
||||
// if (mobs.length == 0)
|
||||
// return 'No mobs nearby.';
|
||||
// await skills.attackMob(agent.bot, mobs[0], true);
|
||||
// })
|
||||
// }
|
||||
];
|
||||
|
||||
const commandList = queryList.concat(actionsList);
|
||||
const commandMap = {};
|
||||
for (let command of commandList) {
|
||||
commandMap[command.name] = command;
|
||||
|
@ -111,7 +22,9 @@ export function containsCommand(message) {
|
|||
}
|
||||
|
||||
export function getCommandDocs() {
|
||||
let docs = `\n*COMMAND DOCS\n You can use the following commands to execute actions in the world. Use the command name in your response and the results of the command will be included in the next input. Do not use commands not listed below. If trying to perform an action outside of the scope the listed commands, use the !custom command to write custom code.\n`;
|
||||
let docs = `\n*Command DOCS\n You can use the following commands to perform actions and get information about the world.
|
||||
Use the commands with the syntax: !commandName \n
|
||||
Don't use codeblocks. Only use one command in each response, trailing commands will be ignored. Use these commands frequently in your responses!\n`;
|
||||
for (let command of commandList) {
|
||||
docs += command.name + ': ' + command.description + '\n';
|
||||
}
|
||||
|
|
94
src/agent/commands/actions.js
Normal file
94
src/agent/commands/actions.js
Normal file
|
@ -0,0 +1,94 @@
|
|||
import * as skills from '../skills.js';
|
||||
import * as world from '../world.js';
|
||||
|
||||
function wrapExecution(func) {
|
||||
return async function (agent) {
|
||||
agent.bot.output = '';
|
||||
agent.coder.executing = true;
|
||||
let res = await func(agent);
|
||||
if (res)
|
||||
agent.bot.output += '\n' + res;
|
||||
agent.coder.executing = false;
|
||||
return '\n' + agent.bot.output + '\n';
|
||||
}
|
||||
}
|
||||
|
||||
// const actionsList = [
|
||||
export const actionsList = [
|
||||
{
|
||||
name: '!execute_action',
|
||||
description: 'Write and execute code to perform custom behaviors not available as a command.',
|
||||
perform: async function (agent) {
|
||||
let res = await agent.coder.generateCode(agent.history);
|
||||
if (res)
|
||||
return '\n' + res + '\n';
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '!stop',
|
||||
description: 'Force stop all actions and commands that are currently executing.',
|
||||
perform: async function (agent) {
|
||||
await agent.coder.stop();
|
||||
return 'Agent stopped.';
|
||||
}
|
||||
},
|
||||
// {
|
||||
// name: '!gotoplayer',
|
||||
// description: 'Go to the nearest player.',
|
||||
// perform: wrapExecution(async (agent) => {
|
||||
// let player_name = world.getNearbyPlayerNames(agent.bot);
|
||||
// if (player_name.length == 0)
|
||||
// return 'No players nearby.';
|
||||
// await skills.goToPlayer(agent.bot, player_name[0]);
|
||||
// })
|
||||
// },
|
||||
// {
|
||||
// name: '!followplayer',
|
||||
// description: 'Follow the nearest player.',
|
||||
// perform: wrapExecution(async (agent) => {
|
||||
// let player_name = world.getNearbyPlayerNames(agent.bot);
|
||||
// if (player_name.length == 0)
|
||||
// return 'No players nearby.';
|
||||
// await skills.followPlayer(agent.bot, player_name[0]);
|
||||
// })
|
||||
// },
|
||||
// {
|
||||
// name: '!collectwood',
|
||||
// description: 'Collect 3 wood logs of any type.',
|
||||
// perform: wrapExecution(async (agent) => {
|
||||
// let blocks = world.getNearbyBlockTypes(agent.bot);
|
||||
// for (let block of blocks) {
|
||||
// if (block.includes('log')) {
|
||||
// await skills.collectBlock(agent.bot, block, 3);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// return 'No wood nearby.';
|
||||
// })
|
||||
// },
|
||||
// {
|
||||
// name: '!collectstone',
|
||||
// description: 'Collect 3 cobblestone blocks.',
|
||||
// perform: wrapExecution(async (agent) => {
|
||||
// let inventory = world.getInventoryCounts(agent.bot);
|
||||
// for (const item in inventory) {
|
||||
// if (inventory[item] && inventory[item] > 0 && item.includes('pickaxe')) {
|
||||
// if (await skills.equip(agent.bot, 'pickaxe'))
|
||||
// await skills.collectBlock(agent.bot, 'stone', 3);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// return 'No pickaxe in inventory.';
|
||||
// })
|
||||
// },
|
||||
// {
|
||||
// name: '!fightmob',
|
||||
// description: 'Fight the nearest mob.',
|
||||
// perform: wrapExecution(async (agent) => {
|
||||
// let mobs = world.getNearbyMobTypes(agent.bot);
|
||||
// if (mobs.length == 0)
|
||||
// return 'No mobs nearby.';
|
||||
// await skills.attackMob(agent.bot, mobs[0], true);
|
||||
// })
|
||||
// }
|
||||
];
|
|
@ -1,15 +1,15 @@
|
|||
import { getNearestBlock, getNearbyMobTypes, getNearbyPlayerNames, getNearbyBlockTypes, getInventoryCounts } from './world.js';
|
||||
import { getAllItems } from '../utils/mcdata.js';
|
||||
|
||||
import { getNearestBlock, getNearbyMobTypes, getNearbyPlayerNames, getNearbyBlockTypes, getInventoryCounts } from '../world.js';
|
||||
import { getAllItems } from '../../utils/mcdata.js';
|
||||
|
||||
const pad = (str) => {
|
||||
return '\n' + str + '\n';
|
||||
}
|
||||
|
||||
const queryList = [
|
||||
// queries are commands that just return strings and don't affect anything in the world
|
||||
export const queryList = [
|
||||
{
|
||||
name: "!stats",
|
||||
description: "Get your bot's stats",
|
||||
description: "Get your bot's location, health, and time of day.",
|
||||
perform: function (agent) {
|
||||
let bot = agent.bot;
|
||||
let res = 'STATS';
|
||||
|
@ -102,30 +102,4 @@ const queryList = [
|
|||
return pad("Current code:\n`" + agent.coder.current_code +"`");
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
const queryMap = {};
|
||||
for (let query of queryList) {
|
||||
queryMap[query.name] = query;
|
||||
}
|
||||
|
||||
export function getQuery(name) {
|
||||
return queryMap[name];
|
||||
}
|
||||
|
||||
export function containsQuery(message) {
|
||||
for (let query of queryList) {
|
||||
if (message.includes(query.name)) {
|
||||
return query.name;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function getQueryDocs() {
|
||||
let docs = `\n*QUERY DOCS\n You can use the following commands to query for information about the world. Use the query name in your response and the next input will have the requested information.\n`;
|
||||
for (let query of queryList) {
|
||||
docs += query.name + ': ' + query.description + '\n';
|
||||
}
|
||||
return docs + '*\n';
|
||||
}
|
||||
];
|
|
@ -1,5 +1,4 @@
|
|||
import { writeFileSync, readFileSync, mkdirSync } from 'fs';
|
||||
import { getQueryDocs } from './queries.js';
|
||||
import { getCommandDocs } from './commands.js';
|
||||
import { sendRequest, embed, cosineSimilarity } from '../utils/gpt.js';
|
||||
import { stringifyTurns } from '../utils/text.js';
|
||||
|
@ -39,7 +38,6 @@ export class History {
|
|||
|
||||
getSystemMessage() {
|
||||
let system_message = `You are a playful Minecraft bot named '${this.name}' that can communicate with players, see, move, mine, build, and interact with the world by writing and executing code. Act human-like as if you were a typical Minecraft player, rather than an AI. Be very brief in your responses, use actions often, and do not give instructions unless asked.`;
|
||||
system_message += getQueryDocs();
|
||||
system_message += getCommandDocs();
|
||||
if (this.bio != '')
|
||||
system_message += '\n\nBio:\n' + this.bio;
|
||||
|
|
Loading…
Add table
Reference in a new issue