diff --git a/metagpt/actions/design_api.py b/metagpt/actions/design_api.py index 933c59b74..d24cd2ae3 100644 --- a/metagpt/actions/design_api.py +++ b/metagpt/actions/design_api.py @@ -19,7 +19,7 @@ from metagpt.actions.design_api_an import ( DESIGN_API_NODE, PROGRAM_CALL_FLOW, REFINED_DATA_STRUCTURES_AND_INTERFACES, - REFINED_DESIGN_NODES, + REFINED_DESIGN_NODE, REFINED_PROGRAM_CALL_FLOW, ) from metagpt.config import CONFIG @@ -89,7 +89,7 @@ class WriteDesign(Action): async def _merge(self, prd_doc, system_design_doc, schema=CONFIG.prompt_schema): context = NEW_REQ_TEMPLATE.format(old_design=system_design_doc.content, context=prd_doc.content) - node = await REFINED_DESIGN_NODES.fill(context=context, llm=self.llm, schema=schema) + node = await REFINED_DESIGN_NODE.fill(context=context, llm=self.llm, schema=schema) system_design_doc.content = node.instruct_content.model_dump_json() return system_design_doc diff --git a/metagpt/actions/design_api_an.py b/metagpt/actions/design_api_an.py index b872159e1..35b50ef8f 100644 --- a/metagpt/actions/design_api_an.py +++ b/metagpt/actions/design_api_an.py @@ -99,7 +99,7 @@ NODES = [ ANYTHING_UNCLEAR, ] -REFINE_NODES = [ +REFINED_NODES = [ REFINED_IMPLEMENTATION_APPROACH, REFINED_FILE_LIST, REFINED_DATA_STRUCTURES_AND_INTERFACES, @@ -108,13 +108,13 @@ REFINE_NODES = [ ] DESIGN_API_NODE = ActionNode.from_children("DesignAPI", NODES) -REFINED_DESIGN_NODES = ActionNode.from_children("RefinedDesignAPI", REFINE_NODES) +REFINED_DESIGN_NODE = ActionNode.from_children("RefinedDesignAPI", REFINED_NODES) def main(): prompt = DESIGN_API_NODE.compile(context="") logger.info(prompt) - prompt = REFINED_DESIGN_NODES.compile(context="") + prompt = REFINED_DESIGN_NODE.compile(context="") logger.info(prompt) diff --git a/metagpt/actions/project_management.py b/metagpt/actions/project_management.py index d6b351d18..448a8afcd 100644 --- a/metagpt/actions/project_management.py +++ b/metagpt/actions/project_management.py @@ -15,7 +15,7 @@ from typing import Optional from metagpt.actions import ActionOutput from metagpt.actions.action import Action -from metagpt.actions.project_management_an import PM_NODE, REFINED_PM_NODES +from metagpt.actions.project_management_an import PM_NODE, REFINED_PM_NODE from metagpt.config import CONFIG from metagpt.const import ( PACKAGE_REQUIREMENTS_FILENAME, @@ -93,7 +93,7 @@ class WriteTasks(Action): async def _merge(self, system_design_doc, task_doc, schema=CONFIG.prompt_schema) -> Document: context = NEW_REQ_TEMPLATE.format(context=system_design_doc.content, old_tasks=task_doc.content) - node = await REFINED_PM_NODES.fill(context, self.llm, schema) + node = await REFINED_PM_NODE.fill(context, self.llm, schema) task_doc.content = node.instruct_content.model_dump_json() return task_doc diff --git a/metagpt/actions/project_management_an.py b/metagpt/actions/project_management_an.py index e3d6537ab..379a23384 100644 --- a/metagpt/actions/project_management_an.py +++ b/metagpt/actions/project_management_an.py @@ -107,7 +107,7 @@ NODES = [ ANYTHING_UNCLEAR_PM, ] -REFINE_NODES = [ +REFINED_NODES = [ REQUIRED_PYTHON_PACKAGES, REQUIRED_OTHER_LANGUAGE_PACKAGES, REFINED_LOGIC_ANALYSIS, @@ -118,13 +118,13 @@ REFINE_NODES = [ ] PM_NODE = ActionNode.from_children("PM_NODE", NODES) -REFINED_PM_NODES = ActionNode.from_children("REFINED_PM_NODES", REFINE_NODES) +REFINED_PM_NODE = ActionNode.from_children("REFINED_PM_NODE", REFINED_NODES) def main(): prompt = PM_NODE.compile(context="") logger.info(prompt) - prompt = REFINED_PM_NODES.compile(context="") + prompt = REFINED_PM_NODE.compile(context="") logger.info(prompt) diff --git a/metagpt/actions/write_code.py b/metagpt/actions/write_code.py index 093633a8b..662524518 100644 --- a/metagpt/actions/write_code.py +++ b/metagpt/actions/write_code.py @@ -23,14 +23,14 @@ from tenacity import retry, stop_after_attempt, wait_random_exponential from metagpt.actions.action import Action from metagpt.actions.project_management_an import REFINED_TASK_LIST, TASK_LIST -from metagpt.actions.write_code_plan_an import REFINED_CODE_TEMPLATE +from metagpt.actions.write_code_plan_and_change_an import REFINED_TEMPLATE from metagpt.config import CONFIG from metagpt.const import ( BUGFIX_FILENAME, + CODE_PLAN_AND_CHANGE_FILE_REPO, + CODE_PLAN_AND_CHANGE_FILENAME, CODE_SUMMARIES_FILE_REPO, DOCS_FILE_REPO, - PLAN_FILE_REPO, - PLAN_FILENAME, REQUIREMENT_FILENAME, TASK_FILE_REPO, TEST_OUTPUTS_FILE_REPO, @@ -107,8 +107,10 @@ class WriteCode(Action): test_doc = await FileRepository.get_file( filename="test_" + coding_context.filename + ".json", relative_path=TEST_OUTPUTS_FILE_REPO ) - plan_doc = await FileRepository.get_file(filename=PLAN_FILENAME, relative_path=PLAN_FILE_REPO) - plan = plan_doc.content if plan_doc else "" + code_plan_and_change_doc = await FileRepository.get_file( + filename=CODE_PLAN_AND_CHANGE_FILENAME, relative_path=CODE_PLAN_AND_CHANGE_FILE_REPO + ) + code_plan_and_change = code_plan_and_change_doc.content if code_plan_and_change_doc else "" requirement_doc = await FileRepository.get_file(filename=REQUIREMENT_FILENAME, relative_path=DOCS_FILE_REPO) summary_doc = None if coding_context.design_doc and coding_context.design_doc.filename: @@ -122,15 +124,15 @@ class WriteCode(Action): if bug_feedback: code_context = coding_context.code_doc.content - elif plan: - code_context = await self.get_codes(coding_context.task_doc, exclude=self.context.filename, mode="plan") + elif code_plan_and_change: + code_context = await self.get_codes(coding_context.task_doc, exclude=self.context.filename, mode="guide") else: code_context = await self.get_codes(coding_context.task_doc, exclude=self.context.filename) - if plan: - prompt = REFINED_CODE_TEMPLATE.format( + if code_plan_and_change: + prompt = REFINED_TEMPLATE.format( user_requirement=requirement_doc.content if requirement_doc else "", - plan=plan, + code_plan_and_change=code_plan_and_change, design=coding_context.design_doc.content if coding_context.design_doc else "", tasks=coding_context.task_doc.content if coding_context.task_doc else "", code=code_context, @@ -159,14 +161,14 @@ class WriteCode(Action): return coding_context @staticmethod - async def get_codes(task_doc: Document, exclude: str, mode: Literal["normal", "plan"] = "normal") -> str: + async def get_codes(task_doc: Document, exclude: str, mode: Literal["normal", "guide"] = "normal") -> str: """ Get code snippets based on different modes. Attributes: task_doc (Document): Document object of the task file. exclude (str): Specifies the filename to be excluded from the code snippets. - mode (str): Specifies the mode, either "normal" or "plan" (default is "normal"). + mode (str): Specifies the mode, either "normal" or "guide" (default is "normal"). Returns: str: Code snippets. @@ -175,7 +177,7 @@ class WriteCode(Action): If mode is set to "normal", it returns code snippets for the regular coding phase, i.e., all the code generated before writing the current file. - If mode is set to "plan", it returns code snippets for incremental development, + If mode is set to "guide", it returns code snippets for generating the code plan and change, building upon the existing code in the "normal" mode and adding code for the current file's older versions. """ if not task_doc: @@ -187,7 +189,7 @@ class WriteCode(Action): codes = [] src_file_repo = CONFIG.git_repo.new_file_repository(relative_path=CONFIG.src_workspace) - if mode == "plan": + if mode == "guide": src_files = src_file_repo.all_files old_file_repo = CONFIG.git_repo.new_file_repository(relative_path=CONFIG.old_workspace) old_files = old_file_repo.all_files diff --git a/metagpt/actions/write_code_plan_an.py b/metagpt/actions/write_code_plan_and_change_an.py similarity index 88% rename from metagpt/actions/write_code_plan_an.py rename to metagpt/actions/write_code_plan_and_change_an.py index f3f4177e4..1722855d2 100644 --- a/metagpt/actions/write_code_plan_an.py +++ b/metagpt/actions/write_code_plan_and_change_an.py @@ -3,14 +3,14 @@ """ @Time : 2023/12/26 @Author : mannaandpoem -@File : write_code_plan_an.py +@File : write_code_plan_and_change_an.py """ from metagpt.actions.action import Action from metagpt.actions.action_node import ActionNode -Plan = ActionNode( - key="Plan", +CODE_PLAN_AND_CHANGE = ActionNode( + key="Code Plan And Change", expected_type=str, instruction="Developing comprehensive and step-by-step incremental development plan, and write Incremental " "Change by making a code draft that how to implement incremental development including detailed steps based on the " @@ -104,7 +104,7 @@ def add_numbers(): ```""", ) -CODE_PLAN_CONTEXT = """ +CODE_PLAN_AND_CHANGE_CONTEXT = """ ## User New Requirements {user_requirement} @@ -121,7 +121,7 @@ CODE_PLAN_CONTEXT = """ {code} """ -REFINED_CODE_TEMPLATE = """ +REFINED_TEMPLATE = """ NOTICE Role: You are a professional engineer; The main goal is to complete incremental development by combining legacy code and plan and Incremental Change, ensuring the integration of new features. @@ -129,8 +129,8 @@ Role: You are a professional engineer; The main goal is to complete incremental ## User New Requirements {user_requirement} -## Plan -{plan} +## Code Plan And Change +{code_plan_and_change} ## Design {design} @@ -168,18 +168,18 @@ Role: You are a professional engineer; The main goal is to complete incremental 2. COMPLETE CODE: Your code will be part of the entire project, so please implement complete, reliable, reusable code snippets. 3. Set default value: If there is any setting, ALWAYS SET A DEFAULT VALUE, ALWAYS USE STRONG TYPE AND EXPLICIT VARIABLE. AVOID circular import. 4. Follow design: YOU MUST FOLLOW "Data structures and interfaces". DONT CHANGE ANY DESIGN. Do not use public member functions that do not exist in your design. -5. Follow plan and Incremental Change: If there is any Incremental Change or Legacy Code files contain "{filename} to be rewritten", you must merge it into the code file according to the plan. +5. Follow Code Plan And Change: If there is any Incremental Change or Legacy Code files contain "{filename} to be rewritten", you must merge it into the code file according to the plan. 6. CAREFULLY CHECK THAT YOU DONT MISS ANY NECESSARY CLASS/FUNCTION IN THIS FILE. 7. Before using a external variable/module, make sure you import it first. 8. Write out EVERY CODE DETAIL, DON'T LEAVE TODO. 9. Attention: Retain content that is not related to incremental development but important for consistency and clarity.". """ -WRITE_CODE_PLAN_NODE = ActionNode.from_children("WriteCodePlan", [Plan]) +WRITE_CODE_PLAN_AND_CHANGE_NODE = ActionNode.from_children("WriteCodePlanAndChange", [CODE_PLAN_AND_CHANGE]) -class WriteCodePlan(Action): +class WriteCodePlanAndChange(Action): async def run(self, context): self.llm.system_prompt = "You are a professional software engineer, your primary responsibility is to " - "meticulously craft comprehensive incremental development plan and deliver detailed Incremental Change" - return await WRITE_CODE_PLAN_NODE.fill(context=context, llm=self.llm, schema="json") + "meticulously craft comprehensive incremental development plan and deliver detailed incremental change" + return await WRITE_CODE_PLAN_AND_CHANGE_NODE.fill(context=context, llm=self.llm, schema="json") diff --git a/metagpt/actions/write_code_review.py b/metagpt/actions/write_code_review.py index 2b9c7bd10..6dbcb03fa 100644 --- a/metagpt/actions/write_code_review.py +++ b/metagpt/actions/write_code_review.py @@ -15,9 +15,9 @@ from metagpt.actions import WriteCode from metagpt.actions.action import Action from metagpt.config import CONFIG from metagpt.const import ( + CODE_PLAN_AND_CHANGE_FILE_REPO, + CODE_PLAN_AND_CHANGE_FILENAME, DOCS_FILE_REPO, - PLAN_FILE_REPO, - PLAN_FILENAME, REQUIREMENT_FILENAME, ) from metagpt.logs import logger @@ -145,16 +145,18 @@ class WriteCodeReview(Action): async def run(self, *args, **kwargs) -> CodingContext: iterative_code = self.context.code_doc.content k = CONFIG.code_review_k_times or 1 - plan_doc = await FileRepository.get_file(filename=PLAN_FILENAME, relative_path=PLAN_FILE_REPO) - plan = plan_doc.content if plan_doc else "" - mode = "plan" if plan else "normal" + code_plan_and_change_doc = await FileRepository.get_file( + filename=CODE_PLAN_AND_CHANGE_FILENAME, relative_path=CODE_PLAN_AND_CHANGE_FILE_REPO + ) + code_plan_and_change = code_plan_and_change_doc.content if code_plan_and_change_doc else "" + mode = "guide" if code_plan_and_change else "normal" for i in range(k): format_example = FORMAT_EXAMPLE.format(filename=self.context.code_doc.filename) task_content = self.context.task_doc.content if self.context.task_doc else "" code_context = await WriteCode.get_codes(self.context.task_doc, exclude=self.context.filename, mode=mode) - if not plan: + if not code_plan_and_change: context = "\n".join( [ "## System Design\n" + str(self.context.design_doc) + "\n", @@ -171,7 +173,7 @@ class WriteCodeReview(Action): context = "\n".join( [ "## User New Requirements\n" + user_requirement + "\n", - "## Plan\n" + plan + "\n", + "## Code Plan And Change\n" + code_plan_and_change + "\n", "## System Design\n" + str(self.context.design_doc) + "\n", "## Tasks\n" + task_content + "\n", "## Code Files\n" + code_context + "\n", diff --git a/metagpt/actions/write_prd.py b/metagpt/actions/write_prd.py index e12c1e1ec..c92749da0 100644 --- a/metagpt/actions/write_prd.py +++ b/metagpt/actions/write_prd.py @@ -23,8 +23,8 @@ from metagpt.actions.fix_bug import FixBug from metagpt.actions.write_prd_an import ( COMPETITIVE_QUADRANT_CHART, PROJECT_NAME, - REFINE_PRD_NODE, - REFINE_PRD_TEMPLATE, + REFINED_PRD_NODE, + REFINED_TEMPLATE, WP_IS_RELATIVE_NODE, WP_ISSUE_TYPE_NODE, WRITE_PRD_NODE, @@ -135,12 +135,12 @@ class WritePRD(Action): async def _merge(self, new_requirement_doc, prd_doc, schema=CONFIG.prompt_schema) -> Document: if not CONFIG.project_name: CONFIG.project_name = Path(CONFIG.project_path).name - prompt = REFINE_PRD_TEMPLATE.format( + prompt = REFINED_TEMPLATE.format( requirements=new_requirement_doc.content, old_prd=prd_doc.content, project_name=CONFIG.project_name, ) - node = await REFINE_PRD_NODE.fill(context=prompt, llm=self.llm, schema=schema) + node = await REFINED_PRD_NODE.fill(context=prompt, llm=self.llm, schema=schema) prd_doc.content = node.instruct_content.model_dump_json() await self._rename_workspace(node) return prd_doc diff --git a/metagpt/actions/write_prd_an.py b/metagpt/actions/write_prd_an.py index 4830076e3..c65860822 100644 --- a/metagpt/actions/write_prd_an.py +++ b/metagpt/actions/write_prd_an.py @@ -186,7 +186,7 @@ REASON = ActionNode( key="reason", expected_type=str, instruction="Explain the reasoning process from question to answer", example="..." ) -REFINE_PRD_TEMPLATE = """ +REFINED_TEMPLATE = """ ### Project Name {project_name} @@ -216,7 +216,7 @@ NODES = [ ANYTHING_UNCLEAR, ] -REFINE_NODES = [ +REFINED_NODES = [ LANGUAGE, PROGRAMMING_LANGUAGE, REFINED_REQUIREMENTS, @@ -232,7 +232,7 @@ REFINE_NODES = [ ] WRITE_PRD_NODE = ActionNode.from_children("WritePRD", NODES) -REFINE_PRD_NODE = ActionNode.from_children("RefinePRD", REFINE_NODES) +REFINED_PRD_NODE = ActionNode.from_children("RefinedPRD", REFINED_NODES) WP_ISSUE_TYPE_NODE = ActionNode.from_children("WP_ISSUE_TYPE", [ISSUE_TYPE, REASON]) WP_IS_RELATIVE_NODE = ActionNode.from_children("WP_IS_RELATIVE", [IS_RELATIVE, REASON]) @@ -240,7 +240,7 @@ WP_IS_RELATIVE_NODE = ActionNode.from_children("WP_IS_RELATIVE", [IS_RELATIVE, R def main(): prompt = WRITE_PRD_NODE.compile(context="") logger.info(prompt) - prompt = REFINE_PRD_NODE.compile(context="") + prompt = REFINED_PRD_NODE.compile(context="") logger.info(prompt) diff --git a/metagpt/const.py b/metagpt/const.py index 8f0eeef23..fc3d54296 100644 --- a/metagpt/const.py +++ b/metagpt/const.py @@ -87,13 +87,13 @@ MESSAGE_ROUTE_TO_NONE = "" REQUIREMENT_FILENAME = "requirement.txt" BUGFIX_FILENAME = "bugfix.txt" PACKAGE_REQUIREMENTS_FILENAME = "requirements.txt" -PLAN_FILENAME = "plan.json" +CODE_PLAN_AND_CHANGE_FILENAME = "code_plan_and_change.json" DOCS_FILE_REPO = "docs" PRDS_FILE_REPO = "docs/prds" SYSTEM_DESIGN_FILE_REPO = "docs/system_design" TASK_FILE_REPO = "docs/tasks" -PLAN_FILE_REPO = "docs/plan" +CODE_PLAN_AND_CHANGE_FILE_REPO = "docs/code_plan_and_change" COMPETITIVE_ANALYSIS_FILE_REPO = "resources/competitive_analysis" DATA_API_DESIGN_FILE_REPO = "resources/data_api_design" SEQ_FLOW_FILE_REPO = "resources/seq_flow" diff --git a/metagpt/roles/engineer.py b/metagpt/roles/engineer.py index 2803c8668..861c5435e 100644 --- a/metagpt/roles/engineer.py +++ b/metagpt/roles/engineer.py @@ -29,14 +29,17 @@ from metagpt.actions import Action, WriteCode, WriteCodeReview, WriteTasks from metagpt.actions.fix_bug import FixBug from metagpt.actions.project_management_an import REFINED_TASK_LIST, TASK_LIST from metagpt.actions.summarize_code import SummarizeCode -from metagpt.actions.write_code_plan_an import CODE_PLAN_CONTEXT, WriteCodePlan +from metagpt.actions.write_code_plan_and_change_an import ( + CODE_PLAN_AND_CHANGE_CONTEXT, + WriteCodePlanAndChange, +) from metagpt.actions.write_prd_an import REFINED_REQUIREMENT_POOL, REQUIREMENT_POOL from metagpt.config import CONFIG from metagpt.const import ( + CODE_PLAN_AND_CHANGE_FILE_REPO, + CODE_PLAN_AND_CHANGE_FILENAME, CODE_SUMMARIES_FILE_REPO, CODE_SUMMARIES_PDF_FILE_REPO, - PLAN_FILE_REPO, - PLAN_FILENAME, PRDS_FILE_REPO, SYSTEM_DESIGN_FILE_REPO, TASK_FILE_REPO, @@ -103,7 +106,7 @@ class Engineer(Role): m = json.loads(task_msg.content) return m.get(TASK_LIST.key) or m.get(REFINED_TASK_LIST.key) - async def _act_sp_with_cr(self, review=False, mode: Literal["normal", "plan"] = "normal") -> Set[str]: + async def _act_sp_with_cr(self, review=False, mode: Literal["normal", "guide"] = "normal") -> Set[str]: changed_files = set() src_file_repo = CONFIG.git_repo.new_file_repository(CONFIG.src_workspace) for todo in self.code_todos: @@ -122,8 +125,8 @@ class Engineer(Role): coding_context = await action.run() dependencies = {coding_context.design_doc.root_relative_path, coding_context.task_doc.root_relative_path} - if mode == "plan": - dependencies.add(os.path.join(PLAN_FILE_REPO, PLAN_FILENAME)) + if mode == "guide": + dependencies.add(os.path.join(CODE_PLAN_AND_CHANGE_FILE_REPO, CODE_PLAN_AND_CHANGE_FILENAME)) await src_file_repo.save( coding_context.filename, dependencies=dependencies, @@ -156,7 +159,7 @@ class Engineer(Role): async def _act_write_code(self): if CONFIG.inc: - await self._write_code_plan() + await self._write_code_plan_and_change() changed_files = await self._act_sp_with_cr(review=self.use_code_review) return Message( content="\n".join(changed_files), @@ -334,9 +337,9 @@ class Engineer(Role): """AgentStore uses this attribute to display to the user what actions the current role should take.""" return self.next_todo_action - async def _write_code_plan(self): - """Write code plan that guides subsequent WriteCode and WriteCodeReview""" - logger.info("Writing code plan..") + async def _write_code_plan_and_change(self): + """Write code plan and change that guides subsequent WriteCode and WriteCodeReview""" + logger.info("Writing code plan and change..") user_requirement = str(self.rc.memory.get_by_role("Human")[0]) pool_contents = [] @@ -356,16 +359,18 @@ class Engineer(Role): old_codes = await self.get_old_codes() - context = CODE_PLAN_CONTEXT.format( + context = CODE_PLAN_AND_CHANGE_CONTEXT.format( user_requirement=user_requirement, product_requirement_pools=product_requirement_pools, tasks=tasks, design=design, code=old_codes, ) - node = await WriteCodePlan().run(context=context) - plan = node.instruct_content.model_dump_json() - CONFIG.git_repo.new_file_repository(PLAN_FILE_REPO).save(filename=PLAN_FILENAME, content=plan) + node = await WriteCodePlanAndChange().run(context=context) + code_plan_and_change = node.instruct_content.model_dump_json() + CONFIG.git_repo.new_file_repository(CODE_PLAN_AND_CHANGE_FILE_REPO).save( + filename=CODE_PLAN_AND_CHANGE_FILENAME, content=code_plan_and_change + ) @staticmethod async def get_old_codes() -> str: diff --git a/tests/data/incremental_dev_project/mock.py b/tests/data/incremental_dev_project/mock.py index bb3d008a1..5c5191cf2 100644 --- a/tests/data/incremental_dev_project/mock.py +++ b/tests/data/incremental_dev_project/mock.py @@ -372,7 +372,7 @@ REFINED_TASKS_JSON = { "Anything UNCLEAR": "", } -PLAN_SAMPLE = { +CODE_PLAN_AND_CHANGE_SAMPLE = { "Plan": '\n1. Plan for gui.py: Develop the GUI using Tkinter to replace the command-line interface. Start by setting up the main window and event handling. Then, add widgets for displaying the game status, results, and feedback. Implement interactive elements for difficulty selection and visualize the guess history. Finally, create animations for guess feedback and ensure responsiveness across different screen sizes.\n```python\nclass GUI:\n- pass\n+ def __init__(self):\n+ self.setup_window()\n+\n+ def setup_window(self):\n+ # Initialize the main window using Tkinter\n+ pass\n+\n+ def bind_events(self):\n+ # Bind button clicks and other events\n+ pass\n+\n+ def update_feedback(self, message: str):\n+ # Update the feedback label with the given message\n+ pass\n+\n+ def update_attempts(self, attempts: int):\n+ # Update the attempts label with the number of attempts\n+ pass\n+\n+ def update_history(self, history: list):\n+ # Update the history view with the list of past guesses\n+ pass\n+\n+ def show_difficulty_selector(self):\n+ # Show buttons or a dropdown for difficulty selection\n+ pass\n+\n+ def animate_guess_result(self, correct: bool):\n+ # Trigger an animation for correct or incorrect guesses\n+ pass\n```\n\n2. Plan for main.py: Modify the main.py to initialize the GUI and start the event-driven game loop. Ensure that the GUI is the primary interface for user interaction.\n```python\nclass Main:\n def main(self):\n- user_interface = UI()\n- user_interface.start()\n+ graphical_user_interface = GUI()\n+ graphical_user_interface.setup_window()\n+ graphical_user_interface.bind_events()\n+ # Start the Tkinter main loop\n+ pass\n\n if __name__ == "__main__":\n main_instance = Main()\n main_instance.main()\n```\n\n3. Plan for ui.py: Refactor ui.py to work with the new GUI class. Remove command-line interactions and delegate display and input tasks to the GUI.\n```python\nclass UI:\n- def display_message(self, message: str):\n- print(message)\n+\n+ def display_message(self, message: str):\n+ # This method will now pass the message to the GUI to display\n+ pass\n\n- def get_user_input(self, prompt: str) -> str:\n- return input(prompt)\n+\n+ def get_user_input(self, prompt: str) -> str:\n+ # This method will now trigger the GUI to get user input\n+ pass\n\n- def show_attempts(self, attempts: int):\n- print(f"Number of attempts: {attempts}")\n+\n+ def show_attempts(self, attempts: int):\n+ # This method will now update the GUI with the number of attempts\n+ pass\n\n- def show_history(self, history: list):\n- print("Guess history:")\n- for guess in history:\n- print(guess)\n+\n+ def show_history(self, history: list):\n+ # This method will now update the GUI with the guess history\n+ pass\n```\n\n4. Plan for game.py: Ensure game.py remains mostly unchanged as it contains the core game logic. However, make minor adjustments if necessary to integrate with the new GUI.\n```python\nclass Game:\n # No changes required for now\n```\n' } diff --git a/tests/metagpt/actions/test_design_api_an.py b/tests/metagpt/actions/test_design_api_an.py index 39de2a595..fcd2ef666 100644 --- a/tests/metagpt/actions/test_design_api_an.py +++ b/tests/metagpt/actions/test_design_api_an.py @@ -10,7 +10,7 @@ from openai._models import BaseModel from metagpt.actions.action_node import ActionNode, dict_to_markdown from metagpt.actions.design_api import NEW_REQ_TEMPLATE -from metagpt.actions.design_api_an import REFINED_DESIGN_NODES +from metagpt.actions.design_api_an import REFINED_DESIGN_NODE from metagpt.llm import LLM from tests.data.incremental_dev_project.mock import ( DESIGN_SAMPLE, @@ -38,7 +38,7 @@ async def test_write_design_an(mocker): mocker.patch("metagpt.actions.design_api_an.REFINED_DESIGN_NODES.fill", return_value=root) prompt = NEW_REQ_TEMPLATE.format(old_design=DESIGN_SAMPLE, context=dict_to_markdown(REFINED_PRD_JSON)) - node = await REFINED_DESIGN_NODES.fill(prompt, llm) + node = await REFINED_DESIGN_NODE.fill(prompt, llm) assert "Refined Implementation Approach" in node.instruct_content.model_dump() assert "Refined File list" in node.instruct_content.model_dump() diff --git a/tests/metagpt/actions/test_project_management_an.py b/tests/metagpt/actions/test_project_management_an.py index 50dc47067..e230151da 100644 --- a/tests/metagpt/actions/test_project_management_an.py +++ b/tests/metagpt/actions/test_project_management_an.py @@ -10,7 +10,7 @@ from openai._models import BaseModel from metagpt.actions.action_node import ActionNode, dict_to_markdown from metagpt.actions.project_management import NEW_REQ_TEMPLATE -from metagpt.actions.project_management_an import REFINED_PM_NODES +from metagpt.actions.project_management_an import REFINED_PM_NODE from metagpt.llm import LLM from tests.data.incremental_dev_project.mock import ( REFINED_DESIGN_JSON, @@ -38,7 +38,7 @@ async def test_project_management_an(mocker): mocker.patch("metagpt.actions.project_management_an.REFINED_PM_NODES.fill", return_value=root) prompt = NEW_REQ_TEMPLATE.format(old_tasks=TASKS_SAMPLE, context=dict_to_markdown(REFINED_DESIGN_JSON)) - node = await REFINED_PM_NODES.fill(prompt, llm) + node = await REFINED_PM_NODE.fill(prompt, llm) assert "Refined Logic Analysis" in node.instruct_content.model_dump() assert "Refined Task list" in node.instruct_content.model_dump() diff --git a/tests/metagpt/actions/test_write_code_plan_an.py b/tests/metagpt/actions/test_write_code_plan_an.py index 0babab7c5..13bda7cc1 100644 --- a/tests/metagpt/actions/test_write_code_plan_an.py +++ b/tests/metagpt/actions/test_write_code_plan_an.py @@ -10,16 +10,17 @@ from openai._models import BaseModel from metagpt.actions.action_node import ActionNode from metagpt.actions.write_code import WriteCode -from metagpt.actions.write_code_plan_an import ( - CODE_PLAN_CONTEXT, - REFINED_CODE_TEMPLATE, - WriteCodePlan, +from metagpt.actions.write_code_plan_and_change_an import ( + CODE_PLAN_AND_CHANGE_CONTEXT, + REFINED_TEMPLATE, + WriteCodePlanAndChange, ) +from metagpt.actions.write_prd_an import REQUIREMENT_POOL from tests.data.incremental_dev_project.mock import ( + CODE_PLAN_AND_CHANGE_SAMPLE, DESIGN_SAMPLE, NEW_REQUIREMENT_SAMPLE, OLD_CODE_SAMPLE, - PLAN_SAMPLE, REFINED_CODE_INPUT_SAMPLE, REFINED_CODE_SAMPLE, REFINED_DESIGN_JSON, @@ -29,23 +30,23 @@ from tests.data.incremental_dev_project.mock import ( ) -def mock_plan(): - return PLAN_SAMPLE +def mock_code_plan_and_change(): + return CODE_PLAN_AND_CHANGE_SAMPLE @pytest.mark.asyncio async def test_write_code_plan_an(mocker): root = ActionNode.from_children( - "WriteCodePlan", [ActionNode(key="", expected_type=str, instruction="", example="")] + "WriteCodePlanAndChange", [ActionNode(key="", expected_type=str, instruction="", example="")] ) root.instruct_content = BaseModel() - root.instruct_content.model_dump = mock_plan - mocker.patch("metagpt.actions.write_code_plan_an.WriteCodePlan.run", return_value=root) + root.instruct_content.model_dump = mock_code_plan_and_change + mocker.patch("metagpt.actions.write_code_plan_an.WriteCodePlanAndChange.run", return_value=root) - write_code_plan = WriteCodePlan() - context = CODE_PLAN_CONTEXT.format( + write_code_plan = WriteCodePlanAndChange() + context = CODE_PLAN_AND_CHANGE_CONTEXT.format( user_requirement=NEW_REQUIREMENT_SAMPLE, - product_requirement_pools=REFINED_PRD_JSON.get("Refined Requirement Pool", ""), + product_requirement_pools=REFINED_PRD_JSON.get(REQUIREMENT_POOL.key), design=REFINED_DESIGN_JSON, tasks=REFINED_TASKS_JSON, code=OLD_CODE_SAMPLE, @@ -57,10 +58,10 @@ async def test_write_code_plan_an(mocker): @pytest.mark.asyncio async def test_refine_code(mocker): - mocker.patch("metagpt.actions.write_code.WriteCode.write_code", return_value=REFINED_CODE_SAMPLE) - prompt = REFINED_CODE_TEMPLATE.format( + mocker.patch("metagpt.actions.write_code.WriteCodePlanAndChange.write_code", return_value=REFINED_CODE_SAMPLE) + prompt = REFINED_TEMPLATE.format( user_requirement=NEW_REQUIREMENT_SAMPLE, - plan=PLAN_SAMPLE, + code_plan_and_change=CODE_PLAN_AND_CHANGE_SAMPLE, design=DESIGN_SAMPLE, tasks=TASKS_SAMPLE, code=REFINED_CODE_INPUT_SAMPLE, diff --git a/tests/metagpt/actions/test_write_prd_an.py b/tests/metagpt/actions/test_write_prd_an.py index 1fdaa75c2..806f88d36 100644 --- a/tests/metagpt/actions/test_write_prd_an.py +++ b/tests/metagpt/actions/test_write_prd_an.py @@ -9,7 +9,7 @@ import pytest from openai._models import BaseModel from metagpt.actions.action_node import ActionNode -from metagpt.actions.write_prd_an import REFINE_PRD_NODE, REFINE_PRD_TEMPLATE +from metagpt.actions.write_prd_an import REFINED_PRD_NODE, REFINED_TEMPLATE from metagpt.llm import LLM from tests.data.incremental_dev_project.mock import ( NEW_REQUIREMENT_SAMPLE, @@ -34,12 +34,12 @@ async def test_write_prd_an(mocker): root.instruct_content.model_dump = mock_refined_prd_json mocker.patch("metagpt.actions.write_prd_an.REFINE_PRD_NODE.fill", return_value=root) - prompt = REFINE_PRD_TEMPLATE.format( + prompt = REFINED_TEMPLATE.format( requirements=NEW_REQUIREMENT_SAMPLE, old_prd=PRD_SAMPLE, project_name="", ) - node = await REFINE_PRD_NODE.fill(prompt, llm) + node = await REFINED_PRD_NODE.fill(prompt, llm) assert "Refined Requirements" in node.instruct_content.model_dump() assert "Refined Product Goals" in node.instruct_content.model_dump()