Merge branch 'mgx_ops' into json_repair

# Conflicts:
#	metagpt/prompts/di/role_zero.py
#	metagpt/roles/di/data_analyst.py
This commit is contained in:
zhanglei 2024-06-28 15:21:39 +08:00
commit 8d973c2cf7
57 changed files with 4180 additions and 278 deletions

View file

@ -8,6 +8,8 @@
from metagpt.actions import WritePRD
from metagpt.actions.design_api import WriteDesign
from metagpt.roles.di.role_zero import RoleZero
from metagpt.tools.libs.software_development import write_trd_and_framework
from metagpt.utils.common import tool2name
class Architect(RoleZero):
@ -29,9 +31,14 @@ class Architect(RoleZero):
"libraries. Use same language as user requirement"
)
instruction: str = """Use WriteDesign tool to write a system design document"""
instruction: str = """Use WriteDesign tool to write a system design document if a system design is required; Use `write_trd_and_framework` tool to write a software framework if a software framework is required;"""
max_react_loop: int = 1 # FIXME: Read and edit files requires more steps, consider later
tools: list[str] = ["Editor:write,read,write_content", "RoleZero", "WriteDesign"]
tools: list[str] = [
"Editor:write,read,write_content",
"RoleZero",
"WriteDesign",
write_trd_and_framework.__name__,
]
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
@ -45,11 +52,11 @@ class Architect(RoleZero):
self._watch({WritePRD})
def _update_tool_execution(self):
wd = WriteDesign()
write_design = WriteDesign()
self.tool_execution_map.update(tool2name(WriteDesign, ["run"], write_design.run))
self.tool_execution_map.update(
{
"WriteDesign.run": wd.run,
"WriteDesign": wd.run, # alias
"run": wd.run, # alias
write_trd_and_framework.__name__: write_trd_and_framework,
"run": write_design.run, # alias
}
)

View file

@ -12,7 +12,7 @@ class Engineer2(RoleZero):
goal: str = "Take on game, app, and web development"
instruction: str = ENGINEER2_INSTRUCTION
tools: str = ["Plan", "Editor:write,read", "RoleZero", "ReviewAndRewriteCode"]
tools: list[str] = ["Plan", "Editor:write,read", "RoleZero", "ReviewAndRewriteCode"]
def _update_tool_execution(self):
review = ReviewAndRewriteCode()

View file

@ -2,6 +2,7 @@ from __future__ import annotations
import inspect
import json
import re
import traceback
from typing import Callable, Literal, Tuple
@ -10,7 +11,11 @@ from pydantic import model_validator
from metagpt.actions import Action
from metagpt.actions.di.run_command import RunCommand
from metagpt.logs import logger
from metagpt.prompts.di.role_zero import CMD_PROMPT, ROLE_INSTRUCTION, JSON_REPAIR_PROMPT
from metagpt.prompts.di.role_zero import (
CMD_PROMPT,
JSON_REPAIR_PROMPT,
ROLE_INSTRUCTION,
)
from metagpt.roles import Role
from metagpt.schema import AIMessage, Message, UserMessage
from metagpt.strategy.experience_retriever import DummyExpRetriever, ExpRetriever
@ -20,8 +25,8 @@ from metagpt.tools.libs.editor import Editor
from metagpt.tools.tool_recommend import BM25ToolRecommender, ToolRecommender
from metagpt.tools.tool_registry import register_tool
from metagpt.utils.common import CodeParser
from metagpt.utils.repair_llm_raw_output import RepairType, repair_llm_raw_output
from metagpt.utils.report import ThoughtReporter
from metagpt.utils.repair_llm_raw_output import repair_llm_raw_output, RepairType
@register_tool(include_functions=["ask_human", "reply_to_human"])
@ -88,6 +93,23 @@ class RoleZero(Role):
"RoleZero.ask_human": self.ask_human,
"RoleZero.reply_to_human": self.reply_to_human,
}
self.tool_execution_map.update(
{
f"Browser.{i}": getattr(self.browser, i)
for i in [
"click",
"close_tab",
"go_back",
"go_forward",
"goto",
"hover",
"press",
"scroll",
"tab_focus",
"type",
]
}
)
# can be updated by subclass
self._update_tool_execution()
return self
@ -126,7 +148,14 @@ class RoleZero(Role):
available_commands=tool_info,
instruction=self.instruction.strip(),
)
context = self.llm.format_msg(self.rc.memory.get(self.memory_k) + [UserMessage(content=prompt)])
memory = self.rc.memory.get(self.memory_k)
if not self.browser.is_empty_page:
pattern = re.compile(r"Command Browser\.(\w+) executed")
for index, msg in zip(range(len(memory), 0, -1), memory[::-1]):
if pattern.match(msg.content):
memory.insert(index, UserMessage(cause_by="browser", content=await self.browser.view()))
break
context = self.llm.format_msg(memory + [UserMessage(content=prompt)])
# print(*context, sep="\n" + "*" * 5 + "\n")
async with ThoughtReporter(enable_llm_stream=True):
self.command_rsp = await self.llm.aask(context, system_msgs=self.system_msg)
@ -141,7 +170,7 @@ class RoleZero(Role):
try:
commands = CodeParser.parse_code(block=None, lang="json", text=self.command_rsp)
commands = json.loads(repair_llm_raw_output(output=commands, req_keys=[None], repair_type=RepairType.JSON))
except json.JSONDecodeError as e:
except json.JSONDecodeError:
commands = await self.llm.aask(msg=JSON_REPAIR_PROMPT.format(json_data=self.command_rsp))
commands = json.loads(CodeParser.parse_code(block=None, lang="json", text=commands))
except Exception as e:

View file

@ -9,9 +9,10 @@
from metagpt.actions import UserRequirement, WritePRD
from metagpt.actions.prepare_documents import PrepareDocuments
from metagpt.actions.requirement_analysis.requirement.pic2txt import Pic2Txt
from metagpt.roles.di.role_zero import RoleZero
from metagpt.roles.role import RoleReactMode
from metagpt.utils.common import any_to_name, any_to_str
from metagpt.utils.common import any_to_name, any_to_str, tool2name
from metagpt.utils.git_repository import GitRepository
@ -32,9 +33,9 @@ class ProductManager(RoleZero):
constraints: str = "utilize the same language as the user requirements for seamless communication"
todo_action: str = any_to_name(WritePRD)
instruction: str = """Use WritePRD tool to write PRD"""
instruction: str = """Use WritePRD tool to write PRD if a PRD is required; Use `Pic2Txt` tool to write out an intact textual user requirements if an intact textual user requiremnt is required given some images alongside the contextual textual descriptions;"""
max_react_loop: int = 1 # FIXME: Read and edit files requires more steps, consider later
tools: list[str] = ["Editor:write,read,write_content", "RoleZero", "WritePRD"]
tools: list[str] = ["Editor:write,read,write_content", "RoleZero", "WritePRD", Pic2Txt.__name__]
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
@ -47,12 +48,9 @@ class ProductManager(RoleZero):
def _update_tool_execution(self):
wp = WritePRD()
self.tool_execution_map.update(
{
"WritePRD.run": wp.run,
"WritePRD": wp.run, # alias
}
)
self.tool_execution_map.update(tool2name(WritePRD, ["run"], wp.run))
pic2txt = Pic2Txt()
self.tool_execution_map.update(tool2name(Pic2Txt, ["run"], pic2txt.run))
async def _think(self) -> bool:
"""Decide what to do"""