Merge branch 'geekan:werewolf_game' into werewolf_game

This commit is contained in:
Aria F 2023-10-10 20:16:28 +08:00 committed by GitHub
commit 48043f4f9d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 237 additions and 153 deletions

View file

@ -1,5 +1,5 @@
from examples.werewolf_game.actions.moderator_actions import InstructSpeak
from examples.werewolf_game.actions.common_actions import Speak
from examples.werewolf_game.actions.common_actions import Speak, NighttimeWhispers
from examples.werewolf_game.actions.werewolf_actions import Hunt, Impersonate
from examples.werewolf_game.actions.guard_actions import Protect
from examples.werewolf_game.actions.seer_actions import Verify

View file

@ -1,30 +1,174 @@
from metagpt.actions import Action
import json
from metagpt.const import WORKSPACE_ROOT
class Speak(Action):
"""Action: Any speak action in a game"""
PROMPT_TEMPLATE = """
## BACKGROUND
It's a Werewolf game, you are {profile}, say whatever possible to increase your chance of win,
## HISTORY
You have knowledge to the following conversation:
{context}
## YOUR TURN
Please follow the moderator's latest instruction, FIGURE OUT if you need to speak your opinion or directly to vote,
1. If the instruction is to speak, speak in 100 words;
2. If the instruction is to vote, you MUST vote and ONLY say "I vote to eliminate PlayerX", where X is the player index, DO NOT include any other words.
Your will say:
{
"BACKGROUND": "It's a Werewolf game, you are __profile__, say whatever possible to increase your chance of win"
,"HISTORY": "You have knowledge to the following conversation: __context__"
,"ATTENTION": "You can NOT VOTE a player who is NOT ALIVE now!"
,"STRATEGY": __strategy__
,"MODERATOR_INSTRUCTION": __latest_instruction__,
,"RULE": "Please follow the moderator's latest instruction, figure out if you need to speak your opinion or directly to vote:
1. If the instruction is to SPEAK, speak in 200 words. Remember the goal of your role and try to achieve it using your speech;
2. If the instruction is to VOTE, you MUST vote and ONLY say 'I vote to eliminate PlayerX', replace PlayerX with the actual player name, DO NOT include any other words."
,"OUTPUT_FORMAT":
{
"ROLE": "Your role, in this case, __profile__"
,"PLAYER_NAME": "Your name, in this case, __name__"
,"LIVING_PLAYERS": "List living players based on MODERATOR_INSTRUCTION. Return a LIST datatype."
,"THOUGHTS": "Based on `MODERATOR_INSTRUCTION` and `RULE`, carefully think about what to say or vote so that your chance of win as __profile__ maximizes. Give your step-by-step thought process, you should think no more than 3 steps. For example: My step-by-step thought process:..."
,"RESPONSE": "Based on `MODERATOR_INSTRUCTION`, `RULE`, and the 'THOUGHTS' you had, express your opinion or cast a vote."
}
}
"""
STRATEGY = """
Decide whether to reveal your identity based on benefits vs. risks, provide useful information, and vote to eliminate the most suspicious.
If you have special abilities, pay attention to those who falsely claims your role, for they are probably werewolves.
"""
def __init__(self, name="Speak", context=None, llm=None):
super().__init__(name, context, llm)
async def run(self, context: str, profile: str):
async def run(self, profile: str, name: str, context: str, latest_instruction: str):
prompt = self.PROMPT_TEMPLATE.format(context=context, profile=profile)
prompt = (
self.PROMPT_TEMPLATE.replace("__context__", context).replace("__profile__", profile)
.replace("__name__", name).replace("__latest_instruction__", latest_instruction)
.replace("__strategy__", self.STRATEGY)
)
rsp = await self._aask(prompt)
re_run = 2
while re_run > 0:
rsp = await self._aask(prompt)
try:
rsp = rsp.replace("\n", " ")
rsp_json = json.loads(rsp)
break
except:
re_run -= 1
return rsp
with open(WORKSPACE_ROOT / 'speak.txt', 'a') as f:
f.write(rsp)
return rsp_json['RESPONSE']
class NighttimeWhispers(Action):
"""
Action: nighttime whispers with thinking processes
Usage Example:
class Hunt(NighttimeWhispers):
def __init__(self, name="Hunt", context=None, llm=None):
super().__init__(name, context, llm)
class Protect(NighttimeWhispers):
def __init__(self, name="Protect", context=None, llm=None):
super().__init__(name, context, llm)
class Verify(NighttimeWhispers):
def __init__(self, name="Verify", context=None, llm=None):
super().__init__(name, context, llm)
class Save(NighttimeWhispers):
def __init__(self, name="Save", context=None, llm=None):
super().__init__(name, context, llm)
def _update_prompt_json(self, prompt_json: dict, profile: str, name: str, context: str, **kwargs):
del prompt_json['ACTION']
del prompt_json['ATTENTION']
prompt_json["OUTPUT_FORMAT"]["THOUGHTS"] = "It is night time. Return the thinking steps of your decision of whether to save the player JUST be killed at this night."
prompt_json["OUTPUT_FORMAT"]["RESPONSE"] = "Follow the Moderator's instruction, decide whether you want to save that person or not. Return SAVE or PASS."
return prompt_json
class Poison(NighttimeWhispers):
def __init__(self, name="Poison", context=None, llm=None):
super().__init__(name, context, llm)
def _update_prompt_json(self, prompt_json: dict, profile: str, name: str, context: str, **kwargs):
prompt_json["OUTPUT_FORMAT"]["RESPONSE"] += "Or if you want to PASS, return PASS."
return prompt_json
"""
PROMPT_TEMPLATE = """
{
"ROLE": "__profile__"
,"ACTION": "Choose one living player to __action__."
,"ATTENTION": "1. You can only __action__ a player who is alive this night! And you can not __action__ a player who is dead this night! 2. `HISTORY` is all the information you observed, DONT hallucinate other player actions!"
,"STRATEGY": "__strategy__"
,"BACKGROUND": "It's a werewolf game and you are a __profile__. Here's the game history: __context__."
,"OUTPUT_FORMAT":
{
"ROLE": "Your role, in this case, __profile__"
,"PLAYER_NAME": "Your name, in this case, __name__"
,"LIVING_PLAYERS": "List the players who is alive based on moderator's latest instruction. Return a LIST datatype."
,"THOUGHTS": "Choose one living player from `LIVING_PLAYERS` to __action__ this night. Return the reason why you choose to __action__ this player. If you observe nothing at first night, DONT imagine unexisting player actions! Give your step-by-step thought process, you should think no more than 3 steps. For example: My step-by-step thought process:..."
,"RESPONSE": "As a __profile__, you should choose one living player from `LIVING_PLAYERS` to __action__ this night according to the THOUGHTS you have just now. Return the player name ONLY."
}
}
"""
STRATEGY = """
Decide which player is most threatening to you or most needs your support, take your action correspondingly.
"""
def __init__(self, name="NightTimeWhispers", context=None, llm=None):
super().__init__(name, context, llm)
def _construct_prompt_json(self, role_profile: str, role_name: str, context: str, **kwargs):
prompt_template = self.PROMPT_TEMPLATE
def replace_string(prompt_json: dict):
k: str
for k in prompt_json.keys():
if isinstance(prompt_json[k], dict):
prompt_json[k] = replace_string(prompt_json[k])
continue
prompt_json[k] = prompt_json[k].replace("__profile__", role_profile)
prompt_json[k] = prompt_json[k].replace("__name__", role_name)
prompt_json[k] = prompt_json[k].replace("__context__", context)
prompt_json[k] = prompt_json[k].replace("__action__", self.name)
prompt_json[k] = prompt_json[k].replace("__strategy__", self.STRATEGY)
return prompt_json
prompt_json: dict = json.loads(prompt_template)
prompt_json = replace_string(prompt_json)
prompt_json: dict = self._update_prompt_json(prompt_json, role_profile, role_name, context, **kwargs)
assert isinstance(prompt_json, dict)
prompt: str = json.dumps(prompt_json, indent=4, separators=(',', ': '), ensure_ascii=False)
return prompt
def _update_prompt_json(self, prompt_json: dict, role_profile: str, role_name: str, context: str) -> dict:
# one can modify the prompt_json dictionary here
return prompt_json
async def run(self, context: str, profile: str, name: str):
final_prompt = self._construct_prompt_json(
role_profile=profile, role_name=name, context=context
)
re_run = 2
while re_run > 0:
rsp_content = await self._aask(final_prompt)
try:
rsp_content = rsp_content.replace("\n", " ")
rsp = json.loads(rsp_content)
break
except:
re_run -= 1
with open(WORKSPACE_ROOT / f'{self.name}.txt', 'a') as f:
f.write(rsp_content)
return f"{self.name} " + str(rsp["RESPONSE"])

View file

@ -1,26 +1,7 @@
from metagpt.actions import Action
from examples.werewolf_game.actions import NighttimeWhispers
class Protect(Action):
"""Action: choose a player to protect"""
PROMPT_TEMPLATE = """
It's a werewolf game and you are a guard,
you can choose to protect a player, including yourself, then the protected player will not be killed by the Werewolves this night.
this is game history:
{context}.
Attention: you can not protect the same player two nights in a row.
Format: "Protect PlayerX", where X is the player index.
Now, choose one to protect, you will:
"""
class Protect(NighttimeWhispers):
def __init__(self, name="Protect", context=None, 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)
# rsp = "Protect Player 1"
return rsp

View file

@ -42,7 +42,7 @@ STEP_INSTRUCTIONS = {
"restricted_to": "Moderator,Witch"}, # 要先判断女巫是否有解药,再去询问女巫是否使用解药救人
9: {"content": """Witch, you also have a bottle of poison, would you like to use it to kill one of the living players?
Choose one from the following living options: {living_players}.
If so, say "Poison PlayerX", where X is the player index, else, say "Pass".""",
If so, say ONLY "Poison PlayerX", replace PlayerX with the actual player name, else, say "Pass".""",
"send_to": "Witch",
"restricted_to": "Moderator,Witch"}, #
10: {"content": "Witch, close your eyes",
@ -65,13 +65,13 @@ STEP_INSTRUCTIONS = {
15: {"content": "{player_current_dead} was killed last night!",
"send_to": "Moderator",
"restricted_to": ""},
16: {"content": """Now freely talk about roles of other players with each other based on your observation and
reflection with few sentences. Decide whether to reveal your identity based on your reflection.""",
16: {"content": """Living players: {living_players}, now freely talk about the current situation based on your observation and
reflection with a few sentences. Decide whether to reveal your identity based on your reflection.""",
"send_to": "", # send to all to speak in daytime
"restricted_to": ""},
17: {"content": """Now vote and tell me who you think is the werewolf. Dont mention your role.
You only choose one from the following living options please:
{living_players}. Or you can pass. For example: I vote to kill ...""",
{living_players}. Say ONLY: I vote to eliminate ...""",
"send_to": "",
"restricted_to": ""},
18: {"content": """{player_current_dead} was eliminated.""",
@ -91,12 +91,12 @@ class InstructSpeak(Action):
})
content = instruction_info["content"]
if "{living_players}" in content and "{werewolf_players}" in content:
content = content.format(living_players=",".join(living_players),
werewolf_players=",".join(werewolf_players))
content = content.format(living_players=living_players,
werewolf_players=werewolf_players)
if "{living_players}" in content:
content = content.format(living_players=",".join(living_players))
content = content.format(living_players=living_players)
if "{werewolf_players}" in content:
content = content.format(werewolf_players=",".join(werewolf_players))
content = content.format(werewolf_players=werewolf_players)
if "{player_hunted}" in content:
content = content.format(player_hunted=player_hunted)
if "{player_current_dead}" in content:
@ -140,8 +140,8 @@ class SummarizeDay(Action):
class AnnounceGameResult(Action):
async def run(self, winner: str):
return f"Game over! The winner is the {winner}"
async def run(self, winner: str, win_reason: str):
return f"Game over! {win_reason}. The winner is the {winner}"
async def main():
rst1 = await SummarizeDay().run({"Player1": 0, "Player2": 0, "Player3": 0, "Player4": 0})

View file

@ -1,24 +1,6 @@
from metagpt.actions import Action
from examples.werewolf_game.actions import NighttimeWhispers
class Verify(Action):
"""Action: Seer verifies a player's identity at night"""
PROMPT_TEMPLATE = """
It's a werewolf game and you are a seer.
You can choose to verify the identity of a player.
Here's the game history:
{context}.
Now, choose one player to verify
Format: "Verify PlayerX", where X is the player index.
You will:
"""
class Verify(NighttimeWhispers):
def __init__(self, name="Verify", context=None, 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

View file

@ -1,46 +1,18 @@
from metagpt.actions import Action
from examples.werewolf_game.actions.common_actions import Speak
from examples.werewolf_game.actions.common_actions import Speak, NighttimeWhispers
class Hunt(Action):
"""Action: choose a villager to kill"""
PROMPT_TEMPLATE = """
It's a werewolf game and you are a werewolf,
this is game history:
{context}.
Attention: if your previous werewolf has chosen, follow its choice.
Format: "Kill PlayerX", where X is the player index.
Now, choose one to kill, you will:
"""
class Hunt(NighttimeWhispers):
def __init__(self, name="Hunt", context=None, 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)
# rsp = "Kill Player 1"
return rsp
class Impersonate(Speak):
"""Action: werewolf impersonating a good guy in daytime speak"""
PROMPT_TEMPLATE = """
## BACKGROUND
It's a Werewolf game, you are {profile}, say whatever possible to increase your chance of win,
## HISTORY
You have knowledge to the following conversation:
{context}
## ATTENTION: Try continuously impersonating a role with special ability, such as a Seer or a Witch, in order to mislead
other players, make them trust you, and thus hiding your werewolf identity
## YOUR TURN
Please follow the moderator's latest instruction, FIGURE OUT if you need to speak your opinion or directly to vote,
1. If the instruction is to speak, speak in 100 words;
2. If the instruction is to vote, you MUST vote and ONLY say "I vote to eliminate PlayerX", where X is the player index, DO NOT include any other words.
Your will say:
STRATEGY = """
Try continuously impersonating a role with special ability, such as a Seer or a Witch, in order to mislead
other players, make them trust you, and thus hiding your werewolf identity. However, pay attention to what your werewolf partner said,
if your werewolf partner has claimed to be a Seer or Witch, DONT claim to be the same role. Remmber NOT to reveal your real identity as a werewolf!
"""
def __init__(self, name="Impersonate", context=None, llm=None):

View file

@ -1,45 +1,30 @@
from metagpt.actions import Action
from examples.werewolf_game.actions import NighttimeWhispers
class Save(Action):
"""Action: choose a villager to Save"""
PROMPT_TEMPLATE = """
It's a werewolf game and you are a witch,
this is game history:
{context}.
Follow the Moderator's instruction, decide whether you want to save that person or not:
"""
class Save(NighttimeWhispers):
def __init__(self, name="Save", context=None, llm=None):
super().__init__(name, context, llm)
async def run(self, context: str):
def _update_prompt_json(self, prompt_json: dict, profile: str, name: str, context: str, **kwargs):
del prompt_json['ACTION']
del prompt_json['ATTENTION']
prompt = self.PROMPT_TEMPLATE.format(context=context)
prompt_json["OUTPUT_FORMAT"]["THOUGHTS"] = "It is night time. Return the thinking steps of your decision of whether to save the player JUST be killed at this night."
prompt_json["OUTPUT_FORMAT"]["RESPONSE"] = "Follow the Moderator's instruction, decide whether you want to save that person or not. Return SAVE or PASS."
rsp = await self._aask(prompt)
# rsp = "Save Player 1"
return prompt_json
return rsp
class Poison(Action):
"""Action: choose a villager to Poison"""
PROMPT_TEMPLATE = """
It's a werewolf game and you are a witch,
this is game history:
{context}.
Follow the Moderator's instruction, decide whether you want to poison another person or not:
class Poison(NighttimeWhispers):
STRATEGY = """
Only poison a player if you are confident he/she is a werewolf. Don't poison a player randomly or at first night.
If someone claims to be the witch, poison him/her, because you are the only witch, he/she can only be a werewolf.
"""
def __init__(self, name="Poison", context=None, llm=None):
super().__init__(name, context, llm)
async def run(self, context: str):
def _update_prompt_json(self, prompt_json: dict, profile: str, name: str, context: str, **kwargs):
prompt = self.PROMPT_TEMPLATE.format(context=context)
prompt_json["OUTPUT_FORMAT"]["RESPONSE"] += "Or if you want to PASS, return PASS."
rsp = await self._aask(prompt)
# rsp = "Poison Player 1"
return rsp
return prompt_json

View file

@ -15,8 +15,6 @@ class BasePlayer(Role):
**kwargs,
):
super().__init__(name, profile, **kwargs)
self._init_actions([Speak])
self._watch([InstructSpeak])
# 通过 set_status() 更新状态。
self.status = 0 # 0代表活着1代表死亡
@ -60,6 +58,9 @@ class BasePlayer(Role):
memories = [f"{m.sent_from}: {re.sub(time_stamp_pattern, '', m.content)}" for m in memories] # regex去掉时间戳
memories = "\n".join(memories)
return memories
def get_latest_instruction(self) -> str:
return self._rc.important_memory[-1].content # 角色监听着Moderator的InstructSpeak是其重要记忆直接获取即可
def set_status(self, new_status):
self.status = new_status

View file

@ -18,20 +18,21 @@ class Guard(BasePlayer):
todo = self._rc.todo
logger.info(f"{self._setting}: ready to {str(todo)}")
# 可以用这个函数获取该角色的全部记忆
# 可以用这个函数获取该角色的全部记忆和最新的instruction
memories = self.get_all_memories()
latest_instruction = self.get_latest_instruction()
# print("*" * 10, f"{self._setting}'s current memories: {memories}", "*" * 10)
# 根据自己定义的角色Action对应地去runrun的入参可能不同
if isinstance(todo, Speak):
rsp = await todo.run(profile=self.profile, context=memories)
rsp = await todo.run(profile=self.profile, name=self.name, context=memories, latest_instruction=latest_instruction)
msg = Message(
content=rsp, role=self.profile, sent_from=self.name,
cause_by=Speak, send_to="", restricted_to="",
)
elif isinstance(todo, Protect):
rsp = await todo.run(context=memories)
rsp = await todo.run(profile=self.profile, name=self.name, context=memories)
msg = Message(
content=rsp, role=self.profile, sent_from=self.name,
cause_by=Protect, send_to="",

View file

@ -14,7 +14,7 @@ async def _act(self):
## You are {self.name}({self.profile})
## Guidance:
1. If you are performing a special action or exercising a vote,
end your response with "PlayerX" where X is the player index, e.g., "..., kill/protect/poison/.../vote Player1".
end your response with "PlayerX", replace PlayerX with the actual player name, e.g., "..., kill/protect/poison/.../vote Player1".
2. If it is a daytime free speech, you can speak in whatever format.
Now, please speak:
"""

View file

@ -24,12 +24,15 @@ class Moderator(Role):
self._watch([UserRequirement, InstructSpeak, ParseSpeak])
self._init_actions([InstructSpeak, ParseSpeak, AnnounceGameResult])
self.step_idx = 0
self.eval_step_idx = []
# game states
self.living_players = []
self.werewolf_players = []
self.good_guys = []
self.villager_players = []
self.special_role_players = []
self.winner = None
self.win_reason = None
self.witch_poison_left = 1
self.witch_antidote_left = 1
@ -44,7 +47,10 @@ class Moderator(Role):
self.living_players = re.findall(r"Player[0-9]+", game_setup)
self.werewolf_players = re.findall(r"Player[0-9]+: Werewolf", game_setup)
self.werewolf_players = [p.replace(": Werewolf", "") for p in self.werewolf_players]
self.good_guys = [p for p in self.living_players if p not in self.werewolf_players]
self.villager_players = re.findall(r"Player[0-9]+: Villager", game_setup)
self.villager_players = [p.replace(": Villager", "") for p in self.villager_players]
self.special_role_players = [p for p in self.living_players \
if p not in self.werewolf_players + self.villager_players]
def update_player_status(self, player_names: list[str]):
if not player_names:
@ -114,8 +120,10 @@ class Moderator(Role):
def _update_game_states(self, memories):
step_idx = self.step_idx % len(STEP_INSTRUCTIONS)
if step_idx not in [15, 18]: # FIXME: hard code
if step_idx not in [15, 18] or self.step_idx in self.eval_step_idx: # FIXME: hard code
return
else:
self.eval_step_idx.append(self.step_idx) # record evaluation, avoid repetitive evaluation at the same step
if step_idx == 15: # FIXME: hard code
# night ends: after all special roles acted, process the whole night
@ -135,6 +143,7 @@ class Moderator(Role):
self.player_poisoned = None
elif step_idx == 18: # FIXME: hard code
print("*" * 10, step_idx)
# day ends: after all roles voted, process all votings
voting_msgs = memories[-len(self.living_players):]
voted_all = []
@ -144,16 +153,20 @@ class Moderator(Role):
continue
voted_all.append(voted.group(0))
self.player_current_dead = [Counter(voted_all).most_common()[0][0]] # 平票时,杀序号小的
# print("*" * 10, "dead", self.player_current_dead)
self.living_players = [p for p in self.living_players if p not in self.player_current_dead]
self.update_player_status(self.player_current_dead)
# game's termination condition
living_werewolf = [p for p in self.werewolf_players if p in self.living_players]
living_good_guys = [p for p in self.good_guys if p in self.living_players]
living_villagers = [p for p in self.villager_players if p in self.living_players]
living_special_roles = [p for p in self.special_role_players if p in self.living_players]
if not living_werewolf:
self.winner = "good guys"
elif not living_good_guys:
self.win_reason = "werewolves all dead"
elif not living_villagers or not living_special_roles:
self.winner = "werewolf"
self.win_reason = "villagers all dead" if not living_villagers else "special roles all dead"
def _record_game_history(self):
if self.step_idx % len(STEP_INSTRUCTIONS) == 0 or self.winner is not None:
@ -210,7 +223,7 @@ class Moderator(Role):
cause_by=ParseSpeak, send_to="", restricted_to=msg_restriced_to)
elif isinstance(todo, AnnounceGameResult):
msg_content = await AnnounceGameResult().run(winner=self.winner)
msg_content = await AnnounceGameResult().run(winner=self.winner, win_reason=self.win_reason)
msg = Message(content=msg_content, role=self.profile, sent_from=self.name, cause_by=AnnounceGameResult)
logger.info(f"{self._setting}: {msg_content}")

View file

@ -19,19 +19,21 @@ class Seer(BasePlayer):
todo = self._rc.todo
logger.info(f"{self._setting}: ready to {str(todo)}")
# 可以用这个函数获取该角色的全部记忆和最新的instruction
memories = self.get_all_memories()
latest_instruction = self.get_latest_instruction()
# print("*" * 10, f"{self._setting}'s current memories: {memories}", "*" * 10)
# 基于todo的类型调用不同的action
if isinstance(todo, Speak):
rsp = await todo.run(profile=self.profile, context=memories)
rsp = await todo.run(profile=self.profile, name=self.name, context=memories, latest_instruction=latest_instruction)
msg = Message(
content=rsp, role=self.profile, sent_from=self.name,
cause_by=Speak, send_to="", restricted_to="",
)
elif isinstance(todo, Verify):
rsp = await todo.run(context=memories)
rsp = await todo.run(profile=self.profile, name=self.name, context=memories)
msg = Message(
content=rsp, role=self.profile, sent_from=self.name,
cause_by=Verify, send_to="",

View file

@ -19,12 +19,13 @@ class Villager(BasePlayer):
todo = self._rc.todo
logger.info(f"{self._setting}: ready to {todo}")
# 可以用这个函数获取该角色的全部记忆
# 可以用这个函数获取该角色的全部记忆和最新的instruction
memories = self.get_all_memories()
latest_instruction = self.get_latest_instruction()
# print("*" * 10, f"{self._setting}'s current memories: {memories}", "*" * 10)
# 根据自己定义的角色Action对应地去run
rsp = await todo.run(profile=self.profile, context=memories)
rsp = await todo.run(profile=self.profile, name=self.name, context=memories, latest_instruction=latest_instruction)
# 返回消息注意给Moderator发送的加密消息需要用restricted_to="Moderator"
msg = Message(

View file

@ -18,21 +18,22 @@ class Werewolf(BasePlayer):
todo = self._rc.todo
logger.info(f"{self._setting}: ready to {str(todo)}")
# 可以用这个函数获取该角色的全部记忆
# 可以用这个函数获取该角色的全部记忆和最新的instruction
memories = self.get_all_memories()
latest_instruction = self.get_latest_instruction()
# print("*" * 10, f"{self._setting}'s current memories: {memories}", "*" * 10)
# 根据自己定义的角色Action对应地去runrun的入参可能不同
if isinstance(todo, Speak):
# rsp = await todo.run(profile=self.profile, context=memories)
rsp = await Impersonate().run(profile=self.profile, context=memories)
# rsp = await todo.run(profile=self.profile, name=self.name, context=memories, latest_instruction=latest_instruction)
rsp = await Impersonate().run(profile=self.profile, name=self.name, context=memories, latest_instruction=latest_instruction)
msg = Message(
content=rsp, role=self.profile, sent_from=self.name,
cause_by=Speak, send_to="", restricted_to="",
)
elif isinstance(todo, Hunt):
rsp = await todo.run(context=memories)
rsp = await todo.run(profile=self.profile, name=self.name, context=memories)
msg = Message(
content=rsp, role=self.profile, sent_from=self.name,
cause_by=Hunt, send_to="",

View file

@ -38,18 +38,19 @@ class Witch(BasePlayer):
# 可以用这个函数获取该角色的全部记忆
memories = self.get_all_memories()
latest_instruction = self.get_latest_instruction()
# print("*" * 10, f"{self._setting}'s current memories: {memories}", "*" * 10)
# 根据自己定义的角色Action对应地去runrun的入参可能不同
if isinstance(todo, Speak):
rsp = await todo.run(profile=self.profile, context=memories)
rsp = await todo.run(profile=self.profile, name=self.name, context=memories, latest_instruction=latest_instruction)
msg = Message(
content=rsp, role=self.profile, sent_from=self.name,
cause_by=Speak, send_to="", restricted_to="",
)
elif isinstance(todo, Save):
rsp = await todo.run(context=memories)
rsp = await todo.run(profile=self.profile, name=self.name, context=memories)
msg = Message(
content=rsp, role=self.profile, sent_from=self.name,
cause_by=Save, send_to="",
@ -57,7 +58,7 @@ class Witch(BasePlayer):
)
elif isinstance(todo, Poison):
rsp = await todo.run(context=memories)
rsp = await todo.run(profile=self.profile, name=self.name, context=memories)
msg = Message(
content=rsp, role=self.profile, sent_from=self.name,
cause_by=Poison, send_to="",