mirror of
https://github.com/FoundationAgents/MetaGPT.git
synced 2026-06-08 15:05:17 +02:00
feat: merge geekan:cli-etc
This commit is contained in:
commit
78548c2ddc
84 changed files with 2982 additions and 1000 deletions
|
|
@ -6,12 +6,13 @@ Author: garylin2099
|
|||
import re
|
||||
|
||||
from metagpt.actions import Action
|
||||
from metagpt.const import PROJECT_ROOT, WORKSPACE_ROOT
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.const import METAGPT_ROOT
|
||||
from metagpt.logs import logger
|
||||
from metagpt.roles import Role
|
||||
from metagpt.schema import Message
|
||||
|
||||
with open(PROJECT_ROOT / "examples/build_customized_agent.py", "r") as f:
|
||||
with open(METAGPT_ROOT / "examples/build_customized_agent.py", "r") as f:
|
||||
# use official example script to guide AgentCreator
|
||||
MULTI_ACTION_AGENT_CODE_EXAMPLE = f.read()
|
||||
|
||||
|
|
@ -48,7 +49,7 @@ class CreateAgent(Action):
|
|||
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:
|
||||
with open(CONFIG.workspace_path / "agent_created_agent.py", "w") as f:
|
||||
f.write(code_text)
|
||||
return code_text
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import subprocess
|
|||
import fire
|
||||
|
||||
from metagpt.actions import Action
|
||||
from metagpt.llm import LLM
|
||||
from metagpt.logs import logger
|
||||
from metagpt.roles import Role
|
||||
from metagpt.schema import Message
|
||||
|
|
@ -19,19 +20,10 @@ 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,
|
||||
example:
|
||||
```python
|
||||
# function
|
||||
def add(a, b):
|
||||
return a + b
|
||||
# test cases
|
||||
print(add(1, 2))
|
||||
print(add(3, 4))
|
||||
```
|
||||
your code:
|
||||
"""
|
||||
|
||||
def __init__(self, name="SimpleWriteCode", context=None, llm=None):
|
||||
def __init__(self, name: str = "SimpleWriteCode", context=None, llm: LLM = None):
|
||||
super().__init__(name, context, llm)
|
||||
|
||||
async def run(self, instruction: str):
|
||||
|
|
@ -52,7 +44,7 @@ class SimpleWriteCode(Action):
|
|||
|
||||
|
||||
class SimpleRunCode(Action):
|
||||
def __init__(self, name="SimpleRunCode", context=None, llm=None):
|
||||
def __init__(self, name: str = "SimpleRunCode", context=None, llm: LLM = None):
|
||||
super().__init__(name, context, llm)
|
||||
|
||||
async def run(self, code_text: str):
|
||||
|
|
@ -74,13 +66,11 @@ class SimpleCoder(Role):
|
|||
|
||||
async def _act(self) -> Message:
|
||||
logger.info(f"{self._setting}: ready to {self._rc.todo}")
|
||||
todo = self._rc.todo
|
||||
todo = self._rc.todo # todo will be SimpleWriteCode()
|
||||
|
||||
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 = self.get_memories(k=1)[0] # find the most recent messages
|
||||
code_text = await todo.run(msg.content)
|
||||
msg = Message(content=code_text, role=self.profile, cause_by=type(todo))
|
||||
|
||||
return msg
|
||||
|
||||
|
|
@ -94,44 +84,23 @@ class RunnableCoder(Role):
|
|||
):
|
||||
super().__init__(name, profile, **kwargs)
|
||||
self._init_actions([SimpleWriteCode, SimpleRunCode])
|
||||
|
||||
async def _think(self) -> None:
|
||||
if self._rc.todo is None:
|
||||
self._set_state(0)
|
||||
return
|
||||
|
||||
if self._rc.state + 1 < len(self._states):
|
||||
self._set_state(self._rc.state + 1)
|
||||
else:
|
||||
self._rc.todo = None
|
||||
self._set_react_mode(react_mode="by_order")
|
||||
|
||||
async def _act(self) -> Message:
|
||||
logger.info(f"{self._setting}: ready to {self._rc.todo}")
|
||||
# By choosing the Action by order under the hood
|
||||
# todo will be first SimpleWriteCode() then SimpleRunCode()
|
||||
todo = self._rc.todo
|
||||
msg = self._rc.memory.get()[-1]
|
||||
|
||||
if isinstance(todo, SimpleWriteCode):
|
||||
instruction = msg.content
|
||||
result = await SimpleWriteCode().run(instruction)
|
||||
msg = self.get_memories(k=1)[0] # find the most k recent messages
|
||||
result = await todo.run(msg.content)
|
||||
|
||||
elif isinstance(todo, SimpleRunCode):
|
||||
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=type(todo))
|
||||
self._rc.memory.add(msg)
|
||||
return msg
|
||||
|
||||
async def _react(self) -> Message:
|
||||
while True:
|
||||
await self._think()
|
||||
if self._rc.todo is None:
|
||||
break
|
||||
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"):
|
||||
def main(msg="write a function that calculates the product of a list and run it"):
|
||||
# role = SimpleCoder()
|
||||
role = RunnableCoder()
|
||||
logger.info(msg)
|
||||
|
|
|
|||
155
examples/build_customized_multi_agents.py
Normal file
155
examples/build_customized_multi_agents.py
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
"""
|
||||
Filename: MetaGPT/examples/build_customized_multi_agents.py
|
||||
Created Date: Wednesday, November 15th 2023, 7:12:39 pm
|
||||
Author: garylin2099
|
||||
"""
|
||||
import re
|
||||
|
||||
import fire
|
||||
|
||||
from metagpt.actions import Action, UserRequirement
|
||||
from metagpt.llm import LLM
|
||||
from metagpt.logs import logger
|
||||
from metagpt.roles import Role
|
||||
from metagpt.schema import Message
|
||||
from metagpt.team import Team
|
||||
|
||||
|
||||
def parse_code(rsp):
|
||||
pattern = r"```python(.*)```"
|
||||
match = re.search(pattern, rsp, re.DOTALL)
|
||||
code_text = match.group(1) if match else rsp
|
||||
return code_text
|
||||
|
||||
|
||||
class SimpleWriteCode(Action):
|
||||
PROMPT_TEMPLATE = """
|
||||
Write a python function that can {instruction}.
|
||||
Return ```python your_code_here ``` with NO other texts,
|
||||
your code:
|
||||
"""
|
||||
|
||||
def __init__(self, name: str = "SimpleWriteCode", context=None, llm: LLM = None):
|
||||
super().__init__(name, context, llm)
|
||||
|
||||
async def run(self, instruction: str):
|
||||
prompt = self.PROMPT_TEMPLATE.format(instruction=instruction)
|
||||
|
||||
rsp = await self._aask(prompt)
|
||||
|
||||
code_text = parse_code(rsp)
|
||||
|
||||
return code_text
|
||||
|
||||
|
||||
class SimpleCoder(Role):
|
||||
def __init__(
|
||||
self,
|
||||
name: str = "Alice",
|
||||
profile: str = "SimpleCoder",
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__(name, profile, **kwargs)
|
||||
self._watch([UserRequirement])
|
||||
self._init_actions([SimpleWriteCode])
|
||||
|
||||
|
||||
class SimpleWriteTest(Action):
|
||||
PROMPT_TEMPLATE = """
|
||||
Context: {context}
|
||||
Write {k} unit tests using pytest for the given function, assuming you have imported it.
|
||||
Return ```python your_code_here ``` with NO other texts,
|
||||
your code:
|
||||
"""
|
||||
|
||||
def __init__(self, name: str = "SimpleWriteTest", context=None, llm: LLM = None):
|
||||
super().__init__(name, context, llm)
|
||||
|
||||
async def run(self, context: str, k: int = 3):
|
||||
prompt = self.PROMPT_TEMPLATE.format(context=context, k=k)
|
||||
|
||||
rsp = await self._aask(prompt)
|
||||
|
||||
code_text = parse_code(rsp)
|
||||
|
||||
return code_text
|
||||
|
||||
|
||||
class SimpleTester(Role):
|
||||
def __init__(
|
||||
self,
|
||||
name: str = "Bob",
|
||||
profile: str = "SimpleTester",
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__(name, profile, **kwargs)
|
||||
self._init_actions([SimpleWriteTest])
|
||||
# self._watch([SimpleWriteCode])
|
||||
self._watch([SimpleWriteCode, SimpleWriteReview]) # feel free to try this too
|
||||
|
||||
async def _act(self) -> Message:
|
||||
logger.info(f"{self._setting}: ready to {self._rc.todo}")
|
||||
todo = self._rc.todo
|
||||
|
||||
# context = self.get_memories(k=1)[0].content # use the most recent memory as context
|
||||
context = self.get_memories() # use all memories as context
|
||||
|
||||
code_text = await todo.run(context, k=5) # specify arguments
|
||||
msg = Message(content=code_text, role=self.profile, cause_by=type(todo))
|
||||
|
||||
return msg
|
||||
|
||||
|
||||
class SimpleWriteReview(Action):
|
||||
PROMPT_TEMPLATE = """
|
||||
Context: {context}
|
||||
Review the test cases and provide one critical comments:
|
||||
"""
|
||||
|
||||
def __init__(self, name: str = "SimpleWriteReview", context=None, llm: LLM = None):
|
||||
super().__init__(name, context, llm)
|
||||
|
||||
async def run(self, context: str):
|
||||
prompt = self.PROMPT_TEMPLATE.format(context=context)
|
||||
|
||||
rsp = await self._aask(prompt)
|
||||
|
||||
return rsp
|
||||
|
||||
|
||||
class SimpleReviewer(Role):
|
||||
def __init__(
|
||||
self,
|
||||
name: str = "Charlie",
|
||||
profile: str = "SimpleReviewer",
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__(name, profile, **kwargs)
|
||||
self._init_actions([SimpleWriteReview])
|
||||
self._watch([SimpleWriteTest])
|
||||
|
||||
|
||||
async def main(
|
||||
idea: str = "write a function that calculates the product of a list",
|
||||
investment: float = 3.0,
|
||||
n_round: int = 5,
|
||||
add_human: bool = False,
|
||||
):
|
||||
logger.info(idea)
|
||||
|
||||
team = Team()
|
||||
team.hire(
|
||||
[
|
||||
SimpleCoder(),
|
||||
SimpleTester(),
|
||||
SimpleReviewer(is_human=add_human),
|
||||
]
|
||||
)
|
||||
|
||||
team.invest(investment=investment)
|
||||
team.start_project(idea)
|
||||
await team.run(n_round=n_round)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
fire.Fire(main)
|
||||
|
|
@ -10,16 +10,15 @@ import platform
|
|||
|
||||
import fire
|
||||
|
||||
from metagpt.actions import Action, BossRequirement
|
||||
from metagpt.actions import Action, UserRequirement
|
||||
from metagpt.logs import logger
|
||||
from metagpt.roles import Role
|
||||
from metagpt.schema import Message
|
||||
from metagpt.software_company import SoftwareCompany
|
||||
from metagpt.utils.common import any_to_str
|
||||
from metagpt.team import Team
|
||||
|
||||
|
||||
class ShoutOut(Action):
|
||||
"""Action: Shout out loudly in a debate (quarrel)"""
|
||||
class SpeakAloud(Action):
|
||||
"""Action: Speak out aloud in a debate (quarrel)"""
|
||||
|
||||
PROMPT_TEMPLATE = """
|
||||
## BACKGROUND
|
||||
|
|
@ -32,7 +31,7 @@ class ShoutOut(Action):
|
|||
craft a strong and emotional response in 80 words, in {name}'s rhetoric and viewpoints, your will argue:
|
||||
"""
|
||||
|
||||
def __init__(self, name="ShoutOut", context=None, llm=None):
|
||||
def __init__(self, name="SpeakAloud", context=None, llm=None):
|
||||
super().__init__(name, context, llm)
|
||||
|
||||
async def run(self, context: str, name: str, opponent_name: str):
|
||||
|
|
@ -44,18 +43,18 @@ class ShoutOut(Action):
|
|||
return rsp
|
||||
|
||||
|
||||
class Trump(Role):
|
||||
class Debator(Role):
|
||||
def __init__(
|
||||
self,
|
||||
name: str = "Trump",
|
||||
profile: str = "Republican",
|
||||
name: str,
|
||||
profile: str,
|
||||
opponent_name: str,
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__(name, profile, **kwargs)
|
||||
self._init_actions([ShoutOut])
|
||||
self._watch([ShoutOut])
|
||||
self.name = "Trump"
|
||||
self.opponent_name = "Biden"
|
||||
self._init_actions([SpeakAloud])
|
||||
self._watch([UserRequirement, SpeakAloud])
|
||||
self.opponent_name = opponent_name
|
||||
|
||||
async def _observe(self) -> int:
|
||||
await super()._observe()
|
||||
|
|
@ -65,80 +64,35 @@ class Trump(Role):
|
|||
|
||||
async def _act(self) -> Message:
|
||||
logger.info(f"{self._setting}: ready to {self._rc.todo}")
|
||||
todo = self._rc.todo # An instance of SpeakAloud
|
||||
|
||||
msg_history = self._rc.memory.get_by_actions([ShoutOut])
|
||||
context = []
|
||||
for m in msg_history:
|
||||
context.append(str(m))
|
||||
context = "\n".join(context)
|
||||
memories = self.get_memories()
|
||||
context = "\n".join(f"{msg.sent_from}: {msg.content}" for msg in memories)
|
||||
# print(context)
|
||||
|
||||
rsp = await ShoutOut().run(context=context, name=self.name, opponent_name=self.opponent_name)
|
||||
rsp = await todo.run(context=context, name=self.name, opponent_name=self.opponent_name)
|
||||
|
||||
msg = Message(
|
||||
content=rsp,
|
||||
role=self.profile,
|
||||
cause_by=ShoutOut,
|
||||
cause_by=type(todo),
|
||||
sent_from=self.name,
|
||||
send_to=self.opponent_name,
|
||||
)
|
||||
self._rc.memory.add(msg)
|
||||
|
||||
return msg
|
||||
|
||||
|
||||
class Biden(Role):
|
||||
def __init__(
|
||||
self,
|
||||
name: str = "Biden",
|
||||
profile: str = "Democrat",
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__(name, profile, **kwargs)
|
||||
self._init_actions([ShoutOut])
|
||||
self._watch([BossRequirement, ShoutOut])
|
||||
self.name = "Biden"
|
||||
self.opponent_name = "Trump"
|
||||
|
||||
async def _observe(self) -> int:
|
||||
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 == any_to_str(BossRequirement) or msg.send_to == {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([BossRequirement, ShoutOut])
|
||||
context = []
|
||||
for m in msg_history:
|
||||
context.append(str(m))
|
||||
context = "\n".join(context)
|
||||
|
||||
rsp = await ShoutOut().run(context=context, name=self.name, opponent_name=self.opponent_name)
|
||||
|
||||
msg = Message(
|
||||
content=rsp,
|
||||
role=self.profile,
|
||||
cause_by=ShoutOut,
|
||||
sent_from=self.name,
|
||||
send_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
|
||||
):
|
||||
"""We reuse the startup paradigm for roles to interact with each other.
|
||||
Now we run a startup of presidents and watch they quarrel. :)"""
|
||||
company = SoftwareCompany()
|
||||
company.hire([Biden(), Trump()])
|
||||
company.invest(investment)
|
||||
company.start_project(idea)
|
||||
await company.run(n_round=n_round)
|
||||
async def debate(idea: str, investment: float = 3.0, n_round: int = 5):
|
||||
"""Run a team of presidents and watch they quarrel. :)"""
|
||||
Biden = Debator(name="Biden", profile="Democrat", opponent_name="Trump")
|
||||
Trump = Debator(name="Trump", profile="Republican", opponent_name="Biden")
|
||||
team = Team()
|
||||
team.hire([Biden, Trump])
|
||||
team.invest(investment)
|
||||
team.run_project(idea, send_to="Biden") # send debate topic to Biden and let him speak first
|
||||
await team.run(n_round=n_round)
|
||||
|
||||
|
||||
def main(idea: str, investment: float = 3.0, n_round: int = 10):
|
||||
|
|
@ -151,7 +105,7 @@ def main(idea: str, investment: float = 3.0, n_round: int = 10):
|
|||
"""
|
||||
if platform.system() == "Windows":
|
||||
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||||
asyncio.run(startup(idea, investment, n_round))
|
||||
asyncio.run(debate(idea, investment, n_round))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ from semantic_kernel.planning import SequentialPlanner
|
|||
# from semantic_kernel.planning import SequentialPlanner
|
||||
from semantic_kernel.planning.action_planner.action_planner import ActionPlanner
|
||||
|
||||
from metagpt.actions import BossRequirement
|
||||
from metagpt.actions import UserRequirement
|
||||
from metagpt.const import SKILL_DIRECTORY
|
||||
from metagpt.roles.sk_agent import SkAgent
|
||||
from metagpt.schema import Message
|
||||
|
|
@ -39,7 +39,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=UserRequirement))
|
||||
|
||||
|
||||
async def sequential_planner_example():
|
||||
|
|
@ -53,7 +53,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=UserRequirement))
|
||||
|
||||
|
||||
async def basic_planner_web_search_example():
|
||||
|
|
@ -64,7 +64,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=UserRequirement))
|
||||
|
||||
|
||||
async def action_planner_example():
|
||||
|
|
@ -75,7 +75,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=UserRequirement)) # it will choose mathskill.Add
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue