From a8aaece8fb09ab1afbac6450fddfeb4e6562a6d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E4=BC=9F=E9=9F=AC?= Date: Wed, 18 Sep 2024 19:34:39 +0800 Subject: [PATCH] remove the outdated editor results. --- metagpt/roles/di/role_zero.py | 19 ++++++++ metagpt/strategy/experience_retriever.py | 8 ++-- metagpt/tools/libs/editor.py | 55 +++++++++++++----------- tests/metagpt/tools/libs/test_editor.py | 32 +++++++------- 4 files changed, 68 insertions(+), 46 deletions(-) diff --git a/metagpt/roles/di/role_zero.py b/metagpt/roles/di/role_zero.py index 5e07f4895..f93ad9058 100644 --- a/metagpt/roles/di/role_zero.py +++ b/metagpt/roles/di/role_zero.py @@ -213,6 +213,7 @@ class RoleZero(Role): ### Recent Observation ### memory = self.rc.memory.get(self.memory_k) memory = await self.parse_browser_actions(memory) + memory = await self.parse_editor_result(memory) memory = self.parse_images(memory) req = self.llm.format_msg(memory + [UserMessage(content=prompt)]) @@ -246,6 +247,24 @@ class RoleZero(Role): break return memory + async def parse_editor_result(self, memory: list[Message]) -> list[Message]: + """Retain the latest result for each editor command and remove outdated editor results.""" + # Set to keep track of unique editor commands + record = set() + pattern = re.compile(r"Command Editor\.(\w+) executed") + # Iterate over the memory in reverse order + for msg in reversed(memory): + matches = pattern.findall(msg.content) + if not matches: + continue + # If all matches are already in the record, remove the editor content + if all(match in record for match in matches): + msg.content = msg.content[: msg.content.find("Command Editor")] + else: + # Add new matches to the record + record.update(matches) + return memory + def parse_images(self, memory: list[Message]) -> list[Message]: if not self.llm.support_image_input(): return memory diff --git a/metagpt/strategy/experience_retriever.py b/metagpt/strategy/experience_retriever.py index 7cefe863c..aec8a3337 100644 --- a/metagpt/strategy/experience_retriever.py +++ b/metagpt/strategy/experience_retriever.py @@ -972,11 +972,11 @@ Editor tool is exclusive. If I use this tool, I cannot use any other commands in "command_name": "Editor.edit_file_by_replace", "args": { "file_name":"/workspace/MetaGPT/provider/openai_api.py", - "start_line_number": 143, - "start_line_content":" if event.key == pygame.K_w:", + "first_replaced_line_number": 143, + "first_replaced_line_content":" if event.key == pygame.K_w:", "new_content": " if event.key == pygame.K_UP:\\n self.move_up()\\n elif event.key == pygame.K_DOWN:\\n self.move_down()\\n elif event.key == pygame.K_SPACE:\\n self.stop()" - "end_line_number": 146, - "end_line_content": " self.move_down()", + "last_replaced_line_number": 146, + "last_replaced_line_content": " self.move_down()", } } ] diff --git a/metagpt/tools/libs/editor.py b/metagpt/tools/libs/editor.py index 46a3bf970..376c86db5 100644 --- a/metagpt/tools/libs/editor.py +++ b/metagpt/tools/libs/editor.py @@ -54,13 +54,13 @@ Your changes have NOT been applied. Please fix your edit command and try again """ -LINE_NUMBER_AND_CONTENT_MISMATCH = """ -Error: The `{position}_line_number` does not match the `{position}_line_content`. Please correct the parameters. -The `{position}_line_number` is {line_number} and the corresponding content is "{true_content}". -But the `{position}_line_content` is "{fake_content}". +LINE_NUMBER_AND_CONTENT_MISMATCH = """Error: The `{position}_replaced_line_number` does not match the `{position}_replaced_line_content`. Please correct the parameters. +The `{position}_replaced_line_number` is {line_number} and the corresponding content is "{true_content}". +But the `{position}_replaced_line_content ` is "{fake_content}". The content around the specified line is: {context} -""".strip() +Pay attention to the new content. Ensure that it aligns with the new parameters. +""" SUCCESS_EDIT_INFO = """ [File: {file_name} ({n_total_lines} lines total after edit)] {window_after_applied} @@ -689,10 +689,10 @@ class Editor(BaseModel): def edit_file_by_replace( self, file_name: str, - start_line_number: int, - start_line_content: str, - end_line_number: int, - end_line_content: str, + first_replaced_line_number: int, + first_replaced_line_content: str, + last_replaced_line_number: int, + last_replaced_line_content: str, new_content: str, ) -> str: """ @@ -713,10 +713,10 @@ class Editor(BaseModel): edit_file_by_replace( '/workspace/example.txt', - start_line_number=2, - start_line_content="contain g", - end_line_number=3, - end_line_content="contain h", + first_replaced_line_number =2, + first_replaced_line_content="contain g", + last_replaced_line_number =3, + last_replaced_line_content="contain h", new_content='new content', ) This will replace only the second line 2 and line 3 with "new content". @@ -738,10 +738,10 @@ class Editor(BaseModel): EDITING: If you want to remove the line 2 and line 3 edit_file_by_replace( '/workspace/example.txt', - start_line_number=2, - start_line_content="contain g", - end_line_number=3, - end_line_content="contain h", + first_replaced_line_number =2, + first_replaced_line_content="contain g", + last_replaced_line_number =3, + last_replaced_line_content="contain h", new_content='new line', ) This will remove line 2 and line 3 @@ -753,17 +753,17 @@ class Editor(BaseModel): ``` Args: file_name str:The name of the file to edit. - start_line_number int:The line number to start the edit at, starting from 1. - start_line_content str:The content of the start replace line, according to the start_line_number. - end_line_number int:The line number to end the edit at (inclusive), starting from 1. - end_line_content str:The content of the end replace line, according to the end_line_number. + first_replaced_line_number int:The line number to start the edit at, starting from 1. + first_replaced_line_content str:The content of the start replace line, according to the first_replaced_line_number . + last_replaced_line_number int:The line number to end the edit at (inclusive), starting from 1. + last_replaced_line_content str:The content of the end replace line, according to the last_replaced_line_number . new_content str: The text to replace the current selection with, must conform to PEP8 standards.The content in the start line and end line will also be replaced. """ file_name = self._try_fix_path(file_name) - # Check if the start_line_number and end_line_number correspond to the appropriate content. + # Check if the first_replaced_line_number and last_replaced_line_number correspond to the appropriate content. mismatch_error = "" with file_name.open() as file: content = file.read() @@ -772,7 +772,10 @@ class Editor(BaseModel): content += "\n" lines = content.splitlines(True) total_lines = len(lines) - check_list = [("start", start_line_number, start_line_content), ("end", end_line_number, end_line_content)] + check_list = [ + ("first_replaced", first_replaced_line_number, first_replaced_line_content), + ("last_replaced", last_replaced_line_number, last_replaced_line_content), + ] for position, line_number, line_content in check_list: if lines[line_number - 1].rstrip() != line_content: start = max(1, line_number - 3) @@ -785,14 +788,14 @@ class Editor(BaseModel): line_number=line_number, true_content=lines[line_number - 1].rstrip(), fake_content=line_content, - context=context, + context=context.strip(), ) if mismatch_error: return mismatch_error ret_str = self._edit_file_impl( file_name, - start=start_line_number, - end=end_line_number, + start=first_replaced_line_number, + end=last_replaced_line_number, content=new_content, ) # TODO: automatically tries to fix linter error (maybe involve some static analysis tools on the location near the edit to figure out indentation) diff --git a/tests/metagpt/tools/libs/test_editor.py b/tests/metagpt/tools/libs/test_editor.py index 91c74085e..40b905e13 100644 --- a/tests/metagpt/tools/libs/test_editor.py +++ b/tests/metagpt/tools/libs/test_editor.py @@ -538,11 +538,11 @@ def test_edit_file_by_replace(temp_py_file): editor = Editor() editor.edit_file_by_replace( file_name=str(temp_py_file), - start_line_number=5, - start_line_content=" b = 2", + first_replaced_line_number=5, + first_replaced_line_content=" b = 2", new_content=" b = 9", - end_line_number=5, - end_line_content=" b = 2", + last_replaced_line_number=5, + last_replaced_line_content=" b = 2", ) with open(temp_py_file, "r") as f: new_content = f.read() @@ -550,9 +550,9 @@ def test_edit_file_by_replace(temp_py_file): MISMATCH_ERROR = """ -Error: The `start_line_number` does not match the `start_line_content`. Please correct the parameters. -The `start_line_number` is 5 and the corresponding content is " b = 2". -But the `start_line_content` is "". +Error: The `first_replaced_replaced_line_number` does not match the `first_replaced_replaced_line_content`. Please correct the parameters. +The `first_replaced_replaced_line_number` is 5 and the corresponding content is " b = 2". +But the `first_replaced_replaced_line_content ` is "". The content around the specified line is: 002|def test_function_for_fm(): 003| "some docstring" @@ -560,9 +560,10 @@ The content around the specified line is: 005| b = 2 006| c = 3 007| # this is the 7th line -Error: The `end_line_number` does not match the `end_line_content`. Please correct the parameters. -The `end_line_number` is 5 and the corresponding content is " b = 2". -But the `end_line_content` is "". +Pay attention to the new content. Ensure that it aligns with the new parameters. +Error: The `last_replaced_replaced_line_number` does not match the `last_replaced_replaced_line_content`. Please correct the parameters. +The `last_replaced_replaced_line_number` is 5 and the corresponding content is " b = 2". +But the `last_replaced_replaced_line_content ` is "". The content around the specified line is: 002|def test_function_for_fm(): 003| "some docstring" @@ -570,6 +571,7 @@ The content around the specified line is: 005| b = 2 006| c = 3 007| # this is the 7th line +Pay attention to the new content. Ensure that it aligns with the new parameters. """.strip() @@ -577,14 +579,12 @@ def test_edit_file_by_replace_mismatch(temp_py_file): editor = Editor() output = editor.edit_file_by_replace( file_name=str(temp_py_file), - start_line_number=5, - start_line_content="", + first_replaced_line_number=5, + first_replaced_line_content="", new_content=" b = 9", - end_line_number=5, - end_line_content="", + last_replaced_line_number=5, + last_replaced_line_content="", ) - with open("tmp.txt", "w", encoding="utf-8") as f: - f.write(output) assert output.strip() == MISMATCH_ERROR.strip()