refactor: Refactor Message transmission & filtering

This commit is contained in:
莘权 马 2023-11-01 20:08:58 +08:00
parent 5e8ada5cff
commit 545d77ce0d
30 changed files with 658 additions and 296 deletions

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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这是主入口其他的模块IndexRanking和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())

View file

@ -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

View file

@ -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 = [

View file

@ -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=}")

View file

@ -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)