mirror of
https://github.com/FoundationAgents/MetaGPT.git
synced 2026-06-17 15:35:21 +02:00
Move test func & add comment
This commit is contained in:
parent
7f763b57d0
commit
3a705a0e89
25 changed files with 489 additions and 333 deletions
|
|
@ -5,5 +5,4 @@
|
|||
from .load_prompts import load_prompt
|
||||
from .json_utils import *
|
||||
from .file_utils import *
|
||||
from .load_skills_code_context import load_skills_code_context
|
||||
from .action_rsp_parser import parse_action_response
|
||||
from .action_rsp_parser import parse_js_code, parse_action_response
|
||||
|
|
|
|||
|
|
@ -2,28 +2,47 @@ import re
|
|||
import time
|
||||
from javascript import require
|
||||
|
||||
def parse_js_code(msg: str):
|
||||
'''
|
||||
Extract and Parse JavaScript code blocks
|
||||
'''
|
||||
babel = require("@babel/core")
|
||||
code_pattern = re.compile(r"```(?:javascript|js)(.*?)```", re.DOTALL)
|
||||
code = "\n".join(code_pattern.findall(msg))
|
||||
parsed = babel.parse(code)
|
||||
return parsed
|
||||
|
||||
def parse_action_response(msg: str):
|
||||
"""
|
||||
Input:
|
||||
'''
|
||||
Explain: ...
|
||||
Plan: ...
|
||||
Code:
|
||||
```javascript
|
||||
...
|
||||
```
|
||||
'''
|
||||
|
||||
Return:
|
||||
{
|
||||
"program_code": program_code,
|
||||
"program_name": main_function["name"],
|
||||
"exec_code": exec_code,
|
||||
}
|
||||
} or
|
||||
|
||||
"{error}"
|
||||
|
||||
Refer to @ https://github.com/MineDojo/Voyager/blob/main/voyager/agents/action.py
|
||||
"""
|
||||
|
||||
retry = 3
|
||||
error = None
|
||||
error = None # 3 times failed return error
|
||||
babel_generator = require("@babel/generator").default
|
||||
while retry > 0:
|
||||
try:
|
||||
babel = require("@babel/core")
|
||||
babel_generator = require("@babel/generator").default
|
||||
|
||||
code_pattern = re.compile(r"```(?:javascript|js)(.*?)```", re.DOTALL)
|
||||
code = "\n".join(code_pattern.findall(msg))
|
||||
parsed = babel.parse(code)
|
||||
parsed = parse_js_code(msg)
|
||||
# Collect func list: check if func & async
|
||||
functions = []
|
||||
assert len(list(parsed.program.body)) > 0, "No functions found"
|
||||
for i, node in enumerate(parsed.program.body):
|
||||
|
|
@ -42,7 +61,8 @@ def parse_action_response(msg: str):
|
|||
"params": list(node["params"]),
|
||||
}
|
||||
)
|
||||
# find the last async function
|
||||
|
||||
# Ensure main_function is the last async function
|
||||
main_function = None
|
||||
for function in reversed(functions):
|
||||
if function["type"] == "AsyncFunctionDeclaration":
|
||||
|
|
@ -55,6 +75,8 @@ def parse_action_response(msg: str):
|
|||
len(main_function["params"]) == 1
|
||||
and main_function["params"][0].name == "bot"
|
||||
), f"Main function {main_function['name']} must take a single argument named 'bot'"
|
||||
|
||||
# Split to program_code & exec_code for output
|
||||
program_code = "\n\n".join(function["body"] for function in functions)
|
||||
exec_code = f"await {main_function['name']}(bot);"
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
import os
|
||||
import metagpt.utils.minecraft as utils
|
||||
from metagpt.logs import logger
|
||||
|
||||
|
||||
def load_skills_code_context(skill_names=None):
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
skills_dir = os.path.join(current_dir, "skills_code_context")
|
||||
if skill_names is None:
|
||||
skill_names = [
|
||||
skill[:-3] for skill in os.listdir(f"{skills_dir}") if skill.endswith(".js")
|
||||
]
|
||||
skills = [
|
||||
utils.load_text(os.path.join(skills_dir, f"{skill_name}.js"))
|
||||
for skill_name in skill_names
|
||||
]
|
||||
return skills
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
logger.info(load_skills_code_context(["craftItem", "exploreUntil"]))
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"tabWidth": 4
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
// Craft 8 oak_planks from 2 oak_log (do the recipe 2 times): craftItem(bot, "oak_planks", 2);
|
||||
// You must place a crafting table before calling this function
|
||||
async function craftItem(bot, name, count = 1) {
|
||||
const item = mcData.itemsByName[name];
|
||||
const craftingTable = bot.findBlock({
|
||||
matching: mcData.blocksByName.crafting_table.id,
|
||||
maxDistance: 32,
|
||||
});
|
||||
await bot.pathfinder.goto(
|
||||
new GoalLookAtBlock(craftingTable.position, bot.world)
|
||||
);
|
||||
const recipe = bot.recipesFor(item.id, null, 1, craftingTable)[0];
|
||||
await bot.craft(recipe, count, craftingTable);
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
Explore until find an iron_ore, use Vec3(0, -1, 0) because iron ores are usually underground
|
||||
await exploreUntil(bot, new Vec3(0, -1, 0), 60, () => {
|
||||
const iron_ore = bot.findBlock({
|
||||
matching: mcData.blocksByName["iron_ore"].id,
|
||||
maxDistance: 32,
|
||||
});
|
||||
return iron_ore;
|
||||
});
|
||||
|
||||
Explore until find a pig, use Vec3(1, 0, 1) because pigs are usually on the surface
|
||||
let pig = await exploreUntil(bot, new Vec3(1, 0, 1), 60, () => {
|
||||
const pig = bot.nearestEntity((entity) => {
|
||||
return (
|
||||
entity.name === "pig" &&
|
||||
entity.position.distanceTo(bot.entity.position) < 32
|
||||
);
|
||||
});
|
||||
return pig;
|
||||
});
|
||||
*/
|
||||
async function exploreUntil(bot, direction, maxTime = 60, callback) {
|
||||
/*
|
||||
Implementation of this function is omitted.
|
||||
direction: Vec3, can only contain value of -1, 0 or 1
|
||||
maxTime: number, the max time for exploration
|
||||
callback: function, early stop condition, will be called each second, exploration will stop if return value is not null
|
||||
|
||||
Return: null if explore timeout, otherwise return the return value of callback
|
||||
*/
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
// Kill a pig and collect the dropped item: killMob(bot, "pig", 300);
|
||||
async function killMob(bot, mobName, timeout = 300) {
|
||||
const entity = bot.nearestEntity(
|
||||
(entity) =>
|
||||
entity.name === mobName &&
|
||||
entity.position.distanceTo(bot.entity.position) < 32
|
||||
);
|
||||
await bot.pvp.attack(entity);
|
||||
await bot.pathfinder.goto(
|
||||
new GoalBlock(entity.position.x, entity.position.y, entity.position.z)
|
||||
);
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
// Mine 3 cobblestone: mineBlock(bot, "stone", 3);
|
||||
async function mineBlock(bot, name, count = 1) {
|
||||
const blocks = bot.findBlocks({
|
||||
matching: (block) => {
|
||||
return block.name === name;
|
||||
},
|
||||
maxDistance: 32,
|
||||
count: count,
|
||||
});
|
||||
const targets = [];
|
||||
for (let i = 0; i < Math.min(blocks.length, count); i++) {
|
||||
targets.push(bot.blockAt(blocks[i]));
|
||||
}
|
||||
await bot.collectBlock.collect(targets, { ignoreNoPath: true });
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
await bot.pathfinder.goto(goal); // A very useful function. This function may change your main-hand equipment.
|
||||
// Following are some Goals you can use:
|
||||
new GoalNear(x, y, z, range); // Move the bot to a block within the specified range of the specified block. `x`, `y`, `z`, and `range` are `number`
|
||||
new GoalXZ(x, z); // Useful for long-range goals that don't have a specific Y level. `x` and `z` are `number`
|
||||
new GoalGetToBlock(x, y, z); // Not get into the block, but get directly adjacent to it. Useful for fishing, farming, filling bucket, and beds. `x`, `y`, and `z` are `number`
|
||||
new GoalFollow(entity, range); // Follow the specified entity within the specified range. `entity` is `Entity`, `range` is `number`
|
||||
new GoalPlaceBlock(position, bot.world, {}); // Position the bot in order to place a block. `position` is `Vec3`
|
||||
new GoalLookAtBlock(position, bot.world, {}); // Path into a position where a blockface of the block at position is visible. `position` is `Vec3`
|
||||
|
||||
// These are other Mineflayer functions you can use:
|
||||
bot.isABed(bedBlock); // Return true if `bedBlock` is a bed
|
||||
bot.blockAt(position); // Return the block at `position`. `position` is `Vec3`
|
||||
|
||||
// These are other Mineflayer async functions you can use:
|
||||
await bot.equip(item, destination); // Equip the item in the specified destination. `item` is `Item`, `destination` can only be "hand", "head", "torso", "legs", "feet", "off-hand"
|
||||
await bot.consume(); // Consume the item in the bot's hand. You must equip the item to consume first. Useful for eating food, drinking potions, etc.
|
||||
await bot.fish(); // Let bot fish. Before calling this function, you must first get to a water block and then equip a fishing rod. The bot will automatically stop fishing when it catches a fish
|
||||
await bot.sleep(bedBlock); // Sleep until sunrise. You must get to a bed block first
|
||||
await bot.activateBlock(block); // This is the same as right-clicking a block in the game. Useful for buttons, doors, etc. You must get to the block first
|
||||
await bot.lookAt(position); // Look at the specified position. You must go near the position before you look at it. To fill bucket with water, you must lookAt first. `position` is `Vec3`
|
||||
await bot.activateItem(); // This is the same as right-clicking to use the item in the bot's hand. Useful for using buckets, etc. You must equip the item to activate first
|
||||
await bot.useOn(entity); // This is the same as right-clicking an entity in the game. Useful for shearing sheep, equipping harnesses, etc. You must get to the entity first
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
// Place a crafting_table near the player, Vec3(1, 0, 0) is just an example, you shouldn't always use that: placeItem(bot, "crafting_table", bot.entity.position.offset(1, 0, 0));
|
||||
async function placeItem(bot, name, position) {
|
||||
const item = bot.inventory.findInventoryItem(mcData.itemsByName[name].id);
|
||||
// find a reference block
|
||||
const faceVectors = [
|
||||
new Vec3(0, 1, 0),
|
||||
new Vec3(0, -1, 0),
|
||||
new Vec3(1, 0, 0),
|
||||
new Vec3(-1, 0, 0),
|
||||
new Vec3(0, 0, 1),
|
||||
new Vec3(0, 0, -1),
|
||||
];
|
||||
let referenceBlock = null;
|
||||
let faceVector = null;
|
||||
for (const vector of faceVectors) {
|
||||
const block = bot.blockAt(position.minus(vector));
|
||||
if (block?.name !== "air") {
|
||||
referenceBlock = block;
|
||||
faceVector = vector;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// You must first go to the block position you want to place
|
||||
await bot.pathfinder.goto(new GoalPlaceBlock(position, bot.world, {}));
|
||||
// You must equip the item right before calling placeBlock
|
||||
await bot.equip(item, "hand");
|
||||
await bot.placeBlock(referenceBlock, faceVector);
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
// Smelt 1 raw_iron into 1 iron_ingot using 1 oak_planks as fuel: smeltItem(bot, "raw_iron", "oak_planks");
|
||||
// You must place a furnace before calling this function
|
||||
async function smeltItem(bot, itemName, fuelName, count = 1) {
|
||||
const item = mcData.itemsByName[itemName];
|
||||
const fuel = mcData.itemsByName[fuelName];
|
||||
const furnaceBlock = bot.findBlock({
|
||||
matching: mcData.blocksByName.furnace.id,
|
||||
maxDistance: 32,
|
||||
});
|
||||
await bot.pathfinder.goto(
|
||||
new GoalLookAtBlock(furnaceBlock.position, bot.world)
|
||||
);
|
||||
const furnace = await bot.openFurnace(furnaceBlock);
|
||||
for (let i = 0; i < count; i++) {
|
||||
await furnace.putFuel(fuel.id, null, 1);
|
||||
await furnace.putInput(item.id, null, 1);
|
||||
// Wait 12 seconds for the furnace to smelt the item
|
||||
await bot.waitForTicks(12 * 20);
|
||||
await furnace.takeOutput();
|
||||
}
|
||||
await furnace.close();
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
// Get a torch from chest at (30, 65, 100): getItemFromChest(bot, new Vec3(30, 65, 100), {"torch": 1});
|
||||
// This function will work no matter how far the bot is from the chest.
|
||||
async function getItemFromChest(bot, chestPosition, itemsToGet) {
|
||||
await moveToChest(bot, chestPosition);
|
||||
const chestBlock = bot.blockAt(chestPosition);
|
||||
const chest = await bot.openContainer(chestBlock);
|
||||
for (const name in itemsToGet) {
|
||||
const itemByName = mcData.itemsByName[name];
|
||||
const item = chest.findContainerItem(itemByName.id);
|
||||
await chest.withdraw(item.type, null, itemsToGet[name]);
|
||||
}
|
||||
await closeChest(bot, chestBlock);
|
||||
}
|
||||
// Deposit a torch into chest at (30, 65, 100): depositItemIntoChest(bot, new Vec3(30, 65, 100), {"torch": 1});
|
||||
// This function will work no matter how far the bot is from the chest.
|
||||
async function depositItemIntoChest(bot, chestPosition, itemsToDeposit) {
|
||||
await moveToChest(bot, chestPosition);
|
||||
const chestBlock = bot.blockAt(chestPosition);
|
||||
const chest = await bot.openContainer(chestBlock);
|
||||
for (const name in itemsToDeposit) {
|
||||
const itemByName = mcData.itemsByName[name];
|
||||
const item = bot.inventory.findInventoryItem(itemByName.id);
|
||||
await chest.deposit(item.type, null, itemsToDeposit[name]);
|
||||
}
|
||||
await closeChest(bot, chestBlock);
|
||||
}
|
||||
// Check the items inside the chest at (30, 65, 100): checkItemInsideChest(bot, new Vec3(30, 65, 100));
|
||||
// You only need to call this function once without any action to finish task of checking items inside the chest.
|
||||
async function checkItemInsideChest(bot, chestPosition) {
|
||||
await moveToChest(bot, chestPosition);
|
||||
const chestBlock = bot.blockAt(chestPosition);
|
||||
await bot.openContainer(chestBlock);
|
||||
// You must close the chest after opening it if you are asked to open a chest
|
||||
await closeChest(bot, chestBlock);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue