From c6b28643bdd27d5079c287365240a31fa78b08a8 Mon Sep 17 00:00:00 2001 From: garylin2099 Date: Tue, 4 Jun 2024 20:59:21 +0800 Subject: [PATCH] refactor team leader, use RoleZero framework --- metagpt/prompts/di/engineer2.py | 6 ++ metagpt/prompts/di/role_zero.py | 25 +++--- metagpt/prompts/di/team_leader.py | 49 ++--------- metagpt/roles/di/engineer2.py | 19 ++-- metagpt/roles/di/role_zero.py | 77 +++++++++++----- metagpt/roles/di/team_leader.py | 107 +++++++++-------------- metagpt/strategy/experience_retriever.py | 53 ++++++----- 7 files changed, 158 insertions(+), 178 deletions(-) create mode 100644 metagpt/prompts/di/engineer2.py diff --git a/metagpt/prompts/di/engineer2.py b/metagpt/prompts/di/engineer2.py new file mode 100644 index 000000000..346f2fc5a --- /dev/null +++ b/metagpt/prompts/di/engineer2.py @@ -0,0 +1,6 @@ +from metagpt.prompts.di.role_zero import ROLE_INSTRUCTION + +ENGINEER2_INSTRUCTION = ( + ROLE_INSTRUCTION + + "4. Each time you write a code in your response, write with the Editor directly without preparing a repetitive code block beforehand." +) diff --git a/metagpt/prompts/di/role_zero.py b/metagpt/prompts/di/role_zero.py index 4fececf7f..f098d2c4b 100644 --- a/metagpt/prompts/di/role_zero.py +++ b/metagpt/prompts/di/role_zero.py @@ -1,3 +1,14 @@ +ROLE_INSTRUCTION = """ +Based on the context, write a plan or modify an existing plan to achieve the goal. A plan consists of one to 3 tasks. +If plan is created, you should track the progress and update the plan accordingly, such as Plan.finish_current_task, Plan.append_task, Plan.reset_task, Plan.replace_task, etc. +When presented a current task, tackle the task using the available commands. +Pay close attention to new user message, review the conversation history, use RoleZero.reply_to_human to respond to new user requirement. +Note: +1. If you keeping encountering errors, unexpected situation, or you are not sure of proceeding, use RoleZero.ask_human to ask for help. +2. Carefully review your progress at the current task, if your actions so far has not fulfilled the task instruction, you should continue with current task. Otherwise, finish current task. +3. Each time you finish a task, use RoleZero.reply_to_human to report your progress. +""" + CMD_PROMPT = """ # Data Structure class Task(BaseModel): @@ -20,18 +31,10 @@ Special Command: Use {{"command_name": "pass"}} to do nothing and {{"command_nam # Example {example} -# Instructions -Based on the context, write a plan or modify an existing plan to achieve the goal. A plan consists of one to 3 tasks. -If plan is created, you should track the progress and update the plan accordingly, such as Plan.finish_current_task, Plan.append_task, Plan.reset_task, Plan.replace_task, etc. -When presented a current task, tackle the task using the available commands. -Pay close attention to new user message, review the conversation history, use MGXEnv.reply_to_human to respond to new user requirement. -Note: -1. If you keeping encountering errors, unexpected situation, or you are not sure of proceeding, use MGXEnv.ask_human to ask for help. -2. Carefully review your progress at the current task, if your actions so far has not fulfilled the task instruction, you should continue with current task. Otherwise, finish current task. -3. Each time you finish a task, use MGXEnv.reply_to_human to report your progress. -4. Each time you write a code in your response, write with the Editor directly without preparing a repetitive code block beforehand. -Pay close attention to the Example provided, you can reuse the example for your current situation if it fits. +# Instruction +{instruction} +Pay close attention to the Example provided, you can reuse the example for your current situation if it fits. You may use any of the available commands to create a plan or update the plan. You may output mutiple commands, they will be executed sequentially. If you finish current task, you will automatically take the next task in the existing plan, use Plan.finish_task, DON'T append a new task. diff --git a/metagpt/prompts/di/team_leader.py b/metagpt/prompts/di/team_leader.py index dacd3d876..14297b026 100644 --- a/metagpt/prompts/di/team_leader.py +++ b/metagpt/prompts/di/team_leader.py @@ -4,62 +4,27 @@ When drafting and routing tasks, ALWAYS include necessary or important info insi Each time you do something, reply to human letting them know what you did. """ -CMD_PROMPT = """ -# Data Structure -class Task(BaseModel): - task_id: str = "" - dependent_task_ids: list[str] = [] - instruction: str = "" - task_type: str = "" - assignee: str = "" - -# Team Member Info -{team_info} - -# Available Commands -{available_commands} - -# Current Plan -{plan_status} - -# Example -{example} - -# Instructions +TL_INSTRUCTION = """ You are a team leader, and you are responsible for drafting tasks and routing tasks to your team members. +Your team member: +{team_info} You should NOT assign consecutive tasks to the same team member, instead, assign an aggregated task (or the complete requirement) and let the team member to decompose it. When creating a new plan involving multiple members, create all tasks at once. -If plan is created, you should track the progress based on team member feedback message, and update plan accordingly, such as finish_current_task, reset_task, replace_task, etc. -You should publish_message to team members, asking them to start their task. -Pay close attention to new user message, review the conversation history, use reply_to_human to respond to the user directly, DON'T ask your team members. +If plan is created, you should track the progress based on team member feedback message, and update plan accordingly, such as Plan.finish_current_task, Plan.reset_task, Plan.replace_task, etc. +You should use TeamLeader.publish_team_message to team members, asking them to start their task. +Pay close attention to new user message, review the conversation history, use RoleZero.reply_to_human to respond to the user directly, DON'T ask your team members. Note: 1. If the requirement is a pure DATA-RELATED requirement, such as bug fixes, issue reporting, environment setup, terminal operations, pip install, web browsing, web scraping, web searching, web imitation, data science, data analysis, machine learning, deep learning, text-to-image etc. DON'T decompose it, assign a single task with the original user requirement as instruction directly to Data Analyst. 2. If the requirement is developing a software, game, app, or website, excluding the above data-related tasks, you should decompose the requirement into multiple tasks and assign them to different team members based on their expertise, usually the sequence of Product Manager -> Architect -> Project Manager -> Engineer -> (optional: QaEngine if present) -> (optional: DataAnalyst if user requests deployment), each assigned ONE task. When publishing message to Product Manager, you should directly copy the full original user requirement. 3. If the requirement contains both DATA-RELATED part mentioned in 1 and software development part mentioned in 2, you should decompose the software development part and assign them to different team members based on their expertise, and assign the DATA-RELATED part to Data Analyst David directly. -Pay close attention to the Example provided - -You may use any of the available commands to create a plan or update the plan. You may output mutiple commands, they will be executed sequentially. -If you finish current task, you will automatically take the next task in the existing plan, use finish_task, DON'T append a new task. - -# Your commands in a json array, in the following output format, always output a json array, if there is nothing to do, use the pass command: -Some text indicating your thoughts, such as how you categorize the requirement based on Note (is it 1., 2., or 3.?) or how you should update the plan status. Then a json array of commands. -```json -[ - {{ - "command_name": str, - "args": {{"arg_name": arg_value, ...}} - }}, - ... -] -``` """ FINISH_CURRENT_TASK_CMD = """ ```json [ { - "command_name": "finish_current_task", + "command_name": "Plan.finish_current_task", "args": {{}} } ``` diff --git a/metagpt/roles/di/engineer2.py b/metagpt/roles/di/engineer2.py index 8618e0c47..673f3ff64 100644 --- a/metagpt/roles/di/engineer2.py +++ b/metagpt/roles/di/engineer2.py @@ -4,34 +4,32 @@ import asyncio from pydantic import model_validator +from metagpt.prompts.di.engineer2 import ENGINEER2_INSTRUCTION from metagpt.roles.di.role_zero import RoleZero from metagpt.tools.libs.editor import Editor from test3 import design_doc_2048, design_doc_snake, task_doc_2048, task_doc_snake -def dummy_func(**kwargs): - pass - - class Engineer2(RoleZero): name: str = "Alex" profile: str = "Engineer" - goal: str = "" - tools: str = ["Plan", "Editor:write,read,write_content", "MGXEnv:ask_human,reply_to_human"] + goal: str = "Take on game, app, and web development" + tools: str = ["Plan", "Editor:write,read,write_content", "RoleZero"] + instruction: str = ENGINEER2_INSTRUCTION editor: Editor = Editor() @model_validator(mode="after") - def set_tool_execution_map(self) -> "RoleZero": - self.tool_execute_map = { + def set_tool_execution(self) -> "RoleZero": + self.tool_execution_map = { "Plan.append_task": self.planner.plan.append_task, "Plan.reset_task": self.planner.plan.reset_task, "Plan.replace_task": self.planner.plan.replace_task, "Editor.write": self.editor.write, "Editor.write_content": self.editor.write_content, "Editor.read": self.editor.read, - "MGXEnv.ask_human": dummy_func, - "MGXEnv.reply_to_human": dummy_func, + "RoleZero.ask_human": self.ask_human, + "RoleZero.reply_to_human": self.reply_to_human, } return self @@ -70,6 +68,7 @@ Found this issue, TypeError: generate_new_position() missing 1 required position Write code review for the codes (food.py, game.py, main.py, snake.py, ui.py) under under /Users/gary/Files/temp/workspace/snake_game_bugs/src. Then correct any issues you find. You can review all code in one time, and solve issues in one time. """ +CASUAL_CHAT = """what's your name?""" if __name__ == "__main__": engineer2 = Engineer2() diff --git a/metagpt/roles/di/role_zero.py b/metagpt/roles/di/role_zero.py index 8d6455d90..f1518f8be 100644 --- a/metagpt/roles/di/role_zero.py +++ b/metagpt/roles/di/role_zero.py @@ -9,22 +9,28 @@ from pydantic import model_validator from metagpt.actions import Action from metagpt.actions.di.run_command import RunCommand +from metagpt.environment.mgx.mgx_env import MGXEnv from metagpt.logs import logger -from metagpt.prompts.di.role_zero import CMD_PROMPT +from metagpt.prompts.di.role_zero import CMD_PROMPT, ROLE_INSTRUCTION from metagpt.roles import Role from metagpt.schema import Message -from metagpt.strategy.experience_retriever import KeywordExpRetriever +from metagpt.strategy.experience_retriever import DummyExpRetriever, ExpRetriever from metagpt.strategy.planner import Planner from metagpt.tools.tool_recommend import BM25ToolRecommender, ToolRecommender +from metagpt.tools.tool_registry import register_tool from metagpt.utils.common import CodeParser +@register_tool(include_functions=["ask_human", "reply_to_human"]) class RoleZero(Role): + """A role serving as the basis for other MGX roles.""" + name: str = "Zero" profile: str = "RoleZero" goal: str = "" - system_msg: str = "" + system_msg: list[str] = None # Use None to conform to the default value at llm.aask cmd_prompt: str = CMD_PROMPT + instruction: str = ROLE_INSTRUCTION react_mode: Literal["react"] = "react" max_react_loop: int = 20 # used for react mode @@ -37,6 +43,9 @@ class RoleZero(Role): tools: list[str] = [] # Use special symbol [""] to indicate use of all registered tools tool_recommender: ToolRecommender = None tool_execution_map: dict[str, callable] = {} + special_tool_commands: list[str] = ["Plan.finish_current_task", "end"] + + experience_retriever: ExpRetriever = DummyExpRetriever() @model_validator(mode="after") def set_plan_and_tool(self) -> "RoleZero": @@ -56,30 +65,23 @@ class RoleZero(Role): return self @model_validator(mode="after") - def set_tool_execution_map(self) -> "RoleZero": + def set_tool_execution(self) -> "RoleZero": raise NotImplementedError async def _think(self) -> bool: """Useful in 'react' mode. Use LLM to decide whether and what to do next.""" + ### 0. Preparation ### if not self.rc.todo and not self.rc.news: return False - self._set_state(0) - example = "" if not self.planner.plan.goal: self.user_requirement = self.get_memories()[-1].content self.planner.plan.goal = self.user_requirement - example = KeywordExpRetriever().retrieve(self.user_requirement) - else: - self.rc.memory.add_batch(self.rc.news) - # TODO: implement experience retrieval in multi-round setting - # if self.planner.plan.current_task: - # experience = KeywordExpRetriever().retrieve(self.planner.plan.current_task.instruction, exp_type="task") - # if experience and experience not in [msg.content for msg in self.rc.memory.get()]: - # exp_msg = Message(content=experience, role="assistant") - # self.rc.memory.add(exp_msg) - # example = KeywordExpRetriever().retrieve(self.planner.plan.current_task.instruction, exp_type="task") + ### 1. Experience ### + example = self._retrieve_experience() + + ### 2. Plan Status ### plan_status = self.planner.plan.model_dump(include=["goal", "tasks"]) for task in plan_status["tasks"]: task.pop("code") @@ -92,20 +94,21 @@ class RoleZero(Role): else "" ) + ### 3. Tool/Command Info ### tools = await self.tool_recommender.recommend_tools() tool_info = json.dumps({tool.name: tool.schemas for tool in tools}) + + ### Make Decision ### prompt = self.cmd_prompt.format( plan_status=plan_status, current_task=current_task, example=example, available_commands=tool_info, + instruction=self.instruction.strip(), ) context = self.llm.format_msg(self.rc.memory.get(self.memory_k) + [Message(content=prompt, role="user")]) - print(*context, sep="\n" + "*" * 5 + "\n") - - self.command_rsp = await self.llm.aask(context) - + self.command_rsp = await self.llm.aask(context, system_msgs=self.system_msg) self.rc.memory.add(Message(content=self.command_rsp, role="assistant")) return True @@ -121,7 +124,12 @@ class RoleZero(Role): return error_msg outputs = await self._run_commands(commands) self.rc.memory.add(Message(content=outputs, role="user")) - return Message(content="Task completed", role="assistant", sent_from=self._setting, cause_by=RunCommand) + return Message( + content=f"Complete run with outputs: {outputs}", + role="assistant", + sent_from=self._setting, + cause_by=RunCommand, + ) async def _react(self) -> Message: actions_taken = 0 @@ -146,8 +154,8 @@ class RoleZero(Role): if await self._run_special_command(cmd): continue # run command as specified by tool_execute_map - if cmd["command_name"] in self.tool_execute_map: - tool_obj = self.tool_execute_map[cmd["command_name"]] + if cmd["command_name"] in self.tool_execution_map: + tool_obj = self.tool_execution_map[cmd["command_name"]] output = f"Command {cmd['command_name']} executed" try: if inspect.iscoroutinefunction(tool_obj): @@ -171,7 +179,7 @@ class RoleZero(Role): async def _run_special_command(self, cmd) -> bool: """command requiring special check or parsing""" - is_special_cmd = cmd["command_name"] in ["Plan.finish_current_task", "Common.end"] + is_special_cmd = cmd["command_name"] in self.special_tool_commands if cmd["command_name"] == "Plan.finish_current_task" and not self.planner.plan.is_plan_finished(): # task_result = TaskResult(code=str(commands), result=outputs, is_success=is_success) @@ -182,3 +190,24 @@ class RoleZero(Role): self._set_state(-1) return is_special_cmd + + def _retrieve_experience(self) -> str: + """Default implementation of experience retrieval. Can be overwritten in subclasses.""" + context = [str(msg) for msg in self.rc.memory.get(self.memory_k)] + context = "\n\n".join(context) + example = self.experience_retriever.retrieve(context=context) + return example + + async def ask_human(self, question: str) -> str: + """Use this when you fail the current task or if you are unsure of the situation encountered. Your response should contain a brief summary of your situation, ended with a clear and concise question.""" + # NOTE: Can be overwritten in remote setting + if not isinstance(self.rc.env, MGXEnv): + return "Not in MGXEnv, command will not be executed." + return await self.rc.env.get_human_input(question, sent_from=self) + + async def reply_to_human(self, content: str) -> str: + """Reply to human user with the content provided. Use this when you have a clear answer or solution to the user's question.""" + # NOTE: Can be overwritten in remote setting + if not isinstance(self.rc.env, MGXEnv): + return "Not in MGXEnv, command will not be executed." + return await self.rc.env.reply_to_human(content, sent_from=self) diff --git a/metagpt/roles/di/team_leader.py b/metagpt/roles/di/team_leader.py index a1ef11fa6..3a4c71254 100644 --- a/metagpt/roles/di/team_leader.py +++ b/metagpt/roles/di/team_leader.py @@ -1,99 +1,70 @@ from __future__ import annotations -import json - from pydantic import model_validator -from metagpt.actions.di.run_command import RunCommand from metagpt.prompts.di.team_leader import ( - CMD_PROMPT, FINISH_CURRENT_TASK_CMD, SYSTEM_PROMPT, + TL_INSTRUCTION, ) -from metagpt.roles import Role -from metagpt.schema import Message, TaskResult -from metagpt.strategy.experience_retriever import SimpleExpRetriever -from metagpt.strategy.planner import Planner -from metagpt.strategy.thinking_command import ( - Command, - prepare_command_prompt, - run_commands, -) -from metagpt.utils.common import CodeParser +from metagpt.roles.di.role_zero import RoleZero +from metagpt.schema import Message +from metagpt.strategy.experience_retriever import ExpRetriever, SimpleExpRetriever +from metagpt.tools.tool_registry import register_tool -class TeamLeader(Role): +@register_tool(include_functions=["publish_team_message"]) +class TeamLeader(RoleZero): name: str = "Tim" profile: str = "Team Leader" - task_result: TaskResult = None - available_commands: list[Command] = [ - Command.APPEND_TASK, - Command.RESET_TASK, - Command.REPLACE_TASK, - Command.FINISH_CURRENT_TASK, - Command.PUBLISH_MESSAGE, - Command.ASK_HUMAN, - Command.REPLY_TO_HUMAN, - Command.PASS, - ] - commands: list[dict] = [] # issued commands to be executed + system_msg: list[str] = [SYSTEM_PROMPT] + + max_react_loop: int = 1 # TeamLeader only reacts once each time + + tools: list[str] = ["Plan", "RoleZero", "TeamLeader"] + experience_retriever: ExpRetriever = SimpleExpRetriever() @model_validator(mode="after") - def set_plan(self) -> "TeamLeader": - self.planner = Planner(goal=self.goal, working_memory=self.rc.working_memory, auto_run=True) + def set_tool_execution(self) -> "RoleZero": + self.tool_execution_map = { + "Plan.append_task": self.planner.plan.append_task, + "Plan.reset_task": self.planner.plan.reset_task, + "Plan.replace_task": self.planner.plan.replace_task, + "RoleZero.ask_human": self.ask_human, + "RoleZero.reply_to_human": self.reply_to_human, + "TeamLeader.publish_team_message": self.publish_team_message, + } return self - async def _think(self) -> bool: - """Useful in 'react' mode. Use LLM to decide whether and what to do next.""" - - if not self.planner.plan.goal: - user_requirement = self.get_memories()[-1].content - self.planner.plan.goal = user_requirement - - plan_status = self.planner.plan.model_dump(include=["goal", "tasks"]) - for task in plan_status["tasks"]: - task.pop("code") - task.pop("result") + def set_instruction(self): team_info = "" for role in self.rc.env.roles.values(): - if role.profile == "TeamLeader": - continue + # if role.profile == "Team Leader": + # continue team_info += f"{role.name}: {role.profile}, {role.goal}\n" - example = SimpleExpRetriever().retrieve() + self.instruction = TL_INSTRUCTION.format(team_info=team_info) - prompt = CMD_PROMPT.format( - plan_status=plan_status, - team_info=team_info, - example=example, - available_commands=prepare_command_prompt(self.available_commands), - ) - context = self.llm.format_msg(self.get_memories(k=10) + [Message(content=prompt, role="user")]) + async def _think(self) -> bool: + self.set_instruction() + return await super()._think() - rsp = await self.llm.aask(context, system_msgs=[SYSTEM_PROMPT]) - self.commands = json.loads(CodeParser.parse_code(text=rsp)) - self.rc.memory.add(Message(content=rsp, role="assistant")) - - return True - - async def _act(self) -> Message: - """Useful in 'react' mode. Return a Message conforming to Role._act interface.""" - await run_commands(self, self.commands, self.rc.memory) - self.task_result = TaskResult(result="Success", is_success=True) - msg = Message(content="Commands executed", send_to="no one") # a dummy message to conform to the interface - self.rc.memory.add(msg) - return msg - - def publish_message(self, msg): - """If the role belongs to env, then the role's messages will be broadcast to env""" + def publish_message(self, msg, send_to="no one"): + """Overwrite Role.publish_message, send to no one if called within Role.run, send to the specified role if called dynamically.""" if not msg: return if not self.rc.env: # If env does not exist, do not publish the message return - msg.sent_from = self.profile - msg.cause_by = RunCommand + msg.send_to = send_to self.rc.env.publish_message(msg, publicer=self.profile) + def publish_team_message(self, content: str, send_to: str): + """ + Publish a message to a team member, use member name to fill send_to args. You may copy the full original content or add additional information from upstream. This will make team members start their work. + DONT omit any necessary info such as path, link, environment, programming language, framework, requirement, constraint from original content to team members because you are their sole info source. + """ + self.publish_message(Message(content=content), send_to=send_to) + def finish_current_task(self): self.planner.plan.finish_current_task() self.rc.memory.add(Message(content=FINISH_CURRENT_TASK_CMD, role="assistant")) diff --git a/metagpt/strategy/experience_retriever.py b/metagpt/strategy/experience_retriever.py index 4b209717c..c122affb5 100644 --- a/metagpt/strategy/experience_retriever.py +++ b/metagpt/strategy/experience_retriever.py @@ -10,6 +10,13 @@ class ExpRetriever(BaseModel): raise NotImplementedError +class DummyExpRetriever(ExpRetriever): + """A dummy experience retriever that returns empty string.""" + + def retrieve(self, context: str = "") -> str: + return "" + + class SimpleExpRetriever(ExpRetriever): """A simple experience retriever that returns manually crafted examples.""" @@ -20,7 +27,7 @@ class SimpleExpRetriever(ExpRetriever): ```json [ { - "command_name": "append_task", + "command_name": "Plan.append_task", "args": { "task_id": "1", "dependent_task_ids": [], @@ -29,7 +36,7 @@ class SimpleExpRetriever(ExpRetriever): } }, { - "command_name": "append_task", + "command_name": "Plan.append_task", "args": { "task_id": "2", "dependent_task_ids": ["1"], @@ -38,7 +45,7 @@ class SimpleExpRetriever(ExpRetriever): } }, { - "command_name": "append_task", + "command_name": "Plan.append_task", "args": { "task_id": "3", "dependent_task_ids": ["2"], @@ -47,7 +54,7 @@ class SimpleExpRetriever(ExpRetriever): } }, { - "command_name": "append_task", + "command_name": "Plan.append_task", "args": { "task_id": "4", "dependent_task_ids": ["3"], @@ -56,7 +63,7 @@ class SimpleExpRetriever(ExpRetriever): } }, { - "command_name": "append_task", + "command_name": "Plan.append_task", "args": { "task_id": "5", "dependent_task_ids": ["4"], @@ -65,14 +72,14 @@ class SimpleExpRetriever(ExpRetriever): } }, { - "command_name": "publish_message", + "command_name": "TeamLeader.publish_message", "args": { "content": "Create a cli snake game using Python", "send_to": "Alice" } }, { - "command_name": "reply_to_human", + "command_name": "RoleZero.reply_to_human", "args": { "content": "I have assigned the tasks to the team members. Alice will create the PRD, Bob will design the software architecture, Eve will break down the architecture into tasks, Alex will implement the core game logic, and Edward will write comprehensive tests. The team will work on the project accordingly", } @@ -86,7 +93,7 @@ class SimpleExpRetriever(ExpRetriever): ```json [ { - "command_name": "append_task", + "command_name": "Plan.append_task", "args": { "task_id": "1", "dependent_task_ids": [], @@ -95,14 +102,14 @@ class SimpleExpRetriever(ExpRetriever): } }, { - "command_name": "publish_message", + "command_name": "TeamLeader.publish_message", "args": { "content": "Run data analysis on sklearn Wine recognition dataset, include a plot, and train a model to predict wine class (20% as validation), and show validation accuracy.", "send_to": "David" } }, { - "command_name": "reply_to_human", + "command_name": "RoleZero.reply_to_human", "args": { "content": "I have assigned the task to David. He will break down the task further by himself and starts solving it.", } @@ -116,22 +123,22 @@ class SimpleExpRetriever(ExpRetriever): ..., {'role': 'assistant', 'content': 'from Alice(Product Manager) to {'Bob'}: {'docs': {'20240424153821.json': {'root_path': 'docs/prd', 'filename': '20240424153821.json', 'content': '{"Language":"en_us","Programming Language":"Python","Original Requirements":"create a cli snake game","Project Name":"snake_game","Product Goals":["Develop an intuitive and addictive snake game",...], ...}}}}}, ] - Explanation: You received a message from Alice, the Product Manager, that she has completed the PRD, use finish_current_task to mark her task as finished and moves the plan to the next task. Based on plan status, next task is for Bob (Architect), publish a message asking him to start. The message content should contain important path info. + Explanation: You received a message from Alice, the Product Manager, that she has completed the PRD, use Plan.finish_current_task to mark her task as finished and moves the plan to the next task. Based on plan status, next task is for Bob (Architect), publish a message asking him to start. The message content should contain important path info. ```json [ { - "command_name": "finish_current_task", + "command_name": "Plan.finish_current_task", "args": {} }, { - "command_name": "publish_message", + "command_name": "TeamLeader.publish_message", "args": { "content": "Please design the software architecture for the snake game based on the PRD created by Alice. The PRD is at 'docs/prd/20240424153821.json'. Include the choice of programming language, libraries, and data flow, etc.", "send_to": "Bob" } }, { - "command_name": "reply_to_human", + "command_name": "RoleZero.reply_to_human", "args": { "content": "Alice has completed the PRD. I have marked her task as finished and sent the PRD to Bob. Bob will work on the software architecture.", } @@ -145,7 +152,7 @@ class SimpleExpRetriever(ExpRetriever): ```json [ { - "command_name": "reply_to_human", + "command_name": "RoleZero.reply_to_human", "args": { "content": "The team is currently working on ... We have completed ...", } @@ -180,7 +187,7 @@ Explanation: Launching a service requires Terminal tool with daemon mode, write ```json [ { - "command_name": "append_task", + "command_name": "Plan.append_task", "args": { "task_id": "1", "dependent_task_ids": [], @@ -189,7 +196,7 @@ Explanation: Launching a service requires Terminal tool with daemon mode, write } }, { - "command_name": "append_task", + "command_name": "Plan.append_task", "args": { "task_id": "2", "dependent_task_ids": ["1"], @@ -198,7 +205,7 @@ Explanation: Launching a service requires Terminal tool with daemon mode, write } }, { - "command_name": "append_task", + "command_name": "Plan.append_task", "args": { "task_id": "3", "dependent_task_ids": ["2"], @@ -216,7 +223,7 @@ Explanation: The requirement is to fix an issue in an existing repository. The p ```json [ { - "command_name": "append_task", + "command_name": "Plan.append_task", "args": { "task_id": "1", "dependent_task_ids": [], @@ -225,7 +232,7 @@ Explanation: The requirement is to fix an issue in an existing repository. The p } }, { - "command_name": "append_task", + "command_name": "Plan.append_task", "args": { "task_id": "2", "dependent_task_ids": ["1"], @@ -234,7 +241,7 @@ Explanation: The requirement is to fix an issue in an existing repository. The p } }, { - "command_name": "append_task", + "command_name": "Plan.append_task", "args": { "task_id": "3", "dependent_task_ids": ["2"], @@ -243,7 +250,7 @@ Explanation: The requirement is to fix an issue in an existing repository. The p } }, { - "command_name": "append_task", + "command_name": "Plan.append_task", "args": { "task_id": "4", "dependent_task_ids": ["3"], @@ -252,7 +259,7 @@ Explanation: The requirement is to fix an issue in an existing repository. The p } }, { - "command_name": "append_task", + "command_name": "Plan.append_task", "args": { "task_id": "5", "dependent_task_ids": ["4"],