{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "68c0837d-c40a-4209-9f88-5d08c00c31b0",
   "metadata": {},
   "source": [
    "# How to create agents with configuration\n",
    "\n",
    "One of the benefits of LangGraph API is that it lets you create agents with different configurations.\n",
    "This is useful when you want to:\n",
    "\n",
    "- Define a cognitive architecture once as a LangGraph\n",
    "- Let that LangGraph be configurable across some attributes (for example, system message or LLM to use)\n",
    "- Let users create agents with arbitrary configurations, save them, and then use them in the future\n",
    "\n",
    "In this guide we will show how to do that for the default agent we have built in.\n",
    "\n",
    "If you look at the agent we defined, you can see that inside the `call_model` node we have created the model based on some configuration. That node looks like:\n",
    "\n",
    "```python\n",
    "def call_model(state, config):\n",
    "    messages = state[\"messages\"]\n",
    "    model_name = config.get('configurable', {}).get(\"model_name\", \"anthropic\")\n",
    "    model = _get_model(model_name)\n",
    "    response = model.invoke(messages)\n",
    "    # We return a list, because this will get added to the existing list\n",
    "    return {\"messages\": [response]}\n",
    "```\n",
    "\n",
    "We are looking inside the config for a `model_name` parameter (which defaults to `anthropic` if none is found).\n",
    "That means that by default we are using Anthropic as our model provider.\n",
    "In this example we will see an example of how to create an example agent that is configured to use OpenAI.\n",
    "\n",
    "We've also communicated to the graph that it should expect configuration with this key. \n",
    "We've done this by passing `config_schema` when constructing the graph, eg:\n",
    "\n",
    "```python\n",
    "class GraphConfig(TypedDict):\n",
    "    model_name: Literal[\"anthropic\", \"openai\"]\n",
    "\n",
    "\n",
    "# Define a new graph\n",
    "workflow = StateGraph(AgentState, config_schema=GraphConfig)\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "f69c9a4f-2ef9-4998-827b-fe86d12bfd76",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langgraph_sdk import get_client\n",
    "\n",
    "client = get_client()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "9a37bfb5-7331-4004-8054-508838e54f18",
   "metadata": {},
   "outputs": [],
   "source": [
    "# First, let's check what valid configuration can be\n",
    "# We can do this by getting the default assistant\n",
    "# There should always be a default assistant with no configuration\n",
    "assistants = await client.assistants.search()\n",
    "assistants = [a for a in assistants if not a[\"config\"]]\n",
    "base_assistant = assistants[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "70193a08-127c-44b3-a102-10db260d7e3b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'model_name': {'title': 'Model Name',\n",
       "  'enum': ['anthropic', 'openai'],\n",
       "  'type': 'string'}}"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# We can now call `.get_schemas` to get schemas associated with this graph\n",
    "schemas = await client.assistants.get_schemas(\n",
    "    assistant_id=base_assistant[\"assistant_id\"]\n",
    ")\n",
    "# There are multiple types of schemas\n",
    "# We can get the `config_schema` to look at the the configurable parameters\n",
    "schemas[\"config_schema\"][\"definitions\"][\"Configurable\"][\"properties\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "99be5aee-9a6b-4515-b72f-ba135a893c65",
   "metadata": {},
   "outputs": [],
   "source": [
    "assistant = await client.assistants.create(\n",
    "    graph_id=\"agent\", config={\"configurable\": {\"model_name\": \"openai\"}}\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4f10d346-69e6-44f4-8ff0-ef539ba938df",
   "metadata": {},
   "source": [
    "We can see that this assistant has saved the config"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "3898ca35-eb2c-4b12-97ea-e0cc6a7c6a2e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'assistant_id': '40a3a2bf-5319-4fae-a2ac-05e075615cdc',\n",
       " 'graph_id': 'agent',\n",
       " 'config': {'configurable': {'model_name': 'openai'}},\n",
       " 'created_at': '2024-06-05T23:12:30.519458+00:00',\n",
       " 'updated_at': '2024-06-05T23:12:30.519458+00:00',\n",
       " 'metadata': {}}"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assistant"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "68ed7a1b-74be-4560-8c55-c76d49d3d348",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "StreamPart(event='metadata', data={'run_id': '1ef23911-c23b-6d8c-b1dc-94bb982ca7b1'})\n",
      "StreamPart(event='values', data={'messages': [{'role': 'user', 'content': 'who made you?'}]})\n",
      "StreamPart(event='values', data={'messages': [{'content': 'who made you?', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': 'ed93c1c9-80d6-4f2b-a048-ef859ea533f9', 'example': False}, {'content': 'I was created by OpenAI, a research organization focused on developing and advancing artificial intelligence technology.', 'additional_kwargs': {}, 'response_metadata': {'finish_reason': 'stop'}, 'type': 'ai', 'name': None, 'id': 'run-6560cd65-5c9c-434b-8835-0baadc684760', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}]})\n",
      "StreamPart(event='end', data=None)\n"
     ]
    }
   ],
   "source": [
    "thread = await client.threads.create()\n",
    "input = {\"messages\": [{\"role\": \"user\", \"content\": \"who made you?\"}]}\n",
    "async for event in client.runs.stream(\n",
    "    thread[\"thread_id\"], assistant[\"assistant_id\"], input=input\n",
    "):\n",
    "    print(event)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "666d78f1-019a-433e-839e-52d2ebb3d9c8",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
