feat: merge geekan:env_refactor

This commit is contained in:
莘权 马 2023-12-15 17:05:09 +08:00
commit be832c9995
47 changed files with 1928 additions and 843 deletions

View file

@ -26,8 +26,9 @@ class Architect(Role):
self,
name: str = "Bob",
profile: str = "Architect",
goal: str = "Design a concise, usable, complete python system",
constraints: str = "Try to specify good open source tools as much as possible",
goal: str = "design a concise, usable, complete software system",
constraints: str = "make sure the architecture is simple enough and use appropriate open source libraries."
"Use same language as user requirement"
) -> None:
"""Initializes the Architect with given attributes."""
super().__init__(name, profile, goal, constraints)

View file

@ -71,14 +71,16 @@ class Engineer(Role):
self,
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",
goal: str = "write elegant, readable, extensible, efficient code",
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,
) -> None:
"""Initializes the Engineer role with given attributes."""
super().__init__(name, profile, goal, constraints)
self.use_code_review = use_code_review
self._init_actions([WriteCode])
self._watch([WriteTasks, SummarizeCode, WriteCode, WriteCodeReview, FixBug])
self.code_todos = []
self.summarize_todos = []
@ -104,7 +106,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},
@ -201,11 +205,11 @@ class Engineer(Role):
return None
msg = self._rc.news[0]
if msg.cause_by in write_code_filters:
logger.info(f"TODO WriteCode:{msg.json()}")
logger.debug(f"TODO WriteCode:{msg.json()}")
await self._new_code_actions(bug_fix=msg.cause_by == any_to_str(FixBug))
return self._rc.todo
if msg.cause_by in summarize_code_filters and msg.sent_from == any_to_str(self):
logger.info(f"TODO SummarizeCode:{msg.json()}")
logger.debug(f"TODO SummarizeCode:{msg.json()}")
await self._new_summarize_actions()
return self._rc.todo
return None
@ -225,6 +229,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

View file

@ -29,8 +29,8 @@ class ProductManager(Role):
self,
name: str = "Alice",
profile: str = "Product Manager",
goal: str = "Efficiently create a successful product",
constraints: str = "",
goal: str = "efficiently create a successful product",
constraints: str = "use same language as user requirement",
) -> None:
"""
Initializes the ProductManager role with given attributes.

View file

@ -25,8 +25,9 @@ class ProjectManager(Role):
self,
name: str = "Eve",
profile: str = "Project Manager",
goal: str = "Improve team efficiency and deliver with quality and quantity",
constraints: str = "",
goal: str = "break down tasks according to PRD/technical design, generate a task list, and analyze task "
"dependencies to start with the prerequisite modules",
constraints: str = "use same language as user requirement",
) -> None:
"""
Initializes the ProjectManager role with given attributes.

View file

@ -26,6 +26,7 @@ from metagpt.logs import logger
from metagpt.roles import Role
from metagpt.schema import Document, Message, RunCodeContext, TestingContext
from metagpt.utils.common import any_to_str_set, parse_recipient
from metagpt.utils.file_repository import FileRepository
class QaEngineer(Role):
@ -125,8 +126,8 @@ class QaEngineer(Role):
async def _debug_error(self, msg):
run_code_context = RunCodeContext.loads(msg.content)
code = await DebugError(context=run_code_context, llm=self._llm).run()
await CONFIG.git_repo.new_file_repository(CONFIG.src_workspace).save(
filename=run_code_context.code_filename, content=code
await FileRepository.save_file(
filename=run_code_context.test_filename, content=code, relative_path=TEST_CODES_FILE_REPO
)
run_code_context.output = None
self.publish_message(

View file

@ -27,11 +27,13 @@ from typing import Iterable, Set, Type
from pydantic import BaseModel, Field
from metagpt.actions import Action, ActionOutput
from metagpt.actions.action_node import ActionNode
from metagpt.llm import LLM, HumanProvider
from metagpt.logs import logger
from metagpt.memory import Memory
from metagpt.schema import Message, MessageQueue
from metagpt.utils.common import any_to_name, any_to_str
from metagpt.utils.repair_llm_raw_output import extract_state_value_from_output
PREFIX_TEMPLATE = """You are a {profile}, named {name}, your goal is {goal}, and the constraint is {constraints}. """
@ -133,6 +135,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)
@ -143,6 +146,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):
@ -151,12 +157,13 @@ class Role:
else:
if self._setting.is_human and not isinstance(action.llm, HumanProvider):
logger.warning(
f"is_human attribute does not take effect,"
f"as Role's {str(action)} was initialized using LLM, try passing in Action classes instead of initialized instances"
f"is_human attribute does not take effect, "
f"as Role's {str(action)} was initialized using LLM, "
f"try passing in Action classes instead of initialized instances"
)
i = action
i.set_env(self._rc.env)
i.set_prefix(self._get_prefix(), self.profile)
# i.set_env(self._rc.env)
self._init_action_system_message(i)
self._actions.append(i)
self._states.append(f"{idx}. {action}")
@ -271,6 +278,7 @@ class Role:
)
# print(prompt)
next_state = await self._llm.aask(prompt)
next_state = extract_state_value_from_output(next_state)
logger.debug(f"{prompt=}")
if (not next_state.isdigit() and next_state != "-1") or int(next_state) not in range(-1, len(self._states)):
logger.warning(f"Invalid answer of state, {next_state=}, will be set to -1")
@ -285,7 +293,7 @@ class Role:
async def _act(self) -> Message:
logger.info(f"{self._setting}: ready to {self._rc.todo}")
response = await self._rc.todo.run(self._rc.important_memory)
if isinstance(response, ActionOutput):
if isinstance(response, ActionOutput) or isinstance(response, ActionNode):
msg = Message(
content=response.content,
instruct_content=response.instruct_content,
@ -396,7 +404,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

View file

@ -8,6 +8,7 @@
the `cause_by` value in the `Message` to a string to support the new message distribution feature.
"""
from metagpt.actions import ActionOutput, SearchAndSummarize
from metagpt.actions.action_node import ActionNode
from metagpt.logs import logger
from metagpt.roles import Role
from metagpt.schema import Message
@ -58,7 +59,7 @@ class Searcher(Role):
logger.info(f"{self._setting}: ready to {self._rc.todo}")
response = await self._rc.todo.run(self._rc.memory.get(k=0))
if isinstance(response, ActionOutput):
if isinstance(response, ActionOutput) or isinstance(response, ActionNode):
msg = Message(
content=response.content,
instruct_content=response.instruct_content,