{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# SocietyOfMindAgent\n",
    "\n",
    "This notebook demonstrates the SocietyOfMindAgent, which runs a group chat as an internal monologue, but appears to the external world as a single agent. This confers three distinct advantages:\n",
    "\n",
    "1. It provides a clean way of producing a hierarchy of agents, hiding complexity as inner monologues.\n",
    "2. It provides a consistent way of extracting an answer from a lengthy group chat (normally, it is not clear which message is the final response, and the response itself may not always be formatted in a way that makes sense when extracted as a standalone message).\n",
    "3. It provides a way of recovering when agents exceed their context window constraints (the inner monologue is protected by try-catch blocks)\n",
    "\n",
    "````{=mdx}\n",
    ":::info Requirements\n",
    "Install `autogen-agentchat`:\n",
    "```bash\n",
    "pip install autogen-agentchat~=0.2\n",
    "```\n",
    "\n",
    "For more information, please refer to the [installation guide](/docs/installation/).\n",
    ":::\n",
    "````"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import autogen  # noqa: E402\n",
    "\n",
    "llm_config = {\n",
    "    \"timeout\": 600,\n",
    "    \"cache_seed\": 44,  # change the seed for different trials\n",
    "    \"config_list\": autogen.config_list_from_json(\n",
    "        \"OAI_CONFIG_LIST\",\n",
    "        filter_dict={\"model\": [\"gpt-4\", \"gpt-4-0613\", \"gpt-4-32k\", \"gpt-4-32k-0613\", \"gpt-4-1106-preview\"]},\n",
    "    ),\n",
    "    \"temperature\": 0,\n",
    "}"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "````{=mdx}\n",
    ":::tip\n",
    "Learn more about configuring LLMs for agents [here](/docs/topics/llm_configuration).\n",
    ":::\n",
    "````\n",
    "\n",
    "### Example Group Chat with Two Agents\n",
    "\n",
    "In this example, we will use an AssistantAgent and a UserProxy agent (configured for code execution) to work together to solve a problem. Executing code requires *at least* two conversation turns (one to write the code, and one to execute the code). If the code fails, or needs further refinement, then additional turns may also be needed. We will then wrap these agents in a SocietyOfMindAgent, hiding the internal discussion from other agents (though will still appear in the console), and ensuring that the response is suitable as a standalone message."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Construct the Inner-Monologue Agents\n",
    "We begin by constructing the inner-monologue agents. These are the agents that do that real work."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "assistant = autogen.AssistantAgent(\n",
    "    \"inner-assistant\",\n",
    "    llm_config=llm_config,\n",
    "    is_termination_msg=lambda x: x.get(\"content\", \"\").find(\"TERMINATE\") >= 0,\n",
    ")\n",
    "\n",
    "code_interpreter = autogen.UserProxyAgent(\n",
    "    \"inner-code-interpreter\",\n",
    "    human_input_mode=\"NEVER\",\n",
    "    code_execution_config={\n",
    "        \"work_dir\": \"coding\",\n",
    "        \"use_docker\": False,\n",
    "    },\n",
    "    default_auto_reply=\"\",\n",
    "    is_termination_msg=lambda x: x.get(\"content\", \"\").find(\"TERMINATE\") >= 0,\n",
    ")\n",
    "\n",
    "groupchat = autogen.GroupChat(\n",
    "    agents=[assistant, code_interpreter],\n",
    "    messages=[],\n",
    "    speaker_selection_method=\"round_robin\",  # With two agents, this is equivalent to a 1:1 conversation.\n",
    "    allow_repeat_speaker=False,\n",
    "    max_round=8,\n",
    ")\n",
    "\n",
    "manager = autogen.GroupChatManager(\n",
    "    groupchat=groupchat,\n",
    "    is_termination_msg=lambda x: x.get(\"content\", \"\").find(\"TERMINATE\") >= 0,\n",
    "    llm_config=llm_config,\n",
    ")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Construct and Run the SocietyOfMind Agent\n",
    "We now wrap the inner group-chat with the SocietyOfMind Agent, and create a UserProxy to talk to it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[33muser_proxy\u001b[0m (to society_of_mind):\n",
      "\n",
      "On which days in 2024 was Microsoft Stock higher than $370?\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[31m\n",
      ">>>>>>>> USING AUTO REPLY...\u001b[0m\n",
      "\u001b[33msociety_of_mind\u001b[0m (to chat_manager):\n",
      "\n",
      "On which days in 2024 was Microsoft Stock higher than $370?\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33minner-assistant\u001b[0m (to chat_manager):\n",
      "\n",
      "To find out on which days in 2024 Microsoft stock (MSFT) was higher than $370, we would typically need to access historical stock price data. This data can be obtained from financial data providers or APIs that offer stock market data.\n",
      "\n",
      "One common way to access such data is by using the `yfinance` library in Python, which allows us to download historical stock prices from Yahoo Finance. However, since I cannot directly access the internet or external APIs, I will provide you with a Python script that you can run on your machine to fetch the data and determine on which days MSFT was higher than $370 in 2024.\n",
      "\n",
      "Please install the `yfinance` library if you haven't already by running `pip install yfinance` in your terminal, and then run the following Python script:\n",
      "\n",
      "```python\n",
      "# filename: msft_stock_analysis.py\n",
      "import yfinance as yf\n",
      "from datetime import datetime\n",
      "\n",
      "# Define the ticker symbol and the date range\n",
      "ticker_symbol = \"MSFT\"\n",
      "start_date = \"2024-01-01\"\n",
      "end_date = \"2024-12-31\"\n",
      "\n",
      "# Download the historical stock prices\n",
      "msft_data = yf.download(ticker_symbol, start=start_date, end=end_date)\n",
      "\n",
      "# Filter the days where the stock price was higher than $370\n",
      "days_higher_than_370 = msft_data[msft_data['Close'] > 370]\n",
      "\n",
      "# Print the dates\n",
      "print(\"Dates in 2024 when MSFT stock was higher than $370:\")\n",
      "for date in days_higher_than_370.index:\n",
      "    print(date.strftime('%Y-%m-%d'))\n",
      "```\n",
      "\n",
      "This script will download the historical data for Microsoft stock for the year 2024 and print out the dates when the closing price was higher than $370. Please run this script and provide me with the output.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[31m\n",
      ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n",
      "\u001b[33minner-code-interpreter\u001b[0m (to chat_manager):\n",
      "\n",
      "exitcode: 1 (execution failed)\n",
      "Code output: \n",
      "Traceback (most recent call last):\n",
      "  File \"msft_stock_analysis.py\", line 2, in <module>\n",
      "    import yfinance as yf\n",
      "ModuleNotFoundError: No module named 'yfinance'\n",
      "\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33minner-assistant\u001b[0m (to chat_manager):\n",
      "\n",
      "The error indicates that the `yfinance` module is not installed on your system. To resolve this, you need to install the `yfinance` library. Please run the following command in your terminal to install it:\n",
      "\n",
      "```sh\n",
      "pip install yfinance\n",
      "```\n",
      "\n",
      "After you have installed `yfinance`, please try running the provided Python script again. If you encounter any further issues, please let me know.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[31m\n",
      ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is sh)...\u001b[0m\n",
      "\u001b[33minner-code-interpreter\u001b[0m (to chat_manager):\n",
      "\n",
      "exitcode: 0 (execution succeeded)\n",
      "Code output: \n",
      "Collecting yfinance\n",
      "  Using cached yfinance-0.2.36-py2.py3-none-any.whl (72 kB)\n",
      "Requirement already satisfied: lxml>=4.9.1 in /home/afourney/repos/autogen/notebook/.venv/lib/python3.10/site-packages (from yfinance) (5.1.0)\n",
      "Requirement already satisfied: appdirs>=1.4.4 in /home/afourney/repos/autogen/notebook/.venv/lib/python3.10/site-packages (from yfinance) (1.4.4)\n",
      "Requirement already satisfied: pytz>=2022.5 in /home/afourney/repos/autogen/notebook/.venv/lib/python3.10/site-packages (from yfinance) (2023.3.post1)\n",
      "Requirement already satisfied: pandas>=1.3.0 in /home/afourney/repos/autogen/notebook/.venv/lib/python3.10/site-packages (from yfinance) (2.2.0)\n",
      "Requirement already satisfied: peewee>=3.16.2 in /home/afourney/repos/autogen/notebook/.venv/lib/python3.10/site-packages (from yfinance) (3.17.0)\n",
      "Requirement already satisfied: requests>=2.31 in /home/afourney/repos/autogen/notebook/.venv/lib/python3.10/site-packages (from yfinance) (2.31.0)\n",
      "Requirement already satisfied: beautifulsoup4>=4.11.1 in /home/afourney/repos/autogen/notebook/.venv/lib/python3.10/site-packages (from yfinance) (4.12.3)\n",
      "Requirement already satisfied: numpy>=1.16.5 in /home/afourney/repos/autogen/notebook/.venv/lib/python3.10/site-packages (from yfinance) (1.26.3)\n",
      "Requirement already satisfied: html5lib>=1.1 in /home/afourney/repos/autogen/notebook/.venv/lib/python3.10/site-packages (from yfinance) (1.1)\n",
      "Requirement already satisfied: frozendict>=2.3.4 in /home/afourney/repos/autogen/notebook/.venv/lib/python3.10/site-packages (from yfinance) (2.4.0)\n",
      "Requirement already satisfied: multitasking>=0.0.7 in /home/afourney/repos/autogen/notebook/.venv/lib/python3.10/site-packages (from yfinance) (0.0.11)\n",
      "Requirement already satisfied: soupsieve>1.2 in /home/afourney/repos/autogen/notebook/.venv/lib/python3.10/site-packages (from beautifulsoup4>=4.11.1->yfinance) (2.5)\n",
      "Requirement already satisfied: six>=1.9 in /home/afourney/repos/autogen/notebook/.venv/lib/python3.10/site-packages (from html5lib>=1.1->yfinance) (1.16.0)\n",
      "Requirement already satisfied: webencodings in /home/afourney/repos/autogen/notebook/.venv/lib/python3.10/site-packages (from html5lib>=1.1->yfinance) (0.5.1)\n",
      "Requirement already satisfied: python-dateutil>=2.8.2 in /home/afourney/repos/autogen/notebook/.venv/lib/python3.10/site-packages (from pandas>=1.3.0->yfinance) (2.8.2)\n",
      "Requirement already satisfied: tzdata>=2022.7 in /home/afourney/repos/autogen/notebook/.venv/lib/python3.10/site-packages (from pandas>=1.3.0->yfinance) (2023.4)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /home/afourney/repos/autogen/notebook/.venv/lib/python3.10/site-packages (from requests>=2.31->yfinance) (2023.11.17)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in /home/afourney/repos/autogen/notebook/.venv/lib/python3.10/site-packages (from requests>=2.31->yfinance) (3.3.2)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /home/afourney/repos/autogen/notebook/.venv/lib/python3.10/site-packages (from requests>=2.31->yfinance) (3.6)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in /home/afourney/repos/autogen/notebook/.venv/lib/python3.10/site-packages (from requests>=2.31->yfinance) (2.1.0)\n",
      "Installing collected packages: yfinance\n",
      "Successfully installed yfinance-0.2.36\n",
      "\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33minner-assistant\u001b[0m (to chat_manager):\n",
      "\n",
      "It seems that the `yfinance` library has been successfully installed. Now that the library is available, please run the previously provided Python script again to fetch the historical stock prices for Microsoft and determine on which days the stock was higher than $370 in 2024.\n",
      "\n",
      "Here is the script again for your convenience:\n",
      "\n",
      "```python\n",
      "# filename: msft_stock_analysis.py\n",
      "import yfinance as yf\n",
      "from datetime import datetime\n",
      "\n",
      "# Define the ticker symbol and the date range\n",
      "ticker_symbol = \"MSFT\"\n",
      "start_date = \"2024-01-01\"\n",
      "end_date = \"2024-12-31\"\n",
      "\n",
      "# Download the historical stock prices\n",
      "msft_data = yf.download(ticker_symbol, start=start_date, end=end_date)\n",
      "\n",
      "# Filter the days where the stock price was higher than $370\n",
      "days_higher_than_370 = msft_data[msft_data['Close'] > 370]\n",
      "\n",
      "# Print the dates\n",
      "print(\"Dates in 2024 when MSFT stock was higher than $370:\")\n",
      "for date in days_higher_than_370.index:\n",
      "    print(date.strftime('%Y-%m-%d'))\n",
      "```\n",
      "\n",
      "Please execute this script and provide me with the output.\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[31m\n",
      ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n",
      "\u001b[33minner-code-interpreter\u001b[0m (to chat_manager):\n",
      "\n",
      "exitcode: 0 (execution succeeded)\n",
      "Code output: \n",
      "Dates in 2024 when MSFT stock was higher than $370:\n",
      "2024-01-02\n",
      "2024-01-03\n",
      "2024-01-08\n",
      "2024-01-09\n",
      "2024-01-10\n",
      "2024-01-11\n",
      "2024-01-12\n",
      "2024-01-16\n",
      "2024-01-17\n",
      "2024-01-18\n",
      "2024-01-19\n",
      "\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33minner-assistant\u001b[0m (to chat_manager):\n",
      "\n",
      "The output indicates that Microsoft stock (MSFT) was higher than $370 on the following days in 2024:\n",
      "\n",
      "- January 2, 2024\n",
      "- January 3, 2024\n",
      "- January 8, 2024\n",
      "- January 9, 2024\n",
      "- January 10, 2024\n",
      "- January 11, 2024\n",
      "- January 12, 2024\n",
      "- January 16, 2024\n",
      "- January 17, 2024\n",
      "- January 18, 2024\n",
      "- January 19, 2024\n",
      "\n",
      "Please note that this list includes only the dates provided in the output and may not be exhaustive for the entire year of 2024. The script would have listed more dates if the stock price was higher than $370 on additional days beyond those listed.\n",
      "\n",
      "TERMINATE\n",
      "\n",
      "--------------------------------------------------------------------------------\n",
      "\u001b[33msociety_of_mind\u001b[0m (to user_proxy):\n",
      "\n",
      "Microsoft stock (MSFT) was higher than $370 on the following days in 2024:\n",
      "\n",
      "- January 2, 2024\n",
      "- January 3, 2024\n",
      "- January 8, 2024\n",
      "- January 9, 2024\n",
      "- January 10, 2024\n",
      "- January 11, 2024\n",
      "- January 12, 2024\n",
      "- January 16, 2024\n",
      "- January 17, 2024\n",
      "- January 18, 2024\n",
      "- January 19, 2024\n",
      "\n",
      "--------------------------------------------------------------------------------\n"
     ]
    }
   ],
   "source": [
    "from autogen.agentchat.contrib.society_of_mind_agent import SocietyOfMindAgent  # noqa: E402\n",
    "\n",
    "task = \"On which days in 2024 was Microsoft Stock higher than $370?\"\n",
    "\n",
    "society_of_mind_agent = SocietyOfMindAgent(\n",
    "    \"society_of_mind\",\n",
    "    chat_manager=manager,\n",
    "    llm_config=llm_config,\n",
    ")\n",
    "\n",
    "user_proxy = autogen.UserProxyAgent(\n",
    "    \"user_proxy\",\n",
    "    human_input_mode=\"NEVER\",\n",
    "    code_execution_config=False,\n",
    "    default_auto_reply=\"\",\n",
    "    is_termination_msg=lambda x: True,\n",
    ")\n",
    "\n",
    "user_proxy.initiate_chat(society_of_mind_agent, message=task)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Remarks\n",
    "\n",
    "There are a few things to notice about this output:\n",
    "- First, the user_proxy sent only one message to the society_of_mind agent, and received only one message in response. As far as it is concerned, the society_of_mind agent is the only agent in the chat.\n",
    "- Second, the final response is formatted in a way that is standalone. Unlike the prior response, it makes no reference of a previous script or execution, and it lacks the TERMINATE keyword that ended the inner monologue."
   ]
  }
 ],
 "metadata": {
  "front_matter": {
   "description": "Explore the demonstration of the SocietyOfMindAgent in the AutoGen library, which runs a group chat as an internal monologue, but appears to the external world as a single agent, offering a structured way to manage complex interactions among multiple agents and handle issues such as extracting responses from complex dialogues and dealing with context window constraints.",
   "tags": [
    "orchestration",
    "nested chat"
   ]
  },
  "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.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
