From a896351ed81655f7becb0d43612ddf4de71f5315 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 25 Mar 2024 17:09:02 +0800 Subject: [PATCH] fixbug: #1095 --- .../actions/write_code_plan_and_change_an.py | 6 ++- metagpt/actions/write_prd_an.py | 4 +- metagpt/roles/engineer.py | 37 ++++++++++++++----- metagpt/schema.py | 3 +- 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/metagpt/actions/write_code_plan_and_change_an.py b/metagpt/actions/write_code_plan_and_change_an.py index f99bffd84..a90946981 100644 --- a/metagpt/actions/write_code_plan_and_change_an.py +++ b/metagpt/actions/write_code_plan_and_change_an.py @@ -128,6 +128,9 @@ CODE_PLAN_AND_CHANGE_CONTEXT = """ ## User New Requirements {requirement} +## Issue +{issue} + ## PRD {prd} @@ -211,7 +214,8 @@ class WriteCodePlanAndChange(Action): design_doc = await self.repo.docs.system_design.get(filename=self.i_context.design_filename) task_doc = await self.repo.docs.task.get(filename=self.i_context.task_filename) context = CODE_PLAN_AND_CHANGE_CONTEXT.format( - requirement=self.i_context.requirement, + requirement=f"```text\n{self.i_context.requirement}\n```", + issue=f"```text\n{self.i_context.issue}\n```", prd=prd_doc.content, design=design_doc.content, task=task_doc.content, diff --git a/metagpt/actions/write_prd_an.py b/metagpt/actions/write_prd_an.py index 5733b29da..6a995e184 100644 --- a/metagpt/actions/write_prd_an.py +++ b/metagpt/actions/write_prd_an.py @@ -133,10 +133,10 @@ REQUIREMENT_ANALYSIS = ActionNode( REFINED_REQUIREMENT_ANALYSIS = ActionNode( key="Refined Requirement Analysis", expected_type=List[str], - instruction="Review and refine the existing requirement analysis to align with the evolving needs of the project " + instruction="Review and refine the existing requirement analysis into a string list to align with the evolving needs of the project " "due to incremental development. Ensure the analysis comprehensively covers the new features and enhancements " "required for the refined project scope.", - example=["Require add/update/modify ..."], + example=["Require add ...", "Require modify ..."], ) REQUIREMENT_POOL = ActionNode( diff --git a/metagpt/roles/engineer.py b/metagpt/roles/engineer.py index 9d8f6884f..41735023a 100644 --- a/metagpt/roles/engineer.py +++ b/metagpt/roles/engineer.py @@ -22,7 +22,7 @@ from __future__ import annotations import json from collections import defaultdict from pathlib import Path -from typing import Set +from typing import Optional, Set from metagpt.actions import Action, WriteCode, WriteCodeReview, WriteTasks from metagpt.actions.fix_bug import FixBug @@ -30,6 +30,7 @@ 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_and_change_an import WriteCodePlanAndChange from metagpt.const import ( + BUGFIX_FILENAME, CODE_PLAN_AND_CHANGE_FILE_REPO, REQUIREMENT_FILENAME, SYSTEM_DESIGN_FILE_REPO, @@ -248,11 +249,11 @@ class Engineer(Role): msg = self.rc.news[0] if self.config.inc and msg.cause_by in write_plan_and_change_filters: logger.debug(f"TODO WriteCodePlanAndChange:{msg.model_dump_json()}") - await self._new_code_plan_and_change_action() + await self._new_code_plan_and_change_action(cause_by=msg.cause_by) return self.rc.todo if msg.cause_by in write_code_filters: logger.debug(f"TODO WriteCode:{msg.model_dump_json()}") - await self._new_code_actions(bug_fix=msg.cause_by == any_to_str(FixBug)) + await self._new_code_actions() return self.rc.todo if msg.cause_by in summarize_code_filters and msg.sent_from == any_to_str(self): logger.debug(f"TODO SummarizeCode:{msg.model_dump_json()}") @@ -267,7 +268,7 @@ class Engineer(Role): dependencies = {Path(i) for i in await dependency.get(old_code_doc.root_relative_path)} task_doc = None design_doc = None - code_plan_and_change_doc = None + code_plan_and_change_doc = await self._get_any_code_plan_and_change() if await self._is_fixbug() else None for i in dependencies: if str(i.parent) == TASK_FILE_REPO: task_doc = await self.project_repo.docs.task.get(i.name) @@ -294,7 +295,8 @@ class Engineer(Role): ) return coding_doc - async def _new_code_actions(self, bug_fix=False): + async def _new_code_actions(self): + bug_fix = await self._is_fixbug() # Prepare file repos changed_src_files = self.project_repo.srcs.all_files if bug_fix else self.project_repo.srcs.changed_files changed_task_files = self.project_repo.docs.task.changed_files @@ -371,15 +373,32 @@ class Engineer(Role): self.set_todo(self.summarize_todos[0]) self.summarize_todos.pop(0) - async def _new_code_plan_and_change_action(self): + async def _new_code_plan_and_change_action(self, cause_by: str): """Create a WriteCodePlanAndChange action for subsequent to-do actions.""" files = self.project_repo.all_files - requirement_doc = await self.project_repo.docs.get(REQUIREMENT_FILENAME) - requirement = requirement_doc.content if requirement_doc else "" - code_plan_and_change_ctx = CodePlanAndChangeContext.loads(files, requirement=requirement) + options = {} + if cause_by != any_to_str(FixBug): + requirement_doc = await self.project_repo.docs.get(REQUIREMENT_FILENAME) + options["requirement"] = requirement_doc.content + else: + fixbug_doc = await self.project_repo.docs.get(BUGFIX_FILENAME) + options["issue"] = fixbug_doc.content + code_plan_and_change_ctx = CodePlanAndChangeContext.loads(files, **options) self.rc.todo = WriteCodePlanAndChange(i_context=code_plan_and_change_ctx, context=self.context, llm=self.llm) @property def action_description(self) -> str: """AgentStore uses this attribute to display to the user what actions the current role should take.""" return self.next_todo_action + + async def _is_fixbug(self) -> bool: + fixbug_doc = await self.project_repo.docs.get(BUGFIX_FILENAME) + return bool(fixbug_doc and fixbug_doc.content) + + async def _get_any_code_plan_and_change(self) -> Optional[Document]: + changed_files = self.project_repo.docs.code_plan_and_change.changed_files + for filename in changed_files.keys(): + doc = await self.project_repo.docs.code_plan_and_change.get(filename) + if doc and doc.content: + return doc + return None diff --git a/metagpt/schema.py b/metagpt/schema.py index 45c7480f9..071518d62 100644 --- a/metagpt/schema.py +++ b/metagpt/schema.py @@ -677,13 +677,14 @@ class BugFixContext(BaseContext): class CodePlanAndChangeContext(BaseModel): requirement: str = "" + issue: str = "" prd_filename: str = "" design_filename: str = "" task_filename: str = "" @staticmethod def loads(filenames: List, **kwargs) -> CodePlanAndChangeContext: - ctx = CodePlanAndChangeContext(requirement=kwargs.get("requirement", "")) + ctx = CodePlanAndChangeContext(requirement=kwargs.get("requirement", ""), issue=kwargs.get("issue", "")) for filename in filenames: filename = Path(filename) if filename.is_relative_to(PRDS_FILE_REPO):