mirror of
https://github.com/FoundationAgents/MetaGPT.git
synced 2026-05-24 14:15:17 +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
|
|
@ -1,22 +1,24 @@
|
|||
'''
|
||||
"""
|
||||
Filename: MetaGPT/examples/agent_creator.py
|
||||
Created Date: Tuesday, September 12th 2023, 3:28:37 pm
|
||||
Author: garylin2099
|
||||
'''
|
||||
@Modified By: mashenquan, 2023-11-1. Standardize the usage of message filtering-related features.
|
||||
"""
|
||||
import re
|
||||
|
||||
from metagpt.const import PROJECT_ROOT, WORKSPACE_ROOT
|
||||
from metagpt.actions import Action
|
||||
from metagpt.const import PROJECT_ROOT, WORKSPACE_ROOT
|
||||
from metagpt.logs import logger
|
||||
from metagpt.roles import Role
|
||||
from metagpt.schema import Message
|
||||
from metagpt.logs import logger
|
||||
from metagpt.utils.common import get_object_name
|
||||
|
||||
with open(PROJECT_ROOT / "examples/build_customized_agent.py", "r") as f:
|
||||
# use official example script to guide AgentCreator
|
||||
MULTI_ACTION_AGENT_CODE_EXAMPLE = f.read()
|
||||
|
||||
class CreateAgent(Action):
|
||||
|
||||
class CreateAgent(Action):
|
||||
PROMPT_TEMPLATE = """
|
||||
### BACKGROUND
|
||||
You are using an agent framework called metagpt to write agents capable of different actions,
|
||||
|
|
@ -34,7 +36,6 @@ class CreateAgent(Action):
|
|||
"""
|
||||
|
||||
async def run(self, example: str, instruction: str):
|
||||
|
||||
prompt = self.PROMPT_TEMPLATE.format(example=example, instruction=instruction)
|
||||
# logger.info(prompt)
|
||||
|
||||
|
|
@ -46,13 +47,14 @@ class CreateAgent(Action):
|
|||
|
||||
@staticmethod
|
||||
def parse_code(rsp):
|
||||
pattern = r'```python(.*)```'
|
||||
pattern = r"```python(.*)```"
|
||||
match = re.search(pattern, rsp, re.DOTALL)
|
||||
code_text = match.group(1) if match else ""
|
||||
with open(WORKSPACE_ROOT / "agent_created_agent.py", "w") as f:
|
||||
f.write(code_text)
|
||||
return code_text
|
||||
|
||||
|
||||
class AgentCreator(Role):
|
||||
def __init__(
|
||||
self,
|
||||
|
|
@ -72,15 +74,15 @@ class AgentCreator(Role):
|
|||
|
||||
instruction = msg.content
|
||||
code_text = await CreateAgent().run(example=self.agent_template, instruction=instruction)
|
||||
msg = Message(content=code_text, role=self.profile, cause_by=todo)
|
||||
msg = Message(content=code_text, role=self.profile, cause_by=get_object_name(todo))
|
||||
|
||||
return msg
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import asyncio
|
||||
|
||||
async def main():
|
||||
|
||||
agent_template = MULTI_ACTION_AGENT_CODE_EXAMPLE
|
||||
|
||||
creator = AgentCreator(agent_template=agent_template)
|
||||
|
|
|
|||
|
|
@ -1,21 +1,23 @@
|
|||
'''
|
||||
"""
|
||||
Filename: MetaGPT/examples/build_customized_agent.py
|
||||
Created Date: Tuesday, September 19th 2023, 6:52:25 pm
|
||||
Author: garylin2099
|
||||
'''
|
||||
@Modified By: mashenquan, 2023-11-1. Standardize the usage of message filtering-related features.
|
||||
"""
|
||||
import asyncio
|
||||
import re
|
||||
import subprocess
|
||||
import asyncio
|
||||
|
||||
import fire
|
||||
|
||||
from metagpt.actions import Action
|
||||
from metagpt.logs import logger
|
||||
from metagpt.roles import Role
|
||||
from metagpt.schema import Message
|
||||
from metagpt.logs import logger
|
||||
from metagpt.utils.common import get_object_name
|
||||
|
||||
|
||||
class SimpleWriteCode(Action):
|
||||
|
||||
PROMPT_TEMPLATE = """
|
||||
Write a python function that can {instruction} and provide two runnnable test cases.
|
||||
Return ```python your_code_here ``` with NO other texts,
|
||||
|
|
@ -35,7 +37,6 @@ class SimpleWriteCode(Action):
|
|||
super().__init__(name, context, llm)
|
||||
|
||||
async def run(self, instruction: str):
|
||||
|
||||
prompt = self.PROMPT_TEMPLATE.format(instruction=instruction)
|
||||
|
||||
rsp = await self._aask(prompt)
|
||||
|
|
@ -46,11 +47,12 @@ class SimpleWriteCode(Action):
|
|||
|
||||
@staticmethod
|
||||
def parse_code(rsp):
|
||||
pattern = r'```python(.*)```'
|
||||
pattern = r"```python(.*)```"
|
||||
match = re.search(pattern, rsp, re.DOTALL)
|
||||
code_text = match.group(1) if match else rsp
|
||||
return code_text
|
||||
|
||||
|
||||
class SimpleRunCode(Action):
|
||||
def __init__(self, name="SimpleRunCode", context=None, llm=None):
|
||||
super().__init__(name, context, llm)
|
||||
|
|
@ -61,6 +63,7 @@ class SimpleRunCode(Action):
|
|||
logger.info(f"{code_result=}")
|
||||
return code_result
|
||||
|
||||
|
||||
class SimpleCoder(Role):
|
||||
def __init__(
|
||||
self,
|
||||
|
|
@ -75,14 +78,15 @@ class SimpleCoder(Role):
|
|||
logger.info(f"{self._setting}: ready to {self._rc.todo}")
|
||||
todo = self._rc.todo
|
||||
|
||||
msg = self._rc.memory.get()[-1] # retrieve the latest memory
|
||||
msg = self._rc.memory.get()[-1] # retrieve the latest memory
|
||||
instruction = msg.content
|
||||
|
||||
code_text = await SimpleWriteCode().run(instruction)
|
||||
msg = Message(content=code_text, role=self.profile, cause_by=todo)
|
||||
msg = Message(content=code_text, role=self.profile, cause_by=get_object_name(todo))
|
||||
|
||||
return msg
|
||||
|
||||
|
||||
class RunnableCoder(Role):
|
||||
def __init__(
|
||||
self,
|
||||
|
|
@ -116,7 +120,7 @@ class RunnableCoder(Role):
|
|||
code_text = msg.content
|
||||
result = await SimpleRunCode().run(code_text)
|
||||
|
||||
msg = Message(content=result, role=self.profile, cause_by=todo)
|
||||
msg = Message(content=result, role=self.profile, cause_by=get_object_name(todo))
|
||||
self._rc.memory.add(msg)
|
||||
return msg
|
||||
|
||||
|
|
@ -128,6 +132,7 @@ class RunnableCoder(Role):
|
|||
await self._act()
|
||||
return Message(content="All job done", role=self.profile)
|
||||
|
||||
|
||||
def main(msg="write a function that calculates the sum of a list"):
|
||||
# role = SimpleCoder()
|
||||
role = RunnableCoder()
|
||||
|
|
@ -135,5 +140,6 @@ def main(msg="write a function that calculates the sum of a list"):
|
|||
result = asyncio.run(role.run(msg))
|
||||
logger.info(result)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
if __name__ == "__main__":
|
||||
fire.Fire(main)
|
||||
|
|
|
|||
|
|
@ -1,17 +1,20 @@
|
|||
'''
|
||||
"""
|
||||
Filename: MetaGPT/examples/debate.py
|
||||
Created Date: Tuesday, September 19th 2023, 6:52:25 pm
|
||||
Author: garylin2099
|
||||
'''
|
||||
@Modified By: mashenquan, 2023-11-1. Standardize the usage of message filtering-related features.
|
||||
"""
|
||||
import asyncio
|
||||
import platform
|
||||
|
||||
import fire
|
||||
|
||||
from metagpt.software_company import SoftwareCompany
|
||||
from metagpt.actions import Action, BossRequirement
|
||||
from metagpt.logs import logger
|
||||
from metagpt.roles import Role
|
||||
from metagpt.schema import Message
|
||||
from metagpt.logs import logger
|
||||
from metagpt.software_company import SoftwareCompany
|
||||
|
||||
|
||||
class ShoutOut(Action):
|
||||
"""Action: Shout out loudly in a debate (quarrel)"""
|
||||
|
|
@ -31,7 +34,6 @@ class ShoutOut(Action):
|
|||
super().__init__(name, context, llm)
|
||||
|
||||
async def run(self, context: str, name: str, opponent_name: str):
|
||||
|
||||
prompt = self.PROMPT_TEMPLATE.format(context=context, name=name, opponent_name=opponent_name)
|
||||
# logger.info(prompt)
|
||||
|
||||
|
|
@ -39,6 +41,7 @@ class ShoutOut(Action):
|
|||
|
||||
return rsp
|
||||
|
||||
|
||||
class Trump(Role):
|
||||
def __init__(
|
||||
self,
|
||||
|
|
@ -55,13 +58,13 @@ class Trump(Role):
|
|||
async def _observe(self) -> int:
|
||||
await super()._observe()
|
||||
# accept messages sent (from opponent) to self, disregard own messages from the last round
|
||||
self._rc.news = [msg for msg in self._rc.news if msg.send_to == self.name]
|
||||
self._rc.news = [msg for msg in self._rc.news if msg.is_recipient({self.name})]
|
||||
return len(self._rc.news)
|
||||
|
||||
async def _act(self) -> Message:
|
||||
logger.info(f"{self._setting}: ready to {self._rc.todo}")
|
||||
|
||||
msg_history = self._rc.memory.get_by_actions([ShoutOut])
|
||||
msg_history = self._rc.memory.get_by_actions([ShoutOut.get_class_name()])
|
||||
context = []
|
||||
for m in msg_history:
|
||||
context.append(str(m))
|
||||
|
|
@ -72,13 +75,14 @@ class Trump(Role):
|
|||
msg = Message(
|
||||
content=rsp,
|
||||
role=self.profile,
|
||||
cause_by=ShoutOut,
|
||||
sent_from=self.name,
|
||||
send_to=self.opponent_name,
|
||||
cause_by=ShoutOut.get_class_name(),
|
||||
tx_from=self.name,
|
||||
tx_to=self.opponent_name,
|
||||
)
|
||||
|
||||
return msg
|
||||
|
||||
|
||||
class Biden(Role):
|
||||
def __init__(
|
||||
self,
|
||||
|
|
@ -96,13 +100,14 @@ class Biden(Role):
|
|||
await super()._observe()
|
||||
# accept the very first human instruction (the debate topic) or messages sent (from opponent) to self,
|
||||
# disregard own messages from the last round
|
||||
self._rc.news = [msg for msg in self._rc.news if msg.cause_by == BossRequirement or msg.send_to == self.name]
|
||||
message_filter = {BossRequirement.get_class_name(), self.name}
|
||||
self._rc.news = [msg for msg in self._rc.news if msg.is_recipient(message_filter)]
|
||||
return len(self._rc.news)
|
||||
|
||||
async def _act(self) -> Message:
|
||||
logger.info(f"{self._setting}: ready to {self._rc.todo}")
|
||||
|
||||
msg_history = self._rc.memory.get_by_actions([BossRequirement, ShoutOut])
|
||||
msg_history = self._rc.memory.get_by_actions([BossRequirement.get_class_name(), ShoutOut.get_class_name()])
|
||||
context = []
|
||||
for m in msg_history:
|
||||
context.append(str(m))
|
||||
|
|
@ -113,17 +118,19 @@ class Biden(Role):
|
|||
msg = Message(
|
||||
content=rsp,
|
||||
role=self.profile,
|
||||
cause_by=ShoutOut,
|
||||
sent_from=self.name,
|
||||
send_to=self.opponent_name,
|
||||
cause_by=ShoutOut.get_class_name(),
|
||||
tx_from=self.name,
|
||||
tx_to=self.opponent_name,
|
||||
)
|
||||
|
||||
return msg
|
||||
|
||||
async def startup(idea: str, investment: float = 3.0, n_round: int = 5,
|
||||
code_review: bool = False, run_tests: bool = False):
|
||||
|
||||
async def startup(
|
||||
idea: str, investment: float = 3.0, n_round: int = 5, code_review: bool = False, run_tests: bool = False
|
||||
):
|
||||
"""We reuse the startup paradigm for roles to interact with each other.
|
||||
Now we run a startup of presidents and watch they quarrel. :) """
|
||||
Now we run a startup of presidents and watch they quarrel. :)"""
|
||||
company = SoftwareCompany()
|
||||
company.hire([Biden(), Trump()])
|
||||
company.invest(investment)
|
||||
|
|
@ -133,7 +140,7 @@ async def startup(idea: str, investment: float = 3.0, n_round: int = 5,
|
|||
|
||||
def main(idea: str, investment: float = 3.0, n_round: int = 10):
|
||||
"""
|
||||
:param idea: Debate topic, such as "Topic: The U.S. should commit more in climate change fighting"
|
||||
:param idea: Debate topic, such as "Topic: The U.S. should commit more in climate change fighting"
|
||||
or "Trump: Climate change is a hoax"
|
||||
:param investment: contribute a certain dollar amount to watch the debate
|
||||
:param n_round: maximum rounds of the debate
|
||||
|
|
@ -144,5 +151,5 @@ def main(idea: str, investment: float = 3.0, n_round: int = 10):
|
|||
asyncio.run(startup(idea, investment, n_round))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
fire.Fire(main)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
@Time : 2023/9/13 12:36
|
||||
@Author : femto Zheng
|
||||
@File : sk_agent.py
|
||||
@Modified By: mashenquan, 2023-11-1. Standardize the usage of message filtering-related features.
|
||||
"""
|
||||
import asyncio
|
||||
|
||||
|
|
@ -39,7 +40,7 @@ async def basic_planner_example():
|
|||
role.import_semantic_skill_from_directory(SKILL_DIRECTORY, "WriterSkill")
|
||||
role.import_skill(TextSkill(), "TextSkill")
|
||||
# using BasicPlanner
|
||||
await role.run(Message(content=task, cause_by=BossRequirement))
|
||||
await role.run(Message(content=task, cause_by=BossRequirement.get_class_name()))
|
||||
|
||||
|
||||
async def sequential_planner_example():
|
||||
|
|
@ -53,7 +54,7 @@ async def sequential_planner_example():
|
|||
role.import_semantic_skill_from_directory(SKILL_DIRECTORY, "WriterSkill")
|
||||
role.import_skill(TextSkill(), "TextSkill")
|
||||
# using BasicPlanner
|
||||
await role.run(Message(content=task, cause_by=BossRequirement))
|
||||
await role.run(Message(content=task, cause_by=BossRequirement.get_class_name()))
|
||||
|
||||
|
||||
async def basic_planner_web_search_example():
|
||||
|
|
@ -64,7 +65,7 @@ async def basic_planner_web_search_example():
|
|||
role.import_skill(SkSearchEngine(), "WebSearchSkill")
|
||||
# role.import_semantic_skill_from_directory(skills_directory, "QASkill")
|
||||
|
||||
await role.run(Message(content=task, cause_by=BossRequirement))
|
||||
await role.run(Message(content=task, cause_by=BossRequirement.get_class_name()))
|
||||
|
||||
|
||||
async def action_planner_example():
|
||||
|
|
@ -75,7 +76,7 @@ async def action_planner_example():
|
|||
role.import_skill(TimeSkill(), "time")
|
||||
role.import_skill(TextSkill(), "text")
|
||||
task = "What is the sum of 110 and 990?"
|
||||
await role.run(Message(content=task, cause_by=BossRequirement)) # it will choose mathskill.Add
|
||||
await role.run(Message(content=task, cause_by=BossRequirement.get_class_name())) # it will choose mathskill.Add
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue