diff --git a/metagpt/const.py b/metagpt/const.py index 0dfe9e5ec..c53e8494a 100644 --- a/metagpt/const.py +++ b/metagpt/const.py @@ -83,6 +83,7 @@ MESSAGE_ROUTE_TO_ALL = "" MESSAGE_ROUTE_TO_NONE = "" MESSAGE_ROUTE_TO_SELF = "" # Add this tag to replace `ActionOutput` + REQUIREMENT_FILENAME = "requirement.txt" BUGFIX_FILENAME = "bugfix.txt" PACKAGE_REQUIREMENTS_FILENAME = "requirements.txt" @@ -153,3 +154,6 @@ IMAGES = "images" # SWE agent SWE_SETUP_PATH = get_metagpt_package_root() / "metagpt/tools/swe_agent_commands/setup_default.sh" + +# experience pool +EXPERIENCE_MASK = "" diff --git a/metagpt/exp_pool/context_builders/role_zero.py b/metagpt/exp_pool/context_builders/role_zero.py index 924bd56aa..cbda72fc5 100644 --- a/metagpt/exp_pool/context_builders/role_zero.py +++ b/metagpt/exp_pool/context_builders/role_zero.py @@ -1,9 +1,9 @@ """RoleZero context builder.""" import copy -import re from typing import Any +from metagpt.const import EXPERIENCE_MASK from metagpt.exp_pool.context_builders.base import BaseContextBuilder @@ -31,26 +31,9 @@ class RoleZeroContextBuilder(BaseContextBuilder): return req_copy def replace_example_content(self, text: str, new_example_content: str) -> str: - return self.replace_content_between_markers(text, "# Example", "# Instruction", new_example_content) + return self.fill_experience(text, new_example_content) @staticmethod - def replace_content_between_markers(text: str, start_marker: str, end_marker: str, new_content: str) -> str: - """Replace the content between `start_marker` and `end_marker` in the text with `new_content`. - - Args: - text (str): The original text. - new_content (str): The new content to replace the old content. - start_marker (str): The marker indicating the start of the content to be replaced, such as '# Example'. - end_marker (str): The marker indicating the end of the content to be replaced, such as '# Instruction'. - - Returns: - str: The text with the content replaced. - """ - - pattern = re.compile(f"({start_marker}\n)(.*?)(\n{end_marker})", re.DOTALL) - - def replacement(match): - return f"{match.group(1)}{new_content}\n{match.group(3)}" - - replaced_text = pattern.sub(replacement, text) + def fill_experience(text: str, new_example_content: str) -> str: + replaced_text = text.replace(EXPERIENCE_MASK, new_example_content) return replaced_text diff --git a/metagpt/prompts/di/role_zero.py b/metagpt/prompts/di/role_zero.py index d12363f4f..3c47ebf5f 100644 --- a/metagpt/prompts/di/role_zero.py +++ b/metagpt/prompts/di/role_zero.py @@ -1,3 +1,5 @@ +from metagpt.const import EXPERIENCE_MASK + 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. @@ -10,7 +12,6 @@ Note: 4. Don't forget to append task first when all existing tasks are finished and new tasks are required. 5. Avoid repeating tasks you have already completed. And end loop when all requirements are met. """ -# To ensure compatibility with hard-coded experience, do not add any other content between "# Example" and "# Instruction". ########################## ignore guidance @@ -47,7 +48,14 @@ Special Command: Use {{"command_name": "end"}} to do nothing or indicate complet {instruction} """ -CMD_PROMPT = """ +CMD_EXPERIENCE_MASK = f""" +# Past Experience +{EXPERIENCE_MASK} +""" + +CMD_PROMPT = ( + CMD_EXPERIENCE_MASK + + """ {current_state} # Current Plan @@ -79,6 +87,7 @@ Output should adhere to the following format. ``` Notice: your output JSON data section must start with **```json [** """ +) THOUGHT_GUIDANCE = """ First, describe the actions you have taken recently. diff --git a/metagpt/roles/di/role_zero.py b/metagpt/roles/di/role_zero.py index 8b1ab2267..c6cbfdfa8 100644 --- a/metagpt/roles/di/role_zero.py +++ b/metagpt/roles/di/role_zero.py @@ -436,11 +436,6 @@ class RoleZero(Role): def _get_plan_status(self) -> Tuple[str, str]: plan_status = self.planner.plan.model_dump(include=["goal", "tasks"]) - for task in plan_status["tasks"]: - task.pop("code") - task.pop("result") - task.pop("is_success") - # print(plan_status) current_task = ( self.planner.plan.current_task.model_dump(exclude=["code", "result", "is_success"]) if self.planner.plan.current_task diff --git a/tests/metagpt/exp_pool/test_context_builders/test_rolezero_context_builder.py b/tests/metagpt/exp_pool/test_context_builders/test_rolezero_context_builder.py index b7182602d..82a3622a5 100644 --- a/tests/metagpt/exp_pool/test_context_builders/test_rolezero_context_builder.py +++ b/tests/metagpt/exp_pool/test_context_builders/test_rolezero_context_builder.py @@ -1,5 +1,6 @@ import pytest +from metagpt.const import EXPERIENCE_MASK from metagpt.exp_pool.context_builders.base import BaseContextBuilder from metagpt.exp_pool.context_builders.role_zero import RoleZeroContextBuilder @@ -30,22 +31,20 @@ class TestRoleZeroContextBuilder: assert result == [{"content": "Updated content"}] def test_replace_example_content(self, context_builder, mocker): - mocker.patch.object(RoleZeroContextBuilder, "replace_content_between_markers", return_value="Replaced content") + mocker.patch.object(RoleZeroContextBuilder, "fill_experience", return_value="Replaced content") result = context_builder.replace_example_content("Original text", "New example content") assert result == "Replaced content" - context_builder.replace_content_between_markers.assert_called_once_with( - "Original text", "# Example", "# Instruction", "New example content" - ) + context_builder.fill_experience.assert_called_once_with("Original text", "New example content") - def test_replace_content_between_markers(self): - text = "Start\n# Example\nOld content\n# Instruction\nEnd" + def test_fill_experience(self): + text = f"Start\n# Past Experience\n{EXPERIENCE_MASK}\n\n# Instruction\nEnd" new_content = "New content" - result = RoleZeroContextBuilder.replace_content_between_markers(text, "# Example", "# Instruction", new_content) - expected = "Start\n# Example\nNew content\n\n# Instruction\nEnd" + result = RoleZeroContextBuilder.fill_experience(text, new_content) + expected = "Start\n# Past Experience\nNew content\n\n# Instruction\nEnd" assert result == expected - def test_replace_content_between_markers_no_match(self): + def test_fill_experience_no_match(self): text = "Start\nNo markers\nEnd" new_content = "New content" - result = RoleZeroContextBuilder.replace_content_between_markers(text, "# Example", "# Instruction", new_content) + result = RoleZeroContextBuilder.fill_experience(text, new_content) assert result == text