{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 🤖 Level 1.5 · Session 1 — Meet the Agent\n",
    "### AI Agents track · Google Colab · powered by **Google Gemini (free)**\n",
    "\n",
    "You'll turn a plain LLM into a real **agent**: give it a tool and run the **loop** (Perceive → Reason → Act → Observe → repeat).\n",
    "\n",
    "| Part | You'll do | ✅ Done when |\n",
    "|---|---|---|\n",
    "| **A · The engine** | Talk to Gemini once | You print a reply |\n",
    "| **B · Add a tool** | A tool the model can call | The model asks to use your tool |\n",
    "| **C · The agent loop** | Perceive→Reason→Act→Observe | The agent reaches the goal by calling tools |\n",
    "\n",
    "> Run each grey cell in order with ▶️ / Shift+Enter. Read the note above it first."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 🅰️ Part A — The engine underneath\n",
    "### 🔑 Get your free Gemini key (once)\n",
    "1. Open **https://aistudio.google.com/apikey** → **Create API key** → copy it.\n",
    "2. Run the cells below; paste the key when asked.\n",
    "\n",
    "🔒 An API key is a password — never paste it into a public doc, chat, or GitHub."
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "!pip -q install google-genai"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "from google import genai\n",
    "from google.genai import types\n",
    "import getpass\n",
    "API_KEY = getpass.getpass('Paste your Gemini API key: ').strip()\n",
    "client = genai.Client(api_key=API_KEY)\n",
    "print('Client ready ✅')"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "# Auto-pick a fast model (names change, so we ask your key what's available)\n",
    "model_names = [m.name for m in client.models.list()]\n",
    "flash = [m for m in model_names if 'flash' in m and 'embedding' not in m]\n",
    "MODEL = flash[0] if flash else 'models/gemini-2.5-flash'\n",
    "print('Using MODEL =', MODEL)"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "# ✅ TEST: the LLM 'engine' works\n",
    "r = client.models.generate_content(model=MODEL, contents='In 8 words, what is an AI agent?')\n",
    "print(r.text)\n",
    "assert r.text, 'No reply — check your key/model.'\n",
    "print('\\n✅ Engine works! But right now it can only TALK. Let’s give it hands.')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 🅱️ Part B — Give it a tool\n",
    "On its own the model can only produce text. A **tool** is a Python function it can choose to call. Let's give it one it actually needs: today's date + a simple calculator (the model is bad at exact math)."
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "import datetime\n",
    "\n",
    "def today() -> str:\n",
    "    \"\"\"Return today's date.\"\"\"\n",
    "    return str(datetime.date.today())\n",
    "\n",
    "def calculator(expression: str) -> str:\n",
    "    \"\"\"Evaluate a simple arithmetic expression like '128*47'.\"\"\"\n",
    "    allowed = set('0123456789+-*/(). ')\n",
    "    if not set(expression) <= allowed:\n",
    "        return 'Error: only numbers and + - * / ( ) allowed'\n",
    "    return str(eval(expression))\n",
    "\n",
    "print('Tools ready:', today.__name__, '+', calculator.__name__)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 🅲 Part C — Run the agent loop\n",
    "We hand both tools to Gemini and **turn OFF auto-calling** so *we* run the loop and can watch every step: **Perceive → Reason → Act → Observe**, repeating until the goal is met."
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "TOOLS = {'today': today, 'calculator': calculator}\n",
    "\n",
    "config = types.GenerateContentConfig(\n",
    "    system_instruction=(\n",
    "        'You are a helpful agent. You are bad at exact math and do not know today\\'s date, '\n",
    "        'so you MUST call the calculator and today tools instead of guessing.'),\n",
    "    tools=[today, calculator],\n",
    "    automatic_function_calling=types.AutomaticFunctionCallingConfig(disable=True),\n",
    ")\n",
    "\n",
    "goal = 'What is today\\'s date, and what is 1440 multiplied by 365?'\n",
    "history = [types.Content(role='user', parts=[types.Part(text=goal)])]\n",
    "\n",
    "for step in range(6):  # safety cap so it can't loop forever\n",
    "    resp = client.models.generate_content(model=MODEL, contents=history, config=config)\n",
    "    parts = resp.candidates[0].content.parts\n",
    "    calls = [p.function_call for p in parts if p.function_call]\n",
    "    if not calls:\n",
    "        print('\\n🏁 FINAL ANSWER:\\n', resp.text); break\n",
    "    history.append(resp.candidates[0].content)          # Observe/Memory: remember the action\n",
    "    for fc in calls:\n",
    "        print(f'🛠️  Act → {fc.name}({dict(fc.args)})')\n",
    "        result = TOOLS[fc.name](**dict(fc.args))\n",
    "        print(f'👀 Observe → {result}')\n",
    "        history.append(types.Content(role='user',\n",
    "            parts=[types.Part.from_function_response(name=fc.name, response={'result': result})]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "🧪 **Test:** you should see `🛠️ Act` and `👀 Observe` lines (the agent using tools), then a correct final answer. That loop — reason, act, observe, repeat — is the whole idea of an agent. 🎉"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "# 🎯 YOUR TURN: add a THIRD tool and give a goal that needs it.\n",
    "def reverse_text(text: str) -> str:\n",
    "    \"\"\"Reverse a string.\"\"\"\n",
    "    return text[::-1]\n",
    "\n",
    "# Add reverse_text to tools=[...] and TOOLS above, then try a goal like:\n",
    "# 'Reverse the word AGENT and tell me today\\'s date.'\n",
    "print('Wire reverse_text into the agent and re-run the loop!')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 🎉 You built an agent\n",
    "An LLM is the brain; **tools** are the hands; the **loop** keeps it going until the goal is met.\n",
    "\n",
    "**Next session — Powering the Agent:** more tools (function calling), sharper prompts, and giving your agent a memory.\n",
    "\n",
    "_AI Agents track · LearnAI Level 1.5 · part of MillionRoots._"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "name": "L1.5 Session 1 — Meet the Agent",
   "provenance": []
  },
  "kernelspec": {
   "name": "python3",
   "display_name": "Python 3"
  },
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}