{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# OpenAI Tool Calling Agent - Dummy Weather Example\n",
    "\n",
    "* Collaborator: Roberto Rodriguez @Cyb3rWard0g"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Import Environment Variables"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from dotenv import load_dotenv\n",
    "load_dotenv()  # take environment variables from .env."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Enable Logging"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import logging\n",
    "\n",
    "logging.basicConfig(level=logging.INFO)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Define Tools"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "from dapr_agents import tool\n",
    "from pydantic import BaseModel, Field\n",
    "\n",
    "class GetWeatherSchema(BaseModel):\n",
    "    location: str = Field(description=\"location to get weather for\")\n",
    "\n",
    "@tool(args_model=GetWeatherSchema)\n",
    "def get_weather(location: str) -> str:\n",
    "    \"\"\"Get weather information for a specific location.\"\"\"\n",
    "    import random\n",
    "    temperature = random.randint(60, 80)\n",
    "    return f\"{location}: {temperature}F.\"\n",
    "\n",
    "class JumpSchema(BaseModel):\n",
    "    distance: str = Field(description=\"Distance for agent to jump\")\n",
    "\n",
    "@tool(args_model=JumpSchema)\n",
    "def jump(distance: str) -> str:\n",
    "    \"\"\"Jump a specific distance.\"\"\"\n",
    "    return f\"I jumped the following distance {distance}\"\n",
    "\n",
    "tools = [get_weather,jump]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Initialize Agent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:dapr_agents.llm.openai.client.base:Initializing OpenAI client...\n",
      "INFO:dapr_agents.tool.executor:Tool registered: GetWeather\n",
      "INFO:dapr_agents.tool.executor:Tool registered: Jump\n",
      "INFO:dapr_agents.tool.executor:Tool Executor initialized with 2 tool(s).\n",
      "INFO:dapr_agents.agent.base:Constructing system_prompt from agent attributes.\n",
      "INFO:dapr_agents.agent.base:Using system_prompt to create the prompt template.\n",
      "INFO:dapr_agents.agent.base:Pre-filled prompt template with attributes: ['name', 'role', 'goal']\n"
     ]
    }
   ],
   "source": [
    "from dapr_agents import ReActAgent\n",
    "\n",
    "AIAgent = ReActAgent(\n",
    "    name=\"Rob\",\n",
    "    role= \"Weather Assistant\",\n",
    "    tools=tools\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "ChatPromptTemplate(input_variables=['chat_history'], pre_filled_variables={'name': 'Rob', 'role': 'Weather Assistant', 'goal': 'Help humans'}, messages=[('system', '# Today\\'s date is: April 05, 2025\\n\\n## Name\\nYour name is {{name}}.\\n\\n## Role\\nYour role is {{role}}.\\n\\n## Goal\\n{{goal}}.\\n\\n## Tools\\nYou have access ONLY to the following tools:\\nGetWeather: Get weather information for a specific location.. Args schema: {\\'location\\': {\\'description\\': \\'location to get weather for\\', \\'type\\': \\'string\\'}}\\nJump: Jump a specific distance.. Args schema: {\\'distance\\': {\\'description\\': \\'Distance for agent to jump\\', \\'type\\': \\'string\\'}}\\n\\nIf you think about using tool, it must use the correct tool JSON blob format as shown below:\\n```\\n{\\n    \"name\": $TOOL_NAME,\\n    \"arguments\": $INPUT\\n}\\n```\\n\\n## ReAct Format\\nThought: Reflect on the current state of the conversation or task. If additional information is needed, determine if using a tool is necessary. When a tool is required, briefly explain why it is needed for the specific step at hand, and immediately follow this with an `Action:` statement to address that specific requirement. Avoid combining multiple tool requests in a single `Thought`. If no tools are needed, proceed directly to an `Answer:` statement.\\nAction:\\n```\\n{\\n    \"name\": $TOOL_NAME,\\n    \"arguments\": $INPUT\\n}\\n```\\nObservation: Describe the result of the action taken.\\n... (repeat Thought/Action/Observation as needed, but **ALWAYS proceed to a final `Answer:` statement when you have enough information**)\\nThought: I now have sufficient information to answer the initial question.\\nAnswer: ALWAYS proceed to a final `Answer:` statement once enough information is gathered or if the tools do not provide the necessary data.\\n\\n### Providing a Final Answer\\nOnce you have enough information to answer the question OR if tools cannot provide the necessary data, respond using one of the following formats:\\n\\n1. **Direct Answer without Tools**:\\nThought: I can answer directly without using any tools. Answer: Direct answer based on previous interactions or current knowledge.\\n\\n2. **When All Needed Information is Gathered**:\\nThought: I now have sufficient information to answer the question. Answer: Complete final answer here.\\n\\n3. **If Tools Cannot Provide the Needed Information**:\\nThought: The available tools do not provide the necessary information. Answer: Explanation of limitation and relevant information if possible.\\n\\n### Key Guidelines\\n- Always Conclude with an `Answer:` statement.\\n- Ensure every response ends with an `Answer:` statement that summarizes the most recent findings or relevant information, avoiding incomplete thoughts.\\n- Direct Final Answer for Past or Known Information: If the user inquires about past interactions, respond directly with an Answer: based on the information in chat history.\\n- Avoid Repetitive Thought Statements: If the answer is ready, skip repetitive Thought steps and proceed directly to Answer.\\n- Minimize Redundant Steps: Use minimal Thought/Action/Observation cycles to arrive at a final Answer efficiently.\\n- Reference Past Information When Relevant: Use chat history accurately when answering questions about previous responses to avoid redundancy.\\n- Progressively Move Towards Finality: Reflect on the current step and avoid re-evaluating the entire user request each time. Aim to advance towards the final Answer in each cycle.\\n\\n## Chat History\\nThe chat history is provided to avoid repeating information and to ensure accurate references when summarizing past interactions.'), MessagePlaceHolder(variable_name=chat_history)], template_format='jinja2')"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "AIAgent.prompt_template"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'GetWeather'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "AIAgent.tools[0].name"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Run Agent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:dapr_agents.agent.patterns.react.base:Iteration 1/10 started.\n",
      "INFO:dapr_agents.llm.openai.chat:Invoking ChatCompletion API.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[38;2;242;182;128muser:\u001b[0m\n",
      "\u001b[38;2;242;182;128m\u001b[0m\u001b[38;2;242;182;128mHi my name is Roberto\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0m\n",
      "\u001b[0m--------------------------------------------------------------------------------\u001b[0m\n",
      "\u001b[0m\u001b[0m\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n",
      "INFO:dapr_agents.llm.openai.chat:Chat completion retrieved successfully.\n",
      "INFO:dapr_agents.agent.patterns.react.base:No action specified; continuing with further reasoning.\n",
      "INFO:dapr_agents.agent.patterns.react.base:Iteration 2/10 started.\n",
      "INFO:dapr_agents.llm.openai.chat:Invoking ChatCompletion API.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[38;2;217;95;118mThought: Hello Roberto! How can I assist you today?\u001b[0m\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n",
      "INFO:dapr_agents.llm.openai.chat:Chat completion retrieved successfully.\n",
      "INFO:dapr_agents.agent.patterns.react.base:Agent provided a direct final answer.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[38;2;217;95;118mThought: Answer: Hello Roberto! How can I assist you today?\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0m\n",
      "\u001b[0m--------------------------------------------------------------------------------\u001b[0m\n",
      "\u001b[0m\u001b[0m\u001b[0m\n",
      "\u001b[38;2;147;191;183massistant:\u001b[0m\n",
      "\u001b[38;2;147;191;183m\u001b[0m\u001b[38;2;147;191;183mHello Roberto! How can I assist you today?\u001b[0m\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'Hello Roberto! How can I assist you today?'"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "await AIAgent.run(\"Hi my name is Roberto\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'role': 'user', 'content': 'Hi my name is Roberto'},\n",
       " {'content': 'Hello Roberto! How can I assist you today?',\n",
       "  'role': 'assistant'}]"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "AIAgent.chat_history"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:dapr_agents.agent.patterns.react.base:Iteration 1/10 started.\n",
      "INFO:dapr_agents.llm.openai.chat:Invoking ChatCompletion API.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[38;2;242;182;128muser:\u001b[0m\n",
      "\u001b[38;2;242;182;128m\u001b[0m\u001b[38;2;242;182;128mWhat is the weather in Virgina, New York and Washington DC?\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0m\n",
      "\u001b[0m--------------------------------------------------------------------------------\u001b[0m\n",
      "\u001b[0m\u001b[0m\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n",
      "INFO:dapr_agents.llm.openai.chat:Chat completion retrieved successfully.\n",
      "INFO:dapr_agents.agent.patterns.react.base:Executing GetWeather with arguments {'location': 'Virginia'}\n",
      "INFO:dapr_agents.tool.executor:Running tool (auto): GetWeather\n",
      "INFO:dapr_agents.agent.patterns.react.base:Iteration 2/10 started.\n",
      "INFO:dapr_agents.llm.openai.chat:Invoking ChatCompletion API.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[38;2;217;95;118mThought: I need to get the current weather information for Virginia, New York, and Washington DC. I will fetch the data for each location separately. Let's start with Virginia.\u001b[0m\u001b[0m\n",
      "\u001b[38;2;191;69;126mAction: {\"name\": \"GetWeather\", \"arguments\": {\"location\": \"Virginia\"}}\u001b[0m\u001b[0m\n",
      "\u001b[38;2;146;94;130mObservation: Virginia: 77F.\u001b[0m\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n",
      "INFO:dapr_agents.llm.openai.chat:Chat completion retrieved successfully.\n",
      "INFO:dapr_agents.agent.patterns.react.base:Executing GetWeather with arguments {'location': 'New York'}\n",
      "INFO:dapr_agents.tool.executor:Running tool (auto): GetWeather\n",
      "INFO:dapr_agents.agent.patterns.react.base:Iteration 3/10 started.\n",
      "INFO:dapr_agents.llm.openai.chat:Invoking ChatCompletion API.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[38;2;217;95;118mThought: I now have the weather information for Virginia. Next, I will get the weather information for New York.\u001b[0m\u001b[0m\n",
      "\u001b[38;2;191;69;126mAction: {\"name\": \"GetWeather\", \"arguments\": {\"location\": \"New York\"}}\u001b[0m\u001b[0m\n",
      "\u001b[38;2;146;94;130mObservation: New York: 68F.\u001b[0m\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n",
      "INFO:dapr_agents.llm.openai.chat:Chat completion retrieved successfully.\n",
      "INFO:dapr_agents.agent.patterns.react.base:Executing GetWeather with arguments {'location': 'Washington DC'}\n",
      "INFO:dapr_agents.tool.executor:Running tool (auto): GetWeather\n",
      "INFO:dapr_agents.agent.patterns.react.base:Iteration 4/10 started.\n",
      "INFO:dapr_agents.llm.openai.chat:Invoking ChatCompletion API.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[38;2;217;95;118mThought: I have the weather information for Virginia and New York. Next, I will get the weather information for Washington DC.\u001b[0m\u001b[0m\n",
      "\u001b[38;2;191;69;126mAction: {\"name\": \"GetWeather\", \"arguments\": {\"location\": \"Washington DC\"}}\u001b[0m\u001b[0m\n",
      "\u001b[38;2;146;94;130mObservation: Washington DC: 69F.\u001b[0m\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n",
      "INFO:dapr_agents.llm.openai.chat:Chat completion retrieved successfully.\n",
      "INFO:dapr_agents.agent.patterns.react.base:Agent provided a direct final answer.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[38;2;217;95;118mThought: I now have the weather information for all requested locations. \u001b[0m\n",
      "\u001b[38;2;217;95;118m\u001b[0m\n",
      "\u001b[38;2;217;95;118mAnswer: The current weather is as follows:\u001b[0m\n",
      "\u001b[38;2;217;95;118m- Virginia: 77°F\u001b[0m\n",
      "\u001b[38;2;217;95;118m- New York: 68°F\u001b[0m\n",
      "\u001b[38;2;217;95;118m- Washington DC: 69°F\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0m\n",
      "\u001b[0m--------------------------------------------------------------------------------\u001b[0m\n",
      "\u001b[0m\u001b[0m\u001b[0m\n",
      "\u001b[38;2;147;191;183massistant:\u001b[0m\n",
      "\u001b[38;2;147;191;183m\u001b[0m\u001b[38;2;147;191;183mThe current weather is as follows:\u001b[0m\n",
      "\u001b[38;2;147;191;183m- Virginia: 77°F\u001b[0m\n",
      "\u001b[38;2;147;191;183m- New York: 68°F\u001b[0m\n",
      "\u001b[38;2;147;191;183m- Washington DC: 69°F\u001b[0m\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'The current weather is as follows:\\n- Virginia: 77°F\\n- New York: 68°F\\n- Washington DC: 69°F'"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "await AIAgent.run(\"What is the weather in Virgina, New York and Washington DC?\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "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.13.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
