mirror of
https://github.com/FoundationAgents/MetaGPT.git
synced 2026-05-15 11:02:36 +02:00
refactor: Refactor Message transmission & filtering
This commit is contained in:
parent
5e8ada5cff
commit
545d77ce0d
30 changed files with 658 additions and 296 deletions
|
|
@ -4,6 +4,7 @@
|
|||
@Time : 2023/5/11 17:45
|
||||
@Author : alexanderwu
|
||||
@File : test_write_prd.py
|
||||
@Modified By: mashenquan, 2023-11-1. Standardize the usage of message filtering-related features.
|
||||
"""
|
||||
import pytest
|
||||
|
||||
|
|
@ -17,7 +18,7 @@ from metagpt.schema import Message
|
|||
async def test_write_prd():
|
||||
product_manager = ProductManager()
|
||||
requirements = "开发一个基于大语言模型与私有知识库的搜索引擎,希望可以基于大语言模型进行搜索总结"
|
||||
prd = await product_manager.handle(Message(content=requirements, cause_by=BossRequirement))
|
||||
prd = await product_manager.handle(Message(content=requirements, cause_by=BossRequirement.get_class_name()))
|
||||
logger.info(requirements)
|
||||
logger.info(prd)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Desc : unittest of `metagpt/memory/longterm_memory.py`
|
||||
"""
|
||||
@Desc : unittest of `metagpt/memory/longterm_memory.py`
|
||||
@Modified By: mashenquan, 2023-11-1. Standardize the usage of message filtering-related features.
|
||||
"""
|
||||
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.schema import Message
|
||||
from metagpt.actions import BossRequirement
|
||||
from metagpt.roles.role import RoleContext
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.memory import LongTermMemory
|
||||
from metagpt.roles.role import RoleContext
|
||||
from metagpt.schema import Message
|
||||
|
||||
|
||||
def test_ltm_search():
|
||||
|
|
@ -14,25 +17,25 @@ def test_ltm_search():
|
|||
openai_api_key = CONFIG.openai_api_key
|
||||
assert len(openai_api_key) > 20
|
||||
|
||||
role_id = 'UTUserLtm(Product Manager)'
|
||||
rc = RoleContext(watch=[BossRequirement])
|
||||
role_id = "UTUserLtm(Product Manager)"
|
||||
rc = RoleContext(watch=[BossRequirement.get_class_name()])
|
||||
ltm = LongTermMemory()
|
||||
ltm.recover_memory(role_id, rc)
|
||||
|
||||
idea = 'Write a cli snake game'
|
||||
message = Message(role='BOSS', content=idea, cause_by=BossRequirement)
|
||||
idea = "Write a cli snake game"
|
||||
message = Message(role="BOSS", content=idea, cause_by=BossRequirement.get_class_name())
|
||||
news = ltm.find_news([message])
|
||||
assert len(news) == 1
|
||||
ltm.add(message)
|
||||
|
||||
sim_idea = 'Write a game of cli snake'
|
||||
sim_message = Message(role='BOSS', content=sim_idea, cause_by=BossRequirement)
|
||||
sim_idea = "Write a game of cli snake"
|
||||
sim_message = Message(role="BOSS", content=sim_idea, cause_by=BossRequirement.get_class_name())
|
||||
news = ltm.find_news([sim_message])
|
||||
assert len(news) == 0
|
||||
ltm.add(sim_message)
|
||||
|
||||
new_idea = 'Write a 2048 web game'
|
||||
new_message = Message(role='BOSS', content=new_idea, cause_by=BossRequirement)
|
||||
new_idea = "Write a 2048 web game"
|
||||
new_message = Message(role="BOSS", content=new_idea, cause_by=BossRequirement.get_class_name())
|
||||
news = ltm.find_news([new_message])
|
||||
assert len(news) == 1
|
||||
ltm.add(new_message)
|
||||
|
|
@ -47,8 +50,8 @@ def test_ltm_search():
|
|||
news = ltm_new.find_news([sim_message])
|
||||
assert len(news) == 0
|
||||
|
||||
new_idea = 'Write a Battle City'
|
||||
new_message = Message(role='BOSS', content=new_idea, cause_by=BossRequirement)
|
||||
new_idea = "Write a Battle City"
|
||||
new_message = Message(role="BOSS", content=new_idea, cause_by=BossRequirement.get_class_name())
|
||||
news = ltm_new.find_news([new_message])
|
||||
assert len(news) == 1
|
||||
|
||||
|
|
|
|||
|
|
@ -1,20 +1,23 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Desc : the unittests of metagpt/memory/memory_storage.py
|
||||
"""
|
||||
@Desc : the unittests of metagpt/memory/memory_storage.py
|
||||
@Modified By: mashenquan, 2023-11-1. Standardize the usage of message filtering-related features.
|
||||
"""
|
||||
|
||||
|
||||
from typing import List
|
||||
|
||||
from metagpt.actions import BossRequirement, WritePRD
|
||||
from metagpt.actions.action_output import ActionOutput
|
||||
from metagpt.memory.memory_storage import MemoryStorage
|
||||
from metagpt.schema import Message
|
||||
from metagpt.actions import BossRequirement
|
||||
from metagpt.actions import WritePRD
|
||||
from metagpt.actions.action_output import ActionOutput
|
||||
|
||||
|
||||
def test_idea_message():
|
||||
idea = 'Write a cli snake game'
|
||||
role_id = 'UTUser1(Product Manager)'
|
||||
message = Message(role='BOSS', content=idea, cause_by=BossRequirement)
|
||||
idea = "Write a cli snake game"
|
||||
role_id = "UTUser1(Product Manager)"
|
||||
message = Message(role="BOSS", content=idea, cause_by=BossRequirement.get_class_name())
|
||||
|
||||
memory_storage: MemoryStorage = MemoryStorage()
|
||||
messages = memory_storage.recover_memory(role_id)
|
||||
|
|
@ -23,13 +26,13 @@ def test_idea_message():
|
|||
memory_storage.add(message)
|
||||
assert memory_storage.is_initialized is True
|
||||
|
||||
sim_idea = 'Write a game of cli snake'
|
||||
sim_message = Message(role='BOSS', content=sim_idea, cause_by=BossRequirement)
|
||||
sim_idea = "Write a game of cli snake"
|
||||
sim_message = Message(role="BOSS", content=sim_idea, cause_by=BossRequirement.get_class_name())
|
||||
new_messages = memory_storage.search(sim_message)
|
||||
assert len(new_messages) == 0 # similar, return []
|
||||
assert len(new_messages) == 0 # similar, return []
|
||||
|
||||
new_idea = 'Write a 2048 web game'
|
||||
new_message = Message(role='BOSS', content=new_idea, cause_by=BossRequirement)
|
||||
new_idea = "Write a 2048 web game"
|
||||
new_message = Message(role="BOSS", content=new_idea, cause_by=BossRequirement.get_class_name())
|
||||
new_messages = memory_storage.search(new_message)
|
||||
assert new_messages[0].content == message.content
|
||||
|
||||
|
|
@ -38,22 +41,15 @@ def test_idea_message():
|
|||
|
||||
|
||||
def test_actionout_message():
|
||||
out_mapping = {
|
||||
'field1': (str, ...),
|
||||
'field2': (List[str], ...)
|
||||
}
|
||||
out_data = {
|
||||
'field1': 'field1 value',
|
||||
'field2': ['field2 value1', 'field2 value2']
|
||||
}
|
||||
ic_obj = ActionOutput.create_model_class('prd', out_mapping)
|
||||
out_mapping = {"field1": (str, ...), "field2": (List[str], ...)}
|
||||
out_data = {"field1": "field1 value", "field2": ["field2 value1", "field2 value2"]}
|
||||
ic_obj = ActionOutput.create_model_class("prd", out_mapping)
|
||||
|
||||
role_id = 'UTUser2(Architect)'
|
||||
content = 'The boss has requested the creation of a command-line interface (CLI) snake game'
|
||||
message = Message(content=content,
|
||||
instruct_content=ic_obj(**out_data),
|
||||
role='user',
|
||||
cause_by=WritePRD) # WritePRD as test action
|
||||
role_id = "UTUser2(Architect)"
|
||||
content = "The boss has requested the creation of a command-line interface (CLI) snake game"
|
||||
message = Message(
|
||||
content=content, instruct_content=ic_obj(**out_data), role="user", cause_by=WritePRD.get_class_name()
|
||||
) # WritePRD as test action
|
||||
|
||||
memory_storage: MemoryStorage = MemoryStorage()
|
||||
messages = memory_storage.recover_memory(role_id)
|
||||
|
|
@ -62,19 +58,17 @@ def test_actionout_message():
|
|||
memory_storage.add(message)
|
||||
assert memory_storage.is_initialized is True
|
||||
|
||||
sim_conent = 'The request is command-line interface (CLI) snake game'
|
||||
sim_message = Message(content=sim_conent,
|
||||
instruct_content=ic_obj(**out_data),
|
||||
role='user',
|
||||
cause_by=WritePRD)
|
||||
sim_conent = "The request is command-line interface (CLI) snake game"
|
||||
sim_message = Message(
|
||||
content=sim_conent, instruct_content=ic_obj(**out_data), role="user", cause_by=WritePRD.get_class_name()
|
||||
)
|
||||
new_messages = memory_storage.search(sim_message)
|
||||
assert len(new_messages) == 0 # similar, return []
|
||||
assert len(new_messages) == 0 # similar, return []
|
||||
|
||||
new_conent = 'Incorporate basic features of a snake game such as scoring and increasing difficulty'
|
||||
new_message = Message(content=new_conent,
|
||||
instruct_content=ic_obj(**out_data),
|
||||
role='user',
|
||||
cause_by=WritePRD)
|
||||
new_conent = "Incorporate basic features of a snake game such as scoring and increasing difficulty"
|
||||
new_message = Message(
|
||||
content=new_conent, instruct_content=ic_obj(**out_data), role="user", cause_by=WritePRD.get_class_name()
|
||||
)
|
||||
new_messages = memory_storage.search(new_message)
|
||||
assert new_messages[0].content == message.content
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@
|
|||
@Time : 2023/9/16 20:03
|
||||
@Author : femto Zheng
|
||||
@File : test_basic_planner.py
|
||||
@Modified By: mashenquan, 2023-11-1. Optimization:
|
||||
1. Standardize the usage of message filtering-related features.
|
||||
2. Standardize the usage of message transmission.
|
||||
"""
|
||||
import pytest
|
||||
from semantic_kernel.core_skills import FileIOSkill, MathSkill, TextSkill, TimeSkill
|
||||
|
|
@ -23,7 +26,7 @@ async def test_action_planner():
|
|||
role.import_skill(TimeSkill(), "time")
|
||||
role.import_skill(TextSkill(), "text")
|
||||
task = "What is the sum of 110 and 990?"
|
||||
role.recv(Message(content=task, cause_by=BossRequirement))
|
||||
|
||||
role.async_put_message(Message(content=task, cause_by=BossRequirement.get_class_name()))
|
||||
await role._observe()
|
||||
await role._think() # it will choose mathskill.Add
|
||||
assert "1100" == (await role._act()).content
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@
|
|||
@Time : 2023/9/16 20:03
|
||||
@Author : femto Zheng
|
||||
@File : test_basic_planner.py
|
||||
@Modified By: mashenquan, 2023-11-1. Optimization:
|
||||
1. Standardize the usage of message filtering-related features.
|
||||
2. Standardize the usage of message transmission.
|
||||
"""
|
||||
import pytest
|
||||
from semantic_kernel.core_skills import TextSkill
|
||||
|
|
@ -26,7 +29,8 @@ async def test_basic_planner():
|
|||
role.import_semantic_skill_from_directory(SKILL_DIRECTORY, "WriterSkill")
|
||||
role.import_skill(TextSkill(), "TextSkill")
|
||||
# using BasicPlanner
|
||||
role.recv(Message(content=task, cause_by=BossRequirement))
|
||||
role.async_put_message(Message(content=task, cause_by=BossRequirement.get_class_name()))
|
||||
await role._observe()
|
||||
await role._think()
|
||||
# assuming sk_agent will think he needs WriterSkill.Brainstorm and WriterSkill.Translate
|
||||
assert "WriterSkill.Brainstorm" in role.plan.generated_plan.result
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
@Time : 2023/5/12 13:05
|
||||
@Author : alexanderwu
|
||||
@File : mock.py
|
||||
@Modified By: mashenquan, 2023-11-1. Standardize the usage of message filtering-related features.
|
||||
"""
|
||||
from metagpt.actions import BossRequirement, WriteDesign, WritePRD, WriteTasks
|
||||
from metagpt.schema import Message
|
||||
|
|
@ -71,7 +72,7 @@ PRD = '''## 原始需求
|
|||
```
|
||||
'''
|
||||
|
||||
SYSTEM_DESIGN = '''## Python package name
|
||||
SYSTEM_DESIGN = """## Python package name
|
||||
```python
|
||||
"smart_search_engine"
|
||||
```
|
||||
|
|
@ -149,10 +150,10 @@ sequenceDiagram
|
|||
S-->>SE: return summary
|
||||
SE-->>M: return summary
|
||||
```
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
TASKS = '''## Logic Analysis
|
||||
TASKS = """## Logic Analysis
|
||||
|
||||
在这个项目中,所有的模块都依赖于“SearchEngine”类,这是主入口,其他的模块(Index、Ranking和Summary)都通过它交互。另外,"Index"类又依赖于"KnowledgeBase"类,因为它需要从知识库中获取数据。
|
||||
|
||||
|
|
@ -181,7 +182,7 @@ task_list = [
|
|||
]
|
||||
```
|
||||
这个任务列表首先定义了最基础的模块,然后是依赖这些模块的模块,最后是辅助模块。可以根据团队的能力和资源,同时开发多个任务,只要满足依赖关系。例如,在开发"search.py"之前,可以同时开发"knowledge_base.py"、"index.py"、"ranking.py"和"summary.py"。
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
TASKS_TOMATO_CLOCK = '''## Required Python third-party packages: Provided in requirements.txt format
|
||||
|
|
@ -224,35 +225,35 @@ task_list = [
|
|||
TASK = """smart_search_engine/knowledge_base.py"""
|
||||
|
||||
STRS_FOR_PARSING = [
|
||||
"""
|
||||
"""
|
||||
## 1
|
||||
```python
|
||||
a
|
||||
```
|
||||
""",
|
||||
"""
|
||||
"""
|
||||
##2
|
||||
```python
|
||||
"a"
|
||||
```
|
||||
""",
|
||||
"""
|
||||
"""
|
||||
## 3
|
||||
```python
|
||||
a = "a"
|
||||
```
|
||||
""",
|
||||
"""
|
||||
"""
|
||||
## 4
|
||||
```python
|
||||
a = 'a'
|
||||
```
|
||||
"""
|
||||
""",
|
||||
]
|
||||
|
||||
|
||||
class MockMessages:
|
||||
req = Message(role="Boss", content=BOSS_REQUIREMENT, cause_by=BossRequirement)
|
||||
prd = Message(role="Product Manager", content=PRD, cause_by=WritePRD)
|
||||
system_design = Message(role="Architect", content=SYSTEM_DESIGN, cause_by=WriteDesign)
|
||||
tasks = Message(role="Project Manager", content=TASKS, cause_by=WriteTasks)
|
||||
req = Message(role="Boss", content=BOSS_REQUIREMENT, cause_by=BossRequirement.get_class_name())
|
||||
prd = Message(role="Product Manager", content=PRD, cause_by=WritePRD.get_class_name())
|
||||
system_design = Message(role="Architect", content=SYSTEM_DESIGN, cause_by=WriteDesign.get_class_name())
|
||||
tasks = Message(role="Project Manager", content=TASKS, cause_by=WriteTasks.get_class_name())
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
@Time : 2023/5/20 14:37
|
||||
@Author : alexanderwu
|
||||
@File : test_architect.py
|
||||
@Modified By: mashenquan, 2023-11-1. Standardize the usage of message transmission.
|
||||
"""
|
||||
import pytest
|
||||
|
||||
|
|
@ -15,7 +16,7 @@ from tests.metagpt.roles.mock import MockMessages
|
|||
@pytest.mark.asyncio
|
||||
async def test_architect():
|
||||
role = Architect()
|
||||
role.recv(MockMessages.req)
|
||||
rsp = await role.handle(MockMessages.prd)
|
||||
role.async_put_message(MockMessages.req)
|
||||
rsp = await role.run(MockMessages.prd)
|
||||
logger.info(rsp)
|
||||
assert len(rsp.content) > 0
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
@Time : 2023/5/12 10:14
|
||||
@Author : alexanderwu
|
||||
@File : test_engineer.py
|
||||
@Modified By: mashenquan, 2023-11-1. Standardize the usage of message transmission.
|
||||
"""
|
||||
import pytest
|
||||
|
||||
|
|
@ -22,10 +23,10 @@ from tests.metagpt.roles.mock import (
|
|||
async def test_engineer():
|
||||
engineer = Engineer()
|
||||
|
||||
engineer.recv(MockMessages.req)
|
||||
engineer.recv(MockMessages.prd)
|
||||
engineer.recv(MockMessages.system_design)
|
||||
rsp = await engineer.handle(MockMessages.tasks)
|
||||
engineer.async_put_message(MockMessages.req)
|
||||
engineer.async_put_message(MockMessages.prd)
|
||||
engineer.async_put_message(MockMessages.system_design)
|
||||
rsp = await engineer.run(MockMessages.tasks)
|
||||
|
||||
logger.info(rsp)
|
||||
assert "all done." == rsp.content
|
||||
|
|
@ -35,13 +36,13 @@ def test_parse_str():
|
|||
for idx, i in enumerate(STRS_FOR_PARSING):
|
||||
text = CodeParser.parse_str(f"{idx+1}", i)
|
||||
# logger.info(text)
|
||||
assert text == 'a'
|
||||
assert text == "a"
|
||||
|
||||
|
||||
def test_parse_blocks():
|
||||
tasks = CodeParser.parse_blocks(TASKS)
|
||||
logger.info(tasks.keys())
|
||||
assert 'Task list' in tasks.keys()
|
||||
assert "Task list" in tasks.keys()
|
||||
|
||||
|
||||
target_list = [
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
@Time : 2023/5/12 00:47
|
||||
@Author : alexanderwu
|
||||
@File : test_environment.py
|
||||
@Modified By: mashenquan, 2023-11-1. Standardize the usage of message transmission.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
|
@ -49,7 +50,7 @@ async def test_publish_and_process_message(env: Environment):
|
|||
|
||||
env.add_roles([product_manager, architect])
|
||||
env.set_manager(Manager())
|
||||
env.publish_message(Message(role="BOSS", content="需要一个基于LLM做总结的搜索引擎", cause_by=BossRequirement))
|
||||
env.publish_message(Message(role="BOSS", content="需要一个基于LLM做总结的搜索引擎", cause_by=BossRequirement.get_class_name()))
|
||||
|
||||
await env.run(k=2)
|
||||
logger.info(f"{env.history=}")
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Desc : the unittest of serialize
|
||||
"""
|
||||
@Desc : the unittest of serialize
|
||||
@Modified By: mashenquan, 2023-11-1. Standardize the usage of message filtering-related features.
|
||||
"""
|
||||
|
||||
from typing import List, Tuple
|
||||
|
||||
|
|
@ -55,7 +58,7 @@ def test_serialize_and_deserialize_message():
|
|||
ic_obj = ActionOutput.create_model_class("prd", out_mapping)
|
||||
|
||||
message = Message(
|
||||
content="prd demand", instruct_content=ic_obj(**out_data), role="user", cause_by=WritePRD
|
||||
content="prd demand", instruct_content=ic_obj(**out_data), role="user", cause_by=WritePRD.get_class_name()
|
||||
) # WritePRD as test action
|
||||
|
||||
message_ser = serialize_message(message)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue