feat: merge geekan:cli-etc

This commit is contained in:
莘权 马 2023-11-28 18:16:50 +08:00
commit 78548c2ddc
84 changed files with 2982 additions and 1000 deletions

View file

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

View file

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

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

View file

@ -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__":

View file

@ -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__":