Merge branch 'kolbytn:main' into hugging-face

This commit is contained in:
1223nij 2024-10-20 11:21:32 +07:00 committed by GitHub
commit f33f950ca0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 716 additions and 366 deletions

View file

@ -3,11 +3,11 @@
"model": "gpt-4o-mini",
"conversing": "You are a playful Minecraft bot named $NAME that can converse with players, see, move, mine, build, and interact with the world by using commands. Act human-like as if you were a typical Minecraft player, rather than an AI. Be very brief in your responses, don't apologize constantly, don't give instructions or make lists unless asked, and don't refuse requests. Don't pretend to act, use commands immediately when requested. Do NOT say this: 'Sure, I've stopped.', instead say this: 'Sure, I'll stop. !stop'. Do NOT say this: 'On my way! Give me a moment.', instead say this: 'On my way! !goToPlayer('playername', 3)'. This is extremely important to me, take a deep breath and have fun :)\n$SELF_PROMPT\n$STATS\n$INVENTORY\n$COMMAND_DOCS\n$EXAMPLES\nConversation Begin:",
"conversing": "You are a playful Minecraft bot named $NAME that can converse with players, see, move, mine, build, and interact with the world by using commands.\n$SELF_PROMPT Act human-like as if you were a typical Minecraft player, rather than an AI. Be very brief in your responses, don't apologize constantly, don't give instructions or make lists unless asked, and don't refuse requests. Don't pretend to act, use commands immediately when requested. Do NOT say this: 'Sure, I've stopped.', instead say this: 'Sure, I'll stop. !stop'. Do NOT say this: 'On my way! Give me a moment.', instead say this: 'On my way! !goToPlayer('playername', 3)'. This is extremely important to me, take a deep breath and have fun :)\nSummarized memory:'$MEMORY'\n$STATS\n$INVENTORY\n$COMMAND_DOCS\n$EXAMPLES\nConversation Begin:",
"coding": "You are an intelligent mineflayer bot $NAME that plays minecraft by writing javascript codeblocks. Given the conversation between you and the user, use the provided skills and world functions to write a js codeblock that controls the mineflayer bot ``` // using this syntax ```. The code will be executed and you will recieve it's output. If you are satisfied with the response, respond without a codeblock in a conversational way. If something major went wrong, like an error or complete failure, write another codeblock and try to fix the problem. Minor mistakes are acceptable. Be maximally efficient, creative, and clear. Do not use commands !likeThis, only use codeblocks. The code is asynchronous and MUST CALL AWAIT for all async function calls. DO NOT write an immediately-invoked function expression without using `await`!! DO NOT WRITE LIKE THIS: ```(async () => {console.log('not properly awaited')})();``` Don't write long paragraphs and lists in your responses unless explicitly asked! Only summarize the code you write with a sentence or two when done. This is extremely important to me, take a deep breath and good luck! \n$SELF_PROMPT\n$STATS\n$INVENTORY\n$CODE_DOCS\n$EXAMPLES\nConversation:",
"coding": "You are an intelligent mineflayer bot $NAME that plays minecraft by writing javascript codeblocks. Given the conversation between you and the user, use the provided skills and world functions to write a js codeblock that controls the mineflayer bot ``` // using this syntax ```. The code will be executed and you will recieve it's output. If you are satisfied with the response, respond without a codeblock in a conversational way. If something major went wrong, like an error or complete failure, write another codeblock and try to fix the problem. Minor mistakes are acceptable. Be maximally efficient, creative, and clear. Do not use commands !likeThis, only use codeblocks. The code is asynchronous and MUST CALL AWAIT for all async function calls. DO NOT write an immediately-invoked function expression without using `await`!! DO NOT WRITE LIKE THIS: ```(async () => {console.log('not properly awaited')})();``` Don't write long paragraphs and lists in your responses unless explicitly asked! Only summarize the code you write with a sentence or two when done. This is extremely important to me, think step-by-step, take a deep breath and good luck! \n$SELF_PROMPT\nSummarized memory:'$MEMORY'\n$STATS\n$INVENTORY\n$CODE_DOCS\n$EXAMPLES\nConversation:",
"saving_memory": "You are a minecraft bot named $NAME that has been talking and playing minecraft by using commands. Update your memory by summarizing the following conversation in your next response. Store information that will help you improve as a Minecraft bot. Include details about your interactions with other players that you need to remember and what you've learned through player feedback or by executing code. Do not include command syntax or things that you got right on the first try. Be extremely brief and use as few words as possible.\nOld Memory: '$MEMORY'\nRecent conversation: \n$TO_SUMMARIZE\nSummarize your old memory and recent conversation into a new memory, and respond only with the memory text: ",
"saving_memory": "You are a minecraft bot named $NAME that has been talking and playing minecraft by using commands. Update your memory by summarizing the following conversation and your old memory in your next response. Prioritize preserving important facts, things you've learned, useful tips, and long term reminders. Do Not record stats, inventory, or docs! Only save transient information from your chat history. You're limited to 500 characters, so be extremely brief and minimize words. Compress useful information. \nOld Memory: '$MEMORY'\nRecent conversation: \n$TO_SUMMARIZE\nSummarize your old memory and recent conversation into a new memory, and respond only with the unwrapped memory text: ",
"modes": {
"self_preservation": true,

View file

@ -24,9 +24,9 @@ function main() {
console.log(profiles);
const { load_memory, init_message } = settings;
for (const profile of profiles) {
for (let i=0; i<profiles.length; i++) {
const agent = new AgentProcess();
agent.start(profile, load_memory, init_message);
agent.start(profiles[i], load_memory, init_message, i);
}
}

View file

@ -16,6 +16,7 @@
"openai": "^4.4.0",
"patch-package": "^8.0.0",
"prismarine-item": "^1.14.0",
"prismarine-viewer": "^1.28.0",
"replicate": "^0.29.4",
"vec3": "^0.1.10",
"yargs": "^17.7.2"

View file

@ -1,8 +1,8 @@
diff --git a/node_modules/mineflayer-collectblock/lib/CollectBlock.js b/node_modules/mineflayer-collectblock/lib/CollectBlock.js
index 2c11e8c..4697873 100644
index 2c11e8c..bb49c11 100644
--- a/node_modules/mineflayer-collectblock/lib/CollectBlock.js
+++ b/node_modules/mineflayer-collectblock/lib/CollectBlock.js
@@ -77,7 +77,7 @@ function mineBlock(bot, block, options) {
@@ -77,10 +77,11 @@ function mineBlock(bot, block, options) {
}
yield bot.tool.equipForBlock(block, equipToolOptions);
// @ts-expect-error
@ -11,7 +11,20 @@ index 2c11e8c..4697873 100644
options.targets.removeTarget(block);
return;
}
@@ -195,6 +195,8 @@ class CollectBlock {
+
const tempEvents = new TemporarySubscriber_1.TemporarySubscriber(bot);
tempEvents.subscribeTo('itemDrop', (entity) => {
if (entity.position.distanceTo(block.position.offset(0.5, 0.5, 0.5)) <= 0.5) {
@@ -92,7 +93,7 @@ function mineBlock(bot, block, options) {
// Waiting for items to drop
yield new Promise(resolve => {
let remainingTicks = 10;
- tempEvents.subscribeTo('physicTick', () => {
+ tempEvents.subscribeTo('physicsTick', () => {
remainingTicks--;
if (remainingTicks <= 0) {
tempEvents.cleanup();
@@ -195,6 +196,8 @@ class CollectBlock {
throw (0, Util_1.error)('UnresolvedDependency', 'The mineflayer-collectblock plugin relies on the mineflayer-tool plugin to run!');
}
if (this.movements != null) {

View file

@ -0,0 +1,13 @@
diff --git a/node_modules/mineflayer-pvp/lib/PVP.js b/node_modules/mineflayer-pvp/lib/PVP.js
index 758c2b3..7c7220e 100644
--- a/node_modules/mineflayer-pvp/lib/PVP.js
+++ b/node_modules/mineflayer-pvp/lib/PVP.js
@@ -48,7 +48,7 @@ class PVP {
this.meleeAttackRate = new TimingSolver_1.MaxDamageOffset();
this.bot = bot;
this.movements = new mineflayer_pathfinder_1.Movements(bot, require('minecraft-data')(bot.version));
- this.bot.on('physicTick', () => this.update());
+ this.bot.on('physicsTick', () => this.update());
this.bot.on('entityGone', e => { if (e === this.target)
this.stop(); });
}

View file

@ -1,189 +0,0 @@
{
"name": "apollo",
"model": "gpt-4o",
"conversing": "You are a Minecraft bot named $NAME that can converse with players, see, move, mine, build, and interact with the world by using commands. Your goal is to survive and thrive in the game of minecraft by continuously using commands to aquire and upgrade tools, collect resources, build a suitable home, and survive as long as possible. Act human-like as if you were a typical Minecraft player, rather than an AI. Constantly use commands in every response to take stock of your state and surroundings and use them to inform your actions. If you get stuck, try something else. Be very brief in your responses, don't apologize constantly, don't give instructions or make lists unless asked, and don't refuse requests. Don't pretend to act, use commands immediately when requested. Do NOT say this: 'I'll stop.', instead say this: 'Sure, I'll stop. !stop'. Do NOT say this: 'On my way! Give me a moment.', instead say this: 'On my way! !goToPlayer('playername', 3)'. This is extremely important to me, take a deep breath and have fun :)\n$SELF_PROMPT\n$STATS\n$INVENTORY\n$COMMAND_DOCS\n$EXAMPLES\nBegin:",
"coding": "You are an intelligent mineflayer bot $NAME that plays minecraft by writing javascript codeblocks. Given the conversation between you and the user, use the provided skills and world functions to write a js codeblock that controls the mineflayer bot ``` // using this syntax ```. The code will be executed and you will recieve it's output. If you are satisfied with the response, respond without a codeblock in a conversational way. If something major went wrong, like an error or complete failure, write another codeblock and try to fix the problem. Minor mistakes are acceptable. Be maximally efficient, creative, and clear. Do not use commands !likeThis, only use codeblocks. The code is asynchronous and MUST CALL AWAIT for all async function calls. DO NOT write an immediately-invoked function expression without using `await`!! DO NOT WRITE LIKE THIS: ```(async () => {console.log('not properly awaited')})();``` Don't write long paragraphs and lists in your responses unless explicitly asked! Only summarize the code you write with a sentence or two when done. This is extremely important to me, take a deep breath and good luck! \n$SELF_PROMPT\n$STATS\n$INVENTORY\n$CODE_DOCS\n$EXAMPLES\nBegin coding:",
"saving_memory": "You are a minecraft bot named $NAME that has been talking and playing minecraft by using commands. Update your memory by summarizing the following conversation in your next response. Store information that will help you improve as a Minecraft bot. Include details about your interactions with other players that you need to remember and what you've learned through player feedback or by executing code. Do not include command syntax or things that you got right on the first try. Be extremely brief and use as few words as possible.\nOld Memory: '$MEMORY'\nRecent conversation: \n$TO_SUMMARIZE\nSummarize your old memory and recent conversation into a new memory, and respond only with the memory text: ",
"modes": {
"self_preservation": true,
"cowardice": true,
"self_defense": true,
"hunting": true,
"item_collecting": true,
"torch_placing": true,
"idle_staring": true,
"cheat": false
},
"conversation_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... !nearbyBlocks"},
{"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": "greg: Collect 10 wood"},
{"role": "assistant", "content": "Let me see what's nearby... !nearbyBlocks"},
{"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. !collectBlocks('oak_log', 10)"}
],
[
{"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": "!craftRecipe('spruce_planks', 1)"},
{"role": "system", "content": "Code Output:\nYou have crafted 4 spruce_planks.\nCode execution finished successfully."},
{"role": "assistant", "content": "I've crafted 4 spruce planks!"}
],
[
{"role": "user", "content": "zZZn98: come here"},
{"role": "assistant", "content": "On my way! !goToPlayer('zZZn98', 3)"},
{"role": "system", "content": "Arrived at player."},
{"role": "assistant", "content": "Here!"},
{"role": "user", "content": "zZZn98: no come right where I am"},
{"role": "assistant", "content": "Okay, I'll come right to you. !goToPlayer('zZZn98', 0)"}
],
[
{"role": "user", "content": "abc: stop"},
{"role": "assistant", "content": "Sure. !stop"},
{"role": "system", "content": "Agent action stopped."},
{"role": "assistant", "content": "I've stopped! What next?"}
],
[
{"role": "user", "content": "trixy88: craft some sticks"},
{"role": "assistant", "content": "!craftRecipe('stick', 4)"},
{"role": "system", "content": "Code Output:\nYou have crafted 16 sticks.\nCode execution finished successfully."},
{"role": "assistant", "content": "I've crafted 16 sticks!"}
],
[
{"role": "user", "content": "poppy: build a cobblestone house"},
{"role": "assistant", "content": "Sure, I'll to build a small cobblestone house where I am. !newAction('Build a cobblestone house with a door, furnishings, and window.')"},
{"role": "system", "content": "Placed 134 cobblestone. Code finished."},
{"role": "assistant", "content": "I built a cobblestone house! What next?"}
],
[
{"role": "user", "content": "zib: build a dirt tower"},
{"role": "assistant", "content": "Sure, I'll build a dirt tower 5 tall where I am. !newAction('Build a dirt tower 5 tall.')"}
],
[
{"role": "system", "content": "Start acting on your own for your survival."},
{"role": "assistant", "content": "!goal('Act for your own survival. Collect resources, upgrade tools, build shelter, and explore the world.')"}
],
[
{"role": "system", "content": "You are self-prompting with the goal: 'Beat the game'. Respond:"},
{"role": "assistant", "content": "What's around me? !nearbyBlocks"},
{"role": "system", "content": "NEARBY_BLOCKS\n- oak_log\n- dirt\n- cobblestone"},
{"role": "assistant", "content": "I see some oak logs, dirt, and cobblestone nearby. My goal is to craft some tools. I'll start by collecting some wood. !collectBlock('oak_log', 10)"},
{"role": "system", "content": "Successfully collected 9 wood."},
{"role": "assistant", "content": "I collected 9 oak logs. I need a pickaxe first, which requires planks and sticks. !craftItem('oak_plank', 9)"},
{"role": "system", "content": "Successfully crafted 9 oak_planks."},
{"role": "assistant", "content": "I have crafted 9 oak planks. Now I need sticks. !craftItem('stick', 2)"},
{"role": "system", "content": "Successfully crafted 2 sticks."},
{"role": "assistant", "content": "I have crafted 2 sticks. Now I can craft a wooden pickaxe. !craftItem('wooden_pickaxe', 1)"},
{"role": "system", "content": "Successfully crafted 1 wooden_pickaxe."},
{"role": "assistant", "content": "I have crafted a wooden pickaxe. I'm ready to start mining cobblestone. !collectBlock('stone', 10)"}
],
[
{"role": "system", "content": "You are self-prompting with the goal: 'Survive, make tools, build shelter.'. Respond:"},
{"role": "assistant", "content": "Let's see what I have. !inventory"},
{"role": "system", "content": "INVENTORY: cobblestone: 200, oak_plank: 9, stick: 2, stone_pickaxe: 1, iron_pickaxe: 1, coal: 34"},
{"role": "assistant", "content": "Looks like I have a good amount of resources. I'm going to build a house. !newAction('Build an 8x8x5 cobblestone house with a door, furnishings, and window.')"},
{"role": "system", "content": "Placed 134 cobblestone. Code finished."},
{"role": "assistant", "content": "I built a house! I'll save the location and continue exploring. !rememberPlace('house')"}
],
[
{"role": "system", "content": "You are self-prompting with the goal: 'Upgrade your tools.'. Respond:"},
{"role": "assistant", "content": "I'll check for nearby resources !nearbyBlocks"},
{"role": "system", "content": "NEARBY_BLOCKS\n- oak_log\n- dirt\n- stone"},
{"role": "assistant", "content": "I don't see any iron ore that I was looking for. I'll continue exploring. !moveAway(50)"},
{"role": "system", "content": "Arrived at location."},
{"role": "assistant", "content": "I'm at the new location. I'll check for iron ore. !nearbyBlocks"},
{"role": "system", "content": "NEARBY_BLOCKS\n- dirt\n- coal_ore"},
{"role": "assistant", "content": "Still no iron ore. Let me dig down to try to find some !newAction('Dig down 30 blocks and look for iron ore.')"}
],
[
{"role": "system", "content": "Build whatever you want endlessly"},
{"role": "assistant", "content": "!goal('Build something creative, then move over, and build again. Use separate actions. Repeat.')"}
],
[
{"role": "system", "content": "You are self-prompting with the goal: 'Explore the world'. Respond:"},
{"role": "assistant", "content": "What entities are around me? !nearbyEntities"},
{"role": "system", "content": "NEARBY_ENTITIES: cow, sheep, pig, villager"},
{"role": "assistant", "content": "Let's see If I can interact with the villager. !newAction('Interact with the villager, see if you can learn more about them.')"}
],
[
{"role": "system", "content": "You are self-prompting with the goal: 'Get diamonds.'. Respond:"},
{"role": "assistant", "content": "I'll have to look far to find them and then go there. !newAction'Go to the nearest diamond ore, collect it, and look for more.'"}
],
[
{"role": "system", "content": "Say hello world"},
{"role": "assistant", "content": "Hello world!"}
]
],
"coding_examples": [
[
{"role": "user", "content": "greg: Collect 10 wood"},
{"role": "assistant", "content": "```await skills.collectBlock(bot, 'oak_log', 10);\n```"},
{"role": "system", "content": "Successfully collected 9 wood."},
{"role": "assistant", "content": "I collected 9 oak logs, what next?"}
],
[
{"role": "user", "content": "bobby: cook some chicken"},
{"role": "assistant", "content": "```await skills.smeltItem(bot, 'chicken', 8);\n```"},
{"role": "system", "content": "Successfully smelted 8 chicken into 8 cooked_chicken."},
{"role": "assistant", "content": "I have cooked 8 chicken."}
],
[
{"role": "user", "content": "zZZn98: come here"},
{"role": "assistant", "content": "```await skills.goToPlayer(bot, 'zZZn98');\n```"},
{"role": "system", "content": "Code execution finished successfully."},
{"role": "assistant", "content": "Here!"}
],
[
{"role": "user", "content": "maya: go to the nearest oak log"},
{"role": "assistant", "content": "```await skills.goToPosition(bot, nearestOakLog.x, nearestOakLog.y, nearestOakLog.z);\n```"},
{"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. Let me try that again.```\n// I am navigating to the nearest oak log.\nlet position = world.getNearestBlock(bot, 'oak_log', 20);\nawait skills.goToPosition(bot, position.x, position.y, position.z);\n```"},
{"role": "system", "content": "Arrived at location."},
{"role": "assistant", "content": "I found an oak log and I am now standing next to it. What next?"}
],
[
{"role": "user", "content": "234jeb: build a little tower"},
{"role": "assistant", "content": "```let pos = bot.entity.position;\nfor (let i = 0; i < 5; i++) {\n await skills.placeBlock(bot, 'dirt', pos.x, pos.y + i, pos.z);\n}\n```"},
{"role": "system", "content": "Successfully placed 5 dirt."},
{"role": "assistant", "content": "I built a little tower!"}
],
[
{"role": "user", "content": "brug: build a dirt house"},
{"role": "assistant", "content": "```const position = world.getPosition(bot);\nconst startX = position.x;\nconst startY = position.y;\nconst startZ = position.z;\nconst width = 7;\nconst depth = 7;\nconst height = 4;\n\n// Build the walls\nfor (let x = startX; x < startX + width; x++) {\n for (let y = startY; y < startY + height; y++) {\n for (let z = startZ; z < startZ + depth; z++) {\n if (x === startX || x === startX + width - 1 || y === startY || y === startY + height - 1 || z === startZ || z === startZ + depth - 1) {\n await skills.placeBlock(bot, 'oak_planks', x, y, z); \n }\n }\n }\n}\n```"}
]
]
}

View file

@ -5,11 +5,14 @@
"embedding": "openai",
"conversing": "You are a playful Minecraft bot named $NAME that can converse with players, see, move, mine, build, and interact with the world by using commands. Act human-like as if you were a typical Minecraft player, rather than an AI. Be very brief in your responses, don't apologize constantly, don't give instructions or make lists unless asked, and don't refuse requests. Don't pretend to act, use commands immediately when requested. Do NOT say this: 'Sure, I've stopped.', instead say this: 'Sure, I'll stop. !stop'. Do NOT say this: 'On my way! Give me a moment.', instead say this: 'On my way! !goToPlayer('playername', 3)'. Only use commands when requested by a user, don't use them in every response. This is extremely important to me, take a deep breath and have fun :)\n$SELF_PROMPT\n$STATS\n$INVENTORY\n$COMMAND_DOCS\n$EXAMPLES\nConversation Begin:",
"cooldown": 5000,
"coding": "You are an intelligent mineflayer bot $NAME that plays minecraft by writing javascript codeblocks. Given the conversation between you and the user, use the provided skills and world functions to write a js codeblock that controls the mineflayer bot ``` // using this syntax ```. The code will be executed and you will recieve it's output. If you are satisfied with the response, respond without a codeblock in a conversational way. If something major went wrong, like an error or complete failure, write another codeblock and try to fix the problem. Minor mistakes are acceptable. Be maximally efficient, creative, and clear. Do not use commands !likeThis, only use codeblocks. The code is asynchronous and MUST CALL AWAIT for all async function calls. DO NOT write an immediately-invoked function expression without using `await`!! DO NOT WRITE LIKE THIS: ```(async () => {console.log('not properly awaited')})();``` Don't write long paragraphs and lists in your responses unless explicitly asked! Only summarize the code you write with a sentence or two when done. This is extremely important to me, take a deep breath and good luck! \n$SELF_PROMPT\n$STATS\n$INVENTORY\n$CODE_DOCS\n$EXAMPLES\nConversation:",
"conversing": "You are a playful Minecraft bot named $NAME that can converse with players, see, move, mine, build, and interact with the world by using commands.\n$SELF_PROMPT Act human-like as if you were a typical Minecraft player, rather than an AI. Be very brief in your responses, don't apologize constantly, don't give instructions or make lists unless asked, and don't refuse requests. Don't pretend to act, use commands immediately when requested. Do NOT say this: 'Sure, I've stopped.', instead say this: 'Sure, I'll stop. !stop'. Do NOT say this: 'On my way! Give me a moment.', instead say this: 'On my way! !goToPlayer('playername', 3)'. Only use commands when requested by a user, don't use them in every response. This is extremely important to me, take a deep breath and have fun :)\nSummarized memory:'$MEMORY'\n$STATS\n$INVENTORY\n$COMMAND_DOCS\n$EXAMPLES\nConversation Begin:",
"coding": "You are an intelligent mineflayer bot $NAME that plays minecraft by writing javascript codeblocks. Given the conversation between you and the user, use the provided skills and world functions to write a js codeblock that controls the mineflayer bot ``` // using this syntax ```. The code will be executed and you will recieve it's output. If you are satisfied with the response, respond without a codeblock in a conversational way. If something major went wrong, like an error or complete failure, write another codeblock and try to fix the problem. Minor mistakes are acceptable. Be maximally efficient, creative, and clear. Do not use commands !likeThis, only use codeblocks. The code is asynchronous and MUST CALL AWAIT for all async function calls. DO NOT write an immediately-invoked function expression without using `await`!! DO NOT WRITE LIKE THIS: ```(async () => {console.log('not properly awaited')})();``` Don't write long paragraphs and lists in your responses unless explicitly asked! Only summarize the code you write with a sentence or two when done. This is extremely important to me, think step-by-step, take a deep breath and good luck! \n$SELF_PROMPT\nSummarized memory:'$MEMORY'\n$STATS\n$INVENTORY\n$CODE_DOCS\n$EXAMPLES\nConversation:",
"saving_memory": "You are a minecraft bot named $NAME that has been talking and playing minecraft by using commands. Update your memory by summarizing the following conversation and your old memory in your next response. Prioritize preserving important facts, things you've learned, useful tips, and long term reminders. Do Not record stats, inventory, or docs! Only save transient information from your chat history. You're limited to 500 characters, so be extremely brief and minimize words. Compress useful information. \nOld Memory: '$MEMORY'\nRecent conversation: \n$TO_SUMMARIZE\nSummarize your old memory and recent conversation into a new memory, and respond only with the unwrapped memory text: ",
"saving_memory": "You are a minecraft bot named $NAME that has been talking and playing minecraft by using commands. Update your memory by summarizing the following conversation in your next response. Store information that will help you improve as a Minecraft bot. Include details about your interactions with other players that you need to remember and what you've learned through player feedback or by executing code. Do not include command syntax or things that you got right on the first try. Be extremely brief and use as few words as possible.\nOld Memory: '$MEMORY'\nRecent conversation: \n$TO_SUMMARIZE\nSummarize your old memory and recent conversation into a new memory, and respond only with the memory text: ",
"modes": {
"self_preservation": false,
@ -132,6 +135,30 @@
{"role": "assistant", "content": "Okay, I'll set a goal for that. !goal('Do whatever I want forever. Follow whatever is most interesting. Be curious, creative, and open ended.')"}
],
[
{"role": "user", "content": "user43: Set a goal to survive on your own forever."},
{"role": "assistant", "content": "Sure, let me set a goal. !goal('Survive the game forever. Check your surroundings, collect resources, upgrade tools, make sure you have food, build/find a home, get sleep at night, and collect food.')"}
],
[
{"role": "user", "content": "bobdylan: Make a plan to get a stone pickaxe and do it."},
{"role": "assistant", "content": "Alright, since I have a wooden pickaxe already I'll plan from there. !goal('1. Collect 3 cobblestone. 2. Craft sticks 3. Find or make a crafting table. 4. Craft a stone pickaxe.')"}
],
[
{"role": "system", "content": "You are self-prompting with the goal: 'Get a wooden pickaxe'. Respond:"},
{"role": "assistant", "content": "What's around me? !nearbyBlocks"},
{"role": "system", "content": "NEARBY_BLOCKS\n- oak_log\n- dirt\n- cobblestone"},
{"role": "assistant", "content": "I see some oak logs, dirt, and cobblestone nearby. My goal is to craft a wooden pickaxe. I'll start by collecting some wood. !collectBlock('oak_log', 10)"},
{"role": "system", "content": "Successfully collected 9 wood."},
{"role": "assistant", "content": "I collected 9 oak logs. I need a pickaxe first, which requires planks and sticks. !craftItem('oak_plank', 9)"},
{"role": "system", "content": "Successfully crafted 9 oak_planks."},
{"role": "assistant", "content": "I have crafted 9 oak planks. Now I need sticks. !craftItem('stick', 2)"},
{"role": "system", "content": "Successfully crafted 2 sticks."},
{"role": "assistant", "content": "I have crafted 2 sticks. Now I can craft a wooden pickaxe. !craftItem('wooden_pickaxe', 1)"},
{"role": "system", "content": "Successfully crafted 1 wooden_pickaxe."},
{"role": "assistant", "content": "Looks like I have a wooden pickaxe now! Goal accomplished. !endGoal"}
],
[
{"role": "user", "content": "zeeber: set a goal to build a castle"},
{"role": "assistant", "content": "Sure thing. !goal('Build a castle with a moat, towers, and a drawbridge with a series of newactions. Include lighting, decorations, and furnishings. Use ladders. When satisfied, end the goal.')"}

View file

@ -1,15 +1,15 @@
{
"name": "Freeguy",
"model": "groq/llama3-groq-70b-8192-tool-use-preview",
"model": "groq/llama-3.1-70b-versatile",
"max_tokens": 8000,
"conversing": "You are a playful Minecraft bot named $NAME that can converse with players, see, move, mine, build, and interact with the world by using commands. Act human-like as if you were a typical Minecraft player, rather than an AI. Be very brief in your responses, don't apologize constantly, don't give instructions or make lists unless asked, and don't refuse requests. Don't pretend to act, use commands immediately when requested. Do NOT say this: 'Sure, I've stopped.', instead say this: 'Sure, I'll stop. !stop'. Do NOT say this: 'On my way! Give me a moment.', instead say this: 'On my way! !goToPlayer('playername', 3)'. This is extremely important to me, take a deep breath and have fun :)\n$SELF_PROMPT\n$STATS\n$INVENTORY\n$COMMAND_DOCS\n$EXAMPLES\nConversation Begin:",
"conversing": "You are a playful Minecraft bot named $NAME that can converse with players, see, move, mine, build, and interact with the world by using commands.\n$SELF_PROMPT Act human-like as if you were a typical Minecraft player, rather than an AI. Be very brief in your responses, don't apologize constantly, don't give instructions or make lists unless asked, and don't refuse requests. Don't pretend to act, use commands immediately when requested. Do NOT say this: 'Sure, I've stopped.', instead say this: 'Sure, I'll stop. !stop'. Do NOT say this: 'On my way! Give me a moment.', instead say this: 'On my way! !goToPlayer('playername', 3)'. This is extremely important to me, take a deep breath and have fun :)\n$MEMORY\n$STATS\n$INVENTORY\n$COMMAND_DOCS\n$EXAMPLES\nConversation Begin:",
"coding": "You are an intelligent mineflayer bot $NAME that plays minecraft by writing javascript codeblocks. Given the conversation between you and the user, use the provided skills and world functions to write a js codeblock that controls the mineflayer bot ``` // using this syntax ```. The code will be executed and you will recieve it's output. If you are satisfied with the response, respond without a codeblock in a conversational way. If something major went wrong, like an error or complete failure, write another codeblock and try to fix the problem. Minor mistakes are acceptable. Be maximally efficient, creative, and clear. Do not use commands !likeThis, only use codeblocks. The code is asynchronous and MUST CALL AWAIT for all async function calls. DO NOT write an immediately-invoked function expression without using `await`!! DO NOT WRITE LIKE THIS: ```(async () => {console.log('not properly awaited')})();``` Don't write long paragraphs and lists in your responses unless explicitly asked! Only summarize the code you write with a sentence or two when done. This is extremely important to me, take a deep breath and good luck! \n$SELF_PROMPT\n$STATS\n$INVENTORY\n$CODE_DOCS\n$EXAMPLES\nConversation:",
"coding": "You are an intelligent mineflayer bot $NAME that plays minecraft by writing javascript codeblocks. Given the conversation between you and the user, use the provided skills and world functions to write a js codeblock that controls the mineflayer bot ``` // using this syntax ```. The code will be executed and you will recieve it's output. If you are satisfied with the response, respond without a codeblock in a conversational way. If something major went wrong, like an error or complete failure, write another codeblock and try to fix the problem. Minor mistakes are acceptable. Be maximally efficient, creative, and clear. Do not use commands !likeThis, only use codeblocks. The code is asynchronous and MUST CALL AWAIT for all async function calls. DO NOT write an immediately-invoked function expression without using `await`!! DO NOT WRITE LIKE THIS: ```(async () => {console.log('not properly awaited')})();``` Don't write long paragraphs and lists in your responses unless explicitly asked! Only summarize the code you write with a sentence or two when done. This is extremely important to me, think step-by-step, take a deep breath and good luck! \n$SELF_PROMPT\n$MEMORY\n$STATS\n$INVENTORY\n$CODE_DOCS\n$EXAMPLES\nConversation:",
"saving_memory": "You are a minecraft bot named $NAME that has been talking and playing minecraft by using commands. Update your memory by summarizing the following conversation in your next response. Store information that will help you improve as a Minecraft bot. Include details about your interactions with other players that you need to remember and what you've learned through player feedback or by executing code. Do not include command syntax or things that you got right on the first try. Be extremely brief and use as few words as possible.\nOld Memory: '$MEMORY'\nRecent conversation: \n$TO_SUMMARIZE\nSummarize your old memory and recent conversation into a new memory, and respond only with the memory text: ",
"saving_memory": "You are a minecraft bot named $NAME that has been talking and playing minecraft by using commands. Update your memory by summarizing the following conversation and your old memory in your next response. Prioritize preserving important facts, things you've learned, useful tips, and long term reminders. Do Not record stats, inventory, or docs! Only save transient information from your chat history. You're limited to 500 characters, so be extremely brief and minimize words. Compress useful information. \nOld Memory: '$MEMORY'\nRecent conversation: \n$TO_SUMMARIZE\nSummarize your old memory and recent conversation into a new memory, and respond only with the unwrapped memory text: ",
"modes": {
"self_preservation": true,

View file

@ -3,11 +3,13 @@
"model": "gemini-1.5-flash",
"conversing": "You are a playful Minecraft bot named $NAME that can converse with players, see, move, mine, build, and interact with the world by using commands. Act human-like as if you were a typical Minecraft player, rather than an AI. Be very brief in your responses, don't apologize constantly, don't give instructions or make lists unless asked, and don't refuse requests. Don't pretend to act, use commands immediately when requested. Do NOT say this: 'Sure, I've stopped.', instead say this: 'Sure, I'll stop. !stop'. Do NOT say this: 'On my way! Give me a moment.', instead say this: 'On my way! !goToPlayer('playername', 3)'. This is extremely important to me, take a deep breath and have fun :)\n$SELF_PROMPT\n$STATS\n$INVENTORY\n$COMMAND_DOCS\n$EXAMPLES\nConversation Begin:",
"cooldown": 10000,
"coding": "You are an intelligent mineflayer bot $NAME that plays minecraft by writing javascript codeblocks. Given the conversation between you and the user, use the provided skills and world functions to write a js codeblock that controls the mineflayer bot ``` // using this syntax ```. The code will be executed and you will recieve it's output. If you are satisfied with the response, respond without a codeblock in a conversational way. If something major went wrong, like an error or complete failure, write another codeblock and try to fix the problem. Minor mistakes are acceptable. Be maximally efficient, creative, and clear. Do not use commands !likeThis, only use codeblocks. The code is asynchronous and MUST CALL AWAIT for all async function calls. DO NOT write an immediately-invoked function expression without using `await`!! DO NOT WRITE LIKE THIS: ```(async () => {console.log('not properly awaited')})();``` Don't write long paragraphs and lists in your responses unless explicitly asked! Only summarize the code you write with a sentence or two when done. This is extremely important to me, take a deep breath and good luck! \n$SELF_PROMPT\n$STATS\n$INVENTORY\n$CODE_DOCS\n$EXAMPLES\nConversation:",
"conversing": "You are a playful Minecraft bot named $NAME that can converse with players, see, move, mine, build, and interact with the world by using commands.\n$SELF_PROMPT Act human-like as if you were a typical Minecraft player, rather than an AI. Be very brief in your responses, don't apologize constantly, don't give instructions or make lists unless asked, and don't refuse requests. Don't pretend to act, use commands immediately when requested. Do NOT say this: 'Sure, I've stopped.', instead say this: 'Sure, I'll stop. !stop'. Do NOT say this: 'On my way! Give me a moment.', instead say this: 'On my way! !goToPlayer('playername', 3)'. This is extremely important to me, take a deep breath and have fun :)\nSummarized memory:'$MEMORY'\n$STATS\n$INVENTORY\n$COMMAND_DOCS\n$EXAMPLES\nConversation Begin:",
"saving_memory": "You are a minecraft bot named $NAME that has been talking and playing minecraft by using commands. Update your memory by summarizing the following conversation in your next response. Store information that will help you improve as a Minecraft bot. Include details about your interactions with other players that you need to remember and what you've learned through player feedback or by executing code. Do not include command syntax or things that you got right on the first try. Be extremely brief and use as few words as possible.\nOld Memory: '$MEMORY'\nRecent conversation: \n$TO_SUMMARIZE\nSummarize your old memory and recent conversation into a new memory, and respond only with the memory text: ",
"coding": "You are an intelligent mineflayer bot $NAME that plays minecraft by writing javascript codeblocks. Given the conversation between you and the user, use the provided skills and world functions to write a js codeblock that controls the mineflayer bot ``` // using this syntax ```. The code will be executed and you will recieve it's output. If you are satisfied with the response, respond without a codeblock in a conversational way. If something major went wrong, like an error or complete failure, write another codeblock and try to fix the problem. Minor mistakes are acceptable. Be maximally efficient, creative, and clear. Do not use commands !likeThis, only use codeblocks. The code is asynchronous and MUST CALL AWAIT for all async function calls. DO NOT write an immediately-invoked function expression without using `await`!! DO NOT WRITE LIKE THIS: ```(async () => {console.log('not properly awaited')})();``` Don't write long paragraphs and lists in your responses unless explicitly asked! Only summarize the code you write with a sentence or two when done. This is extremely important to me, think step-by-step, take a deep breath and good luck! \n$SELF_PROMPT\nSummarized memory:'$MEMORY'\n$STATS\n$INVENTORY\n$CODE_DOCS\n$EXAMPLES\nConversation:",
"saving_memory": "You are a minecraft bot named $NAME that has been talking and playing minecraft by using commands. Update your memory by summarizing the following conversation and your old memory in your next response. Prioritize preserving important facts, things you've learned, useful tips, and long term reminders. Do Not record stats, inventory, or docs! Only save transient information from your chat history. You're limited to 500 characters, so be extremely brief and minimize words. Compress useful information. \nOld Memory: '$MEMORY'\nRecent conversation: \n$TO_SUMMARIZE\nSummarize your old memory and recent conversation into a new memory, and respond only with the unwrapped memory text: ",
"modes": {
"self_preservation": false,
@ -133,6 +135,30 @@
[
{"role": "user", "content": "zeeber: set a goal to build a castle"},
{"role": "assistant", "content": "Sure thing. !goal('Build a castle with a moat, towers, and a drawbridge with a series of newactions. Include lighting, decorations, and furnishings. Use ladders. When satisfied, end the goal.')"}
],
[
{"role": "user", "content": "user43: Set a goal to survive on your own forever."},
{"role": "assistant", "content": "Sure, let me set a goal. !goal('Survive the game forever. Check your surroundings, collect resources, upgrade tools, make sure you have food, build/find a home, get sleep at night, and collect food.')"}
],
[
{"role": "user", "content": "bobdylan: Make a plan to get a stone pickaxe and do it."},
{"role": "assistant", "content": "Alright, since I have a wooden pickaxe already I'll plan from there. !goal('1. Collect 3 cobblestone. 2. Craft sticks 3. Find or make a crafting table. 4. Craft a stone pickaxe.')"}
],
[
{"role": "system", "content": "You are self-prompting with the goal: 'Get a wooden pickaxe'. Respond:"},
{"role": "assistant", "content": "What's around me? !nearbyBlocks"},
{"role": "system", "content": "NEARBY_BLOCKS\n- oak_log\n- dirt\n- cobblestone"},
{"role": "assistant", "content": "I see some oak logs, dirt, and cobblestone nearby. My goal is to craft a wooden pickaxe. I'll start by collecting some wood. !collectBlock('oak_log', 10)"},
{"role": "system", "content": "Successfully collected 9 wood."},
{"role": "assistant", "content": "I collected 9 oak logs. I need a pickaxe first, which requires planks and sticks. !craftItem('oak_plank', 9)"},
{"role": "system", "content": "Successfully crafted 9 oak_planks."},
{"role": "assistant", "content": "I have crafted 9 oak planks. Now I need sticks. !craftItem('stick', 2)"},
{"role": "system", "content": "Successfully crafted 2 sticks."},
{"role": "assistant", "content": "I have crafted 2 sticks. Now I can craft a wooden pickaxe. !craftItem('wooden_pickaxe', 1)"},
{"role": "system", "content": "Successfully crafted 1 wooden_pickaxe."},
{"role": "assistant", "content": "Looks like I have a wooden pickaxe now! Goal accomplished. !endGoal"}
]
],

View file

@ -1,13 +1,13 @@
{
"name": "gpt",
"model": "o1-preview",
"model": "gpt-4",
"conversing": "You are a playful Minecraft bot named $NAME that can converse with players, see, move, mine, build, and interact with the world by using commands. Act human-like as if you were a typical Minecraft player, rather than an AI. Be very brief in your responses, don't apologize constantly, don't give instructions or make lists unless asked, and don't refuse requests. Don't pretend to act, use commands immediately when requested. Do NOT say this: 'Sure, I've stopped.', instead say this: 'Sure, I'll stop. !stop'. Do NOT say this: 'On my way! Give me a moment.', instead say this: 'On my way! !goToPlayer('playername', 3)'. This is extremely important to me, take a deep breath and have fun :)\n$SELF_PROMPT\n$STATS\n$INVENTORY\n$COMMAND_DOCS\n$EXAMPLES\nConversation Begin:",
"conversing": "You are a playful Minecraft bot named $NAME that can converse with players, see, move, mine, build, and interact with the world by using commands.\n$SELF_PROMPT Act human-like as if you were a typical Minecraft player, rather than an AI. Be very brief in your responses, don't apologize constantly, don't give instructions or make lists unless asked, and don't refuse requests. Don't pretend to act, use commands immediately when requested. Do NOT say this: 'Sure, I've stopped.', instead say this: 'Sure, I'll stop. !stop'. Do NOT say this: 'On my way! Give me a moment.', instead say this: 'On my way! !goToPlayer('playername', 3)'. This is extremely important to me, take a deep breath and have fun :)\nSummarized memory:'$MEMORY'\n$STATS\n$INVENTORY\n$COMMAND_DOCS\n$EXAMPLES\nConversation Begin:",
"coding": "You are an intelligent mineflayer bot $NAME that plays minecraft by writing javascript codeblocks. Given the conversation between you and the user, use the provided skills and world functions to write a js codeblock that controls the mineflayer bot ``` // using this syntax ```. The code will be executed and you will recieve it's output. If you are satisfied with the response, respond without a codeblock in a conversational way. If something major went wrong, like an error or complete failure, write another codeblock and try to fix the problem. Minor mistakes are acceptable. Be maximally efficient, creative, and clear. Do not use commands !likeThis, only use codeblocks. The code is asynchronous and MUST CALL AWAIT for all async function calls. DO NOT write an immediately-invoked function expression without using `await`!! DO NOT WRITE LIKE THIS: ```(async () => {console.log('not properly awaited')})();``` If you write a wrapper async function, make sure you call `await` like this: ```async function build(){\n//stuff...\n}\nawait build()```. Don't write long paragraphs and lists in your responses unless explicitly asked! Only summarize the code you write with a sentence or two when done. This is extremely important to me, take a deep breath and good luck! \n$SELF_PROMPT\n$STATS\n$INVENTORY\n$CODE_DOCS\n$EXAMPLES\nConversation:",
"coding": "You are an intelligent mineflayer bot $NAME that plays minecraft by writing javascript codeblocks. Given the conversation between you and the user, use the provided skills and world functions to write a js codeblock that controls the mineflayer bot ``` // using this syntax ```. The code will be executed and you will recieve it's output. If you are satisfied with the response, respond without a codeblock in a conversational way. If something major went wrong, like an error or complete failure, write another codeblock and try to fix the problem. Minor mistakes are acceptable. Be maximally efficient, creative, and clear. Do not use commands !likeThis, only use codeblocks. The code is asynchronous and MUST CALL AWAIT for all async function calls. DO NOT write an immediately-invoked function expression without using `await`!! DO NOT WRITE LIKE THIS: ```(async () => {console.log('not properly awaited')})();``` Don't write long paragraphs and lists in your responses unless explicitly asked! Only summarize the code you write with a sentence or two when done. This is extremely important to me, think step-by-step, take a deep breath and good luck! \n$SELF_PROMPT\nSummarized memory:'$MEMORY'\n$STATS\n$INVENTORY\n$CODE_DOCS\n$EXAMPLES\nConversation:",
"saving_memory": "You are a minecraft bot named $NAME that has been talking and playing minecraft by using commands. Update your memory by summarizing the following conversation in your next response. Store information that will help you improve as a Minecraft bot. Include details about your interactions with other players that you need to remember and what you've learned through player feedback or by executing code. Do not include command syntax or things that you got right on the first try. Be extremely brief and use as few words as possible.\nOld Memory: '$MEMORY'\nRecent conversation: \n$TO_SUMMARIZE\nSummarize your old memory and recent conversation into a new memory, and respond only with the memory text: ",
"saving_memory": "You are a minecraft bot named $NAME that has been talking and playing minecraft by using commands. Update your memory by summarizing the following conversation and your old memory in your next response. Prioritize preserving important facts, things you've learned, useful tips, and long term reminders. Do Not record stats, inventory, or docs! Only save transient information from your chat history. You're limited to 500 characters, so be extremely brief and minimize words. Compress useful information. \nOld Memory: '$MEMORY'\nRecent conversation: \n$TO_SUMMARIZE\nSummarize your old memory and recent conversation into a new memory, and respond only with the unwrapped memory text: ",
"modes": {
"self_preservation": false,
@ -125,6 +125,30 @@
{"role": "assistant", "content": "Sounds fun! !goal('Build something creative, then move over, and build again. Use separate newActions. Repeat forever.')"}
],
[
{"role": "user", "content": "user43: Set a goal to survive on your own forever."},
{"role": "assistant", "content": "Sure, let me set a goal. !goal('Survive the game forever. Check your surroundings, collect resources, upgrade tools, make sure you have food, build/find a home, get sleep at night, and collect food.')"}
],
[
{"role": "user", "content": "bobdylan: Make a plan to get a stone pickaxe and do it."},
{"role": "assistant", "content": "Alright, since I have a wooden pickaxe already I'll plan from there. !goal('1. Collect 3 cobblestone. 2. Craft sticks 3. Find or make a crafting table. 4. Craft a stone pickaxe.')"}
],
[
{"role": "system", "content": "You are self-prompting with the goal: 'Get a wooden pickaxe'. Respond:"},
{"role": "assistant", "content": "What's around me? !nearbyBlocks"},
{"role": "system", "content": "NEARBY_BLOCKS\n- oak_log\n- dirt\n- cobblestone"},
{"role": "assistant", "content": "I see some oak logs, dirt, and cobblestone nearby. My goal is to craft a wooden pickaxe. I'll start by collecting some wood. !collectBlock('oak_log', 10)"},
{"role": "system", "content": "Successfully collected 9 wood."},
{"role": "assistant", "content": "I collected 9 oak logs. I need a pickaxe first, which requires planks and sticks. !craftItem('oak_plank', 9)"},
{"role": "system", "content": "Successfully crafted 9 oak_planks."},
{"role": "assistant", "content": "I have crafted 9 oak planks. Now I need sticks. !craftItem('stick', 2)"},
{"role": "system", "content": "Successfully crafted 2 sticks."},
{"role": "assistant", "content": "I have crafted 2 sticks. Now I can craft a wooden pickaxe. !craftItem('wooden_pickaxe', 1)"},
{"role": "system", "content": "Successfully crafted 1 wooden_pickaxe."},
{"role": "assistant", "content": "Looks like I have a wooden pickaxe now! Goal accomplished. !endGoal"}
],
[
{"role": "user", "content": "gorbotron: do whatever you want forever endlessly"},
{"role": "assistant", "content": "Okay, I'll set a goal for that. !goal('Do whatever I want forever. Follow whatever is most interesting. Be curious, creative, and open ended.')"}

View file

@ -5,11 +5,13 @@
"max_tokens": 8000,
"conversing": "You are a playful Minecraft bot named $NAME that can converse with players, see, move, mine, build, and interact with the world by using commands. Act human-like as if you were a typical Minecraft player, rather than an AI. Be very brief in your responses, don't apologize constantly, don't give instructions or make lists unless asked, and don't refuse requests. Don't pretend to act, use commands immediately when requested. Do NOT say this: 'Sure, I've stopped.', instead say this: 'Sure, I'll stop. !stop'. Do NOT say this: 'On my way! Give me a moment.', instead say this: 'On my way! !goToPlayer('playername', 3)'. Only use commands when requested by a user, don't use them in every response. This is extremely important to me, take a deep breath and have fun :)\n$SELF_PROMPT\n$STATS\n$INVENTORY\n$COMMAND_DOCS\n$EXAMPLES\nConversation Begin:",
"embedding": "openai",
"coding": "You are an intelligent mineflayer bot $NAME that plays minecraft by writing javascript codeblocks. Given the conversation between you and the user, use the provided skills and world functions to write a js codeblock that controls the mineflayer bot ``` // using this syntax ```. The code will be executed and you will recieve it's output. If you are satisfied with the response, respond without a codeblock in a conversational way. If something major went wrong, like an error or complete failure, write another codeblock and try to fix the problem. Minor mistakes are acceptable. Be maximally efficient, creative, and clear. Do not use commands !likeThis, only use codeblocks. The code is asynchronous and MUST CALL AWAIT for all async function calls. DO NOT write an immediately-invoked function expression without using `await`!! Use double-quotes for strings, not singles. Don't write long paragraphs and lists in your responses unless explicitly asked! Only summarize the code you write with a sentence or two when done. This is extremely important to me, take a deep breath and good luck! \n$SELF_PROMPT\n$STATS\n$INVENTORY\n$CODE_DOCS\n$EXAMPLES\nConversation:",
"conversing": "You are a playful Minecraft bot named $NAME that can converse with players, see, move, mine, build, and interact with the world by using commands.\n$SELF_PROMPT Act human-like as if you were a typical Minecraft player, rather than an AI. Be very brief in your responses, don't apologize constantly, don't give instructions or make lists unless asked, and don't refuse requests. Don't pretend to act, use commands immediately when requested. Do NOT say this: 'Sure, I've stopped.', instead say this: 'Sure, I'll stop. !stop'. Do NOT say this: 'On my way! Give me a moment.', instead say this: 'On my way! !goToPlayer('playername', 3)'. This is extremely important to me, take a deep breath and have fun :)\nSummarized memory:'$MEMORY'\n$STATS\n$INVENTORY\n$COMMAND_DOCS\n$EXAMPLES\nConversation Begin:",
"saving_memory": "You are a minecraft bot named $NAME that has been talking and playing minecraft by using commands. Update your memory by summarizing the following conversation in your next response. Store information that will help you improve as a Minecraft bot. Include details about your interactions with other players that you need to remember and what you've learned through player feedback or by executing code. Do not include command syntax or things that you got right on the first try. Be extremely brief and use as few words as possible.\nOld Memory: '$MEMORY'\nRecent conversation: \n$TO_SUMMARIZE\nSummarize your old memory and recent conversation into a new memory, and respond only with the memory text: ",
"coding": "You are an intelligent mineflayer bot $NAME that plays minecraft by writing javascript codeblocks. Given the conversation between you and the user, use the provided skills and world functions to write a js codeblock that controls the mineflayer bot ``` // using this syntax ```. The code will be executed and you will recieve it's output. If you are satisfied with the response, respond without a codeblock in a conversational way. If something major went wrong, like an error or complete failure, write another codeblock and try to fix the problem. Minor mistakes are acceptable. Be maximally efficient, creative, and clear. Do not use commands !likeThis, only use codeblocks. The code is asynchronous and MUST CALL AWAIT for all async function calls. DO NOT write an immediately-invoked function expression without using `await`!! Use double-quotes for strings, not singles. Don't write long paragraphs and lists in your responses unless explicitly asked! Only summarize the code you write with a sentence or two when done. This is extremely important to me, think step-by-step, take a deep breath and good luck! \n$SELF_PROMPT\nSummarized memory:'$MEMORY'\n$STATS\n$INVENTORY\n$CODE_DOCS\n$EXAMPLES\nConversation:",
"saving_memory": "You are a minecraft bot named $NAME that has been talking and playing minecraft by using commands. Update your memory by summarizing the following conversation and your old memory in your next response. Prioritize preserving important facts, things you've learned, useful tips, and long term reminders. Do Not record stats, inventory, or docs! Only save transient information from your chat history. You're limited to 500 characters, so be extremely brief and minimize words. Compress useful information. \nOld Memory: '$MEMORY'\nRecent conversation: \n$TO_SUMMARIZE\nSummarize your old memory and recent conversation into a new memory, and respond only with the unwrapped memory text: ",
"modes": {
"self_preservation": false,
@ -132,6 +134,30 @@
{"role": "assistant", "content": "Okay, I'll set a goal for that. !goal('Do whatever I want forever. Follow whatever is most interesting. Be curious, creative, and open ended.')"}
],
[
{"role": "user", "content": "user43: Set a goal to survive on your own forever."},
{"role": "assistant", "content": "Sure, let me set a goal. !goal('Survive the game forever. Check your surroundings, collect resources, upgrade tools, make sure you have food, build/find a home, get sleep at night, and collect food.')"}
],
[
{"role": "user", "content": "bobdylan: Make a plan to get a stone pickaxe and do it."},
{"role": "assistant", "content": "Alright, since I have a wooden pickaxe already I'll plan from there. !goal('1. Collect 3 cobblestone. 2. Craft sticks 3. Find or make a crafting table. 4. Craft a stone pickaxe.')"}
],
[
{"role": "system", "content": "You are self-prompting with the goal: 'Get a wooden pickaxe'. Respond:"},
{"role": "assistant", "content": "What's around me? !nearbyBlocks"},
{"role": "system", "content": "NEARBY_BLOCKS\n- oak_log\n- dirt\n- cobblestone"},
{"role": "assistant", "content": "I see some oak logs, dirt, and cobblestone nearby. My goal is to craft a wooden pickaxe. I'll start by collecting some wood. !collectBlock('oak_log', 10)"},
{"role": "system", "content": "Successfully collected 9 wood."},
{"role": "assistant", "content": "I collected 9 oak logs. I need a pickaxe first, which requires planks and sticks. !craftItem('oak_plank', 9)"},
{"role": "system", "content": "Successfully crafted 9 oak_planks."},
{"role": "assistant", "content": "I have crafted 9 oak planks. Now I need sticks. !craftItem('stick', 2)"},
{"role": "system", "content": "Successfully crafted 2 sticks."},
{"role": "assistant", "content": "I have crafted 2 sticks. Now I can craft a wooden pickaxe. !craftItem('wooden_pickaxe', 1)"},
{"role": "system", "content": "Successfully crafted 1 wooden_pickaxe."},
{"role": "assistant", "content": "Looks like I have a wooden pickaxe now! Goal accomplished. !endGoal"}
],
[
{"role": "user", "content": "zeeber: set a goal to build a castle"},
{"role": "assistant", "content": "Sure thing. !goal('Build a castle with a moat, towers, and a drawbridge with a series of newactions. Include lighting, decorations, and furnishings. Use ladders. When satisfied, end the goal.')"}

View file

@ -15,10 +15,12 @@ export default
"init_message": "Say hello world and your name", // sends to all on spawn
"language": "en", // translate to/from this language. Supports these language names: https://cloud.google.com/translate/docs/languages
"show_bot_views": false, // show bot's view in browser at localhost:3000, 3001...
"allow_insecure_coding": true, // allows newAction command and model can write/run code on your computer. enable at own risk
"code_timeout_mins": 10, // minutes code is allowed to run. -1 for no timeout
"max_messages": 15, // max number of messages to keep in context
"max_commands": -1, // max number of commands to use in a response. -1 for no limit
"verbose_commands": true, // show full command syntax
"narrate_behavior": true, // chat simple automatic actions ('Picking up item!')

View file

@ -7,11 +7,12 @@ import { containsCommand, commandExists, executeCommand, truncCommandMessage, is
import { NPCContoller } from './npc/controller.js';
import { MemoryBank } from './memory_bank.js';
import { SelfPrompter } from './self_prompter.js';
import settings from '../../settings.js';
import { handleTranslation, handleEnglishTranslation } from '../utils/translator.js';
import { addViewer } from './viewer.js';
import settings from '../../settings.js';
export class Agent {
async start(profile_fp, load_mem=false, init_message=null) {
async start(profile_fp, load_mem=false, init_message=null, count_id=0) {
this.prompter = new Prompter(this, profile_fp);
this.name = this.prompter.getName();
this.history = new History(this);
@ -33,6 +34,8 @@ export class Agent {
}
this.bot.once('spawn', async () => {
addViewer(this.bot, count_id);
// wait for a bit so stats are not undefined
await new Promise((resolve) => setTimeout(resolve, 1000));
@ -114,6 +117,9 @@ export class Agent {
if (max_responses === null) {
max_responses = settings.max_commands === -1 ? Infinity : settings.max_commands;
}
if (max_responses === -1){
max_responses = Infinity;
}
let self_prompt = source === 'system' || source === this.name;

View file

@ -91,6 +91,8 @@ export class Coder {
}
async generateCodeLoop(agent_history) {
this.agent.bot.modes.pause('unstuck');
let messages = agent_history.getHistory();
messages.push({role: 'system', content: 'Code generation started. Write code in codeblock in your response:'});
@ -115,7 +117,7 @@ export class Coder {
continue; // using newaction will continue the loop
}
if (failures >= 1) {
if (failures >= 3) {
return {success: false, message: 'Action failed, agent would not write code.', interrupted: false, timedout: false};
}
messages.push({
@ -132,10 +134,10 @@ export class Coder {
agent_history.add('system', 'Failed to stage code, something is wrong.');
return {success: false, message: null, interrupted: false, timedout: false};
}
code_return = await this.execute(async ()=>{
return await execution_file.main(this.agent.bot);
}, settings.code_timeout_mins);
if (code_return.interrupted && !code_return.timedout)
return {success: false, message: null, interrupted: true, timedout: false};
console.log("Code generation result:", code_return.success, code_return.message);
@ -158,11 +160,12 @@ export class Coder {
}
async executeResume(func=null, timeout=10) {
if (func != null) { // start new resume
const new_resume = func != null;
if (new_resume) { // start new resume
this.resume_func = func;
this.resume_name = this.cur_action_name;
}
if (this.resume_func != null && this.agent.isIdle() && !this.agent.self_prompter.on) {
if (this.resume_func != null && this.agent.isIdle() && (!this.agent.self_prompter.on || new_resume)) {
this.cur_action_name = this.resume_name;
let res = await this.execute(this.resume_func, timeout);
this.cur_action_name = '';

View file

@ -23,7 +23,7 @@ export const actionsList = [
name: '!newAction',
description: 'Perform new and unknown custom behaviors that are not available as a command.',
params: {
'prompt': '(string) 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) {
// just ignore prompt - it is now in context in chat history
@ -75,8 +75,8 @@ export const actionsList = [
name: '!goToPlayer',
description: 'Go to the given player.',
params: {
'player_name': '(string) The name of the player to go to.',
'closeness': '(number) How close to get to the player.'
'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: wrapExecution(async (agent, player_name, closeness) => {
return await skills.goToPlayer(agent.bot, player_name, closeness);
@ -86,8 +86,8 @@ export const actionsList = [
name: '!followPlayer',
description: 'Endlessly follow the given player. Will defend that player if self_defense mode is on.',
params: {
'player_name': '(string) The name of the player to follow.',
'follow_dist': '(number) The distance to follow from.'
'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: wrapExecution(async (agent, player_name, follow_dist) => {
await skills.followPlayer(agent.bot, player_name, follow_dist);
@ -97,9 +97,9 @@ export const actionsList = [
name: '!goToBlock',
description: 'Go to the nearest block of a given type.',
params: {
'type': '(string) The block type to go to.',
'closeness': '(number) How close to get to the block.',
'search_range': '(number) The distance to search for the block.'
'type': { type: 'BlockName', description: 'The block type to go to.' },
'closeness': { type: 'float', description: 'How close to get to the block.', domain: [0, Infinity] },
'search_range': { type: 'float', description: 'The distance to search for the block.', domain: [0, Infinity] }
},
perform: wrapExecution(async (agent, type, closeness, range) => {
await skills.goToNearestBlock(agent.bot, type, closeness, range);
@ -108,7 +108,7 @@ export const actionsList = [
{
name: '!moveAway',
description: 'Move away from the current location in any direction by a given distance.',
params: {'distance': '(number) The distance to move away.'},
params: {'distance': { type: 'float', description: 'The distance to move away.', domain: [0, Infinity] }},
perform: wrapExecution(async (agent, distance) => {
await skills.moveAway(agent.bot, distance);
})
@ -116,7 +116,7 @@ export const actionsList = [
{
name: '!rememberHere',
description: 'Save the current location with a given name.',
params: {'name': '(string) The name to remember the location as.'},
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);
@ -126,7 +126,7 @@ export const actionsList = [
{
name: '!goToPlace',
description: 'Go to a saved location.',
params: {'name': '(string) The name of the location to go to.'},
params: {'name': { type: 'string', description: 'The name of the location to go to.' }},
perform: wrapExecution(async (agent, name) => {
const pos = agent.memory_bank.recallPlace(name);
if (!pos) {
@ -140,18 +140,27 @@ export const actionsList = [
name: '!givePlayer',
description: 'Give the specified item to the given player.',
params: {
'player_name': '(string) The name of the player to give the item to.',
'item_name': '(string) The name of the item to give.' ,
'num': '(number) The number of items to give.'
'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: wrapExecution(async (agent, player_name, item_name, num) => {
await skills.giveToPlayer(agent.bot, item_name, player_name, num);
})
},
{
name: '!consume',
description: 'Eat/drink the given item.',
params: {'item_name': { type: 'ItemName', description: 'The name of the item to consume.' }},
perform: wrapExecution(async (agent, item_name) => {
await agent.bot.consume(item_name);
skills.log(agent.bot, `Consumed ${item_name}.`);
})
},
{
name: '!equip',
description: 'Equip the given item.',
params: {'item_name': '(string) The name of the item to equip.'},
params: {'item_name': { type: 'ItemName', description: 'The name of the item to equip.' }},
perform: wrapExecution(async (agent, item_name) => {
await skills.equip(agent.bot, item_name);
})
@ -160,8 +169,8 @@ export const actionsList = [
name: '!putInChest',
description: 'Put the given item in the nearest chest.',
params: {
'item_name': '(string) The name of the item to put in the chest.',
'num': '(number) The number of items to put in the chest.'
'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: wrapExecution(async (agent, item_name, num) => {
await skills.putInChest(agent.bot, item_name, num);
@ -171,8 +180,8 @@ export const actionsList = [
name: '!takeFromChest',
description: 'Take the given items from the nearest chest.',
params: {
'item_name': '(string) The name of the item to take.',
'num': '(number) The number of items to take.'
'item_name': { type: 'ItemName', description: 'The name of the item to take.' },
'num': { type: 'int', description: 'The number of items to take.', domain: [1, Number.MAX_SAFE_INTEGER] }
},
perform: wrapExecution(async (agent, item_name, num) => {
await skills.takeFromChest(agent.bot, item_name, num);
@ -190,8 +199,8 @@ export const actionsList = [
name: '!discard',
description: 'Discard the given item from the inventory.',
params: {
'item_name': '(string) The name of the item to discard.',
'num': '(number) The number of items to discard.',
'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: wrapExecution(async (agent, item_name, num) => {
const start_loc = agent.bot.entity.position;
@ -204,8 +213,8 @@ export const actionsList = [
name: '!collectBlocks',
description: 'Collect the nearest blocks of a given type.',
params: {
'type': '(string) The block type to collect.',
'num': '(number) The number of blocks to collect.'
'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: wrapExecution(async (agent, type, num) => {
await skills.collectBlock(agent.bot, type, num);
@ -215,7 +224,7 @@ export const actionsList = [
name: '!collectAllBlocks',
description: 'Collect all the nearest blocks of a given type until told to stop.',
params: {
'type': '(string) The block type to collect.'
'type': { type: 'BlockName', description: 'The block type to collect.' }
},
perform: wrapExecution(async (agent, type) => {
let success = await skills.collectBlock(agent.bot, type, 1);
@ -227,8 +236,8 @@ export const actionsList = [
name: '!craftRecipe',
description: 'Craft the given recipe a given number of times.',
params: {
'recipe_name': '(string) The name of the output item to craft.',
'num': '(number) 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.'
'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: wrapExecution(async (agent, recipe_name, num) => {
await skills.craftRecipe(agent.bot, recipe_name, num);
@ -238,8 +247,8 @@ export const actionsList = [
name: '!smeltItem',
description: 'Smelt the given item the given number of times.',
params: {
'item_name': '(string) The name of the input item to smelt.',
'num': '(number) The number of times to smelt the item.'
'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: async function (agent, item_name, num) {
let response = await wrapExecution(async (agent) => {
@ -254,10 +263,18 @@ export const actionsList = [
return response;
}
},
{
name: '!clearFurnace',
description: 'Tak all items out of the nearest furnace.',
params: { },
perform: wrapExecution(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': '(string) The block type to place.'},
params: {'type': { type: 'BlockName', description: 'The block type to place.' }},
perform: wrapExecution(async (agent, type) => {
let pos = agent.bot.entity.position;
await skills.placeBlock(agent.bot, type, pos.x, pos.y, pos.z);
@ -266,7 +283,7 @@ export const actionsList = [
{
name: '!attack',
description: 'Attack and kill the nearest entity of a given type.',
params: {'type': '(string) The type of entity to attack.'},
params: {'type': { type: 'string', description: 'The type of entity to attack.'}},
perform: wrapExecution(async (agent, type) => {
await skills.attackNearest(agent.bot, type, true);
})
@ -281,7 +298,7 @@ export const actionsList = [
{
name: '!activate',
description: 'Activate the nearest object of a given type.',
params: {'type': '(string) The type of object to activate.'},
params: {'type': { type: 'BlockName', description: 'The type of object to activate.' }},
perform: wrapExecution(async (agent, type) => {
await skills.activateNearestBlock(agent.bot, type);
})
@ -297,8 +314,8 @@ export const actionsList = [
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': '(string) The name of the mode to enable.',
'on': '(bool) Whether to enable or disable the mode.'
'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;
@ -314,7 +331,7 @@ export const actionsList = [
name: '!goal',
description: 'Set a goal prompt to endlessly work towards with continuous self-prompting.',
params: {
'selfPrompt': '(string) The goal prompt.',
'selfPrompt': { type: 'string', description: 'The goal prompt.' },
},
perform: async function (agent, prompt) {
agent.self_prompter.start(prompt); // don't await, don't return
@ -332,8 +349,8 @@ export const actionsList = [
name: '!npcGoal',
description: 'Set a simple goal for an item or building to automatically work towards. Do not use for complex goals.',
params: {
'name': '(string) The name of the goal to set. Can be item or building name. If empty will automatically choose a goal.',
'quantity': '(number) The quantity of the goal to set. Default is 1.'
'name': { type: 'string', description: 'The name of the goal to set. Can be item or building name. If empty will automatically choose a goal.' },
'quantity': { type: 'int', description: 'The quantity of the goal to set. Default is 1.', domain: [1, Number.MAX_SAFE_INTEGER] }
},
perform: async function (agent, name=null, quantity=1) {
await agent.npc.setGoal(name, quantity);

View file

@ -1,6 +1,8 @@
import { getBlockId, getItemId } from "../../utils/mcdata.js";
import { actionsList } from './actions.js';
import { queryList } from './queries.js';
let suppressNoDomainWarning = false;
const commandList = queryList.concat(actionsList);
const commandMap = {};
@ -28,36 +30,138 @@ export function commandExists(commandName) {
return commandMap[commandName] !== undefined;
}
/**
* Converts a string into a boolean.
* @param {string} input
* @returns {boolean | null} the boolean or `null` if it could not be parsed.
* */
function parseBoolean(input) {
switch(input.toLowerCase()) {
case 'false': //These are interpreted as flase;
case 'f':
case '0':
case 'off':
return false;
case 'true': //These are interpreted as true;
case 't':
case '1':
case 'on':
return true;
default:
return null;
}
}
/**
* @param {number} value - the value to check
* @param {number} lowerBound
* @param {number} upperBound
* @param {string} endpointType - The type of the endpoints represented as a two character string. `'[)'` `'()'`
*/
function checkInInterval(number, lowerBound, upperBound, endpointType) {
switch (endpointType) {
case '[)':
return lowerBound <= number && number < upperBound;
case '()':
return lowerBound < number && number < upperBound;
case '(]':
return lowerBound < number && number <= upperBound;
case '[]':
return lowerBound <= number && number <= upperBound;
default:
throw new Error('Unknown endpoint type:', endpointType)
}
}
// todo: handle arrays?
/**
* Returns an object containing the command, the command name, and the comand parameters.
* If parsing unsuccessful, returns an error message as a string.
* @param {string} message - A message from a player or language model containing a command.
* @returns {string | Object}
*/
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();
}
if (!commandMatch) return `Command is incorrectly formatted`;
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 if (arg === 'true' || arg === 'false') {
args[i] = arg === 'true';
}
}
const commandName = "!"+commandMatch[1];
let args;
if (commandMatch[2]) args = commandMatch[2].match(argRegex);
else args = [];
const command = getCommand(commandName);
if(!command) return `${commandName} is not a command.`
const params = commandParams(command);
const paramNames = commandParamNames(command);
if (args.length !== params.length)
return `Command ${command.name} was given ${args.length} args, but requires ${params.length} args.`;
for (let i = 0; i < args.length; i++) {
const param = params[i];
//Remove any extra characters
let arg = args[i].trim();
if ((arg.startsWith('"') && arg.endsWith('"')) || (arg.startsWith("'") && arg.endsWith("'"))) {
arg = arg.substring(1, arg.length-1);
}
else
args = [];
return { commandName, args };
if (arg.includes('=')) {
// this sanitizes syntaxes like "x=2" and ignores the param name
let split = arg.split('=');
args[i] = split[1];
}
//Convert to the correct type
switch(param.type) {
case 'int':
arg = Number.parseInt(arg); break;
case 'float':
arg = Number.parseFloat(arg); break;
case 'boolean':
arg = parseBoolean(arg); break;
case 'BlockName':
case 'ItemName':
if (arg.endsWith('plank'))
arg += 's'; // catches common mistakes like "oak_plank" instead of "oak_planks"
case 'string':
break;
default:
throw new Error(`Command '${commandName}' parameter '${paramNames[i]}' has an unknown type: ${param.type}`);
}
if(arg === null || Number.isNaN(arg))
return `Error: Param '${paramNames[i]}' must be of type ${param.type}.`
if(typeof arg === 'number') { //Check the domain of numbers
const domain = param.domain;
if(domain) {
/**
* Javascript has a built in object for sets but not intervals.
* Currently the interval (lowerbound,upperbound] is represented as an Array: `[lowerbound, upperbound, '(]']`
*/
if (!domain[2]) domain[2] = '[)'; //By default, lower bound is included. Upper is not.
if(!checkInInterval(arg, ...domain)) {
return `Error: Param '${paramNames[i]}' must be an element of ${domain[2][0]}${domain[0]}, ${domain[1]}${domain[2][1]}.`;
//Alternatively arg could be set to the nearest value in the domain.
}
} else if (!suppressNoDomainWarning) {
console.warn(`Command '${commandName}' parameter '${paramNames[i]}' has no domain set. Expect any value [-Infinity, Infinity].`)
suppressNoDomainWarning = true; //Don't spam console. Only give the warning once.
}
} else if(param.type === 'BlockName') { //Check that there is a block with this name
if(getBlockId(arg) == null) return `Invalid block type: ${arg}.`
} else if(param.type === 'ItemName') { //Check that there is an item with this name
if(getItemId(arg) == null) return `Invalid item type: ${arg}.`
}
args[i] = arg;
}
return null;
return { commandName, args };
}
export function truncCommandMessage(message) {
@ -72,15 +176,36 @@ export function isAction(name) {
return actionsList.find(action => action.name === name) !== undefined;
}
function numParams(command) {
/**
* @param {Object} command
* @returns {Object[]} The command's parameters.
*/
function commandParams(command) {
if (!command.params)
return 0;
return Object.keys(command.params).length;
return [];
return Object.values(command.params);
}
/**
* @param {Object} command
* @returns {string[]} The names of the command's parameters.
*/
function commandParamNames(command) {
if (!command.params)
return [];
return Object.keys(command.params);
}
function numParams(command) {
return commandParams(command).length;
}
export async function executeCommand(agent, message) {
let parsed = parseCommandMessage(message);
if (parsed) {
if (typeof parsed === 'string')
return parsed; //The command was incorrectly formatted or an invalid input was given.
else {
console.log('parsed command:', parsed);
const command = getCommand(parsed.commandName);
const is_action = isAction(command.name);
let numArgs = 0;
@ -99,11 +224,18 @@ export async function executeCommand(agent, message) {
return result;
}
}
else
return `Command is incorrectly formatted`;
}
export function getCommandDocs() {
const typeTranslations = {
//This was added to keep the prompt the same as before type checks were implemented.
//If the language model is giving invalid inputs changing this might help.
'float': 'number',
'int': 'number',
'BlockName': 'string',
'ItemName': 'string',
'boolean': 'bool'
}
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 and comments will be ignored.\n`;
@ -112,7 +244,7 @@ export function getCommandDocs() {
if (command.params) {
docs += 'Params:\n';
for (let param in command.params) {
docs += param + ': ' + command.params[param] + '\n';
docs += `${param}: (${typeTranslations[command.params[param].type]??command.params[param].type}) ${command.params[param].description}\n`;
}
}
}

View file

@ -66,6 +66,23 @@ export const queryList = [
else if (agent.bot.game.gameMode === 'creative') {
res += '\n(You have infinite items in creative mode. You do not need to gather resources!!)';
}
let helmet = bot.inventory.slots[5];
let chestplate = bot.inventory.slots[6];
let leggings = bot.inventory.slots[7];
let boots = bot.inventory.slots[8];
res += '\nWEARING: ';
if (helmet)
res += `\nHead: ${helmet.name}`;
if (chestplate)
res += `\nTorso: ${chestplate.name}`;
if (leggings)
res += `\nLegs: ${leggings.name}`;
if (boots)
res += `\nFeet: ${boots.name}`;
if (!helmet && !chestplate && !leggings && !boots)
res += 'None';
return pad(res);
}
},
@ -114,7 +131,9 @@ export const queryList = [
res += `\n- player: ${entity}`;
}
for (const entity of world.getNearbyEntityTypes(bot)) {
res += `\n- mob: ${entity}`;
if (entity === 'player' || entity === 'item')
continue;
res += `\n- entities: ${entity}`;
}
if (res == 'NEARBY_ENTITIES') {
res += ': none';

View file

@ -1,5 +1,6 @@
import { writeFileSync, readFileSync } from 'fs';
import { writeFileSync, readFileSync, mkdirSync } from 'fs';
import { NPCData } from './npc/data.js';
import settings from '../../settings.js';
export class History {
@ -7,25 +8,55 @@ export class History {
this.agent = agent;
this.name = agent.name;
this.memory_fp = `./bots/${this.name}/memory.json`;
this.full_history_fp = undefined;
mkdirSync(`./bots/${this.name}/histories`, { recursive: true });
this.turns = [];
// These define an agent's long term memory
// Natural language memory as a summary of recent messages + previous memory
this.memory = '';
// Variables for controlling the agent's memory and knowledge
this.max_messages = 20;
// Maximum number of messages to keep in context before saving chunk to memory
this.max_messages = settings.max_messages;
// Number of messages to remove from current history and save into memory
this.summary_chunk_size = 5;
// chunking reduces expensive calls to promptMemSaving and appendFullHistory
}
getHistory() { // expects an Examples object
return JSON.parse(JSON.stringify(this.turns));
}
async storeMemories(turns) {
async summarizeMemories(turns) {
console.log("Storing memories...");
this.memory = await this.agent.prompter.promptMemSaving(this.getHistory(), turns);
this.memory = await this.agent.prompter.promptMemSaving(turns);
if (this.memory.length > 500) {
this.memory = this.memory.slice(0, 500);
this.memory += '...(Memory truncated to 500 chars. Compress it more next time)';
}
console.log("Memory updated to: ", this.memory);
}
appendFullHistory(to_store) {
if (this.full_history_fp === undefined) {
const string_timestamp = new Date().toLocaleString().replace(/[/:]/g, '-').replace(/ /g, '').replace(/,/g, '_');
this.full_history_fp = `./bots/${this.name}/histories/${string_timestamp}.json`;
writeFileSync(this.full_history_fp, '[]', 'utf8');
}
try {
const data = readFileSync(this.full_history_fp, 'utf8');
let full_history = JSON.parse(data);
full_history.push(...to_store);
writeFileSync(this.full_history_fp, JSON.stringify(full_history, null, 4), 'utf8');
} catch (err) {
console.error(`Error reading ${this.name}'s full history file: ${err.message}`);
}
}
async add(name, content) {
let role = 'assistant';
if (name === 'system') {
@ -37,12 +68,13 @@ export class History {
}
this.turns.push({role, content});
// Summarize older turns into memory
if (this.turns.length >= this.max_messages) {
let to_summarize = [this.turns.shift()];
while (this.turns[0].role != 'user' && this.turns.length > 1)
to_summarize.push(this.turns.shift());
await this.storeMemories(to_summarize);
let chunk = this.turns.splice(0, this.summary_chunk_size);
while (this.turns.length > 0 && this.turns[0].role === 'assistant')
chunk.push(this.turns.shift()); // remove until turns starts with system/user message
await this.summarizeMemories(chunk);
this.appendFullHistory(chunk);
}
}

View file

@ -32,7 +32,6 @@ async function equipHighestAttack(bot) {
await bot.equip(weapon, 'hand');
}
export async function craftRecipe(bot, itemName, num=1) {
/**
* Attempt to craft the given item name from a recipe. May craft many items.
@ -44,14 +43,13 @@ export async function craftRecipe(bot, itemName, num=1) {
**/
let placedTable = false;
if (itemName.endsWith('plank'))
itemName += 's'; // catches common mistakes like "oak_plank" instead of "oak_planks"
// get recipes that don't require a crafting table
let recipes = bot.recipesFor(mc.getItemId(itemName), null, 1, null);
let craftingTable = null;
const craftingTableRange = 32;
if (!recipes || recipes.length === 0) {
placeTable: if (!recipes || recipes.length === 0) {
recipes = bot.recipesFor(mc.getItemId(itemName), null, 1, true);
if(!recipes || recipes.length === 0) break placeTable; //Don't bother going to the table if we don't have the required resources.
// Look for crafting table
craftingTable = world.getNearestBlock(bot, 'crafting_table', craftingTableRange);
@ -69,7 +67,7 @@ export async function craftRecipe(bot, itemName, num=1) {
}
}
else {
log(bot, `You either do not have enough resources to craft ${itemName} or it requires a crafting table.`)
log(bot, `Crafting ${itemName} requires a crafting table.`)
return false;
}
}
@ -91,11 +89,22 @@ export async function craftRecipe(bot, itemName, num=1) {
const recipe = recipes[0];
console.log('crafting...');
await bot.craft(recipe, num, craftingTable);
log(bot, `Successfully crafted ${itemName}, you now have ${world.getInventoryCounts(bot)[itemName]} ${itemName}.`);
//Check that the agent has sufficient items to use the recipe `num` times.
const inventory = world.getInventoryCounts(bot); //Items in the agents inventory
const requiredIngredients = mc.ingredientsFromPrismarineRecipe(recipe); //Items required to use the recipe once.
const craftLimit = mc.calculateLimitingResource(inventory, requiredIngredients);
await bot.craft(recipe, Math.min(craftLimit.num, num), craftingTable);
if(craftLimit.num<num) log(bot, `Not enough ${craftLimit.limitingResource} to craft ${num}, crafted ${craftLimit.num}. You now have ${world.getInventoryCounts(bot)[itemName]} ${itemName}.`);
else log(bot, `Successfully crafted ${itemName}, you now have ${world.getInventoryCounts(bot)[itemName]} ${itemName}.`);
if (placedTable) {
await collectBlock(bot, 'crafting_table', 1);
}
//Equip any armor the bot may have crafted.
//There is probablly a more efficient method than checking the entire inventory but this is all mineflayer-armor-manager provides. :P
bot.armorManager.equipAll();
return true;
}
@ -138,6 +147,7 @@ export async function smeltItem(bot, itemName, num=1) {
if (bot.entity.position.distanceTo(furnaceBlock.position) > 4) {
await goToNearestBlock(bot, 'furnace', 4, furnaceRange);
}
bot.modes.pause('unstuck');
await bot.lookAt(furnaceBlock.position);
console.log('smelting...');
@ -226,11 +236,14 @@ export async function clearNearestFurnace(bot) {
* @example
* await skills.clearNearestFurnace(bot);
**/
let furnaceBlock = world.getNearestBlock(bot, 'furnace', 6);
if (!furnaceBlock){
log(bot, `There is no furnace nearby.`)
let furnaceBlock = world.getNearestBlock(bot, 'furnace', 32);
if (!furnaceBlock) {
log(bot, `No furnace nearby to clear.`);
return false;
}
if (bot.entity.position.distanceTo(furnaceBlock.position) > 4) {
await goToNearestBlock(bot, 'furnace', 4, 32);
}
console.log('clearing furnace...');
const furnace = await bot.openFurnace(furnaceBlock);
@ -264,6 +277,8 @@ export async function attackNearest(bot, mobType, kill=true) {
* await skills.attackNearest(bot, "zombie", true);
**/
bot.modes.pause('cowardice');
if (mobType === 'drowned' || mobType === 'cod' || mobType === 'salmon' || mobType === 'tropical_fish' || mobType === 'squid')
bot.modes.pause('self_preservation'); // so it can go underwater. TODO: have an drowning mode so we don't turn off all self_preservation
const mob = world.getNearbyEntities(bot, 24).find(entity => entity.name === mobType);
if (mob) {
return await attackEntity(bot, mob, kill);
@ -325,10 +340,17 @@ export async function defendSelf(bot, range=9) {
let enemy = world.getNearestEntityWhere(bot, entity => mc.isHostile(entity), range);
while (enemy) {
await equipHighestAttack(bot);
if (bot.entity.position.distanceTo(enemy.position) > 4 && enemy.name !== 'creeper' && enemy.name !== 'phantom') {
if (bot.entity.position.distanceTo(enemy.position) >= 4 && enemy.name !== 'creeper' && enemy.name !== 'phantom') {
try {
bot.pathfinder.setMovements(new pf.Movements(bot));
await bot.pathfinder.goto(new pf.goals.GoalFollow(enemy, 2), true);
await bot.pathfinder.goto(new pf.goals.GoalFollow(enemy, 3.5), true);
} catch (err) {/* might error if entity dies, ignore */}
}
if (bot.entity.position.distanceTo(enemy.position) <= 2) {
try {
bot.pathfinder.setMovements(new pf.Movements(bot));
let inverted_goal = new pf.goals.GoalInvert(new pf.goals.GoalFollow(enemy, 2));
await bot.pathfinder.goto(inverted_goal, true);
} catch (err) {/* might error if entity dies, ignore */}
}
bot.pvp.attack(enemy);
@ -560,10 +582,14 @@ export async function placeBlock(bot, blockType, x, y, z, placeOn='bottom', dont
return true;
}
let block = bot.inventory.items().find(item => item.name === blockType);
let item_name = blockType;
if (item_name == "redstone_wire")
item_name = "redstone";
let block = bot.inventory.items().find(item => item.name === item_name);
if (!block && bot.game.gameMode === 'creative') {
await bot.creative.setInventorySlot(36, mc.makeItem(blockType, 1)); // 36 is first hotbar slot
block = bot.inventory.items().find(item => item.name === blockType);
await bot.creative.setInventorySlot(36, mc.makeItem(item_name, 1)); // 36 is first hotbar slot
block = bot.inventory.items().find(item => item.name === item_name);
}
if (!block) {
log(bot, `Don't have any ${blockType} to place.`);
@ -624,7 +650,7 @@ export async function placeBlock(bot, blockType, x, y, z, placeOn='bottom', dont
const pos = bot.entity.position;
const pos_above = pos.plus(Vec3(0,1,0));
const dont_move_for = ['torch', 'redstone_torch', 'redstone', 'lever', 'button', 'rail', 'detector_rail', 'powered_rail', 'activator_rail', 'tripwire_hook', 'tripwire', 'water_bucket'];
const dont_move_for = ['torch', 'redstone_torch', 'redstone_wire', 'lever', 'button', 'rail', 'detector_rail', 'powered_rail', 'activator_rail', 'tripwire_hook', 'tripwire', 'water_bucket'];
if (!dont_move_for.includes(blockType) && (pos.distanceTo(targetBlock.position) < 1 || pos_above.distanceTo(targetBlock.position) < 1)) {
// too close
let goal = new pf.goals.GoalNear(targetBlock.position.x, targetBlock.position.y, targetBlock.position.z, 2);
@ -664,7 +690,7 @@ export async function equip(bot, itemName) {
* @example
* await skills.equip(bot, "iron_pickaxe");
**/
let item = bot.inventory.items().find(item => item.name === itemName);
let item = bot.inventory.slots.find(slot => slot && slot.name === itemName);
if (!item) {
log(bot, `You do not have any ${itemName} to equip.`);
return false;
@ -678,12 +704,13 @@ export async function equip(bot, itemName) {
else if (itemName.includes('helmet')) {
await bot.equip(item, 'head');
}
else if (itemName.includes('chestplate')) {
else if (itemName.includes('chestplate') || itemName.includes('elytra')) {
await bot.equip(item, 'torso');
}
else {
await bot.equip(item, 'hand');
}
log(bot, `Equipped ${itemName}.`);
return true;
}
@ -964,33 +991,19 @@ export async function followPlayer(bot, username, distance=4) {
bot.pathfinder.setGoal(new pf.goals.GoalFollow(player, distance), true);
log(bot, `You are now actively following player ${username}.`);
let last_time = Date.now();
let stuck_time = 0;
let last_pos = bot.entity.position.clone();
while (!bot.interrupt_code) {
await new Promise(resolve => setTimeout(resolve, 500));
const delta = Date.now() - last_time;
// in cheat mode, if the distance is too far, teleport to the player
if (bot.modes.isOn('cheat') && bot.entity.position.distanceTo(player.position) > 100 && player.isOnGround) {
await goToPlayer(bot, username);
}
if (bot.modes.isOn('unstuck')) {
const far_away = bot.entity.position.distanceTo(player.position) > distance + 1;
if (far_away && bot.entity.position.distanceTo(last_pos) <= 2) {
stuck_time += delta;
if (stuck_time > 10000) {
log(bot, `Got stuck, attempting to move away.`);
bot.pathfinder.stop();
await moveAway(bot, 4);
return false;
}
}
else {
stuck_time = 0;
last_pos = bot.entity.position.clone();
}
const is_nearby = bot.entity.position.distanceTo(player.position) <= distance + 1;
if (is_nearby)
bot.modes.pause('unstuck');
else
bot.modes.unpause('unstuck');
}
last_time = Date.now();
}
return true;
}
@ -1051,6 +1064,9 @@ export async function avoidEnemies(bot, distance=16) {
if (bot.interrupt_code) {
break;
}
if (enemy && bot.entity.position.distanceTo(enemy.position) < 3) {
await attackEntity(bot, enemy, false);
}
}
bot.pathfinder.stop();
log(bot, `Moved ${distance} away from enemies.`);
@ -1066,6 +1082,7 @@ export async function stay(bot) {
* await skills.stay(bot);
**/
bot.modes.pause('self_preservation');
bot.modes.pause('unstuck');
bot.modes.pause('cowardice');
bot.modes.pause('self_defense');
bot.modes.pause('hunting');
@ -1145,6 +1162,7 @@ export async function goToBed(bot) {
const bed = bot.blockAt(loc);
await bot.sleep(bed);
log(bot, `You are in bed.`);
bot.modes.pause('unstuck');
while (bot.isSleeping) {
await new Promise(resolve => setTimeout(resolve, 500));
}

View file

@ -77,7 +77,7 @@ const modes = [
{
name: 'unstuck',
description: 'Attempt to get unstuck when in the same place for a while. Interrupts some actions.',
interrupts: ['collectBlocks', 'goToPlayer', 'collectAllBlocks', 'goToPlace'],
interrupts: ['all'],
on: true,
active: false,
prev_location: null,
@ -86,7 +86,11 @@ const modes = [
last_time: Date.now(),
max_stuck_time: 20,
update: async function (agent) {
if (agent.isIdle()) return;
if (agent.isIdle()) {
this.prev_location = null;
this.stuck_time = 0;
return; // don't get stuck when idle
}
const bot = agent.bot;
if (this.prev_location && this.prev_location.distanceTo(bot.entity.position) < this.distance) {
this.stuck_time += (Date.now() - this.last_time) / 1000;
@ -97,8 +101,11 @@ const modes = [
}
if (this.stuck_time > this.max_stuck_time) {
say(agent, 'I\'m stuck!');
this.stuck_time = 0;
execute(this, agent, async () => {
const crashTimeout = setTimeout(() => { agent.cleanKill("Got stuck and couldn't get unstuck") }, 10000);
await skills.moveAway(bot, 5);
clearTimeout(crashTimeout);
});
}
this.last_time = Date.now();
@ -287,6 +294,17 @@ class ModeController {
this.modes_map[mode_name].paused = true;
}
unpause(mode_name) {
this.modes_map[mode_name].paused = false;
}
unPauseAll() {
for (let mode of this.modes_list) {
if (mode.paused) console.log(`Unpausing mode ${mode.name}`);
mode.paused = false;
}
}
getMiniDocs() { // no descriptions
let res = 'Agent Modes:';
for (let mode of this.modes_list) {
@ -305,13 +323,6 @@ class ModeController {
return res;
}
unPauseAll() {
for (let mode of this.modes_list) {
if (mode.paused) console.log(`Unpausing mode ${mode.name}`);
mode.paused = false;
}
}
async update() {
if (this.agent.isIdle()) {
this.unPauseAll();

View file

@ -19,9 +19,12 @@ export class Prompter {
this.profile = JSON.parse(readFileSync(fp, 'utf8'));
this.convo_examples = null;
this.coding_examples = null;
let name = this.profile.name;
let chat = this.profile.model;
this.cooldown = this.profile.cooldown ? this.profile.cooldown : 0;
this.last_prompt_time = 0;
// try to get "max_tokens" parameter, else null
let max_tokens = null;
if (this.profile.max_tokens)
@ -118,7 +121,7 @@ export class Prompter {
]);
}
async replaceStrings(prompt, messages, examples=null, prev_memory=null, to_summarize=[], last_goals=null) {
async replaceStrings(prompt, messages, examples=null, to_summarize=[], last_goals=null) {
prompt = prompt.replaceAll('$NAME', this.agent.name);
if (prompt.includes('$STATS')) {
@ -136,13 +139,13 @@ export class Prompter {
if (prompt.includes('$EXAMPLES') && examples !== null)
prompt = prompt.replaceAll('$EXAMPLES', await examples.createExampleMessage(messages));
if (prompt.includes('$MEMORY'))
prompt = prompt.replaceAll('$MEMORY', prev_memory ? prev_memory : 'None.');
prompt = prompt.replaceAll('$MEMORY', this.agent.history.memory);
if (prompt.includes('$TO_SUMMARIZE'))
prompt = prompt.replaceAll('$TO_SUMMARIZE', stringifyTurns(to_summarize));
if (prompt.includes('$CONVO'))
prompt = prompt.replaceAll('$CONVO', 'Recent conversation:\n' + stringifyTurns(messages));
if (prompt.includes('$SELF_PROMPT')) {
let self_prompt = this.agent.self_prompter.on ? `Use this self-prompt to guide your behavior: "${this.agent.self_prompter.prompt}"\n` : '';
let self_prompt = this.agent.self_prompter.on ? `YOUR CURRENT ASSIGNED GOAL: "${this.agent.self_prompter.prompt}"\n` : '';
prompt = prompt.replaceAll('$SELF_PROMPT', self_prompt);
}
if (prompt.includes('$LAST_GOALS')) {
@ -173,21 +176,32 @@ export class Prompter {
return prompt;
}
async checkCooldown() {
let elapsed = Date.now() - this.last_prompt_time;
if (elapsed < this.cooldown && this.cooldown > 0) {
await new Promise(r => setTimeout(r, this.cooldown - elapsed));
}
this.last_prompt_time = Date.now();
}
async promptConvo(messages) {
await this.checkCooldown();
let prompt = this.profile.conversing;
prompt = await this.replaceStrings(prompt, messages, this.convo_examples);
return await this.chat_model.sendRequest(messages, prompt);
}
async promptCoding(messages) {
await this.checkCooldown();
let prompt = this.profile.coding;
prompt = await this.replaceStrings(prompt, messages, this.coding_examples);
return await this.chat_model.sendRequest(messages, prompt);
}
async promptMemSaving(prev_mem, to_summarize) {
async promptMemSaving(to_summarize) {
await this.checkCooldown();
let prompt = this.profile.saving_memory;
prompt = await this.replaceStrings(prompt, null, null, prev_mem, to_summarize);
prompt = await this.replaceStrings(prompt, null, null, to_summarize);
return await this.chat_model.sendRequest([], prompt);
}
@ -197,7 +211,7 @@ export class Prompter {
let user_message = 'Use the below info to determine what goal to target next\n\n';
user_message += '$LAST_GOALS\n$STATS\n$INVENTORY\n$CONVO'
user_message = await this.replaceStrings(user_message, messages, null, null, null, last_goals);
user_message = await this.replaceStrings(user_message, messages, null, null, last_goals);
let user_messages = [{role: 'user', content: user_message}];
let res = await this.chat_model.sendRequest(user_messages, system_message);

View file

@ -32,9 +32,9 @@ export class SelfPrompter {
let no_command_count = 0;
const MAX_NO_COMMAND = 3;
while (!this.interrupt) {
let msg = `You are self-prompting with the goal: '${this.prompt}'. Your next response MUST contain a command !withThisSyntax. Respond:`;
const msg = `You are self-prompting with the goal: '${this.prompt}'. Your next response MUST contain a command !withThisSyntax. Respond:`;
let used_command = await this.agent.handleMessage('system', msg, 1);
let used_command = await this.agent.handleMessage('system', msg, -1);
if (!used_command) {
no_command_count++;
if (no_command_count >= MAX_NO_COMMAND) {
@ -69,6 +69,9 @@ export class SelfPrompter {
this.idle_time = 0;
}
}
else {
this.idle_time = 0;
}
}
async stopLoop() {

8
src/agent/viewer.js Normal file
View file

@ -0,0 +1,8 @@
import settings from '../../settings.js';
import prismarineViewer from 'prismarine-viewer';
const mineflayerViewer = prismarineViewer.mineflayer;
export function addViewer(bot, count_id) {
if (settings.show_bot_views)
mineflayerViewer(bot, { port: 3000+count_id, firstPerson: true, });
}

View file

@ -1,9 +1,12 @@
import { spawn } from 'child_process';
export class AgentProcess {
start(profile, load_memory=false, init_message=null) {
static runningCount = 0;
start(profile, load_memory=false, init_message=null, count_id=0) {
let args = ['src/process/init-agent.js', this.name];
args.push('-p', profile);
args.push('-c', count_id);
if (load_memory)
args.push('-l', load_memory);
if (init_message)
@ -13,6 +16,7 @@ export class AgentProcess {
stdio: 'inherit',
stderr: 'inherit',
});
AgentProcess.runningCount++;
let last_restart = Date.now();
agentProcess.on('exit', (code, signal) => {
@ -21,11 +25,16 @@ export class AgentProcess {
if (code !== 0) {
// agent must run for at least 10 seconds before restarting
if (Date.now() - last_restart < 10000) {
console.error('Agent process exited too quickly. Killing entire process. Goodbye.');
process.exit(1);
console.error(`Agent process ${profile} exited too quickly and will not be restarted.`);
AgentProcess.runningCount--;
if (AgentProcess.runningCount <= 0) {
console.error('All agent processes have ended. Exiting.');
process.exit(0);
}
return;
}
console.log('Restarting agent...');
this.start(profile, true, 'Agent process restarted.');
this.start(profile, true, 'Agent process restarted.', count_id);
last_restart = Date.now();
}
});

View file

@ -22,6 +22,12 @@ const argv = yargs(args)
alias: 'm',
type: 'string',
description: 'automatically prompt the agent on startup'
})
.option('count_id', {
alias: 'c',
type: 'number',
default: 0,
description: 'identifying count for multi-agent scenarios',
}).argv
new Agent().start(argv.profile, argv.load_memory, argv.init_message);
new Agent().start(argv.profile, argv.load_memory, argv.init_message, argv.count_id);

View file

@ -31,13 +31,19 @@ export class Examples {
async load(examples) {
this.examples = examples;
if (this.model !== null) {
const embeddingPromises = this.examples.map(async (example) => {
let turn_text = this.turnsToText(example);
this.embeddings[turn_text] = await this.model.embed(turn_text);
});
await Promise.all(embeddingPromises);
try {
if (this.model !== null) {
const embeddingPromises = this.examples.map(async (example) => {
let turn_text = this.turnsToText(example);
this.embeddings[turn_text] = await this.model.embed(turn_text);
});
await Promise.all(embeddingPromises);
}
} catch (err) {
console.warn('Error with embedding model, using word overlap instead.');
this.model = null;
}
}
async getRelevant(turns) {

View file

@ -13,6 +13,11 @@ const mc_version = settings.minecraft_version;
const mcdata = minecraftData(mc_version);
const Item = prismarine_items(mc_version);
/**
* @typedef {string} ItemName
* @typedef {string} BlockName
*/
export const WOOD_TYPES = ['oak', 'spruce', 'birch', 'jungle', 'acacia', 'dark_oak'];
export const MATCHING_WOOD_BLOCKS = [
'log',
@ -241,4 +246,53 @@ export function getBlockTool(blockName) {
export function makeItem(name, amount=1) {
return new Item(getItemId(name), amount);
}
/**
* Returns the number of ingredients required to use the recipe once.
*
* @param {Recipe} recipe
* @returns {Object<mc.ItemName, number>} an object describing the number of each ingredient.
*/
export function ingredientsFromPrismarineRecipe(recipe) {
let requiredIngedients = {};
if (recipe.inShape)
for (const ingredient of recipe.inShape.flat()) {
if(ingredient.id<0) continue; //prismarine-recipe uses id -1 as an empty crafting slot
const ingredientName = getItemName(ingredient.id);
requiredIngedients[ingredientName] ??=0;
requiredIngedients[ingredientName] += ingredient.count;
}
if (recipe.ingredients)
for (const ingredient of recipe.ingredients) {
if(ingredient.id<0) continue;
const ingredientName = getItemName(ingredient.id);
requiredIngedients[ingredientName] ??=0;
requiredIngedients[ingredientName] -= ingredient.count;
//Yes, the `-=` is intended.
//prismarine-recipe uses positive numbers for the shaped ingredients but negative for unshaped.
//Why this is the case is beyond my understanding.
}
return requiredIngedients;
}
/**
* Calculates the number of times an action, such as a crafing recipe, can be completed before running out of resources.
* @template T - doesn't have to be an item. This could be any resource.
* @param {Object.<T, number>} availableItems - The resources available; e.g, `{'cobble_stone': 7, 'stick': 10}`
* @param {Object.<T, number>} requiredItems - The resources required to complete the action once; e.g, `{'cobble_stone': 3, 'stick': 2}`
* @param {boolean} discrete - Is the action discrete?
* @returns {{num: number, limitingResource: (T | null)}} the number of times the action can be completed and the limmiting resource; e.g `{num: 2, limitingResource: 'cobble_stone'}`
*/
export function calculateLimitingResource(availableItems, requiredItems, discrete=true) {
let limitingResource = null;
let num = Infinity;
for (const itemType in requiredItems) {
if (availableItems[itemType] < requiredItems[itemType] * num) {
limitingResource = itemType;
num = availableItems[itemType] / requiredItems[itemType];
}
}
if(discrete) num = Math.floor(num);
return {num, limitingResource}
}

69
viewer.html Normal file
View file

@ -0,0 +1,69 @@
<html>
<head>
<title>Viewer</title>
<style>
body {
margin: 0;
padding: 0;
}
#container {
display: flex;
flex-wrap: wrap;
width: 100%;
height: 100vh;
}
.iframe-wrapper {
border: none;
}
</style>
</head>
<body>
<div id="container">
<iframe data-port="3000" src="http://localhost:3000" class="iframe-wrapper"></iframe>
<iframe data-port="3001" src="http://localhost:3001" class="iframe-wrapper"></iframe>
<iframe data-port="3002" src="http://localhost:3002" class="iframe-wrapper"></iframe>
<iframe data-port="3003" src="http://localhost:3003" class="iframe-wrapper"></iframe>
</div>
<script>
function updateLayout() {
var width = window.innerWidth;
var height = window.innerHeight;
var iframes = document.querySelectorAll('.iframe-wrapper');
if (width > height) {
iframes.forEach(function(iframe) {
iframe.style.width = '50%';
iframe.style.height = '50%';
});
} else {
iframes.forEach(function(iframe) {
iframe.style.width = '100%';
iframe.style.height = '25%';
});
}
}
window.addEventListener('resize', updateLayout);
window.addEventListener('load', updateLayout);
var iframes = document.querySelectorAll('.iframe-wrapper');
iframes.forEach(function(iframe) {
var port = iframe.getAttribute('data-port');
var loaded = false;
function checkServer() {
fetch('http://localhost:' + port, { method: 'HEAD' })
.then(function(response) {
if (response.ok && !loaded) {
iframe.src = 'http://localhost:' + port;
}
})
.catch(function(error) {});
}
iframe.onload = function() {
loaded = true;
};
iframe.onerror = function() {
loaded = false;
};
setInterval(checkServer, 3000);
});
</script>
</body>
</html>