mirror of
https://github.com/FoundationAgents/MetaGPT.git
synced 2026-05-06 06:12:39 +02:00
feat: resolve conflicts
This commit is contained in:
parent
ad0ac94093
commit
b97ca3af7e
12 changed files with 120 additions and 90 deletions
|
|
@ -44,6 +44,7 @@ class Action(ABC):
|
|||
self.prefix = prefix
|
||||
self.profile = profile
|
||||
self.llm.system_prompt = prefix
|
||||
return self
|
||||
|
||||
def __str__(self):
|
||||
return self.__class__.__name__
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ class ActionNode:
|
|||
)
|
||||
return prompt
|
||||
|
||||
@retry(wait=wait_random_exponential(min=1, max=60), stop=stop_after_attempt(6))
|
||||
@retry(wait=wait_random_exponential(min=1, max=10), stop=stop_after_attempt(6))
|
||||
async def _aask_v1(
|
||||
self,
|
||||
prompt: str,
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ class WriteTasks(Action):
|
|||
async def _merge(self, system_design_doc, task_doc, format=CONFIG.prompt_format) -> Document:
|
||||
context = NEW_REQ_TEMPLATE.format(context=system_design_doc.content, old_tasks=task_doc.content)
|
||||
node = await PM_NODE.fill(context, self.llm, format)
|
||||
task_doc.content = node.content
|
||||
task_doc.content = node.instruct_content.json(ensure_ascii=False)
|
||||
return task_doc
|
||||
|
||||
@staticmethod
|
||||
|
|
|
|||
|
|
@ -34,59 +34,52 @@ from metagpt.utils.file_repository import FileRepository
|
|||
|
||||
PROMPT_TEMPLATE = """
|
||||
NOTICE
|
||||
Role: You are a professional engineer; the main goal is to write PEP8 compliant, elegant, modular, easy to read and maintain Python 3.9 code (but you can also use other programming language)
|
||||
Role: You are a professional engineer; the main goal is to write google-style, elegant, modular, easy to read and maintain code
|
||||
Language: Please use the same language as the user requirement, but the title and code should be still in English. For example, if the user speaks Chinese, the specific text of your answer should also be in Chinese.
|
||||
ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenced "Format example".
|
||||
|
||||
-----
|
||||
# Design
|
||||
```json
|
||||
# Context
|
||||
## Design
|
||||
{design}
|
||||
```
|
||||
-----
|
||||
# Tasks
|
||||
```json
|
||||
|
||||
## Tasks
|
||||
{tasks}
|
||||
```
|
||||
-----
|
||||
# Legacy Code
|
||||
```python
|
||||
|
||||
## Legacy Code
|
||||
```Code
|
||||
{code}
|
||||
```
|
||||
-----
|
||||
# Debug logs
|
||||
|
||||
## Debug logs
|
||||
```text
|
||||
{logs}
|
||||
|
||||
{summary_log}
|
||||
```
|
||||
-----
|
||||
# Bug Feedback logs
|
||||
|
||||
## Bug Feedback logs
|
||||
```text
|
||||
{feedback}
|
||||
```
|
||||
-----
|
||||
|
||||
|
||||
## Code: {filename} Write code with triple quoto, based on the following list and context.
|
||||
1. Do your best to implement THIS ONLY ONE FILE. ONLY USE EXISTING API. IF NO API, IMPLEMENT IT.
|
||||
2. Requirement: Based on the context, implement one following code file, note to return only in code form, your code will be part of the entire project, so please implement complete, reliable, reusable code snippets
|
||||
3. Set default value: If there is any setting, ALWAYS SET A DEFAULT VALUE, ALWAYS USE STRONG TYPE AND EXPLICIT VARIABLE.
|
||||
4. Follow design: YOU MUST FOLLOW "Data structures and interfaces". DONT CHANGE ANY DESIGN.
|
||||
5. Think before writing: What should be implemented and provided in this document?
|
||||
6. CAREFULLY CHECK THAT YOU DONT MISS ANY NECESSARY CLASS/FUNCTION IN THIS FILE.
|
||||
7. Do not use public member functions that do not exist in your design.
|
||||
8. Before using a variable, make sure you reference it first
|
||||
9. Write out EVERY DETAIL, DON'T LEAVE TODO.
|
||||
|
||||
## Format example
|
||||
-----
|
||||
# Format example
|
||||
## Code: {filename}
|
||||
```python
|
||||
## {filename}
|
||||
...
|
||||
```
|
||||
-----
|
||||
|
||||
# Instruction: Based on the context, follow "Format example", write code.
|
||||
|
||||
## Code: {filename}. Write code with triple quoto, based on the following attentions and context.
|
||||
1. Only One file: do your best to implement THIS ONLY ONE FILE.
|
||||
2. COMPLETE CODE: Your code will be part of the entire project, so please implement complete, reliable, reusable code snippets.
|
||||
3. Set default value: If there is any setting, ALWAYS SET A DEFAULT VALUE, ALWAYS USE STRONG TYPE AND EXPLICIT VARIABLE. AVOID circular import.
|
||||
4. Follow design: YOU MUST FOLLOW "Data structures and interfaces". DONT CHANGE ANY DESIGN. Do not use public member functions that do not exist in your design.
|
||||
5. CAREFULLY CHECK THAT YOU DONT MISS ANY NECESSARY CLASS/FUNCTION IN THIS FILE.
|
||||
6. Before using a external variable/module, make sure you import it first.
|
||||
7. Write out EVERY CODE DETAIL, DON'T LEAVE TODO.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
|
|
@ -107,7 +100,7 @@ class WriteCode(Action):
|
|||
filename="test_" + coding_context.filename + ".json", relative_path=TEST_OUTPUTS_FILE_REPO
|
||||
)
|
||||
summary_doc = None
|
||||
if coding_context.design_doc.filename:
|
||||
if coding_context.design_doc and coding_context.design_doc.filename:
|
||||
summary_doc = await FileRepository.get_file(
|
||||
filename=coding_context.design_doc.filename, relative_path=CODE_SUMMARIES_FILE_REPO
|
||||
)
|
||||
|
|
@ -115,9 +108,14 @@ class WriteCode(Action):
|
|||
if test_doc:
|
||||
test_detail = RunCodeResult.loads(test_doc.content)
|
||||
logs = test_detail.stderr
|
||||
code_context = await self.get_codes(coding_context.task_doc, exclude=self.context.filename)
|
||||
|
||||
if bug_feedback:
|
||||
code_context = coding_context.code_doc.content
|
||||
else:
|
||||
code_context = await self.get_codes(coding_context.task_doc, exclude=self.context.filename)
|
||||
|
||||
prompt = PROMPT_TEMPLATE.format(
|
||||
design=coding_context.design_doc.content,
|
||||
design=coding_context.design_doc.content if coding_context.design_doc else "",
|
||||
tasks=coding_context.task_doc.content if coding_context.task_doc else "",
|
||||
code=code_context,
|
||||
logs=logs,
|
||||
|
|
@ -148,5 +146,5 @@ class WriteCode(Action):
|
|||
doc = await src_file_repo.get(filename=filename)
|
||||
if not doc:
|
||||
continue
|
||||
codes.append(doc.content)
|
||||
return "\n----------\n".join(codes)
|
||||
codes.append(f"----- {filename}\n" + doc.content)
|
||||
return "\n".join(codes)
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ from metagpt.schema import CodingContext
|
|||
from metagpt.utils.common import CodeParser
|
||||
|
||||
PROMPT_TEMPLATE = """
|
||||
NOTICE
|
||||
Role: You are a professional software engineer, and your main task is to review the code. You need to ensure that the code conforms to the PEP8 standards, is elegantly designed and modularized, easy to read and maintain, and is written in Python 3.9 (or in another programming language).
|
||||
# System
|
||||
Role: You are a professional software engineer, and your main task is to review and revise the code. You need to ensure that the code conforms to the google-style standards, is elegantly designed and modularized, easy to read and maintain.
|
||||
Language: Please use the same language as the user requirement, but the title and code should be still in English. For example, if the user speaks Chinese, the specific text of your answer should also be in Chinese.
|
||||
ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenced "Format example".
|
||||
|
||||
|
|
@ -27,53 +27,52 @@ ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenc
|
|||
{context}
|
||||
|
||||
## Code to be Reviewed: {filename}
|
||||
```
|
||||
```Code
|
||||
{code}
|
||||
```
|
||||
"""
|
||||
|
||||
-----
|
||||
|
||||
## Code Review: Based on the "Code to be Reviewed", provide key, clear, concise, and specific code modification suggestions, up to 5.
|
||||
EXAMPLE_AND_INSTRUCTION = """
|
||||
|
||||
{format_example}
|
||||
|
||||
|
||||
# Instruction: Based on the actual code situation, follow one of the "Format example".
|
||||
|
||||
## Code Review: Ordered List. Based on the "Code to be Reviewed", provide key, clear, concise, and specific answer. If any answer is no, explain how to fix it step by step.
|
||||
1. Is the code implemented as per the requirements? If not, how to achieve it? Analyse it step by step.
|
||||
2. Is the code logic completely correct? If there are errors, please indicate how to correct them.
|
||||
3. Does the existing code follow the "Data structures and interfaces"?
|
||||
4. Are all functions implemented? If there is no implementation, please indicate how to achieve it step by step.
|
||||
5. Have all necessary pre-dependencies been imported? If not, indicate which ones need to be imported
|
||||
6. Is the code implemented concisely enough? Are methods from other files being reused correctly?
|
||||
6. Are methods from other files being reused correctly?
|
||||
|
||||
## Code Review Result: If the code doesn't have bugs, we don't need to rewrite it, so answer LGTM and stop. ONLY ANSWER LGTM/LBTM.
|
||||
## Actions: Ordered List. Things that should be done after CR, such as implementing class A and function B
|
||||
|
||||
## Code Review Result: str. If the code doesn't have bugs, we don't need to rewrite it, so answer LGTM and stop. ONLY ANSWER LGTM/LBTM.
|
||||
LGTM/LBTM
|
||||
|
||||
## Rewrite Code: if it still has some bugs, rewrite {filename} based on "Code Review" with triple quotes, try to get LGTM. Do your utmost to optimize THIS SINGLE FILE. Implement ALL TODO. RETURN ALL CODE, NEVER OMIT ANYTHING. 以任何方式省略代码都是不允许的。
|
||||
```
|
||||
```
|
||||
|
||||
## Format example
|
||||
{format_example}
|
||||
|
||||
"""
|
||||
|
||||
FORMAT_EXAMPLE = """
|
||||
-----
|
||||
# EXAMPLE 1
|
||||
# Format example 1
|
||||
## Code Review: {filename}
|
||||
1. No, we should add the logic of ...
|
||||
1. No, we should fix the logic of class A due to ...
|
||||
2. ...
|
||||
3. ...
|
||||
4. ...
|
||||
4. No, function B is not implemented, ...
|
||||
5. ...
|
||||
6. ...
|
||||
|
||||
## Code Review Result: {filename}
|
||||
## Actions
|
||||
1. fix class A
|
||||
2. implement function B
|
||||
|
||||
## Code Review Result
|
||||
LBTM
|
||||
|
||||
## Rewrite Code: {filename}
|
||||
```python
|
||||
## {filename}
|
||||
...
|
||||
```
|
||||
-----
|
||||
# EXAMPLE 2
|
||||
# Format example 2
|
||||
## Code Review: {filename}
|
||||
1. Yes.
|
||||
2. Yes.
|
||||
|
|
@ -82,12 +81,20 @@ LBTM
|
|||
5. Yes.
|
||||
6. Yes.
|
||||
|
||||
## Code Review Result: {filename}
|
||||
LGTM
|
||||
|
||||
## Rewrite Code: {filename}
|
||||
## Actions
|
||||
pass
|
||||
-----
|
||||
|
||||
## Code Review Result
|
||||
LGTM
|
||||
"""
|
||||
|
||||
REWRITE_CODE_TEMPLATE = """
|
||||
# Instruction: rewrite code based on the Code Review and Actions
|
||||
## Rewrite Code: CodeBlock. If it still has some bugs, rewrite {filename} with triple quotes. Do your utmost to optimize THIS SINGLE FILE. Return all completed codes and prohibit the return of unfinished codes.
|
||||
```Code
|
||||
## {filename}
|
||||
...
|
||||
```
|
||||
"""
|
||||
|
||||
|
||||
|
|
@ -96,11 +103,15 @@ class WriteCodeReview(Action):
|
|||
super().__init__(name, context, llm)
|
||||
|
||||
@retry(wait=wait_random_exponential(min=1, max=60), stop=stop_after_attempt(6))
|
||||
async def write_code_review_and_rewrite(self, prompt):
|
||||
code_rsp = await self._aask(prompt)
|
||||
result = CodeParser.parse_block("Code Review Result", code_rsp)
|
||||
async def write_code_review_and_rewrite(self, context_prompt, cr_prompt, filename):
|
||||
cr_rsp = await self._aask(context_prompt + cr_prompt)
|
||||
result = CodeParser.parse_block("Code Review Result", cr_rsp)
|
||||
if "LGTM" in result:
|
||||
return result, None
|
||||
|
||||
# if LBTM, rewrite code
|
||||
rewrite_prompt = f"{context_prompt}\n{cr_rsp}\n{REWRITE_CODE_TEMPLATE.format(filename=filename)}"
|
||||
code_rsp = await self._aask(rewrite_prompt)
|
||||
code = CodeParser.parse_code(block="", text=code_rsp)
|
||||
return result, code
|
||||
|
||||
|
|
@ -111,23 +122,23 @@ class WriteCodeReview(Action):
|
|||
format_example = FORMAT_EXAMPLE.format(filename=self.context.code_doc.filename)
|
||||
task_content = self.context.task_doc.content if self.context.task_doc else ""
|
||||
code_context = await WriteCode.get_codes(self.context.task_doc, exclude=self.context.filename)
|
||||
context = "\n----------\n".join(
|
||||
context = "\n".join(
|
||||
[
|
||||
"```text\n" + self.context.design_doc.content + "```\n",
|
||||
"```text\n" + task_content + "```\n",
|
||||
"```python\n" + code_context + "```\n",
|
||||
"## System Design\n" + str(self.context.design_doc) + "\n",
|
||||
"## Tasks\n" + task_content + "\n",
|
||||
"## Code Files\n" + code_context + "\n",
|
||||
]
|
||||
)
|
||||
prompt = PROMPT_TEMPLATE.format(
|
||||
context_prompt = PROMPT_TEMPLATE.format(
|
||||
context=context,
|
||||
code=iterative_code,
|
||||
filename=self.context.code_doc.filename,
|
||||
format_example=format_example,
|
||||
)
|
||||
cr_prompt = EXAMPLE_AND_INSTRUCTION.format(format_example=format_example, )
|
||||
logger.info(
|
||||
f"Code review and rewrite {self.context.code_doc.filename,}: {i+1}/{k} | {len(iterative_code)=}, {len(self.context.code_doc.content)=}"
|
||||
f"Code review and rewrite {self.context.code_doc.filename}: {i+1}/{k} | {len(iterative_code)=}, {len(self.context.code_doc.content)=}"
|
||||
)
|
||||
result, rewrited_code = await self.write_code_review_and_rewrite(prompt)
|
||||
result, rewrited_code = await self.write_code_review_and_rewrite(context_prompt, cr_prompt, self.context.code_doc.filename)
|
||||
if "LBTM" in result:
|
||||
iterative_code = rewrited_code
|
||||
elif "LGTM" in result:
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ REQUIREMENT_POOL = ActionNode(
|
|||
key="Requirement Pool",
|
||||
expected_type=list[list[str]],
|
||||
instruction="List down the requirements with their priority (P0, P1, P2).",
|
||||
example=[["P0", "High priority requirement"], ["P1", "Medium priority requirement"]],
|
||||
example=[["P0", "..."], ["P1", "..."]],
|
||||
)
|
||||
|
||||
UI_DESIGN_DRAFT = ActionNode(
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@ class BaseGPTAPI(BaseChatbot):
|
|||
message = (
|
||||
[self._default_system_msg(), self._user_msg(msg)] if self.use_system_prompt else [self._user_msg(msg)]
|
||||
)
|
||||
rsp = await self.acompletion_text(message, stream=stream)
|
||||
logger.debug(message)
|
||||
rsp = await self.acompletion_text(message, stream=stream)
|
||||
# logger.debug(rsp)
|
||||
return rsp
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ class Engineer(Role):
|
|||
name: str = "Alex",
|
||||
profile: str = "Engineer",
|
||||
goal: str = "write elegant, readable, extensible, efficient code",
|
||||
constraints: str = "the code should conform to standards like PEP8 and be modular and maintainable. "
|
||||
constraints: str = "the code should conform to standards like google-style and be modular and maintainable. "
|
||||
"Use same language as user requirement",
|
||||
n_borg: int = 1,
|
||||
use_code_review: bool = False,
|
||||
|
|
@ -105,7 +105,9 @@ class Engineer(Role):
|
|||
coding_context = await todo.run()
|
||||
# Code review
|
||||
if review:
|
||||
coding_context = await WriteCodeReview(context=coding_context, llm=self._llm).run()
|
||||
action = WriteCodeReview(context=coding_context, llm=self._llm)
|
||||
self._init_action_system_message(action)
|
||||
coding_context = await action.run()
|
||||
await src_file_repo.save(
|
||||
coding_context.filename,
|
||||
dependencies={coding_context.design_doc.root_relative_path, coding_context.task_doc.root_relative_path},
|
||||
|
|
@ -224,6 +226,7 @@ class Engineer(Role):
|
|||
task_doc = await task_file_repo.get(i.name)
|
||||
elif str(i.parent) == SYSTEM_DESIGN_FILE_REPO:
|
||||
design_doc = await design_file_repo.get(i.name)
|
||||
# FIXME: design doc没有加载进来,是None
|
||||
context = CodingContext(filename=filename, design_doc=design_doc, task_doc=task_doc, code_doc=old_code_doc)
|
||||
return context
|
||||
|
||||
|
|
|
|||
|
|
@ -134,6 +134,7 @@ class Role:
|
|||
self._setting = RoleSetting(
|
||||
name=name, profile=profile, goal=goal, constraints=constraints, desc=desc, is_human=is_human
|
||||
)
|
||||
self._llm.system_prompt = self._get_prefix()
|
||||
self._states = []
|
||||
self._actions = []
|
||||
self._role_id = str(self._setting)
|
||||
|
|
@ -144,6 +145,9 @@ class Role:
|
|||
self._states = []
|
||||
self._actions = []
|
||||
|
||||
def _init_action_system_message(self, action: Action):
|
||||
action.set_prefix(self._get_prefix(), self.profile)
|
||||
|
||||
def _init_actions(self, actions):
|
||||
self._reset()
|
||||
for idx, action in enumerate(actions):
|
||||
|
|
@ -158,7 +162,7 @@ class Role:
|
|||
)
|
||||
i = action
|
||||
# i.set_env(self._rc.env)
|
||||
i.set_prefix(self._get_prefix(), self.profile)
|
||||
self._init_action_system_message(i)
|
||||
self._actions.append(i)
|
||||
self._states.append(f"{idx}. {action}")
|
||||
|
||||
|
|
@ -408,7 +412,7 @@ class Role:
|
|||
logger.debug(f"{self._setting}: no news. waiting.")
|
||||
return
|
||||
|
||||
rsp = await self._react()
|
||||
rsp = await self.react()
|
||||
|
||||
# Reset the next action to be taken.
|
||||
self._rc.todo = None
|
||||
|
|
|
|||
|
|
@ -74,6 +74,12 @@ class Document(BaseModel):
|
|||
return None
|
||||
return str(CONFIG.git_repo.workdir / self.root_path / self.filename)
|
||||
|
||||
def __str__(self):
|
||||
return self.content
|
||||
|
||||
def __repr__(self):
|
||||
return self.content
|
||||
|
||||
|
||||
class Documents(BaseModel):
|
||||
"""A class representing a collection of documents.
|
||||
|
|
@ -259,7 +265,7 @@ class MessageQueue:
|
|||
|
||||
class CodingContext(BaseModel):
|
||||
filename: str
|
||||
design_doc: Document
|
||||
design_doc: Optional[Document]
|
||||
task_doc: Optional[Document]
|
||||
code_doc: Optional[Document]
|
||||
|
||||
|
|
|
|||
|
|
@ -223,10 +223,15 @@ class CodeParser:
|
|||
# 遍历所有的block
|
||||
for block in blocks:
|
||||
# 如果block不为空,则继续处理
|
||||
if block.strip() != "":
|
||||
if block.strip() == "":
|
||||
continue
|
||||
if "\n" not in block:
|
||||
block_title = block
|
||||
block_content = ""
|
||||
else:
|
||||
# 将block的标题和内容分开,并分别去掉前后的空白字符
|
||||
block_title, block_content = block.split("\n", 1)
|
||||
block_dict[block_title.strip()] = block_content.strip()
|
||||
block_dict[block_title.strip()] = block_content.strip()
|
||||
|
||||
return block_dict
|
||||
|
||||
|
|
|
|||
|
|
@ -233,6 +233,8 @@ class GitRepository:
|
|||
files = []
|
||||
try:
|
||||
directory_path = Path(self.workdir) / relative_path
|
||||
if not directory_path.exists():
|
||||
return []
|
||||
for file_path in directory_path.iterdir():
|
||||
if file_path.is_file():
|
||||
rpath = file_path.relative_to(root_relative_path)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue