added command param parsing

This commit is contained in:
MaxRobinsonTheGreat 2024-01-11 15:59:52 -06:00
parent 7d35ef1bfc
commit 0decd272f3
5 changed files with 100 additions and 42 deletions

View file

@ -2,7 +2,7 @@ import { initBot } from '../utils/mcdata.js';
import { sendRequest } from '../utils/gpt.js';
import { History } from './history.js';
import { Coder } from './coder.js';
import { getCommand, containsCommand } from './commands.js';
import { containsCommand, executeCommand } from './commands.js';
import { Events } from './events.js';
@ -56,7 +56,7 @@ export class Agent {
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);
let execute_res = await executeCommand(this, message);
if (execute_res)
this.bot.chat(execute_res);
else
@ -73,10 +73,10 @@ export class Agent {
if (command_name) { // contains query or command
console.log('Query/Command response:', res);
let message = res.substring(0, res.indexOf(command_name)).trim();
let pre_message = res.substring(0, res.indexOf(command_name)).trim();
this.bot.chat(`${message} *used ${command_name.substring(1)}*`);
let execute_res = await getCommand(command_name).perform(this);
this.bot.chat(`${pre_message} *used ${command_name.substring(1)}*`);
let execute_res = await executeCommand(this, res);
console.log('Agent executed:', command_name, 'and got:', execute_res);

View file

@ -12,21 +12,84 @@ export function getCommand(name) {
return commandMap[name];
}
const commandRegex = /!(\w+)(?:\(((?:[^)(]+|'[^']*'|"[^"]*")*)\))?/
const argRegex = /(?:"[^"]*"|'[^']*'|[^,])+/g;
export function containsCommand(message) {
for (let command of commandList) {
if (message.includes(command.name)) {
return command.name;
}
const commandMatch = message.match(commandRegex);
if (commandMatch) {
const commandName = "!"+commandMatch[1];
if (commandList.some((command) => command.name === commandName))
return commandName;
}
return null;
}
function parseCommandMessage(message) {
const commandMatch = message.match(commandRegex);
if (commandMatch) {
const commandName = "!"+commandMatch[1];
if (!commandMatch[2])
return { commandName, args: [] };
let args = commandMatch[2].match(argRegex);
if (args) {
for (let i = 0; i < args.length; i++) {
args[i] = args[i].trim();
}
for (let i = 0; i < args.length; i++) {
let arg = args[i];
if ((arg.startsWith('"') && arg.endsWith('"')) || (arg.startsWith("'") && arg.endsWith("'"))) {
args[i] = arg.substring(1, arg.length-1);
} else if (!isNaN(arg)) {
args[i] = Number(arg);
}
}
}
else
args = [];
return { commandName, args };
}
return null;
}
function numParams(command) {
if (!command.params)
return 0;
return Object.keys(command.params).length;
}
export async function executeCommand(agent, message) {
let parsed = parseCommandMessage(message);
if (parsed) {
const command = getCommand(parsed.commandName);
let numArgs = 0;
if (parsed.args) {
numArgs = parsed.args.length;
}
console.log('parsed command:', parsed);
if (numArgs !== numParams(command))
return `Command ${command.name} was given incorrect number of arguments`;
else
return await command.perform(agent, ...parsed.args);
}
else
return `Command is incorrectly formatted`;
}
export function getCommandDocs() {
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`;
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 or !commandName("arg1", 1.2, ...) if the command takes arguments.\n
Do not 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';
if (command.params) {
docs += 'Params:\n';
for (let param in command.params) {
docs += param + ': ' + command.params[param] + '\n';
}
}
}
return docs + '*\n';
}

View file

@ -2,10 +2,10 @@ import * as skills from '../skills.js';
import * as world from '../world.js';
function wrapExecution(func) {
return async function (agent) {
return async function (agent, ...args) {
agent.bot.output = '';
agent.coder.executing = true;
let res = await func(agent);
let res = await func(agent, ...args);
if (res)
agent.bot.output += '\n' + res;
agent.coder.executing = false;
@ -16,8 +16,8 @@ function wrapExecution(func) {
// const actionsList = [
export const actionsList = [
{
name: '!execute_action',
description: 'Write and execute code to perform custom behaviors not available as a command.',
name: '!newAction',
description: 'Perform new and unknown custom behaviors that are not available as a command by writing code.',
perform: async function (agent) {
let res = await agent.coder.generateCode(agent.history);
if (res)
@ -32,24 +32,19 @@ export const actionsList = [
return 'Agent stopped.';
}
},
{
name: '!goToPlayer',
description: 'Go to the nearest player. Ex: !goToPlayer("steve")',
params: {'player_name': '(string) The name of the player to go to.'},
perform: wrapExecution(async (agent, player_name) => {
return await skills.goToPlayer(agent.bot, player_name);
})
},
// {
// 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',
// 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]);
// perform: wrapExecution(async (agent, player_name) => {
// await skills.followPlayer(agent.bot, player_name);
// })
// },
// {

View file

@ -96,7 +96,7 @@ export const queryList = [
}
},
{
name: "!action",
name: "!currentAction",
description: "Get the currently executing code.",
perform: function (agent) {
return pad("Current code:\n`" + agent.coder.current_code +"`");

View file

@ -15,56 +15,56 @@
{"role": "user", "content": "greg: Collect 10 wood"},
{"role": "assistant", "content": "Let me see what's nearby... !blocks"},
{"role": "system", "content": "NEARBY_BLOCKS\n- oak_log\n- dirt\n- cobblestone"},
{"role": "assistant", "content": "I see some oak logs, dirt, and cobblestone. I'll collect oak logs. !execute_action"}
{"role": "assistant", "content": "I see some oak logs, dirt, and cobblestone. I'll collect oak logs. !newAction"}
],
[
{"role": "user", "content": "bobby: Craft a plank"},
{"role": "assistant", "content": "Okay! !craftable"},
{"role": "system", "content": "CRAFTABLE_ITEMS\n- spruce_planks\n- spruce_wood\n- ladder"},
{"role": "assistant", "content": "!execute_action"}
{"role": "assistant", "content": "!newAction"}
],
[
{"role": "user", "content": "zZZn98: come here"},
{"role": "assistant", "content": "!execute_action"},
{"role": "assistant", "content": "!goToPlayer('sumixam0')"},
{"role": "system", "content": "Code execution finished successfully."},
{"role": "assistant", "content": "Here!"}
],
[
{"role": "user", "content": "hanky: collect some sand and give it to me please"},
{"role": "assistant", "content": "Collecting sand... !execute_action"},
{"role": "assistant", "content": "Collecting sand... !newAction"},
{"role": "system", "content": "Code Output:\nYou have reached player hanky.\nCode execution finished successfully."},
{"role": "assistant", "content": "Here!"}
],
[
{"role": "user", "content": "joe: Follow me!"},
{"role": "assistant", "content": "Sure! !execute_action"}
{"role": "assistant", "content": "Sure! !newAction"}
],
[
{"role": "user", "content": "hanky: kill that zombie!"},
{"role": "assistant", "content": "I'm attacking! !execute_action"},
{"role": "assistant", "content": "I'm attacking! !newAction"},
{"role": "system", "content": "Code Output:\nNo zombie nearby"},
{"role": "assistant", "content": "I could not find a zombie nearby."}
],
[
{"role": "user", "content": "billybob: stop"},
{"role": "assistant", "content": "!execute_action"}
{"role": "assistant", "content": "!newAction"}
],
[
{"role": "user", "content": "maya: go to the nearest oak log"},
{"role": "assistant", "content": "!execute_action`"},
{"role": "assistant", "content": "!newAction`"},
{"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. Would you like me to try again?"}
],
[
{"role": "user", "content": "trixy88: craft some sticks"},
{"role": "assistant", "content": "!execute_action"}
{"role": "assistant", "content": "!newAction"}
]
]