-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #481 from garylin2099/human_roleplay
allow human to play any roles
- Loading branch information
Showing
6 changed files
with
218 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
''' | ||
Filename: MetaGPT/examples/build_customized_multi_agents.py | ||
Created Date: Wednesday, November 15th 2023, 7:12:39 pm | ||
Author: garylin2099 | ||
''' | ||
import re | ||
import asyncio | ||
import fire | ||
|
||
from metagpt.llm import LLM | ||
from metagpt.actions import Action, BossRequirement | ||
from metagpt.roles import Role | ||
from metagpt.team import Team | ||
from metagpt.schema import Message | ||
from metagpt.logs import logger | ||
|
||
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([BossRequirement]) | ||
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
''' | ||
Filename: MetaGPT/metagpt/provider/human_provider.py | ||
Created Date: Wednesday, November 8th 2023, 11:55:46 pm | ||
Author: garylin2099 | ||
''' | ||
from typing import Optional | ||
from metagpt.provider.base_gpt_api import BaseGPTAPI | ||
from metagpt.logs import logger | ||
|
||
class HumanProvider(BaseGPTAPI): | ||
"""Humans provide themselves as a 'model', which actually takes in human input as its response. | ||
This enables replacing LLM anywhere in the framework with a human, thus introducing human interaction | ||
""" | ||
|
||
def ask(self, msg: str) -> str: | ||
logger.info("It's your turn, please type in your response. You may also refer to the context below") | ||
rsp = input(msg) | ||
if rsp in ["exit", "quit"]: | ||
exit() | ||
return rsp | ||
|
||
async def aask(self, msg: str, system_msgs: Optional[list[str]] = None) -> str: | ||
return self.ask(msg) | ||
|
||
def completion(self, messages: list[dict]): | ||
"""dummy implementation of abstract method in base""" | ||
return [] | ||
|
||
async def acompletion(self, messages: list[dict]): | ||
"""dummy implementation of abstract method in base""" | ||
return [] | ||
|
||
async def acompletion_text(self, messages: list[dict], stream=False) -> str: | ||
"""dummy implementation of abstract method in base""" | ||
return [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters