mirror of
https://github.com/FoundationAgents/MetaGPT.git
synced 2026-06-08 15:05:17 +02:00
serdeser rebase from main
This commit is contained in:
commit
dd640991b7
15 changed files with 91 additions and 11 deletions
|
|
@ -64,11 +64,10 @@ class Action(BaseModel):
|
|||
"""Set prefix for later usage"""
|
||||
self.prefix = prefix
|
||||
self.profile = profile
|
||||
return self
|
||||
|
||||
def __str__(self):
|
||||
return self.__class__.__name__
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,11 @@ from pydantic import Field
|
|||
|
||||
from metagpt.actions import Action, ActionOutput
|
||||
from metagpt.actions.design_api_an import DESIGN_API_NODE
|
||||
from typing import List, Optional, Any
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@
|
|||
@Modified By: mashenquan, 2023/11/27. Following the think-act principle, solidify the task parameters when creating the
|
||||
WriteCode object, rather than passing them in when calling the run function.
|
||||
"""
|
||||
from typing import List, Optional, Any
|
||||
from pydantic import Field
|
||||
from tenacity import retry, stop_after_attempt, wait_fixed
|
||||
|
||||
from typing import List, Optional, Any
|
||||
from pydantic import Field
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ DATA_PATH = METAGPT_ROOT / "data"
|
|||
RESEARCH_PATH = DATA_PATH / "research"
|
||||
TUTORIAL_PATH = DATA_PATH / "tutorial_docx"
|
||||
INVOICE_OCR_TABLE_PATH = DATA_PATH / "invoice_table"
|
||||
|
||||
UT_PATH = DATA_PATH / "ut"
|
||||
SWAGGER_PATH = UT_PATH / "files/api/"
|
||||
UT_PY_PATH = UT_PATH / "files/ut/"
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@
|
|||
from typing import Optional
|
||||
from pydantic import Field
|
||||
|
||||
from typing import Optional
|
||||
from pydantic import Field
|
||||
|
||||
from metagpt.logs import logger
|
||||
from metagpt.memory import Memory
|
||||
from metagpt.memory.memory_storage import MemoryStorage
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
"""
|
||||
import copy
|
||||
from collections import defaultdict
|
||||
|
||||
from typing import Iterable, Type, Union, Optional, Set
|
||||
from pathlib import Path
|
||||
from pydantic import BaseModel, Field
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ class Architect(Role):
|
|||
goal (str): Primary goal or responsibility of the architect.
|
||||
constraints (str): Constraints or guidelines for the architect.
|
||||
"""
|
||||
|
||||
name: str = "Bob"
|
||||
profile: str = Field(default="Architect", alias='profile')
|
||||
goal: str = "design a concise, usable, complete software system"
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ from metagpt.utils.common import any_to_str, any_to_str_set
|
|||
IS_PASS_PROMPT = """
|
||||
{context}
|
||||
|
||||
<<<<<<< HEAD
|
||||
----
|
||||
Does the above log indicate anything that needs to be done?
|
||||
If there are any tasks to be completed, please answer 'NO' along with the to-do list in JSON format;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ class ProjectManager(Role):
|
|||
name: str = Field(default="Eve")
|
||||
profile: str = Field(default="Project Manager")
|
||||
|
||||
|
||||
goal: str = "reak 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"
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ class RoleContext(BaseModel):
|
|||
news: list[Type[Message]] = Field(default=[], exclude=True) # TODO not used
|
||||
react_mode: RoleReactMode = RoleReactMode.REACT # see `Role._set_react_mode` for definitions of the following two attributes
|
||||
max_react_loop: int = 1
|
||||
|
||||
|
||||
class Config:
|
||||
arbitrary_types_allowed = True
|
||||
|
||||
|
|
@ -175,7 +175,7 @@ class _RoleInjector(type):
|
|||
role_subclass_registry = {}
|
||||
|
||||
|
||||
class Role(BaseModel):
|
||||
class Role(BaseModel, metaclass=_RoleInjector):
|
||||
"""Role/Agent"""
|
||||
name: str = ""
|
||||
profile: str = ""
|
||||
|
|
@ -248,6 +248,62 @@ class Role(BaseModel):
|
|||
super().__init_subclass__(**kwargs)
|
||||
role_subclass_registry[cls.__name__] = cls
|
||||
|
||||
# builtin variables
|
||||
recovered: bool = False # to tag if a recovered role
|
||||
builtin_class_name: str = ""
|
||||
|
||||
_private_attributes = {
|
||||
"_llm": LLM() if not is_human else HumanProvider(),
|
||||
"_role_id": _role_id,
|
||||
"_states": [],
|
||||
"_actions": [],
|
||||
"_rc": RoleContext()
|
||||
}
|
||||
|
||||
class Config:
|
||||
arbitrary_types_allowed = True
|
||||
exclude = ["_llm"]
|
||||
|
||||
def __init__(self, **kwargs: Any):
|
||||
for index in range(len(kwargs.get("_actions", []))):
|
||||
current_action = kwargs["_actions"][index]
|
||||
if isinstance(current_action, dict):
|
||||
item_class_name = current_action.get("builtin_class_name", None)
|
||||
for name, subclass in action_subclass_registry.items():
|
||||
registery_class_name = subclass.__fields__["builtin_class_name"].default
|
||||
if item_class_name == registery_class_name:
|
||||
current_action = subclass(**current_action)
|
||||
break
|
||||
kwargs["_actions"][index] = current_action
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
# 关于私有变量的初始化 https://github.com/pydantic/pydantic/issues/655
|
||||
self._private_attributes["_llm"] = LLM() if not self.is_human else HumanProvider()
|
||||
self._private_attributes["_role_id"] = str(self._setting)
|
||||
|
||||
for key in self._private_attributes.keys():
|
||||
if key in kwargs:
|
||||
object.__setattr__(self, key, kwargs[key])
|
||||
if key == "_rc":
|
||||
_rc = RoleContext(**kwargs["_rc"])
|
||||
object.__setattr__(self, "_rc", _rc)
|
||||
else:
|
||||
if key == "_rc":
|
||||
# # Warning, if use self._private_attributes["_rc"],
|
||||
# # self._rc will be a shared object between roles, so init one or reset it inside `_reset`
|
||||
object.__setattr__(self, key, RoleContext())
|
||||
else:
|
||||
object.__setattr__(self, key, self._private_attributes[key])
|
||||
|
||||
# deserialize child classes dynamically for inherited `role`
|
||||
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)
|
||||
role_subclass_registry[cls.__name__] = cls
|
||||
|
||||
def _reset(self):
|
||||
object.__setattr__(self, "_states", [])
|
||||
object.__setattr__(self, "_actions", [])
|
||||
|
|
@ -442,7 +498,7 @@ class Role(BaseModel):
|
|||
if next_state == -1:
|
||||
logger.info(f"End actions with {next_state=}")
|
||||
self._set_state(next_state)
|
||||
|
||||
|
||||
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)
|
||||
|
|
@ -574,7 +630,7 @@ class Role(BaseModel):
|
|||
# If there is no new information, suspend and wait
|
||||
logger.debug(f"{self._setting}: no news. waiting.")
|
||||
return
|
||||
|
||||
|
||||
rsp = await self.react()
|
||||
|
||||
# Reset the next action to be taken.
|
||||
|
|
|
|||
|
|
@ -39,6 +39,9 @@ from metagpt.const import (
|
|||
TASK_FILE_REPO,
|
||||
)
|
||||
from metagpt.logs import logger
|
||||
from metagpt.utils.serialize import actionoutout_schema_to_mapping, actionoutput_mapping_to_str, \
|
||||
actionoutput_str_to_mapping
|
||||
from metagpt.utils.utils import import_class
|
||||
|
||||
from metagpt.utils.common import any_to_str, any_to_str_set
|
||||
# from metagpt.utils.serialize import actionoutout_schema_to_mapping
|
||||
|
|
@ -55,6 +58,7 @@ class RawMessage(TypedDict):
|
|||
role: str
|
||||
|
||||
|
||||
|
||||
class Document(BaseModel):
|
||||
"""
|
||||
Represents a document.
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ class Team(BaseModel):
|
|||
n_round -= 1
|
||||
logger.debug(f"max {n_round=} left.")
|
||||
self._check_balance()
|
||||
|
||||
await self.env.run()
|
||||
if CONFIG.git_repo:
|
||||
CONFIG.git_repo.archive()
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@ import json
|
|||
from pathlib import Path
|
||||
import importlib
|
||||
from tenacity import _utils
|
||||
import traceback
|
||||
|
||||
from metagpt.logs import logger
|
||||
|
||||
|
||||
def general_after_log(logger: "loguru.Logger", sec_format: str = "%0.3f") -> typing.Callable[["RetryCallState"], None]:
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ async def test_publish_and_process_message(env: Environment):
|
|||
constraints="资源有限,需要节省成本")
|
||||
|
||||
env.add_roles([product_manager, architect])
|
||||
|
||||
env.set_manager(Manager())
|
||||
env.publish_message(Message(role="User", content="需要一个基于LLM做总结的搜索引擎", cause_by=UserRequirement))
|
||||
|
||||
|
|
|
|||
|
|
@ -8,16 +8,22 @@
|
|||
the utilization of the new feature of `Message` class.
|
||||
"""
|
||||
|
||||
<<<<<<< HEAD
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
from metagpt.actions import Action
|
||||
=======
|
||||
>>>>>>> a69be36abf7beef1a989a707d1aa027948c07fee
|
||||
from metagpt.schema import AIMessage, Message, SystemMessage, UserMessage
|
||||
from metagpt.actions.action_output import ActionOutput
|
||||
from metagpt.actions.write_code import WriteCode
|
||||
from metagpt.utils.serialize import serialize_general_message, deserialize_general_message
|
||||
<<<<<<< HEAD
|
||||
from metagpt.utils.common import get_class_name
|
||||
=======
|
||||
>>>>>>> a69be36abf7beef1a989a707d1aa027948c07fee
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -110,7 +116,3 @@ def test_message_serdeser():
|
|||
new_message = deserialize_general_message(message_dict)
|
||||
assert new_message.instruct_content is None
|
||||
assert new_message.cause_by == ""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__, "-s"])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue