diff --git a/metagpt/actions/design_api_an.py b/metagpt/actions/design_api_an.py index 02f20a133..ee1941350 100644 --- a/metagpt/actions/design_api_an.py +++ b/metagpt/actions/design_api_an.py @@ -22,7 +22,7 @@ INCREMENTAL_IMPLEMENTATION_APPROACH = ActionNode( key="Incremental Implementation approach", expected_type=str, instruction="Analyze the challenging aspects of the requirements and select a suitable open-source framework. " - "Outline the incremental steps involved in the implementation process with a list of detailed strategies.", + "Outline the incremental steps involved in the implementation process with the detailed strategies.", example="we will ...", ) @@ -30,8 +30,8 @@ REFINED_IMPLEMENTATION_APPROACH = ActionNode( key="Refined Implementation Approach", expected_type=str, instruction="Update and extend the original implementation approach to reflect the evolving challenges and " - "requirements due to incremental development. Provide detailed strategies for incremental steps in the " - "implementation process. Retain any content unrelated to incremental development for coherence and clarity.", + "requirements due to incremental development. Outline the steps involved in the implementation process with the " + "detailed strategies.", example="We will refine ...", ) @@ -49,8 +49,8 @@ FILE_LIST = ActionNode( REFINED_FILE_LIST = ActionNode( key="Refined File List", expected_type=List[str], - instruction="Update and expand the original file list including only relative paths, up to 2 files can be added." - "Ensure that the refined file list reflects the evolving structure of the project due to incremental development.", + instruction="Update and expand the original file list including only relative paths. Up to 2 files can be added." + "Ensure that the refined file list reflects the evolving structure of the project.", example=["main.py", "game.py", "new_feature.py"], ) @@ -78,9 +78,8 @@ REFINED_DATA_STRUCTURES_AND_INTERFACES = ActionNode( expected_type=str, instruction="Update and extend the existing mermaid classDiagram code syntax to incorporate new classes, " "methods (including __init__), and functions with precise type annotations. Delineate additional " - "relationships between classes, ensuring clarity and adherence to PEP8 standards. Further enhance the " - "detail in data structures for a comprehensive API design that seamlessly integrates with the evolving structure." - "Retain any content unrelated to incremental development for coherence and clarity.", + "relationships between classes, ensuring clarity and adherence to PEP8 standards." + "Retain content that is not related to incremental development but important for consistency and clarity.", example=MMC1_REFINE, ) @@ -97,7 +96,8 @@ REFINED_PROGRAM_CALL_FLOW = ActionNode( expected_type=str, instruction="Extend the existing sequenceDiagram code syntax with detailed information, accurately covering the" "CRUD and initialization of each object. Ensure correct syntax usage and reflect the incremental changes introduced" - "in the classes and API defined above.Retain content unrelated to incremental development for coherence and clarity", + "in the classes and API defined above. " + "Retain content that is not related to incremental development but important for consistency and clarity.", example=MMC2_REFINE, ) diff --git a/metagpt/actions/project_management_an.py b/metagpt/actions/project_management_an.py index 9b54698a1..559c5ef8e 100644 --- a/metagpt/actions/project_management_an.py +++ b/metagpt/actions/project_management_an.py @@ -52,8 +52,7 @@ REFINED_LOGIC_ANALYSIS = ActionNode( expected_type=List[List[str]], instruction="Review and refine the logic analysis by merging the Legacy Content and Incremental Content. " "Provide a comprehensive list of files with classes/methods/functions to be implemented or modified incrementally. " - "Include thorough dependency analysis, consider potential impacts on existing code, and document necessary imports." - "Retain any content unrelated to incremental development for coherence and clarity.", + "Include thorough dependency analysis, consider potential impacts on existing code, and document necessary imports.", example=[ ["game.py", "Contains Game class and ... functions"], ["main.py", "Contains main function, from game import Game"], @@ -81,9 +80,9 @@ INCREMENTAL_TASK_LIST = ActionNode( REFINED_TASK_LIST = ActionNode( key="Refined Task list", expected_type=List[str], - instruction="Review and refine the combined task list after the merger of Legacy Content and Incremental Content, and consistent with Refined File List." - "Ensure that tasks are organized in a logical and prioritized order, considering dependencies for a streamlined and" - " efficient development process. ", + instruction="Review and refine the combined task list after the merger of Legacy Content and Incremental Content, " + "and consistent with Refined File List. Ensure that tasks are organized in a logical and prioritized order, " + "considering dependencies for a streamlined and efficient development process. ", example=["new_feature.py", "utils", "game.py", "main.py"], ) @@ -113,9 +112,9 @@ INCREMENTAL_SHARED_KNOWLEDGE = ActionNode( REFINED_SHARED_KNOWLEDGE = ActionNode( key="Refined Shared Knowledge", expected_type=str, - instruction="Update and expand shared knowledge to reflect any new elements introduced during incremental " - "development. This includes common utility functions, configuration variables, or any information vital for team " - "collaboration. Retain any content unrelated to incremental development for coherence and clarity.", + instruction="Update and expand shared knowledge to reflect any new elements introduced. This includes common " + "utility functions, configuration variables for team collaboration. Retain content that is not related to " + "incremental development but important for consistency and clarity.", example="`new_module.py` enhances shared utility functions for improved code reusability and collaboration.", ) diff --git a/metagpt/actions/write_code.py b/metagpt/actions/write_code.py index 25e65ddc7..f92b72f7f 100644 --- a/metagpt/actions/write_code.py +++ b/metagpt/actions/write_code.py @@ -174,13 +174,15 @@ class WriteCode(Action): for filename in union_files_list: if filename == exclude: if filename in old_files and filename != "main.py": - doc = await old_file_repo.get(filename=filename) # 使用原始代码 + # Use legacy code + doc = await old_file_repo.get(filename=filename) else: continue codes.insert(0, f"-----Now, {filename} to be rewritten\n```{doc.content}```\n=====") else: - doc = await src_file_repo.get(filename=filename) # 使用先前生成的代码 + # Use new code + doc = await src_file_repo.get(filename=filename) if not doc: continue codes.append(f"----- {filename}\n```{doc.content}```") diff --git a/metagpt/actions/write_code_guideline_an.py b/metagpt/actions/write_code_guideline_an.py index 7b27fbe4c..cc532ed0f 100644 --- a/metagpt/actions/write_code_guideline_an.py +++ b/metagpt/actions/write_code_guideline_an.py @@ -434,11 +434,11 @@ 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 Guidelines and Incremental Change: If there is any Incremental Change, you must merge it into the code file according to the guidelines. +5. Follow Guidelines 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 guidelines. 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: If Legacy Code files contain "{filename} to be rewritten", you are required to merge the Incremental Change into the {filename} file when rewriting "{filename} to be rewritten". +9. Attention: Retain content that is not related to incremental development but important for consistency and clarity.". """ WRITE_CODE_GUIDELINE_NODE = ActionNode.from_children("WriteCodeGuideline", [GUIDELINES_AND_INCREMENTAL_CHANGE]) diff --git a/metagpt/actions/write_prd_an.py b/metagpt/actions/write_prd_an.py index 2eaed7114..7004bfffc 100644 --- a/metagpt/actions/write_prd_an.py +++ b/metagpt/actions/write_prd_an.py @@ -34,8 +34,7 @@ ORIGINAL_REQUIREMENTS = ActionNode( REFINED_REQUIREMENTS = ActionNode( key="Refined Requirements", expected_type=str, - instruction="Update and expand the original user's requirements to reflect the evolving needs of the project." - "Retain any content unrelated to incremental development", + instruction="Place the New user's requirements here.", example="Create a 2048 game with a new feature that ...", ) @@ -57,8 +56,7 @@ REFINED_PRODUCT_GOALS = ActionNode( key="Refined Product Goals", expected_type=List[str], instruction="Update and expand the original product goals to reflect the evolving needs due to incremental " - "development.Ensure that the refined goals align with the current project direction and contribute to its success." - "Retain any content unrelated to incremental development", + "development.Ensure that the refined goals align with the current project direction and contribute to its success.", example=[ "Enhance user engagement through new features", "Optimize performance for scalability", @@ -83,8 +81,7 @@ REFINED_USER_STORIES = ActionNode( key="Refined User Stories", expected_type=List[str], instruction="Update and expand the original scenario-based user stories to reflect the evolving needs due to " - "incremental development, no less than 5. Ensure that the refined user stories capture incremental features and " - "improvements. Retain any content unrelated to incremental development", + "incremental development. Ensure that the refined user stories capture incremental features and improvements. ", example=[ "As a player, I want to choose difficulty levels to challenge my skills", "As a player, I want a visually appealing score display after each game for a better gaming experience", @@ -160,8 +157,8 @@ REQUIREMENT_POOL = ActionNode( REFINED_REQUIREMENT_POOL = ActionNode( key="Refined Requirement Pool", expected_type=List[List[str]], - instruction="List no less than 5 requirements with their priority (P0, P1, P2) from high to low. " - "Cover both legacy content and incremental content. Retain any content unrelated to incremental development", + instruction="List down the top 5 to 7 requirements with their priority (P0, P1, P2). " + "Cover both legacy content and incremental content. Retain content unrelated to incremental development", example=[["P0", "The main code ..."], ["P0", "The game algorithm ..."]], ) diff --git a/tests/metagpt/test_incremental_dev.py b/tests/metagpt/test_incremental_dev.py index 2ff33dff3..223b0fb10 100644 --- a/tests/metagpt/test_incremental_dev.py +++ b/tests/metagpt/test_incremental_dev.py @@ -35,6 +35,7 @@ def test_refined_simple_calculator(): assert False else: tag = subprocess.run(["git", "describe", "--tags"], capture_output=True, text=True).stdout.strip() + # After running, there will be new commit if tag == "base": assert False else: @@ -261,6 +262,87 @@ def test_refined_pygame_2048_3(): raise e +def test_refined_snake_game_1(): + project_path = f"{DATA_PATH}/snake_game" + check_or_create_base_tag(project_path) + + args = [ + "Incremental Idea Gradually increase the speed of the snake as the game progresses. In the current version of the game, the snake’s speed remains constant throughout the gameplay. Implement a feature where the snake’s speed gradually increases over time, making the game more challenging and intense as the player progresses.", + "--inc", + "--project-path", + project_path, + ] + result = runner.invoke(app, args) + logger.info(result) + logger.info(result.output) + if "Aborting" in result.output: + assert False + else: + tag = subprocess.run(["git", "describe", "--tags"], capture_output=True, text=True).stdout.strip() + if tag == "base": + assert False + else: + assert True + try: + subprocess.run(["git", "tag", "refine_1"], check=True) + except subprocess.CalledProcessError as e: + raise e + + +def test_refined_snake_game_2(): + project_path = f"{DATA_PATH}/snake_game" + check_or_create_base_tag(project_path) + + args = [ + "Introduce power-ups and obstacles to the game. The current version of the game only involves eating food and growing the snake. Add new elements such as power-ups that can enhance the snake’s speed or make it invincible for a short duration. At the same time, introduce obstacles like walls or enemies that the snake must avoid or overcome to continue growing.", + "--inc", + "--project-path", + project_path, + ] + result = runner.invoke(app, args) + logger.info(result) + logger.info(result.output) + if "Aborting" in result.output: + assert False + else: + tag = subprocess.run(["git", "describe", "--tags"], capture_output=True, text=True).stdout.strip() + if tag == "base": + assert False + else: + assert True + try: + subprocess.run(["git", "tag", "refine_2"], check=True) + except subprocess.CalledProcessError as e: + raise e + + +def test_refined_gomoku(): + project_path = f"{DATA_PATH}/Gomoku" + check_or_create_base_tag(project_path) + + args = [ + "Add an AI opponent with fixed difficulty levels. Currently, the game only allows players to compete against themselves. Implement an AI algorithm that can playing with player. This will provide a more engaging and challenging experience for players.", + "--inc", + "--project-path", + project_path, + ] + result = runner.invoke(app, args) + logger.info(result) + logger.info(result.output) + if "Aborting" in result.output: + assert False + else: + tag = subprocess.run(["git", "describe", "--tags"], capture_output=True, text=True).stdout.strip() + if tag == "base": + assert False + else: + assert True + try: + subprocess.run(["git", "tag", "refine"], check=True) + except subprocess.CalledProcessError as e: + raise e + + def check_or_create_base_tag(project_path): # Change the current working directory to the specified project path os.chdir(project_path)