diff --git a/docs/00-introduction.ipynb b/docs/00-introduction.ipynb
index 4d672f379a44b236ad60a04eaf439c7a0c29ec94..0665070391a00545a4230aead9f22bd9b22717b3 100644
--- a/docs/00-introduction.ipynb
+++ b/docs/00-introduction.ipynb
@@ -44,13 +44,6 @@
     "!pip install -qU semantic-router==0.0.15"
    ]
   },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "_**⚠️ If using Google Colab, install the prerequisites and then restart the notebook before continuing**_"
-   ]
-  },
   {
    "cell_type": "markdown",
    "metadata": {},
diff --git a/docs/01-save-load-from-file.ipynb b/docs/01-save-load-from-file.ipynb
index 43937d2b7d74f1161073d866128df7b43ce87dca..6c5945cb9020a5d2296b86a1c282553abfb15736 100644
--- a/docs/01-save-load-from-file.ipynb
+++ b/docs/01-save-load-from-file.ipynb
@@ -39,13 +39,6 @@
     "!pip install -qU semantic-router==0.0.15"
    ]
   },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "_**⚠️ If using Google Colab, install the prerequisites and then restart the notebook before continuing**_"
-   ]
-  },
   {
    "cell_type": "markdown",
    "metadata": {},
diff --git a/docs/02-dynamic-routes.ipynb b/docs/02-dynamic-routes.ipynb
index 70c5eced9ece37a822ac0af0174f03f9ec07768a..88b7794aadac761ec74dc872d2203203208791e7 100644
--- a/docs/02-dynamic-routes.ipynb
+++ b/docs/02-dynamic-routes.ipynb
@@ -1,376 +1,453 @@
 {
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/aurelio-labs/semantic-router/blob/main/docs/02-dynamic-routes.ipynb) [![Open nbviewer](https://raw.githubusercontent.com/pinecone-io/examples/master/assets/nbviewer-shield.svg)](https://nbviewer.org/github/aurelio-labs/semantic-router/blob/main/docs/02-dynamic-routes.ipynb)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "# Dynamic Routes"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "In semantic-router there are two types of routes that can be chosen. Both routes belong to the `Route` object, the only difference between them is that _static_ routes return a `Route.name` when chosen, whereas _dynamic_ routes use an LLM call to produce parameter input values.\n",
-    "\n",
-    "For example, a _static_ route will tell us if a query is talking about mathematics by returning the route name (which could be `\"math\"` for example). A _dynamic_ route can generate additional values, so it may decide a query is talking about maths, but it can also generate Python code that we can later execute to answer the user's query, this output may look like `\"math\", \"import math; output = math.sqrt(64)`."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Installing the Library"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "!pip install -qU semantic-router==0.0.15"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "_**⚠️ If using Google Colab, install the prerequisites and then restart the notebook before continuing**_"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Initializing Routes and RouteLayer"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Dynamic routes are treated in the same way as static routes, let's begin by initializing a `RouteLayer` consisting of static routes."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 1,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "from semantic_router import Route\n",
-    "\n",
-    "politics = Route(\n",
-    "    name=\"politics\",\n",
-    "    utterances=[\n",
-    "        \"isn't politics the best thing ever\",\n",
-    "        \"why don't you tell me about your political opinions\",\n",
-    "        \"don't you just love the president\" \"don't you just hate the president\",\n",
-    "        \"they're going to destroy this country!\",\n",
-    "        \"they will save the country!\",\n",
-    "    ],\n",
-    ")\n",
-    "chitchat = Route(\n",
-    "    name=\"chitchat\",\n",
-    "    utterances=[\n",
-    "        \"how's the weather today?\",\n",
-    "        \"how are things going?\",\n",
-    "        \"lovely weather today\",\n",
-    "        \"the weather is horrendous\",\n",
-    "        \"let's go to the chippy\",\n",
-    "    ],\n",
-    ")\n",
-    "\n",
-    "routes = [politics, chitchat]"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "We initialize our `RouteLayer` with our `encoder` and `routes`. We can use popular encoder APIs like `CohereEncoder` and `OpenAIEncoder`, or local alternatives like `FastEmbedEncoder`."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 2,
-   "metadata": {},
-   "outputs": [
+  "cells": [
     {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "\u001b[32m2024-01-07 18:11:05 INFO semantic_router.utils.logger Initializing RouteLayer\u001b[0m\n"
-     ]
-    }
-   ],
-   "source": [
-    "import os\n",
-    "from getpass import getpass\n",
-    "from semantic_router import RouteLayer\n",
-    "from semantic_router.encoders import CohereEncoder, OpenAIEncoder\n",
-    "\n",
-    "# dashboard.cohere.ai\n",
-    "# os.environ[\"COHERE_API_KEY\"] = os.getenv(\"COHERE_API_KEY\") or getpass(\n",
-    "#     \"Enter Cohere API Key: \"\n",
-    "# )\n",
-    "# platform.openai.com\n",
-    "os.environ[\"OPENAI_API_KEY\"] = os.getenv(\"OPENAI_API_KEY\") or getpass(\n",
-    "    \"Enter OpenAI API Key: \"\n",
-    ")\n",
-    "\n",
-    "# encoder = CohereEncoder()\n",
-    "encoder = OpenAIEncoder()\n",
-    "\n",
-    "rl = RouteLayer(encoder=encoder, routes=routes)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "We run the solely static routes layer:"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 3,
-   "metadata": {},
-   "outputs": [
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "UxqB7_Ieur0s"
+      },
+      "source": [
+        "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/aurelio-labs/semantic-router/blob/main/docs/02-dynamic-routes.ipynb) [![Open nbviewer](https://raw.githubusercontent.com/pinecone-io/examples/master/assets/nbviewer-shield.svg)](https://nbviewer.org/github/aurelio-labs/semantic-router/blob/main/docs/02-dynamic-routes.ipynb)"
+      ]
+    },
     {
-     "data": {
-      "text/plain": [
-       "RouteChoice(name='chitchat', function_call=None)"
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "EduhQaNAur0u"
+      },
+      "source": [
+        "# Dynamic Routes"
       ]
-     },
-     "execution_count": 3,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "rl(\"how's the weather today?\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Creating a Dynamic Route"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "As with static routes, we must create a dynamic route before adding it to our route layer. To make a route dynamic, we need to provide a `function_schema`. The function schema provides instructions on what a function is, so that an LLM can decide how to use it correctly."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 4,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "from datetime import datetime\n",
-    "from zoneinfo import ZoneInfo\n",
-    "\n",
-    "\n",
-    "def get_time(timezone: str) -> str:\n",
-    "    \"\"\"Finds the current time in a specific timezone.\n",
-    "\n",
-    "    :param timezone: The timezone to find the current time in, should\n",
-    "        be a valid timezone from the IANA Time Zone Database like\n",
-    "        \"America/New_York\" or \"Europe/London\".\n",
-    "    :type timezone: str\n",
-    "    :return: The current time in the specified timezone.\"\"\"\n",
-    "    now = datetime.now(ZoneInfo(timezone))\n",
-    "    return now.strftime(\"%H:%M\")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 5,
-   "metadata": {},
-   "outputs": [
+    },
     {
-     "data": {
-      "text/plain": [
-       "'12:11'"
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "_4JgNeX4ur0v"
+      },
+      "source": [
+        "In semantic-router there are two types of routes that can be chosen. Both routes belong to the `Route` object, the only difference between them is that _static_ routes return a `Route.name` when chosen, whereas _dynamic_ routes use an LLM call to produce parameter input values.\n",
+        "\n",
+        "For example, a _static_ route will tell us if a query is talking about mathematics by returning the route name (which could be `\"math\"` for example). A _dynamic_ route can generate additional values, so it may decide a query is talking about maths, but it can also generate Python code that we can later execute to answer the user's query, this output may look like `\"math\", \"import math; output = math.sqrt(64)`."
       ]
-     },
-     "execution_count": 5,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "get_time(\"America/New_York\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "To get the function schema we can use the `get_schema` function from the `function_call` module."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 6,
-   "metadata": {},
-   "outputs": [
+    },
     {
-     "data": {
-      "text/plain": [
-       "{'name': 'get_time',\n",
-       " 'description': 'Finds the current time in a specific timezone.\\n\\n:param timezone: The timezone to find the current time in, should\\n    be a valid timezone from the IANA Time Zone Database like\\n    \"America/New_York\" or \"Europe/London\".\\n:type timezone: str\\n:return: The current time in the specified timezone.',\n",
-       " 'signature': '(timezone: str) -> str',\n",
-       " 'output': \"<class 'str'>\"}"
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "bbmw8CO4ur0v"
+      },
+      "source": [
+        "## Installing the Library"
       ]
-     },
-     "execution_count": 6,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "from semantic_router.utils.function_call import get_schema\n",
-    "\n",
-    "schema = get_schema(get_time)\n",
-    "schema"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "We use this to define our dynamic route:"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 7,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "time_route = Route(\n",
-    "    name=\"get_time\",\n",
-    "    utterances=[\n",
-    "        \"what is the time in new york city?\",\n",
-    "        \"what is the time in london?\",\n",
-    "        \"I live in Rome, what time is it?\",\n",
-    "    ],\n",
-    "    function_schema=schema,\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Add the new route to our `layer`:"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 8,
-   "metadata": {},
-   "outputs": [
+    },
     {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "\u001b[32m2024-01-07 18:11:20 INFO semantic_router.utils.logger Adding `get_time` route\u001b[0m\n"
-     ]
-    }
-   ],
-   "source": [
-    "rl.add(time_route)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Now we can ask our layer a time related question to trigger our new dynamic route."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 9,
-   "metadata": {},
-   "outputs": [
+      "cell_type": "code",
+      "execution_count": null,
+      "metadata": {
+        "id": "dLElfRhgur0v"
+      },
+      "outputs": [],
+      "source": [
+        "!pip install -qU semantic-router==0.0.15"
+      ]
+    },
     {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "\u001b[33m2024-01-07 18:11:23 WARNING semantic_router.utils.logger No LLM provided for dynamic route, will use OpenAI LLM default. Ensure API key is set in OPENAI_API_KEY environment variable.\u001b[0m\n",
-      "\u001b[32m2024-01-07 18:11:23 INFO semantic_router.utils.logger Extracting function input...\u001b[0m\n"
-     ]
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "BixZd6Eour0w"
+      },
+      "source": [
+        "## Initializing Routes and RouteLayer"
+      ]
     },
     {
-     "data": {
-      "text/plain": [
-       "RouteChoice(name='get_time', function_call={'timezone': 'new york city'})"
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "PxnW9qBvur0x"
+      },
+      "source": [
+        "Dynamic routes are treated in the same way as static routes, let's begin by initializing a `RouteLayer` consisting of static routes."
+      ]
+    },
+    {
+      "cell_type": "code",
+      "execution_count": 1,
+      "metadata": {
+        "id": "kc9Ty6Lgur0x"
+      },
+      "outputs": [],
+      "source": [
+        "from semantic_router import Route\n",
+        "\n",
+        "politics = Route(\n",
+        "    name=\"politics\",\n",
+        "    utterances=[\n",
+        "        \"isn't politics the best thing ever\",\n",
+        "        \"why don't you tell me about your political opinions\",\n",
+        "        \"don't you just love the president\" \"don't you just hate the president\",\n",
+        "        \"they're going to destroy this country!\",\n",
+        "        \"they will save the country!\",\n",
+        "    ],\n",
+        ")\n",
+        "chitchat = Route(\n",
+        "    name=\"chitchat\",\n",
+        "    utterances=[\n",
+        "        \"how's the weather today?\",\n",
+        "        \"how are things going?\",\n",
+        "        \"lovely weather today\",\n",
+        "        \"the weather is horrendous\",\n",
+        "        \"let's go to the chippy\",\n",
+        "    ],\n",
+        ")\n",
+        "\n",
+        "routes = [politics, chitchat]"
+      ]
+    },
+    {
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "voWyqmffur0x"
+      },
+      "source": [
+        "We initialize our `RouteLayer` with our `encoder` and `routes`. We can use popular encoder APIs like `CohereEncoder` and `OpenAIEncoder`, or local alternatives like `FastEmbedEncoder`."
+      ]
+    },
+    {
+      "cell_type": "code",
+      "execution_count": 3,
+      "metadata": {
+        "id": "BI9AiDspur0y",
+        "outputId": "27329a54-3f16-44a5-ac20-13a6b26afb97",
+        "colab": {
+          "base_uri": "https://localhost:8080/"
+        }
+      },
+      "outputs": [
+        {
+          "output_type": "stream",
+          "name": "stderr",
+          "text": [
+            "\u001b[32m2024-01-08 11:12:24 INFO semantic_router.utils.logger Initializing RouteLayer\u001b[0m\n"
+          ]
+        }
+      ],
+      "source": [
+        "import os\n",
+        "from getpass import getpass\n",
+        "from semantic_router import RouteLayer\n",
+        "from semantic_router.encoders import CohereEncoder, OpenAIEncoder\n",
+        "\n",
+        "# dashboard.cohere.ai\n",
+        "# os.environ[\"COHERE_API_KEY\"] = os.getenv(\"COHERE_API_KEY\") or getpass(\n",
+        "#     \"Enter Cohere API Key: \"\n",
+        "# )\n",
+        "# platform.openai.com\n",
+        "os.environ[\"OPENAI_API_KEY\"] = os.getenv(\"OPENAI_API_KEY\") or getpass(\n",
+        "    \"Enter OpenAI API Key: \"\n",
+        ")\n",
+        "\n",
+        "# encoder = CohereEncoder()\n",
+        "encoder = OpenAIEncoder()\n",
+        "\n",
+        "rl = RouteLayer(encoder=encoder, routes=routes)"
+      ]
+    },
+    {
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "GuLCeIS5ur0y"
+      },
+      "source": [
+        "We run the solely static routes layer:"
+      ]
+    },
+    {
+      "cell_type": "code",
+      "execution_count": 4,
+      "metadata": {
+        "id": "_rNREh7gur0y",
+        "outputId": "f3a1dc0b-d760-4efb-b634-d3547011dcb7",
+        "colab": {
+          "base_uri": "https://localhost:8080/"
+        }
+      },
+      "outputs": [
+        {
+          "output_type": "execute_result",
+          "data": {
+            "text/plain": [
+              "RouteChoice(name='chitchat', function_call=None)"
+            ]
+          },
+          "metadata": {},
+          "execution_count": 4
+        }
+      ],
+      "source": [
+        "rl(\"how's the weather today?\")"
+      ]
+    },
+    {
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "McbLKO26ur0y"
+      },
+      "source": [
+        "## Creating a Dynamic Route"
+      ]
+    },
+    {
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "ANAoEjxYur0y"
+      },
+      "source": [
+        "As with static routes, we must create a dynamic route before adding it to our route layer. To make a route dynamic, we need to provide a `function_schema`. The function schema provides instructions on what a function is, so that an LLM can decide how to use it correctly."
+      ]
+    },
+    {
+      "cell_type": "code",
+      "execution_count": 5,
+      "metadata": {
+        "id": "5jaF1Xa5ur0y"
+      },
+      "outputs": [],
+      "source": [
+        "from datetime import datetime\n",
+        "from zoneinfo import ZoneInfo\n",
+        "\n",
+        "\n",
+        "def get_time(timezone: str) -> str:\n",
+        "    \"\"\"Finds the current time in a specific timezone.\n",
+        "\n",
+        "    :param timezone: The timezone to find the current time in, should\n",
+        "        be a valid timezone from the IANA Time Zone Database like\n",
+        "        \"America/New_York\" or \"Europe/London\". Do NOT put the place\n",
+        "        name itself like \"rome\", or \"new york\", you must provide\n",
+        "        the IANA format.\n",
+        "    :type timezone: str\n",
+        "    :return: The current time in the specified timezone.\"\"\"\n",
+        "    now = datetime.now(ZoneInfo(timezone))\n",
+        "    return now.strftime(\"%H:%M\")"
+      ]
+    },
+    {
+      "cell_type": "code",
+      "execution_count": 6,
+      "metadata": {
+        "id": "YyFKV8jMur0z",
+        "outputId": "29cf80f4-552c-47bb-fbf9-019f5dfdf00a",
+        "colab": {
+          "base_uri": "https://localhost:8080/",
+          "height": 35
+        }
+      },
+      "outputs": [
+        {
+          "output_type": "execute_result",
+          "data": {
+            "text/plain": [
+              "'06:13'"
+            ],
+            "application/vnd.google.colaboratory.intrinsic+json": {
+              "type": "string"
+            }
+          },
+          "metadata": {},
+          "execution_count": 6
+        }
+      ],
+      "source": [
+        "get_time(\"America/New_York\")"
+      ]
+    },
+    {
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "4qyaRuNXur0z"
+      },
+      "source": [
+        "To get the function schema we can use the `get_schema` function from the `function_call` module."
+      ]
+    },
+    {
+      "cell_type": "code",
+      "execution_count": 7,
+      "metadata": {
+        "id": "tOjuhp5Xur0z",
+        "outputId": "ca88a3ea-d70a-4950-be9a-63fab699de3b",
+        "colab": {
+          "base_uri": "https://localhost:8080/"
+        }
+      },
+      "outputs": [
+        {
+          "output_type": "execute_result",
+          "data": {
+            "text/plain": [
+              "{'name': 'get_time',\n",
+              " 'description': 'Finds the current time in a specific timezone.\\n\\n:param timezone: The timezone to find the current time in, should\\n    be a valid timezone from the IANA Time Zone Database like\\n    \"America/New_York\" or \"Europe/London\". Do NOT put the place\\n    name itself like \"rome\", or \"new york\", you must provide\\n    the IANA format.\\n:type timezone: str\\n:return: The current time in the specified timezone.',\n",
+              " 'signature': '(timezone: str) -> str',\n",
+              " 'output': \"<class 'str'>\"}"
+            ]
+          },
+          "metadata": {},
+          "execution_count": 7
+        }
+      ],
+      "source": [
+        "from semantic_router.utils.function_call import get_schema\n",
+        "\n",
+        "schema = get_schema(get_time)\n",
+        "schema"
+      ]
+    },
+    {
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "HcF7jGjAur0z"
+      },
+      "source": [
+        "We use this to define our dynamic route:"
+      ]
+    },
+    {
+      "cell_type": "code",
+      "execution_count": 8,
+      "metadata": {
+        "id": "iesBG9P3ur0z"
+      },
+      "outputs": [],
+      "source": [
+        "time_route = Route(\n",
+        "    name=\"get_time\",\n",
+        "    utterances=[\n",
+        "        \"what is the time in new york city?\",\n",
+        "        \"what is the time in london?\",\n",
+        "        \"I live in Rome, what time is it?\",\n",
+        "    ],\n",
+        "    function_schema=schema,\n",
+        ")"
+      ]
+    },
+    {
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "ZiUs3ovpur0z"
+      },
+      "source": [
+        "Add the new route to our `layer`:"
+      ]
+    },
+    {
+      "cell_type": "code",
+      "execution_count": 9,
+      "metadata": {
+        "id": "-0vY8PRXur0z",
+        "outputId": "db01e14c-eab3-4f93-f4c2-e30f508c8b5d",
+        "colab": {
+          "base_uri": "https://localhost:8080/"
+        }
+      },
+      "outputs": [
+        {
+          "output_type": "stream",
+          "name": "stderr",
+          "text": [
+            "\u001b[32m2024-01-08 11:15:26 INFO semantic_router.utils.logger Adding `get_time` route\u001b[0m\n"
+          ]
+        }
+      ],
+      "source": [
+        "rl.add(time_route)"
+      ]
+    },
+    {
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "7yoE0IrNur0z"
+      },
+      "source": [
+        "Now we can ask our layer a time related question to trigger our new dynamic route."
+      ]
+    },
+    {
+      "cell_type": "code",
+      "execution_count": 11,
+      "metadata": {
+        "id": "Wfb68M0-ur0z",
+        "outputId": "79923883-2a4d-4744-f8ce-e818cb5f14c3",
+        "colab": {
+          "base_uri": "https://localhost:8080/",
+          "height": 53
+        }
+      },
+      "outputs": [
+        {
+          "output_type": "stream",
+          "name": "stderr",
+          "text": [
+            "\u001b[32m2024-01-08 11:16:24 INFO semantic_router.utils.logger Extracting function input...\u001b[0m\n"
+          ]
+        },
+        {
+          "output_type": "execute_result",
+          "data": {
+            "text/plain": [
+              "'06:16'"
+            ],
+            "application/vnd.google.colaboratory.intrinsic+json": {
+              "type": "string"
+            }
+          },
+          "metadata": {},
+          "execution_count": 11
+        }
+      ],
+      "source": [
+        "out = rl(\"what is the time in new york city?\")\n",
+        "get_time(**out.function_call)"
+      ]
+    },
+    {
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "Qt0vkq2Xur00"
+      },
+      "source": [
+        "Our dynamic route provides both the route itself _and_ the input parameters required to use the route."
+      ]
+    },
+    {
+      "cell_type": "markdown",
+      "metadata": {
+        "id": "J0oD1dxIur00"
+      },
+      "source": [
+        "---"
       ]
-     },
-     "execution_count": 9,
-     "metadata": {},
-     "output_type": "execute_result"
     }
-   ],
-   "source": [
-    "# https://platform.openai.com/\n",
-    "os.environ[\"OPENAI_API_KEY\"] = os.getenv(\"OPENAI_API_KEY\") or getpass(\n",
-    "    \"Enter OpenAI API Key: \"\n",
-    ")\n",
-    "\n",
-    "rl(\"what is the time in new york city?\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Our dynamic route provides both the route itself _and_ the input parameters required to use the route."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "---"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "decision-layer",
-   "language": "python",
-   "name": "python3"
+  ],
+  "metadata": {
+    "kernelspec": {
+      "display_name": "decision-layer",
+      "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"
+    },
+    "colab": {
+      "provenance": []
+    }
   },
-  "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
-}
+  "nbformat": 4,
+  "nbformat_minor": 0
+}
\ No newline at end of file
diff --git a/docs/03-basic-langchain-agent.ipynb b/docs/03-basic-langchain-agent.ipynb
index c8c48b3dbedf5c6a09243ff2c93a1071f40c916d..dc728495136a804a79340026d14f56807929e443 100644
--- a/docs/03-basic-langchain-agent.ipynb
+++ b/docs/03-basic-langchain-agent.ipynb
@@ -83,15 +83,6 @@
     "    openai==1.6.1"
    ]
   },
-  {
-   "cell_type": "markdown",
-   "metadata": {
-    "id": "cHtVnoJPA04x"
-   },
-   "source": [
-    "_**⚠️ If using Google Colab, install the prerequisites and then restart the notebook before continuing**_"
-   ]
-  },
   {
    "cell_type": "markdown",
    "metadata": {
diff --git a/docs/04-chat-history.ipynb b/docs/04-chat-history.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..4ac533b1ef4126ac63cb6b8cacf2441d73a538ea
--- /dev/null
+++ b/docs/04-chat-history.ipynb
@@ -0,0 +1,139 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/aurelio-labs/semantic-router/blob/main/docs/00-introduction.ipynb) [![Open nbviewer](https://raw.githubusercontent.com/pinecone-io/examples/master/assets/nbviewer-shield.svg)](https://nbviewer.org/github/aurelio-labs/semantic-router/blob/main/docs/00-introduction.ipynb)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Considering Chat History"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Applying semantic-router to the most recent interaction in a conversation can work for many cases but it misses scenarios where information provided in the latest interaction."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "/Users/jamesbriggs/opt/anaconda3/envs/decision-layer/lib/python3.11/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
+      "  from .autonotebook import tqdm as notebook_tqdm\n",
+      "100%|██████████| 83.2M/83.2M [00:09<00:00, 8.45MiB/s]\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "{'split 1': ['User: Hello! Can you tell me the latest news headlines?',\n",
+       "  'Bot: Hi! Sure, here are the top news headlines for today...'],\n",
+       " 'split 2': [\"User: That's quite interesting. I'm also looking for some new music to listen to.\",\n",
+       "  'Bot: What genre do you prefer?',\n",
+       "  'User: I like pop music.',\n",
+       "  'Bot: You might enjoy the latest album by Dua Lipa.',\n",
+       "  \"User: I'll give it a listen. Also, I'm planning a trip and need some travel tips.\",\n",
+       "  'Bot: Sure, where are you planning to go?'],\n",
+       " 'split 3': [\"User: I'm thinking of visiting Italy.\",\n",
+       "  'Bot: Italy is a beautiful country. Make sure to visit the Colosseum in Rome and the canals in Venice.'],\n",
+       " 'split 4': ['User: Those sound like great suggestions. I also need some help with my diet.',\n",
+       "  'Bot: What kind of diet are you following?',\n",
+       "  \"User: I'm trying to eat more protein.\",\n",
+       "  'Bot: Include lean meats, eggs, and legumes in your diet for a protein boost.',\n",
+       "  \"User: Thanks for the tips! I'll talk to you later.\",\n",
+       "  \"Bot: You're welcome! Don't hesitate to reach out if you need more help.\",\n",
+       "  'User: I appreciate it. Goodbye!',\n",
+       "  'Bot: Goodbye! Take care!']}"
+      ]
+     },
+     "execution_count": 1,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "from semantic_router.schema import Conversation, Message\n",
+    "from semantic_router.encoders import FastEmbedEncoder\n",
+    "\n",
+    "\n",
+    "messages = [\n",
+    "    \"User: Hello! Can you tell me the latest news headlines?\",\n",
+    "    \"Bot: Hi! Sure, here are the top news headlines for today...\",\n",
+    "    \"User: That's quite interesting. I'm also looking for some new music to listen to.\",\n",
+    "    \"Bot: What genre do you prefer?\",\n",
+    "    \"User: I like pop music.\",\n",
+    "    \"Bot: You might enjoy the latest album by Dua Lipa.\",\n",
+    "    \"User: I'll give it a listen. Also, I'm planning a trip and need some travel tips.\",\n",
+    "    \"Bot: Sure, where are you planning to go?\",\n",
+    "    \"User: I'm thinking of visiting Italy.\",\n",
+    "    \"Bot: Italy is a beautiful country. Make sure to visit the Colosseum in Rome and the canals in Venice.\",\n",
+    "    \"User: Those sound like great suggestions. I also need some help with my diet.\",\n",
+    "    \"Bot: What kind of diet are you following?\",\n",
+    "    \"User: I'm trying to eat more protein.\",\n",
+    "    \"Bot: Include lean meats, eggs, and legumes in your diet for a protein boost.\",\n",
+    "    \"User: Thanks for the tips! I'll talk to you later.\",\n",
+    "    \"Bot: You're welcome! Don't hesitate to reach out if you need more help.\",\n",
+    "    \"User: I appreciate it. Goodbye!\",\n",
+    "    \"Bot: Goodbye! Take care!\",\n",
+    "]\n",
+    "\n",
+    "encoder = FastEmbedEncoder(model_name=\"sentence-transformers/all-MiniLM-L6-v2\")\n",
+    "\n",
+    "convo = Conversation(\n",
+    "    messages=[\n",
+    "        Message(role=m.split(\": \")[0], content=m.split(\": \")[1]) for m in messages\n",
+    "    ]\n",
+    ")\n",
+    "\n",
+    "convo.split_by_topic(\n",
+    "    encoder=encoder, threshold=0.72, split_method=\"cumulative_similarity_drop\"\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "ml",
+   "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
+}