From fd7ae23f0efca8960b22169b9942de67b0e429f8 Mon Sep 17 00:00:00 2001 From: better629 Date: Sun, 1 Oct 2023 21:43:05 +0800 Subject: [PATCH] add action prompt templates --- examples/st_game/actions/gen_iter_chat_utt.py | 101 ++++++++++++++++ examples/st_game/plan/converse.py | 110 ++++++++++++++++++ .../st_game/prompts/decide_to_talk_v2.txt | 18 +++ .../st_game/prompts/iterative_convo_v1.txt | 46 ++++++++ .../prompts/new_decomp_schedule_v1.txt | 24 ++++ .../summarize_chat_relationship_v2.txt | 15 +++ .../prompts/summarize_conversation_v1.txt | 11 ++ 7 files changed, 325 insertions(+) create mode 100644 examples/st_game/actions/gen_iter_chat_utt.py create mode 100644 examples/st_game/plan/converse.py create mode 100644 examples/st_game/prompts/decide_to_talk_v2.txt create mode 100644 examples/st_game/prompts/iterative_convo_v1.txt create mode 100644 examples/st_game/prompts/new_decomp_schedule_v1.txt create mode 100644 examples/st_game/prompts/summarize_chat_relationship_v2.txt create mode 100644 examples/st_game/prompts/summarize_conversation_v1.txt diff --git a/examples/st_game/actions/gen_iter_chat_utt.py b/examples/st_game/actions/gen_iter_chat_utt.py new file mode 100644 index 000000000..02a96191f --- /dev/null +++ b/examples/st_game/actions/gen_iter_chat_utt.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# @Desc : generate_iterative_chat_utt + +from metagpt.logs import logger +from metagpt.schema import Message + +from ..roles.st_role import STRole +from ..actions.st_action import STAction +from ..utils.utils import extract_first_json_dict +from ..maze import Maze + + +class GenIterChatUTT(STAction): + + def __init__(self, name="GenIterChatUTT", context: list[Message] = None, llm=None): + super().__init__(name, context, llm) + + def _func_validate(self, llm_resp: str, prompt: str) -> bool: + resp = False + try: + _ = extract_first_json_dict(llm_resp) + resp = True + except Exception as exp: + pass + return resp + + def _func_cleanup(self, llm_resp: str, prompt: str) -> dict: + gpt_response = extract_first_json_dict(llm_resp) + + cleaned_dict = dict() + cleaned = [] + for key, val in gpt_response.items(): + cleaned += [val] + cleaned_dict["utterance"] = cleaned[0] + cleaned_dict["end"] = True + if "f" in str(cleaned[1]) or "F" in str(cleaned[1]): + cleaned_dict["end"] = False + + return cleaned_dict + + def _func_fail_default_resp(self) -> dict: + cleaned_dict = dict() + cleaned_dict["utterance"] = "..." + cleaned_dict["end"] = False + return cleaned_dict + + async def run(self, maze: Maze, init_role: STRole, target_role: STRole, retrieved: dict, curr_context: str, + curr_chat: list[str], *args, **kwargs) -> dict: + def create_prompt_input(maze: Maze, init_role: STRole, target_role: STRole, + retrieved: dict, curr_context: str, curr_chat: list[str]): + role = init_role + scratch = role._rc.scratch + target_scratch = target_role._rc.scratch + prev_convo_insert = "\n" + if role._rc.memory.chat_list: + for i in role._rc.memory.chat_list: + if i.object == target_role.name: + v1 = int((scratch.curr_time - i.created).total_seconds() / 60) + prev_convo_insert += f"{str(v1)} minutes ago, {scratch.name} and " \ + f"{target_scratch.name} were already {i.description} " \ + f"This context takes place after that conversation." + break + if prev_convo_insert == "\n": + prev_convo_insert = "" + if role._rc.memory.chat_list: + if int((scratch.curr_time - role._rc.memory.chat_list[-1].created).total_seconds() / 60) > 480: + prev_convo_insert = "" + print(prev_convo_insert) + + curr_sector = f"{maze.access_tile(scratch.curr_tile)['sector']}" + curr_arena = f"{maze.access_tile(scratch.curr_tile)['arena']}" + curr_location = f"{curr_arena} in {curr_sector}" + + retrieved_str = "" + for key, vals in retrieved.items(): + for v in vals: + retrieved_str += f"- {v.description}\n" + + convo_str = "" + for i in curr_chat: + convo_str += ": ".join(i) + "\n" + if convo_str == "": + convo_str = "[The conversation has not started yet -- start it!]" + + init_iss = f"Here is Here is a brief description of {scratch.name}.\n{scratch.get_str_iss()}" + prompt_input = [init_iss, scratch.name, retrieved_str, prev_convo_insert, + curr_location, curr_context, scratch.name, target_scratch.name, + convo_str, scratch.name, target_scratch.name, + scratch.name, scratch.name, + scratch.name + ] + return prompt_input + + prompt_input = create_prompt_input(maze, init_role, target_role, retrieved, curr_context, curr_chat) + prompt = self.generate_prompt_with_tmpl_filename(prompt_input, + "iterative_convo_v1.txt") + # original using `ChatGPT_safe_generate_response_OLD` + self.fail_default_resp = self._func_fail_default_resp() + output = await self._run_v1(prompt) + return output diff --git a/examples/st_game/plan/converse.py b/examples/st_game/plan/converse.py new file mode 100644 index 000000000..cf1d92f08 --- /dev/null +++ b/examples/st_game/plan/converse.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# @Desc : conversation between two agents + +from typing import Union, Tuple + +from metagpt.logs import logger + +from ..maze import Maze +from ..roles.st_role import STRole +from ..memory.retrieve import new_retrieve +from ..actions.agent_chat_sum_rel import AgentChatSumRel +from ..actions.gen_iter_chat_utt import GenIterChatUTT + + +def agent_conversation(maze: Maze, init_role: STRole, target_role: STRole) -> list[str]: + curr_chat = [] + logger.info(f"Role: {init_role.name} starts a conversation with Role: {target_role.name}") + + conv_rounds = 8 + for idx in range(conv_rounds): + scratch = init_role._rc.scratch + target_scratch = target_role._rc.scratch + + focal_points = [f"{target_scratch.name}"] + retrieved = new_retrieve(init_role, focal_points, 50) + relationship = generate_summarize_agent_relationship(init_role, target_role, retrieved) + print("-------- relationship: ", relationship) + last_chat = "" + for i in curr_chat[-4:]: + last_chat += ": ".join(i) + "\n" + if last_chat: + focal_points = [f"{relationship}", + f"{target_scratch.name} is {target_scratch.act_description}", + last_chat] + else: + focal_points = [f"{relationship}", + f"{target_scratch.name} is {target_scratch.act_description}"] + retrieved = new_retrieve(init_role, focal_points, 15) + utt, end = generate_one_utterance(maze, init_role, target_role, retrieved, curr_chat) + + curr_chat += [[scratch.name, utt]] + if end: + break + + focal_points = [f"{scratch.name}"] + retrieved = new_retrieve(target_role, focal_points, 50) + relationship = generate_summarize_agent_relationship(target_role, init_role, retrieved) + print("-------- relationship: ", relationship) + last_chat = "" + for i in curr_chat[-4:]: + last_chat += ": ".join(i) + "\n" + if last_chat: + focal_points = [f"{relationship}", + f"{scratch.name} is {scratch.act_description}", + last_chat] + else: + focal_points = [f"{relationship}", + f"{scratch.name} is {scratch.act_description}"] + retrieved = new_retrieve(target_role, focal_points, 15) + utt, end = generate_one_utterance(maze, target_role, init_role, retrieved, curr_chat) + + curr_chat += [[target_scratch.name, utt]] + if end: + break + + print("July 23 PU") + for row in curr_chat: + print(row) + print("July 23 FIN") + + return curr_chat + + +def generate_summarize_agent_relationship(init_role: STRole, + target_role: STRole, + retrieved: dict) -> str: + all_embedding_keys = list() + for key, val in retrieved.items(): + for i in val: + all_embedding_keys += [i.embedding_key] + all_embedding_key_str = "" + for i in all_embedding_keys: + all_embedding_key_str += f"{i}\n" + + summarized_relationship = AgentChatSumRel().run(init_role, + target_role, + all_embedding_key_str) + return summarized_relationship + + +def generate_one_utterance(maze: Maze, init_role, target_role, retrieved: dict, curr_chat: list) -> Tuple[str, str]: + # Chat version optimized for speed via batch generation + scratch = init_role._rc.scratch + target_scratch = target_role._rc.scratch + curr_context = (f"{scratch.name} " + + f"was {scratch.act_description} " + + f"when {scratch.name} " + + f"saw {target_scratch.name} " + + f"in the middle of {target_scratch.act_description}.\n") + curr_context += (f"{scratch.name} " + + f"is initiating a conversation with " + + f"{target_scratch.name}.") + + print("July 23 5") + x = GenIterChatUTT().run(maze, init_role, target_role, retrieved, curr_context, curr_chat) + + print("July 23 6") + + return x["utterance"], x["end"] diff --git a/examples/st_game/prompts/decide_to_talk_v2.txt b/examples/st_game/prompts/decide_to_talk_v2.txt new file mode 100644 index 000000000..94204f9eb --- /dev/null +++ b/examples/st_game/prompts/decide_to_talk_v2.txt @@ -0,0 +1,18 @@ +decide_to_talk_v1.txt + +### +Task -- given context, determine whether the subject will initiate a conversation with another. +Format: +Context: [] +Question: [] +Reasoning: [] +Answer in "yes" or "no": [] +--- +Context: !! +Right now, it is !!. !! and !! last chatted at !! about !!. +!! +!! + +Question: Would !! initiate a conversation with !!? + +Reasoning: Let's think step by step. \ No newline at end of file diff --git a/examples/st_game/prompts/iterative_convo_v1.txt b/examples/st_game/prompts/iterative_convo_v1.txt new file mode 100644 index 000000000..7bd4e7216 --- /dev/null +++ b/examples/st_game/prompts/iterative_convo_v1.txt @@ -0,0 +1,46 @@ +iterative_convo_v1.txt + +Variables: +!! -- persona ISS +!! -- persona name +!! -- retrieved memory +!! -- past context +!! -- current location +!! -- current context +!! -- persona name +!! -- target persona name +!! -- curr convo +!! -- persona name +!! -- target persona name +!! -- persona name +!! -- persona name +!! -- persona name +### +Context for the task: + +PART 1. +!! + +Here is the memory that is in !!'s head: +!! + +PART 2. +Past Context: +!! + +Current Location: !! + +Current Context: +!! + +!! and !! are chatting. Here is their conversation so far: +!! + +--- +Task: Given the above, what should !! say to !! next in the conversation? And did it end the conversation? + +Output format: Output a json of the following format: +{ +"!!": "!'s utterance>", +"Did the conversation end with !!'s utterance?": "" +} \ No newline at end of file diff --git a/examples/st_game/prompts/new_decomp_schedule_v1.txt b/examples/st_game/prompts/new_decomp_schedule_v1.txt new file mode 100644 index 000000000..e21dc69eb --- /dev/null +++ b/examples/st_game/prompts/new_decomp_schedule_v1.txt @@ -0,0 +1,24 @@ +new_decomp_schedule_v1.txt + +Variables: +!! -- persona name +!! -- start hour +!! -- end hour +!! -- original plan +!! -- persona name +!! -- new event +!! -- new event duration +!! -- persona name +!! -- start hour +!! -- end hour +!! -- end hour +!! -- new schedule init + + +### +Here was !!'s originally planned schedule from !! to !!. +!! + +But !! unexpectedly ended up !! for !! minutes. Revise !!'s schedule from !! to !! accordingly (it has to end by !!). +The revised schedule: +!! \ No newline at end of file diff --git a/examples/st_game/prompts/summarize_chat_relationship_v2.txt b/examples/st_game/prompts/summarize_chat_relationship_v2.txt new file mode 100644 index 000000000..6f71824da --- /dev/null +++ b/examples/st_game/prompts/summarize_chat_relationship_v2.txt @@ -0,0 +1,15 @@ +summarize_chat_relationship_v2.txt + +Variables: +!! -- Statements +!! -- curr persona name +!! -- target_persona.scratch.name + +### +[Statements] +!! + +Based on the statements above, summarize !! and !!'s relationship. What do they feel or know about each other? + + +" \ No newline at end of file diff --git a/examples/st_game/prompts/summarize_conversation_v1.txt b/examples/st_game/prompts/summarize_conversation_v1.txt new file mode 100644 index 000000000..1cb423c7d --- /dev/null +++ b/examples/st_game/prompts/summarize_conversation_v1.txt @@ -0,0 +1,11 @@ +summarize_conversation_v1.txt + +Variables: +!! -- init_persona_name + +### +Conversation: +!! + +Summarize the conversation above in one sentence: +This is a conversation about \ No newline at end of file