{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "c00",
   "metadata": {},
   "source": [
    "# Practice — Core Code Patterns, from One Call to an Agent Loop\n",
    "\n",
    "[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/ralbu85/stml_2026/blob/main/lectures/week05/W5_practice_core_patterns_v2.ipynb)\n",
    "\n",
    "**Goal.** Write, without looking them up, the code every lab is built from: (1) one call, (2) a conversation, (3) JSON output, (4) a tool call, (5) the agent loop, (6) ReAct, and (7) an agent kept in a class. The tools are easy ones: live weather, a calculator, and Wikipedia search.\n",
    "\n",
    "**One way to write every call.** Every call uses the same three lines:\n",
    "\n",
    "```python\n",
    "response = client.chat.completions.create(model=MODEL, messages=messages)   # call the model with the list\n",
    "reply = response.choices[0].message.model_dump(exclude_none=True)           # the model's reply, as a dictionary\n",
    "messages.append(reply)                                                       # keep it as it arrived\n",
    "```\n",
    "\n",
    "Then you check the key of `reply`: a text answer has `\"content\"`; a tool request (Part 4 on) has `\"tool_calls\"`. You type only the messages you write (system, user, tool). The model's reply is never retyped.\n",
    "\n",
    "**Cell labels.** The first line of each code cell says what to do with it:\n",
    "\n",
    "- `# ✍️ TYPE` — an exercise: write the code between the `FILL IN` lines yourself.\n",
    "- `# ✍️ WRITE` — answer in words (not checked).\n",
    "- `# ▶ RUN · example` — the pattern being taught: read each line, then run.\n",
    "- `# ▶ RUN · setup` or `# ▶ RUN · check` — support cells: just run.\n",
    "\n",
    "About 80 minutes. Not collected. Needs basic Python: lists, dictionaries, functions, `for` loops, `if`, and f-strings."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c01",
   "metadata": {},
   "source": [
    "## 0. Setup\n",
    "\n",
    "*Do:* run the four cells; paste your API key into the second. The third defines `show_messages`, which prints the message list: each message's position, role, and content (for a request, the requested function). The fourth sends a first call and prints `ready`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c02",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · setup: just run\n",
    "%pip install -q \"openai==1.109.1\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c03",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · setup: just run\n",
    "import os\n",
    "\n",
    "OPENAI_API_KEY = \"PASTE-YOUR-KEY-HERE\"   # paste your key between the quotes\n",
    "if OPENAI_API_KEY != \"PASTE-YOUR-KEY-HERE\":\n",
    "    os.environ[\"OPENAI_API_KEY\"] = OPENAI_API_KEY   # the client reads the key from here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c04",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · setup: just run\n",
    "import json\n",
    "from openai import OpenAI\n",
    "\n",
    "client = OpenAI()                  # the OpenAI library; reads OPENAI_API_KEY from the environment\n",
    "MODEL = \"gpt-4.1\"\n",
    "done = {}                          # the check cells record your results here\n",
    "\n",
    "\n",
    "def show_messages(messages):\n",
    "    \"\"\"Print each message: position, role, and content.\"\"\"\n",
    "    for i in range(len(messages)):\n",
    "        m = messages[i]\n",
    "        if \"tool_calls\" in m:                          # a request: print each requested function\n",
    "            for request in m[\"tool_calls\"]:\n",
    "                print(i, m[\"role\"], request[\"function\"])\n",
    "        else:\n",
    "            print(i, m[\"role\"], m[\"content\"])\n",
    "    print()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c05",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · setup: just run\n",
    "messages = [{\"role\": \"user\", \"content\": \"Reply with exactly: ready\"}]\n",
    "response = client.chat.completions.create(model=MODEL, messages=messages)\n",
    "reply = response.choices[0].message.model_dump(exclude_none=True)\n",
    "messages.append(reply)\n",
    "reply[\"content\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c06",
   "metadata": {},
   "source": [
    "## 1. One Call: Call the Model, Keep the Reply\n",
    "\n",
    "```python\n",
    "messages = [{\"role\": \"user\", \"content\": QUESTION}]                           # the list you send\n",
    "response = client.chat.completions.create(model=MODEL, messages=messages)   # call the model with the list\n",
    "reply = response.choices[0].message.model_dump(exclude_none=True)           # the model's reply, as a dictionary\n",
    "messages.append(reply)                                                       # keep it as it arrived\n",
    "answer = reply[\"content\"]                                                    # the text answer\n",
    "```\n",
    "\n",
    "- `messages` is the list you send. Every message in it is a dictionary with a `\"role\"`.\n",
    "- `response` is what the API returns. `response.choices[0].message` is the model's reply; `.model_dump(exclude_none=True)` gives it as a dictionary and leaves out the fields whose value is `None`. So `reply` has the same shape as the messages you write.\n",
    "- `messages.append(reply)` keeps the reply in the list exactly as it arrived.\n",
    "- The keys of `reply` say what it holds. A text answer is under `\"content\"`.\n",
    "\n",
    "### 1.1 One call\n",
    "\n",
    "*Do:* run the cell. `print(reply)` shows the dictionary: `role`, `content`, and `annotations` (a list of web citations, empty here). The list now holds two messages."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c07",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "QUESTION = \"In one sentence, what is a cancelled order in an online shop?\"\n",
    "messages = [{\"role\": \"user\", \"content\": QUESTION}]\n",
    "response = client.chat.completions.create(model=MODEL, messages=messages)\n",
    "reply = response.choices[0].message.model_dump(exclude_none=True)\n",
    "messages.append(reply)\n",
    "answer = reply[\"content\"]\n",
    "\n",
    "print(reply)\n",
    "print(answer)\n",
    "show_messages(messages)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c08",
   "metadata": {},
   "source": [
    "**Reading the output.** The first printed line is `reply`, the model's message as a dictionary:\n",
    "\n",
    "```python\n",
    "{'content': 'A cancelled order in an online shop is ...',   # the text answer\n",
    " 'role': 'assistant',                                       # who wrote it: the model\n",
    " 'annotations': []}                                         # web citations; empty here\n",
    "```\n",
    "\n",
    "`reply` came out of `response` like this:\n",
    "\n",
    "```text\n",
    "response                                  the whole result of the call (an object)\n",
    " └─ choices                               a list of replies; one by default\n",
    "     └─ [0]                               the first reply\n",
    "         └─ message                       the model's message (an object)\n",
    "             └─ .model_dump(exclude_none=True)  ->  reply, a dictionary\n",
    "```\n",
    "\n",
    "The last lines come from `show_messages(messages)`: line `0` is your question (`messages[0]`), typed by you; line `1` is `reply` (`messages[1]`), kept as it arrived. Both are dictionaries with a `\"role\"`, so they sit in the same list."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c09",
   "metadata": {},
   "source": [
    "### 1.2 ✍️ Your first call\n",
    "\n",
    "*Do:* the question and the list are given; write the three call lines and read the answer. Expected: `PASS`, and 2 messages in the list."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c10",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ✍️ TYPE · exercise: write the code between the FILL IN lines yourself\n",
    "QUESTION = \"Reply with exactly: PASS\"\n",
    "messages = [{\"role\": \"user\", \"content\": QUESTION}]\n",
    "answer = None\n",
    "### FILL IN (START) ###\n",
    "# send the list, keep the reply, read the answer\n",
    "### FILL IN (END) ###"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c11",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · check: just run\n",
    "show_messages(messages)\n",
    "done[\"1.2\"] = answer == \"PASS\" and len(messages) == 2\n",
    "done[\"1.2\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c12",
   "metadata": {},
   "source": [
    "## 2. A Conversation: the List Grows\n",
    "\n",
    "A call sees only the list you send; the model keeps nothing between calls. To continue a conversation, add your next message to the same list and send the whole list again. Each message's **role** says who wrote it:\n",
    "\n",
    "| Kind | In the code | Written by | Holds |\n",
    "|---|---|---|---|\n",
    "| **System** message | `{\"role\": \"system\", \"content\": ...}`, first in the list | you, once | standing instructions for the whole conversation |\n",
    "| **User** message | `{\"role\": \"user\", \"content\": ...}` | you, for each request | the question or task, with any data it needs |\n",
    "| **Assistant** message | `reply`, kept with `messages.append(reply)` | the model | a text answer, or tool requests (Part 4) |\n",
    "| **Tool** message | `{\"role\": \"tool\", \"tool_call_id\": ..., \"content\": ...}` | your program (Part 4) | the result of a requested function |\n",
    "| **Tool schema** | `tools=TOOLS`, next to `messages`, not in it | you (Part 4) | a function the model may request |\n",
    "\n",
    "An **instruction** applies where you put it: in the system message, to every turn; in a user message, to that request; in a tool schema, whenever the model considers that tool.\n",
    "\n",
    "### 2.1 Two turns\n",
    "\n",
    "*Do:* run the four cells one by one. Units 2 and 4 are the same code: add nothing new, just call the model and keep the reply."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c13",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "## Unit 1 - the list: a system message and a user message\n",
    "STAFF_SYSTEM = \"You answer questions from shop staff. Answer in at most two sentences.\"\n",
    "QUESTION = \"A customer ordered 2 mugs and 1 desk lamp. List the items in the order.\"\n",
    "\n",
    "messages = [\n",
    "    {\"role\": \"system\", \"content\": STAFF_SYSTEM},     # SYSTEM message\n",
    "    {\"role\": \"user\", \"content\": QUESTION},           # USER message\n",
    "]\n",
    "show_messages(messages)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c14",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "## Unit 2 - call the model, read the answer\n",
    "response = client.chat.completions.create(model=MODEL, messages=messages)\n",
    "reply = response.choices[0].message.model_dump(exclude_none=True)\n",
    "messages.append(reply)                               # ASSISTANT message\n",
    "answer = reply[\"content\"]\n",
    "show_messages(messages)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c15",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "## Unit 3 - add the next question\n",
    "messages.append({\"role\": \"user\", \"content\": \"The lamp was cancelled. What is left in the order?\"})   # USER message\n",
    "show_messages(messages)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c16",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "## Unit 4 - call the model, read the answer (the same code as unit 2)\n",
    "response = client.chat.completions.create(model=MODEL, messages=messages)\n",
    "reply = response.choices[0].message.model_dump(exclude_none=True)\n",
    "messages.append(reply)                               # ASSISTANT message\n",
    "answer = reply[\"content\"]\n",
    "show_messages(messages)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c17",
   "metadata": {},
   "source": [
    "**Reading the output.** After two turns the list holds five messages:\n",
    "\n",
    "| Position | Role | Written by | How it got into the list |\n",
    "|---|---|---|---|\n",
    "| `[0]` | system | you | typed in unit 1 |\n",
    "| `[1]` | user | you | typed in unit 1 |\n",
    "| `[2]` | assistant | the model | `messages.append(reply)` in unit 2 |\n",
    "| `[3]` | user | you | typed in unit 3 |\n",
    "| `[4]` | assistant | the model | `messages.append(reply)` in unit 4 |\n",
    "\n",
    "User and assistant messages alternate. Unit 4 sent the whole list, so the second question could say only \"the lamp\": the model read the order in `[1]` and `[2]`. To rerun, start again from unit 1, or the list grows twice.\n",
    "\n",
    "### 2.2 ✍️ One more turn\n",
    "\n",
    "*Do:* the next question and the call are given; write the two lines that make `reply` and keep it. Expected: 7 messages, and an answer that lists the mugs and the notebooks."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c18",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ✍️ TYPE · exercise: write the code between the FILL IN lines yourself\n",
    "messages.append({\"role\": \"user\", \"content\": \"The customer adds 3 notebooks. What is in the order now?\"})\n",
    "response = client.chat.completions.create(model=MODEL, messages=messages)\n",
    "### FILL IN (START) ###\n",
    "# the reply as a dictionary, kept in the list\n",
    "### FILL IN (END) ###\n",
    "answer = reply[\"content\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c19",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · check: just run\n",
    "show_messages(messages)\n",
    "roles = []\n",
    "for m in messages:\n",
    "    roles.append(m[\"role\"])\n",
    "done[\"2.2\"] = roles == [\"system\", \"user\", \"assistant\", \"user\", \"assistant\", \"user\", \"assistant\"] and \"notebook\" in answer.lower() and \"mug\" in answer.lower()\n",
    "done[\"2.2\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c20",
   "metadata": {},
   "source": [
    "## 3. JSON Output Read into a Dictionary\n",
    "\n",
    "An answer is always text. When code needs its parts, ask for JSON and turn the text into a dictionary with `json.loads`. The three call lines stay the same; `response_format={\"type\": \"json_object\"}` is one more argument, and makes the API return valid JSON (the messages must contain the word \"JSON\").\n",
    "\n",
    "```python\n",
    "response = client.chat.completions.create(model=MODEL, messages=messages,\n",
    "                                          response_format={\"type\": \"json_object\"})\n",
    "reply = response.choices[0].message.model_dump(exclude_none=True)\n",
    "messages.append(reply)\n",
    "order = json.loads(reply[\"content\"])     # JSON text -> dictionary\n",
    "```\n",
    "\n",
    "### 3.1 Ask for JSON, read it as a dictionary\n",
    "\n",
    "The prompt is an f-string in triple quotes: `{customer_message}` is replaced by its value, and the text can span several lines.\n",
    "\n",
    "*Do:* run the two cells. The first prints `str`: the JSON arrives as text. The second reads it as a dictionary; `order[\"items\"]` is a list, so a `for` loop reads each item."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c21",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "## Unit 1 - call the model: the answer is JSON text\n",
    "customer_message = \"Hi, I'd like to order 3 notebooks and 2 pen sets, delivered to Busan.\"\n",
    "prompt = f\"\"\"Extract the order from the customer message.\n",
    "Return JSON with keys \"items\" (a list of objects with keys \"product\" and \"quantity\", the quantity as a number) and \"city\".\n",
    "\n",
    "Customer message: {customer_message}\"\"\"\n",
    "\n",
    "messages = [{\"role\": \"user\", \"content\": prompt}]\n",
    "response = client.chat.completions.create(model=MODEL, messages=messages,\n",
    "                                          response_format={\"type\": \"json_object\"})\n",
    "reply = response.choices[0].message.model_dump(exclude_none=True)\n",
    "messages.append(reply)\n",
    "print(type(reply[\"content\"]))\n",
    "reply[\"content\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c22",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "## Unit 2 - JSON text -> dictionary\n",
    "order = json.loads(reply[\"content\"])\n",
    "print(order[\"city\"])\n",
    "for item in order[\"items\"]:          # each item is a dictionary\n",
    "    print(item[\"product\"], item[\"quantity\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c23",
   "metadata": {},
   "source": [
    "**Reading the output.** `reply[\"content\"]` was JSON text (a `str`). `json.loads` turned it into this dictionary:\n",
    "\n",
    "```python\n",
    "{'items': [{'product': 'notebooks', 'quantity': 3},     # order[\"items\"]: a list\n",
    "           {'product': 'pen sets', 'quantity': 2}],     # each item: a dictionary\n",
    " 'city': 'Busan'}                                        # order[\"city\"]\n",
    "```\n",
    "\n",
    "Read it from the outside in: `order[\"items\"]` is the list, `order[\"items\"][0]` is the first item, and `order[\"items\"][0][\"quantity\"]` is its number, 3. The `for` loop reads each item in turn."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c24",
   "metadata": {},
   "source": [
    "### 3.2 ✍️ Another order\n",
    "\n",
    "*Do:* the prompt and the call lines are given; turn the answer into a dictionary with `json.loads`, and add each item's quantity inside the loop. Expected: `Seoul`, 5."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c25",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ✍️ TYPE · exercise: write the code between the FILL IN lines yourself\n",
    "customer_message = \"Please send 1 desk lamp and 4 mugs to Seoul.\"\n",
    "prompt = f\"\"\"Extract the order from the customer message.\n",
    "Return JSON with keys \"items\" (a list of objects with keys \"product\" and \"quantity\", the quantity as a number) and \"city\".\n",
    "\n",
    "Customer message: {customer_message}\"\"\"\n",
    "messages = [{\"role\": \"user\", \"content\": prompt}]\n",
    "response = client.chat.completions.create(model=MODEL, messages=messages,\n",
    "                                          response_format={\"type\": \"json_object\"})\n",
    "reply = response.choices[0].message.model_dump(exclude_none=True)\n",
    "messages.append(reply)\n",
    "### FILL IN (START) ###\n",
    "order = {\"items\": [], \"city\": \"\"}        # turn reply[\"content\"] into a dictionary\n",
    "### FILL IN (END) ###\n",
    "total_quantity = 0\n",
    "for item in order[\"items\"]:\n",
    "    ### FILL IN (START) ###\n",
    "    pass                                 # add this item's quantity to total_quantity\n",
    "    ### FILL IN (END) ###"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c26",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · check: just run\n",
    "print(order)\n",
    "done[\"3.2\"] = order[\"city\"] == \"Seoul\" and total_quantity == 5\n",
    "print(done[\"3.2\"], total_quantity)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c27",
   "metadata": {},
   "source": [
    "## 4. A Tool Call: the Reply's Keys Decide\n",
    "\n",
    "A **tool** is a Python function the model may ask your program to run. You describe it in a **tool schema** and pass the schemas with `tools=TOOLS`. The model runs nothing; its reply is then one of two kinds, and the keys of `reply` tell you which:\n",
    "\n",
    "| The reply is | Its key | What your program does |\n",
    "|---|---|---|\n",
    "| a text answer | `\"content\"` | read `reply[\"content\"]` |\n",
    "| requests to run functions | `\"tool_calls\"` | run the tools: run each one, add each result as a **tool** message, call the model again |\n",
    "\n",
    "After the call lines, check the key: for requests, run the tools; for a text answer, read it. You will use this code unchanged from here to the end:\n",
    "\n",
    "```python\n",
    "if \"tool_calls\" in reply:                                   # requests: run the tools\n",
    "    for request in reply[\"tool_calls\"]:\n",
    "        name = request[\"function\"][\"name\"]                     # which function\n",
    "        args = json.loads(request[\"function\"][\"arguments\"])    # its arguments: JSON text -> dictionary\n",
    "        result = FUNCTIONS[name](**args)                    # run it\n",
    "        messages.append({\"role\": \"tool\", \"tool_call_id\": request[\"id\"], \"content\": json.dumps(result)})   # TOOL message\n",
    "else:                                                       # a text answer\n",
    "    answer = reply[\"content\"]\n",
    "```\n",
    "\n",
    "![p5_check](data:image/png;base64,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ddVVV61bt+6zzz6rq6urrKysrq6O5zh0deWVV65du/ann37q9tKJU+fSSy+95pprNm/e/OSTT06aNOnAgQM7duwYMmTInDlzui6+4YYbNm7cuGLFimnTphUUFEyePHncuHFRXzQqrae/7r6Sl5c3efLk7du3v/rqq2PHjh0wYMDYsWPj7Xh6bUX2veqpUdmrra395ptvzj333MWLF/+3M+21kye/oFe1tbX19fW5mhoLAHCWE3AQhvnz51dVVX388ccbNmxIJpOJRGLGjBkzZ86Mjw4cOHDevHnV1dXff/99a2trIpG49dZb586dG8+VOPHR2NixY5csWbJq1arPP/+8tLR0+vTpCxYsuOuuu9IL8vLylixZ8s4772zduvXnn3++/PLLZ8+e/fTTT6e3zzzJIrPRa5Gxm2++Ob6UoK2t7dJLL120aFF5eXn2C058Fr3Kz89ftmzZu+++u23btt27d0+ZMmXOnDnPPPNM15UTJkwYOnTo5s2bu52ykTmmtM89+uijw4cP//rrrz/55JPS0tKZM2fOmzev271LJ0yY8MADD6xZs2bNmjWpVKqwsDD9uv0kG9WfFi9eXFBQsGPHjk2bNkVRtHDhwjjgiLJoRZa9OkGjshRfC9N1KOxpJb6j6gRPzs2bN0f/XOADAEA/y+vpBnhOK/v379+9e3dVVVVAGzSc8X766adly5Y9+OCDJzkFsw/t3LlzxYoV99577+zZs//bgn720UcfrVy58vXXX8/cVjZ25MiRhQsXXnfddY8++mhOaqOfvfjiiz/88MNTTz01ffr0XNfSo02bNr366qtPPPHE1Vdf3fVoKpV65JFHysvLly1b1v+1QU/q6+t/++23cePG9fPlcgDQ/8zggGwdt23Kxo0boyi67LLLclTOmeCmm2664IILPvjgg66HzjnnnEQisWPHjurq6sOHD6dnQHBGSqVSu3fvrqioiIfdnIYaGxv37t376aefRlFUWVnZ7Zrvvvvu4MGD8+bN69/SAAD4P7eoQLZefvnl9vb28ePHl5WV7dq16/vvv581a1bXSw/IXkFBwWOPPbZ79+5kMhlv9pFp0aJFr7/+ejzxccWKFZMnT85FjfSHffv2tbS0LF68+JTemnQy7r///mQymZeXd8stt/T0NngymXzooYdGjhzZz7UBABATcEC2pk6d+tVXX61fv769vb28vPzuu+++7bbbcl1U8CZMmDBhwoRuD1111VVXXHFFTU1Nc3NzVVVVPxdGf6qsrPzwww9zXcWJLF26tLi4+OKLLx48eHBPa6655pr+LAkAgOOYwREGMzgAgP/ADA4Azh5mcAAAAADBE3AAAAAAwRNwAAAAAMETcAAAAADBE3AAAAAAwRNwAAAAAMETcAAAAADBE3AAAAAAwRNwAAAAAMETcAAAAADBE3AAAAAAwRNwAAAAAMETcAAAAADBE3AAAAAAwRNwAAAAAMETcAAAAADBE3CEoaCgIIqizs7OXBcCAIQkmUxGUZSf71c+AM58ftqFobi4OIqiY8eO5boQACAkHR0d0T/vlADAmU3AEYY44Ghtbc11IQBASOJ3R0pKSnJdCACccgKOMBQVFZWVlR05ciR+HwYAIBt///33gAEDSktLc10IAJxyAo5glJeXp1KphoaGXBcCAIShubm5vb09kUiYwQHA2cBPu2AMHTo0Ly/vwIEDqVQq17UAAAGI3xcZMmRIrgsBgP4g4AhGaWnpsGHD2tra6urqcl0LAHC6a29vr6urKywsvPDCC3NdCwD0BwFHSEaOHJmfn//nn3/aTgUAOLGamprOzs7KysoBAwbkuhYA6A8CjpAUFRWNGjWqo6Njz5498bb2AABdNTQ0HDp0qKSk5OKLL851LQDQTwQcgamoqCgvL29padm7d69hHABAV/HvCfn5+ZMmTTJeFICzR0GuC+BfGz9+/NGjR//666/Ozs4xY8b4xQUASDty5MiePXs6OzsnTpx4zjnn5LocAOg/ea4CCFFHR8fOnTsbGxvLysqqqqrKyspyXREAkGOpVKq2tvaPP/6IomjMmDEjRozIdUUA0K8EHKFKJpO7du2qra3Ny8sbOnTo8OHDjRADgLNWY2NjTU3N0aNHBw4cOHHixEQikeuKAKC/CTjCVl9fv2fPnra2tgEDBpx//vnnn39+WVlZYWFhrusCAE65zs7OlpaWxsbGhoaGeIe18vLyUaNGlZSU5Lo0AMgBAUfwOjs7f//99z///LO9vT3+TH5+fkFBQV5eXm4LAwBOkVQq1dHRkd5SLT8/P5FIVFZWGroBwNlMwHGGSKVSjY2Nf/31V1NT07Fjx2wiCwBntry8vKKiotLS0kQikUgk3KkKAAIOAAAAIHh2GAUAAACCJ+AAAAAAgifgAAAAAIIn4AAAAACCJ+AAAAAAgifgAAAAAIIn4AAAAACCJ+AAAAAAgifgAAAAAIIn4AAAAACCJ+AAAAAAgifgAAAAAIIn4AAAAACCJ+AAAAAAgifgAAAAAIIn4AAAAACCJ+AAAAAAgifgAAAAAIIn4AAAAACCJ+AAAAAAgifgAAAAAIIn4AAAAACCJ+AAAAAAgifgAAAAAIIn4AAAAACCJ+AAAAAAgifgAAAAAIIn4AAAAACCJ+AAAAAAgifgAAAAAIIn4AAAAACCJ+AAAAAAgifgAAAAAIIn4AAAAACCJ+AAAAAAgifgAAAAAIIn4AAAAACCJ+AAAAAAgifgAAAAAIIn4AAAAACCJ+AAAAAAgifgAAAAAIIn4AAAAACCJ+AAAAAAgifgAAAAAIIn4AAAAACCJ+AAAAAAgifgAAAAAIIn4AAAAACCJ+AAAAAAgifgAAAAAIIn4AAAAACCJ+AAAAAAgifgAAAAAIIn4AAAAACCJ+AAAAAAgifgAAAAAIIn4AAAAACC9z/2pXL7yqdHJgAAAABJRU5ErkJggg==)\n",
    "\n",
    "- `FUNCTIONS` maps each name to its Python function. `**args` passes a dictionary as keyword arguments: `get_weather(**{\"city\": \"Seoul\"})` is `get_weather(city=\"Seoul\")`.\n",
    "- `tool_call_id` links a result to its request. The API has two rules for this link. A tool message needs its request in the list before it, so the reply with the request is kept first; the call lines always do this. And each request needs its tool message before the next call; otherwise the API returns an error.\n",
    "\n",
    "### 4.1 The function\n",
    "\n",
    "`get_weather(city)` returns a city's current temperature from Open-Meteo, a free weather service (no key).\n",
    "\n",
    "*Do:* run the cell."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c28",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "import requests\n",
    "\n",
    "def get_weather(city: str):\n",
    "    \"\"\"Get the current temperature of a city in Celsius.\n",
    "\n",
    "    Args:\n",
    "        city: City name in English, for example \"Seoul\".\n",
    "    \"\"\"\n",
    "    try:                                                    # on a network or lookup error, return the error as text\n",
    "        place = requests.get(\"https://geocoding-api.open-meteo.com/v1/search\",\n",
    "                             params={\"name\": city, \"count\": 1}, timeout=10).json()[\"results\"][0]   # first match\n",
    "        weather = requests.get(\"https://api.open-meteo.com/v1/forecast\",\n",
    "                               params={\"latitude\": place[\"latitude\"], \"longitude\": place[\"longitude\"],\n",
    "                                       \"current\": \"temperature_2m\"}, timeout=10).json()\n",
    "        return {\"city\": place[\"name\"], \"temperature_c\": weather[\"current\"][\"temperature_2m\"]}\n",
    "    except Exception as error:\n",
    "        return \"error: \" + str(error)\n",
    "\n",
    "get_weather(\"Seoul\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c29",
   "metadata": {},
   "source": [
    "### 4.2 The tool schema\n",
    "\n",
    "The model cannot read Python code; it reads a schema, a dictionary with this shape:\n",
    "\n",
    "```python\n",
    "{\"type\": \"function\",\n",
    " \"function\": {\"name\": \"get_weather\",                                   # the function's name\n",
    "              \"description\": \"Get the current temperature of ...\",     # the docstring's first line\n",
    "              \"parameters\": {\"type\": \"object\",\n",
    "                             \"properties\": {\"city\": {\"type\": \"string\",               # from  city: str\n",
    "                                                     \"description\": \"City name ...\"}},  # from the Args: line\n",
    "                             \"required\": [\"city\"]}}}\n",
    "```\n",
    "\n",
    "Everything in it comes from the function, so `tool_from_function` builds it for any function written in this docstring format.\n",
    "\n",
    "*Do:* run the two cells (the first only defines the helper) and match each entry with the function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c30",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · setup: just run\n",
    "import inspect\n",
    "\n",
    "PYTHON_TO_JSON = {str: \"string\", int: \"integer\", float: \"number\", bool: \"boolean\"}\n",
    "\n",
    "def tool_from_function(function):\n",
    "    \"\"\"Build a tool schema from a function's name, docstring, and type annotations.\"\"\"\n",
    "    doc = inspect.getdoc(function)                        # the docstring, indentation removed\n",
    "    arg_help = {}\n",
    "    for line in doc.split(\"\\n\"):                          # \"name: description\" lines under Args:\n",
    "        line = line.strip()\n",
    "        if \":\" in line and not line.endswith(\":\"):\n",
    "            name, text = line.split(\":\", 1)\n",
    "            arg_help[name.strip()] = text.strip()\n",
    "    properties = {}\n",
    "    for name, parameter in inspect.signature(function).parameters.items():   # each parameter and its annotation\n",
    "        properties[name] = {\"type\": PYTHON_TO_JSON[parameter.annotation], \"description\": arg_help[name]}\n",
    "    return {\n",
    "        \"type\": \"function\",\n",
    "        \"function\": {\n",
    "            \"name\": function.__name__,                    # the function's own name\n",
    "            \"description\": doc.split(\"\\n\")[0],            # the docstring's first line\n",
    "            \"parameters\": {\"type\": \"object\", \"properties\": properties, \"required\": list(properties)},\n",
    "        },\n",
    "    }"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c31",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "TOOLS = [tool_from_function(get_weather)]          # TOOL SCHEMAS, sent with tools=TOOLS\n",
    "FUNCTIONS = {\"get_weather\": get_weather}           # name -> Python function\n",
    "print(json.dumps(TOOLS[0], indent=2))              # indent=2 prints the dictionary on several lines"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c32",
   "metadata": {},
   "source": [
    "### 4.3 Call, check, call, check\n",
    "\n",
    "Five cells: the list, then call, check, call, check. The two call cells are the same code, and so are the two check cells. The first reply has `\"tool_calls\"`, so the first check runs the tools; the second reply has `\"content\"`, so the second check reads the answer.\n",
    "\n",
    "*Do:* run the cells in order. Look at the keys in each printed `reply`, and watch the list grow 2 → 3 → 4 → 5."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c33",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "## Unit 1 - the list\n",
    "WEATHER_SYSTEM = \"You answer questions about the weather. Use the tools for current values; never guess them.\"\n",
    "QUESTION = \"What is the temperature in Seoul right now?\"\n",
    "\n",
    "messages = [\n",
    "    {\"role\": \"system\", \"content\": WEATHER_SYSTEM},   # SYSTEM message\n",
    "    {\"role\": \"user\", \"content\": QUESTION},           # USER message\n",
    "]\n",
    "answer = None\n",
    "show_messages(messages)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c34",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "## Unit 2 - call the model\n",
    "response = client.chat.completions.create(model=MODEL, messages=messages, tools=TOOLS)\n",
    "reply = response.choices[0].message.model_dump(exclude_none=True)\n",
    "messages.append(reply)                               # ASSISTANT message\n",
    "print(reply)                                         # which key does it have?\n",
    "show_messages(messages)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c35",
   "metadata": {},
   "source": [
    "**Reading the output.** This `reply` has no `\"content\"` key. It has `\"tool_calls\"` instead, so it is a request:\n",
    "\n",
    "```python\n",
    "{'role': 'assistant',\n",
    " 'annotations': [],\n",
    " 'tool_calls': [                                         # a list: one reply may hold several requests\n",
    "     {'id': 'call_SOdeABsx...',                          # the request's id; its result must carry it\n",
    "      'function': {'arguments': '{\"city\":\"Seoul\"}',      # the arguments, as JSON text\n",
    "                   'name': 'get_weather'},               # which function to run\n",
    "      'type': 'function'}]}\n",
    "```\n",
    "\n",
    "Your id and numbers will differ from run to run; the keys are always the same. `request[\"function\"]` is not the Python function: it is a dictionary with the function's name and its arguments as text. The tool-running lines read exactly these parts: `request[\"function\"][\"name\"]`, `json.loads(request[\"function\"][\"arguments\"])`, and `request[\"id\"]`. `show_messages` prints a request as its `function` part: `{'arguments': '{\"city\":\"Seoul\"}', 'name': 'get_weather'}`. Nothing has run yet: the temperature is nowhere in the list."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c36",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "## Unit 3 - check the key, run the tools\n",
    "if \"tool_calls\" in reply:\n",
    "    for request in reply[\"tool_calls\"]:\n",
    "        name = request[\"function\"][\"name\"]\n",
    "        args = json.loads(request[\"function\"][\"arguments\"])\n",
    "        result = FUNCTIONS[name](**args)\n",
    "        messages.append({\"role\": \"tool\", \"tool_call_id\": request[\"id\"], \"content\": json.dumps(result)})   # TOOL message\n",
    "else:\n",
    "    answer = reply[\"content\"]\n",
    "print(\"answer:\", answer)\n",
    "show_messages(messages)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c37",
   "metadata": {},
   "source": [
    "**Reading the output.** The check took the `\"tool_calls\"` branch: it ran `get_weather(city=\"Seoul\")` and added one tool message. `answer` is still `None`, because no text answer has arrived yet. The new message:\n",
    "\n",
    "```python\n",
    "{'role': 'tool',\n",
    " 'tool_call_id': 'call_SOdeABsx...',                     # the same id as the request in [2]\n",
    " 'content': '{\"city\": \"Seoul\", \"temperature_c\": 19.7}'}  # the result as JSON text, made by json.dumps\n",
    "```\n",
    "\n",
    "The id pairs this result with its request. A message's content is text, so `json.dumps` turns the result into JSON text; `show_messages` prints that text as it is."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c38",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "## Unit 4 - call the model (the same code as unit 2)\n",
    "response = client.chat.completions.create(model=MODEL, messages=messages, tools=TOOLS)\n",
    "reply = response.choices[0].message.model_dump(exclude_none=True)\n",
    "messages.append(reply)                               # ASSISTANT message\n",
    "print(reply)                                         # which key does it have?\n",
    "show_messages(messages)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c39",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "## Unit 5 - check the key, run the tools (the same code as unit 3)\n",
    "if \"tool_calls\" in reply:\n",
    "    for request in reply[\"tool_calls\"]:\n",
    "        name = request[\"function\"][\"name\"]\n",
    "        args = json.loads(request[\"function\"][\"arguments\"])\n",
    "        result = FUNCTIONS[name](**args)\n",
    "        messages.append({\"role\": \"tool\", \"tool_call_id\": request[\"id\"], \"content\": json.dumps(result)})   # TOOL message\n",
    "else:\n",
    "    answer = reply[\"content\"]\n",
    "print(\"answer:\", answer)\n",
    "show_messages(messages)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c40",
   "metadata": {},
   "source": [
    "**Reading the output.** The second `reply` had `\"content\"`, so the check took the `else` branch and set `answer`. The list now shows the whole round trip:\n",
    "\n",
    "| Position | Role | Written by | Holds |\n",
    "|---|---|---|---|\n",
    "| `[0]` | system | you | the standing instruction |\n",
    "| `[1]` | user | you | the question |\n",
    "| `[2]` | assistant | the model, kept as it arrived | the request: `get_weather` with `{\"city\": \"Seoul\"}` |\n",
    "| `[3]` | tool | your program | the result, linked to `[2]` by its id |\n",
    "| `[4]` | assistant | the model, kept as it arrived | the answer, written from `[3]` |\n",
    "\n",
    "The model never ran anything. It asked in `[2]`; your code ran the function and wrote `[3]`; the model read `[3]` in the next call."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c41",
   "metadata": {},
   "source": [
    "### 4.4 ✍️ The same cells for Tokyo\n",
    "\n",
    "*Do:* the cells are given except the line that keeps the reply in each call cell, and the two lines that run the function and add its result in each check cell. Each cell prints the list. Afterwards, try a question that needs no tool (\"Say hello\"): the first reply already has `\"content\"`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c42",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "## Unit 1 - the list\n",
    "QUESTION = \"What is the temperature in Tokyo right now?\"\n",
    "messages = [\n",
    "    {\"role\": \"system\", \"content\": WEATHER_SYSTEM},\n",
    "    {\"role\": \"user\", \"content\": QUESTION},\n",
    "]\n",
    "answer = None\n",
    "show_messages(messages)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c43",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ✍️ TYPE · exercise: write the code between the FILL IN lines yourself\n",
    "## Unit 2 - call the model\n",
    "response = client.chat.completions.create(model=MODEL, messages=messages, tools=TOOLS)\n",
    "reply = response.choices[0].message.model_dump(exclude_none=True)\n",
    "### FILL IN (START) ###\n",
    "# keep the reply in the list\n",
    "### FILL IN (END) ###"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c44",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · check: just run\n",
    "show_messages(messages)                  # expected: 3 messages, the last one a request"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c45",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ✍️ TYPE · exercise: write the code between the FILL IN lines yourself\n",
    "## Unit 3 - check the key, run the tools\n",
    "if \"tool_calls\" in reply:\n",
    "    for request in reply[\"tool_calls\"]:\n",
    "        name = request[\"function\"][\"name\"]\n",
    "        args = json.loads(request[\"function\"][\"arguments\"])\n",
    "        ### FILL IN (START) ###\n",
    "        pass    # run the function, then add its result as a tool message\n",
    "        ### FILL IN (END) ###\n",
    "else:\n",
    "    answer = reply[\"content\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c46",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · check: just run\n",
    "show_messages(messages)                  # expected: 4 messages, the last one a result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c47",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ✍️ TYPE · exercise: write the code between the FILL IN lines yourself\n",
    "## Unit 4 - call the model\n",
    "response = client.chat.completions.create(model=MODEL, messages=messages, tools=TOOLS)\n",
    "reply = response.choices[0].message.model_dump(exclude_none=True)\n",
    "### FILL IN (START) ###\n",
    "# keep the reply in the list\n",
    "### FILL IN (END) ###"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c48",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · check: just run\n",
    "show_messages(messages)                  # expected: 5 messages, the last one the answer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c49",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ✍️ TYPE · exercise: write the code between the FILL IN lines yourself\n",
    "## Unit 5 - check the key, run the tools\n",
    "if \"tool_calls\" in reply:\n",
    "    for request in reply[\"tool_calls\"]:\n",
    "        name = request[\"function\"][\"name\"]\n",
    "        args = json.loads(request[\"function\"][\"arguments\"])\n",
    "        ### FILL IN (START) ###\n",
    "        pass    # run the function, then add its result as a tool message\n",
    "        ### FILL IN (END) ###\n",
    "else:\n",
    "    answer = reply[\"content\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c50",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · check: just run\n",
    "print(\"answer:\", answer)\n",
    "roles = []\n",
    "for m in messages:\n",
    "    roles.append(m[\"role\"])\n",
    "found = False\n",
    "if answer is not None and isinstance(result, dict) and result[\"city\"] == \"Tokyo\":\n",
    "    value = result[\"temperature_c\"]\n",
    "    if str(value) in answer:\n",
    "        found = True\n",
    "    if value == round(value) and str(round(value)) in answer:   # 21.0 may be written as 21\n",
    "        found = True\n",
    "done[\"4.4\"] = roles == [\"system\", \"user\", \"assistant\", \"tool\", \"assistant\"] and found\n",
    "done[\"4.4\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c51",
   "metadata": {},
   "source": [
    "## 5. The Agent Loop\n",
    "\n",
    "Part 4 was call, check, call, check. Put the two in a loop and stop when the check finds a text answer: that is the **agent loop**. The model picks the next action from everything in the list, the program runs it, and the result joins the next call. Write the loop once, as a function, and call it for every question:\n",
    "\n",
    "```python\n",
    "def run_loop(messages, tools, functions, max_steps=6):\n",
    "    for step in range(max_steps):                    # a limit, so the loop always ends\n",
    "        response = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)\n",
    "        reply = response.choices[0].message.model_dump(exclude_none=True)\n",
    "        messages.append(reply)\n",
    "        if \"tool_calls\" in reply:\n",
    "            for request in reply[\"tool_calls\"]:\n",
    "                name = request[\"function\"][\"name\"]\n",
    "                args = json.loads(request[\"function\"][\"arguments\"])\n",
    "                result = functions[name](**args)\n",
    "                messages.append({\"role\": \"tool\", \"tool_call_id\": request[\"id\"], \"content\": json.dumps(result)})\n",
    "        else:\n",
    "            return reply[\"content\"]                  # a text answer: stop\n",
    "    return None                                      # the step limit ended the loop\n",
    "```\n",
    "\n",
    "The body is Part 4's call lines and check lines. The new parts are the `for`, the `return` of the answer, and the arguments: the list, the tool schemas, and the name → function dictionary.\n",
    "\n",
    "### 5.1 A calculator tool\n",
    "\n",
    "One tool, `calculate(expression)`: the model writes the whole arithmetic expression, and `eval` runs it as Python, for example `eval(\"58 * 94 + 37 * 21\")` returns `6229`. `eval` runs whatever Python text it receives, so the second argument, `{\"__builtins__\": {}}`, removes Python's built-in functions (such as `open`) and leaves only arithmetic. That is enough for this practice but not a real safeguard; Ch. 14 returns to running model-written code. A bad expression returns the error as text, as `get_weather` does.\n",
    "\n",
    "*Do:* run the cell; it prints two results."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c52",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "def calculate(expression: str):\n",
    "    \"\"\"Evaluate an arithmetic expression and return the result.\n",
    "\n",
    "    Args:\n",
    "        expression: A Python arithmetic expression, for example \"58 * 94 + 37 * 21\".\n",
    "    \"\"\"\n",
    "    try:\n",
    "        return eval(expression, {\"__builtins__\": {}})     # run the text as Python, with no built-in functions\n",
    "    except Exception as error:\n",
    "        return \"error: \" + str(error)\n",
    "\n",
    "CALC_SYSTEM = \"You are a careful calculator. Use the calculate tool for every calculation; never compute in your head.\"\n",
    "TOOLS = [tool_from_function(calculate)]\n",
    "FUNCTIONS = {\"calculate\": calculate}\n",
    "print(calculate(\"58 * 94 + 37 * 21\"))\n",
    "print(calculate(\"open('file.txt')\"))                       # blocked: no built-in functions"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c53",
   "metadata": {},
   "source": [
    "### 5.2 The loop as a function\n",
    "\n",
    "*Do:* run the cell. It defines `run_loop` and runs it once. The list shows the request with the expression the model wrote, its result, and the final answer."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c54",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "def run_loop(messages, tools, functions, max_steps=6):\n",
    "    \"\"\"Call the model and run the requested tools until a text answer; return the answer.\"\"\"\n",
    "    for step in range(max_steps):                    # a limit, so the loop always ends\n",
    "        response = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)\n",
    "        reply = response.choices[0].message.model_dump(exclude_none=True)\n",
    "        messages.append(reply)                       # ASSISTANT message\n",
    "        if \"tool_calls\" in reply:                    # requests: run the tools\n",
    "            for request in reply[\"tool_calls\"]:\n",
    "                name = request[\"function\"][\"name\"]\n",
    "                args = json.loads(request[\"function\"][\"arguments\"])\n",
    "                result = functions[name](**args)\n",
    "                messages.append({\"role\": \"tool\", \"tool_call_id\": request[\"id\"], \"content\": json.dumps(result)})   # TOOL message\n",
    "        else:                                        # a text answer: stop\n",
    "            return reply[\"content\"]\n",
    "    return None                                      # the step limit ended the loop\n",
    "\n",
    "QUESTION = \"What is (4817 × 293) + 1569?\"\n",
    "messages = [{\"role\": \"system\", \"content\": CALC_SYSTEM}, {\"role\": \"user\", \"content\": QUESTION}]\n",
    "answer = run_loop(messages, TOOLS, FUNCTIONS)\n",
    "show_messages(messages)\n",
    "print(\"answer:\", answer)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c55",
   "metadata": {},
   "source": [
    "**Reading the output.** Each pass of the loop adds one reply, and then one tool message for each request in it. In a typical run:\n",
    "\n",
    "| Step | Added to the list | Branch taken |\n",
    "|---|---|---|\n",
    "| 0 | `[2]` request `calculate` with `{\"expression\": \"(4817 * 293) + 1569\"}`, `[3]` its result | `\"tool_calls\"`: run, add the result |\n",
    "| 1 | `[4]` the text answer, written from `[3]` | `else`: return the answer |\n",
    "\n",
    "The model turned `×` into `*` and wrote the whole expression in one request; `eval` computed it. `run_loop` adds to the list you pass, so `messages` shows every step after the call. With more steps (5.3 and Part 6) the loop simply runs more passes. If one reply holds several requests, the inner `for` adds one tool message for each in the same step."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c56",
   "metadata": {},
   "source": [
    "### 5.3 ✍️ Weather and calculator together\n",
    "\n",
    "Registering a tool is one item in `TOOLS` and one entry in `FUNCTIONS`. With the weather tool and `calculate` together, the model can answer a question that needs a lookup and then arithmetic. `run_loop` does not change.\n",
    "\n",
    "*Do:* complete the registration: `TOOLS` needs the schema for `calculate` too, and `FUNCTIONS` its name. Expected: two requests in two steps, `get_weather` and then `calculate`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c57",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ✍️ TYPE · exercise: write the code between the FILL IN lines yourself\n",
    "MIXED_SYSTEM = \"Use get_weather for current temperatures and calculate for every calculation; never compute in your head.\"\n",
    "QUESTION = \"What is the current temperature in Seoul in Fahrenheit? Use F = C × 1.8 + 32.\"\n",
    "### FILL IN (START) ###\n",
    "TOOLS = [tool_from_function(get_weather)]            # add the schema for calculate\n",
    "FUNCTIONS = {\"get_weather\": get_weather}             # add its name and function\n",
    "### FILL IN (END) ###\n",
    "messages = [{\"role\": \"system\", \"content\": MIXED_SYSTEM}, {\"role\": \"user\", \"content\": QUESTION}]\n",
    "answer = run_loop(messages, TOOLS, FUNCTIONS)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c58",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · check: just run\n",
    "show_messages(messages)\n",
    "requested = []\n",
    "for m in messages:\n",
    "    if \"tool_calls\" in m:                            # replies that hold requests\n",
    "        for request in m[\"tool_calls\"]:\n",
    "            requested.append(request[\"function\"][\"name\"])\n",
    "done[\"5.3\"] = \"get_weather\" in requested and \"calculate\" in requested and answer is not None\n",
    "done[\"5.3\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c59",
   "metadata": {},
   "source": [
    "## 6. ReAct: a Thought before Each Action\n",
    "\n",
    "ReAct has the model write a **Thought** before each **Action**: what the results so far show, what is still missing, and which tool to use next. Then the model acts, and the tool's result is the **Observation**. The next Thought reads that Observation.\n",
    "\n",
    "In practice, the thought is one more tool: `think(thought)`. It runs nothing; it only puts the thought into the list. The system message tells the model to call `think` before each action. So the order in the list is Thought, Action, Observation, and the model reads its thought when it chooses the action. The loop is Part 5's `run_loop`, unchanged. This \"think\" tool is a documented practice for tool-using agents (Anthropic, 2025).\n",
    "\n",
    "### 6.1 The tools\n",
    "\n",
    "*Do:* run the two cells. The first defines a plain Wikipedia search (no key). The second defines `think` and registers the three tools."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c60",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "## Unit 1 - a plain Wikipedia search\n",
    "import html\n",
    "\n",
    "def wikipedia_search(query: str):\n",
    "    \"\"\"Search Wikipedia and return the top three results: title and a short snippet.\n",
    "\n",
    "    Args:\n",
    "        query: Search words, for example \"Gyeongbokgung Palace\".\n",
    "    \"\"\"\n",
    "    try:\n",
    "        data = requests.get(\"https://en.wikipedia.org/w/api.php\",\n",
    "                            params={\"action\": \"query\", \"list\": \"search\", \"srsearch\": query,\n",
    "                                    \"srlimit\": 3, \"format\": \"json\"},\n",
    "                            headers={\"User-Agent\": \"STML-course-practice/1.0\"}, timeout=10).json()\n",
    "        lines = []\n",
    "        for item in data[\"query\"][\"search\"]:\n",
    "            snippet = item[\"snippet\"].replace('<span class=\"searchmatch\">', \"\").replace(\"</span>\", \"\")   # drop highlight tags\n",
    "            lines.append(item[\"title\"] + \" | \" + html.unescape(snippet))                               # &#039; -> '\n",
    "        return \"\\n\".join(lines)\n",
    "    except Exception as error:                     # a failed search is returned as text, not raised\n",
    "        return \"error: \" + str(error)\n",
    "\n",
    "print(wikipedia_search(\"Gyeongbokgung Palace\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c61",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "## Unit 2 - the think tool, and the three tools\n",
    "def think(thought: str):\n",
    "    \"\"\"Write down your reasoning before an action: what the results so far show, what is missing, and what you will do next.\n",
    "\n",
    "    Args:\n",
    "        thought: Your reasoning.\n",
    "    \"\"\"\n",
    "    print(\"Thought:\", thought)\n",
    "    return \"ok\"                                    # nothing runs: the thought is now in the list\n",
    "\n",
    "TOOLS = [tool_from_function(think), tool_from_function(wikipedia_search), tool_from_function(get_weather)]\n",
    "FUNCTIONS = {\"think\": think, \"wikipedia_search\": wikipedia_search, \"get_weather\": get_weather}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c62",
   "metadata": {},
   "source": [
    "### 6.2 The same `run_loop`, with a thought before each action\n",
    "\n",
    "*Do:* run the cell. Each Thought is printed when the model calls `think`. Then read the list and find each Thought, the Action after it, and that Action's result."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c63",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "TRAVEL_SYSTEM = \"\"\"You help travellers with questions about places. Before each action, call think to plan your next step.\"\"\"\n",
    "QUESTION = \"I am visiting Gyeongbokgung Palace this afternoon. What is the temperature there right now?\"\n",
    "\n",
    "messages = [{\"role\": \"system\", \"content\": TRAVEL_SYSTEM}, {\"role\": \"user\", \"content\": QUESTION}]\n",
    "answer = run_loop(messages, TOOLS, FUNCTIONS)\n",
    "show_messages(messages)\n",
    "print(\"answer:\", answer)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c64",
   "metadata": {},
   "source": [
    "**Reading the output.** In the list, each part of ReAct has its own place:\n",
    "\n",
    "| ReAct | Where it is in the list |\n",
    "|---|---|\n",
    "| Thought | a `think` request with the thought as its argument, and its tool message `ok` |\n",
    "| Action | the next request, for example `wikipedia_search` or `get_weather` |\n",
    "| Observation | the tool message after that request |\n",
    "| Answer | the last assistant message |\n",
    "\n",
    "Check one step: does the Thought before an Action use the Observation before it? If the model already knows a fact, it can skip a tool; the Thought shows why. The thought is already in the list when the model chooses the action, so the action can follow from it. Each thought costs one more model call."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c65",
   "metadata": {},
   "source": [
    "### 6.3 ✍️ Read one step\n",
    "\n",
    "*Do:* choose one Thought and the Action after it. In `reading`, write which fact from the previous Observation the Thought used, and whether the Action follows from the Thought. (Not checked.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c66",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ✍️ WRITE · your answer in words (not checked)\n",
    "reading = \"\"\"\n",
    "\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c67",
   "metadata": {},
   "source": [
    "## 7. The Agent as a Class\n",
    "\n",
    "A loop written in a cell starts a new `messages` list each time, so a follow-up (\"And in Busan?\") has nothing to refer to. A **class** keeps the list inside an object and gives names to the code you already wrote. These named pieces are **methods**, functions that belong to the object:\n",
    "\n",
    "| Method | What it does | The code from |\n",
    "|---|---|---|\n",
    "| `call_model()` | calls the model with the list, keeps the reply, returns it | Part 1: the three call lines |\n",
    "| `run_tools(reply)` | runs each request in the reply and adds each result | Part 4: the tool-running lines |\n",
    "| `ask(question)` | adds the question, then loops: call the model, check the key, run the tools or return the answer | Part 5: `run_loop` |\n",
    "| `show()` | prints the object's list | `show_messages` |\n",
    "\n",
    "`self` is the object itself; `self.messages` is a value stored in it (an **attribute**) that stays between calls. `__init__` runs when you write `Agent(...)`: it receives the system message and `tool_functions`, the list of Python functions you give the agent (the default `()` is an empty tuple: no tools). `self.tools` and `self.functions` are Part 4's `TOOLS` and `FUNCTIONS`, kept inside the object: the schemas, and each name mapped to its function. An `Agent` made without functions has no tools, so every reply has `\"content\"`: it is a plain conversation.\n",
    "\n",
    "The class adds two safeguards that the cells did not need. If a request names an unknown function or gives wrong arguments, `run_tools` puts the error text in that request's tool message, so every request still gets its tool message. If the step limit ends the loop, `ask` prints a line and returns `None`.\n",
    "\n",
    "### 7.1 The class\n",
    "\n",
    "*Do:* run the cell. Find in each method the lines you wrote in Parts 1, 4, and 5."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c68",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "class Agent:\n",
    "    \"\"\"A model with its own message list and, optionally, tools.\"\"\"\n",
    "\n",
    "    def __init__(self, system, tool_functions=()):\n",
    "        self.messages = [{\"role\": \"system\", \"content\": system}]              # SYSTEM message, once\n",
    "        self.tools = []                                                      # TOOL SCHEMAS\n",
    "        self.functions = {}                                                  # name -> Python function\n",
    "        for function in tool_functions:                                      # () = no tools\n",
    "            self.tools.append(tool_from_function(function))\n",
    "            self.functions[function.__name__] = function\n",
    "\n",
    "    def call_model(self):\n",
    "        \"\"\"Call the model with the list; keep the reply and return it.\"\"\"\n",
    "        if len(self.tools) > 0:\n",
    "            response = client.chat.completions.create(model=MODEL, messages=self.messages, tools=self.tools)\n",
    "        else:                                                                # no tools: the API rejects an empty list\n",
    "            response = client.chat.completions.create(model=MODEL, messages=self.messages)\n",
    "        reply = response.choices[0].message.model_dump(exclude_none=True)\n",
    "        self.messages.append(reply)                                          # ASSISTANT message\n",
    "        return reply\n",
    "\n",
    "    def run_tools(self, reply):\n",
    "        \"\"\"Run each request in the reply and add each result as a tool message.\"\"\"\n",
    "        for request in reply[\"tool_calls\"]:\n",
    "            name = request[\"function\"][\"name\"]\n",
    "            try:\n",
    "                args = json.loads(request[\"function\"][\"arguments\"])\n",
    "                result = self.functions[name](**args)\n",
    "            except Exception as error:                                       # unknown name or wrong arguments\n",
    "                result = \"error: \" + str(error)                              # the error becomes the result\n",
    "            self.messages.append({\"role\": \"tool\", \"tool_call_id\": request[\"id\"], \"content\": json.dumps(result)})   # TOOL message\n",
    "\n",
    "    def ask(self, question, max_steps=6):\n",
    "        \"\"\"Add the question, then loop until the model answers in text.\"\"\"\n",
    "        self.messages.append({\"role\": \"user\", \"content\": question})          # USER message\n",
    "        for step in range(max_steps):\n",
    "            reply = self.call_model()\n",
    "            if \"tool_calls\" in reply:                                        # requests: run the tools\n",
    "                self.run_tools(reply)\n",
    "            else:                                                            # a text answer: done\n",
    "                return reply[\"content\"]\n",
    "        print(\"Stopped: no text answer after\", max_steps, \"steps\")\n",
    "        return None                                                          # the step limit ended the loop\n",
    "\n",
    "    def show(self):\n",
    "        \"\"\"Print this object's messages.\"\"\"\n",
    "        show_messages(self.messages)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c69",
   "metadata": {},
   "source": [
    "### 7.2 One step at a time\n",
    "\n",
    "The methods can also be called one by one. These cells are the 4.3 cells, with the object doing the work: `call_model()` replaces the three call lines, and `run_tools(reply)` replaces the tool-running lines. The key check stays in the cell.\n",
    "\n",
    "*Do:* run the cells in order and compare each list with 4.3."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c70",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "## Unit 1 - create the agent and add the question\n",
    "weather_agent = Agent(WEATHER_SYSTEM, [get_weather])\n",
    "weather_agent.messages.append({\"role\": \"user\", \"content\": \"What is the temperature in Seoul right now?\"})   # USER message\n",
    "answer = None\n",
    "weather_agent.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c71",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "## Unit 2 - call the model\n",
    "reply = weather_agent.call_model()\n",
    "print(reply)                                         # which key does it have?\n",
    "weather_agent.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c72",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "## Unit 3 - check the key, run the tools\n",
    "if \"tool_calls\" in reply:\n",
    "    weather_agent.run_tools(reply)\n",
    "else:\n",
    "    answer = reply[\"content\"]\n",
    "print(\"answer:\", answer)\n",
    "weather_agent.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c73",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "## Unit 4 - call the model (the same code as unit 2)\n",
    "reply = weather_agent.call_model()\n",
    "print(reply)\n",
    "weather_agent.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c74",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "## Unit 5 - check the key, run the tools (the same code as unit 3)\n",
    "if \"tool_calls\" in reply:\n",
    "    weather_agent.run_tools(reply)\n",
    "else:\n",
    "    answer = reply[\"content\"]\n",
    "print(\"answer:\", answer)\n",
    "weather_agent.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c75",
   "metadata": {},
   "source": [
    "**Reading the output.** The same five messages as in 4.3: system, user, the request, the tool result, the answer. The code in each cell is shorter because the methods hold the lines; what happens is the same.\n",
    "\n",
    "### 7.3 `ask`: the whole loop in one method\n",
    "\n",
    "*Do:* run the two cells. The second question only makes sense after the first: its messages sit below the first question's, and the difference uses Seoul's temperature from there."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c76",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "## Unit 1 - create the agent and ask the first question\n",
    "agent = Agent(MIXED_SYSTEM, [get_weather, calculate])\n",
    "agent.ask(\"What is the temperature in Seoul right now?\")\n",
    "agent.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c77",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "## Unit 2 - a follow-up that needs the first answer\n",
    "agent.ask(\"And in Busan? How many degrees warmer or colder is Busan than Seoul?\")\n",
    "agent.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c78",
   "metadata": {},
   "source": [
    "**Reading the output.** The follow-up's messages start below the first question's. To compare Busan with Seoul, the model usually does not look Seoul up again: it uses the Seoul result that is still in `agent.messages`. A result can have a long tail of digits, for example `3.8000000000000007` for 22.0 − 18.2. This is ordinary floating-point rounding; the model rounds it in the answer.\n",
    "\n",
    "### 7.4 An agent without tools\n",
    "\n",
    "*Do:* run the cell. `Agent(STAFF_SYSTEM)` gets no functions, so `call_model` sends no tools and every reply has `\"content\"`. Compare the list with 2.1."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c79",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · example: read each line, then run\n",
    "staff_agent = Agent(STAFF_SYSTEM)\n",
    "staff_agent.ask(\"A customer ordered 2 mugs and 1 desk lamp. List the items in the order.\")\n",
    "staff_agent.ask(\"The lamp was cancelled. What is left in the order?\")\n",
    "staff_agent.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c80",
   "metadata": {},
   "source": [
    "**Reading the output.** The list alternates user and assistant messages, as in 2.1. With no tools, `ask` returned at the first pass of its loop each time.\n",
    "\n",
    "### 7.5 ✍️ Complete the class\n",
    "\n",
    "*Do:* `MyAgent` is the `Agent` class with three lines missing: in `call_model`, the line that keeps the reply; in `run_tools`, the line that adds a result; in `ask`, the line that runs the tools. The check converts two temperatures. Expected: 86 and 53.6."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c81",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ✍️ TYPE · exercise: write the code between the FILL IN lines yourself\n",
    "CONVERTER_SYSTEM = \"You convert Celsius to Fahrenheit with F = C × 1.8 + 32. Use the calculate tool for every calculation.\"\n",
    "class MyAgent:\n",
    "    def __init__(self, system, tool_functions=()):\n",
    "        self.messages = [{\"role\": \"system\", \"content\": system}]\n",
    "        self.tools = []\n",
    "        self.functions = {}\n",
    "        for function in tool_functions:\n",
    "            self.tools.append(tool_from_function(function))\n",
    "            self.functions[function.__name__] = function\n",
    "\n",
    "    def call_model(self):\n",
    "        if len(self.tools) > 0:\n",
    "            response = client.chat.completions.create(model=MODEL, messages=self.messages, tools=self.tools)\n",
    "        else:\n",
    "            response = client.chat.completions.create(model=MODEL, messages=self.messages)\n",
    "        reply = response.choices[0].message.model_dump(exclude_none=True)\n",
    "        ### FILL IN (START) ###\n",
    "        # keep the reply\n",
    "        ### FILL IN (END) ###\n",
    "        return reply\n",
    "\n",
    "    def run_tools(self, reply):\n",
    "        for request in reply[\"tool_calls\"]:\n",
    "            name = request[\"function\"][\"name\"]\n",
    "            try:\n",
    "                args = json.loads(request[\"function\"][\"arguments\"])\n",
    "                result = self.functions[name](**args)\n",
    "            except Exception as error:\n",
    "                result = \"error: \" + str(error)\n",
    "            ### FILL IN (START) ###\n",
    "            # add the result as a tool message\n",
    "            ### FILL IN (END) ###\n",
    "\n",
    "    def ask(self, question, max_steps=6):\n",
    "        self.messages.append({\"role\": \"user\", \"content\": question})\n",
    "        for step in range(max_steps):\n",
    "            reply = self.call_model()\n",
    "            if \"tool_calls\" in reply:\n",
    "                ### FILL IN (START) ###\n",
    "                pass    # run the tools\n",
    "                ### FILL IN (END) ###\n",
    "            else:\n",
    "                return reply[\"content\"]\n",
    "        print(\"Stopped: no text answer after\", max_steps, \"steps\")\n",
    "        return None\n",
    "\n",
    "    def show(self):\n",
    "        show_messages(self.messages)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c82",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · check: just run\n",
    "converter = MyAgent(CONVERTER_SYSTEM, [calculate])\n",
    "answer_30 = converter.ask(\"Convert 30 °C to Fahrenheit.\")\n",
    "answer_12 = converter.ask(\"And 12 °C?\")\n",
    "converter.show()\n",
    "roles = []\n",
    "for m in converter.messages:\n",
    "    roles.append(m[\"role\"])\n",
    "done[\"7.5\"] = \"86\" in str(answer_30) and \"53.6\" in str(answer_12) and \"tool\" in roles\n",
    "done[\"7.5\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c83",
   "metadata": {},
   "source": [
    "### 7.6 ✍️ Two agents working together\n",
    "\n",
    "An advisor answers, a reviewer comments, the advisor revises. The reviewer is an `Agent` without tools; its **system** message is `REVIEW_SYSTEM`. The answer reaches it in a **user** message, and the review goes back to the advisor in another **user** message. Each object keeps its own list, so \"revise your answer\" is enough.\n",
    "\n",
    "*Do:* the two objects and the first answer are given; write the two `ask` lines: the reviewer receives the question and the answer, and the advisor receives the review."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c84",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ✍️ TYPE · exercise: write the code between the FILL IN lines yourself\n",
    "REVIEW_SYSTEM = \"\"\"You review weather advice and say how it could be better. Answer in at most three sentences.\"\"\"\n",
    "QUESTION = \"Should I take a jacket for a walk in Seoul right now?\"\n",
    "advisor = Agent(WEATHER_SYSTEM, [get_weather])\n",
    "reviewer = Agent(REVIEW_SYSTEM)\n",
    "answer = advisor.ask(QUESTION)\n",
    "### FILL IN (START) ###\n",
    "review = \"\"     # ask the reviewer with a message that holds QUESTION and answer\n",
    "revised = \"\"    # ask the advisor to revise, with a message that holds review\n",
    "### FILL IN (END) ###"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c85",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · check: just run\n",
    "reviewer.show()                                      # the answer reached the reviewer as a USER message\n",
    "print(\"REVISED:\", revised)\n",
    "advisor_user_messages = 0\n",
    "for m in advisor.messages:\n",
    "    if m[\"role\"] == \"user\":                          # the question, then the review\n",
    "        advisor_user_messages = advisor_user_messages + 1\n",
    "done[\"7.6\"] = advisor_user_messages == 2 and len(reviewer.messages) == 3 and revised is not None and revised != \"\"\n",
    "done[\"7.6\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c86",
   "metadata": {},
   "source": [
    "## Summary\n",
    "\n",
    "Every call was the same three call lines, followed by a check of the key. In a class, the two longer pieces are the methods `call_model()` and `run_tools(reply)`:\n",
    "\n",
    "```python\n",
    "response = client.chat.completions.create(model=MODEL, messages=messages, tools=TOOLS)\n",
    "reply = response.choices[0].message.model_dump(exclude_none=True)\n",
    "messages.append(reply)\n",
    "if \"tool_calls\" in reply:\n",
    "    for request in reply[\"tool_calls\"]:\n",
    "        name = request[\"function\"][\"name\"]\n",
    "        args = json.loads(request[\"function\"][\"arguments\"])\n",
    "        result = FUNCTIONS[name](**args)\n",
    "        messages.append({\"role\": \"tool\", \"tool_call_id\": request[\"id\"], \"content\": json.dumps(result)})\n",
    "else:\n",
    "    answer = reply[\"content\"]\n",
    "```\n",
    "\n",
    "*Do:* run the cell. For a `False` item, rerun that part from its first cell, so its list and tools are set again."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c87",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ▶ RUN · check: just run\n",
    "for key in done:\n",
    "    print(key, done[key])"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
