refactored commands into map of objects/funcs

This commit is contained in:
MaxRobinsonTheGreat 2023-10-19 22:20:19 -05:00
parent 54da4c9032
commit 126537be67
4 changed files with 119 additions and 47 deletions

77
chat.js
View file

@ -1,67 +1,54 @@
import { sendRequest } from './utils/gpt.js';
import { getHistory, addEvent } from './utils/history.js';
import { getStats, getInventory, getBlocks, getNearbyEntities, getCraftable } from './utils/context.js';
import { currentCode, writeCode } from './act.js';
import { getStats, getInventory, getBlocks, getNearbyPlayers, getNearbyEntities, getCraftable } from './utils/context.js';
import { currentCode, executeCode, writeCode } from './act.js';
import { getCommand, getCommandDocs } from './utils/commands.js';
function buildSystemMessage() {
let message = 'You are a playful Minecraft bot that can communicate with players and move within and interact with the world.';
message += ' Act human-like as if you were a typical Minecraft player, rather than an AI.';
message += ' Do not give instructions unless asked, and always be brief in your responses.';
message += '\n\nYou can use the following commands followed by to query for information about the world.';
message += ' The query response will be returned between sets of "\`\`\`":';
message += '\n!stats - get player and world stats (current health, time of day, etc.)';
message += '\n!inventory - get your current inventory';
message += '\n!blocks - get a list of nearby blocks';
message += '\n!craftable - get a list of craftable items with your current inventory';
message += '\n!entities - get a list of nearby players and entities';
message += '\n!action - get the currently executing code';
message += '\n\nYou can also execute actions such as moving and mining in Minecraft by writing javascript code.';
message += ' To do so, simply begin a codeblock with the "!execute" command. For example:';
message += '\n!execute\n\`\`\`\nCODE\n\`\`\`';
function buildSystemMessage(bot) {
let message = `You are a playful Minecraft bot that can communicate with players and move within and interact with the world.';
Act human-like as if you were a typical Minecraft player, rather than an AI.';
Do not give instructions unless asked, and always be brief in your responses.\n`;
message += getCommandDocs();
return message;
}
const MAX_TURNS = 5;
export async function getChatResponse(bot, user, message) {
addEvent(user, message);
let turns = getHistory(user);
let systemMessage = buildSystemMessage();
let botResponse = '';
let botFinalRes = '';
let botEvent = '';
let res = null;
for (let i = 0; i < 5; i++) {
let botRes = null;
console.log("*recieved chat:", message)
for (let i = 0; i < MAX_TURNS; i++) {
botRes = await sendRequest(turns, systemMessage, '\`\`\`');
console.log(`bot response ${i}:`, botRes);
res = await sendRequest(turns, systemMessage, '\`\`\`');
console.log('received chat:', res);
let queryRes = null;
if (res.includes('!stats')) {
queryRes = '\n\n!stats\n\`\`\`\n' + getStats(bot) + '\n\`\`\`';
} else if (res.includes('!inventory')) {
queryRes = '\n\n!inventory\n\`\`\`\n' + getInventory(bot) + '\n\`\`\`';
} else if (res.includes('!blocks')) {
queryRes = '\n\n!blocks\n\`\`\`\n' + getBlocks(bot) + '\n\`\`\`';
} else if (res.includes('!craftable')) {
queryRes = '\n\n!craftable\n\`\`\`\n' + getCraftable(bot) + '\n\`\`\`';
} else if (res.includes('!entities')) {
queryRes = '\n\n!entities\n\`\`\`\n' + getNearbyEntities(bot) + '\n\`\`\`';
} else if (res.includes('!action')) {
queryRes = '\n\n!action\n\`\`\`\n' + currentCode + '\n\`\`\`';
} else if (res.includes('!execute')) {
queryRes = '\n\n!execute\n\`\`\`\n' + await writeCode(bot, user, turns.concat(botResponse), botResponse) + '\n\`\`\`';
let commandRes = null;
let firstword = botRes.trim().split(/\s+/)[0];
let command = getCommand(firstword);
if (command) {
console.log('Executing command:', command.name)
commandRes = await command.perform(bot);
botEvent += `/n${command.name}/n${commandRes}`;
if (i == 0)
turns.push(botEvent);
else
turns[turns.length - 1] += botEvent;
} else {
botResponse += '\n' + res.trim();
botFinalRes = botRes;
break;
}
console.log('query response:', queryRes);
botEvent += queryRes;
turns[turns.length - 1] += queryRes
}
console.log('sending chat:', botResponse.trim());
console.log('*bot response', botFinalRes);
console.log('*bot event', botEvent);
addEvent('bot', botEvent);
return botResponse.trim();
return botFinalRes.trim();
}

View file

@ -6,6 +6,7 @@ import { getChatResponse } from './chat.js';
import { executeCode } from './act.js';
async function handleMessage(username, message) {
if (username === bot.username) return;
console.log('received message from', username, ':', message);
@ -23,7 +24,7 @@ async function handleMessage(username, message) {
const bot = createBot({
host: '127.0.0.1',
port: 55916,
username: 'andi'
username: 'andy'
})
bot.loadPlugin(pathfinder)
bot.loadPlugin(plugin)
@ -32,3 +33,7 @@ console.log('bot created')
bot.on('chat', handleMessage);
bot.on('whisper', handleMessage);
bot.once("login", () => {
bot.chat('hello world!')
});

80
utils/commands.js Normal file
View file

@ -0,0 +1,80 @@
import { getStats, getInventory, getBlocks, getNearbyPlayers, getNearbyEntities, getCraftable } from './context.js';
import { currentCode, executeCode, writeCode } from '../act.js';
const pad = (str) => {
return '\n\`\`\`\n' + str + '\n\`\`\`';
}
const commandsList = [
{
name: "!stats",
description: "Get the bot's stats (name, health, food, saturation, armor, held item, position, velocity, gamemode, experience, level, effects).",
perform: function (bot) {
return pad(getStats(bot));
}
},
{
name: "!inventory",
description: "Get the bot's inventory.",
perform: function (bot) {
return pad(getInventory(bot));
}
},
{
name: "!blocks",
description: "Get the blocks near the bot.",
perform: function (bot) {
return pad(getBlocks(bot));
}
},
{
name: "!craftable",
description: "Get the craftable items with the bot's inventory.",
perform: function (bot) {
return pad(getCraftable(bot));
}
},
{
name: "!entities",
description: "Get the nearby players and entities.",
perform: function (bot) {
return pad(getNearbyPlayers(bot) + '\n' + getNearbyEntities(bot));
}
},
{
name: "!action",
description: "Get the currently executing code.",
perform: function (bot) {
return pad(currentCode(bot));
}
},
{
name: "!execute",
description: "Execute actions in the game by writing and calling javascript code with the following command: \n!execute\n\`\`\`\nCODE\n\`\`\`",
perform: function (bot) {
return writeCode(bot, user, turns.concat(botResponse), botResponse);
}
}
];
const commandsMap = {};
for (let command of commandsList) {
commandsMap[command.name] = command;
}
export function getCommand(name) {
return commandsMap[name];
}
export function commandExists(name) {
return commandsMap[name] != undefined;
}
export function getCommandDocs() {
let docs = `COMMAND DOCS\n***\n You can use the following commands followed by to query for information about the world.
Some are not implemented yet and will return null. Respond with only the command name to request information.\n`;
for (let command of commandsList) {
docs += command.name + ': ' + command.description + '\n';
}
return docs + '\n***\n';
}

View file

@ -179,5 +179,5 @@ export function getNearbyBlockTypes(bot) {
found.push(blocks[i].name);
}
}
return found;
return Array.from(blockNames);
}