{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "e9732067-71c7-46f7-ad09-381b3bf21a27",
   "metadata": {},
   "source": [
    "# Generative Agents in LangChain\n",
    "\n",
    "This notebook implements a generative agent based on the paper [Generative Agents: Interactive Simulacra of Human Behavior](https://arxiv.org/abs/2304.03442) by Park, et. al.\n",
    "\n",
    "In it, we leverage a time-weighted Memory object backed by a LangChain Retriever."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "53f81c37-db45-4fdc-843c-aa8fd2a9e99d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Use termcolor to make it easy to colorize the outputs.\n",
    "!pip install termcolor > /dev/null"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "3128fc21",
   "metadata": {},
   "outputs": [],
   "source": [
    "import logging\n",
    "\n",
    "logging.basicConfig(level=logging.ERROR)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "8851c370-b395-4b80-a79d-486a38ffc244",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from datetime import datetime, timedelta\n",
    "from typing import List\n",
    "\n",
    "from langchain.docstore import InMemoryDocstore\n",
    "from langchain.retrievers import TimeWeightedVectorStoreRetriever\n",
    "from langchain_community.vectorstores import FAISS\n",
    "from langchain_openai import ChatOpenAI, OpenAIEmbeddings\n",
    "from termcolor import colored"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "81824e76",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "USER_NAME = \"Person A\"  # The name you want to use when interviewing the agent.\n",
    "LLM = ChatOpenAI(max_tokens=1500)  # Can be any LLM you want."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c3da1649-d88f-4973-b655-7042975cde7e",
   "metadata": {},
   "source": [
    "### Generative Agent Memory Components\n",
    "\n",
    "This tutorial highlights the memory of generative agents and its impact on their behavior. The memory varies from standard LangChain Chat memory in two aspects:\n",
    "\n",
    "1. **Memory Formation**\n",
    "\n",
    "   Generative Agents have extended memories, stored in a single stream:\n",
    "      1. Observations - from dialogues or interactions with the virtual world, about self or others\n",
    "      2. Reflections - resurfaced and summarized core memories\n",
    "\n",
    "\n",
    "2. **Memory Recall**\n",
    "\n",
    "   Memories are retrieved using a weighted sum of salience, recency, and importance.\n",
    "\n",
    "You can review the definitions of the `GenerativeAgent` and `GenerativeAgentMemory` in the [reference documentation](\"https://api.python.langchain.com/en/latest/modules/experimental.html\") for the following imports, focusing on `add_memory` and `summarize_related_memories` methods."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "043e5203-6a41-431c-9efa-3e1743d7d25a",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from langchain_experimental.generative_agents import (\n",
    "    GenerativeAgent,\n",
    "    GenerativeAgentMemory,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "361bd49e",
   "metadata": {
    "jp-MarkdownHeadingCollapsed": true,
    "tags": []
   },
   "source": [
    "## Memory Lifecycle\n",
    "\n",
    "Summarizing the key methods in the above: `add_memory` and `summarize_related_memories`.\n",
    "\n",
    "When an agent makes an observation, it stores the memory:\n",
    "    \n",
    "1. Language model scores the memory's importance (1 for mundane, 10 for poignant)\n",
    "2. Observation and importance are stored within a document by TimeWeightedVectorStoreRetriever, with a `last_accessed_time`.\n",
    "\n",
    "When an agent responds to an observation:\n",
    "\n",
    "1. Generates query(s) for retriever, which fetches documents based on salience, recency, and importance.\n",
    "2. Summarizes the retrieved information\n",
    "3. Updates the `last_accessed_time` for the used documents.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2fa3ca02",
   "metadata": {},
   "source": [
    "## Create a Generative Character\n",
    "\n",
    "\n",
    "\n",
    "Now that we've walked through the definition, we will create two characters named \"Tommie\" and \"Eve\"."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "ee9c1a1d-c311-4f1c-8131-75fccd9025b1",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import math\n",
    "\n",
    "import faiss\n",
    "\n",
    "\n",
    "def relevance_score_fn(score: float) -> float:\n",
    "    \"\"\"Return a similarity score on a scale [0, 1].\"\"\"\n",
    "    # This will differ depending on a few things:\n",
    "    # - the distance / similarity metric used by the VectorStore\n",
    "    # - the scale of your embeddings (OpenAI's are unit norm. Many others are not!)\n",
    "    # This function converts the euclidean norm of normalized embeddings\n",
    "    # (0 is most similar, sqrt(2) most dissimilar)\n",
    "    # to a similarity function (0 to 1)\n",
    "    return 1.0 - score / math.sqrt(2)\n",
    "\n",
    "\n",
    "def create_new_memory_retriever():\n",
    "    \"\"\"Create a new vector store retriever unique to the agent.\"\"\"\n",
    "    # Define your embedding model\n",
    "    embeddings_model = OpenAIEmbeddings()\n",
    "    # Initialize the vectorstore as empty\n",
    "    embedding_size = 1536\n",
    "    index = faiss.IndexFlatL2(embedding_size)\n",
    "    vectorstore = FAISS(\n",
    "        embeddings_model.embed_query,\n",
    "        index,\n",
    "        InMemoryDocstore({}),\n",
    "        {},\n",
    "        relevance_score_fn=relevance_score_fn,\n",
    "    )\n",
    "    return TimeWeightedVectorStoreRetriever(\n",
    "        vectorstore=vectorstore, other_score_keys=[\"importance\"], k=15\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "7884f9dd-c597-4c27-8c77-1402c71bc2f8",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "tommies_memory = GenerativeAgentMemory(\n",
    "    llm=LLM,\n",
    "    memory_retriever=create_new_memory_retriever(),\n",
    "    verbose=False,\n",
    "    reflection_threshold=8,  # we will give this a relatively low number to show how reflection works\n",
    ")\n",
    "\n",
    "tommie = GenerativeAgent(\n",
    "    name=\"Tommie\",\n",
    "    age=25,\n",
    "    traits=\"anxious, likes design, talkative\",  # You can add more persistent traits here\n",
    "    status=\"looking for a job\",  # When connected to a virtual world, we can have the characters update their status\n",
    "    memory_retriever=create_new_memory_retriever(),\n",
    "    llm=LLM,\n",
    "    memory=tommies_memory,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "c524d529",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Name: Tommie (age: 25)\n",
      "Innate traits: anxious, likes design, talkative\n",
      "No information about Tommie's core characteristics is provided in the given statements.\n"
     ]
    }
   ],
   "source": [
    "# The current \"Summary\" of a character can't be made because the agent hasn't made\n",
    "# any observations yet.\n",
    "print(tommie.get_summary())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "4be60979-d56e-4abf-a636-b34ffa8b7fba",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# We can add memories directly to the memory object\n",
    "tommie_observations = [\n",
    "    \"Tommie remembers his dog, Bruno, from when he was a kid\",\n",
    "    \"Tommie feels tired from driving so far\",\n",
    "    \"Tommie sees the new home\",\n",
    "    \"The new neighbors have a cat\",\n",
    "    \"The road is noisy at night\",\n",
    "    \"Tommie is hungry\",\n",
    "    \"Tommie tries to get some rest.\",\n",
    "]\n",
    "for observation in tommie_observations:\n",
    "    tommie.memory.add_memory(observation)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "6992b48b-697f-4973-9560-142ef85357d7",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Name: Tommie (age: 25)\n",
      "Innate traits: anxious, likes design, talkative\n",
      "Tommie is a person who is observant of his surroundings, has a sentimental side, and experiences basic human needs such as hunger and the need for rest. He also tends to get tired easily and is affected by external factors such as noise from the road or a neighbor's pet.\n"
     ]
    }
   ],
   "source": [
    "# Now that Tommie has 'memories', their self-summary is more descriptive, though still rudimentary.\n",
    "# We will see how this summary updates after more observations to create a more rich description.\n",
    "print(tommie.get_summary(force_refresh=True))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "40d39a32-838c-4a03-8b27-a52c76c402e7",
   "metadata": {
    "tags": []
   },
   "source": [
    "## Pre-Interview with Character\n",
    "\n",
    "Before sending our character on their way, let's ask them a few questions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "eaf125d8-f54c-4c5f-b6af-32789b1f7d3a",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def interview_agent(agent: GenerativeAgent, message: str) -> str:\n",
    "    \"\"\"Help the notebook user interact with the agent.\"\"\"\n",
    "    new_message = f\"{USER_NAME} says {message}\"\n",
    "    return agent.generate_dialogue_response(new_message)[1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "54024d41-6e83-4914-91e5-73140e2dd9c8",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Tommie said \"I really enjoy design and being creative. I\\'ve been working on some personal projects lately. What about you, Person A? What do you like to do?\"'"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "interview_agent(tommie, \"What do you like to do?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "71e2e8cc-921e-4816-82f1-66962b2c1055",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Tommie said \"Well, I\\'m actually looking for a job right now, so hopefully I can find some job postings online and start applying. How about you, Person A? What\\'s on your schedule for today?\"'"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "interview_agent(tommie, \"What are you looking forward to doing today?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "a2521ffc-7050-4ac3-9a18-4cccfc798c31",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Tommie said \"Honestly, I\\'m feeling pretty anxious about finding a job. It\\'s been a bit of a struggle lately, but I\\'m trying to stay positive and keep searching. How about you, Person A? What worries you?\"'"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "interview_agent(tommie, \"What are you most worried about today?\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e509c468-f7cd-4d72-9f3a-f4aba28b1eea",
   "metadata": {},
   "source": [
    "## Step through the day's observations."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "154dee3d-bfe0-4828-b963-ed7e885799b3",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# Let's have Tommie start going through a day in the life.\n",
    "observations = [\n",
    "    \"Tommie wakes up to the sound of a noisy construction site outside his window.\",\n",
    "    \"Tommie gets out of bed and heads to the kitchen to make himself some coffee.\",\n",
    "    \"Tommie realizes he forgot to buy coffee filters and starts rummaging through his moving boxes to find some.\",\n",
    "    \"Tommie finally finds the filters and makes himself a cup of coffee.\",\n",
    "    \"The coffee tastes bitter, and Tommie regrets not buying a better brand.\",\n",
    "    \"Tommie checks his email and sees that he has no job offers yet.\",\n",
    "    \"Tommie spends some time updating his resume and cover letter.\",\n",
    "    \"Tommie heads out to explore the city and look for job openings.\",\n",
    "    \"Tommie sees a sign for a job fair and decides to attend.\",\n",
    "    \"The line to get in is long, and Tommie has to wait for an hour.\",\n",
    "    \"Tommie meets several potential employers at the job fair but doesn't receive any offers.\",\n",
    "    \"Tommie leaves the job fair feeling disappointed.\",\n",
    "    \"Tommie stops by a local diner to grab some lunch.\",\n",
    "    \"The service is slow, and Tommie has to wait for 30 minutes to get his food.\",\n",
    "    \"Tommie overhears a conversation at the next table about a job opening.\",\n",
    "    \"Tommie asks the diners about the job opening and gets some information about the company.\",\n",
    "    \"Tommie decides to apply for the job and sends his resume and cover letter.\",\n",
    "    \"Tommie continues his search for job openings and drops off his resume at several local businesses.\",\n",
    "    \"Tommie takes a break from his job search to go for a walk in a nearby park.\",\n",
    "    \"A dog approaches and licks Tommie's feet, and he pets it for a few minutes.\",\n",
    "    \"Tommie sees a group of people playing frisbee and decides to join in.\",\n",
    "    \"Tommie has fun playing frisbee but gets hit in the face with the frisbee and hurts his nose.\",\n",
    "    \"Tommie goes back to his apartment to rest for a bit.\",\n",
    "    \"A raccoon tore open the trash bag outside his apartment, and the garbage is all over the floor.\",\n",
    "    \"Tommie starts to feel frustrated with his job search.\",\n",
    "    \"Tommie calls his best friend to vent about his struggles.\",\n",
    "    \"Tommie's friend offers some words of encouragement and tells him to keep trying.\",\n",
    "    \"Tommie feels slightly better after talking to his friend.\",\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "238be49c-edb3-4e26-a2b6-98777ba8de86",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[32mTommie wakes up to the sound of a noisy construction site outside his window.\u001b[0m Tommie groans and covers his head with a pillow, trying to block out the noise.\n",
      "\u001b[32mTommie gets out of bed and heads to the kitchen to make himself some coffee.\u001b[0m Tommie stretches his arms and yawns before starting to make the coffee.\n",
      "\u001b[32mTommie realizes he forgot to buy coffee filters and starts rummaging through his moving boxes to find some.\u001b[0m Tommie sighs in frustration and continues searching through the boxes.\n",
      "\u001b[32mTommie finally finds the filters and makes himself a cup of coffee.\u001b[0m Tommie takes a deep breath and enjoys the aroma of the fresh coffee.\n",
      "\u001b[32mThe coffee tastes bitter, and Tommie regrets not buying a better brand.\u001b[0m Tommie grimaces and sets the coffee mug aside.\n",
      "\u001b[32mTommie checks his email and sees that he has no job offers yet.\u001b[0m Tommie sighs and closes his laptop, feeling discouraged.\n",
      "\u001b[32mTommie spends some time updating his resume and cover letter.\u001b[0m Tommie nods, feeling satisfied with his progress.\n",
      "\u001b[32mTommie heads out to explore the city and look for job openings.\u001b[0m Tommie feels a surge of excitement and anticipation as he steps out into the city.\n",
      "\u001b[32mTommie sees a sign for a job fair and decides to attend.\u001b[0m Tommie feels hopeful and excited about the possibility of finding job opportunities at the job fair.\n",
      "\u001b[32mThe line to get in is long, and Tommie has to wait for an hour.\u001b[0m Tommie taps his foot impatiently and checks his phone for the time.\n",
      "\u001b[32mTommie meets several potential employers at the job fair but doesn't receive any offers.\u001b[0m Tommie feels disappointed and discouraged, but he remains determined to keep searching for job opportunities.\n",
      "\u001b[32mTommie leaves the job fair feeling disappointed.\u001b[0m Tommie feels disappointed and discouraged, but he remains determined to keep searching for job opportunities.\n",
      "\u001b[32mTommie stops by a local diner to grab some lunch.\u001b[0m Tommie feels relieved to take a break and satisfy his hunger.\n",
      "\u001b[32mThe service is slow, and Tommie has to wait for 30 minutes to get his food.\u001b[0m Tommie feels frustrated and impatient due to the slow service.\n",
      "\u001b[32mTommie overhears a conversation at the next table about a job opening.\u001b[0m Tommie feels a surge of hope and excitement at the possibility of a job opportunity but decides not to interfere with the conversation at the next table.\n",
      "\u001b[32mTommie asks the diners about the job opening and gets some information about the company.\u001b[0m Tommie said \"Excuse me, I couldn't help but overhear your conversation about the job opening. Could you give me some more information about the company?\"\n",
      "\u001b[32mTommie decides to apply for the job and sends his resume and cover letter.\u001b[0m Tommie feels hopeful and proud of himself for taking action towards finding a job.\n",
      "\u001b[32mTommie continues his search for job openings and drops off his resume at several local businesses.\u001b[0m Tommie feels hopeful and determined to keep searching for job opportunities.\n",
      "\u001b[32mTommie takes a break from his job search to go for a walk in a nearby park.\u001b[0m Tommie feels refreshed and rejuvenated after taking a break in the park.\n",
      "\u001b[32mA dog approaches and licks Tommie's feet, and he pets it for a few minutes.\u001b[0m Tommie feels happy and enjoys the brief interaction with the dog.\n",
      "****************************************\n",
      "\u001b[34mAfter 20 observations, Tommie's summary is:\n",
      "Name: Tommie (age: 25)\n",
      "Innate traits: anxious, likes design, talkative\n",
      "Tommie is determined and hopeful in his search for job opportunities, despite encountering setbacks and disappointments. He is also able to take breaks and care for his physical needs, such as getting rest and satisfying his hunger. Tommie is nostalgic towards his past, as shown by his memory of his childhood dog. Overall, Tommie is a hardworking and resilient individual who remains focused on his goals.\u001b[0m\n",
      "****************************************\n",
      "\u001b[32mTommie sees a group of people playing frisbee and decides to join in.\u001b[0m Do nothing.\n",
      "\u001b[32mTommie has fun playing frisbee but gets hit in the face with the frisbee and hurts his nose.\u001b[0m Tommie feels pain and puts a hand to his nose to check for any injury.\n",
      "\u001b[32mTommie goes back to his apartment to rest for a bit.\u001b[0m Tommie feels relieved to take a break and rest for a bit.\n",
      "\u001b[32mA raccoon tore open the trash bag outside his apartment, and the garbage is all over the floor.\u001b[0m Tommie feels annoyed and frustrated at the mess caused by the raccoon.\n",
      "\u001b[32mTommie starts to feel frustrated with his job search.\u001b[0m Tommie feels discouraged but remains determined to keep searching for job opportunities.\n",
      "\u001b[32mTommie calls his best friend to vent about his struggles.\u001b[0m Tommie said \"Hey, can I talk to you for a bit? I'm feeling really frustrated with my job search.\"\n",
      "\u001b[32mTommie's friend offers some words of encouragement and tells him to keep trying.\u001b[0m Tommie said \"Thank you, I really appreciate your support and encouragement.\"\n",
      "\u001b[32mTommie feels slightly better after talking to his friend.\u001b[0m Tommie feels grateful for his friend's support.\n"
     ]
    }
   ],
   "source": [
    "# Let's send Tommie on their way. We'll check in on their summary every few observations to watch it evolve\n",
    "for i, observation in enumerate(observations):\n",
    "    _, reaction = tommie.generate_reaction(observation)\n",
    "    print(colored(observation, \"green\"), reaction)\n",
    "    if ((i + 1) % 20) == 0:\n",
    "        print(\"*\" * 40)\n",
    "        print(\n",
    "            colored(\n",
    "                f\"After {i+1} observations, Tommie's summary is:\\n{tommie.get_summary(force_refresh=True)}\",\n",
    "                \"blue\",\n",
    "            )\n",
    "        )\n",
    "        print(\"*\" * 40)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dd62a275-7290-43ca-aa0f-504f3a706d09",
   "metadata": {},
   "source": [
    "## Interview after the day"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "6336ab5d-3074-4831-951f-c9e2cba5dfb5",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Tommie said \"It\\'s been a bit of a rollercoaster, to be honest. I\\'ve had some setbacks in my job search, but I also had some good moments today, like sending out a few resumes and meeting some potential employers at a job fair. How about you?\"'"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "interview_agent(tommie, \"Tell me about how your day has been going\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "809ac906-69b7-4326-99ec-af638d32bb20",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Tommie said \"I really enjoy coffee, but sometimes I regret not buying a better brand. How about you?\"'"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "interview_agent(tommie, \"How do you feel about coffee?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "f733a431-19ea-421a-9101-ae2593a8c626",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Tommie said \"Oh, I had a dog named Bruno when I was a kid. He was a golden retriever and my best friend. I have so many fond memories of him.\"'"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "interview_agent(tommie, \"Tell me about your childhood dog!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c9261428-778a-4c0b-b725-bc9e91b71391",
   "metadata": {},
   "source": [
    "## Adding Multiple Characters\n",
    "\n",
    "Let's add a second character to have a conversation with Tommie. Feel free to configure different traits."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "id": "ec8bbe18-a021-419c-bf1f-23d34732cd99",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "eves_memory = GenerativeAgentMemory(\n",
    "    llm=LLM,\n",
    "    memory_retriever=create_new_memory_retriever(),\n",
    "    verbose=False,\n",
    "    reflection_threshold=5,\n",
    ")\n",
    "\n",
    "\n",
    "eve = GenerativeAgent(\n",
    "    name=\"Eve\",\n",
    "    age=34,\n",
    "    traits=\"curious, helpful\",  # You can add more persistent traits here\n",
    "    status=\"N/A\",  # When connected to a virtual world, we can have the characters update their status\n",
    "    llm=LLM,\n",
    "    daily_summaries=[\n",
    "        (\n",
    "            \"Eve started her new job as a career counselor last week and received her first assignment, a client named Tommie.\"\n",
    "        )\n",
    "    ],\n",
    "    memory=eves_memory,\n",
    "    verbose=False,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "1e2745f5-e0da-4abd-98b4-830802ce6698",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "yesterday = (datetime.now() - timedelta(days=1)).strftime(\"%A %B %d\")\n",
    "eve_observations = [\n",
    "    \"Eve wakes up and hear's the alarm\",\n",
    "    \"Eve eats a boal of porridge\",\n",
    "    \"Eve helps a coworker on a task\",\n",
    "    \"Eve plays tennis with her friend Xu before going to work\",\n",
    "    \"Eve overhears her colleague say something about Tommie being hard to work with\",\n",
    "]\n",
    "for observation in eve_observations:\n",
    "    eve.memory.add_memory(observation)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "de4726e3-4bb1-47da-8fd9-f317a036fe0f",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Name: Eve (age: 34)\n",
      "Innate traits: curious, helpful\n",
      "Eve is a helpful and active person who enjoys sports and takes care of her physical health. She is attentive to her surroundings, including her colleagues, and has good time management skills.\n"
     ]
    }
   ],
   "source": [
    "print(eve.get_summary())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "837524e9-7f7e-4e9f-b610-f454062f5915",
   "metadata": {},
   "source": [
    "## Pre-conversation interviews\n",
    "\n",
    "\n",
    "Let's \"Interview\" Eve before she speaks with Tommie."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "6cda916d-800c-47bc-a7f9-6a2f19187472",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Eve said \"I\\'m feeling pretty good, thanks for asking! Just trying to stay productive and make the most of the day. How about you?\"'"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "interview_agent(eve, \"How are you feeling about today?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "448ae644-0a66-4eb2-a03a-319f36948b37",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Eve said \"I don\\'t know much about Tommie, but I heard someone mention that they find them difficult to work with. Have you had any experiences working with Tommie?\"'"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "interview_agent(eve, \"What do you know about Tommie?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "493fc5b8-8730-4ef8-9820-0f1769ce1691",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Eve said \"That\\'s interesting. I don\\'t know much about Tommie\\'s work experience, but I would probably ask about his strengths and areas for improvement. What about you?\"'"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "interview_agent(\n",
    "    eve,\n",
    "    \"Tommie is looking to find a job. What are are some things you'd like to ask him?\",\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "4b46452a-6c54-4db2-9d87-18597f70fec8",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Eve said \"Sure, I can keep the conversation going and ask plenty of questions. I want to make sure Tommie feels comfortable and supported. Thanks for letting me know.\"'"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "interview_agent(\n",
    "    eve,\n",
    "    \"You'll have to ask him. He may be a bit anxious, so I'd appreciate it if you keep the conversation going and ask as many questions as possible.\",\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dd780655-1d73-4fcb-a78d-79fd46a20636",
   "metadata": {},
   "source": [
    "## Dialogue between Generative Agents\n",
    "\n",
    "Generative agents are much more complex when they interact with a virtual environment or with each other. Below, we run a simple conversation between Tommie and Eve."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "042ea271-4bf1-4247-9082-239a6fea43b8",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def run_conversation(agents: List[GenerativeAgent], initial_observation: str) -> None:\n",
    "    \"\"\"Runs a conversation between agents.\"\"\"\n",
    "    _, observation = agents[1].generate_reaction(initial_observation)\n",
    "    print(observation)\n",
    "    turns = 0\n",
    "    while True:\n",
    "        break_dialogue = False\n",
    "        for agent in agents:\n",
    "            stay_in_dialogue, observation = agent.generate_dialogue_response(\n",
    "                observation\n",
    "            )\n",
    "            print(observation)\n",
    "            # observation = f\"{agent.name} said {reaction}\"\n",
    "            if not stay_in_dialogue:\n",
    "                break_dialogue = True\n",
    "        if break_dialogue:\n",
    "            break\n",
    "        turns += 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "d5462b14-218e-4d85-b035-df57ea8e0f80",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Eve said \"Sure, Tommie. I'd be happy to share about my experience. Where would you like me to start?\"\n",
      "Tommie said \"That's great, thank you! How about you start by telling me about your previous work experience?\"\n",
      "Eve said \"Sure, I'd be happy to share my previous work experience with you. I've worked in a few different industries, including marketing and event planning. What specific questions do you have for me?\"\n",
      "Tommie said \"That's great to hear. Can you tell me more about your experience in event planning? I've always been interested in that field.\"\n",
      "Eve said \"Sure, I'd be happy to share about my experience in event planning. I've worked on a variety of events, from corporate conferences to weddings. One of the biggest challenges I faced was managing multiple vendors and ensuring everything ran smoothly on the day of the event. What specific questions do you have?\"\n",
      "Tommie said \"That sounds like a lot of responsibility! Can you tell me more about how you handled the challenges that came up during those events?\"\n",
      "Eve said \"Sure, Tommie. I'd be happy to share with you how I handled those challenges. One approach that worked well for me was to stay organized and create a detailed timeline for the event. This helped me keep track of all the different tasks that needed to be done and when they needed to be completed. I also made sure to communicate clearly with all the vendors and team members involved in the event to ensure everyone was on the same page. Would you like me to go into more detail?\"\n",
      "Tommie said \"Thank you for sharing that with me, Eve. That sounds like a great approach to managing events. Can you tell me more about how you handled any unexpected issues that came up during the events?\"\n",
      "Eve said \"Of course, Tommie. One example of an unexpected issue I faced was when one of the vendors didn't show up on time. To handle this, I quickly contacted a backup vendor and was able to get everything back on track. It's always important to have a backup plan in case things don't go as planned. Do you have any other questions about event planning?\"\n",
      "Tommie said \"Thank you for sharing that with me, Eve. It's really helpful to hear how you handled unexpected issues like that. Can you give me an example of how you communicated with your team to ensure everyone was on the same page during an event?\"\n",
      "Eve said \"Sure, Tommie. One thing I did to ensure everyone was on the same page was to have regular check-ins and meetings with the team leading up to the event. This helped us address any issues or concerns early on and make sure everyone was clear on their roles and responsibilities. Have you ever had to manage a team for an event before?\"\n",
      "Tommie said \"That's a great idea, Eve. I haven't had the opportunity to manage a team for an event yet, but I'll definitely keep that in mind for the future. Thank you for sharing your experience with me.\"\n",
      "Eve said \"Thanks for the opportunity to share my experience, Tommie. It was great meeting with you today.\"\n"
     ]
    }
   ],
   "source": [
    "agents = [tommie, eve]\n",
    "run_conversation(\n",
    "    agents,\n",
    "    \"Tommie said: Hi, Eve. Thanks for agreeing to meet with me today. I have a bunch of questions and am not sure where to start. Maybe you could first share about your experience?\",\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1b28fe80-03dc-4399-961d-6e9ee1980216",
   "metadata": {
    "tags": []
   },
   "source": [
    "## Let's interview our agents after their conversation\n",
    "\n",
    "Since the generative agents retain their memories from the day, we can ask them about their plans, conversations, and other memoreis."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "id": "c4d252f3-fcc1-474c-846e-a7605a6b4ce7",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Name: Tommie (age: 25)\n",
      "Innate traits: anxious, likes design, talkative\n",
      "Tommie is determined and hopeful in his job search, but can also feel discouraged and frustrated at times. He has a strong connection to his childhood dog, Bruno. Tommie seeks support from his friends when feeling overwhelmed and is grateful for their help. He also enjoys exploring his new city.\n"
     ]
    }
   ],
   "source": [
    "# We can see a current \"Summary\" of a character based on their own perception of self\n",
    "# has changed\n",
    "print(tommie.get_summary(force_refresh=True))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "id": "c04db9a4",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Name: Eve (age: 34)\n",
      "Innate traits: curious, helpful\n",
      "Eve is a helpful and friendly person who enjoys playing sports and staying productive. She is attentive and responsive to others' needs, actively listening and asking questions to understand their perspectives. Eve has experience in event planning and communication, and is willing to share her knowledge and expertise with others. She values teamwork and collaboration, and strives to create a comfortable and supportive environment for everyone.\n"
     ]
    }
   ],
   "source": [
    "print(eve.get_summary(force_refresh=True))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "id": "71762558-8fb6-44d7-8483-f5b47fb2a862",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Tommie said \"It was really helpful actually. Eve shared some great tips on managing events and handling unexpected issues. I feel like I learned a lot from her experience.\"'"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "interview_agent(tommie, \"How was your conversation with Eve?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "id": "085af3d8-ac21-41ea-8f8b-055c56976a67",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Eve said \"It was great, thanks for asking. Tommie was very receptive and had some great questions about event planning. How about you, have you had any interactions with Tommie?\"'"
      ]
     },
     "execution_count": 59,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "interview_agent(eve, \"How was your conversation with Tommie?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "id": "5b439f3c-7849-4432-a697-2bcc85b89dae",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Eve said \"It was great meeting with you, Tommie. If you have any more questions or need any help in the future, don\\'t hesitate to reach out to me. Have a great day!\"'"
      ]
     },
     "execution_count": 60,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "interview_agent(eve, \"What do you wish you would have said to Tommie?\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}