diff --git a/metagpt/actions/write_code_guideline_an.py b/metagpt/actions/write_code_guideline_an.py index ee6dc81b7..0677f6edc 100644 --- a/metagpt/actions/write_code_guideline_an.py +++ b/metagpt/actions/write_code_guideline_an.py @@ -3,7 +3,7 @@ """ @Time : 2023/12/26 @Author : mannaandpoem -@File : write_code_guide_an.py +@File : write_code_guideline_an.py """ import asyncio @@ -78,19 +78,7 @@ if __name__ == '__main__': ) CODE_GUIDELINE_CONTEXT = """ -NOTICE -Role: You are a professional software engineer, and your main task is to craft comprehensive incremental development plans and provide detailed code guidance with triple quote, based on the following attentions and context. Output format carefully referenced "Format example". -1. Determine the scope of responsibilities of each file and what classes and methods need to be implemented. -2. Import all referenced classes. -3. Implement all methods. -4. Add necessary explanation to all methods. -5. Ensure there are no potential bugs. -6. Confirm that the entire project conforms to the tasks proposed by the user. -7. Examine the code closely to find and fix errors, and confirm that the logic is sound to ensure smooth user interaction while meeting all specified requirements. -8. Attention: Code files in the task list may have a different number of files compared to legacy code files. This requires integrating legacy code files that do not appear in the task list into the code files of the task list. Therefore, when writing code guidance and incremental changes for the code files in the task list, also include how to seamlessly merge and adjust legacy code files. - -# Context -## Requirement +## New Requirements {requirement} ## Design @@ -104,19 +92,7 @@ Role: You are a professional software engineer, and your main task is to craft c """ CODE_GUIDELINE_CONTEXT_EXAMPLE = """ -NOTICE -Role: You are a professional software engineer, and your main task is to craft comprehensive incremental development plans and provide detailed code guidance with triple quote, based on the following attentions and context. Output format carefully referenced "Format example". -1. Determine the scope of responsibilities of each file and what classes and methods need to be implemented. -2. Import all referenced classes. -3. Implement all methods. -4. Add necessary explanation to all methods. -5. Ensure there are no potential bugs. -6. Confirm that the entire project conforms to the tasks proposed by the user. -7. Examine the code closely to find and fix errors, and confirm that the logic is sound to ensure smooth user interaction while meeting all specified requirements. -8. Attention: Code files in the task list may have a different number of files compared to legacy code files. This requires integrating legacy code files that do not appear in the task list into the code files of the task list. Therefore, when writing code guidance and incremental changes for the code files in the task list, also include how to seamlessly merge and adjust legacy code files. - -# Context -## Requirement +## New Requirements Add subtraction, multiplication and division operations to the calculator. The current calculator can only perform basic addition operations, and it is necessary to introduce subtraction, multiplication, division operation into the calculator @@ -172,10 +148,6 @@ The current calculator can only perform basic addition operations, and it is nec } ## Legacy Code -{code} -""" - -CODE_GUIDELINE_SCRIPT_EXAMPLE = """ ----- calculator.py ```## calculator.py @@ -381,9 +353,6 @@ class Interface: def show_error(self, message: str): tk.messagebox.showerror("Error", message) - -# This code is meant to be used as a module and not as a standalone script. -# The Interface class will be instantiated and started by the main.py file. ``` """ @@ -448,12 +417,14 @@ WRITE_CODE_GUIDELINE_NODE = ActionNode.from_children("WriteCodeGuideline", GUIDE class WriteCodeGuideline(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 plans and deliver detailed Incremental Change" return await WRITE_CODE_GUIDELINE_NODE.fill(context=context, llm=self.llm, schema="json") async def main(): write_code_guideline = WriteCodeGuideline() - node = await write_code_guideline.run(CODE_GUIDELINE_CONTEXT_EXAMPLE.format(code=CODE_GUIDELINE_SCRIPT_EXAMPLE)) + node = await write_code_guideline.run(CODE_GUIDELINE_CONTEXT_EXAMPLE) guideline = node.instruct_content.json(ensure_ascii=False) print(guideline) diff --git a/tests/metagpt/actions/test_design_api_an.py b/tests/metagpt/actions/test_design_api_an.py index 32d6c11b0..305c708c0 100644 --- a/tests/metagpt/actions/test_design_api_an.py +++ b/tests/metagpt/actions/test_design_api_an.py @@ -3,7 +3,7 @@ """ @Time : 2024/01/03 @Author : mannaandpoem -@File : test_design_api_an.py.py +@File : test_design_api_an.py """ import pytest diff --git a/tests/metagpt/actions/test_project_management_an.py b/tests/metagpt/actions/test_project_management_an.py index 116dffe83..9ad4360cf 100644 --- a/tests/metagpt/actions/test_project_management_an.py +++ b/tests/metagpt/actions/test_project_management_an.py @@ -3,7 +3,7 @@ """ @Time : 2024/01/03 @Author : mannaandpoem -@File : test_project_management_an.py.py +@File : test_project_management_an.py """ import pytest diff --git a/tests/metagpt/actions/test_write_code_guideline_an.py b/tests/metagpt/actions/test_write_code_guideline_an.py index 602145ce8..d740a6bd8 100644 --- a/tests/metagpt/actions/test_write_code_guideline_an.py +++ b/tests/metagpt/actions/test_write_code_guideline_an.py @@ -3,14 +3,13 @@ """ @Time : 2024/01/03 @Author : mannaandpoem -@File : test_write_code_guideline_an.py.py +@File : test_write_code_guideline_an.py """ import pytest from metagpt.actions.write_code import WriteCode from metagpt.actions.write_code_guideline_an import ( CODE_GUIDELINE_CONTEXT, - CODE_GUIDELINE_SCRIPT_EXAMPLE, REFINE_CODE_SCRIPT_EXAMPLE, REFINED_CODE_TEMPLATE, WriteCodeGuideline, @@ -73,6 +72,119 @@ TASKS_EXAMPLE = """ } """ +CODE_GUIDELINE_SCRIPT_EXAMPLE = """ +----- calculator.py +```## calculator.py + +class Calculator: + def __init__(self): + self.result = 0.0 # Default value for the result + + def add(self, number1: float, number2: float) -> float: + ''' + Adds two numbers and returns the result. + + Args: + number1 (float): The first number to add. + number2 (float): The second number to add. + + Returns: + float: The sum of number1 and number2. + ''' + self.result = number1 + number2 + return self.result + + def clear(self) -> None: + ''' + Clears the result to its default value. + ''' + self.result = 0.0 +``` + +---- interface.py +```## interface.py +import tkinter as tk +from calculator import Calculator + +class Interface: + def __init__(self): + self.calculator = Calculator() + self.root = tk.Tk() + self.root.title("Calculator") + self.create_widgets() + + def create_widgets(self): + self.result_var = tk.StringVar() + self.result_display = tk.Entry(self.root, textvariable=self.result_var, state='readonly', justify='right', font=('Arial', 24)) + self.result_display.grid(row=0, column=0, columnspan=4, sticky='nsew') + + self.entry_number1 = tk.Entry(self.root, justify='right', font=('Arial', 18)) + self.entry_number1.grid(row=1, column=0, columnspan=2, sticky='nsew') + + self.entry_number2 = tk.Entry(self.root, justify='right', font=('Arial', 18)) + self.entry_number2.grid(row=1, column=2, columnspan=2, sticky='nsew') + + self.add_button = tk.Button(self.root, text='+', command=self.add, font=('Arial', 18)) + self.add_button.grid(row=2, column=0, sticky='nsew') + + self.clear_button = tk.Button(self.root, text='C', command=self.clear, font=('Arial', 18)) + self.clear_button.grid(row=2, column=1, sticky='nsew') + + self.quit_button = tk.Button(self.root, text='Quit', command=self.root.quit, font=('Arial', 18)) + self.quit_button.grid(row=2, column=2, columnspan=2, sticky='nsew') + + self.root.grid_rowconfigure(1, weight=1) + self.root.grid_columnconfigure(0, weight=1) + + def start(self): + self.root.mainloop() + + def display_result(self, result: float): + self.result_var.set(str(result)) + + def get_input(self): + try: + number1 = float(self.entry_number1.get()) + number2 = float(self.entry_number2.get()) + return number1, number2 + except ValueError: + self.show_error("Invalid input! Please enter valid numbers.") + return None, None + + def add(self): + number1, number2 = self.get_input() + if number1 is not None and number2 is not None: + result = self.calculator.add(number1, number2) + self.display_result(result) + + def clear(self): + self.entry_number1.delete(0, tk.END) + self.entry_number2.delete(0, tk.END) + self.result_var.set("") + + def show_error(self, message: str): + tk.messagebox.showerror("Error", message) + +# This code is meant to be used as a module and not as a standalone script. +# The Interface class will be instantiated and started by the main.py file. +``` + +---- main.py +```## main.py +from interface import Interface + + +class CalculatorApp: + @staticmethod + def main(): + interface = Interface() + interface.start() + + +if __name__ == "__main__": + CalculatorApp.main() +```""" + INCREMENTAL_CHANGE_EXAMPLE = """ { "Incremental Change": "- operations.py: Implement the Operations class with a method to perform the requested arithmetic operation. This class will be used by the Calculator class to execute the operations.\n```python\n## operations.py\nclass Operations:\n @staticmethod\n def perform_operation(operation: str, number1: float, number2: float) -> float:\n if operation == 'add':\n return number1 + number2\n elif operation == 'subtract':\n return number1 - number2\n elif operation == 'multiply':\n return number1 * number2\n elif operation == 'divide':\n if number2 == 0:\n raise ValueError('Cannot divide by zero')\n return number1 / number2\n else:\n raise ValueError('Invalid operation')\n```\n\n- calculator.py: Extend the Calculator class to include methods for subtraction, multiplication, and division. These methods will utilize the Operations class to perform the actual calculations.\n```python\n## calculator.py\nfrom operations import Operations\nclass Calculator:\n ...\n def subtract(self, number1: float, number2: float) -> float:\n return Operations.perform_operation('subtract', number1, number2)\n\n def multiply(self, number1: float, number2: float) -> float:\n return Operations.perform_operation('multiply', number1, number2)\n\n def divide(self, number1: float, number2: float) -> float:\n return Operations.perform_operation('divide', number1, number2)\n```\n\n- interface.py: Update the Interface class to include buttons for subtraction, multiplication, and division, and link them to the corresponding methods in the Calculator class. Also, handle the display of errors such as division by zero.\n```python\n## interface.py\nimport tkinter as tk\nfrom tkinter import messagebox\nfrom calculator import Calculator\n...\nclass Interface:\n ...\n def create_widgets(self):\n ...\n self.subtract_button = tk.Button(self.root, text='-', command=self.subtract, font=('Arial', 18))\n self.subtract_button.grid(row=3, column=0, sticky='nsew')\n\n self.multiply_button = tk.Button(self.root, text='*', command=self.multiply, font=('Arial', 18))\n self.multiply_button.grid(row=3, column=1, sticky='nsew')\n\n self.divide_button = tk.Button(self.root, text='/', command=self.divide, font=('Arial', 18))\n self.divide_button.grid(row=3, column=2, sticky='nsew')\n ...\n\n def subtract(self):\n number1, number2 = self.get_input()\n if number1 is not None and number2 is not None:\n result = self.calculator.subtract(number1, number2)\n self.display_result(result)\n\n def multiply(self):\n number1, number2 = self.get_input()\n if number1 is not None and number2 is not None:\n result = self.calculator.multiply(number1, number2)\n self.display_result(result)\n\n def divide(self):\n number1, number2 = self.get_input()\n if number1 is not None and number2 is not None:\n try:\n result = self.calculator.divide(number1, number2)\n except ValueError as e:\n self.show_error(str(e))\n return\n self.display_result(result)\n```\n\n- main.py: No changes needed in main.py as it serves as the entry point and will run the updated Interface class.\n```python\n## main.py\nfrom interface import Interface\n...\n```\n\nNote: Ensure that the new operations buttons in the Interface class are properly arranged and that the grid layout is adjusted accordingly. Also, make sure to import the messagebox module from tkinter for error handling." diff --git a/tests/metagpt/actions/test_write_prd_an.py b/tests/metagpt/actions/test_write_prd_an.py index ef0dd2eff..d520eb863 100644 --- a/tests/metagpt/actions/test_write_prd_an.py +++ b/tests/metagpt/actions/test_write_prd_an.py @@ -3,7 +3,7 @@ """ @Time : 2024/01/03 @Author : mannaandpoem -@File : test_write_prd_an.py.py +@File : test_write_prd_an.py """ import pytest