mirror of
https://github.com/FoundationAgents/MetaGPT.git
synced 2026-05-27 14:25:20 +02:00
update unittest of ser&deser
This commit is contained in:
parent
39e4aa98ab
commit
9e5c873d77
19 changed files with 496 additions and 228 deletions
|
|
@ -11,20 +11,3 @@ from metagpt.actions import Action, WritePRD, WriteTest
|
|||
def test_action_repr():
|
||||
actions = [Action(), WriteTest(), WritePRD()]
|
||||
assert "WriteTest" in str(actions)
|
||||
|
||||
|
||||
def test_action_serdes():
|
||||
action_info = WriteTest.ser_class()
|
||||
assert action_info["action_class"] == "WriteTest"
|
||||
|
||||
action_class = Action.deser_class(action_info)
|
||||
assert action_class == WriteTest
|
||||
|
||||
|
||||
def test_action_class_serdes():
|
||||
name = "write test"
|
||||
action_info = WriteTest(name=name).serialize()
|
||||
assert action_info["name"] == name
|
||||
|
||||
action = Action.deserialize(action_info)
|
||||
assert action.name == name
|
||||
|
|
|
|||
|
|
@ -2,84 +2,10 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# @Desc : unittest of Role
|
||||
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import pytest
|
||||
|
||||
from metagpt.roles.role import Role, RoleReactMode
|
||||
from metagpt.actions.action import Action
|
||||
from metagpt.schema import Message
|
||||
from metagpt.actions.add_requirement import BossRequirement
|
||||
from metagpt.roles.product_manager import ProductManager
|
||||
|
||||
serdes_path = Path(__file__).absolute().parent.joinpath("../../data/serdes_storage")
|
||||
from metagpt.roles.role import Role
|
||||
|
||||
|
||||
def test_role_serdes():
|
||||
stg_path_prefix = serdes_path.joinpath("team/environment/roles/")
|
||||
shutil.rmtree(serdes_path.joinpath("team"), ignore_errors=True)
|
||||
|
||||
pm = ProductManager()
|
||||
role_tag = f"{pm.__class__.__name__}_{pm.name}"
|
||||
stg_path = stg_path_prefix.joinpath(role_tag)
|
||||
pm.serialize(stg_path)
|
||||
assert stg_path.joinpath("actions/actions_info.json").exists()
|
||||
|
||||
new_pm = Role.deserialize(stg_path)
|
||||
assert new_pm.name == pm.name
|
||||
assert len(new_pm.get_memories(1)) == 0
|
||||
|
||||
|
||||
class ActionOK(Action):
|
||||
|
||||
async def run(self, messages: list["Message"]):
|
||||
return "ok"
|
||||
|
||||
|
||||
class ActionRaise(Action):
|
||||
|
||||
async def run(self, messages: list["Message"]):
|
||||
raise RuntimeError("parse error")
|
||||
|
||||
|
||||
class RoleA(Role):
|
||||
|
||||
def __init__(self,
|
||||
name: str = "RoleA",
|
||||
profile: str = "Role A",
|
||||
goal: str = "",
|
||||
constraints: str = ""):
|
||||
super(RoleA, self).__init__(name=name, profile=profile, goal=goal, constraints=constraints)
|
||||
self._init_actions([ActionOK, ActionRaise])
|
||||
self._watch([BossRequirement])
|
||||
self._rc.react_mode = RoleReactMode.BY_ORDER
|
||||
|
||||
async def run(self, message: "Message" = None, stg_path: str = None):
|
||||
try:
|
||||
await super(RoleA, self).run(message)
|
||||
except Exception as exp:
|
||||
print("exp ", exp)
|
||||
self.serialize(stg_path)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_role_serdes_interrupt():
|
||||
role_a = RoleA()
|
||||
shutil.rmtree(serdes_path.joinpath("team"), ignore_errors=True)
|
||||
|
||||
stg_path = serdes_path.joinpath(f"team/environment/roles/{role_a.__class__.__name__}_{role_a.name}")
|
||||
await role_a.run(
|
||||
message=Message(content="demo", cause_by=BossRequirement),
|
||||
stg_path=stg_path
|
||||
)
|
||||
assert role_a._rc.memory.count() == 2
|
||||
|
||||
assert stg_path.joinpath("actions/todo.json").exists()
|
||||
|
||||
new_role_a: Role = Role.deserialize(stg_path)
|
||||
assert new_role_a._rc.state == 1
|
||||
await role_a.run(
|
||||
message=Message(content="demo", cause_by=BossRequirement),
|
||||
stg_path=stg_path
|
||||
)
|
||||
|
||||
def test_role_desc():
|
||||
role = Role(profile="Sales", desc="Best Seller")
|
||||
assert role.profile == "Sales"
|
||||
assert role._setting.desc == "Best Seller"
|
||||
|
|
|
|||
49
tests/metagpt/serialize_deserialize/test_action.py
Normal file
49
tests/metagpt/serialize_deserialize/test_action.py
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# @Date : 11/22/2023 11:48 AM
|
||||
# @Author : stellahong (stellahong@fuzhi.ai)
|
||||
# @Desc :
|
||||
import pytest
|
||||
|
||||
from metagpt.actions import Action, WritePRD, WriteTest
|
||||
from metagpt.llm import LLM
|
||||
from metagpt.provider.openai_api import OpenAIGPTAPI
|
||||
|
||||
|
||||
def test_action_serialize():
|
||||
action = Action()
|
||||
ser_action_dict = action.dict()
|
||||
assert "name" in ser_action_dict
|
||||
assert "llm" in ser_action_dict
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_action_deserialize():
|
||||
action = Action()
|
||||
serialized_data = action.dict()
|
||||
assert isinstance(serialized_data["llm"], OpenAIGPTAPI)
|
||||
|
||||
new_action = Action(**serialized_data)
|
||||
|
||||
assert new_action.name == ""
|
||||
assert new_action.llm == LLM()
|
||||
assert len(await new_action._aask("who are you")) > 0
|
||||
|
||||
|
||||
def test_action_serdeser():
|
||||
action_info = WriteTest.ser_class()
|
||||
assert action_info["action_class"] == "WriteTest"
|
||||
|
||||
action_class = Action.deser_class(action_info)
|
||||
assert action_class == WriteTest
|
||||
|
||||
|
||||
def test_action_class_serdeser():
|
||||
name = "write test"
|
||||
action_info = WriteTest(name=name).serialize()
|
||||
assert action_info["name"] == name
|
||||
|
||||
action_info = WriteTest(name=name, llm=LLM()).serialize()
|
||||
assert action_info["name"] == name
|
||||
|
||||
action = Action.deserialize(action_info)
|
||||
assert action.name == name
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# @Date : 11/22/2023 11:48 AM
|
||||
# @Author : stellahong (stellahong@fuzhi.ai)
|
||||
# @Desc :
|
||||
import pytest
|
||||
|
||||
from metagpt.actions import Action
|
||||
from metagpt.llm import LLM
|
||||
|
||||
|
||||
def test_action_serialize():
|
||||
action = Action()
|
||||
ser_action_dict = action.dict()
|
||||
assert "name" in ser_action_dict
|
||||
assert "llm" in ser_action_dict
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_action_deserialize():
|
||||
action = Action()
|
||||
serialized_data = action.dict()
|
||||
|
||||
new_action = Action(**serialized_data)
|
||||
assert new_action.name == ""
|
||||
assert new_action.llm == LLM()
|
||||
assert len(await new_action._aask("who are you")) > 0
|
||||
|
|
@ -25,4 +25,4 @@ async def test_architect_deserialize():
|
|||
assert new_role.name == "Bob"
|
||||
assert len(new_role._actions) == 1
|
||||
assert isinstance(new_role._actions[0], Action)
|
||||
await new_role._actions[0].run(context="write a cli snake game")
|
||||
await new_role._actions[0].run(context="write a cli snake game")
|
||||
|
|
|
|||
91
tests/metagpt/serialize_deserialize/test_environment.py
Normal file
91
tests/metagpt/serialize_deserialize/test_environment.py
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Desc :
|
||||
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
|
||||
from metagpt.schema import Message
|
||||
from metagpt.actions.action_output import ActionOutput
|
||||
from metagpt.roles.project_manager import ProjectManager
|
||||
from metagpt.actions.add_requirement import BossRequirement
|
||||
from metagpt.actions.project_management import WriteTasks
|
||||
from metagpt.environment import Environment
|
||||
from tests.metagpt.serialize_deserialize.test_serdeser_base import RoleC, ActionOK, serdeser_path
|
||||
|
||||
|
||||
def test_env_serialize():
|
||||
env = Environment()
|
||||
ser_env_dict = env.dict()
|
||||
assert "roles" in ser_env_dict
|
||||
assert "memory" in ser_env_dict
|
||||
|
||||
|
||||
def test_env_deserialize():
|
||||
env = Environment()
|
||||
env.publish_message(message=Message(content="test env serialize"))
|
||||
ser_env_dict = env.dict()
|
||||
new_env = Environment(**ser_env_dict)
|
||||
assert len(new_env.roles) == 0
|
||||
assert new_env.memory.storage[0].content == "test env serialize"
|
||||
assert len(new_env.history) == 25
|
||||
|
||||
|
||||
def test_environment_serdeser():
|
||||
out_mapping = {"field1": (list[str], ...)}
|
||||
out_data = {"field1": ["field1 value1", "field1 value2"]}
|
||||
ic_obj = ActionOutput.create_model_class("prd", out_mapping)
|
||||
|
||||
message = Message(
|
||||
content="prd",
|
||||
instruct_content=ic_obj(**out_data),
|
||||
role="product manager",
|
||||
cause_by=BossRequirement
|
||||
)
|
||||
|
||||
environment = Environment()
|
||||
role_c = RoleC()
|
||||
environment.add_role(role_c)
|
||||
environment.publish_message(message)
|
||||
|
||||
ser_data = environment.dict()
|
||||
assert ser_data["roles"]["Role C"]["name"] == "RoleC"
|
||||
|
||||
new_env: Environment = Environment(**ser_data)
|
||||
assert len(new_env.roles) == 1
|
||||
|
||||
assert new_env.memory.count() == 1
|
||||
assert new_env.memory.storage[0].instruct_content == ic_obj(**out_data)
|
||||
assert list(new_env.roles.values())[0]._states == list(environment.roles.values())[0]._states
|
||||
assert list(new_env.roles.values())[0]._actions == list(environment.roles.values())[0]._actions
|
||||
assert isinstance(list(environment.roles.values())[0]._actions[0], ActionOK)
|
||||
assert type(list(new_env.roles.values())[0]._actions[0]) == ActionOK
|
||||
|
||||
|
||||
def test_environment_serdeser_v2():
|
||||
environment = Environment()
|
||||
pm = ProjectManager()
|
||||
environment.add_role(pm)
|
||||
|
||||
ser_data = environment.dict()
|
||||
|
||||
new_env: Environment = Environment(**ser_data)
|
||||
role = new_env.get_role(pm.profile)
|
||||
assert isinstance(role, ProjectManager)
|
||||
assert isinstance(role._actions[0], WriteTasks)
|
||||
assert isinstance(list(new_env.roles.values())[0]._actions[0], WriteTasks)
|
||||
|
||||
|
||||
def test_environment_serdeser_save():
|
||||
environment = Environment()
|
||||
role_c = RoleC()
|
||||
|
||||
shutil.rmtree(serdeser_path.joinpath("team"), ignore_errors=True)
|
||||
|
||||
stg_path = serdeser_path.joinpath("team/environment")
|
||||
environment.add_role(role_c)
|
||||
environment.serialize(stg_path)
|
||||
|
||||
new_env: Environment = Environment.deserialize(stg_path)
|
||||
assert len(new_env.roles) == 1
|
||||
assert type(list(new_env.roles.values())[0]._actions[0]) == ActionOK
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
# @Desc : unittest of memory
|
||||
|
||||
from pathlib import Path
|
||||
from pydantic import BaseModel
|
||||
|
||||
from metagpt.schema import Message
|
||||
from metagpt.memory.memory import Memory
|
||||
|
|
@ -10,10 +11,36 @@ from metagpt.actions.action_output import ActionOutput
|
|||
from metagpt.actions.design_api import WriteDesign
|
||||
from metagpt.actions.add_requirement import BossRequirement
|
||||
|
||||
serdes_path = Path(__file__).absolute().parent.joinpath("../../data/serdes_storage")
|
||||
from tests.metagpt.serialize_deserialize.test_serdeser_base import serdeser_path
|
||||
|
||||
|
||||
def test_memory_serdes():
|
||||
def test_memory_serdeser():
|
||||
msg1 = Message(role="Boss",
|
||||
content="write a snake game",
|
||||
cause_by=BossRequirement)
|
||||
|
||||
out_mapping = {"field2": (list[str], ...)}
|
||||
out_data = {"field2": ["field2 value1", "field2 value2"]}
|
||||
ic_obj = ActionOutput.create_model_class("system_design", out_mapping)
|
||||
msg2 = Message(role="Architect",
|
||||
instruct_content=ic_obj(**out_data),
|
||||
content="system design content",
|
||||
cause_by=WriteDesign)
|
||||
|
||||
memory = Memory()
|
||||
memory.add_batch([msg1, msg2])
|
||||
ser_data = memory.dict()
|
||||
|
||||
new_memory = Memory(**ser_data)
|
||||
assert new_memory.count() == 2
|
||||
new_msg2 = new_memory.get(2)[0]
|
||||
assert isinstance(new_msg2, BaseModel)
|
||||
assert isinstance(new_memory.storage[-1], BaseModel)
|
||||
assert new_memory.storage[-1].cause_by == WriteDesign
|
||||
assert new_msg2.role == "Boss"
|
||||
|
||||
|
||||
def test_memory_serdeser_save():
|
||||
msg1 = Message(role="User",
|
||||
content="write a 2048 game",
|
||||
cause_by=BossRequirement)
|
||||
|
|
@ -29,7 +56,7 @@ def test_memory_serdes():
|
|||
memory = Memory()
|
||||
memory.add_batch([msg1, msg2])
|
||||
|
||||
stg_path = serdes_path.joinpath("team/environment")
|
||||
stg_path = serdeser_path.joinpath("team/environment")
|
||||
memory.serialize(stg_path)
|
||||
assert stg_path.joinpath("memory.json").exists()
|
||||
|
||||
|
|
@ -38,5 +65,6 @@ def test_memory_serdes():
|
|||
new_msg2 = new_memory.get(1)[0]
|
||||
assert new_msg2.instruct_content.field1 == ["field1 value1", "field1 value2"]
|
||||
assert new_msg2.cause_by == WriteDesign
|
||||
assert len(new_memory.index) == 2
|
||||
|
||||
stg_path.joinpath("memory.json").unlink()
|
||||
|
|
@ -15,8 +15,8 @@ async def test_product_manager_deserialize():
|
|||
ser_role_dict = role.dict(by_alias=True)
|
||||
new_role = ProductManager(**ser_role_dict)
|
||||
# new_role = ProductManager().deserialize(ser_role_dict)
|
||||
|
||||
|
||||
assert new_role.name == "Alice"
|
||||
assert len(new_role._actions) == 1
|
||||
assert isinstance(new_role._actions[0], Action)
|
||||
await new_role._actions[0].run([Message(content="write a cli snake game")])
|
||||
await new_role._actions[0].run([Message(content="write a cli snake game")])
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import pytest
|
|||
|
||||
from metagpt.roles.project_manager import ProjectManager
|
||||
from metagpt.actions.action import Action
|
||||
from metagpt.actions.project_management import WriteTasks
|
||||
|
||||
|
||||
def test_project_manager_serialize():
|
||||
|
|
@ -20,9 +21,10 @@ def test_project_manager_serialize():
|
|||
async def test_project_manager_deserialize():
|
||||
role = ProjectManager()
|
||||
ser_role_dict = role.dict(by_alias=True)
|
||||
|
||||
new_role = ProjectManager(**ser_role_dict)
|
||||
# new_role = ProjectManager().deserialize(ser_role_dict)
|
||||
assert new_role.name == "Eve"
|
||||
assert len(new_role._actions) == 1
|
||||
assert isinstance(new_role._actions[0], Action)
|
||||
await new_role._actions[0].run(context="write a cli snake game")
|
||||
assert isinstance(new_role._actions[0], WriteTasks)
|
||||
# await new_role._actions[0].run(context="write a cli snake game")
|
||||
|
|
|
|||
|
|
@ -2,12 +2,22 @@
|
|||
# @Date : 11/23/2023 4:49 PM
|
||||
# @Author : stellahong (stellahong@fuzhi.ai)
|
||||
# @Desc :
|
||||
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import pytest
|
||||
|
||||
from metagpt.logs import logger
|
||||
from metagpt.roles.role import Role
|
||||
from metagpt.actions import WriteCode, WriteCodeReview
|
||||
from metagpt.schema import Message
|
||||
from metagpt.actions.add_requirement import BossRequirement
|
||||
from metagpt.roles.product_manager import ProductManager
|
||||
from metagpt.const import SERDESER_PATH
|
||||
from metagpt.roles.engineer import Engineer
|
||||
from metagpt.utils.utils import format_trackback_info
|
||||
|
||||
from metagpt.actions.action import Action
|
||||
from tests.metagpt.serialize_deserialize.test_serdeser_base import RoleC, serdeser_path
|
||||
|
||||
|
||||
def test_role_serialize():
|
||||
|
|
@ -30,12 +40,53 @@ def test_engineer_serialize():
|
|||
async def test_engineer_deserialize():
|
||||
role = Engineer(use_code_review=True)
|
||||
ser_role_dict = role.dict(by_alias=True)
|
||||
# new_role = Engineer().deserialize(ser_role_dict)
|
||||
# also can be deserialized in this way:
|
||||
|
||||
new_role = Engineer(**ser_role_dict)
|
||||
assert new_role.name == "Alex"
|
||||
assert new_role.use_code_review is True
|
||||
assert len(new_role._actions) == 2
|
||||
assert isinstance(new_role._actions[0], Action)
|
||||
assert isinstance(new_role._actions[1], Action)
|
||||
await new_role._actions[0].run(context="write a cli snake game", filename="test_code")
|
||||
assert isinstance(new_role._actions[0], WriteCode)
|
||||
assert isinstance(new_role._actions[1], WriteCodeReview)
|
||||
# await new_role._actions[0].run(context="write a cli snake game", filename="test_code")
|
||||
|
||||
|
||||
def test_role_serdeser_save():
|
||||
stg_path_prefix = serdeser_path.joinpath("team/environment/roles/")
|
||||
shutil.rmtree(serdeser_path.joinpath("team"), ignore_errors=True)
|
||||
|
||||
pm = ProductManager()
|
||||
role_tag = f"{pm.__class__.__name__}_{pm.name}"
|
||||
stg_path = stg_path_prefix.joinpath(role_tag)
|
||||
pm.serialize(stg_path)
|
||||
assert stg_path.joinpath("actions/actions_info.json").exists()
|
||||
|
||||
new_pm = Role.deserialize(stg_path)
|
||||
assert new_pm.name == pm.name
|
||||
assert len(new_pm.get_memories(1)) == 0
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_role_serdeser_interrupt():
|
||||
role_c = RoleC()
|
||||
shutil.rmtree(SERDESER_PATH.joinpath("team"), ignore_errors=True)
|
||||
|
||||
stg_path = SERDESER_PATH.joinpath(f"team/environment/roles/{role_c.__class__.__name__}_{role_c.name}")
|
||||
try:
|
||||
await role_c.run(
|
||||
message=Message(content="demo", cause_by=BossRequirement)
|
||||
)
|
||||
except Exception as exp:
|
||||
logger.error(f"Exception in `role_a.run`, detail: {format_trackback_info()}")
|
||||
role_c.serialize(stg_path)
|
||||
|
||||
assert role_c._rc.memory.count() == 2
|
||||
|
||||
assert stg_path.joinpath("actions/todo.json").exists()
|
||||
|
||||
new_role_a: Role = Role.deserialize(stg_path)
|
||||
assert new_role_a._rc.state == 1
|
||||
|
||||
with pytest.raises(Exception):
|
||||
await role_c.run(
|
||||
message=Message(content="demo", cause_by=BossRequirement)
|
||||
)
|
||||
|
|
|
|||
49
tests/metagpt/serialize_deserialize/test_schema.py
Normal file
49
tests/metagpt/serialize_deserialize/test_schema.py
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Desc : unittest of schema ser&deser
|
||||
|
||||
from metagpt.schema import Message
|
||||
from metagpt.actions.action_output import ActionOutput
|
||||
from metagpt.actions.write_code import WriteCode
|
||||
|
||||
from tests.metagpt.serialize_deserialize.test_serdeser_base import MockMessage
|
||||
|
||||
|
||||
def test_message_serdeser():
|
||||
out_mapping = {"field3": (str, ...), "field4": (list[str], ...)}
|
||||
out_data = {"field3": "field3 value3", "field4": ["field4 value1", "field4 value2"]}
|
||||
ic_obj = ActionOutput.create_model_class("code", out_mapping)
|
||||
|
||||
message = Message(
|
||||
content="code",
|
||||
instruct_content=ic_obj(**out_data),
|
||||
role="engineer",
|
||||
cause_by=WriteCode
|
||||
)
|
||||
ser_data = message.dict()
|
||||
assert ser_data["cause_by"] == {
|
||||
"action_class": "WriteCode",
|
||||
"module_name": "metagpt.actions.write_code"
|
||||
}
|
||||
assert ser_data["instruct_content"]["class"] == "code"
|
||||
|
||||
new_message = Message(**ser_data)
|
||||
assert new_message.cause_by == WriteCode
|
||||
assert new_message.cause_by in [WriteCode]
|
||||
assert new_message.instruct_content == ic_obj(**out_data)
|
||||
|
||||
|
||||
def test_message_without_postprocess():
|
||||
""" to explain `instruct_content` should be postprocessed """
|
||||
out_mapping = {"field1": (list[str], ...)}
|
||||
out_data = {"field1": ["field1 value1", "field1 value2"]}
|
||||
ic_obj = ActionOutput.create_model_class("code", out_mapping)
|
||||
message = MockMessage(
|
||||
content="code",
|
||||
instruct_content=ic_obj(**out_data)
|
||||
)
|
||||
ser_data = message.dict()
|
||||
assert ser_data["instruct_content"] == {"field1": ["field1 value1", "field1 value2"]}
|
||||
|
||||
new_message = MockMessage(**ser_data)
|
||||
assert new_message.instruct_content != ic_obj(**out_data)
|
||||
88
tests/metagpt/serialize_deserialize/test_serdeser_base.py
Normal file
88
tests/metagpt/serialize_deserialize/test_serdeser_base.py
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Desc : base test actions / roles used in unittest
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
from pathlib import Path
|
||||
|
||||
from metagpt.actions.action import Action
|
||||
from metagpt.roles.role import Role, RoleReactMode
|
||||
from metagpt.actions.add_requirement import BossRequirement
|
||||
|
||||
|
||||
serdeser_path = Path(__file__).absolute().parent.joinpath("../../data/serdeser_storage")
|
||||
|
||||
|
||||
class MockMessage(BaseModel):
|
||||
""" to test normal dict without postprocess """
|
||||
content: str = ""
|
||||
instruct_content: BaseModel = Field(default=None)
|
||||
|
||||
|
||||
class ActionPass(Action):
|
||||
name: str = "ActionPass"
|
||||
|
||||
async def run(self, messages: list["Message"]):
|
||||
return "pass"
|
||||
|
||||
|
||||
class ActionOK(Action):
|
||||
name: str = "ActionOK"
|
||||
|
||||
async def run(self, messages: list["Message"]):
|
||||
return "ok"
|
||||
|
||||
|
||||
class ActionRaise(Action):
|
||||
name: str = "ActionRaise"
|
||||
|
||||
async def run(self, messages: list["Message"]):
|
||||
raise RuntimeError("parse error in ActionRaise")
|
||||
|
||||
|
||||
class RoleA(Role):
|
||||
|
||||
name: str = Field(default="RoleA")
|
||||
profile: str = Field(default="Role A")
|
||||
goal: str = "RoleA's goal"
|
||||
constraints: str = "RoleA's constraints"
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(RoleA, self).__init__(**kwargs)
|
||||
self._init_actions([ActionPass])
|
||||
self._watch([BossRequirement])
|
||||
|
||||
async def run(self, message: "Message" = None):
|
||||
await super(RoleA, self).run(message)
|
||||
|
||||
|
||||
class RoleB(Role):
|
||||
name: str = Field(default="RoleB")
|
||||
profile: str = Field(default="Role B")
|
||||
goal: str = "RoleB's goal"
|
||||
constraints: str = "RoleB's constraints"
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(RoleB, self).__init__(**kwargs)
|
||||
self._init_actions([ActionOK, ActionRaise])
|
||||
self._watch([ActionPass])
|
||||
self._rc.react_mode = RoleReactMode.BY_ORDER
|
||||
|
||||
async def run(self, message: "Message" = None):
|
||||
await super(RoleB, self).run(message)
|
||||
|
||||
|
||||
class RoleC(Role):
|
||||
name: str = Field(default="RoleC")
|
||||
profile: str = Field(default="Role C")
|
||||
goal: str = "RoleC's goal"
|
||||
constraints: str = "RoleC's constraints"
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(RoleC, self).__init__(**kwargs)
|
||||
self._init_actions([ActionOK, ActionRaise])
|
||||
self._watch([BossRequirement])
|
||||
self._rc.react_mode = RoleReactMode.BY_ORDER
|
||||
|
||||
async def run(self, message: "Message" = None):
|
||||
await super(RoleC, self).run(message)
|
||||
|
|
@ -2,46 +2,104 @@
|
|||
# @Date : 11/27/2023 10:07 AM
|
||||
# @Author : stellahong (stellahong@fuzhi.ai)
|
||||
# @Desc :
|
||||
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import pytest
|
||||
|
||||
from metagpt.environment import Environment
|
||||
from metagpt.schema import Message
|
||||
from metagpt.software_company import SoftwareCompany
|
||||
from metagpt.roles import ProjectManager, ProductManager, Architect
|
||||
from metagpt.team import Team
|
||||
from metagpt.const import SERDESER_PATH
|
||||
|
||||
from tests.metagpt.serialize_deserialize.test_serdeser_base import RoleA, RoleB, RoleC, serdeser_path
|
||||
|
||||
|
||||
def test_env_serialize():
|
||||
env = Environment()
|
||||
ser_env_dict = env.dict()
|
||||
assert "roles" in ser_env_dict
|
||||
assert "memory" in ser_env_dict
|
||||
assert "memory" in ser_env_dict
|
||||
def test_team_deserialize():
|
||||
company = Team()
|
||||
|
||||
|
||||
def test_env_deserialize():
|
||||
env = Environment()
|
||||
env.publish_message(message=Message(content="test env serialize"))
|
||||
ser_env_dict = env.dict()
|
||||
new_env = Environment(**ser_env_dict)
|
||||
assert len(new_env.roles) == 0
|
||||
assert new_env.memory.storage[0].content == "test env serialize"
|
||||
assert len(new_env.history) == 25
|
||||
|
||||
|
||||
def test_softwarecompany_deserialize():
|
||||
team = SoftwareCompany()
|
||||
team.hire(
|
||||
pm = ProductManager()
|
||||
arch = Architect()
|
||||
company.hire(
|
||||
[
|
||||
ProductManager(),
|
||||
Architect(),
|
||||
pm,
|
||||
arch,
|
||||
ProjectManager(),
|
||||
]
|
||||
)
|
||||
assert len(team.environment.get_roles()) == 3
|
||||
ser_team_dict = team.dict()
|
||||
new_team = SoftwareCompany(**ser_team_dict)
|
||||
|
||||
assert len(new_team.environment.get_roles()) == 3
|
||||
assert new_team.environment.get_role('Product Manager') is not None
|
||||
assert new_team.environment.get_role('Product Manager') is not None
|
||||
assert new_team.environment.get_role('Architect') is not None
|
||||
assert len(company.environment.get_roles()) == 3
|
||||
ser_company = company.dict()
|
||||
new_company = Team(**ser_company)
|
||||
|
||||
assert len(new_company.environment.get_roles()) == 3
|
||||
assert new_company.environment.get_role(pm.profile) is not None
|
||||
|
||||
new_pm = new_company.environment.get_role(pm.profile)
|
||||
assert type(new_pm) == ProductManager
|
||||
assert new_company.environment.get_role(pm.profile) is not None
|
||||
assert new_company.environment.get_role(arch.profile) is not None
|
||||
|
||||
|
||||
def test_team_serdeser():
|
||||
company = Team()
|
||||
company.hire([RoleC()])
|
||||
|
||||
stg_path = serdeser_path.joinpath("team")
|
||||
shutil.rmtree(stg_path, ignore_errors=True)
|
||||
|
||||
company.serialize(stg_path=stg_path)
|
||||
|
||||
new_company = Team.deserialize(stg_path)
|
||||
|
||||
assert len(new_company.environment.roles) == 1
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_team_recover():
|
||||
idea = "write a snake game"
|
||||
stg_path = SERDESER_PATH.joinpath("team")
|
||||
shutil.rmtree(stg_path, ignore_errors=True)
|
||||
|
||||
company = Team()
|
||||
company.hire([RoleC()])
|
||||
company.start_project(idea)
|
||||
await company.run(n_round=4)
|
||||
|
||||
ser_data = company.dict()
|
||||
new_company = Team(**ser_data)
|
||||
assert new_company.environment.memory.count() == 1
|
||||
assert type(list(new_company.environment.roles.values())[0]._actions[0]) == ActionOK
|
||||
|
||||
new_company.start_project(idea)
|
||||
await new_company.run(n_round=4)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_team_recover_save():
|
||||
idea = "write a 2048 web game"
|
||||
stg_path = SERDESER_PATH.joinpath("team")
|
||||
shutil.rmtree(stg_path, ignore_errors=True)
|
||||
|
||||
company = Team()
|
||||
company.hire([RoleC()])
|
||||
company.start_project(idea)
|
||||
await company.run(n_round=4)
|
||||
|
||||
new_company = Team.recover(stg_path)
|
||||
new_company.start_project(idea)
|
||||
await new_company.run(n_round=4)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_team_recover_multi_roles_save():
|
||||
idea = "write a snake game"
|
||||
stg_path = SERDESER_PATH.joinpath("team")
|
||||
shutil.rmtree(stg_path, ignore_errors=True)
|
||||
|
||||
company = Team()
|
||||
company.hire([RoleA(), RoleB()])
|
||||
company.start_project(idea)
|
||||
await company.run(n_round=4)
|
||||
|
||||
new_company = Team.recover(stg_path)
|
||||
new_company.start_project(idea)
|
||||
await new_company.run(n_round=4)
|
||||
|
|
|
|||
|
|
@ -25,4 +25,3 @@ async def test_action_deserialize():
|
|||
assert new_action.name == ""
|
||||
assert new_action.llm == LLM()
|
||||
assert len(await new_action.run([Message(content="write a cli snake game")])) > 0
|
||||
|
||||
|
|
|
|||
|
|
@ -43,4 +43,4 @@ async def test_write_code_review_deserialize():
|
|||
|
||||
assert new_action.name == "WriteCodeReview"
|
||||
assert new_action.llm == LLM()
|
||||
await new_action.run(context="write a cli snake game", code =code, filename="test_rewrite_code")
|
||||
await new_action.run(context="write a cli snake game", code=code, filename="test_rewrite_code")
|
||||
|
|
|
|||
|
|
@ -8,17 +8,15 @@
|
|||
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
|
||||
from metagpt.actions import BossRequirement
|
||||
from metagpt.environment import Environment
|
||||
from metagpt.logs import logger
|
||||
from metagpt.roles import Architect, ProductManager, Role
|
||||
from metagpt.schema import Message
|
||||
from tests.metagpt.roles.test_role import RoleA
|
||||
|
||||
|
||||
serdes_path = Path(__file__).absolute().parent.joinpath("../data/serdes_storage")
|
||||
serdeser_path = Path(__file__).absolute().parent.joinpath("../data/serdeser_storage")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
@ -27,14 +25,23 @@ def env():
|
|||
|
||||
|
||||
def test_add_role(env: Environment):
|
||||
role = ProductManager("Alice", "product manager", "create a new product", "limited resources")
|
||||
role = ProductManager(name="Alice",
|
||||
profile="product manager",
|
||||
goal="create a new product",
|
||||
constraints="limited resources")
|
||||
env.add_role(role)
|
||||
assert env.get_role(role.profile) == role
|
||||
|
||||
|
||||
def test_get_roles(env: Environment):
|
||||
role1 = Role("Alice", "product manager", "create a new product", "limited resources")
|
||||
role2 = Role("Bob", "engineer", "develop the new product", "short deadline")
|
||||
role1 = Role(name="Alice",
|
||||
profile="product manager",
|
||||
goal="create a new product",
|
||||
constraints="limited resources")
|
||||
role2 = Role(name="Bob",
|
||||
profile="engineer",
|
||||
goal="develop the new product",
|
||||
constraints="short deadline")
|
||||
env.add_role(role1)
|
||||
env.add_role(role2)
|
||||
roles = env.get_roles()
|
||||
|
|
@ -43,8 +50,14 @@ def test_get_roles(env: Environment):
|
|||
|
||||
@pytest.mark.asyncio
|
||||
async def test_publish_and_process_message(env: Environment):
|
||||
product_manager = ProductManager("Alice", "Product Manager", "做AI Native产品", "资源有限")
|
||||
architect = Architect("Bob", "Architect", "设计一个可用、高效、较低成本的系统,包括数据结构与接口", "资源有限,需要节省成本")
|
||||
product_manager = ProductManager(name="Alice",
|
||||
profile="Product Manager",
|
||||
goal="做AI Native产品",
|
||||
constraints="资源有限")
|
||||
architect = Architect(name="Bob",
|
||||
profile="Architect",
|
||||
goal="设计一个可用、高效、较低成本的系统,包括数据结构与接口",
|
||||
constraints="资源有限,需要节省成本")
|
||||
|
||||
env.add_roles([product_manager, architect])
|
||||
env.publish_message(Message(role="BOSS", content="需要一个基于LLM做总结的搜索引擎", cause_by=BossRequirement))
|
||||
|
|
@ -52,18 +65,3 @@ async def test_publish_and_process_message(env: Environment):
|
|||
await env.run(k=2)
|
||||
logger.info(f"{env.history=}")
|
||||
assert len(env.history) > 10
|
||||
|
||||
|
||||
def test_environment_serdes():
|
||||
environment = Environment()
|
||||
role_a = RoleA()
|
||||
|
||||
shutil.rmtree(serdes_path.joinpath("team"), ignore_errors=True)
|
||||
|
||||
stg_path = serdes_path.joinpath("team/environment")
|
||||
environment.add_role(role_a)
|
||||
environment.serialize(stg_path)
|
||||
|
||||
new_env: Environment = Environment()
|
||||
new_env.deserialize(stg_path)
|
||||
assert len(new_env.roles) == 1
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
@Time : 2023/5/11 14:44
|
||||
@Author : alexanderwu
|
||||
@File : test_role.py
|
||||
"""
|
||||
from metagpt.roles import Role
|
||||
|
||||
|
||||
def test_role_desc():
|
||||
i = Role(profile='Sales', desc='Best Seller')
|
||||
assert i.profile == 'Sales'
|
||||
assert i._setting.desc == 'Best Seller'
|
||||
|
|
@ -25,7 +25,7 @@ def test_messages():
|
|||
assert all([i in text for i in roles])
|
||||
|
||||
|
||||
def test_message_serdes():
|
||||
def test_message_serdeser():
|
||||
out_mapping = {"field3": (str, ...), "field4": (list[str], ...)}
|
||||
out_data = {"field3": "field3 value3", "field4": ["field4 value1", "field4 value2"]}
|
||||
ic_obj = ActionOutput.create_model_class("code", out_mapping)
|
||||
|
|
@ -37,7 +37,7 @@ def test_message_serdes():
|
|||
cause_by=WriteCode
|
||||
)
|
||||
message_dict = serialize_general_message(message)
|
||||
assert message_dict["cause_by"] == {"action_class": "WriteCode"}
|
||||
assert message_dict["cause_by"] == {"action_class": "WriteCode", "module_name": "metagpt.actions.write_code"}
|
||||
assert message_dict["instruct_content"] == {
|
||||
"class": "code",
|
||||
"mapping": {
|
||||
|
|
|
|||
|
|
@ -2,26 +2,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# @Desc : unittest of team
|
||||
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
|
||||
from metagpt.team import Team
|
||||
|
||||
from tests.metagpt.roles.test_role import RoleA
|
||||
|
||||
serdes_path = Path(__file__).absolute().parent.joinpath("../data/serdes_storage")
|
||||
from metagpt.roles.project_manager import ProjectManager
|
||||
|
||||
|
||||
def test_team_serdes():
|
||||
def test_team():
|
||||
company = Team()
|
||||
company.hire([RoleA()])
|
||||
company.hire([ProjectManager()])
|
||||
|
||||
stg_path = serdes_path.joinpath("team")
|
||||
shutil.rmtree(stg_path, ignore_errors=True)
|
||||
|
||||
company.serialize(stg_path=stg_path)
|
||||
|
||||
new_company = Team()
|
||||
new_company.deserialize(stg_path)
|
||||
|
||||
assert len(new_company.environment.roles) == 1
|
||||
assert len(company.environment.roles) == 1
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue