diff --git a/metagpt/actions/action.py b/metagpt/actions/action.py index addc672bc..1b93213f7 100644 --- a/metagpt/actions/action.py +++ b/metagpt/actions/action.py @@ -15,6 +15,7 @@ from pydantic import BaseModel, ConfigDict, Field, model_validator from metagpt.actions.action_node import ActionNode from metagpt.context_mixin import ContextMixin from metagpt.schema import ( + CodePlanAndChangeContext, CodeSummarizeContext, CodingContext, RunCodeContext, @@ -28,7 +29,9 @@ class Action(SerializationMixin, ContextMixin, BaseModel): model_config = ConfigDict(arbitrary_types_allowed=True) name: str = "" - i_context: Union[dict, CodingContext, CodeSummarizeContext, TestingContext, RunCodeContext, str, None] = "" + i_context: Union[ + dict, CodingContext, CodeSummarizeContext, TestingContext, RunCodeContext, CodePlanAndChangeContext, str, None + ] = "" prefix: str = "" # aask*时会加上prefix,作为system_message desc: str = "" # for skill manager node: ActionNode = Field(default=None, exclude=True) diff --git a/metagpt/actions/write_code_plan_and_change_an.py b/metagpt/actions/write_code_plan_and_change_an.py index 188520ba8..3fac22242 100644 --- a/metagpt/actions/write_code_plan_and_change_an.py +++ b/metagpt/actions/write_code_plan_and_change_an.py @@ -118,8 +118,8 @@ CODE_PLAN_AND_CHANGE_CONTEXT = """ ## Design {design} -## Tasks -{tasks} +## Task +{task} ## Legacy Code {code} @@ -139,8 +139,8 @@ Role: You are a professional engineer; The main goal is to complete incremental ## Design {design} -## Tasks -{tasks} +## Task +{task} ## Legacy Code ```Code @@ -189,13 +189,16 @@ class WriteCodePlanAndChange(Action): async def run(self, *args, **kwargs): self.llm.system_prompt = "You are a professional software engineer, your primary responsibility is to " "meticulously craft comprehensive incremental development plan and deliver detailed incremental change" - requirement = self.i_context.requirement_doc.content - prd = "\n".join([doc.content for doc in self.i_context.prd_docs]) - design = "\n".join([doc.content for doc in self.i_context.design_docs]) - tasks = "\n".join([doc.content for doc in self.i_context.tasks_docs]) + prd_doc = await self.repo.docs.prd.get(filename=self.i_context.prd_filename) + 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) code_text = await self.get_old_codes() context = CODE_PLAN_AND_CHANGE_CONTEXT.format( - requirement=requirement, prd=prd, design=design, tasks=tasks, code=code_text + requirement=self.i_context.requirement, + prd=prd_doc.content, + design=design_doc.content, + task=task_doc.content, + code=code_text, ) return await WRITE_CODE_PLAN_AND_CHANGE_NODE.fill(context=context, llm=self.llm, schema="json") diff --git a/metagpt/actions/write_prd.py b/metagpt/actions/write_prd.py index 000c1731e..823786893 100644 --- a/metagpt/actions/write_prd.py +++ b/metagpt/actions/write_prd.py @@ -147,7 +147,7 @@ class WritePRD(Action): async def _update_prd(self, req: Document, prd_doc: Document) -> Document: new_prd_doc: Document = await self._merge(req, prd_doc) - self.repo.docs.prd.save_doc(doc=new_prd_doc) + await self.repo.docs.prd.save_doc(doc=new_prd_doc) await self._save_competitive_analysis(new_prd_doc) await self.repo.resources.prd.save_pdf(doc=new_prd_doc) return new_prd_doc diff --git a/metagpt/actions/write_prd_an.py b/metagpt/actions/write_prd_an.py index 4baa46b12..9898be55b 100644 --- a/metagpt/actions/write_prd_an.py +++ b/metagpt/actions/write_prd_an.py @@ -33,7 +33,7 @@ ORIGINAL_REQUIREMENTS = ActionNode( REFINED_REQUIREMENTS = ActionNode( key="Refined Requirements", expected_type=str, - instruction="Place the New user's requirements here.", + instruction="Place the New user's original requirements here.", example="Create a 2048 game with a new feature that ...", ) diff --git a/metagpt/roles/engineer.py b/metagpt/roles/engineer.py index 3cf52fc35..ae4f40ac7 100644 --- a/metagpt/roles/engineer.py +++ b/metagpt/roles/engineer.py @@ -210,18 +210,16 @@ class Engineer(Role): node = await self.rc.todo.run() code_plan_and_change = node.instruct_content.model_dump_json() dependencies = { - self.rc.todo.i_context.requirement_doc.filename, - self.rc.todo.i_context.prd_docs[0].filename, - self.rc.todo.i_context.design_docs[0].filename, - self.rc.todo.i_context.tasks_docs[0].filename, + REQUIREMENT_FILENAME, + self.rc.todo.i_context.prd_filename, + self.rc.todo.i_context.design_filename, + self.rc.todo.i_context.task_filename, } - - code_plan_and_change_filename = os.path.join(CODE_PLAN_AND_CHANGE_FILE_REPO, CODE_PLAN_AND_CHANGE_FILENAME) await self.project_repo.resources.code_plan_and_change.save( - filename=code_plan_and_change_filename, content=code_plan_and_change, dependencies=dependencies + filename=self.rc.todo.i_context.filename, content=code_plan_and_change, dependencies=dependencies ) await self.project_repo.docs.code_plan_and_change.save( - filename=Path(code_plan_and_change_filename).with_suffix(".md").name, + filename=Path(self.rc.todo.i_context.filename).with_suffix(".md").name, content=node.content, dependencies=dependencies, ) @@ -350,18 +348,10 @@ class Engineer(Role): async def _new_code_plan_and_change_action(self): """Create a WriteCodePlanAndChange action for subsequent to-do actions.""" - requirement_doc = await self.project_repo.docs.requirement.get(REQUIREMENT_FILENAME) - prd_docs = await self.project_repo.docs.prd.get_all() - design_docs = await self.project_repo.docs.system_design.get_all() - task_docs = await self.project_repo.docs.task.get_all() - - code_plan_and_change_context = CodePlanAndChangeContext( - requirement_doc=requirement_doc, - prd_docs=prd_docs, - design_docs=design_docs, - task_docs=task_docs, - ) - self.rc.todo = WriteCodePlanAndChange(i_context=code_plan_and_change_context, llm=self.llm) + files = self.project_repo.all_files + requirement = str(self.rc.memory.get_by_role("Human")[0]) + code_plan_and_change_ctx = CodePlanAndChangeContext.loads(files, requirement=requirement) + self.rc.todo = WriteCodePlanAndChange(i_context=code_plan_and_change_ctx, context=self.context, llm=self.llm) @property def action_description(self) -> str: diff --git a/metagpt/schema.py b/metagpt/schema.py index 88e1712fc..ee194afbd 100644 --- a/metagpt/schema.py +++ b/metagpt/schema.py @@ -37,10 +37,12 @@ from pydantic import ( ) from metagpt.const import ( + CODE_PLAN_AND_CHANGE_FILENAME, MESSAGE_ROUTE_CAUSE_BY, MESSAGE_ROUTE_FROM, MESSAGE_ROUTE_TO, MESSAGE_ROUTE_TO_ALL, + PRDS_FILE_REPO, SYSTEM_DESIGN_FILE_REPO, TASK_FILE_REPO, ) @@ -470,12 +472,28 @@ class BugFixContext(BaseContext): filename: str = "" -class CodePlanAndChangeContext(BaseContext): - filename: str = "" - requirement_doc: Document - prd_docs: List[Document] - design_docs: List[Document] - task_docs: List[Document] +class CodePlanAndChangeContext(BaseModel): + filename: str = CODE_PLAN_AND_CHANGE_FILENAME + requirement: str = "" + prd_filename: str = "" + design_filename: str = "" + task_filename: str = "" + + @staticmethod + def loads(filenames: List, **kwargs) -> CodePlanAndChangeContext: + ctx = CodePlanAndChangeContext(requirement=kwargs.get("requirement", "")) + for filename in filenames: + filename = Path(filename) + if filename.is_relative_to(PRDS_FILE_REPO): + ctx.prd_filename = filename.name + continue + if filename.is_relative_to(SYSTEM_DESIGN_FILE_REPO): + ctx.design_filename = filename.name + continue + if filename.is_relative_to(TASK_FILE_REPO): + ctx.task_filename = filename.name + continue + return ctx # mermaid class view