mirror of
https://github.com/FoundationAgents/MetaGPT.git
synced 2026-06-17 15:35:21 +02:00
Action developer add chest_memory & .run test pass
This commit is contained in:
parent
3a705a0e89
commit
73cd368828
8 changed files with 84 additions and 49 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -114,6 +114,7 @@ venv/
|
|||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
*/ckpt
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
|
|
|
|||
|
|
@ -32,11 +32,11 @@ class GenerateActionCode(Action):
|
|||
logger.error(f"Failed to parse response: {parsed_result}")
|
||||
return None
|
||||
|
||||
async def run(self, msg, *args, **kwargs):
|
||||
async def run(self, human_msg, system_msg, *args, **kwargs):
|
||||
logger.info(f"run {self.__repr__()}")
|
||||
# Generate action code.
|
||||
generated_code = await self.generate_code(
|
||||
human_msg=msg['human_msg'], system_msg=msg['system_msg']
|
||||
human_msg=human_msg, system_msg=system_msg
|
||||
)
|
||||
|
||||
# Return the generated code.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ from typing import Iterable, Dict, Any
|
|||
from pydantic import BaseModel, Field
|
||||
import requests
|
||||
import json
|
||||
import asyncio
|
||||
|
||||
from metagpt.logs import logger
|
||||
from metagpt.roles import Role
|
||||
|
|
@ -33,17 +32,31 @@ class GameEnvironment(BaseModel, arbitrary_types_allowed=True):
|
|||
critique: str = Field(default="")
|
||||
skills: list[str] = Field(default_factory=list)
|
||||
|
||||
chest_memory: dict[str, Any] = Field(default_factory=dict)
|
||||
|
||||
mf_instance: MineflayerEnv = Field(default_factory=MineflayerEnv)
|
||||
|
||||
def set_mc_port(self, mc_port):
|
||||
self.mf_instance.set_mc_port(mc_port)
|
||||
|
||||
def set_mc_resume(self, resume: bool = False):
|
||||
if resume:
|
||||
logger.info(
|
||||
f"Loading Action Developer from {self.mf_instance.ckpt_dir}/action"
|
||||
)
|
||||
with open(
|
||||
f"{self.mf_instance.ckpt_dir}/action/chest_memory.json", "r"
|
||||
) as f:
|
||||
self.chest_memory = json.load(f)
|
||||
# TODO: add skills resume
|
||||
|
||||
def register_roles(self, roles: Iterable[Minecraft]):
|
||||
for role in roles:
|
||||
role.set_memory(self)
|
||||
|
||||
def update_event(self, event: Dict):
|
||||
self.event = event
|
||||
self.update_chest_memory(event)
|
||||
|
||||
def update_task(self, task: str):
|
||||
self.current_task = task
|
||||
|
|
@ -52,7 +65,7 @@ class GameEnvironment(BaseModel, arbitrary_types_allowed=True):
|
|||
self.context = context
|
||||
|
||||
def update_code(self, code: str):
|
||||
self.code = code # action_developer.gen to HERE
|
||||
self.code = code # action_developer.gen_action_code to HERE
|
||||
|
||||
def update_programs(self, programs: str):
|
||||
self.programs = programs
|
||||
|
|
@ -63,6 +76,26 @@ class GameEnvironment(BaseModel, arbitrary_types_allowed=True):
|
|||
def update_skills(self, skills: list):
|
||||
self.skills = skills # skill_manager.retrieve_skills to HERE
|
||||
|
||||
def update_chest_memory(self, events: Dict):
|
||||
"""
|
||||
Input: events: Dict
|
||||
Result: self.chest_memory update & save to json
|
||||
"""
|
||||
nearbyChests = events[-1][1]["nearbyChests"]
|
||||
for position, chest in nearbyChests.items():
|
||||
if position in self.chest_memory:
|
||||
if isinstance(chest, dict):
|
||||
self.chest_memory[position] = chest
|
||||
if chest == "Invalid":
|
||||
logger.info(f"Action Developer removing chest {position}: {chest}")
|
||||
self.chest_memory.pop(position)
|
||||
else:
|
||||
if chest != "Invalid":
|
||||
logger.info(f"Action Developer saving chest {position}: {chest}")
|
||||
self.chest_memory[position] = chest
|
||||
with open(f"{self.mf_instance.ckpt_dir}/action/chest_memory.json", "w") as f:
|
||||
json.dump(self.chest_memory, f)
|
||||
|
||||
async def on_event(self, *args):
|
||||
"""
|
||||
Retrieve Minecraft events.
|
||||
|
|
@ -126,6 +159,9 @@ class MinecraftPlayer(SoftwareCompany):
|
|||
def set_port(self, mc_port):
|
||||
self.game_memory.set_mc_port(mc_port)
|
||||
|
||||
def set_resume(self, resume: bool = False):
|
||||
self.game_memory.set_mc_resume(resume=resume)
|
||||
|
||||
def hire(self, roles: list[Role]):
|
||||
self.environment.add_roles(roles)
|
||||
self.game_memory.register_roles(roles)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ class MineflayerEnv:
|
|||
self.reset_options = None
|
||||
self.connected = False
|
||||
self.server_paused = False
|
||||
self.ckpt_dir = "metagpt/ckpt"
|
||||
|
||||
os.makedirs(f"{self.ckpt_dir}/action", exist_ok=True)
|
||||
|
||||
def set_mc_port(self, mc_port):
|
||||
self.mc_port = mc_port
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ from metagpt.roles.minecraft.minecraft_base import Minecraft as Base
|
|||
from metagpt.schema import Message, HumanMessage, SystemMessage
|
||||
from metagpt.roles.minecraft.minecraft_base import agent_registry
|
||||
from metagpt.actions.minecraft.generate_actions import GenerateActionCode
|
||||
from metagpt.actions.minecraft.design_curriculumn import DesignCurriculum
|
||||
from metagpt.actions.minecraft.manage_skills import (
|
||||
GenerateSkillDescription,
|
||||
RetrieveSkills,
|
||||
|
|
@ -42,6 +41,30 @@ class ActionDeveloper(Base):
|
|||
# 需要根据events进行自己chest_observation的更新
|
||||
self._watch([RetrieveSkills])
|
||||
|
||||
def render_chest_observation(self):
|
||||
"""
|
||||
Render game_memory.chest_memory to prompt text.
|
||||
Refer to @ https://github.com/MineDojo/Voyager/blob/main/voyager/agents/action.py
|
||||
"""
|
||||
|
||||
chests = []
|
||||
for chest_position, chest in self.game_memory.chest_memory.items():
|
||||
if isinstance(chest, dict) and len(chest) > 0:
|
||||
chests.append(f"{chest_position}: {chest}")
|
||||
for chest_position, chest in self.game_memory.chest_memory.items():
|
||||
if isinstance(chest, dict) and len(chest) == 0:
|
||||
chests.append(f"{chest_position}: Empty")
|
||||
for chest_position, chest in self.game_memory.chest_memory.items():
|
||||
if isinstance(chest, str):
|
||||
assert chest == "Unknown"
|
||||
chests.append(f"{chest_position}: Unknown items inside")
|
||||
assert len(chests) == len(self.game_memory.chest_memory)
|
||||
if chests:
|
||||
chests = "\n".join(chests)
|
||||
return f"Chests:\n{chests}\n\n"
|
||||
else:
|
||||
return f"Chests: None\n\n"
|
||||
|
||||
def render_system_message(self, skills=[], *args, **kwargs):
|
||||
"""
|
||||
According to basic skills context files to genenarate js skill codes.
|
||||
|
|
@ -140,12 +163,12 @@ class ActionDeveloper(Base):
|
|||
observation += f"Equipment: {equipment}\n\n"
|
||||
observation += f"Inventory ({inventory_used}/36): {'Empty' if not inventory else ', '.join(inventory)}\n\n"
|
||||
|
||||
if not (
|
||||
task == "Place and deposit useless items into a chest"
|
||||
or task.startswith("Deposit useless items into the chest at")
|
||||
):
|
||||
# TODO: observation += self.render_chest_observation()
|
||||
logger.warning("chest_observation will add later")
|
||||
# TODO: if task update, uncomment this
|
||||
# if not (
|
||||
# task == "Place and deposit useless items into a chest"
|
||||
# or task.startswith("Deposit useless items into the chest at")
|
||||
# ):
|
||||
observation += self.render_chest_observation()
|
||||
|
||||
observation += f"Task: {task}\n\n"
|
||||
observation += f"Context: {context or 'None'}\n\n"
|
||||
|
|
@ -183,8 +206,8 @@ class ActionDeveloper(Base):
|
|||
logger.info(len(self._rc.news))
|
||||
return len(self._rc.news)
|
||||
|
||||
async def generate_action_code(self, msg, *args, **kwargs):
|
||||
code = await GenerateActionCode().run(msg, *args, **kwargs)
|
||||
async def generate_action_code(self, human_msg, system_msg, *args, **kwargs):
|
||||
code = await GenerateActionCode().run(human_msg, system_msg, *args, **kwargs)
|
||||
# logger.warning(type(code))
|
||||
# logger.info(f"Code is Here:{code}")
|
||||
self.perform_game_info_callback(code, self.game_memory.update_code)
|
||||
|
|
@ -202,6 +225,7 @@ class ActionDeveloper(Base):
|
|||
|
||||
# 获取最新的游戏周边信息
|
||||
events = await self._obtain_events()
|
||||
self.perform_game_info_callback(events, self.game_memory.update_event)
|
||||
context = self.game_memory.context
|
||||
task = self.game_memory.current_task
|
||||
code = self.game_memory.code
|
||||
|
|
|
|||
|
|
@ -6,38 +6,6 @@
|
|||
import json
|
||||
import re
|
||||
from typing import Any, Dict, Union
|
||||
from .file_utils import f_join
|
||||
|
||||
|
||||
def json_load(*file_path, **kwargs):
|
||||
file_path = f_join(file_path)
|
||||
with open(file_path, "r") as fp:
|
||||
return json.load(fp, **kwargs)
|
||||
|
||||
|
||||
def json_loads(string, **kwargs):
|
||||
return json.loads(string, **kwargs)
|
||||
|
||||
|
||||
def json_dump(data, *file_path, **kwargs):
|
||||
file_path = f_join(file_path)
|
||||
with open(file_path, "w") as fp:
|
||||
json.dump(data, fp, **kwargs)
|
||||
|
||||
|
||||
def json_dumps(data, **kwargs):
|
||||
"""
|
||||
Returns: string
|
||||
"""
|
||||
return json.dumps(data, **kwargs)
|
||||
|
||||
|
||||
# ---------------- Aliases -----------------
|
||||
# add aliases where verb goes first, json_load -> load_json
|
||||
load_json = json_load
|
||||
loads_json = json_loads
|
||||
dump_json = json_dump
|
||||
dumps_json = json_dumps
|
||||
|
||||
|
||||
def extract_char_position(error_message: str) -> int:
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ from metagpt.minecraft_team import MinecraftPlayer
|
|||
|
||||
async def learn(task="Start", investment: float = 50.0, n_round: int = 3):
|
||||
mc_player = MinecraftPlayer()
|
||||
mc_player.set_port(2253) # Modify this to your LAN port
|
||||
mc_player.set_port(1077) # Modify this to your Minecraft LAN port
|
||||
# mc_player.set_resume(True) # If load json from ckpt dir(include chest_memory, skills, ...)
|
||||
mc_player.hire(
|
||||
[
|
||||
CurriculumDesigner(),
|
||||
|
|
|
|||
|
|
@ -37,11 +37,12 @@ async def main():
|
|||
"elapsedTime": 41,
|
||||
},
|
||||
"inventory": {},
|
||||
"nearbyChests": {},
|
||||
"nearbyChests": {"(1344, 64, 1381)": "Unknown"},
|
||||
"blockRecords": ["grass_block", "dirt", "grass"],
|
||||
},
|
||||
]
|
||||
]
|
||||
|
||||
code = """
|
||||
async function collectBamboo(bot) {
|
||||
// Equip the iron sword
|
||||
|
|
@ -78,11 +79,12 @@ async def main():
|
|||
"""
|
||||
ad = ActionDeveloper()
|
||||
ge = GameEnvironment()
|
||||
ge.update_event(events)
|
||||
ad.set_memory(shared_memory=ge)
|
||||
msg = ad.encapsule_message(events=events, code=code)
|
||||
msg = ad.encapsule_message(events=ge.event, code=code)
|
||||
logger.info(f"Encapsuled_message: {msg}")
|
||||
|
||||
parsed_result = await ad.generate_action_code(msg)
|
||||
parsed_result = await ad.generate_action_code(**msg)
|
||||
|
||||
logger.info(f"Parsed_code_updating: {parsed_result}")
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue