{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Conversation Patterns\n",
    "\n",
    "In the previous chapter we used two-agent conversation, which\n",
    "can be started by the `initiate_chat` method.\n",
    "Two-agent chat is a useful conversation pattern but AutoGen offers more.\n",
    "In this chapter, we will first dig a little bit more into the two-agent \n",
    "chat pattern and chat result, \n",
    "then we will show you several conversation patterns that involve \n",
    "more than two agents.\n",
    "\n",
    "### An Overview\n",
    "\n",
    "1. **Two-agent chat**: the simplest form of conversation pattern where two agents chat with each other.\n",
    "2. **Sequential chat**: a sequence of chats between two agents, chained together by a carryover mechanism, which brings the summary of the previous chat to the context of the next chat.\n",
    "3. **Group Chat**: a single chat involving more than two agents. An important question in group chat is: What agent should be next to speak? To support different scenarios, we provide different ways to organize agents in a group chat:\n",
    "    - We support several strategies to select the next agent: `round_robin`, `random`, `manual` (human selection), and `auto` (Default, using an LLM to decide).\n",
    "    - We provide a way to constrain the selection of the next speaker (See examples below).\n",
    "    - We allow you to pass in a function to customize the selection of the next speaker. With this feature, you can build a **StateFlow** model which allows a deterministic workflow among your agents.\n",
    " Please refer to this [guide](/docs/topics/groupchat/customized_speaker_selection) and this [blog post](/blog/2024/02/29/StateFlow) on StateFlow for more details.\n",
    "4. **Nested Chat**: package a workflow into a single agent for reuse in a larger workflow."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Two-Agent Chat and Chat Result\n",
    "\n",
    "Two-agent chat is the simplest form of conversation pattern. \n",
    "We start a two-agent chat using the `initiate_chat` method of every \n",
    "`ConversableAgent` agent.\n",
    "We have already\n",
    "seen multiple examples of two-agent chats in previous chapters\n",
    "but we haven't covered the details.\n",
    "\n",
    "The following figure illustrates how two-agent chat works.\n",
    "\n",
    "```{=mdx}\n",
    "![Two-agent chat](./assets/two-agent-chat.png)\n",
    "```\n",
    "\n",
    "A two-agent chats takes two inputs: a message, which is a string provided by\n",
    "the caller; a context, which specifies various parameters of the chat.\n",
    "The sender agent uses its chat initializer method\n",
    "(i.e., `generate_init_message` method of `ConversableAgent`)\n",
    "to generate an initial message from the inputs, and\n",
    "sends it to the recipient agent to start the chat.\n",
    "The sender agent is the agent whose `initiate_chat` method is called, and\n",
    "the recipient agent is the other agent.\n",
    "\n",
    "Once the chat terminates, the history of the chat is processed by a \n",
    "chat summarizer. The summarizer summarizes the chat history and calculates\n",
    "the token usage of the chat. \n",
    "You can configure the type of summary using the `summary_method`\n",
    "parameter of the `initiate_chat` method. By default, it is the last\n",
    "message of the chat (i.e., `summary_method='last_msg'`).\n",
    "\n",
    "The example below is a two-agent chat between a student agent and a teacher\n",
    "agent. Its summarizer uses an LLM-based summary."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[33mStudent_Agent\u001b[0m (to Teacher_Agent):\n",
      "\n",
      "What is triangle inequality?\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[31m\n",
      ">>>>>>>> USING AUTO REPLY...\u001b[0m\n",
      "\u001b[33mTeacher_Agent\u001b[0m (to Student_Agent):\n",
      "\n",
      "Triangle inequality theorem is a fundamental principle in geometry that states that the sum of the lengths of any two sides of a triangle must always be greater than the length of the third side. In a triangle with sides of lengths a, b, and c, the theorem can be written as:\n",
      "\n",
      "a + b > c\n",
      "a + c > b\n",
      "b + c > a\n",
      "\n",
      "Each of these represents the condition for one specific side (a, b, or c). All must be true for a triangle to exist.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[31m\n",
      ">>>>>>>> USING AUTO REPLY...\u001b[0m\n",
      "\u001b[33mStudent_Agent\u001b[0m (to Teacher_Agent):\n",
      "\n",
      "Thank you for the explanation. This theorem helps in understanding the basic properties of a triangle. It can also be useful when solving geometric problems or proving other mathematical theorems. Can you give me an example of how we can use the triangle inequality theorem?\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[31m\n",
      ">>>>>>>> USING AUTO REPLY...\u001b[0m\n",
      "\u001b[33mTeacher_Agent\u001b[0m (to Student_Agent):\n",
      "\n",
      "Absolutely! Here's an example:\n",
      "\n",
      "Suppose you're given three line segments with lengths 10, 7, and 3 units. The question is: \"Can these three line segments form a triangle?\"\n",
      "\n",
      "To answer this, you would use the triangle inequality theorem. Adding any two side lengths together should be greater than the third:\n",
      "\n",
      "- For sides 10 and 7: 10 + 7 = 17, which is larger than 3.\n",
      "- For sides 10 and 3: 10 + 3 = 13, which is larger than 7.\n",
      "- For sides 7 and 3: 7 + 3 = 10, which is equal to the length of the third side (10), but not greater.\n",
      "\n",
      "So, these three lines cannot form a triangle, because not all pairs of sides satisfy the triangle inequality theorem.\n",
      "\n",
      "--------------------------------------------------------------------------------\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "\n",
    "from autogen import ConversableAgent\n",
    "\n",
    "student_agent = ConversableAgent(\n",
    "    name=\"Student_Agent\",\n",
    "    system_message=\"You are a student willing to learn.\",\n",
    "    llm_config={\"config_list\": [{\"model\": \"gpt-4\", \"api_key\": os.environ[\"OPENAI_API_KEY\"]}]},\n",
    ")\n",
    "teacher_agent = ConversableAgent(\n",
    "    name=\"Teacher_Agent\",\n",
    "    system_message=\"You are a math teacher.\",\n",
    "    llm_config={\"config_list\": [{\"model\": \"gpt-4\", \"api_key\": os.environ[\"OPENAI_API_KEY\"]}]},\n",
    ")\n",
    "\n",
    "chat_result = student_agent.initiate_chat(\n",
    "    teacher_agent,\n",
    "    message=\"What is triangle inequality?\",\n",
    "    summary_method=\"reflection_with_llm\",\n",
    "    max_turns=2,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's see what the summary looks like.\n",
    "The summary is stored in the `chat_result` object of the type `ChatResult` \n",
    "that was returned by the `initiate_chat` method."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The triangle inequality theorem states that in a triangle, the sum of the lengths of any two sides must always be greater than the length of the third side. This principle is significant in geometry and is used in solving problems or proving theorems. For instance, if given three line segments, you can determine if they can form a triangle using this theorem.\n"
     ]
    }
   ],
   "source": [
    "print(chat_result.summary)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the above example, the summary method is set to `reflection_with_llm` which\n",
    "takes a list of messages from the conversation and summarize them \n",
    "using a call to an LLM.\n",
    "The summary method first tries to use the recipient's LLM, if it is not available\n",
    "then it uses the sender's LLM. In this case the recipient is \"Teacher_Agent\" and\n",
    "the sender is \"Student_Agent\".\n",
    "The input prompt for the LLM is the following default prompt:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Summarize the takeaway from the conversation. Do not add any introductory phrases.\n"
     ]
    }
   ],
   "source": [
    "print(ConversableAgent.DEFAULT_SUMMARY_PROMPT)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can also use a custom prompt by setting the `summary_prompt` argument\n",
    "of `initiate_chat`.\n",
    "\n",
    "There are some other useful information in the `ChatResult` object, including\n",
    "the conversation history, human input, and token cost."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[{'content': 'What is triangle inequality?', 'role': 'assistant'},\n",
      " {'content': 'Triangle inequality theorem is a fundamental principle in '\n",
      "             'geometry that states that the sum of the lengths of any two '\n",
      "             'sides of a triangle must always be greater than the length of '\n",
      "             'the third side. In a triangle with sides of lengths a, b, and c, '\n",
      "             'the theorem can be written as:\\n'\n",
      "             '\\n'\n",
      "             'a + b > c\\n'\n",
      "             'a + c > b\\n'\n",
      "             'b + c > a\\n'\n",
      "             '\\n'\n",
      "             'Each of these represents the condition for one specific side (a, '\n",
      "             'b, or c). All must be true for a triangle to exist.',\n",
      "  'role': 'user'},\n",
      " {'content': 'Thank you for the explanation. This theorem helps in '\n",
      "             'understanding the basic properties of a triangle. It can also be '\n",
      "             'useful when solving geometric problems or proving other '\n",
      "             'mathematical theorems. Can you give me an example of how we can '\n",
      "             'use the triangle inequality theorem?',\n",
      "  'role': 'assistant'},\n",
      " {'content': \"Absolutely! Here's an example:\\n\"\n",
      "             '\\n'\n",
      "             \"Suppose you're given three line segments with lengths 10, 7, and \"\n",
      "             '3 units. The question is: \"Can these three line segments form a '\n",
      "             'triangle?\"\\n'\n",
      "             '\\n'\n",
      "             'To answer this, you would use the triangle inequality theorem. '\n",
      "             'Adding any two side lengths together should be greater than the '\n",
      "             'third:\\n'\n",
      "             '\\n'\n",
      "             '- For sides 10 and 7: 10 + 7 = 17, which is larger than 3.\\n'\n",
      "             '- For sides 10 and 3: 10 + 3 = 13, which is larger than 7.\\n'\n",
      "             '- For sides 7 and 3: 7 + 3 = 10, which is equal to the length of '\n",
      "             'the third side (10), but not greater.\\n'\n",
      "             '\\n'\n",
      "             'So, these three lines cannot form a triangle, because not all '\n",
      "             'pairs of sides satisfy the triangle inequality theorem.',\n",
      "  'role': 'user'}]\n"
     ]
    }
   ],
   "source": [
    "# Get the chat history.\n",
    "import pprint\n",
    "\n",
    "pprint.pprint(chat_result.chat_history)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "That chat messages in the chat result are from the \n",
    "recipient agent's perspective -- the sender is the \"assistant\" and the recipient\n",
    "is the \"user\"."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "({'gpt-4-0613': {'completion_tokens': 399,\n",
      "                 'cost': 0.04521,\n",
      "                 'prompt_tokens': 709,\n",
      "                 'total_tokens': 1108},\n",
      "  'total_cost': 0.04521},\n",
      " {'total_cost': 0})\n"
     ]
    }
   ],
   "source": [
    "# Get the cost of the chat.\n",
    "pprint.pprint(chat_result.cost)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Sequential Chats\n",
    "\n",
    "The name of this pattern is self-explanatory -- it is a sequence of\n",
    "chats between two agents, chained together by a mechanism called *carryover*,\n",
    "which brings the summary of the previous chat to the context\n",
    "of the next chat.\n",
    "\n",
    "This pattern is useful for complex task that can be broken down into \n",
    "interdependent sub-tasks. \n",
    "The figure below illustrate how this pattern works.\n",
    "\n",
    "```{=mdx}\n",
    "![initiate_chats](./assets/sequential-two-agent-chat.png)\n",
    "```\n",
    "\n",
    "In this pattern, the a pair of agents first start a two-agent chat,\n",
    "then the summary of the conversation becomes a *carryover* for the next\n",
    "two-agent chat. The next chat passes the carryover to the `carryover` parameter\n",
    "of the context to generate its initial message.\n",
    "\n",
    "Carryover accumulates as the conversation moves forward,\n",
    "so each subsequent chat starts with all the carryovers \n",
    "from previous chats.\n",
    "\n",
    "The figure above shows distinct recipient agents for all the chats, however,\n",
    "the recipient agents in the sequence are allowed to repeat."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To illustrate this pattern, let's consider a simple example of arithmetic\n",
    "operator agents. One agent \n",
    "(called the \"Number_Agent\") is responsible for coming up with a number,\n",
    "and other agents are responsible for performing a specific arithmetic\n",
    "operation on the number, e.g., add 1, multiply by 2, etc.."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "# The Number Agent always returns the same numbers.\n",
    "number_agent = ConversableAgent(\n",
    "    name=\"Number_Agent\",\n",
    "    system_message=\"You return me the numbers I give you, one number each line.\",\n",
    "    llm_config={\"config_list\": [{\"model\": \"gpt-4\", \"api_key\": os.environ[\"OPENAI_API_KEY\"]}]},\n",
    "    human_input_mode=\"NEVER\",\n",
    ")\n",
    "\n",
    "# The Adder Agent adds 1 to each number it receives.\n",
    "adder_agent = ConversableAgent(\n",
    "    name=\"Adder_Agent\",\n",
    "    system_message=\"You add 1 to each number I give you and return me the new numbers, one number each line.\",\n",
    "    llm_config={\"config_list\": [{\"model\": \"gpt-4\", \"api_key\": os.environ[\"OPENAI_API_KEY\"]}]},\n",
    "    human_input_mode=\"NEVER\",\n",
    ")\n",
    "\n",
    "# The Multiplier Agent multiplies each number it receives by 2.\n",
    "multiplier_agent = ConversableAgent(\n",
    "    name=\"Multiplier_Agent\",\n",
    "    system_message=\"You multiply each number I give you by 2 and return me the new numbers, one number each line.\",\n",
    "    llm_config={\"config_list\": [{\"model\": \"gpt-4\", \"api_key\": os.environ[\"OPENAI_API_KEY\"]}]},\n",
    "    human_input_mode=\"NEVER\",\n",
    ")\n",
    "\n",
    "# The Subtracter Agent subtracts 1 from each number it receives.\n",
    "subtracter_agent = ConversableAgent(\n",
    "    name=\"Subtracter_Agent\",\n",
    "    system_message=\"You subtract 1 from each number I give you and return me the new numbers, one number each line.\",\n",
    "    llm_config={\"config_list\": [{\"model\": \"gpt-4\", \"api_key\": os.environ[\"OPENAI_API_KEY\"]}]},\n",
    "    human_input_mode=\"NEVER\",\n",
    ")\n",
    "\n",
    "# The Divider Agent divides each number it receives by 2.\n",
    "divider_agent = ConversableAgent(\n",
    "    name=\"Divider_Agent\",\n",
    "    system_message=\"You divide each number I give you by 2 and return me the new numbers, one number each line.\",\n",
    "    llm_config={\"config_list\": [{\"model\": \"gpt-4\", \"api_key\": os.environ[\"OPENAI_API_KEY\"]}]},\n",
    "    human_input_mode=\"NEVER\",\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The Number Agent chats with the first operator agent, then the second\n",
    "operator agent, and so on.\n",
    "After each chat, the last message in the conversation (i.e., the result of the arithmetic operation from the operator agent)\n",
    "is used as the summary of the chat.\n",
    "This is specified by the `summary_method` parameter.\n",
    "In the end we will have the result of the arithmetic operations."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[34m\n",
      "********************************************************************************\u001b[0m\n",
      "\u001b[34mStart a new chat with the following message: \n",
      "14\n",
      "\n",
      "With the following carryover: \n",
      "\u001b[0m\n",
      "\u001b[34m\n",
      "********************************************************************************\u001b[0m\n",
      "\u001b[33mNumber_Agent\u001b[0m (to Adder_Agent):\n",
      "\n",
      "14\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mAdder_Agent\u001b[0m (to Number_Agent):\n",
      "\n",
      "15\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mNumber_Agent\u001b[0m (to Adder_Agent):\n",
      "\n",
      "15\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mAdder_Agent\u001b[0m (to Number_Agent):\n",
      "\n",
      "16\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[34m\n",
      "********************************************************************************\u001b[0m\n",
      "\u001b[34mStart a new chat with the following message: \n",
      "These are my numbers\n",
      "\n",
      "With the following carryover: \n",
      "16\u001b[0m\n",
      "\u001b[34m\n",
      "********************************************************************************\u001b[0m\n",
      "\u001b[33mNumber_Agent\u001b[0m (to Multiplier_Agent):\n",
      "\n",
      "These are my numbers\n",
      "Context: \n",
      "16\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mMultiplier_Agent\u001b[0m (to Number_Agent):\n",
      "\n",
      "32\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mNumber_Agent\u001b[0m (to Multiplier_Agent):\n",
      "\n",
      "32\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mMultiplier_Agent\u001b[0m (to Number_Agent):\n",
      "\n",
      "64\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[34m\n",
      "********************************************************************************\u001b[0m\n",
      "\u001b[34mStart a new chat with the following message: \n",
      "These are my numbers\n",
      "\n",
      "With the following carryover: \n",
      "16\n",
      "64\u001b[0m\n",
      "\u001b[34m\n",
      "********************************************************************************\u001b[0m\n",
      "\u001b[33mNumber_Agent\u001b[0m (to Subtracter_Agent):\n",
      "\n",
      "These are my numbers\n",
      "Context: \n",
      "16\n",
      "64\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mSubtracter_Agent\u001b[0m (to Number_Agent):\n",
      "\n",
      "15\n",
      "63\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mNumber_Agent\u001b[0m (to Subtracter_Agent):\n",
      "\n",
      "15\n",
      "63\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mSubtracter_Agent\u001b[0m (to Number_Agent):\n",
      "\n",
      "14\n",
      "62\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[34m\n",
      "********************************************************************************\u001b[0m\n",
      "\u001b[34mStart a new chat with the following message: \n",
      "These are my numbers\n",
      "\n",
      "With the following carryover: \n",
      "16\n",
      "64\n",
      "14\n",
      "62\u001b[0m\n",
      "\u001b[34m\n",
      "********************************************************************************\u001b[0m\n",
      "\u001b[33mNumber_Agent\u001b[0m (to Divider_Agent):\n",
      "\n",
      "These are my numbers\n",
      "Context: \n",
      "16\n",
      "64\n",
      "14\n",
      "62\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mDivider_Agent\u001b[0m (to Number_Agent):\n",
      "\n",
      "8\n",
      "32\n",
      "7\n",
      "31\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mNumber_Agent\u001b[0m (to Divider_Agent):\n",
      "\n",
      "8\n",
      "32\n",
      "7\n",
      "31\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mDivider_Agent\u001b[0m (to Number_Agent):\n",
      "\n",
      "4\n",
      "16\n",
      "3.5\n",
      "15.5\n",
      "\n",
      "--------------------------------------------------------------------------------\n"
     ]
    }
   ],
   "source": [
    "# Start a sequence of two-agent chats.\n",
    "# Each element in the list is a dictionary that specifies the arguments\n",
    "# for the initiate_chat method.\n",
    "chat_results = number_agent.initiate_chats(\n",
    "    [\n",
    "        {\n",
    "            \"recipient\": adder_agent,\n",
    "            \"message\": \"14\",\n",
    "            \"max_turns\": 2,\n",
    "            \"summary_method\": \"last_msg\",\n",
    "        },\n",
    "        {\n",
    "            \"recipient\": multiplier_agent,\n",
    "            \"message\": \"These are my numbers\",\n",
    "            \"max_turns\": 2,\n",
    "            \"summary_method\": \"last_msg\",\n",
    "        },\n",
    "        {\n",
    "            \"recipient\": subtracter_agent,\n",
    "            \"message\": \"These are my numbers\",\n",
    "            \"max_turns\": 2,\n",
    "            \"summary_method\": \"last_msg\",\n",
    "        },\n",
    "        {\n",
    "            \"recipient\": divider_agent,\n",
    "            \"message\": \"These are my numbers\",\n",
    "            \"max_turns\": 2,\n",
    "            \"summary_method\": \"last_msg\",\n",
    "        },\n",
    "    ]\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First thing to note is that the `initiate_chats` method takes a list of\n",
    "dictionaries, each dictionary contains the arguments for the `initiate_chat`\n",
    "method.\n",
    "\n",
    "Second, each chat in the sequence has a maximum round of 2, as specified with\n",
    "the setting `max_turns=2`, \n",
    "which means each arithmetic operation is performed twice.\n",
    "So you can see in the first chat the number 14 becomes 15 and then 16,\n",
    "in the second chat the number 16 becomes 32 and then 64, and so on.\n",
    "\n",
    "Third, the carryover accumulates as the chats go on. In the second chat,\n",
    "the carryover is the summary of the first chat \"16\".\n",
    "In the third chat, the carryover is the summary of the first and second\n",
    "chat, which is the list \"16\" and \"64\", and both numbers are operated upon.\n",
    "In the forth and last chat, the carryover is the summary of all previous\n",
    "chats, which is the list \"16\", \"64\", \"14\" and \"62\", and all of these\n",
    "numbers are operated upon.\n",
    "\n",
    "The final note is that the `initiate_chats` method returns a list of\n",
    "`ChatResult` objects, one for each chat in the sequence."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "First Chat Summary:  16\n",
      "Second Chat Summary:  64\n",
      "Third Chat Summary:  14\n",
      "62\n",
      "Fourth Chat Summary:  4\n",
      "16\n",
      "3.5\n",
      "15.5\n"
     ]
    }
   ],
   "source": [
    "print(\"First Chat Summary: \", chat_results[0].summary)\n",
    "print(\"Second Chat Summary: \", chat_results[1].summary)\n",
    "print(\"Third Chat Summary: \", chat_results[2].summary)\n",
    "print(\"Fourth Chat Summary: \", chat_results[3].summary)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Besides calling `initiate_chats` from the same sender agent, you can also\n",
    "call a high-level function `autogen.agentchat.initiate_chats` to start\n",
    "a sequence of two-agent chats with different sender agents. \n",
    "This function allows you to specify the\n",
    "sender agent for each chat in the sequence."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Group Chat\n",
    "\n",
    "So far we have only seen conversation patterns that involve two agents or \n",
    "a sequence of two-agent chats. AutoGen provides a more general conversation\n",
    "pattern called group chat, which involves more than two agents.\n",
    "The core idea of group chat is that all agents contribute to a single\n",
    "conversation thread and share the same context.\n",
    "This is useful for tasks that require collaboration among multiple agents.\n",
    "\n",
    "The figure below illustrates how group chat works.\n",
    "\n",
    "```{=mdx}\n",
    "![group_chat](./assets/group-chat.png)\n",
    "```\n",
    "\n",
    "A group chat is orchestrated by a special\n",
    "agent type `GroupChatManager`. In the first step of the group chat,\n",
    "the Group Chat Manager selects an agent to speak. Then, the selected agent\n",
    "speaks and the message is sent back to the Group Chat Manager,\n",
    "who **broadcasts** the message to all other agents in the group.\n",
    "This process repeats until the conversation stops.\n",
    "\n",
    "The Group Chat Manager can use several strategies to select the next agent.\n",
    "Currently, the following strategies are supported:\n",
    "\n",
    "1. `round_robin`: The Group Chat Manager selects agents in a round-robin\n",
    "   fashion based on the order of the agents provided.\n",
    "2. `random`: The Group Chat Manager selects agents randomly.\n",
    "3. `manual`: The Group Chat Manager selects agents by asking for human input.\n",
    "4. `auto`: The default strategy, which selects agents using the Group Chat\n",
    "   Manager's LLM."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To illustrate this pattern, let's consider a simple example of a group chat\n",
    "among the same arithmetic operator agents as in the previous example,\n",
    "with the objective of turning a number into a specific target number\n",
    "using a sequence of arithmetic operations powered by the agents.\n",
    "\n",
    "In this example, we use the `auto` strategy to select the next agent.\n",
    "To help the Group Chat Manager select the next agent, we also set the\n",
    "`description` of the agents. Without the `description`, the Group Chat Manager\n",
    "will use the agents' `system_message`, which may be not be the best choice."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "# The `description` attribute is a string that describes the agent.\n",
    "# It can also be set in `ConversableAgent` constructor.\n",
    "adder_agent.description = \"Add 1 to each input number.\"\n",
    "multiplier_agent.description = \"Multiply each input number by 2.\"\n",
    "subtracter_agent.description = \"Subtract 1 from each input number.\"\n",
    "divider_agent.description = \"Divide each input number by 2.\"\n",
    "number_agent.description = \"Return the numbers given.\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We first create a `GroupChat` object and provide the list of agents.\n",
    "If we were to use the `round_robin` strategy, this list would specify the order\n",
    "of the agents to be selected.\n",
    "We also initialize the group chat with an empty message list and a maximum\n",
    "round of 6, which means there will be at most 6 iterations of selecting a speaker,\n",
    "agent speaks and broadcasting message."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "from autogen import GroupChat\n",
    "\n",
    "group_chat = GroupChat(\n",
    "    agents=[adder_agent, multiplier_agent, subtracter_agent, divider_agent, number_agent],\n",
    "    messages=[],\n",
    "    max_round=6,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we create a `GroupChatManager` object and provide the `GroupChat` object as\n",
    "input. We also need to specify the `llm_config` of the Group Chat Manager\n",
    "so it can use the LLM to select the next agent (the `auto` strategy)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "from autogen import GroupChatManager\n",
    "\n",
    "group_chat_manager = GroupChatManager(\n",
    "    groupchat=group_chat,\n",
    "    llm_config={\"config_list\": [{\"model\": \"gpt-4\", \"api_key\": os.environ[\"OPENAI_API_KEY\"]}]},\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, we have the Number Agent from before to start a two-agent chat with\n",
    "the Group Chat Manager, which runs the group chat internally and terminates\n",
    "the two-agent chat when the internal group chat is done.\n",
    "Because the Number Agent is selected to speak by us, it counts as the \n",
    "first round of the group chat."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[33mNumber_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "My number is 3, I want to turn it into 13.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mMultiplier_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "6\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mAdder_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "7\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mMultiplier_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "14\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mSubtracter_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "13\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mNumber_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "13\n",
      "\n",
      "--------------------------------------------------------------------------------\n"
     ]
    }
   ],
   "source": [
    "chat_result = number_agent.initiate_chat(\n",
    "    group_chat_manager,\n",
    "    message=\"My number is 3, I want to turn it into 13.\",\n",
    "    summary_method=\"reflection_with_llm\",\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can see that the Number Agent is selected to speak first, then the\n",
    "Group Chat Manager selects the Multiplier Agent to speak, then the Adder\n",
    "Agent, and so on. The number is operated upon by each agent in the group\n",
    "chat, and the final result is 13.\n",
    "\n",
    "We can take a look at the summary of the group chat, provided by the \n",
    "`ChatResult` object returned by the `initiate_chat` method."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The agents cooperatively manipulated the initial number (3) through multipliying, adding, and subtracting operations to reach the target number (13).\n"
     ]
    }
   ],
   "source": [
    "print(chat_result.summary)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Send Introductions\n",
    "\n",
    "In the previous example, we set the `description` of the agents to help the\n",
    "Group Chat Manager select the next agent. This only helps the Group Chat Manager,\n",
    "however, does not help the participating agents to know about each other.\n",
    "Sometimes it is useful have each agent introduce themselves to other\n",
    "agents in the group chat. This can be done by setting the `send_introductions=True`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "group_chat_with_introductions = GroupChat(\n",
    "    agents=[adder_agent, multiplier_agent, subtracter_agent, divider_agent, number_agent],\n",
    "    messages=[],\n",
    "    max_round=6,\n",
    "    send_introductions=True,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Under the hood, the Group Chat Manager sends a message containing the \n",
    "agents' names and descriptions to all agents in the group chat before the\n",
    "group chat starts."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Group Chat in a Sequential Chat\n",
    "\n",
    "Group chat can also be used as a part of a sequential chat.\n",
    "In this case, the Group Chat Manager is treated as a regular agent\n",
    "in the sequence of two-agent chats."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[34m\n",
      "********************************************************************************\u001b[0m\n",
      "\u001b[34mStart a new chat with the following message: \n",
      "My number is 3, I want to turn it into 13.\n",
      "\n",
      "With the following carryover: \n",
      "\u001b[0m\n",
      "\u001b[34m\n",
      "********************************************************************************\u001b[0m\n",
      "\u001b[33mNumber_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "My number is 3, I want to turn it into 13.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mMultiplier_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "6\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mAdder_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "7\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mMultiplier_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "14\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mSubtracter_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "13\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mNumber_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "Your number is 13.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[34m\n",
      "********************************************************************************\u001b[0m\n",
      "\u001b[34mStart a new chat with the following message: \n",
      "Turn this number to 32.\n",
      "\n",
      "With the following carryover: \n",
      "Your number is 13.\u001b[0m\n",
      "\u001b[34m\n",
      "********************************************************************************\u001b[0m\n",
      "\u001b[33mNumber_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "Turn this number to 32.\n",
      "Context: \n",
      "Your number is 13.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mMultiplier_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "26\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mAdder_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "14\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mMultiplier_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "28\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mAdder_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "15\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mMultiplier_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "30\n",
      "\n",
      "--------------------------------------------------------------------------------\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/ekzhu/autogen/autogen/agentchat/chat.py:46: UserWarning: Repetitive recipients detected: The chat history will be cleared by default if a recipient appears more than once. To retain the chat history, please set 'clear_history=False' in the configuration of the repeating agent.\n",
      "  warnings.warn(\n"
     ]
    }
   ],
   "source": [
    "# Let's use the group chat with introduction messages created above.\n",
    "group_chat_manager_with_intros = GroupChatManager(\n",
    "    groupchat=group_chat_with_introductions,\n",
    "    llm_config={\"config_list\": [{\"model\": \"gpt-4\", \"api_key\": os.environ[\"OPENAI_API_KEY\"]}]},\n",
    ")\n",
    "\n",
    "# Start a sequence of two-agent chats between the number agent and\n",
    "# the group chat manager.\n",
    "chat_result = number_agent.initiate_chats(\n",
    "    [\n",
    "        {\n",
    "            \"recipient\": group_chat_manager_with_intros,\n",
    "            \"message\": \"My number is 3, I want to turn it into 13.\",\n",
    "        },\n",
    "        {\n",
    "            \"recipient\": group_chat_manager_with_intros,\n",
    "            \"message\": \"Turn this number to 32.\",\n",
    "        },\n",
    "    ]\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the above example, the Group Chat Manager runs the group chat two times.\n",
    "In the first time the number 3 becomes 13, and the last message of this group chat\n",
    "is being used as the carryover for the next group chat, which starts from 13.\n",
    "\n",
    "You can also see from the warning message that the Group Chat Manager's\n",
    "history is being cleared after the first group chat, which is the default.\n",
    "To keep the history of the Group Chat Manager, \n",
    "you can set the `clear_history=False` for the first chat."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Constrained Speaker Selection\n",
    "\n",
    "Group chat is a powerful conversation pattern, but it can be hard to control\n",
    "if the number of participating agents is large.\n",
    "AutoGen provides a way to constrain the selection of the next speaker\n",
    "by using the `allowed_or_disallowed_speaker_transitions` argument of the \n",
    "`GroupChat` class.\n",
    "\n",
    "The `allowed_or_disallowed_speaker_transitions` argument is a dictionary\n",
    "that maps a given agent to a list of agents that can (or cannot) \n",
    "be selected to speak next. The `speaker_transitions_type` argument specifies\n",
    "whether the transitions are allowed or disallowed.\n",
    "\n",
    "Here is an example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "allowed_transitions = {\n",
    "    number_agent: [adder_agent, number_agent],\n",
    "    adder_agent: [multiplier_agent, number_agent],\n",
    "    subtracter_agent: [divider_agent, number_agent],\n",
    "    multiplier_agent: [subtracter_agent, number_agent],\n",
    "    divider_agent: [adder_agent, number_agent],\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this example, the allowed transitions are specified for each agent.\n",
    "The Number Agent can be followed by the Adder Agent and the Number Agent, \n",
    "the Adder Agent can be followed by the Multiplier Agent and the Number Agent,\n",
    "and so on.\n",
    "Let's put this into the group chat and see how it works.\n",
    "The `speaker_transitions_type` is set to `allowed` so the transitions are\n",
    "positive constraints."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[33mNumber_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "My number is 3, I want to turn it into 10. Once I get to 10, keep it there.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mAdder_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "4\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mMultiplier_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "8\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mSubtracter_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "7\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mDivider_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "3.5\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mAdder_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "4.5\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mMultiplier_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "9\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mSubtracter_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "8\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mDivider_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "4\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mAdder_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "5\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mMultiplier_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "10\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mNumber_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "10\n",
      "\n",
      "--------------------------------------------------------------------------------\n"
     ]
    }
   ],
   "source": [
    "constrained_graph_chat = GroupChat(\n",
    "    agents=[adder_agent, multiplier_agent, subtracter_agent, divider_agent, number_agent],\n",
    "    allowed_or_disallowed_speaker_transitions=allowed_transitions,\n",
    "    speaker_transitions_type=\"allowed\",\n",
    "    messages=[],\n",
    "    max_round=12,\n",
    "    send_introductions=True,\n",
    ")\n",
    "\n",
    "constrained_group_chat_manager = GroupChatManager(\n",
    "    groupchat=constrained_graph_chat,\n",
    "    llm_config={\"config_list\": [{\"model\": \"gpt-4\", \"api_key\": os.environ[\"OPENAI_API_KEY\"]}]},\n",
    ")\n",
    "\n",
    "chat_result = number_agent.initiate_chat(\n",
    "    constrained_group_chat_manager,\n",
    "    message=\"My number is 3, I want to turn it into 10. Once I get to 10, keep it there.\",\n",
    "    summary_method=\"reflection_with_llm\",\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This time, the agents are selected following the constraints we have specified."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Changing the select speaker role name\n",
    "\n",
    "As part of the Group chat process, when the select_speaker_method is set to 'auto' (the default value),\n",
    "a select speaker message is sent to the LLM to determine the next speaker.\n",
    "\n",
    "Each message in the chat sequence has a `role` attribute that is typically `user`,\n",
    "`assistant`, or `system`. The select speaker message is the last in the chat\n",
    "sequence when used and, by default, has a role of `system`.\n",
    "\n",
    "When using some models, such as Mistral through Mistral.AI's API, the role on\n",
    "the last message in the chat sequence has to be `user`.\n",
    "\n",
    "To change the default behaviour, Autogen provides a way to set the value of the\n",
    "select speaker message's role to any string value by setting the\n",
    "`role_for_select_speaker_messages` parameter in the GroupChat's constructor. The\n",
    "default value is `system` and by setting it to `user` you can accommodate the\n",
    "last message role requirement of Mistral.AI's API."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Nested Chats\n",
    "\n",
    "The previous conversations patterns (two-agent chat, sequential chat, and group chat)\n",
    "are useful for building complex workflows, however, they do not expose a\n",
    "single conversational interface, which is often needed for scenarios like\n",
    "question-answering bots and personal assistants.\n",
    "In some other cases, it is also useful to package a workflow into a single\n",
    "agent for reuse in a larger workflow. \n",
    "AutoGen provides a way to achieve this by using nested chats.\n",
    "\n",
    "Nested chats is powered by the nested chats handler, which is a pluggable\n",
    "component of `ConversableAgent`.\n",
    "The figure below illustrates how the nested chats handler triggers\n",
    "a sequence of nested chats when a message is received.\n",
    "\n",
    "```{=mdx}\n",
    "![nested_chat](./assets/nested-chats.png)\n",
    "```\n",
    "\n",
    "When a message comes in and passes the [human-in-the-loop component](./human-in-the-loop), \n",
    "the nested chats handler checks if the message should trigger a nested chat\n",
    "based on conditions specified by the user.\n",
    "If the conditions are met, the nested chats handler starts a sequence of\n",
    "nested chats specified using the sequential chats pattern.\n",
    "In each of the nested chats, the sender agent is always the same agent\n",
    "that triggered the nested chats.\n",
    "In the end, the nested chat handler uses the results of the nested chats\n",
    "to produce a response to the original message.\n",
    "By default, the nested chat handler uses the summary of the last chat\n",
    "as the response."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here is an example of using nested chats to build an arithmetic agent that\n",
    "packages arithmetic operations, code-based validation, and poetry into a single\n",
    "agent. This arithmetic agent takes a number transformation request like \n",
    "\"turn number 3 into 13\" and returns a poem that describes a transformation attempt.\n",
    "\n",
    "First we define the agents. We reuse the `group_chat_manager_with_intros`\n",
    "from previous example to orchestrate the arithmetic operations."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "import tempfile\n",
    "\n",
    "temp_dir = tempfile.gettempdir()\n",
    "\n",
    "arithmetic_agent = ConversableAgent(\n",
    "    name=\"Arithmetic_Agent\",\n",
    "    llm_config=False,\n",
    "    human_input_mode=\"ALWAYS\",\n",
    "    # This agent will always require human input to make sure the code is\n",
    "    # safe to execute.\n",
    "    code_execution_config={\"use_docker\": False, \"work_dir\": temp_dir},\n",
    ")\n",
    "\n",
    "code_writer_agent = ConversableAgent(\n",
    "    name=\"Code_Writer_Agent\",\n",
    "    system_message=\"You are a code writer. You write Python script in Markdown code blocks.\",\n",
    "    llm_config={\"config_list\": [{\"model\": \"gpt-4\", \"api_key\": os.environ[\"OPENAI_API_KEY\"]}]},\n",
    "    human_input_mode=\"NEVER\",\n",
    ")\n",
    "\n",
    "poetry_agent = ConversableAgent(\n",
    "    name=\"Poetry_Agent\",\n",
    "    system_message=\"You are an AI poet.\",\n",
    "    llm_config={\"config_list\": [{\"model\": \"gpt-4\", \"api_key\": os.environ[\"OPENAI_API_KEY\"]}]},\n",
    "    human_input_mode=\"NEVER\",\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we define the nested chats using the sequential chat pattern.\n",
    "All the senders are always `artihmetic_agent`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [],
   "source": [
    "nested_chats = [\n",
    "    {\n",
    "        \"recipient\": group_chat_manager_with_intros,\n",
    "        \"summary_method\": \"reflection_with_llm\",\n",
    "        \"summary_prompt\": \"Summarize the sequence of operations used to turn \" \"the source number into target number.\",\n",
    "    },\n",
    "    {\n",
    "        \"recipient\": code_writer_agent,\n",
    "        \"message\": \"Write a Python script to verify the arithmetic operations is correct.\",\n",
    "        \"summary_method\": \"reflection_with_llm\",\n",
    "    },\n",
    "    {\n",
    "        \"recipient\": poetry_agent,\n",
    "        \"message\": \"Write a poem about it.\",\n",
    "        \"max_turns\": 1,\n",
    "        \"summary_method\": \"last_msg\",\n",
    "    },\n",
    "]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we register the nested chats handler to the `arithmetic_agent` and\n",
    "set the conditions for triggering the nested chats."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "arithmetic_agent.register_nested_chats(\n",
    "    nested_chats,\n",
    "    # The trigger function is used to determine if the agent should start the nested chat\n",
    "    # given the sender agent.\n",
    "    # In this case, the arithmetic agent will not start the nested chats if the sender is\n",
    "    # from the nested chats' recipient to avoid recursive calls.\n",
    "    trigger=lambda sender: sender not in [group_chat_manager_with_intros, code_writer_agent, poetry_agent],\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, we call `generate_reply` to get a response from the `arithmetic_agent`\n",
    "-- this will trigger a sequence of nested chats and return the summary of the\n",
    "last nested chat as the response."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[31m\n",
      ">>>>>>>> NO HUMAN INPUT RECEIVED.\u001b[0m\n",
      "\u001b[31m\n",
      ">>>>>>>> USING AUTO REPLY...\u001b[0m\n",
      "\u001b[34m\n",
      "********************************************************************************\u001b[0m\n",
      "\u001b[34mStart a new chat with the following message: \n",
      "I have a number 3 and I want to turn it into 7.\n",
      "\n",
      "With the following carryover: \n",
      "\u001b[0m\n",
      "\u001b[34m\n",
      "********************************************************************************\u001b[0m\n",
      "\u001b[33mArithmetic_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "I have a number 3 and I want to turn it into 7.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mAdder_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "To give you the result, I'll add 1 to the number you gave me. So your new number is 4.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mMultiplier_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "8\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mSubtracter_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "7\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mNumber_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "7\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mNumber_Agent\u001b[0m (to chat_manager):\n",
      "\n",
      "7\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[34m\n",
      "********************************************************************************\u001b[0m\n",
      "\u001b[34mStart a new chat with the following message: \n",
      "Write a Python script to verify the arithmetic operations is correct.\n",
      "\n",
      "With the following carryover: \n",
      "First, 1 was added to the initial number 3 to make it 4. Then it was multiplied by 2 which resulted in 8. Finally, 1 was subtracted from 8 to reach the target number 7.\u001b[0m\n",
      "\u001b[34m\n",
      "********************************************************************************\u001b[0m\n",
      "\u001b[33mArithmetic_Agent\u001b[0m (to Code_Writer_Agent):\n",
      "\n",
      "Write a Python script to verify the arithmetic operations is correct.\n",
      "Context: \n",
      "First, 1 was added to the initial number 3 to make it 4. Then it was multiplied by 2 which resulted in 8. Finally, 1 was subtracted from 8 to reach the target number 7.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mCode_Writer_Agent\u001b[0m (to Arithmetic_Agent):\n",
      "\n",
      "Here is a Python script to verify the aforementioned arithmetic operations:\n",
      "\n",
      "```python\n",
      "# defining the initial value\n",
      "initial_number = 3\n",
      "\n",
      "# Adding 1 to initial number\n",
      "initial_number += 1\n",
      "assert initial_number == 4, \"The first operation failed!\"\n",
      "\n",
      "# Multiplying the result by 2\n",
      "initial_number *= 2\n",
      "assert initial_number == 8, \"The second operation failed!\"\n",
      "\n",
      "# Subtracting 1 from the result\n",
      "initial_number -= 1\n",
      "assert initial_number == 7, \"The final operation failed!\"\n",
      "\n",
      "print(\"All operations were carried out successfully!\")\n",
      "```\n",
      "In the script, the entire process is broken down into steps. The `assert` function is used to verify the result at every step. If any of the operations doesn't yield the expected result, an `AssertionError` exception will be raised. If all operations pass, the message \"All operations were carried out successfully!\" will be printed.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[31m\n",
      ">>>>>>>> NO HUMAN INPUT RECEIVED.\u001b[0m\n",
      "\u001b[31m\n",
      ">>>>>>>> USING AUTO REPLY...\u001b[0m\n",
      "\u001b[31m\n",
      ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n",
      "\u001b[33mArithmetic_Agent\u001b[0m (to Code_Writer_Agent):\n",
      "\n",
      "exitcode: 0 (execution succeeded)\n",
      "Code output: \n",
      "All operations were carried out successfully!\n",
      "\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mCode_Writer_Agent\u001b[0m (to Arithmetic_Agent):\n",
      "\n",
      "Certainly, that means the python script was successful and every arithmetic operation performed correctly given the initial input and the steps performed.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[34m\n",
      "********************************************************************************\u001b[0m\n",
      "\u001b[34mStart a new chat with the following message: \n",
      "Write a poem about it.\n",
      "\n",
      "With the following carryover: \n",
      "First, 1 was added to the initial number 3 to make it 4. Then it was multiplied by 2 which resulted in 8. Finally, 1 was subtracted from 8 to reach the target number 7.\n",
      "The Python script successfully performed and verified the arithmetic operations on the initial number provided. The steps included adding 1 to the initial number, multiplying the result by 2, and finally subtracting 1. The assert function was used to check the result at each step, and confirmed that all operations were carried out correctly.\u001b[0m\n",
      "\u001b[34m\n",
      "********************************************************************************\u001b[0m\n",
      "\u001b[33mArithmetic_Agent\u001b[0m (to Poetry_Agent):\n",
      "\n",
      "Write a poem about it.\n",
      "Context: \n",
      "First, 1 was added to the initial number 3 to make it 4. Then it was multiplied by 2 which resulted in 8. Finally, 1 was subtracted from 8 to reach the target number 7.\n",
      "The Python script successfully performed and verified the arithmetic operations on the initial number provided. The steps included adding 1 to the initial number, multiplying the result by 2, and finally subtracting 1. The assert function was used to check the result at each step, and confirmed that all operations were carried out correctly.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33mPoetry_Agent\u001b[0m (to Arithmetic_Agent):\n",
      "\n",
      "From numbers, logic, pure mathematical creation,\n",
      "Ponder this tale of numeric manipulation.\n",
      "In the universe of Python where operations exist,\n",
      "A story of integers and functions persist.\n",
      "\n",
      "Three was the number from where we began,\n",
      "Oblivious to the journey and its grandiosely plan.\n",
      "Added with 1, the sum it adorned,\n",
      "A sweet quadruple in the dawn was formed.\n",
      "\n",
      "The saga continued with a twist of the tale,\n",
      "The four was multiplied, while the winds wail.\n",
      "The duo of four unfolded its wings,\n",
      "An octet presence in our midst it brings.\n",
      "\n",
      "Then enters subtraction, sly and clever,\n",
      "Removing one to alter the endeavor.\n",
      "From eight, subtracted one in delight,\n",
      "To finally bask in the glow of seven's light.\n",
      "\n",
      "Each operation, together they conspired,\n",
      "In this tale of integers, creatively inspired.\n",
      "Through life's equation, the script ran so free,\n",
      "Amidst the language of Python, a symphony, you see.\n",
      "\n",
      "Tested with assert, cross-checked the chain,\n",
      "Confirming accuracy in program's domain.\n",
      "Each move calculated, each step so right,\n",
      "In the maze of coding, found was the light. \n",
      "\n",
      "Such is the tale, of numbers and operations, \n",
      "A dance among digits, logical iterations,\n",
      "Just another day, in this AI poet's life,\n",
      "Cutting through ambiguity, like a razor-sharp knife.\n",
      "\n",
      "--------------------------------------------------------------------------------\n"
     ]
    }
   ],
   "source": [
    "# Instead of using `initiate_chat` method to start another conversation,\n",
    "# we can use the `generate_reply` method to get single reply to a message directly.\n",
    "reply = arithmetic_agent.generate_reply(\n",
    "    messages=[{\"role\": \"user\", \"content\": \"I have a number 3 and I want to turn it into 7.\"}]\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A poem is returned as the response, which describes the transformation attempt\n",
    "from 3 to 7."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The implementation of the nested chats handler makes use of the\n",
    "[`register_reply`](/docs/reference/agentchat/conversable_agent/#register_reply)\n",
    "method, which allows you to make extensive customization to\n",
    " `ConversableAgent`. The GroupChatManager uses the same mechanism to implement the group chat.\n",
    "\n",
    "Nested chat is a powerful conversation pattern that allows you to package\n",
    "complex workflows into a single agent.\n",
    "You can hide [tool usages](/docs/tutorial/tool-use) within a single agent by having the tool-caller agent \n",
    "starts a nested chat with a tool-executor agent and then use the result\n",
    "of the nested chat to generate a response.\n",
    "See the [nested chats for tool use notebook](/docs/notebooks/agentchat_nested_chats_chess) for an example."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Summary\n",
    "\n",
    "In this chapter, we covered two-agent chat, sequential chat, group chat,\n",
    "and nested chat patterns. You can compose these patterns like LEGO blocks to \n",
    "create complex workflows. You can also use [`register_reply`](/docs/reference/agentchat/conversable_agent/#register_reply) to create new patterns.\n",
    "\n",
    "This is the last chapter on basic AutoGen concepts. \n",
    "In the next chatper, we will give you some tips on what to do next."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "autogen",
   "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.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
