mirror of
https://github.com/FoundationAgents/MetaGPT.git
synced 2026-06-08 15:05:17 +02:00
update write_code_plan_and_change_an.py and add it to _think and _act process
This commit is contained in:
parent
95ccd980f8
commit
1959743d0b
5 changed files with 101 additions and 56 deletions
|
|
@ -5,9 +5,14 @@
|
|||
@Author : mannaandpoem
|
||||
@File : write_code_plan_and_change_an.py
|
||||
"""
|
||||
import os
|
||||
|
||||
from pydantic import Field
|
||||
|
||||
from metagpt.actions.action import Action
|
||||
from metagpt.actions.action_node import ActionNode
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.schema import CodePlanAndChangeContext
|
||||
|
||||
CODE_PLAN_AND_CHANGE = ActionNode(
|
||||
key="Code Plan And Change",
|
||||
|
|
@ -106,10 +111,10 @@ def add_numbers():
|
|||
|
||||
CODE_PLAN_AND_CHANGE_CONTEXT = """
|
||||
## User New Requirements
|
||||
{user_requirement}
|
||||
{requirement}
|
||||
|
||||
## Product Requirement Pool
|
||||
{product_requirement_pools}
|
||||
## PRD
|
||||
{prd}
|
||||
|
||||
## Design
|
||||
{design}
|
||||
|
|
@ -179,7 +184,26 @@ WRITE_CODE_PLAN_AND_CHANGE_NODE = ActionNode.from_children("WriteCodePlanAndChan
|
|||
|
||||
|
||||
class WriteCodePlanAndChange(Action):
|
||||
async def run(self, context):
|
||||
name: str = "WriteCodePlanAndChange"
|
||||
context: CodePlanAndChangeContext = Field(default_factory=CodePlanAndChangeContext)
|
||||
|
||||
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.context.requirement_doc.content
|
||||
prd = "\n".join([doc.content for doc in self.context.prd_docs])
|
||||
design = "\n".join([doc.content for doc in self.context.design_docs])
|
||||
tasks = "\n".join([doc.content for doc in self.context.task_docs])
|
||||
code_text = self.get_old_codes()
|
||||
context = CODE_PLAN_AND_CHANGE_CONTEXT.format(
|
||||
requirement=requirement, prd=prd, design=design, tasks=tasks, code=code_text
|
||||
)
|
||||
return await WRITE_CODE_PLAN_AND_CHANGE_NODE.fill(context=context, llm=self.llm, schema="json")
|
||||
|
||||
@staticmethod
|
||||
async def get_old_codes() -> str:
|
||||
CONFIG.old_workspace = CONFIG.git_repo.workdir / os.path.basename(CONFIG.project_path)
|
||||
old_file_repo = CONFIG.git_repo.new_file_repository(relative_path=CONFIG.old_workspace)
|
||||
old_codes = await old_file_repo.get_all()
|
||||
codes = [f"----- {code.filename}\n```{code.content}```" for code in old_codes]
|
||||
return "\n".join(codes)
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ SEQ_FLOW_FILE_REPO = "resources/seq_flow"
|
|||
SYSTEM_DESIGN_PDF_FILE_REPO = "resources/system_design"
|
||||
PRD_PDF_FILE_REPO = "resources/prd"
|
||||
TASK_PDF_FILE_REPO = "resources/api_spec_and_tasks"
|
||||
CODE_PLAN_AND_CHANGE_PDF_FILE_REPO = "resources/code_plan_and_change"
|
||||
TEST_CODES_FILE_REPO = "tests"
|
||||
TEST_OUTPUTS_FILE_REPO = "test_outputs"
|
||||
CODE_SUMMARIES_FILE_REPO = "docs/code_summaries"
|
||||
|
|
|
|||
|
|
@ -29,24 +29,24 @@ from metagpt.actions import Action, WriteCode, WriteCodeReview, WriteTasks
|
|||
from metagpt.actions.fix_bug import FixBug
|
||||
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 (
|
||||
CODE_PLAN_AND_CHANGE_CONTEXT,
|
||||
WriteCodePlanAndChange,
|
||||
)
|
||||
from metagpt.actions.write_prd_an import REFINED_REQUIREMENT_POOL, REQUIREMENT_POOL
|
||||
from metagpt.actions.write_code_plan_and_change_an import WriteCodePlanAndChange
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.const import (
|
||||
CODE_PLAN_AND_CHANGE_FILE_REPO,
|
||||
CODE_PLAN_AND_CHANGE_FILENAME,
|
||||
CODE_PLAN_AND_CHANGE_PDF_FILE_REPO,
|
||||
CODE_SUMMARIES_FILE_REPO,
|
||||
CODE_SUMMARIES_PDF_FILE_REPO,
|
||||
DOCS_FILE_REPO,
|
||||
PRDS_FILE_REPO,
|
||||
REQUIREMENT_FILENAME,
|
||||
SYSTEM_DESIGN_FILE_REPO,
|
||||
TASK_FILE_REPO,
|
||||
)
|
||||
from metagpt.logs import logger
|
||||
from metagpt.roles import Role
|
||||
from metagpt.schema import (
|
||||
CodePlanAndChangeContext,
|
||||
CodeSummarizeContext,
|
||||
CodingContext,
|
||||
Document,
|
||||
|
|
@ -149,6 +149,9 @@ class Engineer(Role):
|
|||
"""Determines the mode of action based on whether code review is used."""
|
||||
if self.rc.todo is None:
|
||||
return None
|
||||
if isinstance(self.rc.todo, WriteCodePlanAndChange):
|
||||
self.next_todo_action = any_to_name(WriteCode)
|
||||
return await self._act_code_plan_and_change()
|
||||
if isinstance(self.rc.todo, WriteCode):
|
||||
self.next_todo_action = any_to_name(SummarizeCode)
|
||||
return await self._act_write_code()
|
||||
|
|
@ -212,6 +215,40 @@ class Engineer(Role):
|
|||
content=json.dumps(tasks), role=self.profile, cause_by=SummarizeCode, send_to=self, sent_from=self
|
||||
)
|
||||
|
||||
async def _act_code_plan_and_change(self):
|
||||
"""Write code plan and change that guides subsequent WriteCode and WriteCodeReview"""
|
||||
logger.info("Writing code plan and change..")
|
||||
code_plan_and_change_file_repo = CONFIG.git_repo.new_file_repository(CODE_PLAN_AND_CHANGE_FILE_REPO)
|
||||
code_plan_and_change_pdf_file_repo = CONFIG.git_repo.new_file_repository(CODE_PLAN_AND_CHANGE_PDF_FILE_REPO)
|
||||
|
||||
node = await self.rc.todo.run()
|
||||
code_plan_and_change = node.instruct_content.model_dump_json()
|
||||
|
||||
dependencies = {
|
||||
self.rc.todo.context.requirement_filename,
|
||||
self.rc.todo.context.prd_filename,
|
||||
self.rc.todo.context.design_filename,
|
||||
self.rc.todo.context.task_filename,
|
||||
}
|
||||
|
||||
code_plan_and_change_filename = os.path.join(CODE_PLAN_AND_CHANGE_FILE_REPO, CODE_PLAN_AND_CHANGE_FILENAME)
|
||||
await code_plan_and_change_file_repo.save(
|
||||
filename=code_plan_and_change_filename, content=code_plan_and_change, dependencies=dependencies
|
||||
)
|
||||
await code_plan_and_change_pdf_file_repo.save(
|
||||
filename=Path(code_plan_and_change_filename).with_suffix(".md").name,
|
||||
content=node.content,
|
||||
dependencies=dependencies,
|
||||
)
|
||||
|
||||
return Message(
|
||||
content=code_plan_and_change,
|
||||
role=self.profile,
|
||||
cause_by=WriteCodePlanAndChange,
|
||||
send_to=self,
|
||||
sent_from=self,
|
||||
)
|
||||
|
||||
async def _is_pass(self, summary) -> (str, str):
|
||||
rsp = await self.llm.aask(msg=IS_PASS_PROMPT.format(context=summary), stream=False)
|
||||
logger.info(rsp)
|
||||
|
|
@ -222,11 +259,16 @@ class Engineer(Role):
|
|||
async def _think(self) -> Action | None:
|
||||
if not CONFIG.src_workspace:
|
||||
CONFIG.src_workspace = CONFIG.git_repo.workdir / CONFIG.git_repo.workdir.name
|
||||
write_code_filters = any_to_str_set([WriteTasks, SummarizeCode, FixBug])
|
||||
write_plan_and_change_filters = any_to_str_set([WriteTasks])
|
||||
write_code_filters = any_to_str_set([WriteTasks, WriteCodePlanAndChange, SummarizeCode, FixBug])
|
||||
summarize_code_filters = any_to_str_set([WriteCode, WriteCodeReview])
|
||||
if not self.rc.news:
|
||||
return None
|
||||
msg = self.rc.news[0]
|
||||
if 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()
|
||||
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))
|
||||
|
|
@ -332,50 +374,21 @@ class Engineer(Role):
|
|||
if self.summarize_todos:
|
||||
self.rc.todo = self.summarize_todos[0]
|
||||
|
||||
async def _new_code_plan_and_change_action(self):
|
||||
"""Create a WriteCodePlanAndChange action for subsequent to-do actions."""
|
||||
requirement_doc = await FileRepository.get_file(filename=REQUIREMENT_FILENAME, relative_path=DOCS_FILE_REPO)
|
||||
prd_docs = await FileRepository.get_all_files(relative_path=PRDS_FILE_REPO)
|
||||
design_docs = await FileRepository.get_all_files(relative_path=SYSTEM_DESIGN_FILE_REPO)
|
||||
tasks_docs = await FileRepository.get_all_files(relative_path=TASK_FILE_REPO)
|
||||
code_plan_and_change_context = CodePlanAndChangeContext(
|
||||
requirement_doc=requirement_doc,
|
||||
prd_docs=prd_docs,
|
||||
design_docs=design_docs,
|
||||
tasks_docs=tasks_docs,
|
||||
)
|
||||
self.rc.todo = WriteCodePlanAndChange(context=code_plan_and_change_context, llm=self.llm)
|
||||
|
||||
@property
|
||||
def todo(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 _write_code_plan_and_change(self):
|
||||
"""Write code plan and change that guides subsequent WriteCode and WriteCodeReview"""
|
||||
logger.info("Writing code plan and change..")
|
||||
|
||||
user_requirement = str(self.rc.memory.get_by_role("Human")[0])
|
||||
pool_contents = []
|
||||
prd = await FileRepository.get_all_files(relative_path=PRDS_FILE_REPO)
|
||||
for doc in prd:
|
||||
prd_json = json.loads(doc.content)
|
||||
product_requirement_pool = prd_json.get(REFINED_REQUIREMENT_POOL.key) or prd_json.get(REQUIREMENT_POOL.key)
|
||||
pool_contents.append(str(product_requirement_pool))
|
||||
|
||||
product_requirement_pools = "\n".join(pool_contents)
|
||||
|
||||
design = await FileRepository.get_all_files(relative_path=SYSTEM_DESIGN_FILE_REPO)
|
||||
design = "\n".join([doc.content for doc in design])
|
||||
|
||||
tasks = await FileRepository.get_all_files(relative_path=TASK_FILE_REPO)
|
||||
tasks = "\n".join([doc.content for doc in tasks])
|
||||
|
||||
old_codes = await self.get_old_codes()
|
||||
|
||||
context = CODE_PLAN_AND_CHANGE_CONTEXT.format(
|
||||
user_requirement=user_requirement,
|
||||
product_requirement_pools=product_requirement_pools,
|
||||
tasks=tasks,
|
||||
design=design,
|
||||
code=old_codes,
|
||||
)
|
||||
node = await WriteCodePlanAndChange().run(context=context)
|
||||
code_plan_and_change = node.instruct_content.model_dump_json()
|
||||
CONFIG.git_repo.new_file_repository(CODE_PLAN_AND_CHANGE_FILE_REPO).save(
|
||||
filename=CODE_PLAN_AND_CHANGE_FILENAME, content=code_plan_and_change
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
async def get_old_codes() -> str:
|
||||
CONFIG.old_workspace = CONFIG.git_repo.workdir / os.path.basename(CONFIG.project_path)
|
||||
old_file_repo = CONFIG.git_repo.new_file_repository(relative_path=CONFIG.old_workspace)
|
||||
old_codes = await old_file_repo.get_all()
|
||||
codes = [f"----- {code.filename}\n```{code.content}```" for code in old_codes]
|
||||
return "\n".join(codes)
|
||||
|
|
|
|||
|
|
@ -451,3 +451,11 @@ class CodeSummarizeContext(BaseModel):
|
|||
|
||||
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]
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ from metagpt.actions.write_code_plan_and_change_an import (
|
|||
REFINED_TEMPLATE,
|
||||
WriteCodePlanAndChange,
|
||||
)
|
||||
from metagpt.actions.write_prd_an import REQUIREMENT_POOL
|
||||
from tests.data.incremental_dev_project.mock import (
|
||||
CODE_PLAN_AND_CHANGE_SAMPLE,
|
||||
DESIGN_SAMPLE,
|
||||
|
|
@ -45,8 +44,8 @@ async def test_write_code_plan_an(mocker):
|
|||
|
||||
write_code_plan = WriteCodePlanAndChange()
|
||||
context = CODE_PLAN_AND_CHANGE_CONTEXT.format(
|
||||
user_requirement=NEW_REQUIREMENT_SAMPLE,
|
||||
product_requirement_pools=REFINED_PRD_JSON.get(REQUIREMENT_POOL.key),
|
||||
requirement=NEW_REQUIREMENT_SAMPLE,
|
||||
PRD=REFINED_PRD_JSON,
|
||||
design=REFINED_DESIGN_JSON,
|
||||
tasks=REFINED_TASKS_JSON,
|
||||
code=OLD_CODE_SAMPLE,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue