mirror of
https://github.com/kolbytn/mindcraft.git
synced 2025-06-08 10:15:55 +02:00
Merge 2dd0694042
into f2f06fcf3f
This commit is contained in:
commit
790ec02dc9
1 changed files with 480 additions and 435 deletions
|
@ -3,465 +3,510 @@ import settings from '../../../settings.js';
|
||||||
import convoManager from '../conversation.js';
|
import convoManager from '../conversation.js';
|
||||||
|
|
||||||
|
|
||||||
function runAsAction (actionFn, resume = false, timeout = -1) {
|
function runAsAction(actionFn, resume = false, timeout = -1) {
|
||||||
let actionLabel = null; // Will be set on first use
|
let actionLabel = null; // Will be set on first use
|
||||||
|
|
||||||
const wrappedAction = async function (agent, ...args) {
|
const wrappedAction = async function (agent, ...args) {
|
||||||
// Set actionLabel only once, when the action is first created
|
// Set actionLabel only once, when the action is first created
|
||||||
if (!actionLabel) {
|
if (!actionLabel) {
|
||||||
const actionObj = actionsList.find(a => a.perform === wrappedAction);
|
const actionObj = actionsList.find(a => a.perform === wrappedAction);
|
||||||
actionLabel = actionObj.name.substring(1); // Remove the ! prefix
|
actionLabel = actionObj.name.substring(1); // Remove the ! prefix
|
||||||
}
|
|
||||||
|
|
||||||
const actionFnWithAgent = async () => {
|
|
||||||
await actionFn(agent, ...args);
|
|
||||||
};
|
|
||||||
const code_return = await agent.actions.runAction(`action:${actionLabel}`, actionFnWithAgent, { timeout, resume });
|
|
||||||
if (code_return.interrupted && !code_return.timedout)
|
|
||||||
return;
|
|
||||||
return code_return.message;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return wrappedAction;
|
const actionFnWithAgent = async () => {
|
||||||
|
await actionFn(agent, ...args);
|
||||||
|
};
|
||||||
|
const code_return = await agent.actions.runAction(`action:${actionLabel}`, actionFnWithAgent, { timeout, resume });
|
||||||
|
if (code_return.interrupted && !code_return.timedout)
|
||||||
|
return;
|
||||||
|
return code_return.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wrappedAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const actionsList = [
|
export const actionsList = [
|
||||||
{
|
{
|
||||||
name: '!newAction',
|
name: '!newAction',
|
||||||
description: 'Perform new and unknown custom behaviors that are not available as a command.',
|
description: 'Perform new and unknown custom behaviors that are not available as a command.',
|
||||||
params: {
|
params: {
|
||||||
'prompt': { type: 'string', description: 'A natural language prompt to guide code generation. Make a detailed step-by-step plan.' }
|
'prompt': { type: 'string', description: 'A natural language prompt to guide code generation. Make a detailed step-by-step plan.' }
|
||||||
},
|
},
|
||||||
perform: async function(agent, prompt) {
|
perform: async function (agent, prompt) {
|
||||||
// just ignore prompt - it is now in context in chat history
|
// just ignore prompt - it is now in context in chat history
|
||||||
if (!settings.allow_insecure_coding) {
|
if (!settings.allow_insecure_coding) {
|
||||||
agent.openChat('newAction is disabled. Enable with allow_insecure_coding=true in settings.js');
|
agent.openChat('newAction is disabled. Enable with allow_insecure_coding=true in settings.js');
|
||||||
return "newAction not allowed! Code writing is disabled in settings. Notify the user.";
|
return "newAction not allowed! Code writing is disabled in settings. Notify the user.";
|
||||||
}
|
}
|
||||||
let result = "";
|
let result = "";
|
||||||
const actionFn = async () => {
|
const actionFn = async () => {
|
||||||
try {
|
try {
|
||||||
result = await agent.coder.generateCode(agent.history);
|
result = await agent.coder.generateCode(agent.history);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
result = 'Error generating code: ' + e.toString();
|
result = 'Error generating code: ' + e.toString();
|
||||||
}
|
|
||||||
};
|
|
||||||
await agent.actions.runAction('action:newAction', actionFn);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
await agent.actions.runAction('action:newAction', actionFn);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!stop',
|
||||||
|
description: 'Force stop all actions and commands that are currently executing.',
|
||||||
|
perform: async function (agent) {
|
||||||
|
await agent.actions.stop();
|
||||||
|
agent.clearBotLogs();
|
||||||
|
agent.actions.cancelResume();
|
||||||
|
agent.bot.emit('idle');
|
||||||
|
let msg = 'Agent stopped.';
|
||||||
|
if (agent.self_prompter.isActive())
|
||||||
|
msg += ' Self-prompting still active.';
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!stfu',
|
||||||
|
description: 'Stop all chatting and self prompting, but continue current action.',
|
||||||
|
perform: async function (agent) {
|
||||||
|
agent.openChat('Shutting up.');
|
||||||
|
agent.shutUp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!restart',
|
||||||
|
description: 'Restart the agent process.',
|
||||||
|
perform: async function (agent) {
|
||||||
|
agent.cleanKill();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!clearChat',
|
||||||
|
description: 'Clear the chat history.',
|
||||||
|
perform: async function (agent) {
|
||||||
|
agent.history.clear();
|
||||||
|
return agent.name + "'s chat history was cleared, starting new conversation from scratch.";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!goToPlayer',
|
||||||
|
description: 'Go to the given player.',
|
||||||
|
params: {
|
||||||
|
'player_name': { type: 'string', description: 'The name of the player to go to.' },
|
||||||
|
'closeness': { type: 'float', description: 'How close to get to the player.', domain: [0, Infinity] }
|
||||||
},
|
},
|
||||||
{
|
perform: runAsAction(async (agent, player_name, closeness) => {
|
||||||
name: '!stop',
|
if (agent.bot.entity.vehicle) {
|
||||||
description: 'Force stop all actions and commands that are currently executing.',
|
await agent.bot.dismount(); // Dismount from the vehicle if it's currently mounted as the bot can't control it
|
||||||
perform: async function (agent) {
|
}
|
||||||
await agent.actions.stop();
|
await skills.goToPlayer(agent.bot, player_name, closeness);
|
||||||
agent.clearBotLogs();
|
})
|
||||||
agent.actions.cancelResume();
|
},
|
||||||
agent.bot.emit('idle');
|
{
|
||||||
let msg = 'Agent stopped.';
|
name: '!followPlayer',
|
||||||
if (agent.self_prompter.isActive())
|
description: 'Endlessly follow the given player.',
|
||||||
msg += ' Self-prompting still active.';
|
params: {
|
||||||
return msg;
|
'player_name': { type: 'string', description: 'name of the player to follow.' },
|
||||||
}
|
'follow_dist': { type: 'float', description: 'The distance to follow from.', domain: [0, Infinity] }
|
||||||
},
|
},
|
||||||
{
|
perform: runAsAction(async (agent, player_name, follow_dist) => {
|
||||||
name: '!stfu',
|
if (agent.bot.entity.vehicle) {
|
||||||
description: 'Stop all chatting and self prompting, but continue current action.',
|
await agent.bot.dismount(); // Dismount from the vehicle if it's currently mounted as the bot can't control it
|
||||||
perform: async function (agent) {
|
}
|
||||||
agent.openChat('Shutting up.');
|
await skills.followPlayer(agent.bot, player_name, follow_dist);
|
||||||
agent.shutUp();
|
}, true)
|
||||||
return;
|
},
|
||||||
}
|
{
|
||||||
|
name: '!goToCoordinates',
|
||||||
|
description: 'Go to the given x, y, z location.',
|
||||||
|
params: {
|
||||||
|
'x': { type: 'float', description: 'The x coordinate.', domain: [-Infinity, Infinity] },
|
||||||
|
'y': { type: 'float', description: 'The y coordinate.', domain: [-64, 320] },
|
||||||
|
'z': { type: 'float', description: 'The z coordinate.', domain: [-Infinity, Infinity] },
|
||||||
|
'closeness': { type: 'float', description: 'How close to get to the location.', domain: [0, Infinity] }
|
||||||
},
|
},
|
||||||
{
|
perform: runAsAction(async (agent, x, y, z, closeness) => {
|
||||||
name: '!restart',
|
if (agent.bot.entity.vehicle) {
|
||||||
description: 'Restart the agent process.',
|
await agent.bot.dismount(); // Dismount from the vehicle if it's currently mounted as the bot can't control it
|
||||||
perform: async function (agent) {
|
}
|
||||||
agent.cleanKill();
|
await skills.goToPosition(agent.bot, x, y, z, closeness);
|
||||||
}
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!searchForBlock',
|
||||||
|
description: 'Find and go to the nearest block of a given type in a given range.',
|
||||||
|
params: {
|
||||||
|
'type': { type: 'BlockName', description: 'The block type to go to.' },
|
||||||
|
'search_range': { type: 'float', description: 'The range to search for the block.', domain: [32, 512] }
|
||||||
},
|
},
|
||||||
{
|
perform: runAsAction(async (agent, block_type, range) => {
|
||||||
name: '!clearChat',
|
await skills.goToNearestBlock(agent.bot, block_type, 4, range);
|
||||||
description: 'Clear the chat history.',
|
})
|
||||||
perform: async function (agent) {
|
},
|
||||||
agent.history.clear();
|
{
|
||||||
return agent.name + "'s chat history was cleared, starting new conversation from scratch.";
|
name: '!searchForEntity',
|
||||||
}
|
description: 'Find and go to the nearest entity of a given type in a given range.',
|
||||||
|
params: {
|
||||||
|
'type': { type: 'string', description: 'The type of entity to go to.' },
|
||||||
|
'search_range': { type: 'float', description: 'The range to search for the entity.', domain: [32, 512] }
|
||||||
},
|
},
|
||||||
{
|
perform: runAsAction(async (agent, entity_type, range) => {
|
||||||
name: '!goToPlayer',
|
await skills.goToNearestEntity(agent.bot, entity_type, 4, range);
|
||||||
description: 'Go to the given player.',
|
})
|
||||||
params: {
|
},
|
||||||
'player_name': {type: 'string', description: 'The name of the player to go to.'},
|
{
|
||||||
'closeness': {type: 'float', description: 'How close to get to the player.', domain: [0, Infinity]}
|
name: '!moveAway',
|
||||||
},
|
description: 'Move away from the current location in any direction by a given distance.',
|
||||||
perform: runAsAction(async (agent, player_name, closeness) => {
|
params: { 'distance': { type: 'float', description: 'The distance to move away.', domain: [0, Infinity] } },
|
||||||
await skills.goToPlayer(agent.bot, player_name, closeness);
|
perform: runAsAction(async (agent, distance) => {
|
||||||
})
|
await skills.moveAway(agent.bot, distance);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!rememberHere',
|
||||||
|
description: 'Save the current location with a given name.',
|
||||||
|
params: { 'name': { type: 'string', description: 'The name to remember the location as.' } },
|
||||||
|
perform: async function (agent, name) {
|
||||||
|
const pos = agent.bot.entity.position;
|
||||||
|
agent.memory_bank.rememberPlace(name, pos.x, pos.y, pos.z);
|
||||||
|
return `Location saved as "${name}".`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!goToRememberedPlace',
|
||||||
|
description: 'Go to a saved location.',
|
||||||
|
params: { 'name': { type: 'string', description: 'The name of the location to go to.' } },
|
||||||
|
perform: runAsAction(async (agent, name) => {
|
||||||
|
const pos = agent.memory_bank.recallPlace(name);
|
||||||
|
if (!pos) {
|
||||||
|
skills.log(agent.bot, `No location named "${name}" saved.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await skills.goToPosition(agent.bot, pos[0], pos[1], pos[2], 1);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!givePlayer',
|
||||||
|
description: 'Give the specified item to the given player.',
|
||||||
|
params: {
|
||||||
|
'player_name': { type: 'string', description: 'The name of the player to give the item to.' },
|
||||||
|
'item_name': { type: 'ItemName', description: 'The name of the item to give.' },
|
||||||
|
'num': { type: 'int', description: 'The number of items to give.', domain: [1, Number.MAX_SAFE_INTEGER] }
|
||||||
},
|
},
|
||||||
{
|
perform: runAsAction(async (agent, player_name, item_name, num) => {
|
||||||
name: '!followPlayer',
|
await skills.giveToPlayer(agent.bot, item_name, player_name, num);
|
||||||
description: 'Endlessly follow the given player.',
|
})
|
||||||
params: {
|
},
|
||||||
'player_name': {type: 'string', description: 'name of the player to follow.'},
|
{
|
||||||
'follow_dist': {type: 'float', description: 'The distance to follow from.', domain: [0, Infinity]}
|
name: '!consume',
|
||||||
},
|
description: 'Eat/drink the given item.',
|
||||||
perform: runAsAction(async (agent, player_name, follow_dist) => {
|
params: { 'item_name': { type: 'ItemName', description: 'The name of the item to consume.' } },
|
||||||
await skills.followPlayer(agent.bot, player_name, follow_dist);
|
perform: runAsAction(async (agent, item_name) => {
|
||||||
}, true)
|
await skills.consume(agent.bot, item_name);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!equip',
|
||||||
|
description: 'Equip the given item.',
|
||||||
|
params: { 'item_name': { type: 'ItemName', description: 'The name of the item to equip.' } },
|
||||||
|
perform: runAsAction(async (agent, item_name) => {
|
||||||
|
await skills.equip(agent.bot, item_name);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!putInChest',
|
||||||
|
description: 'Put the given item in the nearest chest.',
|
||||||
|
params: {
|
||||||
|
'item_name': { type: 'ItemName', description: 'The name of the item to put in the chest.' },
|
||||||
|
'num': { type: 'int', description: 'The number of items to put in the chest.', domain: [1, Number.MAX_SAFE_INTEGER] }
|
||||||
},
|
},
|
||||||
{
|
perform: runAsAction(async (agent, item_name, num) => {
|
||||||
name: '!goToCoordinates',
|
await skills.putInChest(agent.bot, item_name, num);
|
||||||
description: 'Go to the given x, y, z location.',
|
})
|
||||||
params: {
|
},
|
||||||
'x': {type: 'float', description: 'The x coordinate.', domain: [-Infinity, Infinity]},
|
{
|
||||||
'y': {type: 'float', description: 'The y coordinate.', domain: [-64, 320]},
|
name: '!takeFromChest',
|
||||||
'z': {type: 'float', description: 'The z coordinate.', domain: [-Infinity, Infinity]},
|
description: 'Take the given items from the nearest chest.',
|
||||||
'closeness': {type: 'float', description: 'How close to get to the location.', domain: [0, Infinity]}
|
params: {
|
||||||
},
|
'item_name': { type: 'ItemName', description: 'The name of the item to take.' },
|
||||||
perform: runAsAction(async (agent, x, y, z, closeness) => {
|
'num': { type: 'int', description: 'The number of items to take.', domain: [1, Number.MAX_SAFE_INTEGER] }
|
||||||
await skills.goToPosition(agent.bot, x, y, z, closeness);
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
{
|
perform: runAsAction(async (agent, item_name, num) => {
|
||||||
name: '!searchForBlock',
|
await skills.takeFromChest(agent.bot, item_name, num);
|
||||||
description: 'Find and go to the nearest block of a given type in a given range.',
|
})
|
||||||
params: {
|
},
|
||||||
'type': { type: 'BlockName', description: 'The block type to go to.' },
|
{
|
||||||
'search_range': { type: 'float', description: 'The range to search for the block.', domain: [32, 512] }
|
name: '!viewChest',
|
||||||
},
|
description: 'View the items/counts of the nearest chest.',
|
||||||
perform: runAsAction(async (agent, block_type, range) => {
|
params: {},
|
||||||
await skills.goToNearestBlock(agent.bot, block_type, 4, range);
|
perform: runAsAction(async (agent) => {
|
||||||
})
|
await skills.viewChest(agent.bot);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!discard',
|
||||||
|
description: 'Discard the given item from the inventory.',
|
||||||
|
params: {
|
||||||
|
'item_name': { type: 'ItemName', description: 'The name of the item to discard.' },
|
||||||
|
'num': { type: 'int', description: 'The number of items to discard.', domain: [1, Number.MAX_SAFE_INTEGER] }
|
||||||
},
|
},
|
||||||
{
|
perform: runAsAction(async (agent, item_name, num) => {
|
||||||
name: '!searchForEntity',
|
const start_loc = agent.bot.entity.position;
|
||||||
description: 'Find and go to the nearest entity of a given type in a given range.',
|
await skills.moveAway(agent.bot, 5);
|
||||||
params: {
|
await skills.discard(agent.bot, item_name, num);
|
||||||
'type': { type: 'string', description: 'The type of entity to go to.' },
|
await skills.goToPosition(agent.bot, start_loc.x, start_loc.y, start_loc.z, 0);
|
||||||
'search_range': { type: 'float', description: 'The range to search for the entity.', domain: [32, 512] }
|
})
|
||||||
},
|
},
|
||||||
perform: runAsAction(async (agent, entity_type, range) => {
|
{
|
||||||
await skills.goToNearestEntity(agent.bot, entity_type, 4, range);
|
name: '!collectBlocks',
|
||||||
})
|
description: 'Collect the nearest blocks of a given type.',
|
||||||
|
params: {
|
||||||
|
'type': { type: 'BlockName', description: 'The block type to collect.' },
|
||||||
|
'num': { type: 'int', description: 'The number of blocks to collect.', domain: [1, Number.MAX_SAFE_INTEGER] }
|
||||||
},
|
},
|
||||||
{
|
perform: runAsAction(async (agent, type, num) => {
|
||||||
name: '!moveAway',
|
await skills.collectBlock(agent.bot, type, num);
|
||||||
description: 'Move away from the current location in any direction by a given distance.',
|
}, false, 10) // 10 minute timeout
|
||||||
params: {'distance': { type: 'float', description: 'The distance to move away.', domain: [0, Infinity] }},
|
},
|
||||||
perform: runAsAction(async (agent, distance) => {
|
{
|
||||||
await skills.moveAway(agent.bot, distance);
|
name: '!craftRecipe',
|
||||||
})
|
description: 'Craft the given recipe a given number of times.',
|
||||||
|
params: {
|
||||||
|
'recipe_name': { type: 'ItemName', description: 'The name of the output item to craft.' },
|
||||||
|
'num': { type: 'int', description: 'The number of times to craft the recipe. This is NOT the number of output items, as it may craft many more items depending on the recipe.', domain: [1, Number.MAX_SAFE_INTEGER] }
|
||||||
},
|
},
|
||||||
{
|
perform: runAsAction(async (agent, recipe_name, num) => {
|
||||||
name: '!rememberHere',
|
await skills.craftRecipe(agent.bot, recipe_name, num);
|
||||||
description: 'Save the current location with a given name.',
|
})
|
||||||
params: {'name': { type: 'string', description: 'The name to remember the location as.' }},
|
},
|
||||||
perform: async function (agent, name) {
|
{
|
||||||
const pos = agent.bot.entity.position;
|
name: '!smeltItem',
|
||||||
agent.memory_bank.rememberPlace(name, pos.x, pos.y, pos.z);
|
description: 'Smelt the given item the given number of times.',
|
||||||
return `Location saved as "${name}".`;
|
params: {
|
||||||
}
|
'item_name': { type: 'ItemName', description: 'The name of the input item to smelt.' },
|
||||||
|
'num': { type: 'int', description: 'The number of times to smelt the item.', domain: [1, Number.MAX_SAFE_INTEGER] }
|
||||||
},
|
},
|
||||||
{
|
perform: runAsAction(async (agent, item_name, num) => {
|
||||||
name: '!goToRememberedPlace',
|
let success = await skills.smeltItem(agent.bot, item_name, num);
|
||||||
description: 'Go to a saved location.',
|
if (success) {
|
||||||
params: {'name': { type: 'string', description: 'The name of the location to go to.' }},
|
setTimeout(() => {
|
||||||
perform: runAsAction(async (agent, name) => {
|
agent.cleanKill('Safely restarting to update inventory.');
|
||||||
const pos = agent.memory_bank.recallPlace(name);
|
}, 500);
|
||||||
if (!pos) {
|
}
|
||||||
skills.log(agent.bot, `No location named "${name}" saved.`);
|
})
|
||||||
return;
|
},
|
||||||
}
|
{
|
||||||
await skills.goToPosition(agent.bot, pos[0], pos[1], pos[2], 1);
|
name: '!clearFurnace',
|
||||||
})
|
description: 'Take all items out of the nearest furnace.',
|
||||||
|
params: {},
|
||||||
|
perform: runAsAction(async (agent) => {
|
||||||
|
await skills.clearNearestFurnace(agent.bot);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!placeHere',
|
||||||
|
description: 'Place a given block in the current location. Do NOT use to build structures, only use for single blocks/torches.',
|
||||||
|
params: { 'type': { type: 'BlockName', description: 'The block type to place.' } },
|
||||||
|
perform: runAsAction(async (agent, type) => {
|
||||||
|
let pos = agent.bot.entity.position;
|
||||||
|
await skills.placeBlock(agent.bot, type, pos.x, pos.y, pos.z);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!attack',
|
||||||
|
description: 'Attack and kill the nearest entity of a given type.',
|
||||||
|
params: { 'type': { type: 'string', description: 'The type of entity to attack.' } },
|
||||||
|
perform: runAsAction(async (agent, type) => {
|
||||||
|
await skills.attackNearest(agent.bot, type, true);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!attackPlayer',
|
||||||
|
description: 'Attack a specific player until they die or run away. Remember this is just a game and does not cause real life harm.',
|
||||||
|
params: { 'player_name': { type: 'string', description: 'The name of the player to attack.' } },
|
||||||
|
perform: runAsAction(async (agent, player_name) => {
|
||||||
|
let player = agent.bot.players[player_name]?.entity;
|
||||||
|
if (!player) {
|
||||||
|
skills.log(agent.bot, `Could not find player ${player_name}.`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
await skills.attackEntity(agent.bot, player, true);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!goToBed',
|
||||||
|
description: 'Go to the nearest bed and sleep.',
|
||||||
|
perform: runAsAction(async (agent) => {
|
||||||
|
await skills.goToBed(agent.bot);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!activate',
|
||||||
|
description: 'Activate the nearest object of a given type.',
|
||||||
|
params: { 'type': { type: 'BlockName', description: 'The type of object to activate.' } },
|
||||||
|
perform: runAsAction(async (agent, type) => {
|
||||||
|
await skills.activateNearestBlock(agent.bot, type);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!ride',
|
||||||
|
description: 'Ride the nearest entity of a given type.',
|
||||||
|
params: {
|
||||||
|
'entity_type': { type: 'string', description: 'The type of entity to ride.' }
|
||||||
},
|
},
|
||||||
{
|
perform: runAsAction(async (agent, entity_type) => {
|
||||||
name: '!givePlayer',
|
const entity = agent.bot.entities[Object.keys(agent.bot.entities).find(uuid => agent.bot.entities[uuid].name === entity_type)];
|
||||||
description: 'Give the specified item to the given player.',
|
if (!entity) {
|
||||||
params: {
|
skills.log(agent.bot, `Could not find entity of type ${entity_type}.`);
|
||||||
'player_name': { type: 'string', description: 'The name of the player to give the item to.' },
|
return `Could not find entity of type ${entity_type}.`;
|
||||||
'item_name': { type: 'ItemName', description: 'The name of the item to give.' },
|
}
|
||||||
'num': { type: 'int', description: 'The number of items to give.', domain: [1, Number.MAX_SAFE_INTEGER] }
|
// Walk to the entity coordinates
|
||||||
},
|
await skills.goToPosition(agent.bot, entity.position.x, entity.position.y, entity.position.z, 3);
|
||||||
perform: runAsAction(async (agent, player_name, item_name, num) => {
|
try {
|
||||||
await skills.giveToPlayer(agent.bot, item_name, player_name, num);
|
// Bug with sneaking? Force control state.
|
||||||
})
|
await agent.bot.setControlState('sneak', false)
|
||||||
|
// Mount the entity
|
||||||
|
await agent.bot.mount(entity);
|
||||||
|
skills.log(agent.bot, `Riding entity of type ${entity_type}.`);
|
||||||
|
return `Riding entity of type ${entity_type}.`;
|
||||||
|
} catch (error) {
|
||||||
|
skills.log(agent.bot, `Failed to ride entity of type ${entity_type}: ${error.message}`);
|
||||||
|
return `Failed to ride entity of type ${entity_type}.`;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!dismount',
|
||||||
|
description: 'Dismount the currently ridden entity.',
|
||||||
|
params: {},
|
||||||
|
perform: runAsAction(async (agent) => {
|
||||||
|
await agent.bot.dismount();
|
||||||
|
return 'Dismounted entity.';
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!stay',
|
||||||
|
description: 'Stay in the current location no matter what. Pauses all modes.',
|
||||||
|
params: { 'type': { type: 'int', description: 'The number of seconds to stay. -1 for forever.', domain: [-1, Number.MAX_SAFE_INTEGER] } },
|
||||||
|
perform: runAsAction(async (agent, seconds) => {
|
||||||
|
await skills.stay(agent.bot, seconds);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!setMode',
|
||||||
|
description: 'Set a mode to on or off. A mode is an automatic behavior that constantly checks and responds to the environment.',
|
||||||
|
params: {
|
||||||
|
'mode_name': { type: 'string', description: 'The name of the mode to enable.' },
|
||||||
|
'on': { type: 'boolean', description: 'Whether to enable or disable the mode.' }
|
||||||
},
|
},
|
||||||
{
|
perform: async function (agent, mode_name, on) {
|
||||||
name: '!consume',
|
const modes = agent.bot.modes;
|
||||||
description: 'Eat/drink the given item.',
|
if (!modes.exists(mode_name))
|
||||||
params: {'item_name': { type: 'ItemName', description: 'The name of the item to consume.' }},
|
return `Mode ${mode_name} does not exist.` + modes.getDocs();
|
||||||
perform: runAsAction(async (agent, item_name) => {
|
if (modes.isOn(mode_name) === on)
|
||||||
await skills.consume(agent.bot, item_name);
|
return `Mode ${mode_name} is already ${on ? 'on' : 'off'}.`;
|
||||||
})
|
modes.setOn(mode_name, on);
|
||||||
|
return `Mode ${mode_name} is now ${on ? 'on' : 'off'}.`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!goal',
|
||||||
|
description: 'Set a goal prompt to endlessly work towards with continuous self-prompting.',
|
||||||
|
params: {
|
||||||
|
'selfPrompt': { type: 'string', description: 'The goal prompt.' },
|
||||||
},
|
},
|
||||||
{
|
perform: async function (agent, prompt) {
|
||||||
name: '!equip',
|
if (convoManager.inConversation()) {
|
||||||
description: 'Equip the given item.',
|
agent.self_prompter.setPromptPaused(prompt);
|
||||||
params: {'item_name': { type: 'ItemName', description: 'The name of the item to equip.' }},
|
}
|
||||||
perform: runAsAction(async (agent, item_name) => {
|
else {
|
||||||
await skills.equip(agent.bot, item_name);
|
agent.self_prompter.start(prompt);
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!endGoal',
|
||||||
|
description: 'Call when you have accomplished your goal. It will stop self-prompting and the current action. ',
|
||||||
|
perform: async function (agent) {
|
||||||
|
agent.self_prompter.stop();
|
||||||
|
return 'Self-prompting stopped.';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!startConversation',
|
||||||
|
description: 'Start a conversation with a player. Use for bots only.',
|
||||||
|
params: {
|
||||||
|
'player_name': { type: 'string', description: 'The name of the player to send the message to.' },
|
||||||
|
'message': { type: 'string', description: 'The message to send.' },
|
||||||
},
|
},
|
||||||
{
|
perform: async function (agent, player_name, message) {
|
||||||
name: '!putInChest',
|
if (!convoManager.isOtherAgent(player_name))
|
||||||
description: 'Put the given item in the nearest chest.',
|
return player_name + ' is not a bot, cannot start conversation.';
|
||||||
params: {
|
if (convoManager.inConversation() && !convoManager.inConversation(player_name))
|
||||||
'item_name': { type: 'ItemName', description: 'The name of the item to put in the chest.' },
|
convoManager.forceEndCurrentConversation();
|
||||||
'num': { type: 'int', description: 'The number of items to put in the chest.', domain: [1, Number.MAX_SAFE_INTEGER] }
|
else if (convoManager.inConversation(player_name))
|
||||||
},
|
agent.history.add('system', 'You are already in conversation with ' + player_name + '. Don\'t use this command to talk to them.');
|
||||||
perform: runAsAction(async (agent, item_name, num) => {
|
convoManager.startConversation(player_name, message);
|
||||||
await skills.putInChest(agent.bot, item_name, num);
|
}
|
||||||
})
|
},
|
||||||
|
{
|
||||||
|
name: '!endConversation',
|
||||||
|
description: 'End the conversation with the given player.',
|
||||||
|
params: {
|
||||||
|
'player_name': { type: 'string', description: 'The name of the player to end the conversation with.' }
|
||||||
},
|
},
|
||||||
{
|
perform: async function (agent, player_name) {
|
||||||
name: '!takeFromChest',
|
if (!convoManager.inConversation(player_name))
|
||||||
description: 'Take the given items from the nearest chest.',
|
return `Not in conversation with ${player_name}.`;
|
||||||
params: {
|
convoManager.endConversation(player_name);
|
||||||
'item_name': { type: 'ItemName', description: 'The name of the item to take.' },
|
return `Converstaion with ${player_name} ended.`;
|
||||||
'num': { type: 'int', description: 'The number of items to take.', domain: [1, Number.MAX_SAFE_INTEGER] }
|
}
|
||||||
},
|
},
|
||||||
perform: runAsAction(async (agent, item_name, num) => {
|
{
|
||||||
await skills.takeFromChest(agent.bot, item_name, num);
|
name: '!lookAtPlayer',
|
||||||
})
|
description: 'Look at a player or look in the same direction as the player.',
|
||||||
|
params: {
|
||||||
|
'player_name': { type: 'string', description: 'Name of the target player' },
|
||||||
|
'direction': {
|
||||||
|
type: 'string',
|
||||||
|
description: 'How to look ("at": look at the player, "with": look in the same direction as the player)',
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
perform: async function (agent, player_name, direction) {
|
||||||
name: '!viewChest',
|
if (direction !== 'at' && direction !== 'with') {
|
||||||
description: 'View the items/counts of the nearest chest.',
|
return "Invalid direction. Use 'at' or 'with'.";
|
||||||
params: { },
|
}
|
||||||
perform: runAsAction(async (agent) => {
|
let result = "";
|
||||||
await skills.viewChest(agent.bot);
|
const actionFn = async () => {
|
||||||
})
|
result = await agent.vision_interpreter.lookAtPlayer(player_name, direction);
|
||||||
},
|
};
|
||||||
{
|
await agent.actions.runAction('action:lookAtPlayer', actionFn);
|
||||||
name: '!discard',
|
return result;
|
||||||
description: 'Discard the given item from the inventory.',
|
}
|
||||||
params: {
|
},
|
||||||
'item_name': { type: 'ItemName', description: 'The name of the item to discard.' },
|
{
|
||||||
'num': { type: 'int', description: 'The number of items to discard.', domain: [1, Number.MAX_SAFE_INTEGER] }
|
name: '!lookAtPosition',
|
||||||
},
|
description: 'Look at specified coordinates.',
|
||||||
perform: runAsAction(async (agent, item_name, num) => {
|
params: {
|
||||||
const start_loc = agent.bot.entity.position;
|
'x': { type: 'int', description: 'x coordinate' },
|
||||||
await skills.moveAway(agent.bot, 5);
|
'y': { type: 'int', description: 'y coordinate' },
|
||||||
await skills.discard(agent.bot, item_name, num);
|
'z': { type: 'int', description: 'z coordinate' }
|
||||||
await skills.goToPosition(agent.bot, start_loc.x, start_loc.y, start_loc.z, 0);
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '!collectBlocks',
|
|
||||||
description: 'Collect the nearest blocks of a given type.',
|
|
||||||
params: {
|
|
||||||
'type': { type: 'BlockName', description: 'The block type to collect.' },
|
|
||||||
'num': { type: 'int', description: 'The number of blocks to collect.', domain: [1, Number.MAX_SAFE_INTEGER] }
|
|
||||||
},
|
|
||||||
perform: runAsAction(async (agent, type, num) => {
|
|
||||||
await skills.collectBlock(agent.bot, type, num);
|
|
||||||
}, false, 10) // 10 minute timeout
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '!craftRecipe',
|
|
||||||
description: 'Craft the given recipe a given number of times.',
|
|
||||||
params: {
|
|
||||||
'recipe_name': { type: 'ItemName', description: 'The name of the output item to craft.' },
|
|
||||||
'num': { type: 'int', description: 'The number of times to craft the recipe. This is NOT the number of output items, as it may craft many more items depending on the recipe.', domain: [1, Number.MAX_SAFE_INTEGER] }
|
|
||||||
},
|
|
||||||
perform: runAsAction(async (agent, recipe_name, num) => {
|
|
||||||
await skills.craftRecipe(agent.bot, recipe_name, num);
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '!smeltItem',
|
|
||||||
description: 'Smelt the given item the given number of times.',
|
|
||||||
params: {
|
|
||||||
'item_name': { type: 'ItemName', description: 'The name of the input item to smelt.' },
|
|
||||||
'num': { type: 'int', description: 'The number of times to smelt the item.', domain: [1, Number.MAX_SAFE_INTEGER] }
|
|
||||||
},
|
|
||||||
perform: runAsAction(async (agent, item_name, num) => {
|
|
||||||
let success = await skills.smeltItem(agent.bot, item_name, num);
|
|
||||||
if (success) {
|
|
||||||
setTimeout(() => {
|
|
||||||
agent.cleanKill('Safely restarting to update inventory.');
|
|
||||||
}, 500);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '!clearFurnace',
|
|
||||||
description: 'Take all items out of the nearest furnace.',
|
|
||||||
params: { },
|
|
||||||
perform: runAsAction(async (agent) => {
|
|
||||||
await skills.clearNearestFurnace(agent.bot);
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '!placeHere',
|
|
||||||
description: 'Place a given block in the current location. Do NOT use to build structures, only use for single blocks/torches.',
|
|
||||||
params: {'type': { type: 'BlockName', description: 'The block type to place.' }},
|
|
||||||
perform: runAsAction(async (agent, type) => {
|
|
||||||
let pos = agent.bot.entity.position;
|
|
||||||
await skills.placeBlock(agent.bot, type, pos.x, pos.y, pos.z);
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '!attack',
|
|
||||||
description: 'Attack and kill the nearest entity of a given type.',
|
|
||||||
params: {'type': { type: 'string', description: 'The type of entity to attack.'}},
|
|
||||||
perform: runAsAction(async (agent, type) => {
|
|
||||||
await skills.attackNearest(agent.bot, type, true);
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '!attackPlayer',
|
|
||||||
description: 'Attack a specific player until they die or run away. Remember this is just a game and does not cause real life harm.',
|
|
||||||
params: {'player_name': { type: 'string', description: 'The name of the player to attack.'}},
|
|
||||||
perform: runAsAction(async (agent, player_name) => {
|
|
||||||
let player = agent.bot.players[player_name]?.entity;
|
|
||||||
if (!player) {
|
|
||||||
skills.log(agent.bot, `Could not find player ${player_name}.`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
await skills.attackEntity(agent.bot, player, true);
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '!goToBed',
|
|
||||||
description: 'Go to the nearest bed and sleep.',
|
|
||||||
perform: runAsAction(async (agent) => {
|
|
||||||
await skills.goToBed(agent.bot);
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '!activate',
|
|
||||||
description: 'Activate the nearest object of a given type.',
|
|
||||||
params: {'type': { type: 'BlockName', description: 'The type of object to activate.' }},
|
|
||||||
perform: runAsAction(async (agent, type) => {
|
|
||||||
await skills.activateNearestBlock(agent.bot, type);
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '!stay',
|
|
||||||
description: 'Stay in the current location no matter what. Pauses all modes.',
|
|
||||||
params: {'type': { type: 'int', description: 'The number of seconds to stay. -1 for forever.', domain: [-1, Number.MAX_SAFE_INTEGER] }},
|
|
||||||
perform: runAsAction(async (agent, seconds) => {
|
|
||||||
await skills.stay(agent.bot, seconds);
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '!setMode',
|
|
||||||
description: 'Set a mode to on or off. A mode is an automatic behavior that constantly checks and responds to the environment.',
|
|
||||||
params: {
|
|
||||||
'mode_name': { type: 'string', description: 'The name of the mode to enable.' },
|
|
||||||
'on': { type: 'boolean', description: 'Whether to enable or disable the mode.' }
|
|
||||||
},
|
|
||||||
perform: async function (agent, mode_name, on) {
|
|
||||||
const modes = agent.bot.modes;
|
|
||||||
if (!modes.exists(mode_name))
|
|
||||||
return `Mode ${mode_name} does not exist.` + modes.getDocs();
|
|
||||||
if (modes.isOn(mode_name) === on)
|
|
||||||
return `Mode ${mode_name} is already ${on ? 'on' : 'off'}.`;
|
|
||||||
modes.setOn(mode_name, on);
|
|
||||||
return `Mode ${mode_name} is now ${on ? 'on' : 'off'}.`;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '!goal',
|
|
||||||
description: 'Set a goal prompt to endlessly work towards with continuous self-prompting.',
|
|
||||||
params: {
|
|
||||||
'selfPrompt': { type: 'string', description: 'The goal prompt.' },
|
|
||||||
},
|
|
||||||
perform: async function (agent, prompt) {
|
|
||||||
if (convoManager.inConversation()) {
|
|
||||||
agent.self_prompter.setPromptPaused(prompt);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
agent.self_prompter.start(prompt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '!endGoal',
|
|
||||||
description: 'Call when you have accomplished your goal. It will stop self-prompting and the current action. ',
|
|
||||||
perform: async function (agent) {
|
|
||||||
agent.self_prompter.stop();
|
|
||||||
return 'Self-prompting stopped.';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '!startConversation',
|
|
||||||
description: 'Start a conversation with a player. Use for bots only.',
|
|
||||||
params: {
|
|
||||||
'player_name': { type: 'string', description: 'The name of the player to send the message to.' },
|
|
||||||
'message': { type: 'string', description: 'The message to send.' },
|
|
||||||
},
|
|
||||||
perform: async function (agent, player_name, message) {
|
|
||||||
if (!convoManager.isOtherAgent(player_name))
|
|
||||||
return player_name + ' is not a bot, cannot start conversation.';
|
|
||||||
if (convoManager.inConversation() && !convoManager.inConversation(player_name))
|
|
||||||
convoManager.forceEndCurrentConversation();
|
|
||||||
else if (convoManager.inConversation(player_name))
|
|
||||||
agent.history.add('system', 'You are already in conversation with ' + player_name + '. Don\'t use this command to talk to them.');
|
|
||||||
convoManager.startConversation(player_name, message);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '!endConversation',
|
|
||||||
description: 'End the conversation with the given player.',
|
|
||||||
params: {
|
|
||||||
'player_name': { type: 'string', description: 'The name of the player to end the conversation with.' }
|
|
||||||
},
|
|
||||||
perform: async function (agent, player_name) {
|
|
||||||
if (!convoManager.inConversation(player_name))
|
|
||||||
return `Not in conversation with ${player_name}.`;
|
|
||||||
convoManager.endConversation(player_name);
|
|
||||||
return `Converstaion with ${player_name} ended.`;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '!lookAtPlayer',
|
|
||||||
description: 'Look at a player or look in the same direction as the player.',
|
|
||||||
params: {
|
|
||||||
'player_name': { type: 'string', description: 'Name of the target player' },
|
|
||||||
'direction': {
|
|
||||||
type: 'string',
|
|
||||||
description: 'How to look ("at": look at the player, "with": look in the same direction as the player)',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
perform: async function(agent, player_name, direction) {
|
|
||||||
if (direction !== 'at' && direction !== 'with') {
|
|
||||||
return "Invalid direction. Use 'at' or 'with'.";
|
|
||||||
}
|
|
||||||
let result = "";
|
|
||||||
const actionFn = async () => {
|
|
||||||
result = await agent.vision_interpreter.lookAtPlayer(player_name, direction);
|
|
||||||
};
|
|
||||||
await agent.actions.runAction('action:lookAtPlayer', actionFn);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '!lookAtPosition',
|
|
||||||
description: 'Look at specified coordinates.',
|
|
||||||
params: {
|
|
||||||
'x': { type: 'int', description: 'x coordinate' },
|
|
||||||
'y': { type: 'int', description: 'y coordinate' },
|
|
||||||
'z': { type: 'int', description: 'z coordinate' }
|
|
||||||
},
|
|
||||||
perform: async function(agent, x, y, z) {
|
|
||||||
let result = "";
|
|
||||||
const actionFn = async () => {
|
|
||||||
result = await agent.vision_interpreter.lookAtPosition(x, y, z);
|
|
||||||
};
|
|
||||||
await agent.actions.runAction('action:lookAtPosition', actionFn);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '!digDown',
|
|
||||||
description: 'Digs down a specified distance. Will stop if it reaches lava, water, or a fall of >=4 blocks below the bot.',
|
|
||||||
params: {'distance': { type: 'int', description: 'Distance to dig down', domain: [1, Number.MAX_SAFE_INTEGER] }},
|
|
||||||
perform: runAsAction(async (agent, distance) => {
|
|
||||||
await skills.digDown(agent.bot, distance)
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
|
perform: async function (agent, x, y, z) {
|
||||||
|
let result = "";
|
||||||
|
const actionFn = async () => {
|
||||||
|
result = await agent.vision_interpreter.lookAtPosition(x, y, z);
|
||||||
|
};
|
||||||
|
await agent.actions.runAction('action:lookAtPosition', actionFn);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '!digDown',
|
||||||
|
description: 'Digs down a specified distance. Will stop if it reaches lava, water, or a fall of >=4 blocks below the bot.',
|
||||||
|
params: { 'distance': { type: 'int', description: 'Distance to dig down', domain: [1, Number.MAX_SAFE_INTEGER] } },
|
||||||
|
perform: runAsAction(async (agent, distance) => {
|
||||||
|
await skills.digDown(agent.bot, distance)
|
||||||
|
})
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
Loading…
Add table
Reference in a new issue