diff --git a/metagpt/actions/minecraft/review_task.py b/metagpt/actions/minecraft/review_task.py index 9f757d9ee..6ae1b7c11 100644 --- a/metagpt/actions/minecraft/review_task.py +++ b/metagpt/actions/minecraft/review_task.py @@ -4,8 +4,7 @@ # @Desc : from metagpt.logs import logger from metagpt.actions import Action - -from metagpt.actions import Action +from metagpt.utils.minecraft import fix_and_parse_json class VerifyTask(Action): @@ -17,22 +16,31 @@ class VerifyTask(Action): def __init__(self, name="", context=None, llm=None): super().__init__(name, context, llm) self.vect_db = "" - - async def run(self, *args, **kwargs): - task, status, review_info = None, False, "" + + async def run(self,human_msg, system_msg, max_retries=5, *args, **kwargs): + # Implement the logic to verify the task here. + + # Example: Verify the completion of a task. + + # If verification is successful, return a success message. + # task, status, review_info = "", True, "Task verified successfully." + + if max_retries == 0: + logger.info(f"Failed to parse Critic Agent response. Consider updating your prompt.") + return False, "" + + if human_msg or system_msg is None: + return False, "" + critic = await self._aask(prompt=human_msg, system_msgs=system_msg) try: - # Implement the logic to verify the task here. - - # Example: Verify the completion of a task. - - # If verification is successful, return a success message. + response = fix_and_parse_json(critic) + assert response["success"] in [True, False] + if "critique" not in response: + response["critique"] = "" logger.info("Task verified successfully.") - task, status, review_info = "", True, "Task verified successfully." - - # If verification fails, return an appropriate error message. - # return "Task verification failed due to [reason]." + return response["success"], response["critique"] except Exception as e: - # Handle any exceptions that may occur during verification. logger.error(f"Error verifying the task: {str(e)}") - task, status, review_info = None, False, "Task verified failed." - return task, status, review_info + return self.run(human_msg, system_msg, max_retries=max_retries-1) + + diff --git a/metagpt/roles/minecraft/critic_agent.py b/metagpt/roles/minecraft/critic_agent.py index 668cba662..5f4f59c46 100644 --- a/metagpt/roles/minecraft/critic_agent.py +++ b/metagpt/roles/minecraft/critic_agent.py @@ -3,9 +3,16 @@ # @Author : stellahong (stellahong@fuzhi.ai) # @Desc : from metagpt.roles.minecraft.minecraft_base import Minecraft as Base -from metagpt.actions.minecraft.review_task import VerifyTask from metagpt.actions.minecraft.generate_actions import GenerateActionCode +from metagpt.actions.minecraft.manage_skills import AddNewSkills +from metagpt.roles.minecraft.minecraft_base import agent_registry +from metagpt.actions.minecraft.review_task import VerifyTask +from metagpt.utils.minecraft import load_prompt +from metagpt.schema import Message, HumanMessage, SystemMessage +from metagpt.logs import logger + +@agent_registry.register("critic_agent") class CriticReviewer(Base): """ self-verification @@ -20,8 +27,117 @@ class CriticReviewer(Base): super().__init__(name, profile, goal, constraints) # Initialize actions specific to the CriticReviewer role self._init_actions([VerifyTask]) - + # Set events or actions the CriticReviewer should watch or be aware of # 需要获取最新的events来进行评估 - self._watch([GenerateActionCode]) - \ No newline at end of file + self._watch([GenerateActionCode,AddNewSkills]) + + def render_system_message(self): + system_message = SystemMessage(content=load_prompt("critic")) + return system_message + + def render_human_message(self, events, task, context, chest_observation): + assert events[-1][0] == "observe", "Last event must be observe" + biome = events[-1][1]["status"]["biome"] + time_of_day = events[-1][1]["status"]["timeOfDay"] + voxels = events[-1][1]["voxels"] + health = events[-1][1]["status"]["health"] + hunger = events[-1][1]["status"]["food"] + position = events[-1][1]["status"]["position"] + equipment = events[-1][1]["status"]["equipment"] + inventory_used = events[-1][1]["status"]["inventoryUsed"] + inventory = events[-1][1]["inventory"] + + for i, (event_type, event) in enumerate(events): + if event_type == "onError": + print(f"\033[31mCritic Agent: Error occurs {event['onError']}\033[0m") + return None + + observation = "" + + observation += f"Biome: {biome}\n\n" + + observation += f"Time: {time_of_day}\n\n" + + if voxels: + observation += f"Nearby blocks: {', '.join(voxels)}\n\n" + else: + observation += f"Nearby blocks: None\n\n" + + observation += f"Health: {health:.1f}/20\n\n" + observation += f"Hunger: {hunger:.1f}/20\n\n" + + observation += f"Position: x={position['x']:.1f}, y={position['y']:.1f}, z={position['z']:.1f}\n\n" + + observation += f"Equipment: {equipment}\n\n" + + if inventory: + observation += f"Inventory ({inventory_used}/36): {inventory}\n\n" + else: + observation += f"Inventory ({inventory_used}/36): Empty\n\n" + + observation += chest_observation + + observation += f"Task: {task}\n\n" + + if context: + observation += f"Context: {context}\n\n" + else: + observation += f"Context: None\n\n" + logger.info(f"****Critic Agent human message****\n: {observation}") + return HumanMessage(content=observation) + + def encapsule_message(self, + events, + task, + context, + chest_observation, + *args, + **kwargs, + ): + system_message = self.render_system_message() + human_message = self.render_human_message( + events=events, + task=task, + context=context, + chest_observation=chest_observation, + ) + + return { + "system_msg": [system_message.content], + "human_msg": human_message.content, + } + + async def verify_task(self,human_msg, system_msg, *args, **kwargs): + success, critique = await VerifyTask().run(human_msg, system_msg, max_retries=5) + return Message(content=f"{critique}", instruct_content="verify_task", role=self.profile, + send_to=agent_registry.entries["skill_manager"]()._setting.name)#addnewskill + #TODO:if not success + async def _act(self) -> Message: + todo = self._rc.todo + logger.debug(f"Todo is {todo}") + + # 获取最新的游戏周边信息 + events = await self._obtain_events() + context = self.game_memory.context + task = self.game_memory.current_task + chest_observation = self.game_memory.chest_observation + + message = self.encapsule_message(events=events, + task=task, + context=context, + chest_observation=chest_observation, ) + logger.info(todo) + handler_map = { + VerifyTask: self.verify_task, + } + handler = handler_map.get(type(todo)) + logger.info(handler) + if handler: + msg = await handler(**message) + msg.cause_by = type(todo) + logger.info(msg.send_to) + self._publish_message(msg) + return msg + + raise ValueError(f"Unknown todo type: {type(todo)}")