mirror of
https://github.com/FoundationAgents/MetaGPT.git
synced 2026-07-14 16:32:16 +02:00
update environment/message to BaseModel, update the ser&deser of roles/actions
This commit is contained in:
parent
9e5c873d77
commit
5e3607f85b
26 changed files with 458 additions and 252 deletions
|
|
@ -5,8 +5,9 @@
|
|||
@Author : alexanderwu
|
||||
@File : action.py
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
import re
|
||||
from abc import ABC
|
||||
from typing import Optional, Any
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
|
@ -14,25 +15,43 @@ from tenacity import retry, stop_after_attempt, wait_fixed
|
|||
|
||||
from metagpt.actions.action_output import ActionOutput
|
||||
from metagpt.llm import LLM
|
||||
from metagpt.provider.base_gpt_api import BaseGPTAPI
|
||||
from metagpt.logs import logger
|
||||
from metagpt.utils.common import OutputParser
|
||||
from metagpt.utils.custom_decoder import CustomDecoder
|
||||
from metagpt.utils.utils import import_class
|
||||
|
||||
|
||||
action_subclass_registry = {}
|
||||
|
||||
|
||||
class Action(BaseModel):
|
||||
name: str = ""
|
||||
llm: LLM = Field(default_factory=LLM)
|
||||
llm: BaseGPTAPI = Field(default_factory=LLM, exclude=True)
|
||||
context = ""
|
||||
prefix = ""
|
||||
profile = ""
|
||||
desc = ""
|
||||
content: Optional[str] = None
|
||||
instruct_content: Optional[str] = None
|
||||
|
||||
# builtin variables
|
||||
builtin_class_name: str = ""
|
||||
|
||||
class Config:
|
||||
arbitrary_types_allowed = True
|
||||
|
||||
def __init__(self, **kwargs: Any):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
# deserialize child classes dynamically for inherited `action`
|
||||
object.__setattr__(self, "builtin_class_name", self.__class__.__name__)
|
||||
self.__fields__["builtin_class_name"].default = self.__class__.__name__
|
||||
|
||||
def __init_subclass__(cls, **kwargs: Any) -> None:
|
||||
super().__init_subclass__(**kwargs)
|
||||
action_subclass_registry[cls.__name__] = cls
|
||||
|
||||
def set_prefix(self, prefix, profile):
|
||||
"""Set prefix for later usage"""
|
||||
self.prefix = prefix
|
||||
|
|
@ -52,14 +71,14 @@ class Action(BaseModel):
|
|||
}
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, action_dict: dict):
|
||||
def deserialize(cls, action_dict: dict) -> "Action":
|
||||
action_class_str = action_dict.pop("action_class")
|
||||
module_name = action_dict.pop("module_name")
|
||||
action_class = import_class(action_class_str, module_name)
|
||||
return action_class(**action_dict)
|
||||
|
||||
@classmethod
|
||||
def ser_class(cls):
|
||||
def ser_class(cls) -> dict:
|
||||
""" serialize class type"""
|
||||
return {
|
||||
"action_class": cls.__name__,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ from pydantic import Field
|
|||
|
||||
from metagpt.actions import Action, ActionOutput
|
||||
from metagpt.llm import LLM
|
||||
from metagpt.provider.base_gpt_api import BaseGPTAPI
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.const import WORKSPACE_ROOT
|
||||
from metagpt.logs import logger
|
||||
|
|
@ -155,12 +156,11 @@ OUTPUT_MAPPING = {
|
|||
class WriteDesign(Action):
|
||||
name: str = ""
|
||||
context: Optional[str] = None
|
||||
llm: LLM = Field(default_factory=LLM)
|
||||
llm: BaseGPTAPI = Field(default_factory=LLM)
|
||||
desc: str = "Based on the PRD, think about the system design, and design the corresponding APIs, "
|
||||
"data structures, library tables, processes, and paths. Please provide your design, feedback "
|
||||
"clearly and in detail."
|
||||
|
||||
|
||||
def recreate_workspace(self, workspace: Path):
|
||||
try:
|
||||
shutil.rmtree(workspace)
|
||||
|
|
@ -168,7 +168,6 @@ class WriteDesign(Action):
|
|||
pass # Folder does not exist, but we don't care
|
||||
workspace.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
|
||||
async def _save_prd(self, docs_path, resources_path, context):
|
||||
prd_file = docs_path / "prd.md"
|
||||
if context[-1].instruct_content and context[-1].instruct_content.dict()["Competitive Quadrant Chart"]:
|
||||
|
|
@ -179,7 +178,6 @@ class WriteDesign(Action):
|
|||
logger.info(f"Saving PRD to {prd_file}")
|
||||
prd_file.write_text(json_to_markdown(context[-1].instruct_content.dict()))
|
||||
|
||||
|
||||
async def _save_system_design(self, docs_path, resources_path, system_design):
|
||||
data_api_design = system_design.instruct_content.dict()[
|
||||
"Data structures and interface definitions"
|
||||
|
|
@ -193,7 +191,6 @@ class WriteDesign(Action):
|
|||
logger.info(f"Saving System Designs to {system_design_file}")
|
||||
system_design_file.write_text((json_to_markdown(system_design.instruct_content.dict())))
|
||||
|
||||
|
||||
async def _save(self, context, system_design):
|
||||
if isinstance(system_design, ActionOutput):
|
||||
ws_name = system_design.instruct_content.dict()["Python package name"]
|
||||
|
|
@ -211,7 +208,6 @@ class WriteDesign(Action):
|
|||
logger.error(f"Failed to save PRD {e}")
|
||||
await self._save_system_design(docs_path, resources_path, system_design)
|
||||
|
||||
|
||||
async def run(self, context, format=CONFIG.prompt_format):
|
||||
prompt_template, format_example = get_template(templates, format)
|
||||
prompt = prompt_template.format(context=context, format_example=format_example)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ from pydantic import Field
|
|||
|
||||
from metagpt.actions.action import Action
|
||||
from metagpt.llm import LLM
|
||||
from metagpt.provider.base_gpt_api import BaseGPTAPI
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.const import WORKSPACE_ROOT
|
||||
from metagpt.utils.common import CodeParser
|
||||
|
|
@ -168,7 +169,7 @@ OUTPUT_MAPPING = {
|
|||
class WriteTasks(Action):
|
||||
name: str = "CreateTasks"
|
||||
context: Optional[str] = None
|
||||
llm: LLM = Field(default_factory=LLM)
|
||||
llm: BaseGPTAPI = Field(default_factory=LLM)
|
||||
|
||||
def _save(self, context, rsp):
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -8,14 +8,15 @@
|
|||
import pydantic
|
||||
from typing import Optional, Any
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import root_validator
|
||||
|
||||
from metagpt.actions import Action
|
||||
from metagpt.llm import LLM
|
||||
from metagpt.config import Config
|
||||
from metagpt.provider.base_gpt_api import BaseGPTAPI
|
||||
from metagpt.config import Config, CONFIG
|
||||
from metagpt.logs import logger
|
||||
from metagpt.schema import Message
|
||||
from metagpt.tools.search_engine import SearchEngine
|
||||
from pydantic import root_validator
|
||||
|
||||
SEARCH_AND_SUMMARIZE_SYSTEM = """### Requirements
|
||||
1. Please summarize the latest dialogue based on the reference information (secondary) and dialogue history (primary). Do not include text that is irrelevant to the conversation.
|
||||
|
|
@ -106,13 +107,13 @@ You are a member of a professional butler team and will provide helpful suggesti
|
|||
class SearchAndSummarize(Action):
|
||||
name: str = ""
|
||||
content: Optional[str] = None
|
||||
llm: None = Field(default_factory=LLM)
|
||||
llm: BaseGPTAPI = Field(default_factory=LLM)
|
||||
config: None = Field(default_factory=Config)
|
||||
engine: Optional[str] = None
|
||||
engine: Optional[str] = CONFIG.search_engine
|
||||
search_func: Optional[str] = None
|
||||
search_engine: SearchEngine = None
|
||||
|
||||
result = ""
|
||||
|
||||
|
||||
@root_validator
|
||||
def validate_engine_and_run_func(cls, values):
|
||||
|
|
@ -130,9 +131,7 @@ class SearchAndSummarize(Action):
|
|||
|
||||
values['search_engine'] = search_engine
|
||||
return values
|
||||
|
||||
|
||||
|
||||
|
||||
async def run(self, context: list[Message], system_text=SEARCH_AND_SUMMARIZE_SYSTEM) -> str:
|
||||
print(context)
|
||||
if self.search_engine is None:
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ from tenacity import retry, stop_after_attempt, wait_fixed
|
|||
from metagpt.actions import WriteDesign
|
||||
from metagpt.actions.action import Action
|
||||
from metagpt.llm import LLM
|
||||
from metagpt.provider.base_gpt_api import BaseGPTAPI
|
||||
from metagpt.const import WORKSPACE_ROOT
|
||||
from metagpt.logs import logger
|
||||
from metagpt.schema import Message
|
||||
|
|
@ -50,7 +51,7 @@ ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenc
|
|||
class WriteCode(Action):
|
||||
name: str = "WriteCode"
|
||||
context: Optional[str] = None
|
||||
llm: LLM = Field(default_factory=LLM)
|
||||
llm: BaseGPTAPI = Field(default_factory=LLM)
|
||||
|
||||
def _is_invalid(self, filename):
|
||||
return any(i in filename for i in ["mp3", "wav"])
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ from tenacity import retry, stop_after_attempt, wait_fixed
|
|||
from metagpt.llm import LLM
|
||||
from metagpt.actions.action import Action
|
||||
from metagpt.logs import logger
|
||||
from metagpt.schema import Message
|
||||
from metagpt.provider.base_gpt_api import BaseGPTAPI
|
||||
from metagpt.utils.common import CodeParser
|
||||
|
||||
PROMPT_TEMPLATE = """
|
||||
|
|
@ -67,7 +67,7 @@ FORMAT_EXAMPLE = """
|
|||
class WriteCodeReview(Action):
|
||||
name: str = "WriteCodeReview"
|
||||
context: Optional[str] = None
|
||||
llm: LLM = Field(default_factory=LLM)
|
||||
llm: BaseGPTAPI = Field(default_factory=LLM)
|
||||
|
||||
@retry(stop=stop_after_attempt(2), wait=wait_fixed(1))
|
||||
async def write_code(self, prompt):
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ from pydantic import BaseModel, Field
|
|||
|
||||
from metagpt.actions import Action, ActionOutput
|
||||
from metagpt.llm import LLM
|
||||
from metagpt.provider.base_gpt_api import BaseGPTAPI
|
||||
from metagpt.actions.search_and_summarize import SearchAndSummarize
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.logs import logger
|
||||
|
|
@ -224,12 +225,9 @@ OUTPUT_MAPPING = {
|
|||
class WritePRD(Action):
|
||||
name: str = ""
|
||||
content: Optional[str] = None
|
||||
llm: LLM = Field(default_factory=LLM)
|
||||
llm: BaseGPTAPI = Field(default_factory=LLM)
|
||||
assistant_search_action: Action = None
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
async def run(self, requirements, format=CONFIG.prompt_format, *args, **kwargs) -> ActionOutput:
|
||||
# self.assistant_search_action = SearchAndSummarize()
|
||||
if self.assistant_search_action is None:
|
||||
|
|
|
|||
|
|
@ -5,6 +5,12 @@
|
|||
@Author : alexanderwu
|
||||
@File : environment.py
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
from pydantic import Field
|
||||
|
||||
from metagpt.llm import LLM
|
||||
from metagpt.provider.base_gpt_api import BaseGPTAPI
|
||||
from metagpt.actions.action import Action
|
||||
from metagpt.logs import logger
|
||||
from metagpt.utils.common import CodeParser
|
||||
|
|
@ -31,8 +37,9 @@ you should correctly import the necessary classes based on these file locations!
|
|||
|
||||
|
||||
class WriteTest(Action):
|
||||
def __init__(self, name="WriteTest", context=None, llm=None):
|
||||
super().__init__(name, context, llm)
|
||||
name: str = "WriteTest"
|
||||
context: Optional[str] = None
|
||||
llm: BaseGPTAPI = Field(default_factory=LLM)
|
||||
|
||||
async def write_code(self, prompt):
|
||||
code_rsp = await self._aask(prompt)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue