From 9339eab20c95263549c8ad60a6bad087ab2cac46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Wed, 22 Nov 2023 20:40:42 +0800 Subject: [PATCH] feat: archive --- metagpt/actions/design_api.py | 22 +++++++--- metagpt/actions/project_management.py | 63 ++++++++++++++++++++++++++- metagpt/const.py | 3 +- metagpt/utils/file_repository.py | 2 +- metagpt/utils/git_repository.py | 16 +++++++ 5 files changed, 97 insertions(+), 9 deletions(-) diff --git a/metagpt/actions/design_api.py b/metagpt/actions/design_api.py index 65d53364b..e7ee87fa2 100644 --- a/metagpt/actions/design_api.py +++ b/metagpt/actions/design_api.py @@ -11,7 +11,7 @@ from typing import List from metagpt.actions import Action, ActionOutput from metagpt.config import CONFIG -from metagpt.const import PRDS_FILE_REPO, SYS_DESIGN_FILE_REPO, WORKSPACE_ROOT +from metagpt.const import PRDS_FILE_REPO, SYSTEM_DESIGN_FILE_REPO, WORKSPACE_ROOT from metagpt.logs import logger from metagpt.schema import Document, Documents from metagpt.utils.common import CodeParser @@ -208,7 +208,7 @@ class WriteDesign(Action): prds_file_repo = CONFIG.git_repo.new_file_repository(PRDS_FILE_REPO) changed_prds = prds_file_repo.changed_files # 通过git diff来识别docs/system_designs下那些设计文档发生了变动; - system_design_file_repo = CONFIG.git_repo.new_file_repository(SYS_DESIGN_FILE_REPO) + system_design_file_repo = CONFIG.git_repo.new_file_repository(SYSTEM_DESIGN_FILE_REPO) changed_system_designs = system_design_file_repo.changed_files # 对于那些发生变动的PRD和设计文档,重新生成设计内容; @@ -219,7 +219,7 @@ class WriteDesign(Action): if not old_system_design_doc: system_design = await self._run(context=prd.content) doc = Document( - root_path=SYS_DESIGN_FILE_REPO, filename=filename, content=system_design.instruct_content.json() + root_path=SYSTEM_DESIGN_FILE_REPO, filename=filename, content=system_design.instruct_content.json() ) else: doc = await self._merge(prd_doc=prd, system_design_doc=old_system_design_doc) @@ -234,7 +234,9 @@ class WriteDesign(Action): prd_doc = await prds_file_repo.get(filename=filename) old_system_design_doc = await system_design_file_repo.get(filename) new_system_design_doc = await self._merge(prd_doc, old_system_design_doc) - await system_design_file_repo.save(filename=filename, content=new_system_design_doc.content) + await system_design_file_repo.save( + filename=filename, content=new_system_design_doc.content, dependencies={prd_doc.root_relative_path} + ) changed_files.docs[filename] = new_system_design_doc # 等docs/system_designs/下所有文件都处理完才发publish message,给后续做全局优化留空间。 @@ -251,8 +253,18 @@ class WriteDesign(Action): "Python package name", system_design.instruct_content.dict()["Python package name"].strip().strip("'").strip('"'), ) - # await self._save(context, system_design) + await self._rename_workspace(system_design) return system_design async def _merge(self, prd_doc, system_design_doc): return system_design_doc + + async def _rename_workspace(self, system_design): + if CONFIG.WORKDIR: # 已经指定了在旧版本上更新 + return + + if isinstance(system_design, ActionOutput): + ws_name = system_design.instruct_content.dict()["Python package name"] + else: + ws_name = CodeParser.parse_str(block="Python package name", text=system_design) + CONFIG.git_repo.rename_root(ws_name) diff --git a/metagpt/actions/project_management.py b/metagpt/actions/project_management.py index b395fa64e..73481c780 100644 --- a/metagpt/actions/project_management.py +++ b/metagpt/actions/project_management.py @@ -5,11 +5,14 @@ @Author : alexanderwu @File : project_management.py """ +import json from typing import List +from metagpt.actions import ActionOutput from metagpt.actions.action import Action from metagpt.config import CONFIG -from metagpt.const import WORKSPACE_ROOT +from metagpt.const import SYSTEM_DESIGN_FILE_REPO, TASK_FILE_REPO, WORKSPACE_ROOT +from metagpt.schema import Document, Documents from metagpt.utils.common import CodeParser from metagpt.utils.get_template import get_template from metagpt.utils.json_to_markdown import json_to_markdown @@ -178,13 +181,69 @@ class WriteTasks(Action): requirements_path = WORKSPACE_ROOT / ws_name / "requirements.txt" requirements_path.write_text("\n".join(rsp.instruct_content.dict().get("Required Python third-party packages"))) - async def run(self, context, format=CONFIG.prompt_format): + async def run(self, with_messages, format=CONFIG.prompt_format): + system_design_file_repo = CONFIG.git_repo.new_file_repository(SYSTEM_DESIGN_FILE_REPO) + changed_system_designs = system_design_file_repo.changed_files + + tasks_file_repo = CONFIG.git_repo.new_file_repository(TASK_FILE_REPO) + changed_tasks = tasks_file_repo.changed_files + change_files = Documents() + # 根据docs/system_designs/下的git head diff识别哪些task文档需要重写 + for filename in changed_system_designs: + system_design_doc = await system_design_file_repo.get(filename) + task_doc = await tasks_file_repo.get(filename) + if task_doc: + task_doc = await self._merge(system_design_doc, task_doc) + else: + rsp = await self._run(system_design_doc.content) + task_doc = Document(root_path=TASK_FILE_REPO, filename=filename, content=rsp.instruct_content.json()) + await tasks_file_repo.save( + filename=filename, content=task_doc.content, dependencies={system_design_doc.root_relative_path} + ) + await self._update_requirements(task_doc) + change_files.docs[filename] = task_doc + + # 根据docs/tasks/下的git head diff识别哪些task文件被用户修改了,需要重写 + for filename in changed_tasks: + if filename in change_files.docs: + continue + system_design_doc = await system_design_file_repo.get(filename) + task_doc = await tasks_file_repo.get(filename) + task_doc = await self._merge(system_design_doc, task_doc) + await tasks_file_repo.save( + filename=filename, content=task_doc.content, dependencies={system_design_doc.root_relative_path} + ) + await self._update_requirements(task_doc) + change_files.docs[filename] = task_doc + + # 等docs/tasks/下所有文件都处理完才发publish message,给后续做全局优化留空间。 + return ActionOutput(content=change_files.json(), instruct_content=change_files) + + async def _run(self, context, format=CONFIG.prompt_format): prompt_template, format_example = get_template(templates, format) prompt = prompt_template.format(context=context, format_example=format_example) rsp = await self._aask_v1(prompt, "task", OUTPUT_MAPPING, format=format) self._save(context, rsp) return rsp + async def _merge(self, system_design_doc, task_dock) -> Document: + return task_dock + + async def _update_requirements(self, doc): + m = json.loads(doc.content) + packages = set(m.get("Required Python third-party packages", set())) + file_repo = CONFIG.git_repo.new_file_repository() + filename = "requirements.txt" + requirement_doc = await file_repo.get(filename) + if not requirement_doc: + requirement_doc = Document(filename=filename, root_path=".", content="") + lines = requirement_doc.content.splitlines() + for pkg in lines: + if pkg == "": + continue + packages.add(pkg) + await file_repo.save(filename, content="\n".join(packages)) + class AssignTasks(Action): async def run(self, *args, **kwargs): diff --git a/metagpt/const.py b/metagpt/const.py index fc1c47b5b..63f39f4a8 100644 --- a/metagpt/const.py +++ b/metagpt/const.py @@ -53,4 +53,5 @@ MESSAGE_ROUTE_TO_ALL = "" REQUIREMENT_FILENAME = "requirement.txt" DOCS_FILE_REPO = "docs" PRDS_FILE_REPO = "docs/prds" -SYS_DESIGN_FILE_REPO = "docs/system_design" +SYSTEM_DESIGN_FILE_REPO = "docs/system_design" +TASK_FILE_REPO = "docs/tasks" diff --git a/metagpt/utils/file_repository.py b/metagpt/utils/file_repository.py index 7f07e4427..ee6811209 100644 --- a/metagpt/utils/file_repository.py +++ b/metagpt/utils/file_repository.py @@ -166,4 +166,4 @@ class FileRepository: """ current_time = datetime.now().strftime("%Y%m%d%H%M%S") guid_suffix = str(uuid.uuid4())[:8] - return f"{current_time}t{guid_suffix}" + return f"{current_time}x{guid_suffix}" diff --git a/metagpt/utils/git_repository.py b/metagpt/utils/git_repository.py index a81b5c4ea..2a4fb4a4d 100644 --- a/metagpt/utils/git_repository.py +++ b/metagpt/utils/git_repository.py @@ -17,6 +17,7 @@ from git.repo import Repo from git.repo.fun import is_git_dir from metagpt.const import WORKSPACE_ROOT +from metagpt.logs import logger from metagpt.utils.dependency_file import DependencyFile from metagpt.utils.file_repository import FileRepository @@ -170,6 +171,21 @@ class GitRepository: self._dependency = DependencyFile(workdir=self.workdir) return self._dependency + def rename_root(self, new_dir_name): + """Rename the root directory of the Git repository. + + :param new_dir_name: The new name for the root directory. + """ + if self.workdir.name == new_dir_name: + return + new_path = self.workdir.parent / new_dir_name + if new_path.exists(): + logger.info(f"Delete directory {str(new_path)}") + shutil.rmtree(new_path) + self.workdir.rename(new_path) + logger.info(f"Rename directory {str(self.workdir)} to {str(new_path)}") + self._repository = Repo(new_path) + if __name__ == "__main__": path = WORKSPACE_ROOT / "git"