{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "a769b3cf",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "# Building a SWE Agent from Scratch\n",
    "\n",
    "**Agentic AI** · playground\n",
    "\n",
    "*A hands-on walkthrough: we build a small software-engineering agent in plain Python (model call, action parsing, a sandboxed shell, the loop) and grow it step by step until it is, almost line by line, mini-swe-agent.*"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9297f90a",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "## What We Build\n",
    "\n",
    "[mini-swe-agent](https://github.com/SWE-agent/mini-swe-agent) (Lieret & Jimenez, 2026) is the deliberately minimal coding agent of the team behind **SWE-agent** — a separate, much larger agent with a hand-designed set of file-editing and search tools ([Yang et al., 2024](https://arxiv.org/html/2405.15793)). The two are related by their authors, not by their code. Its core loop (`agents/default.py`) is about 100 lines; with serialisation and templating the file has about 190. It has **one tool** (bash), a **linear message history**, and it runs every command in a fresh subshell. We rebuild it ourselves in small pieces, then run the real package on the same task and compare.\n",
    "\n",
    "The plan:\n",
    "\n",
    "1. talk to a model through **LiteLLM** (here: a local model served by Ollama),\n",
    "2. write the **input** (system prompt + task) and parse the **output** (one bash command),\n",
    "3. build a **sandboxed environment** (a podman container),\n",
    "4. glue it together into a **minimal loop**,\n",
    "5. extend the loop: **termination**, **errors as observations**, **observation shaping**,\n",
    "6. look at **tool calling** as the alternative to text parsing,\n",
    "7. refactor into mini's three classes: **Model, Environment, Agent**,\n",
    "8. save and read **trajectories**, add a **human in the loop**,\n",
    "9. run the real **mini-swe-agent** on the same bug.\n",
    "\n",
    "At the end of most sections, a short **Concept** paragraph ties the code back to the lectures."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d3d31db2",
   "metadata": {},
   "source": [
    "## Setup\n",
    "\n",
    "**What you need.**\n",
    "\n",
    "- **Ollama** running locally (`ollama serve`) with a model that is decent at code and follows formats, e.g.\n",
    "  ```bash\n",
    "  ollama pull qwen2.5-coder:7b\n",
    "  ```\n",
    "  Any LiteLLM model string works: set `AGENT_MODEL` before starting Jupyter (e.g. `AGENT_MODEL=ollama_chat/qwen2.5:3b`). Small models are fine for the plumbing sections but often fail the actual bug fix. That's instructive too.\n",
    "- **podman** (rootless is fine). The notebook pulls `python:3.12-slim` once.\n",
    "- Python packages: `litellm`, `jinja2`, `pyyaml` and, for the final section only, `mini-swe-agent`.\n",
    "\n",
    "**Safety first.** The model never executes anything itself; it only writes text. The harness, our code, extracts a shell command from that text and executes it. So the harness executes commands whose content a language model chose. In this notebook, **every model-chosen command** runs inside a podman container with no network, which can only see the toy repository in `./sandbox`. The only commands that run on your machine are the ones *we* wrote into the harness (starting the container, `git` on the sandbox). Keep it that way when you experiment."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4a16ef2c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# %pip install litellm jinja2 pyyaml\n",
    "import json\n",
    "import os\n",
    "import re\n",
    "import subprocess\n",
    "import time\n",
    "from pathlib import Path\n",
    "\n",
    "import litellm\n",
    "from jinja2 import StrictUndefined, Template\n",
    "\n",
    "MODEL = os.getenv(\"AGENT_MODEL\", \"ollama_chat/qwen2.5-coder:7b\")   # \"ollama_chat/\" = Ollama's chat endpoint\n",
    "IMAGE = \"docker.io/library/python:3.12-slim\"\n",
    "SANDBOX = Path(\"sandbox\").resolve()     # all that model-chosen commands can see; mounted at /repo in the container\n",
    "\n",
    "litellm.suppress_debug_info = True\n",
    "print(\"model:  \", MODEL)\n",
    "print(\"sandbox:\", SANDBOX)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9b1405b5",
   "metadata": {},
   "source": [
    "### The Toy Repository\n",
    "\n",
    "Our agent needs something to fix. A tiny package `stats` with a classic bug: `median` ignores the even-length case. The tests catch it.\n",
    "\n",
    "`make_toy_repo()` creates the repo once and commits it; afterwards it **resets** it with `git reset --hard && git clean -fdx`. It never deletes the directory itself, because the container bind-mounts it, and a deleted-and-recreated directory would be a *different* directory from the container's point of view.\n",
    "\n",
    "`git` here is **harness code running on the host**, not an action: we use it to reset the repo and, later, to see what the model's commands changed (`git diff`). The container image has no git, so the model's commands cannot use it, and the prompt says so."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "502d5003",
   "metadata": {},
   "outputs": [],
   "source": [
    "TOY_FILES = {\n",
    "    \"stats/__init__.py\": \"\",\n",
    "    \"stats/core.py\": '''\\\n",
    "def mean(xs):\n",
    "    return sum(xs) / len(xs)\n",
    "\n",
    "\n",
    "def median(xs):\n",
    "    \"\"\"Return the median of a non-empty list of numbers.\"\"\"\n",
    "    xs = sorted(xs)\n",
    "    return xs[len(xs) // 2]\n",
    "''',\n",
    "    \"tests/__init__.py\": \"\",\n",
    "    \"tests/test_core.py\": '''\\\n",
    "import unittest\n",
    "\n",
    "from stats.core import mean, median\n",
    "\n",
    "\n",
    "class TestStats(unittest.TestCase):\n",
    "    def test_mean(self):\n",
    "        self.assertEqual(mean([1, 2, 3]), 2)\n",
    "\n",
    "    def test_median_odd(self):\n",
    "        self.assertEqual(median([3, 1, 2]), 2)\n",
    "\n",
    "    def test_median_even(self):\n",
    "        self.assertEqual(median([4, 1, 3, 2]), 2.5)\n",
    "''',\n",
    "}\n",
    "\n",
    "\n",
    "def git(*args):\n",
    "    return subprocess.run([\"git\", *args], cwd=SANDBOX, check=True, capture_output=True, text=True).stdout\n",
    "\n",
    "\n",
    "def make_toy_repo():\n",
    "    \"\"\"Create the sandbox repo on first use; afterwards reset it to the initial commit.\"\"\"\n",
    "    if (SANDBOX / \".git\").exists():\n",
    "        git(\"reset\", \"--hard\", \"-q\")\n",
    "        git(\"clean\", \"-fdxq\")\n",
    "        return\n",
    "    if SANDBOX.exists() and any(SANDBOX.iterdir()):\n",
    "        raise RuntimeError(f\"{SANDBOX} exists and is not our toy repo; refusing to touch it\")\n",
    "    for name, text in TOY_FILES.items():\n",
    "        (SANDBOX / name).parent.mkdir(parents=True, exist_ok=True)\n",
    "        (SANDBOX / name).write_text(text)\n",
    "    git(\"init\", \"-q\")\n",
    "    git(\"add\", \".\")\n",
    "    git(\"-c\", \"user.name=tutorial\", \"-c\", \"user.email=tutorial@example.invalid\", \"commit\", \"-qm\", \"toy repo\")\n",
    "\n",
    "\n",
    "make_toy_repo()\n",
    "print(git(\"ls-files\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a29e45de",
   "metadata": {},
   "source": [
    "## The Big Picture: Model, Loop, Environment\n",
    "\n",
    "The authors of mini-swe-agent define the whole thing in one sentence:\n",
    "\n",
    "> *\"An AI agent is just a big loop: You start with a prompt, the agent proposes an action, you execute the action, tell the LM the output, and then repeat.\"* (Lieret et al., 2026)\n",
    "\n",
    "Three components take part in that loop, and mini-swe-agent gives each one its own class:\n",
    "\n",
    "| Component | Job | mini-swe-agent |\n",
    "|---|---|---|\n",
    "| **Model** | messages in → one assistant message (+ the parsed action) out | `LitellmModel`, `LitellmTextbasedModel` |\n",
    "| **Environment** | one action in → one observation (output, return code) out | `LocalEnvironment`, `DockerEnvironment`, … |\n",
    "| **Agent** | the loop: history, budgets, termination | `DefaultAgent`, `InteractiveAgent` |\n",
    "\n",
    "<div class=\"mermaid-figure\" style=\"max-width:100%;overflow-x:auto\">\n",
    "<svg style=\"width:100%;max-width:731.0296630859375px;height:auto\" id=\"mmd-0\" xmlns=\"http://www.w3.org/2000/svg\" class=\"flowchart\" viewBox=\"0 0 731.0296630859375 280.29998779296875\" role=\"graphics-document document\" aria-roledescription=\"flowchart-v2\"><style>#mmd-0{font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mmd-0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mmd-0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mmd-0 .error-icon{fill:#552222;}#mmd-0 .error-text{fill:#552222;stroke:#552222;}#mmd-0 .edge-thickness-normal{stroke-width:1px;}#mmd-0 .edge-thickness-thick{stroke-width:3.5px;}#mmd-0 .edge-pattern-solid{stroke-dasharray:0;}#mmd-0 .edge-thickness-invisible{stroke-width:0;fill:none;}#mmd-0 .edge-pattern-dashed{stroke-dasharray:3;}#mmd-0 .edge-pattern-dotted{stroke-dasharray:2;}#mmd-0 .marker{fill:#333333;stroke:#333333;}#mmd-0 .marker.cross{stroke:#333333;}#mmd-0 svg{font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;}#mmd-0 p{margin:0;}#mmd-0 .label{font-family:\"trebuchet ms\",verdana,arial,sans-serif;color:#333;}#mmd-0 .cluster-label text{fill:#333;}#mmd-0 .cluster-label span{color:#333;}#mmd-0 .cluster-label span p{background-color:transparent;}#mmd-0 .label text,#mmd-0 span{fill:#333;color:#333;}#mmd-0 .node rect,#mmd-0 .node circle,#mmd-0 .node ellipse,#mmd-0 .node polygon,#mmd-0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mmd-0 .rough-node .label text,#mmd-0 .node .label text,#mmd-0 .image-shape .label,#mmd-0 .icon-shape .label{text-anchor:middle;}#mmd-0 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mmd-0 .rough-node .label,#mmd-0 .node .label,#mmd-0 .image-shape .label,#mmd-0 .icon-shape .label{text-align:center;}#mmd-0 .node.clickable{cursor:pointer;}#mmd-0 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mmd-0 .arrowheadPath{fill:#333333;}#mmd-0 .edgePath .path{stroke:#333333;stroke-width:1px;}#mmd-0 .flowchart-link{stroke:#333333;fill:none;}#mmd-0 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mmd-0 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mmd-0 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mmd-0 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mmd-0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mmd-0 .cluster text{fill:#333;}#mmd-0 .cluster span{color:#333;}#mmd-0 .node .collapsed-indicator{fill:#aaaa33;stroke:none;opacity:0.6;}#mmd-0 .node .collapsed-separator{stroke:#aaaa33;stroke-width:0.75px;}#mmd-0 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mmd-0 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mmd-0 rect.text{fill:none;stroke-width:0;}#mmd-0 .icon-shape,#mmd-0 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mmd-0 .icon-shape p,#mmd-0 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mmd-0 .icon-shape .label rect,#mmd-0 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mmd-0 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mmd-0 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mmd-0 .node .neo-node{stroke:#9370DB;}#mmd-0 [data-look=\"neo\"].node rect,#mmd-0 [data-look=\"neo\"].cluster rect,#mmd-0 [data-look=\"neo\"].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mmd-0 [data-look=\"neo\"].swimlane.cluster rect{filter:none;}#mmd-0 [data-look=\"neo\"].node path{stroke:#9370DB;stroke-width:1px;}#mmd-0 [data-look=\"neo\"].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mmd-0 [data-look=\"neo\"].node .neo-line path{stroke:#9370DB;filter:none;}#mmd-0 [data-look=\"neo\"].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mmd-0 [data-look=\"neo\"].node circle .state-start{fill:#000000;}#mmd-0 [data-look=\"neo\"].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mmd-0 [data-look=\"neo\"].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mmd-0 :root{--mermaid-font-family:\"trebuchet ms\",verdana,arial,sans-serif;}</style><g><marker id=\"mmd-0_flowchart-v2-pointEnd\" class=\"marker flowchart-v2\" viewBox=\"0 0 10 10\" refX=\"5\" refY=\"5\" markerUnits=\"userSpaceOnUse\" markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\"><path d=\"M 0 0 L 10 5 L 0 10 z\" class=\"arrowMarkerPath\" style=\"stroke-width: 1; stroke-dasharray: 1, 0;\"></path></marker><marker id=\"mmd-0_flowchart-v2-pointStart\" class=\"marker flowchart-v2\" viewBox=\"0 0 10 10\" refX=\"4.5\" refY=\"5\" markerUnits=\"userSpaceOnUse\" markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\"><path d=\"M 0 5 L 10 10 L 10 0 z\" class=\"arrowMarkerPath\" style=\"stroke-width: 1; stroke-dasharray: 1, 0;\"></path></marker><marker id=\"mmd-0_flowchart-v2-pointEnd-margin\" class=\"marker flowchart-v2\" viewBox=\"0 0 11.5 14\" refX=\"11.5\" refY=\"7\" markerUnits=\"userSpaceOnUse\" markerWidth=\"10.5\" markerHeight=\"14\" orient=\"auto\"><path d=\"M 0 0 L 11.5 7 L 0 14 z\" class=\"arrowMarkerPath\" style=\"stroke-width: 0; stroke-dasharray: 1, 0;\"></path></marker><marker id=\"mmd-0_flowchart-v2-pointStart-margin\" class=\"marker flowchart-v2\" viewBox=\"0 0 11.5 14\" refX=\"1\" refY=\"7\" markerUnits=\"userSpaceOnUse\" markerWidth=\"11.5\" markerHeight=\"14\" orient=\"auto\"><polygon points=\"0,7 11.5,14 11.5,0\" class=\"arrowMarkerPath\" style=\"stroke-width: 0; stroke-dasharray: 1, 0;\"></polygon></marker><marker id=\"mmd-0_flowchart-v2-circleEnd\" class=\"marker flowchart-v2\" viewBox=\"0 0 10 10\" refX=\"11\" refY=\"5\" markerUnits=\"userSpaceOnUse\" markerWidth=\"11\" markerHeight=\"11\" orient=\"auto\"><circle cx=\"5\" cy=\"5\" r=\"5\" class=\"arrowMarkerPath\" style=\"stroke-width: 1; stroke-dasharray: 1, 0;\"></circle></marker><marker id=\"mmd-0_flowchart-v2-circleStart\" class=\"marker flowchart-v2\" viewBox=\"0 0 10 10\" refX=\"-1\" refY=\"5\" markerUnits=\"userSpaceOnUse\" markerWidth=\"11\" markerHeight=\"11\" orient=\"auto\"><circle cx=\"5\" cy=\"5\" r=\"5\" class=\"arrowMarkerPath\" style=\"stroke-width: 1; stroke-dasharray: 1, 0;\"></circle></marker><marker id=\"mmd-0_flowchart-v2-circleEnd-margin\" class=\"marker flowchart-v2\" viewBox=\"0 0 10 10\" refY=\"5\" refX=\"12.25\" markerUnits=\"userSpaceOnUse\" markerWidth=\"14\" markerHeight=\"14\" orient=\"auto\"><circle cx=\"5\" cy=\"5\" r=\"5\" class=\"arrowMarkerPath\" style=\"stroke-width: 0; stroke-dasharray: 1, 0;\"></circle></marker><marker id=\"mmd-0_flowchart-v2-circleStart-margin\" class=\"marker flowchart-v2\" viewBox=\"0 0 10 10\" refX=\"-2\" refY=\"5\" markerUnits=\"userSpaceOnUse\" markerWidth=\"14\" markerHeight=\"14\" orient=\"auto\"><circle cx=\"5\" cy=\"5\" r=\"5\" class=\"arrowMarkerPath\" style=\"stroke-width: 0; stroke-dasharray: 1, 0;\"></circle></marker><marker id=\"mmd-0_flowchart-v2-crossEnd\" class=\"marker cross flowchart-v2\" viewBox=\"0 0 11 11\" refX=\"12\" refY=\"5.2\" markerUnits=\"userSpaceOnUse\" markerWidth=\"11\" markerHeight=\"11\" orient=\"auto\"><path d=\"M 1,1 l 9,9 M 10,1 l -9,9\" class=\"arrowMarkerPath\" style=\"stroke-width: 2; stroke-dasharray: 1, 0;\"></path></marker><marker id=\"mmd-0_flowchart-v2-crossStart\" class=\"marker cross flowchart-v2\" viewBox=\"0 0 11 11\" refX=\"-1\" refY=\"5.2\" markerUnits=\"userSpaceOnUse\" markerWidth=\"11\" markerHeight=\"11\" orient=\"auto\"><path d=\"M 1,1 l 9,9 M 10,1 l -9,9\" class=\"arrowMarkerPath\" style=\"stroke-width: 2; stroke-dasharray: 1, 0;\"></path></marker><marker id=\"mmd-0_flowchart-v2-crossEnd-margin\" class=\"marker cross flowchart-v2\" viewBox=\"0 0 15 15\" refX=\"17.7\" refY=\"7.5\" markerUnits=\"userSpaceOnUse\" markerWidth=\"12\" markerHeight=\"12\" orient=\"auto\"><path d=\"M 1,1 L 14,14 M 1,14 L 14,1\" class=\"arrowMarkerPath\" style=\"stroke-width: 2.5;\"></path></marker><marker id=\"mmd-0_flowchart-v2-crossStart-margin\" class=\"marker cross flowchart-v2\" viewBox=\"0 0 15 15\" refX=\"-3.5\" refY=\"7.5\" markerUnits=\"userSpaceOnUse\" markerWidth=\"12\" markerHeight=\"12\" orient=\"auto\"><path d=\"M 1,1 L 14,14 M 1,14 L 14,1\" class=\"arrowMarkerPath\" style=\"stroke-width: 2.5; stroke-dasharray: 1, 0;\"></path></marker><g class=\"root\"><g class=\"clusters\"></g><g class=\"edgePaths\"><path d=\"M61.327,125.6L65.494,125.6C69.661,125.6,77.994,125.6,85.661,125.6C93.327,125.6,100.327,125.6,103.827,125.6L107.327,125.6\" id=\"mmd-0-L_T_A_0\" class=\" edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link\" style=\";\" data-edge=\"true\" data-et=\"edge\" data-id=\"L_T_A_0\" data-points=\"W3sieCI6NjEuMzI3MzA4NjU0Nzg1MTU2LCJ5IjoxMjUuNTk5OTk4NDc0MTIxMX0seyJ4Ijo4Ni4zMjczMDg2NTQ3ODUxNiwieSI6MTI1LjU5OTk5ODQ3NDEyMTF9LHsieCI6MTExLjMyNzMwODY1NDc4NTE2LCJ5IjoxMjUuNTk5OTk4NDc0MTIxMX1d\" data-look=\"classic\" marker-end=\"url(#mmd-0_flowchart-v2-pointEnd)\"></path><path d=\"M312.827,74.02L330.902,64.767C348.976,55.513,385.124,37.007,420.67,29.874C456.216,22.742,491.159,26.984,508.631,29.106L526.102,31.227\" id=\"mmd-0-L_A_M_0\" class=\" edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link\" style=\";\" data-edge=\"true\" data-et=\"edge\" data-id=\"L_A_M_0\" data-points=\"W3sieCI6MzEyLjgyNzMwODY1NDc4NTE2LCJ5Ijo3NC4wMTk4NTIwNjc3OTIzM30seyJ4Ijo0MjEuMjcyNjIxMTU0Nzg1MTYsInkiOjE4LjV9LHsieCI6NTMwLjA3Mjk5ODA0Njg3NSwieSI6MzEuNzA4NzQ3MTc0NTYzMjg1fV0=\" data-look=\"classic\" marker-end=\"url(#mmd-0_flowchart-v2-pointEnd)\"></path><path d=\"M530.073,58.613L511.94,61.477C493.806,64.342,457.539,70.071,421.98,77.084C386.421,84.097,351.57,92.393,334.144,96.541L316.719,100.69\" id=\"mmd-0-L_M_A_0\" class=\" edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link\" style=\";\" data-edge=\"true\" data-et=\"edge\" data-id=\"L_M_A_0\" data-points=\"W3sieCI6NTMwLjA3Mjk5ODA0Njg3NSwieSI6NTguNjEyNzEzNjk1OTU0NDI2fSx7IngiOjQyMS4yNzI2MjExNTQ3ODUxNiwieSI6NzUuNzk5OTk5MjM3MDYwNTV9LHsieCI6MzEyLjgyNzMwODY1NDc4NTE2LCJ5IjoxMDEuNjE1OTUyODMxOTIzMjF9XQ==\" data-look=\"classic\" marker-end=\"url(#mmd-0_flowchart-v2-pointEnd)\"></path><path d=\"M312.827,125.6L330.902,125.6C348.976,125.6,385.124,125.6,420.993,128.411C456.862,131.222,492.451,136.844,510.245,139.655L528.04,142.466\" id=\"mmd-0-L_A_E_0\" class=\" edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link\" style=\";\" data-edge=\"true\" data-et=\"edge\" data-id=\"L_A_E_0\" data-points=\"W3sieCI6MzEyLjgyNzMwODY1NDc4NTE2LCJ5IjoxMjUuNTk5OTk4NDc0MTIxMX0seyJ4Ijo0MjEuMjcyNjIxMTU0Nzg1MTYsInkiOjEyNS41OTk5OTg0NzQxMjExfSx7IngiOjUzMS45OTA5NjY3OTY4NzUsInkiOjE0My4wOTAyNjcxMjUyNzUzfV0=\" data-look=\"classic\" marker-end=\"url(#mmd-0_flowchart-v2-pointEnd)\"></path><path d=\"M531.991,173.6L513.538,176.65C495.085,179.7,458.179,185.8,422.287,183.323C386.395,180.846,351.518,169.793,334.079,164.266L316.64,158.739\" id=\"mmd-0-L_E_A_0\" class=\" edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link\" style=\";\" data-edge=\"true\" data-et=\"edge\" data-id=\"L_E_A_0\" data-points=\"W3sieCI6NTMxLjk5MDk2Njc5Njg3NSwieSI6MTczLjU5OTk5NDM5MDcxODE3fSx7IngiOjQyMS4yNzI2MjExNTQ3ODUxNiwieSI6MTkxLjg5OTk5NzcxMTE4MTY0fSx7IngiOjMxMi44MjczMDg2NTQ3ODUxNiwieSI6MTU3LjUzMDU2NTM4NDU3MTZ9XQ==\" data-look=\"classic\" marker-end=\"url(#mmd-0_flowchart-v2-pointEnd)\"></path><path d=\"M312.827,188.546L330.902,199.838C348.976,211.131,385.124,233.715,420.606,245.008C456.088,256.3,490.903,256.3,508.31,256.3L525.718,256.3\" id=\"mmd-0-L_A_R_0\" class=\" edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link\" style=\";\" data-edge=\"true\" data-et=\"edge\" data-id=\"L_A_R_0\" data-points=\"W3sieCI6MzEyLjgyNzMwODY1NDc4NTE2LCJ5IjoxODguNTQ2MDc4NTE0NTE3NjZ9LHsieCI6NDIxLjI3MjYyMTE1NDc4NTE2LCJ5IjoyNTYuMjk5OTk3MzI5NzExOX0seyJ4Ijo1MjkuNzE3OTMzNjU0Nzg1MiwieSI6MjU2LjI5OTk5NzMyOTcxMTl9XQ==\" data-look=\"classic\" marker-end=\"url(#mmd-0_flowchart-v2-pointEnd)\"></path></g><g class=\"edgeLabels\"><g class=\"edgeLabel\"><g class=\"label\" data-id=\"L_T_A_0\" transform=\"translate(0, 0)\"><text y=\"-10.1\" text-anchor=\"middle\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\" text-anchor=\"middle\"></tspan></text></g></g><g><rect class=\"background\" style=\"stroke: none\"></rect></g><g class=\"edgeLabel\" transform=\"translate(421.27262115478516, 18.5)\"><g class=\"label\" data-id=\"L_A_M_0\" transform=\"translate(0, -10.5)\"><g><rect class=\"background\" style=\"\" x=\"-38.4609375\" y=\"0\" width=\"76.921875\" height=\"21\"></rect><text y=\"-10.1\" text-anchor=\"middle\" style=\"\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\" text-anchor=\"middle\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">messages</tspan></tspan></text></g></g></g><g class=\"edgeLabel\" transform=\"translate(420.62754, 75.95356)\"><g class=\"label\" data-id=\"L_M_A_0\" transform=\"translate(0, -19.299999237060547)\"><g><rect class=\"background\" style=\"\" x=\"-83.4453125\" y=\"0\" width=\"166.890625\" height=\"38.599998474121094\"></rect><text y=\"-10.1\" text-anchor=\"middle\" style=\"\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\" text-anchor=\"middle\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">THOUGHT</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> +</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> one</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> bash</tspan></tspan><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"1em\" dy=\"1.1em\" text-anchor=\"middle\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">command</tspan></tspan></text></g></g></g><g class=\"edgeLabel\" transform=\"translate(421.27262115478516, 125.5999984741211)\"><g class=\"label\" data-id=\"L_A_E_0\" transform=\"translate(0, -10.5)\"><g><rect class=\"background\" style=\"\" x=\"-37.125\" y=\"0\" width=\"74.25\" height=\"21\"></rect><text y=\"-10.1\" text-anchor=\"middle\" style=\"\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\" text-anchor=\"middle\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">command</tspan></tspan></text></g></g></g><g class=\"edgeLabel\" transform=\"translate(420.5382, 191.66724)\"><g class=\"label\" data-id=\"L_E_A_0\" transform=\"translate(-0.05078125, -10.5)\"><g><rect class=\"background\" style=\"\" x=\"-73.8359375\" y=\"0\" width=\"147.7734375\" height=\"21\"></rect><text y=\"-10.1\" text-anchor=\"middle\" style=\"\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\" text-anchor=\"middle\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">output</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> +</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> return</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> code</tspan></tspan></text></g></g></g><g class=\"edgeLabel\"><g class=\"label\" data-id=\"L_A_R_0\" transform=\"translate(0, 0)\"><text y=\"-10.1\" text-anchor=\"middle\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\" text-anchor=\"middle\"></tspan></text></g></g><g><rect class=\"background\" style=\"stroke: none\"></rect></g></g><g class=\"nodes\"><g class=\"root\" transform=\"translate(103.32730865478516, 44.874855041503906)\"><g class=\"clusters\"><g class=\"cluster \" id=\"mmd-0-A\" data-look=\"classic\"><rect style=\"\" x=\"8\" y=\"8\" width=\"201.5\" height=\"145.4502944946289\"></rect><g class=\"cluster-label \" transform=\"translate(51.8203125, 8)\"><g><rect class=\"background\" style=\"stroke: none\"></rect><text y=\"-10.1\" style=\"\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">Agent</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> (the</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> loop)</tspan></tspan></text></g></g></g></g><g class=\"edgePaths\"></g><g class=\"edgeLabels\"></g><g class=\"nodes\"><g class=\"node default  \" id=\"mmd-0-flowchart-H-2\" data-look=\"classic\" transform=\"translate(108.75, 80.72514724731445)\"><path d=\"M0,12.816764132553606 a65.75,12.816764132553606 0,0,0 131.5,0 a65.75,12.816764132553606 0,0,0 -131.5,0 l0,44.81676413255361 a65.75,12.816764132553606 0,0,0 131.5,0 l0,-44.81676413255361\" class=\"basic label-container outer-path\" style=\"\" label-offset-y=\"12.816764132553606\" transform=\"translate(-65.75, -35.22514619883041)\"></path><g class=\"label\" style=\"\" transform=\"translate(0, -0.5)\"><rect></rect><g><rect class=\"background\" style=\"stroke: none\"></rect><text y=\"-10.1\" style=\"\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">message</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> history</tspan></tspan></text></g></g></g></g></g><g class=\"node default  \" id=\"mmd-0-flowchart-T-0\" data-look=\"classic\" transform=\"translate(34.66365432739258, 125.5999984741211)\"><g class=\"basic label-container outer-path\"><path d=\"M-10.671875 -16 C-6.214099959892593 -16, -1.756324919785186 -16, 10.671875 -16 C10.671875 -16, 10.671875 -16, 10.671874999999998 -16 C11.059201520494412 -15.987579192373081, 11.446528040988824 -15.975158384746162, 11.696998519691405 -15.967126284005381 C12.068780071535944 -15.931260964831672, 12.44056162338048 -15.895395645657965, 12.717909586952095 -15.868640221171939 C12.993905297145211 -15.824019375126614, 13.269901007338328 -15.779398529081291, 13.730413059221954 -15.704946511857047 C14.015297189591122 -15.639923568142972, 14.300181319960288 -15.574900624428896, 14.730348342552116 -15.476717808624471 C14.990301144334778 -15.399565181575479, 15.25025394611744 -15.322412554526485, 15.71360648837793 -15.184891952170698 C16.091683057282452 -15.045756279912343, 16.46975962618697 -14.906620607653988, 16.676147078069985 -14.830668117536348 C17.022810574570936 -14.67721047104263, 17.369474071071892 -14.523752824548913, 17.61401482588093 -14.415501886438706 C17.930320877588613 -14.250485221866503, 18.246626929296298 -14.085468557294298, 18.523355832063 -13.941099265974232 C18.7776520637387 -13.78694339592189, 19.0319482954144 -13.632787525869546, 19.400433419368778 -13.409409678269451 C19.676809025631123 -13.216622019448007, 19.953184631893468 -13.023834360626562, 20.241643487859456 -12.822617949887306 C20.490077824362757 -12.624498177641268, 20.73851216086606 -12.426378405395228, 21.043529324924613 -12.183135333906153 C21.273754058994637 -11.974051321836422, 21.50397879306466 -11.764967309766691, 21.802795809655784 -11.493589601563642 C21.96227058361315 -11.328918804330222, 22.121745357570514 -11.164248007096802, 22.516322953205048 -10.756814244181072 C22.651599774325376 -10.597910392623952, 22.786876595445708 -10.43900654106683, 23.18117871948848 -9.975836829739738 C23.3886939483143 -9.697785328139394, 23.59620917714012 -9.41973382653905, 23.79463107355129 -9.153866561954718 C24.006930559455697 -8.827717541211378, 24.219230045360103 -8.501568520468037, 24.354159208085537 -8.294281092968403 C24.465432793678456 -8.096703574075809, 24.576706379271375 -7.899126055183216, 24.857463901968003 -7.400612643853364 C25.01083747639723 -7.082129134882289, 25.16421105082646 -6.763645625911213, 25.302476968252996 -6.476533489958305 C25.382656028758703 -6.278489660352529, 25.462835089264413 -6.080445830746752, 25.687369752796165 -5.52584087074093 C25.75702411849977 -5.316053019157719, 25.826678484203377 -5.1062651675745085, 26.01056064858657 -4.552441386096524 C26.11089823750289 -4.169810672972468, 26.211235826419212 -3.7871799598484115, 26.270721594909176 -3.560334943301032 C26.32957964688603 -3.258111286053569, 26.388437698862887 -2.955887628806106, 26.4667835346312 -2.5535983205340735 C26.499305824017366 -2.3013618663074276, 26.53182811340353 -2.049125412080782, 26.59794080718717 -1.536368414522911 C26.620577076266326 -1.1837902519475603, 26.64321334534548 -0.8312120893722094, 26.663654459211006 -0.5128252411464826 C26.663654459211006 -0.19045069078385501, 26.663654459211006 0.13192385957877262, 26.663654459211006 0.5128252411464788 C26.638184122060157 0.9095463015570653, 26.612713784909307 1.3062673619676517, 26.59794080718717 1.5363684145229002 C26.558852932117 1.8395262547931777, 26.51976505704683 2.142684095063455, 26.466783534631205 2.5535983205340624 C26.39012757621737 2.9472104657465388, 26.31347161780354 3.3408226109590147, 26.270721594909176 3.5603349433010285 C26.195293762053737 3.847973960608363, 26.1198659291983 4.135612977915698, 26.01056064858657 4.552441386096513 C25.94469093508481 4.750830468250196, 25.878821221583056 4.949219550403878, 25.687369752796165 5.525840870740919 C25.567442389512987 5.822063776688208, 25.44751502622981 6.118286682635496, 25.302476968253 6.4765334899583005 C25.135020029568892 6.824261406140356, 24.96756309088478 7.171989322322412, 24.857463901968003 7.400612643853361 C24.73178260755487 7.6237725086949695, 24.606101313141732 7.8469323735365775, 24.35415920808554 8.294281092968399 C24.233086261079922 8.480281652207497, 24.112013314074307 8.666282211446594, 23.794631073551297 9.15386656195471 C23.648188055144455 9.350086865386448, 23.50174503673761 9.546307168818185, 23.18117871948848 9.975836829739734 C23.033351726096907 10.149482827771688, 22.885524732705335 10.323128825803643, 22.516322953205055 10.756814244181063 C22.31574070023374 10.96393188848318, 22.115158447262424 11.171049532785295, 21.802795809655784 11.493589601563638 C21.531378345003112 11.740083761648608, 21.259960880350437 11.986577921733575, 21.043529324924627 12.183135333906142 C20.82559086310797 12.356935457618892, 20.607652401291308 12.530735581331642, 20.24164348785946 12.822617949887304 C20.064025313255968 12.946516699523848, 19.886407138652473 13.07041544916039, 19.400433419368788 13.409409678269446 C19.21298116341995 13.523044337417362, 19.02552890747111 13.63667899656528, 18.523355832063004 13.94109926597423 C18.266346417799124 14.07518091277331, 18.009337003535244 14.209262559572391, 17.614014825880933 14.415501886438705 C17.340340301557127 14.536649480090531, 17.06666577723332 14.657797073742358, 16.67614707806999 14.830668117536346 C16.426880093250517 14.922400672148662, 16.17761310843104 15.014133226760977, 15.713606488377941 15.184891952170695 C15.320335886618954 15.301612602453249, 14.927065284859967 15.418333252735803, 14.730348342552134 15.476717808624468 C14.352815497545544 15.56288721686517, 13.975282652538956 15.649056625105871, 13.730413059221961 15.704946511857045 C13.482425220006755 15.745039262526944, 13.23443738079155 15.785132013196844, 12.717909586952105 15.868640221171937 C12.370519459496922 15.902152528969784, 12.02312933204174 15.935664836767632, 11.696998519691405 15.967126284005381 C11.379451720962516 15.97730939177327, 11.061904922233628 15.987492499541156, 10.671875000000004 16 C10.671875000000002 16, 10.671875000000002 16, 10.671875 16 C3.1271382341213876 16, -4.417598531757225 16, -10.671874999999996 16 C-10.906681432672952 15.992470214727174, -11.141487865345908 15.984940429454348, -11.6969985196914 15.967126284005381 C-12.096183836027013 15.928617356629067, -12.495369152362626 15.890108429252754, -12.7179095869521 15.868640221171937 C-13.05389457081634 15.814320774583232, -13.38987955468058 15.760001327994525, -13.730413059221956 15.704946511857045 C-13.952065597096949 15.654355766505063, -14.17371813497194 15.60376502115308, -14.730348342552112 15.476717808624471 C-14.967199854106259 15.406421523254156, -15.204051365660405 15.33612523788384, -15.713606488377923 15.184891952170702 C-16.036741355279496 15.065975334124959, -16.359876222181068 14.947058716079214, -16.676147078069988 14.830668117536348 C-16.918223671447183 14.723507990595268, -17.16030026482438 14.616347863654186, -17.61401482588093 14.415501886438708 C-17.88591960709836 14.2736493362409, -18.157824388315785 14.131796786043092, -18.523355832063 13.941099265974234 C-18.83741660313897 13.750713780922027, -19.15147737421494 13.560328295869821, -19.400433419368767 13.409409678269457 C-19.599972059138725 13.27022016105443, -19.799510698908687 13.131030643839406, -20.241643487859456 12.822617949887308 C-20.4886859179408 12.625608185972593, -20.735728348022146 12.42859842205788, -21.043529324924613 12.183135333906154 C-21.22199937131754 12.021053559830763, -21.400469417710468 11.858971785755374, -21.802795809655777 11.493589601563649 C-21.994530685703946 11.295607600317835, -22.186265561752116 11.097625599072021, -22.516322953205048 10.756814244181069 C-22.67617197467985 10.569046487889775, -22.836020996154655 10.38127873159848, -23.181178719488475 9.97583682973974 C-23.390870197502345 9.694869352487792, -23.600561675516218 9.413901875235844, -23.79463107355129 9.15386656195472 C-24.00248820066036 8.834542197261383, -24.210345327769424 8.515217832568046, -24.354159208085534 8.29428109296841 C-24.524196035420378 7.992363487939563, -24.694232862755218 7.690445882910716, -24.857463901968 7.400612643853366 C-24.98829801484672 7.128932809059146, -25.11913212772544 6.857252974264925, -25.302476968252996 6.476533489958307 C-25.41891583740904 6.188927231950498, -25.53535470656508 5.90132097394269, -25.687369752796165 5.525840870740931 C-25.757920417257893 5.313353510104067, -25.82847108171962 5.100866149467202, -26.01056064858657 4.552441386096519 C-26.075631724699733 4.304297170894246, -26.140702800812896 4.056152955691973, -26.270721594909176 3.5603349433010343 C-26.33793833625443 3.2151911827564614, -26.405155077599687 2.870047422211889, -26.4667835346312 2.5535983205340753 C-26.502183908117495 2.279040014368819, -26.537584281603788 2.0044817082035635, -26.59794080718717 1.5363684145229202 C-26.61473535170058 1.2747798274142461, -26.631529896213987 1.0131912403055718, -26.663654459211006 0.5128252411464846 C-26.663654459211006 0.23108387948354037, -26.663654459211006 -0.05065748217940391, -26.663654459211006 -0.5128252411464769 C-26.641777080994135 -0.8535830659761124, -26.61989970277726 -1.194340890805748, -26.59794080718717 -1.5363684145228982 C-26.557381690354873 -1.8509369153706832, -26.516822573522575 -2.165505416218468, -26.466783534631205 -2.5535983205340678 C-26.423900540020643 -2.7737934345351687, -26.381017545410085 -2.99398854853627, -26.270721594909176 -3.5603349433010267 C-26.187018899094518 -3.879529599420165, -26.10331620327986 -4.198724255539303, -26.010560648586573 -4.552441386096511 C-25.897584944553643 -4.892706206409743, -25.784609240520712 -5.232971026722975, -25.687369752796172 -5.525840870740911 C-25.586955219989196 -5.773866708157057, -25.486540687182224 -6.021892545573205, -25.302476968253 -6.476533489958299 C-25.186093640704566 -6.718205959816909, -25.069710313156133 -6.959878429675518, -24.857463901968003 -7.400612643853359 C-24.70316243915364 -7.674590515797655, -24.54886097633928 -7.94856838774195, -24.354159208085537 -8.294281092968404 C-24.158534850534156 -8.59481263866257, -23.962910492982775 -8.895344184356734, -23.794631073551294 -9.153866561954715 C-23.636334044620877 -9.365970159565467, -23.478037015690457 -9.57807375717622, -23.18117871948848 -9.975836829739734 C-22.934094540518753 -10.266075965845646, -22.687010361549028 -10.556315101951558, -22.516322953205055 -10.756814244181063 C-22.353068685839073 -10.925387678661059, -22.189814418473095 -11.093961113141054, -21.80279580965579 -11.493589601563633 C-21.61735341843327 -11.662003474735124, -21.431911027210752 -11.830417347906616, -21.043529324924627 -12.18313533390614 C-20.880552328022898 -12.31310515193524, -20.71757533112117 -12.443074969964337, -20.241643487859463 -12.822617949887302 C-19.960606679520406 -13.018657061497276, -19.679569871181346 -13.214696173107248, -19.400433419368788 -13.409409678269444 C-19.21866359505006 -13.519599613969515, -19.03689377073133 -13.629789549669585, -18.523355832063007 -13.941099265974229 C-18.176914715967424 -14.12183737433517, -17.83047359987184 -14.302575482696112, -17.614014825880936 -14.415501886438705 C-17.325303750878643 -14.54330571503247, -17.03659267587635 -14.671109543626235, -16.676147078069995 -14.830668117536344 C-16.470793095492557 -14.906240281396247, -16.265439112915118 -14.981812445256152, -15.713606488377943 -15.184891952170695 C-15.475397217963994 -15.255591213243578, -15.237187947550044 -15.326290474316462, -14.730348342552134 -15.476717808624466 C-14.461282393902632 -15.53813035558431, -14.192216445253132 -15.599542902544153, -13.730413059221963 -15.704946511857043 C-13.441478939366412 -15.751659139637725, -13.152544819510862 -15.798371767418406, -12.717909586952107 -15.868640221171937 C-12.386842350820377 -15.90057787927496, -12.055775114688645 -15.932515537377983, -11.696998519691407 -15.967126284005381 C-11.452626811101338 -15.974962809059189, -11.208255102511266 -15.982799334112997, -10.671875000000005 -16 C-10.671875000000004 -16, -10.671875000000002 -16, -10.671875 -16\" stroke=\"none\" stroke-width=\"0\" fill=\"#ECECFF\" style=\"\"></path><path d=\"M-10.671875 -16 C-2.9311169857552457 -16, 4.809641028489509 -16, 10.671875 -16 M-10.671875 -16 C-5.825082538301532 -16, -0.9782900766030647 -16, 10.671875 -16 M10.671875 -16 C10.671875 -16, 10.671874999999998 -16, 10.671874999999998 -16 M10.671875 -16 C10.671875 -16, 10.671874999999998 -16, 10.671874999999998 -16 M10.671874999999998 -16 C11.081200656466734 -15.98687372290117, 11.490526312933468 -15.973747445802339, 11.696998519691405 -15.967126284005381 M10.671874999999998 -16 C10.95273846027872 -15.990993255496422, 11.233601920557442 -15.981986510992845, 11.696998519691405 -15.967126284005381 M11.696998519691405 -15.967126284005381 C12.08033873871533 -15.93014591411021, 12.463678957739253 -15.893165544215035, 12.717909586952095 -15.868640221171939 M11.696998519691405 -15.967126284005381 C11.923753133982459 -15.945251539077047, 12.150507748273514 -15.92337679414871, 12.717909586952095 -15.868640221171939 M12.717909586952095 -15.868640221171939 C12.936687658336211 -15.833269879239838, 13.15546572972033 -15.797899537307737, 13.730413059221954 -15.704946511857047 M12.717909586952095 -15.868640221171939 C13.094650387762986 -15.80773169016538, 13.471391188573877 -15.74682315915882, 13.730413059221954 -15.704946511857047 M13.730413059221954 -15.704946511857047 C14.094047405486615 -15.62194934525801, 14.457681751751274 -15.538952178658972, 14.730348342552116 -15.476717808624471 M13.730413059221954 -15.704946511857047 C14.119373153512852 -15.616168908536972, 14.50833324780375 -15.527391305216897, 14.730348342552116 -15.476717808624471 M14.730348342552116 -15.476717808624471 C15.011842883952912 -15.393171706331715, 15.293337425353709 -15.309625604038958, 15.71360648837793 -15.184891952170698 M14.730348342552116 -15.476717808624471 C14.9446420556883 -15.413116559416306, 15.158935768824485 -15.34951531020814, 15.71360648837793 -15.184891952170698 M15.71360648837793 -15.184891952170698 C15.990933255007588 -15.082833138470455, 16.268260021637246 -14.980774324770213, 16.676147078069985 -14.830668117536348 M15.71360648837793 -15.184891952170698 C16.04407436493597 -15.063276718785776, 16.37454224149401 -14.941661485400854, 16.676147078069985 -14.830668117536348 M16.676147078069985 -14.830668117536348 C16.96156841596257 -14.704320557974466, 17.246989753855157 -14.577972998412584, 17.61401482588093 -14.415501886438706 M16.676147078069985 -14.830668117536348 C16.920424593918025 -14.72253370750547, 17.16470210976607 -14.61439929747459, 17.61401482588093 -14.415501886438706 M17.61401482588093 -14.415501886438706 C17.896764230193615 -14.267991703318415, 18.179513634506296 -14.120481520198126, 18.523355832063 -13.941099265974232 M17.61401482588093 -14.415501886438706 C17.959463897555263 -14.235281327016896, 18.304912969229598 -14.055060767595087, 18.523355832063 -13.941099265974232 M18.523355832063 -13.941099265974232 C18.792791647494806 -13.777765691278868, 19.062227462926614 -13.614432116583501, 19.400433419368778 -13.409409678269451 M18.523355832063 -13.941099265974232 C18.865265130578333 -13.733831839932174, 19.207174429093662 -13.526564413890116, 19.400433419368778 -13.409409678269451 M19.400433419368778 -13.409409678269451 C19.68819265509451 -13.208681292323723, 19.975951890820248 -13.007952906377996, 20.241643487859456 -12.822617949887306 M19.400433419368778 -13.409409678269451 C19.635615366565847 -13.245356932767182, 19.870797313762917 -13.081304187264912, 20.241643487859456 -12.822617949887306 M20.241643487859456 -12.822617949887306 C20.491405605386337 -12.623439307608699, 20.741167722913218 -12.42426066533009, 21.043529324924613 -12.183135333906153 M20.241643487859456 -12.822617949887306 C20.43219134165962 -12.67066110717302, 20.622739195459783 -12.518704264458735, 21.043529324924613 -12.183135333906153 M21.043529324924613 -12.183135333906153 C21.231250228734346 -12.012652175889095, 21.41897113254408 -11.842169017872036, 21.802795809655784 -11.493589601563642 M21.043529324924613 -12.183135333906153 C21.295557315319712 -11.954250181324538, 21.54758530571481 -11.725365028742925, 21.802795809655784 -11.493589601563642 M21.802795809655784 -11.493589601563642 C22.05775914224967 -11.230319027781553, 22.312722474843554 -10.967048453999462, 22.516322953205048 -10.756814244181072 M21.802795809655784 -11.493589601563642 C22.048849215462816 -11.23951925870757, 22.29490262126985 -10.985448915851501, 22.516322953205048 -10.756814244181072 M22.516322953205048 -10.756814244181072 C22.65399601961968 -10.595095626551043, 22.791669086034315 -10.433377008921015, 23.18117871948848 -9.975836829739738 M22.516322953205048 -10.756814244181072 C22.65393662574659 -10.595165393973982, 22.791550298288133 -10.433516543766892, 23.18117871948848 -9.975836829739738 M23.18117871948848 -9.975836829739738 C23.361021225879636 -9.73486425516497, 23.540863732270793 -9.4938916805902, 23.79463107355129 -9.153866561954718 M23.18117871948848 -9.975836829739738 C23.411352519204335 -9.66742490738502, 23.641526318920196 -9.359012985030299, 23.79463107355129 -9.153866561954718 M23.79463107355129 -9.153866561954718 C23.98391685666144 -8.863072768747843, 24.17320263977159 -8.57227897554097, 24.354159208085537 -8.294281092968403 M23.79463107355129 -9.153866561954718 C23.920529362288875 -8.960452982029636, 24.046427651026463 -8.767039402104553, 24.354159208085537 -8.294281092968403 M24.354159208085537 -8.294281092968403 C24.548414648228302 -7.949360888498614, 24.742670088371067 -7.604440684028825, 24.857463901968003 -7.400612643853364 M24.354159208085537 -8.294281092968403 C24.46736959436019 -8.093264588343056, 24.580579980634845 -7.892248083717708, 24.857463901968003 -7.400612643853364 M24.857463901968003 -7.400612643853364 C24.98652195853077 -7.132620828000735, 25.115580015093535 -6.8646290121481055, 25.302476968252996 -6.476533489958305 M24.857463901968003 -7.400612643853364 C25.031932952386704 -7.038323927619272, 25.206402002805405 -6.676035211385179, 25.302476968252996 -6.476533489958305 M25.302476968252996 -6.476533489958305 C25.38207794754071 -6.279917532137411, 25.461678926828426 -6.083301574316517, 25.687369752796165 -5.52584087074093 M25.302476968252996 -6.476533489958305 C25.4443418646076 -6.126124453191252, 25.586206760962206 -5.7757154164242, 25.687369752796165 -5.52584087074093 M25.687369752796165 -5.52584087074093 C25.79145123623043 -5.212364025769276, 25.895532719664693 -4.8988871807976215, 26.01056064858657 -4.552441386096524 M25.687369752796165 -5.52584087074093 C25.774253666480163 -5.2641603657964495, 25.861137580164158 -5.00247986085197, 26.01056064858657 -4.552441386096524 M26.01056064858657 -4.552441386096524 C26.088056022767717 -4.256917937636184, 26.16555139694886 -3.961394489175846, 26.270721594909176 -3.560334943301032 M26.01056064858657 -4.552441386096524 C26.112740853477423 -4.162783979666761, 26.214921058368276 -3.7731265732369983, 26.270721594909176 -3.560334943301032 M26.270721594909176 -3.560334943301032 C26.33872953506907 -3.211128544063215, 26.406737475228965 -2.8619221448253978, 26.4667835346312 -2.5535983205340735 M26.270721594909176 -3.560334943301032 C26.32889369026656 -3.2616335283175726, 26.387065785623946 -2.9629321133341135, 26.4667835346312 -2.5535983205340735 M26.4667835346312 -2.5535983205340735 C26.518100541396866 -2.1555937497487503, 26.569417548162534 -1.757589178963427, 26.59794080718717 -1.536368414522911 M26.4667835346312 -2.5535983205340735 C26.511270464685516 -2.2085664759707764, 26.555757394739835 -1.8635346314074792, 26.59794080718717 -1.536368414522911 M26.59794080718717 -1.536368414522911 C26.623632451598613 -1.1362003148926076, 26.649324096010055 -0.7360322152623042, 26.663654459211006 -0.5128252411464826 M26.59794080718717 -1.536368414522911 C26.617566998004587 -1.2306746505655848, 26.637193188822 -0.9249808866082586, 26.663654459211006 -0.5128252411464826 M26.663654459211006 -0.5128252411464826 C26.663654459211006 -0.23836264178145516, 26.663654459211006 0.03609995758357232, 26.663654459211006 0.5128252411464788 M26.663654459211006 -0.5128252411464826 C26.663654459211006 -0.14537626288750377, 26.663654459211006 0.2220727153714751, 26.663654459211006 0.5128252411464788 M26.663654459211006 0.5128252411464788 C26.639810102999835 0.8842203359533907, 26.615965746788664 1.2556154307603027, 26.59794080718717 1.5363684145229002 M26.663654459211006 0.5128252411464788 C26.639144092635117 0.8945939849777462, 26.61463372605923 1.2763627288090138, 26.59794080718717 1.5363684145229002 M26.59794080718717 1.5363684145229002 C26.551850499469737 1.8938357396186132, 26.505760191752305 2.2513030647143264, 26.466783534631205 2.5535983205340624 M26.59794080718717 1.5363684145229002 C26.57012935225837 1.7520685669577287, 26.542317897329568 1.967768719392557, 26.466783534631205 2.5535983205340624 M26.466783534631205 2.5535983205340624 C26.4221179129528 2.7829468477701758, 26.3774522912744 3.012295375006289, 26.270721594909176 3.5603349433010285 M26.466783534631205 2.5535983205340624 C26.403615476248117 2.877952949757341, 26.340447417865033 3.2023075789806192, 26.270721594909176 3.5603349433010285 M26.270721594909176 3.5603349433010285 C26.20614521896943 3.8065926523376614, 26.14156884302968 4.052850361374294, 26.01056064858657 4.552441386096513 M26.270721594909176 3.5603349433010285 C26.170568494041877 3.9422621235365387, 26.070415393174574 4.324189303772049, 26.01056064858657 4.552441386096513 M26.01056064858657 4.552441386096513 C25.92684617860299 4.804576031597611, 25.84313170861941 5.0567106770987085, 25.687369752796165 5.525840870740919 M26.01056064858657 4.552441386096513 C25.9343676932959 4.781922427733182, 25.858174738005236 5.011403469369851, 25.687369752796165 5.525840870740919 M25.687369752796165 5.525840870740919 C25.561680860159424 5.8362948655831035, 25.43599196752268 6.146748860425287, 25.302476968253 6.4765334899583005 M25.687369752796165 5.525840870740919 C25.576368235923706 5.800016763484227, 25.465366719051246 6.074192656227536, 25.302476968253 6.4765334899583005 M25.302476968253 6.4765334899583005 C25.211469163163006 6.66551314448276, 25.12046135807301 6.85449279900722, 24.857463901968003 7.400612643853361 M25.302476968253 6.4765334899583005 C25.14657548078405 6.800266264445024, 24.990673993315106 7.123999038931748, 24.857463901968003 7.400612643853361 M24.857463901968003 7.400612643853361 C24.719710822108805 7.645207186155281, 24.58195774224961 7.889801728457201, 24.35415920808554 8.294281092968399 M24.857463901968003 7.400612643853361 C24.73926105705689 7.610493764328998, 24.62105821214578 7.820374884804635, 24.35415920808554 8.294281092968399 M24.35415920808554 8.294281092968399 C24.152173362055994 8.604585593263872, 23.950187516026443 8.914890093559343, 23.794631073551297 9.15386656195471 M24.35415920808554 8.294281092968399 C24.14781877262033 8.611275412008041, 23.941478337155115 8.928269731047685, 23.794631073551297 9.15386656195471 M23.794631073551297 9.15386656195471 C23.555493386179972 9.474289277140786, 23.31635569880865 9.794711992326862, 23.18117871948848 9.975836829739734 M23.794631073551297 9.15386656195471 C23.624069467810497 9.382403575165444, 23.453507862069692 9.610940588376181, 23.18117871948848 9.975836829739734 M23.18117871948848 9.975836829739734 C22.917091297134117 10.286048943037194, 22.65300387477976 10.596261056334656, 22.516322953205055 10.756814244181063 M23.18117871948848 9.975836829739734 C22.980177113947725 10.211944752923264, 22.779175508406972 10.448052676106796, 22.516322953205055 10.756814244181063 M22.516322953205055 10.756814244181063 C22.339742551728545 10.939148006226137, 22.163162150252035 11.12148176827121, 21.802795809655784 11.493589601563638 M22.516322953205055 10.756814244181063 C22.373240987132814 10.904558121398535, 22.230159021060572 11.052301998616008, 21.802795809655784 11.493589601563638 M21.802795809655784 11.493589601563638 C21.572059939015002 11.703137814343002, 21.34132406837422 11.912686027122364, 21.043529324924627 12.183135333906142 M21.802795809655784 11.493589601563638 C21.558046685396793 11.715864280508686, 21.3132975611378 11.938138959453735, 21.043529324924627 12.183135333906142 M21.043529324924627 12.183135333906142 C20.826471779232932 12.356232950451394, 20.60941423354124 12.529330566996645, 20.24164348785946 12.822617949887304 M21.043529324924627 12.183135333906142 C20.830811007035187 12.352772531750798, 20.618092689145747 12.522409729595452, 20.24164348785946 12.822617949887304 M20.24164348785946 12.822617949887304 C20.01316747883563 12.981992923215305, 19.7846914698118 13.141367896543308, 19.400433419368788 13.409409678269446 M20.24164348785946 12.822617949887304 C19.96485391429554 13.015694374377972, 19.688064340731618 13.208770798868642, 19.400433419368788 13.409409678269446 M19.400433419368788 13.409409678269446 C19.06965978375604 13.60992660001954, 18.738886148143294 13.810443521769633, 18.523355832063004 13.94109926597423 M19.400433419368788 13.409409678269446 C19.175662687130746 13.545667017051587, 18.950891954892704 13.68192435583373, 18.523355832063004 13.94109926597423 M18.523355832063004 13.94109926597423 C18.298476484540213 14.058418677534773, 18.073597137017426 14.175738089095317, 17.614014825880933 14.415501886438705 M18.523355832063004 13.94109926597423 C18.200815812173644 14.109368187753766, 17.87827579228429 14.277637109533302, 17.614014825880933 14.415501886438705 M17.614014825880933 14.415501886438705 C17.288212522694675 14.55972490147732, 16.962410219508417 14.703947916515936, 16.67614707806999 14.830668117536346 M17.614014825880933 14.415501886438705 C17.35974356415969 14.528060231313711, 17.10547230243845 14.640618576188718, 16.67614707806999 14.830668117536346 M16.67614707806999 14.830668117536346 C16.417102526945662 14.92599890693168, 16.15805797582133 15.021329696327015, 15.713606488377941 15.184891952170695 M16.67614707806999 14.830668117536346 C16.47032931284074 14.906410957699277, 16.264511547611484 14.982153797862209, 15.713606488377941 15.184891952170695 M15.713606488377941 15.184891952170695 C15.434749834872461 15.267655143182678, 15.15589318136698 15.35041833419466, 14.730348342552134 15.476717808624468 M15.713606488377941 15.184891952170695 C15.465737909928924 15.258458045165645, 15.217869331479907 15.332024138160595, 14.730348342552134 15.476717808624468 M14.730348342552134 15.476717808624468 C14.48686342230734 15.532291652782748, 14.243378502062546 15.587865496941028, 13.730413059221961 15.704946511857045 M14.730348342552134 15.476717808624468 C14.503206031456623 15.528561558889916, 14.276063720361112 15.580405309155363, 13.730413059221961 15.704946511857045 M13.730413059221961 15.704946511857045 C13.409994815494631 15.756749248622288, 13.089576571767301 15.808551985387531, 12.717909586952105 15.868640221171937 M13.730413059221961 15.704946511857045 C13.515280413468892 15.739727489643817, 13.30014776771582 15.774508467430588, 12.717909586952105 15.868640221171937 M12.717909586952105 15.868640221171937 C12.452705426136301 15.894224147611169, 12.187501265320495 15.919808074050403, 11.696998519691405 15.967126284005381 M12.717909586952105 15.868640221171937 C12.437077630097974 15.895731742299812, 12.156245673243841 15.922823263427688, 11.696998519691405 15.967126284005381 M11.696998519691405 15.967126284005381 C11.390193368114865 15.976964928056441, 11.083388216538326 15.986803572107501, 10.671875000000004 16 M11.696998519691405 15.967126284005381 C11.468821174345313 15.97444348735037, 11.240643828999222 15.98176069069536, 10.671875000000004 16 M10.671875000000004 16 C10.671875000000002 16, 10.671875000000002 16, 10.671875 16 M10.671875000000004 16 C10.671875000000002 16, 10.671875 16, 10.671875 16 M10.671875 16 C4.67529586324117 16, -1.3212832735176594 16, -10.671874999999996 16 M10.671875 16 C5.605302148221194 16, 0.5387292964423889 16, -10.671874999999996 16 M-10.671874999999996 16 C-11.044508558790762 15.988050367056802, -11.417142117581525 15.976100734113604, -11.6969985196914 15.967126284005381 M-10.671874999999996 16 C-10.970303396643464 15.99042998217528, -11.26873179328693 15.980859964350559, -11.6969985196914 15.967126284005381 M-11.6969985196914 15.967126284005381 C-11.98436512312345 15.939404373381196, -12.2717317265555 15.911682462757012, -12.7179095869521 15.868640221171937 M-11.6969985196914 15.967126284005381 C-11.90768076682999 15.946802021006395, -12.11836301396858 15.926477758007408, -12.7179095869521 15.868640221171937 M-12.7179095869521 15.868640221171937 C-13.095910860378828 15.80752790672796, -13.473912133805554 15.746415592283984, -13.730413059221956 15.704946511857045 M-12.7179095869521 15.868640221171937 C-13.0604774999446 15.813256497653152, -13.4030454129371 15.757872774134366, -13.730413059221956 15.704946511857045 M-13.730413059221956 15.704946511857045 C-13.975092843894988 15.649099947690239, -14.219772628568018 15.593253383523432, -14.730348342552112 15.476717808624471 M-13.730413059221956 15.704946511857045 C-13.944436057291837 15.656097159178179, -14.158459055361718 15.607247806499313, -14.730348342552112 15.476717808624471 M-14.730348342552112 15.476717808624471 C-14.999642609381038 15.3967926837841, -15.268936876209965 15.316867558943725, -15.713606488377923 15.184891952170702 M-14.730348342552112 15.476717808624471 C-14.935440578632791 15.415847509506841, -15.14053281471347 15.354977210389212, -15.713606488377923 15.184891952170702 M-15.713606488377923 15.184891952170702 C-15.985779366212672 15.084729817189013, -16.25795224404742 14.984567682207322, -16.676147078069988 14.830668117536348 M-15.713606488377923 15.184891952170702 C-16.000815739093024 15.079196292974334, -16.28802498980813 14.973500633777967, -16.676147078069988 14.830668117536348 M-16.676147078069988 14.830668117536348 C-17.047981975214437 14.666067838660826, -17.419816872358883 14.501467559785302, -17.61401482588093 14.415501886438708 M-16.676147078069988 14.830668117536348 C-16.86715242163921 14.746115717910458, -17.058157765208435 14.661563318284568, -17.61401482588093 14.415501886438708 M-17.61401482588093 14.415501886438708 C-17.931973858573915 14.249622862745257, -18.2499328912669 14.083743839051806, -18.523355832063 13.941099265974234 M-17.61401482588093 14.415501886438708 C-17.874625472152285 14.279541479208026, -18.135236118423645 14.143581071977344, -18.523355832063 13.941099265974234 M-18.523355832063 13.941099265974234 C-18.70922367154796 13.828425089397784, -18.895091511032923 13.715750912821335, -19.400433419368767 13.409409678269457 M-18.523355832063 13.941099265974234 C-18.847446419949488 13.744633647029747, -19.171537007835976 13.548168028085259, -19.400433419368767 13.409409678269457 M-19.400433419368767 13.409409678269457 C-19.73098505996733 13.178831163137795, -20.061536700565892 12.948252648006134, -20.241643487859456 12.822617949887308 M-19.400433419368767 13.409409678269457 C-19.612335231376576 13.261596147294409, -19.824237043384386 13.113782616319359, -20.241643487859456 12.822617949887308 M-20.241643487859456 12.822617949887308 C-20.510006614831504 12.608605497569831, -20.778369741803548 12.394593045252353, -21.043529324924613 12.183135333906154 M-20.241643487859456 12.822617949887308 C-20.47117570375562 12.639572115818908, -20.70070791965178 12.456526281750508, -21.043529324924613 12.183135333906154 M-21.043529324924613 12.183135333906154 C-21.209263299178474 12.03262012356946, -21.37499727343234 11.882104913232766, -21.802795809655777 11.493589601563649 M-21.043529324924613 12.183135333906154 C-21.214222316913183 12.028116474871219, -21.384915308901753 11.873097615836283, -21.802795809655777 11.493589601563649 M-21.802795809655777 11.493589601563649 C-22.03474474282511 11.254083284704738, -22.26669367599445 11.014576967845825, -22.516322953205048 10.756814244181069 M-21.802795809655777 11.493589601563649 C-21.95192669296703 11.339599720671552, -22.101057576278286 11.185609839779456, -22.516322953205048 10.756814244181069 M-22.516322953205048 10.756814244181069 C-22.722560778509315 10.51455555931397, -22.928798603813586 10.272296874446871, -23.181178719488475 9.97583682973974 M-22.516322953205048 10.756814244181069 C-22.71296949761624 10.52582202361032, -22.90961604202743 10.294829803039574, -23.181178719488475 9.97583682973974 M-23.181178719488475 9.97583682973974 C-23.423540183542453 9.651094547491006, -23.66590164759643 9.32635226524227, -23.79463107355129 9.15386656195472 M-23.181178719488475 9.97583682973974 C-23.411723738389966 9.666927507495037, -23.642268757291458 9.358018185250334, -23.79463107355129 9.15386656195472 M-23.79463107355129 9.15386656195472 C-23.93760546875944 8.934219496914222, -24.08057986396759 8.714572431873727, -24.354159208085534 8.29428109296841 M-23.79463107355129 9.15386656195472 C-24.000363059469617 8.837806984810676, -24.20609504538794 8.521747407666632, -24.354159208085534 8.29428109296841 M-24.354159208085534 8.29428109296841 C-24.53726844550577 7.9691521001078875, -24.720377682926003 7.6440231072473654, -24.857463901968 7.400612643853366 M-24.354159208085534 8.29428109296841 C-24.481824808428705 8.067597892015263, -24.609490408771872 7.840914691062114, -24.857463901968 7.400612643853366 M-24.857463901968 7.400612643853366 C-24.973601618800704 7.1594501899012, -25.089739335633404 6.918287735949034, -25.302476968252996 6.476533489958307 M-24.857463901968 7.400612643853366 C-25.020436303642686 7.0621969647250955, -25.183408705317376 6.723781285596825, -25.302476968252996 6.476533489958307 M-25.302476968252996 6.476533489958307 C-25.402990627567206 6.228262808152809, -25.503504286881416 5.979992126347311, -25.687369752796165 5.525840870740931 M-25.302476968252996 6.476533489958307 C-25.415154947906498 6.198216701733623, -25.527832927560002 5.919899913508938, -25.687369752796165 5.525840870740931 M-25.687369752796165 5.525840870740931 C-25.800683774914923 5.184557090256857, -25.91399779703368 4.8432733097727825, -26.01056064858657 4.552441386096519 M-25.687369752796165 5.525840870740931 C-25.81507486483718 5.14121342031982, -25.94277997687819 4.75658596989871, -26.01056064858657 4.552441386096519 M-26.01056064858657 4.552441386096519 C-26.077828914198935 4.295918335065835, -26.145097179811298 4.039395284035152, -26.270721594909176 3.5603349433010343 M-26.01056064858657 4.552441386096519 C-26.074088879135502 4.310180709704152, -26.137617109684435 4.067920033311784, -26.270721594909176 3.5603349433010343 M-26.270721594909176 3.5603349433010343 C-26.341606123806454 3.1963578688640006, -26.41249065270373 2.832380794426967, -26.4667835346312 2.5535983205340753 M-26.270721594909176 3.5603349433010343 C-26.317277121535888 3.3212821535869104, -26.3638326481626 3.0822293638727865, -26.4667835346312 2.5535983205340753 M-26.4667835346312 2.5535983205340753 C-26.504480056586022 2.2612315402727075, -26.542176578540847 1.9688647600113396, -26.59794080718717 1.5363684145229202 M-26.4667835346312 2.5535983205340753 C-26.506878813450253 2.2426272557218736, -26.546974092269302 1.9316561909096723, -26.59794080718717 1.5363684145229202 M-26.59794080718717 1.5363684145229202 C-26.61692725941445 1.2406390954946669, -26.635913711641727 0.9449097764664137, -26.663654459211006 0.5128252411464846 M-26.59794080718717 1.5363684145229202 C-26.614016196258135 1.2859812539221889, -26.630091585329094 1.0355940933214574, -26.663654459211006 0.5128252411464846 M-26.663654459211006 0.5128252411464846 C-26.663654459211006 0.2967173735708122, -26.663654459211006 0.08060950599513977, -26.663654459211006 -0.5128252411464769 M-26.663654459211006 0.5128252411464846 C-26.663654459211006 0.2121763983638265, -26.663654459211006 -0.08847244441883162, -26.663654459211006 -0.5128252411464769 M-26.663654459211006 -0.5128252411464769 C-26.63981272289848 -0.8841795289172195, -26.615970986585957 -1.2555338166879622, -26.59794080718717 -1.5363684145228982 M-26.663654459211006 -0.5128252411464769 C-26.639278221379517 -0.8925048215169415, -26.61490198354803 -1.2721844018874062, -26.59794080718717 -1.5363684145228982 M-26.59794080718717 -1.5363684145228982 C-26.552565793965112 -1.8882880567633704, -26.507190780743052 -2.2402076990038426, -26.466783534631205 -2.5535983205340678 M-26.59794080718717 -1.5363684145228982 C-26.550902793024445 -1.901185963662499, -26.50386477886172 -2.2660035128021, -26.466783534631205 -2.5535983205340678 M-26.466783534631205 -2.5535983205340678 C-26.414259661670993 -2.823297307260266, -26.36173578871078 -3.0929962939864635, -26.270721594909176 -3.5603349433010267 M-26.466783534631205 -2.5535983205340678 C-26.411132369238338 -2.839355292948466, -26.355481203845468 -3.125112265362864, -26.270721594909176 -3.5603349433010267 M-26.270721594909176 -3.5603349433010267 C-26.16834837265082 -3.950728408607333, -26.065975150392465 -4.3411218739136395, -26.010560648586573 -4.552441386096511 M-26.270721594909176 -3.5603349433010267 C-26.21776575973321 -3.7622784940311313, -26.164809924557247 -3.9642220447612355, -26.010560648586573 -4.552441386096511 M-26.010560648586573 -4.552441386096511 C-25.93328224596555 -4.785191622149663, -25.856003843344528 -5.017941858202814, -25.687369752796172 -5.525840870740911 M-26.010560648586573 -4.552441386096511 C-25.887643976785185 -4.922646817450215, -25.764727304983797 -5.292852248803919, -25.687369752796172 -5.525840870740911 M-25.687369752796172 -5.525840870740911 C-25.579028497225476 -5.79344586663621, -25.47068724165478 -6.061050862531509, -25.302476968253 -6.476533489958299 M-25.687369752796172 -5.525840870740911 C-25.543673094893443 -5.880774393946539, -25.39997643699071 -6.235707917152166, -25.302476968253 -6.476533489958299 M-25.302476968253 -6.476533489958299 C-25.168775400601582 -6.754167655941733, -25.035073832950165 -7.031801821925167, -24.857463901968003 -7.400612643853359 M-25.302476968253 -6.476533489958299 C-25.195725392231527 -6.6982054216847065, -25.088973816210054 -6.919877353411115, -24.857463901968003 -7.400612643853359 M-24.857463901968003 -7.400612643853359 C-24.69211019366897 -7.6942148968168995, -24.52675648536994 -7.98781714978044, -24.354159208085537 -8.294281092968404 M-24.857463901968003 -7.400612643853359 C-24.728199520486477 -7.630134642611804, -24.59893513900495 -7.859656641370248, -24.354159208085537 -8.294281092968404 M-24.354159208085537 -8.294281092968404 C-24.15919304402697 -8.593801476707908, -23.964226879968404 -8.89332186044741, -23.794631073551294 -9.153866561954715 M-24.354159208085537 -8.294281092968404 C-24.14090771088417 -8.621892658714705, -23.927656213682802 -8.949504224461005, -23.794631073551294 -9.153866561954715 M-23.794631073551294 -9.153866561954715 C-23.552526201483417 -9.478265034318083, -23.310421329415544 -9.802663506681451, -23.18117871948848 -9.975836829739734 M-23.794631073551294 -9.153866561954715 C-23.552052310549147 -9.478900004997653, -23.309473547547 -9.803933448040592, -23.18117871948848 -9.975836829739734 M-23.18117871948848 -9.975836829739734 C-22.97639680176543 -10.216385322718446, -22.77161488404238 -10.45693381569716, -22.516322953205055 -10.756814244181063 M-23.18117871948848 -9.975836829739734 C-22.947917197552517 -10.249839086362318, -22.71465567561656 -10.523841342984904, -22.516322953205055 -10.756814244181063 M-22.516322953205055 -10.756814244181063 C-22.258554601476938 -11.022981230515603, -22.00078624974882 -11.289148216850142, -21.80279580965579 -11.493589601563633 M-22.516322953205055 -10.756814244181063 C-22.305605931593252 -10.974396869184462, -22.09488890998145 -11.191979494187862, -21.80279580965579 -11.493589601563633 M-21.80279580965579 -11.493589601563633 C-21.64578612881226 -11.636181639457217, -21.488776447968736 -11.7787736773508, -21.043529324924627 -12.18313533390614 M-21.80279580965579 -11.493589601563633 C-21.59664104544148 -11.68081390386691, -21.39048628122717 -11.868038206170189, -21.043529324924627 -12.18313533390614 M-21.043529324924627 -12.18313533390614 C-20.875980176443395 -12.316751321149829, -20.708431027962163 -12.450367308393519, -20.241643487859463 -12.822617949887302 M-21.043529324924627 -12.18313533390614 C-20.74576453329921 -12.420594831373526, -20.44799974167379 -12.658054328840914, -20.241643487859463 -12.822617949887302 M-20.241643487859463 -12.822617949887302 C-20.034586146738196 -12.967052187685667, -19.827528805616925 -13.11148642548403, -19.400433419368788 -13.409409678269444 M-20.241643487859463 -12.822617949887302 C-20.060660667871172 -12.948863730491128, -19.87967784788288 -13.075109511094954, -19.400433419368788 -13.409409678269444 M-19.400433419368788 -13.409409678269444 C-19.128080864078147 -13.5745113978079, -18.85572830878751 -13.739613117346357, -18.523355832063007 -13.941099265974229 M-19.400433419368788 -13.409409678269444 C-19.080357695769923 -13.603441462888814, -18.760281972171057 -13.797473247508183, -18.523355832063007 -13.941099265974229 M-18.523355832063007 -13.941099265974229 C-18.21361049336014 -14.102693210774158, -17.903865154657268 -14.264287155574088, -17.614014825880936 -14.415501886438705 M-18.523355832063007 -13.941099265974229 C-18.174983968423078 -14.122844644092353, -17.82661210478315 -14.304590022210476, -17.614014825880936 -14.415501886438705 M-17.614014825880936 -14.415501886438705 C-17.27555955658374 -14.565325994237726, -16.937104287286548 -14.71515010203675, -16.676147078069995 -14.830668117536344 M-17.614014825880936 -14.415501886438705 C-17.342163838078303 -14.535842254565898, -17.07031285027567 -14.65618262269309, -16.676147078069995 -14.830668117536344 M-16.676147078069995 -14.830668117536344 C-16.321858514834627 -14.961049583814537, -15.967569951599259 -15.091431050092732, -15.713606488377943 -15.184891952170695 M-16.676147078069995 -14.830668117536344 C-16.330310649073233 -14.957939120284058, -15.98447422007647 -15.085210123031773, -15.713606488377943 -15.184891952170695 M-15.713606488377943 -15.184891952170695 C-15.428310180317863 -15.269566398852046, -15.143013872257782 -15.354240845533397, -14.730348342552134 -15.476717808624466 M-15.713606488377943 -15.184891952170695 C-15.458993250189376 -15.260459824772902, -15.20438001200081 -15.336027697375108, -14.730348342552134 -15.476717808624466 M-14.730348342552134 -15.476717808624466 C-14.466723727136246 -15.536888406781754, -14.203099111720359 -15.597059004939045, -13.730413059221963 -15.704946511857043 M-14.730348342552134 -15.476717808624466 C-14.408465413614797 -15.550185486672001, -14.08658248467746 -15.623653164719537, -13.730413059221963 -15.704946511857043 M-13.730413059221963 -15.704946511857043 C-13.484066291855312 -15.74477394675717, -13.237719524488663 -15.784601381657298, -12.717909586952107 -15.868640221171937 M-13.730413059221963 -15.704946511857043 C-13.347328322988568 -15.76688068114476, -12.964243586755176 -15.828814850432476, -12.717909586952107 -15.868640221171937 M-12.717909586952107 -15.868640221171937 C-12.340729554005582 -15.90502632532493, -11.963549521059058 -15.941412429477925, -11.696998519691407 -15.967126284005381 M-12.717909586952107 -15.868640221171937 C-12.458104930694132 -15.89370326390033, -12.198300274436157 -15.918766306628724, -11.696998519691407 -15.967126284005381 M-11.696998519691407 -15.967126284005381 C-11.371884642598761 -15.97755205324797, -11.046770765506114 -15.987977822490558, -10.671875000000005 -16 M-11.696998519691407 -15.967126284005381 C-11.358215246502349 -15.977990404174916, -11.01943197331329 -15.988854524344452, -10.671875000000005 -16 M-10.671875000000005 -16 C-10.671875000000004 -16, -10.671875000000002 -16, -10.671875 -16 M-10.671875000000005 -16 C-10.671875000000004 -16, -10.671875000000004 -16, -10.671875 -16\" stroke=\"#9370DB\" stroke-width=\"1.3\" fill=\"none\" stroke-dasharray=\"0 0\" style=\"\"></path></g><g class=\"label\" style=\"\" transform=\"translate(0, -8.5)\"><rect></rect><g><rect class=\"background\" style=\"stroke: none\"></rect><text y=\"-10.1\" style=\"\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">task</tspan></tspan></text></g></g></g><g class=\"node default  \" id=\"mmd-0-flowchart-M-4\" data-look=\"classic\" transform=\"translate(626.373779296875, 43.39999961853027)\"><rect class=\"basic label-container\" style=\"\" x=\"-96.30078125\" y=\"-32.29999923706055\" width=\"192.6015625\" height=\"64.5999984741211\"></rect><g class=\"label\" style=\"\" transform=\"translate(0, -17.299999237060547)\"><rect></rect><g><rect class=\"background\" style=\"stroke: none\"></rect><text y=\"-10.1\" style=\"\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">Model</tspan></tspan><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">LiteLLM</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> →</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> Ollama</tspan></tspan></text></g></g></g><g class=\"node default  \" id=\"mmd-0-flowchart-E-8\" data-look=\"classic\" transform=\"translate(626.373779296875, 157.99999809265137)\"><rect class=\"basic label-container\" style=\"\" x=\"-94.3828125\" y=\"-32.29999923706055\" width=\"188.765625\" height=\"64.5999984741211\"></rect><g class=\"label\" style=\"\" transform=\"translate(0, -17.299999237060547)\"><rect></rect><g><rect class=\"background\" style=\"stroke: none\"></rect><text y=\"-10.1\" style=\"\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">Environment</tspan></tspan><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">podman</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> container</tspan></tspan></text></g></g></g><g class=\"node default  \" id=\"mmd-0-flowchart-R-12\" data-look=\"classic\" transform=\"translate(626.373779296875, 256.2999973297119)\"><g class=\"basic label-container outer-path\"><path d=\"M-80.6640625 -16 C-18.631854632561534 -16, 43.40035323487693 -16, 80.6640625 -16 C80.6640625 -16, 80.6640625 -16, 80.6640625 -16 C80.87991651065965 -15.993077982012489, 81.09577052131931 -15.986155964024977, 81.6891860196914 -15.967126284005381 C81.92083088349095 -15.944779782588347, 82.15247574729051 -15.922433281171314, 82.71009708695209 -15.868640221171939 C83.05377635771691 -15.813076821947234, 83.39745562848174 -15.757513422722528, 83.72260055922196 -15.704946511857047 C84.12113094581157 -15.613984551771782, 84.5196613324012 -15.523022591686518, 84.72253584255212 -15.476717808624471 C85.0836434636128 -15.369542962186244, 85.44475108467348 -15.262368115748018, 85.70579398837793 -15.184891952170698 C86.01151924905965 -15.072382230146498, 86.31724450974136 -14.9598725081223, 86.66833457806999 -14.830668117536348 C86.88415844883791 -14.735129292135046, 87.09998231960583 -14.639590466733743, 87.60620232588093 -14.415501886438706 C87.88180260467432 -14.271721397522597, 88.15740288346771 -14.12794090860649, 88.515543332063 -13.941099265974232 C88.82334231634648 -13.754509712873977, 89.13114130062996 -13.567920159773724, 89.39262091936878 -13.409409678269451 C89.68332592726249 -13.206626449179765, 89.9740309351562 -13.00384322009008, 90.23383098785945 -12.822617949887306 C90.45131038475837 -12.649183918230223, 90.66878978165728 -12.475749886573142, 91.0357168249246 -12.183135333906153 C91.27061035430985 -11.969811245460686, 91.50550388369511 -11.75648715701522, 91.79498330965578 -11.493589601563642 C92.00831009783309 -11.273312178315528, 92.22163688601042 -11.053034755067417, 92.50851045320505 -10.756814244181072 C92.66522902999797 -10.572723686340462, 92.82194760679089 -10.388633128499851, 93.17336621948847 -9.975836829739738 C93.3514770899828 -9.737184489511444, 93.52958796047713 -9.49853214928315, 93.78681857355129 -9.153866561954718 C94.00252087589901 -8.822489901370298, 94.21822317824672 -8.491113240785879, 94.34634670808553 -8.294281092968403 C94.45769276837619 -8.096574887911126, 94.56903882866683 -7.89886868285385, 94.849651401968 -7.400612643853364 C95.01829551570714 -7.050419533268087, 95.18693962944626 -6.700226422682809, 95.294664468253 -6.476533489958305 C95.41771413579004 -6.172598432138363, 95.54076380332705 -5.8686633743184204, 95.67955725279616 -5.52584087074093 C95.78186918585301 -5.217693629566487, 95.88418111890985 -4.909546388392043, 96.00274814858656 -4.552441386096524 C96.09002016939154 -4.219635346834094, 96.17729219019651 -3.886829307571665, 96.26290909490918 -3.560334943301032 C96.32194345970846 -3.2572059569741203, 96.38097782450775 -2.9540769706472085, 96.4589710346312 -2.5535983205340735 C96.49752174463522 -2.254606626441695, 96.53607245463922 -1.9556149323493157, 96.59012830718717 -1.536368414522911 C96.61541857969489 -1.1424520062747445, 96.6407088522026 -0.748535598026578, 96.655841959211 -0.5128252411464826 C96.655841959211 -0.12399532428341381, 96.655841959211 0.264834592579655, 96.655841959211 0.5128252411464788 C96.64165509808288 0.7337970546451885, 96.62746823695475 0.9547688681438982, 96.59012830718717 1.5363684145229002 C96.55166631708427 1.834672014582037, 96.51320432698135 2.1329756146411736, 96.4589710346312 2.5535983205340624 C96.38122695386161 2.9527977440686057, 96.30348287309202 3.351997167603149, 96.26290909490918 3.5603349433010285 C96.18292169723306 3.8653615573975184, 96.10293429955694 4.170388171494008, 96.00274814858658 4.552441386096513 C95.93682323386165 4.750996725539283, 95.87089831913671 4.9495520649820515, 95.67955725279617 5.525840870740919 C95.56156570202194 5.817282282364706, 95.44357415124772 6.108723693988495, 95.294664468253 6.4765334899583005 C95.14893865979518 6.7791362492537655, 95.00321285133737 7.081739008549231, 94.849651401968 7.400612643853361 C94.65529131955026 7.7457186512785405, 94.46093123713253 8.09082465870372, 94.34634670808553 8.294281092968399 C94.16954878096188 8.565890185921162, 93.99275085383822 8.837499278873924, 93.7868185735513 9.15386656195471 C93.64844567060976 9.339273645865582, 93.51007276766822 9.524680729776454, 93.17336621948849 9.975836829739734 C92.95418292083565 10.233302004220358, 92.73499962218281 10.490767178700983, 92.50851045320505 10.756814244181063 C92.27359377396986 10.999385002509442, 92.0386770947347 11.24195576083782, 91.79498330965579 11.493589601563638 C91.59880259923786 11.671755732108045, 91.40262188881992 11.849921862652451, 91.03571682492462 12.183135333906142 C90.77916475107556 12.387728785663368, 90.52261267722649 12.592322237420596, 90.23383098785946 12.822617949887304 C89.93555756216496 13.030680579603299, 89.63728413647044 13.238743209319294, 89.39262091936878 13.409409678269446 C89.12223721645506 13.573317867926756, 88.85185351354133 13.737226057584063, 88.515543332063 13.94109926597423 C88.23408966202219 14.087933465354844, 87.95263599198138 14.234767664735456, 87.60620232588093 14.415501886438705 C87.38796537693504 14.512108909967973, 87.16972842798914 14.608715933497242, 86.66833457806999 14.830668117536346 C86.38673705315514 14.93429860976399, 86.10513952824031 15.037929101991637, 85.70579398837793 15.184891952170695 C85.43778987724143 15.264434165573727, 85.16978576610491 15.343976378976757, 84.72253584255213 15.476717808624468 C84.39136199456627 15.552306078315917, 84.0601881465804 15.627894348007368, 83.72260055922196 15.704946511857045 C83.39941570736706 15.757196532368988, 83.07623085551215 15.809446552880932, 82.7100970869521 15.868640221171937 C82.49059749515125 15.889815082806084, 82.27109790335038 15.910989944440232, 81.6891860196914 15.967126284005381 C81.43991283945748 15.975119989714672, 81.19063965922355 15.983113695423963, 80.6640625 16 C80.6640625 16, 80.6640625 16, 80.6640625 16 C32.16199232727942 16, -16.340077845441158 16, -80.6640625 16 C-81.02494677278555 15.98842714379039, -81.38583104557112 15.976854287580782, -81.6891860196914 15.967126284005381 C-81.89953149533392 15.946834508947594, -82.10987697097643 15.926542733889807, -82.7100970869521 15.868640221171937 C-82.9422405188332 15.831109071404603, -83.1743839507143 15.793577921637269, -83.72260055922196 15.704946511857045 C-83.96368849247058 15.649919764338838, -84.2047764257192 15.594893016820633, -84.72253584255212 15.476717808624471 C-84.98156513570318 15.399839274089741, -85.24059442885424 15.322960739555011, -85.70579398837792 15.184891952170702 C-86.06708106833015 15.05193496704712, -86.4283681482824 14.91897798192354, -86.66833457806999 14.830668117536348 C-86.94737355801244 14.707145838513068, -87.2264125379549 14.583623559489789, -87.60620232588093 14.415501886438708 C-87.84799594978082 14.289358307726339, -88.08978957368073 14.16321472901397, -88.515543332063 13.941099265974234 C-88.7504551537483 13.798694339173503, -88.98536697543362 13.656289412372772, -89.39262091936877 13.409409678269457 C-89.69544453243508 13.19817303481733, -89.99826814550138 12.986936391365203, -90.23383098785945 12.822617949887308 C-90.4252621002514 12.669956731950565, -90.61669321264337 12.517295514013822, -91.0357168249246 12.183135333906154 C-91.3119764821693 11.93224362262651, -91.588236139414 11.681351911346866, -91.79498330965578 11.493589601563649 C-92.01110910897938 11.270421969503895, -92.227234908303 11.047254337444143, -92.50851045320505 10.756814244181069 C-92.64193482541931 10.600086384516347, -92.77535919763356 10.443358524851625, -93.17336621948847 9.97583682973974 C-93.31848072340433 9.781396614695764, -93.46359522732018 9.58695639965179, -93.78681857355129 9.15386656195472 C-93.95892362470501 8.889466986705424, -94.13102867585873 8.625067411456127, -94.34634670808553 8.29428109296841 C-94.4926715946336 8.034466439900836, -94.63899648118169 7.774651786833262, -94.849651401968 7.400612643853366 C-95.01640109625802 7.05435333578825, -95.18315079054804 6.708094027723134, -95.294664468253 6.476533489958307 C-95.39918609380369 6.218363054059928, -95.5037077193544 5.9601926181615505, -95.67955725279616 5.525840870740931 C-95.7822734652589 5.216476004409109, -95.88498967772165 4.907111138077286, -96.00274814858656 4.552441386096519 C-96.08034972432176 4.256512945082516, -96.15795130005698 3.960584504068513, -96.26290909490918 3.5603349433010343 C-96.33482766229346 3.1910482997773446, -96.40674622967775 2.8217616562536545, -96.4589710346312 2.5535983205340753 C-96.50470192359248 2.198918576335896, -96.55043281255375 1.8442388321377168, -96.59012830718717 1.5363684145229202 C-96.61370250664612 1.1691812291983892, -96.63727670610508 0.8019940438738581, -96.655841959211 0.5128252411464846 C-96.655841959211 0.2504954233881773, -96.655841959211 -0.011834394370130008, -96.655841959211 -0.5128252411464769 C-96.63601091338356 -0.8217097872409519, -96.61617986755613 -1.130594333335427, -96.59012830718717 -1.5363684145228982 C-96.5416514414666 -1.9123454122117756, -96.49317457574602 -2.288322409900653, -96.4589710346312 -2.5535983205340678 C-96.3818311921201 -2.9496951083170426, -96.30469134960902 -3.345791896100018, -96.26290909490918 -3.5603349433010267 C-96.18753063972605 -3.8477856621434356, -96.11215218454292 -4.135236380985845, -96.00274814858658 -4.552441386096511 C-95.92222344472304 -4.794968964264222, -95.84169874085953 -5.037496542431934, -95.67955725279617 -5.525840870740911 C-95.58825172027946 -5.751367301329567, -95.49694618776275 -5.976893731918223, -95.294664468253 -6.476533489958299 C-95.17981905204292 -6.715012454016807, -95.06497363583281 -6.953491418075315, -94.849651401968 -7.400612643853359 C-94.7395886687826 -7.596040171684292, -94.62952593559721 -7.791467699515225, -94.34634670808553 -8.294281092968404 C-94.2063850909498 -8.509299721845492, -94.06642347381406 -8.72431835072258, -93.7868185735513 -9.153866561954715 C-93.55502762548056 -9.464445315779718, -93.32323667740984 -9.775024069604722, -93.17336621948849 -9.975836829739734 C-93.04022014727953 -10.132237782382512, -92.90707407507055 -10.288638735025291, -92.50851045320505 -10.756814244181063 C-92.31830395288438 -10.95321807200626, -92.1280974525637 -11.149621899831459, -91.79498330965579 -11.493589601563633 C-91.61227287782957 -11.659522381495087, -91.42956244600336 -11.825455161426541, -91.03571682492463 -12.18313533390614 C-90.81322443845754 -12.360567091342585, -90.59073205199044 -12.53799884877903, -90.23383098785946 -12.822617949887302 C-89.97934957727617 -13.000133165587503, -89.72486816669286 -13.177648381287703, -89.3926209193688 -13.409409678269444 C-89.13198881513131 -13.567406391502464, -88.8713567108938 -13.725403104735486, -88.515543332063 -13.941099265974229 C-88.1694663077211 -14.12164742790049, -87.82338928337919 -14.302195589826749, -87.60620232588093 -14.415501886438705 C-87.32624932034038 -14.539428777480659, -87.04629631479982 -14.66335566852261, -86.66833457806999 -14.830668117536344 C-86.39397068958728 -14.931636564689965, -86.11960680110457 -15.032605011843588, -85.70579398837795 -15.184891952170695 C-85.3817787276171 -15.281057980773703, -85.05776346685626 -15.377224009376711, -84.72253584255213 -15.476717808624466 C-84.32651022983447 -15.567108070418634, -83.9304846171168 -15.6574983322128, -83.72260055922196 -15.704946511857043 C-83.32750273718506 -15.768822863694599, -82.93240491514817 -15.832699215532152, -82.7100970869521 -15.868640221171937 C-82.49553517513425 -15.889338750756552, -82.28097326331641 -15.910037280341168, -81.6891860196914 -15.967126284005381 C-81.39582239015986 -15.976533884606793, -81.10245876062832 -15.985941485208205, -80.6640625 -16 C-80.6640625 -16, -80.6640625 -16, -80.6640625 -16\" stroke=\"none\" stroke-width=\"0\" fill=\"#ECECFF\" style=\"\"></path><path d=\"M-80.6640625 -16 C-31.84244592998251 -16, 16.97917064003498 -16, 80.6640625 -16 M-80.6640625 -16 C-42.7444692782688 -16, -4.8248760565376045 -16, 80.6640625 -16 M80.6640625 -16 C80.6640625 -16, 80.6640625 -16, 80.6640625 -16 M80.6640625 -16 C80.6640625 -16, 80.6640625 -16, 80.6640625 -16 M80.6640625 -16 C80.95543924729049 -15.990656114844827, 81.24681599458098 -15.981312229689653, 81.6891860196914 -15.967126284005381 M80.6640625 -16 C81.0157910303687 -15.988720750629128, 81.3675195607374 -15.977441501258257, 81.6891860196914 -15.967126284005381 M81.6891860196914 -15.967126284005381 C81.94642784927791 -15.942310474083735, 82.20366967886442 -15.917494664162088, 82.71009708695209 -15.868640221171939 M81.6891860196914 -15.967126284005381 C81.94775754818531 -15.942182199629334, 82.20632907667922 -15.917238115253287, 82.71009708695209 -15.868640221171939 M82.71009708695209 -15.868640221171939 C83.03584407634801 -15.815975974132037, 83.36159106574395 -15.763311727092136, 83.72260055922196 -15.704946511857047 M82.71009708695209 -15.868640221171939 C82.95686141606619 -15.828745278126723, 83.2036257451803 -15.78885033508151, 83.72260055922196 -15.704946511857047 M83.72260055922196 -15.704946511857047 C84.12169953261576 -15.613854775544104, 84.52079850600956 -15.52276303923116, 84.72253584255212 -15.476717808624471 M83.72260055922196 -15.704946511857047 C84.066865261817 -15.626370340026863, 84.41112996441204 -15.54779416819668, 84.72253584255212 -15.476717808624471 M84.72253584255212 -15.476717808624471 C84.9514771941321 -15.40876921721321, 85.18041854571209 -15.340820625801948, 85.70579398837793 -15.184891952170698 M84.72253584255212 -15.476717808624471 C85.00691494731818 -15.392315583066289, 85.29129405208423 -15.307913357508106, 85.70579398837793 -15.184891952170698 M85.70579398837793 -15.184891952170698 C85.97377994562596 -15.086270642668389, 86.24176590287401 -14.987649333166079, 86.66833457806999 -14.830668117536348 M85.70579398837793 -15.184891952170698 C86.00573828617992 -15.074509677924873, 86.3056825839819 -14.964127403679049, 86.66833457806999 -14.830668117536348 M86.66833457806999 -14.830668117536348 C86.88276303072965 -14.735747002337966, 87.09719148338931 -14.640825887139584, 87.60620232588093 -14.415501886438706 M86.66833457806999 -14.830668117536348 C86.91446436462671 -14.721713762208394, 87.16059415118343 -14.612759406880437, 87.60620232588093 -14.415501886438706 M87.60620232588093 -14.415501886438706 C87.84480636512986 -14.29102231199572, 88.0834104043788 -14.166542737552735, 88.515543332063 -13.941099265974232 M87.60620232588093 -14.415501886438706 C87.91332924785634 -14.255273967968318, 88.22045616983175 -14.095046049497927, 88.515543332063 -13.941099265974232 M88.515543332063 -13.941099265974232 C88.85666676540741 -13.734308236017043, 89.19779019875182 -13.527517206059853, 89.39262091936878 -13.409409678269451 M88.515543332063 -13.941099265974232 C88.78519083937859 -13.777637362414884, 89.05483834669417 -13.614175458855536, 89.39262091936878 -13.409409678269451 M89.39262091936878 -13.409409678269451 C89.56836923734622 -13.286815259670453, 89.74411755532365 -13.164220841071456, 90.23383098785945 -12.822617949887306 M89.39262091936878 -13.409409678269451 C89.67368065135672 -13.213354576114366, 89.95474038334466 -13.017299473959282, 90.23383098785945 -12.822617949887306 M90.23383098785945 -12.822617949887306 C90.5247358781582 -12.5906290411783, 90.81564076845694 -12.358640132469295, 91.0357168249246 -12.183135333906153 M90.23383098785945 -12.822617949887306 C90.54154854525898 -12.577221386569285, 90.84926610265852 -12.331824823251264, 91.0357168249246 -12.183135333906153 M91.0357168249246 -12.183135333906153 C91.22002437671864 -12.015752091877411, 91.40433192851266 -11.848368849848672, 91.79498330965578 -11.493589601563642 M91.0357168249246 -12.183135333906153 C91.22620034451668 -12.01014324133038, 91.41668386410875 -11.837151148754609, 91.79498330965578 -11.493589601563642 M91.79498330965578 -11.493589601563642 C92.0372629193324 -11.24341601304664, 92.27954252900903 -10.993242424529639, 92.50851045320505 -10.756814244181072 M91.79498330965578 -11.493589601563642 C91.99986649857186 -11.282030887785144, 92.20474968748795 -11.070472174006646, 92.50851045320505 -10.756814244181072 M92.50851045320505 -10.756814244181072 C92.76533450121508 -10.455134103686172, 93.0221585492251 -10.153453963191271, 93.17336621948847 -9.975836829739738 M92.50851045320505 -10.756814244181072 C92.66336857878159 -10.574909078201898, 92.81822670435812 -10.393003912222722, 93.17336621948847 -9.975836829739738 M93.17336621948847 -9.975836829739738 C93.34094222185723 -9.75130025305348, 93.50851822422598 -9.52676367636722, 93.78681857355129 -9.153866561954718 M93.17336621948847 -9.975836829739738 C93.30478684661982 -9.799745162049172, 93.43620747375115 -9.623653494358608, 93.78681857355129 -9.153866561954718 M93.78681857355129 -9.153866561954718 C93.94138786346262 -8.916406624984948, 94.09595715337396 -8.678946688015175, 94.34634670808553 -8.294281092968403 M93.78681857355129 -9.153866561954718 C93.99977629493709 -8.826706314750965, 94.21273401632291 -8.499546067547211, 94.34634670808553 -8.294281092968403 M94.34634670808553 -8.294281092968403 C94.47757924301558 -8.06126443846496, 94.60881177794563 -7.828247783961515, 94.849651401968 -7.400612643853364 M94.34634670808553 -8.294281092968403 C94.50740731577223 -8.008301674865644, 94.66846792345893 -7.722322256762886, 94.849651401968 -7.400612643853364 M94.849651401968 -7.400612643853364 C95.00700317923521 -7.073868311569319, 95.16435495650242 -6.7471239792852735, 95.294664468253 -6.476533489958305 M94.849651401968 -7.400612643853364 C94.94015096933511 -7.21268835583502, 95.03065053670223 -7.024764067816676, 95.294664468253 -6.476533489958305 M95.294664468253 -6.476533489958305 C95.43912059354234 -6.119724067624454, 95.58357671883167 -5.7629146452906035, 95.67955725279616 -5.52584087074093 M95.294664468253 -6.476533489958305 C95.42469686988095 -6.155350943931828, 95.55472927150888 -5.834168397905351, 95.67955725279616 -5.52584087074093 M95.67955725279616 -5.52584087074093 C95.77208529680071 -5.24716114454098, 95.86461334080526 -4.96848141834103, 96.00274814858656 -4.552441386096524 M95.67955725279616 -5.52584087074093 C95.74618741568393 -5.325161436197723, 95.8128175785717 -5.124482001654517, 96.00274814858656 -4.552441386096524 M96.00274814858656 -4.552441386096524 C96.07096600898919 -4.292297118573582, 96.13918386939181 -4.03215285105064, 96.26290909490918 -3.560334943301032 M96.00274814858656 -4.552441386096524 C96.06151961752833 -4.328320303305789, 96.1202910864701 -4.104199220515055, 96.26290909490918 -3.560334943301032 M96.26290909490918 -3.560334943301032 C96.33595696397144 -3.185249574338873, 96.40900483303372 -2.810164205376714, 96.4589710346312 -2.5535983205340735 M96.26290909490918 -3.560334943301032 C96.32212058151515 -3.256296473931513, 96.38133206812111 -2.952258004561994, 96.4589710346312 -2.5535983205340735 M96.4589710346312 -2.5535983205340735 C96.49034878054918 -2.3102387194309975, 96.52172652646716 -2.0668791183279214, 96.59012830718717 -1.536368414522911 M96.4589710346312 -2.5535983205340735 C96.50291873934441 -2.212748601234389, 96.5468664440576 -1.8718988819347047, 96.59012830718717 -1.536368414522911 M96.59012830718717 -1.536368414522911 C96.60854272656142 -1.249548968917017, 96.62695714593569 -0.9627295233111228, 96.655841959211 -0.5128252411464826 M96.59012830718717 -1.536368414522911 C96.61610716304858 -1.1317267647264984, 96.64208601890998 -0.7270851149300857, 96.655841959211 -0.5128252411464826 M96.655841959211 -0.5128252411464826 C96.655841959211 -0.24268317232584208, 96.655841959211 0.02745889649479849, 96.655841959211 0.5128252411464788 M96.655841959211 -0.5128252411464826 C96.655841959211 -0.1874968329909893, 96.655841959211 0.13783157516450406, 96.655841959211 0.5128252411464788 M96.655841959211 0.5128252411464788 C96.64254079509547 0.7200016087524126, 96.62923963097992 0.9271779763583465, 96.59012830718717 1.5363684145229002 M96.655841959211 0.5128252411464788 C96.62994056934141 0.9162602955908784, 96.60403917947184 1.319695350035278, 96.59012830718717 1.5363684145229002 M96.59012830718717 1.5363684145229002 C96.55800797710161 1.7854873517899126, 96.52588764701605 2.034606289056925, 96.4589710346312 2.5535983205340624 M96.59012830718717 1.5363684145229002 C96.53978221701045 1.926842747973465, 96.48943612683375 2.31731708142403, 96.4589710346312 2.5535983205340624 M96.4589710346312 2.5535983205340624 C96.39398015011942 2.8873127766737867, 96.32898926560763 3.221027232813511, 96.26290909490918 3.5603349433010285 M96.4589710346312 2.5535983205340624 C96.3982674565366 2.865298364344054, 96.33756387844201 3.176998408154046, 96.26290909490918 3.5603349433010285 M96.26290909490918 3.5603349433010285 C96.18376598421713 3.8621419252109512, 96.10462287352509 4.163948907120874, 96.00274814858658 4.552441386096513 M96.26290909490918 3.5603349433010285 C96.19653680197423 3.8134412621957043, 96.13016450903929 4.06654758109038, 96.00274814858658 4.552441386096513 M96.00274814858658 4.552441386096513 C95.87353345155444 4.941615465991176, 95.74431875452231 5.330789545885838, 95.67955725279617 5.525840870740919 M96.00274814858658 4.552441386096513 C95.87922214019615 4.924482042171788, 95.75569613180573 5.296522698247063, 95.67955725279617 5.525840870740919 M95.67955725279617 5.525840870740919 C95.57972505529158 5.772428328701499, 95.47989285778698 6.019015786662077, 95.294664468253 6.4765334899583005 M95.67955725279617 5.525840870740919 C95.58432051654651 5.761077450554614, 95.48908378029685 5.9963140303683105, 95.294664468253 6.4765334899583005 M95.294664468253 6.4765334899583005 C95.13672883258215 6.804490216710086, 94.97879319691128 7.132446943461872, 94.849651401968 7.400612643853361 M95.294664468253 6.4765334899583005 C95.13674142132507 6.804464075916045, 94.97881837439714 7.13239466187379, 94.849651401968 7.400612643853361 M94.849651401968 7.400612643853361 C94.6559336924054 7.744578053226958, 94.46221598284278 8.088543462600555, 94.34634670808553 8.294281092968399 M94.849651401968 7.400612643853361 C94.7005001418969 7.665445809312437, 94.55134888182577 7.930278974771513, 94.34634670808553 8.294281092968399 M94.34634670808553 8.294281092968399 C94.22570700775081 8.479616068977991, 94.10506730741608 8.664951044987584, 93.7868185735513 9.15386656195471 M94.34634670808553 8.294281092968399 C94.16439359702305 8.573809932811924, 93.98244048596057 8.85333877265545, 93.7868185735513 9.15386656195471 M93.7868185735513 9.15386656195471 C93.61105130673216 9.38937868676493, 93.43528403991303 9.624890811575149, 93.17336621948849 9.975836829739734 M93.7868185735513 9.15386656195471 C93.57192623703202 9.44180271579595, 93.35703390051275 9.729738869637188, 93.17336621948849 9.975836829739734 M93.17336621948849 9.975836829739734 C93.03876354937513 10.133948785163774, 92.90416087926178 10.292060740587816, 92.50851045320505 10.756814244181063 M93.17336621948849 9.975836829739734 C92.9293993670386 10.262414176734536, 92.68543251458871 10.548991523729336, 92.50851045320505 10.756814244181063 M92.50851045320505 10.756814244181063 C92.32178352438225 10.949625128756573, 92.13505659555945 11.142436013332082, 91.79498330965579 11.493589601563638 M92.50851045320505 10.756814244181063 C92.27896110537878 10.993842792163633, 92.04941175755252 11.230871340146205, 91.79498330965579 11.493589601563638 M91.79498330965579 11.493589601563638 C91.57151119888377 11.696541059818749, 91.34803908811173 11.89949251807386, 91.03571682492462 12.183135333906142 M91.79498330965579 11.493589601563638 C91.60677930295392 11.664511500845133, 91.41857529625204 11.835433400126629, 91.03571682492462 12.183135333906142 M91.03571682492462 12.183135333906142 C90.71687714877282 12.43740149095709, 90.39803747262101 12.691667648008037, 90.23383098785946 12.822617949887304 M91.03571682492462 12.183135333906142 C90.79704261341688 12.373471666196057, 90.55836840190914 12.563807998485972, 90.23383098785946 12.822617949887304 M90.23383098785946 12.822617949887304 C89.95827135157573 13.014836423374435, 89.682711715292 13.207054896861566, 89.39262091936878 13.409409678269446 M90.23383098785946 12.822617949887304 C90.01199940131261 12.97735806172778, 89.79016781476575 13.132098173568258, 89.39262091936878 13.409409678269446 M89.39262091936878 13.409409678269446 C89.16634552531191 13.54657915188854, 88.94007013125503 13.683748625507635, 88.515543332063 13.94109926597423 M89.39262091936878 13.409409678269446 C89.12070454410095 13.574246982914802, 88.84878816883311 13.739084287560157, 88.515543332063 13.94109926597423 M88.515543332063 13.94109926597423 C88.25935977158052 14.074750065384537, 88.00317621109805 14.208400864794841, 87.60620232588093 14.415501886438705 M88.515543332063 13.94109926597423 C88.20986029608258 14.100573910045886, 87.90417726010216 14.260048554117542, 87.60620232588093 14.415501886438705 M87.60620232588093 14.415501886438705 C87.2359117894532 14.579418522636772, 86.86562125302547 14.743335158834839, 86.66833457806999 14.830668117536346 M87.60620232588093 14.415501886438705 C87.35410603696992 14.527097435368894, 87.10200974805892 14.638692984299086, 86.66833457806999 14.830668117536346 M86.66833457806999 14.830668117536346 C86.30181051697028 14.96555236013232, 85.93528645587057 15.100436602728294, 85.70579398837793 15.184891952170695 M86.66833457806999 14.830668117536346 C86.31816295443356 14.959534511985554, 85.96799133079715 15.088400906434762, 85.70579398837793 15.184891952170695 M85.70579398837793 15.184891952170695 C85.32934193775533 15.296620944758347, 84.95288988713273 15.408349937346, 84.72253584255213 15.476717808624468 M85.70579398837793 15.184891952170695 C85.44730497442274 15.261610134676078, 85.18881596046754 15.33832831718146, 84.72253584255213 15.476717808624468 M84.72253584255213 15.476717808624468 C84.41436969944029 15.547054719817726, 84.10620355632845 15.617391631010985, 83.72260055922196 15.704946511857045 M84.72253584255213 15.476717808624468 C84.48659649856121 15.53056942424229, 84.25065715457029 15.584421039860109, 83.72260055922196 15.704946511857045 M83.72260055922196 15.704946511857045 C83.41553552252255 15.754590405665681, 83.10847048582315 15.804234299474317, 82.7100970869521 15.868640221171937 M83.72260055922196 15.704946511857045 C83.38723374466885 15.759166017625503, 83.05186693011574 15.81338552339396, 82.7100970869521 15.868640221171937 M82.7100970869521 15.868640221171937 C82.40844198466056 15.897740526096664, 82.10678688236901 15.92684083102139, 81.6891860196914 15.967126284005381 M82.7100970869521 15.868640221171937 C82.42711593688459 15.895939072384325, 82.14413478681708 15.923237923596712, 81.6891860196914 15.967126284005381 M81.6891860196914 15.967126284005381 C81.472934422138 15.97406105183072, 81.25668282458457 15.980995819656059, 80.6640625 16 M81.6891860196914 15.967126284005381 C81.43783327449991 15.975186677315234, 81.18648052930841 15.983247070625087, 80.6640625 16 M80.6640625 16 C80.6640625 16, 80.6640625 16, 80.6640625 16 M80.6640625 16 C80.6640625 16, 80.6640625 16, 80.6640625 16 M80.6640625 16 C17.761368043076985 16, -45.14132641384603 16, -80.6640625 16 M80.6640625 16 C31.684950781530006 16, -17.29416093693999 16, -80.6640625 16 M-80.6640625 16 C-80.88691750334682 15.992853473803617, -81.10977250669366 15.985706947607234, -81.6891860196914 15.967126284005381 M-80.6640625 16 C-81.06060923122844 15.987283518160892, -81.45715596245687 15.974567036321785, -81.6891860196914 15.967126284005381 M-81.6891860196914 15.967126284005381 C-82.09414750188971 15.92806013685515, -82.49910898408802 15.888993989704916, -82.7100970869521 15.868640221171937 M-81.6891860196914 15.967126284005381 C-81.9125813346626 15.945575606642285, -82.1359766496338 15.924024929279186, -82.7100970869521 15.868640221171937 M-82.7100970869521 15.868640221171937 C-82.99926361924024 15.821890018751542, -83.28843015152836 15.775139816331148, -83.72260055922196 15.704946511857045 M-82.7100970869521 15.868640221171937 C-83.05593844281536 15.812727272795737, -83.40177979867862 15.756814324419535, -83.72260055922196 15.704946511857045 M-83.72260055922196 15.704946511857045 C-84.09487279556457 15.619977803215217, -84.46714503190718 15.53500909457339, -84.72253584255212 15.476717808624471 M-83.72260055922196 15.704946511857045 C-84.09753423702001 15.619370346570541, -84.47246791481807 15.533794181284037, -84.72253584255212 15.476717808624471 M-84.72253584255212 15.476717808624471 C-85.0573955409665 15.377333207849508, -85.39225523938089 15.277948607074544, -85.70579398837792 15.184891952170702 M-84.72253584255212 15.476717808624471 C-84.95429803086307 15.407932007678331, -85.18606021917404 15.33914620673219, -85.70579398837792 15.184891952170702 M-85.70579398837792 15.184891952170702 C-86.00528188592827 15.074677637436396, -86.30476978347862 14.964463322702093, -86.66833457806999 14.830668117536348 M-85.70579398837792 15.184891952170702 C-85.9944576038764 15.07866107329005, -86.28312121937488 14.9724301944094, -86.66833457806999 14.830668117536348 M-86.66833457806999 14.830668117536348 C-86.88056727105061 14.736719000012977, -87.09279996403124 14.642769882489604, -87.60620232588093 14.415501886438708 M-86.66833457806999 14.830668117536348 C-86.87634325685822 14.73858884579502, -87.08435193564645 14.646509574053693, -87.60620232588093 14.415501886438708 M-87.60620232588093 14.415501886438708 C-87.8679943722992 14.278925143508111, -88.12978641871744 14.142348400577514, -88.515543332063 13.941099265974234 M-87.60620232588093 14.415501886438708 C-87.83979562217401 14.293636413386254, -88.07338891846709 14.1717709403338, -88.515543332063 13.941099265974234 M-88.515543332063 13.941099265974234 C-88.72557543415111 13.813776571402784, -88.93560753623923 13.686453876831333, -89.39262091936877 13.409409678269457 M-88.515543332063 13.941099265974234 C-88.70076166184155 13.828818825998754, -88.8859799916201 13.716538386023272, -89.39262091936877 13.409409678269457 M-89.39262091936877 13.409409678269457 C-89.6492399268117 13.230403367535056, -89.90585893425464 13.051397056800653, -90.23383098785945 12.822617949887308 M-89.39262091936877 13.409409678269457 C-89.67168617200291 13.214745838571961, -89.95075142463705 13.020081998874467, -90.23383098785945 12.822617949887308 M-90.23383098785945 12.822617949887308 C-90.48330556223938 12.62366861561655, -90.73278013661931 12.424719281345794, -91.0357168249246 12.183135333906154 M-90.23383098785945 12.822617949887308 C-90.53184152212 12.584962479207885, -90.82985205638056 12.347307008528462, -91.0357168249246 12.183135333906154 M-91.0357168249246 12.183135333906154 C-91.23539033081923 12.001797138924122, -91.43506383671385 11.82045894394209, -91.79498330965578 11.493589601563649 M-91.0357168249246 12.183135333906154 C-91.21600782401009 12.019399818775147, -91.39629882309559 11.85566430364414, -91.79498330965578 11.493589601563649 M-91.79498330965578 11.493589601563649 C-91.98477910024789 11.29760986525309, -92.17457489083999 11.101630128942533, -92.50851045320505 10.756814244181069 M-91.79498330965578 11.493589601563649 C-92.04453771540224 11.235904188832665, -92.29409212114872 10.978218776101679, -92.50851045320505 10.756814244181069 M-92.50851045320505 10.756814244181069 C-92.68052194280548 10.554759760765368, -92.85253343240592 10.352705277349665, -93.17336621948847 9.97583682973974 M-92.50851045320505 10.756814244181069 C-92.77091777448462 10.448575673206514, -93.0333250957642 10.140337102231959, -93.17336621948847 9.97583682973974 M-93.17336621948847 9.97583682973974 C-93.35555284118378 9.731723354210699, -93.5377394628791 9.487609878681658, -93.78681857355129 9.15386656195472 M-93.17336621948847 9.97583682973974 C-93.32478814926708 9.772945238657993, -93.47621007904569 9.570053647576245, -93.78681857355129 9.15386656195472 M-93.78681857355129 9.15386656195472 C-93.91462104952059 8.957527639095847, -94.0424235254899 8.761188716236976, -94.34634670808553 8.29428109296841 M-93.78681857355129 9.15386656195472 C-93.90999896787837 8.964628397701016, -94.03317936220544 8.775390233447311, -94.34634670808553 8.29428109296841 M-94.34634670808553 8.29428109296841 C-94.49132937879523 8.036849680035974, -94.63631204950492 7.779418267103539, -94.849651401968 7.400612643853366 M-94.34634670808553 8.29428109296841 C-94.51814317900607 7.989239062569921, -94.68993964992661 7.684197032171433, -94.849651401968 7.400612643853366 M-94.849651401968 7.400612643853366 C-95.02626287221084 7.033875147014022, -95.20287434245367 6.667137650174678, -95.294664468253 6.476533489958307 M-94.849651401968 7.400612643853366 C-94.96156711339663 7.168217274459215, -95.07348282482525 6.935821905065064, -95.294664468253 6.476533489958307 M-95.294664468253 6.476533489958307 C-95.44472547211024 6.1058799091987765, -95.59478647596748 5.735226328439246, -95.67955725279616 5.525840870740931 M-95.294664468253 6.476533489958307 C-95.44037995206496 6.116613427725555, -95.5860954358769 5.7566933654928025, -95.67955725279616 5.525840870740931 M-95.67955725279616 5.525840870740931 C-95.770733571518 5.2512323257243585, -95.86190989023982 4.976623780707786, -96.00274814858656 4.552441386096519 M-95.67955725279616 5.525840870740931 C-95.80774527789538 5.13975896313023, -95.93593330299461 4.753677055519529, -96.00274814858656 4.552441386096519 M-96.00274814858656 4.552441386096519 C-96.09041510029033 4.218129304152859, -96.1780820519941 3.8838172222091973, -96.26290909490918 3.5603349433010343 M-96.00274814858656 4.552441386096519 C-96.07838462438977 4.2640067228028995, -96.15402110019299 3.9755720595092794, -96.26290909490918 3.5603349433010343 M-96.26290909490918 3.5603349433010343 C-96.32035380125902 3.2653685171375604, -96.37779850760887 2.970402090974087, -96.4589710346312 2.5535983205340753 M-96.26290909490918 3.5603349433010343 C-96.3044611219426 3.3469740665084693, -96.34601314897601 3.133613189715904, -96.4589710346312 2.5535983205340753 M-96.4589710346312 2.5535983205340753 C-96.50739322971124 2.1780453375372804, -96.55581542479128 1.8024923545404854, -96.59012830718717 1.5363684145229202 M-96.4589710346312 2.5535983205340753 C-96.5087879089771 2.167228480561831, -96.55860478332299 1.7808586405895868, -96.59012830718717 1.5363684145229202 M-96.59012830718717 1.5363684145229202 C-96.60980578357902 1.2298758363468125, -96.62948325997087 0.9233832581707051, -96.655841959211 0.5128252411464846 M-96.59012830718717 1.5363684145229202 C-96.6143149985912 1.159641172759194, -96.63850168999524 0.7829139309954677, -96.655841959211 0.5128252411464846 M-96.655841959211 0.5128252411464846 C-96.655841959211 0.11825613501078508, -96.655841959211 -0.2763129711249145, -96.655841959211 -0.5128252411464769 M-96.655841959211 0.5128252411464846 C-96.655841959211 0.30304743564525105, -96.655841959211 0.09326963014401746, -96.655841959211 -0.5128252411464769 M-96.655841959211 -0.5128252411464769 C-96.63763901165188 -0.7963508425345065, -96.61943606409278 -1.0798764439225361, -96.59012830718717 -1.5363684145228982 M-96.655841959211 -0.5128252411464769 C-96.64142038499396 -0.7374529004619895, -96.62699881077694 -0.9620805597775022, -96.59012830718717 -1.5363684145228982 M-96.59012830718717 -1.5363684145228982 C-96.54148054731684 -1.9136708334904593, -96.4928327874465 -2.2909732524580204, -96.4589710346312 -2.5535983205340678 M-96.59012830718717 -1.5363684145228982 C-96.54570184026203 -1.8809313189961299, -96.50127537333688 -2.2254942234693615, -96.4589710346312 -2.5535983205340678 M-96.4589710346312 -2.5535983205340678 C-96.41253782790233 -2.7920230234251595, -96.36610462117343 -3.0304477263162513, -96.26290909490918 -3.5603349433010267 M-96.4589710346312 -2.5535983205340678 C-96.38367090496129 -2.940248571701002, -96.30837077529138 -3.3268988228679364, -96.26290909490918 -3.5603349433010267 M-96.26290909490918 -3.5603349433010267 C-96.21005421316362 -3.7618935148474995, -96.15719933141806 -3.9634520863939717, -96.00274814858658 -4.552441386096511 M-96.26290909490918 -3.5603349433010267 C-96.1847081804966 -3.8585489224468943, -96.10650726608402 -4.156762901592762, -96.00274814858658 -4.552441386096511 M-96.00274814858658 -4.552441386096511 C-95.89828347486832 -4.8670723391504795, -95.79381880115005 -5.181703292204447, -95.67955725279617 -5.525840870740911 M-96.00274814858658 -4.552441386096511 C-95.9282558422584 -4.776800344019796, -95.85376353593021 -5.001159301943081, -95.67955725279617 -5.525840870740911 M-95.67955725279617 -5.525840870740911 C-95.59522916637275 -5.734132874579405, -95.51090107994932 -5.942424878417899, -95.294664468253 -6.476533489958299 M-95.67955725279617 -5.525840870740911 C-95.5386836869942 -5.873801301876895, -95.39781012119222 -6.2217617330128805, -95.294664468253 -6.476533489958299 M-95.294664468253 -6.476533489958299 C-95.18828459684399 -6.69743356910373, -95.08190472543498 -6.918333648249161, -94.849651401968 -7.400612643853359 M-95.294664468253 -6.476533489958299 C-95.19785667435069 -6.67755694535143, -95.10104888044836 -6.878580400744561, -94.849651401968 -7.400612643853359 M-94.849651401968 -7.400612643853359 C-94.71255949977568 -7.644033198256243, -94.57546759758335 -7.887453752659127, -94.34634670808553 -8.294281092968404 M-94.849651401968 -7.400612643853359 C-94.65725200622282 -7.742237253550371, -94.46485261047764 -8.083861863247384, -94.34634670808553 -8.294281092968404 M-94.34634670808553 -8.294281092968404 C-94.21769869007505 -8.491918995462344, -94.08905067206459 -8.689556897956283, -93.7868185735513 -9.153866561954715 M-94.34634670808553 -8.294281092968404 C-94.1580143327548 -8.583610195800265, -93.96968195742407 -8.872939298632126, -93.7868185735513 -9.153866561954715 M-93.7868185735513 -9.153866561954715 C-93.64382162711858 -9.345469442884738, -93.50082468068587 -9.537072323814762, -93.17336621948849 -9.975836829739734 M-93.7868185735513 -9.153866561954715 C-93.54424035199648 -9.478899279507575, -93.30166213044164 -9.803931997060436, -93.17336621948849 -9.975836829739734 M-93.17336621948849 -9.975836829739734 C-93.03904477607898 -10.133618440275193, -92.90472333266946 -10.29140005081065, -92.50851045320505 -10.756814244181063 M-93.17336621948849 -9.975836829739734 C-92.92622442001112 -10.266143650172609, -92.67908262053376 -10.556450470605483, -92.50851045320505 -10.756814244181063 M-92.50851045320505 -10.756814244181063 C-92.33023195841459 -10.940901426988848, -92.15195346362412 -11.124988609796633, -91.79498330965579 -11.493589601563633 M-92.50851045320505 -10.756814244181063 C-92.32597965019762 -10.945292284343866, -92.14344884719019 -11.13377032450667, -91.79498330965579 -11.493589601563633 M-91.79498330965579 -11.493589601563633 C-91.62144473516989 -11.651192743332665, -91.44790616068398 -11.808795885101695, -91.03571682492463 -12.18313533390614 M-91.79498330965579 -11.493589601563633 C-91.53220044340273 -11.732242047841027, -91.26941757714968 -11.97089449411842, -91.03571682492463 -12.18313533390614 M-91.03571682492463 -12.18313533390614 C-90.77576163678782 -12.39044267874717, -90.51580644865099 -12.597750023588201, -90.23383098785946 -12.822617949887302 M-91.03571682492463 -12.18313533390614 C-90.74888508318921 -12.411876015026937, -90.46205334145377 -12.640616696147735, -90.23383098785946 -12.822617949887302 M-90.23383098785946 -12.822617949887302 C-89.99024290196893 -12.992534453846256, -89.74665481607839 -13.16245095780521, -89.3926209193688 -13.409409678269444 M-90.23383098785946 -12.822617949887302 C-90.03300457026864 -12.962705765163156, -89.83217815267783 -13.102793580439009, -89.3926209193688 -13.409409678269444 M-89.3926209193688 -13.409409678269444 C-89.15308903295437 -13.554615315459479, -88.91355714653994 -13.699820952649514, -88.515543332063 -13.941099265974229 M-89.3926209193688 -13.409409678269444 C-89.06154768065733 -13.610108221178645, -88.73047444194584 -13.810806764087847, -88.515543332063 -13.941099265974229 M-88.515543332063 -13.941099265974229 C-88.16255445272395 -14.125253338225242, -87.8095655733849 -14.309407410476256, -87.60620232588093 -14.415501886438705 M-88.515543332063 -13.941099265974229 C-88.25317336118347 -14.077977511726097, -87.99080339030392 -14.214855757477965, -87.60620232588093 -14.415501886438705 M-87.60620232588093 -14.415501886438705 C-87.35552419472522 -14.526469658998783, -87.1048460635695 -14.637437431558862, -86.66833457806999 -14.830668117536344 M-87.60620232588093 -14.415501886438705 C-87.37394673999869 -14.518314544691606, -87.14169115411644 -14.621127202944507, -86.66833457806999 -14.830668117536344 M-86.66833457806999 -14.830668117536344 C-86.37954618401172 -14.936944916080442, -86.09075778995344 -15.04322171462454, -85.70579398837795 -15.184891952170695 M-86.66833457806999 -14.830668117536344 C-86.46567451933495 -14.905248892519884, -86.26301446059993 -14.979829667503424, -85.70579398837795 -15.184891952170695 M-85.70579398837795 -15.184891952170695 C-85.37796814968152 -15.28218894030285, -85.0501423109851 -15.379485928435008, -84.72253584255213 -15.476717808624466 M-85.70579398837795 -15.184891952170695 C-85.45395350761105 -15.259636884924651, -85.20211302684415 -15.334381817678606, -84.72253584255213 -15.476717808624466 M-84.72253584255213 -15.476717808624466 C-84.43848648198927 -15.541550221577635, -84.1544371214264 -15.606382634530805, -83.72260055922196 -15.704946511857043 M-84.72253584255213 -15.476717808624466 C-84.34323416759364 -15.563290940758996, -83.96393249263514 -15.649864072893527, -83.72260055922196 -15.704946511857043 M-83.72260055922196 -15.704946511857043 C-83.38924471298526 -15.758840899863396, -83.05588886674856 -15.812735287869748, -82.7100970869521 -15.868640221171937 M-83.72260055922196 -15.704946511857043 C-83.39199895096742 -15.758395616025874, -83.06139734271288 -15.811844720194705, -82.7100970869521 -15.868640221171937 M-82.7100970869521 -15.868640221171937 C-82.42719041339525 -15.895931887724911, -82.1442837398384 -15.923223554277888, -81.6891860196914 -15.967126284005381 M-82.7100970869521 -15.868640221171937 C-82.38505778808342 -15.899996371416849, -82.06001848921473 -15.931352521661761, -81.6891860196914 -15.967126284005381 M-81.6891860196914 -15.967126284005381 C-81.31349865065428 -15.979173846699299, -80.93781128161716 -15.991221409393217, -80.6640625 -16 M-81.6891860196914 -15.967126284005381 C-81.32163637709417 -15.978912885651496, -80.95408673449693 -15.99069948729761, -80.6640625 -16 M-80.6640625 -16 C-80.6640625 -16, -80.6640625 -16, -80.6640625 -16 M-80.6640625 -16 C-80.6640625 -16, -80.6640625 -16, -80.6640625 -16\" stroke=\"#9370DB\" stroke-width=\"1.3\" fill=\"none\" stroke-dasharray=\"0 0\" style=\"\"></path></g><g class=\"label\" style=\"\" transform=\"translate(0, -8.5)\"><rect></rect><g><rect class=\"background\" style=\"stroke: none\"></rect><text y=\"-10.1\" style=\"\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">exit</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> status</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> +</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> submission</tspan></tspan></text></g></g></g></g></g></g><defs><filter id=\"mmd-0-drop-shadow\" height=\"130%\" width=\"130%\"><feDropShadow dx=\"4\" dy=\"4\" stdDeviation=\"0\" flood-opacity=\"0.06\" flood-color=\"#000000\"></feDropShadow></filter></defs><defs><filter id=\"mmd-0-drop-shadow-small\" height=\"150%\" width=\"150%\"><feDropShadow dx=\"2\" dy=\"2\" stdDeviation=\"0\" flood-opacity=\"0.06\" flood-color=\"#000000\"></feDropShadow></filter></defs></svg>\n",
    "</div>\n",
    "\n",
    "**Concept.** This is the **ReAct** loop (→ [L-ReAct](http://christianherta.de/lehre/ai-agents/lecture-02/lecture-02-ReAct.html)): the model's THOUGHT is the reasoning trace, the bash command is the action, and the command's output is the observation ([Yao et al., 2023](https://arxiv.org/html/2210.03629)). Everything around the model call is the **harness** (→ [L-Intro](http://christianherta.de/lehre/ai-agents/lecture-01/lecture-01-Intro.html)). The model is a given; this notebook is entirely about the harness."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b2b7cee5",
   "metadata": {},
   "source": [
    "## Talking to a Model\n",
    "\n",
    "**LiteLLM** exposes one function, `completion`, in the OpenAI chat format, and translates it to 100+ providers. The provider is chosen by a prefix in the model string: `ollama_chat/…`, `anthropic/…`, `openai/…` (BerriAI, 2026). A request is a list of **messages**, each a dict with a `role` (`system`, `user`, `assistant`) and a `content`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5141cb80",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "messages = [\n",
    "    {\"role\": \"system\", \"content\": \"You are a terse assistant.\"},\n",
    "    {\"role\": \"user\", \"content\": \"What is 17 * 23? Reply with the number only.\"},\n",
    "]\n",
    "response = litellm.completion(model=MODEL, messages=messages)\n",
    "print(response.choices[0].message.content)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "39773326",
   "metadata": {},
   "source": [
    "The response carries more than the text. Three fields matter for an agent:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "778bb93e",
   "metadata": {},
   "outputs": [],
   "source": [
    "choice = response.choices[0]\n",
    "print(\"role:         \", choice.message.role)\n",
    "print(\"finish_reason:\", choice.finish_reason)     # \"stop\" = turn ended normally, \"length\" = hit max_tokens\n",
    "print(\"usage:        \", response.usage)           # prompt + completion tokens\n",
    "print(\"cost ($):     \", litellm.completion_cost(response))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "81a60b8c",
   "metadata": {},
   "source": [
    "- `finish_reason == \"length\"` means the reply was **cut off**. An agent should treat that differently from a badly formatted reply (the format-error template below does exactly that).\n",
    "- `usage` is what you pay for with an API model. mini-swe-agent's default budget is **money** ($3 per task), computed from `usage` and LiteLLM's price table. For a local model the cost is 0, so we will budget **tokens** instead.\n",
    "\n",
    "**The API is stateless.** Ask a follow-up question without the history:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9d8b1965",
   "metadata": {},
   "outputs": [],
   "source": [
    "followup = {\"role\": \"user\", \"content\": \"What did I just ask you?\"}\n",
    "\n",
    "forgetful = litellm.completion(model=MODEL, messages=[followup])\n",
    "print(\"without history:\", forgetful.choices[0].message.content[:200])\n",
    "\n",
    "history = messages + [{\"role\": \"assistant\", \"content\": choice.message.content}, followup]\n",
    "print(\"with history:   \", litellm.completion(model=MODEL, messages=history).choices[0].message.content[:200])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "93eca6fa",
   "metadata": {},
   "source": [
    "The model remembers nothing between calls. Everything it \"knows\" about the run is in the list we send, so **the message list is the agent's entire state**. The agent appends to it at every step and sends all of it again with every call.\n",
    "\n",
    "**Concept.** Every message costs tokens and has to fit into the **context window** (→ [L-Att](http://christianherta.de/lehre/ai-agents/lecture-07/lecture-07-Att.html)). Keep this in mind: our history will only ever grow."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "29ca434c",
   "metadata": {},
   "source": [
    "## Input: System Prompt and Task Template\n",
    "\n",
    "Every run starts with two messages:\n",
    "\n",
    "- **system**: who the model is and the **format contract**: exactly one bash block, preceded by a THOUGHT,\n",
    "- **user**: the concrete task, plus workflow advice and a few command recipes.\n",
    "\n",
    "mini-swe-agent keeps both as **Jinja** templates in a YAML config (`config/default.yaml`). Here is a shortened version:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b3cc1731",
   "metadata": {},
   "outputs": [],
   "source": [
    "SYSTEM_TEMPLATE = \"\"\"\\\n",
    "You are a helpful assistant that can interact with a computer.\n",
    "\n",
    "Your response must contain exactly ONE bash code block with ONE command.\n",
    "A pipeline (|) or commands joined with && or || count as one command.\n",
    "Include a THOUGHT section before your command where you explain your reasoning process.\n",
    "\n",
    "<format_example>\n",
    "Your reasoning and analysis here. Explain why you want to perform the action.\n",
    "\n",
    "```mswea_bash_command\n",
    "your_command_here\n",
    "```\n",
    "</format_example>\n",
    "\n",
    "Failure to follow these rules will cause your response to be rejected.\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e332ab1b",
   "metadata": {},
   "outputs": [],
   "source": [
    "INSTANCE_TEMPLATE = \"\"\"\\\n",
    "Please solve this issue: {{task}}\n",
    "\n",
    "You are in a Python repository at /repo (no git available).\n",
    "You can execute bash commands and edit files to implement the necessary changes.\n",
    "\n",
    "## Recommended Workflow\n",
    "\n",
    "This workflow should be done step-by-step so that you can iterate on your changes and any possible problems.\n",
    "\n",
    "1. Analyze the codebase by finding and reading relevant files\n",
    "2. Create a script to reproduce the issue\n",
    "3. Edit the source code to resolve the issue\n",
    "4. Verify your fix works by running your script again\n",
    "5. Test edge cases to ensure your fix is robust\n",
    "6. Submit your changes and finish your work by issuing the following command: `echo COMPLETE_TASK_AND_SUBMIT_FINAL_OUTPUT`.\n",
    "   Do not combine it with any other command. <important>After this command, you cannot continue working on this task.</important>\n",
    "\n",
    "## Important Rules\n",
    "\n",
    "1. Every response must contain exactly one action\n",
    "2. The action must be enclosed in triple backticks\n",
    "3. Directory or environment variable changes are not persistent. Every action is executed in a new subshell.\n",
    "   However, you can prefix any action with `MY_ENV_VAR=MY_VALUE cd /path/to/working/dir && ...` or write/load environment variables from files\n",
    "\n",
    "## Useful command examples\n",
    "Create a file:\n",
    "```mswea_bash_command\n",
    "cat <<'EOF' > newfile.py\n",
    "print(\"hello\")\n",
    "EOF\n",
    "```\n",
    "Change more than one line of a file: first read the file (`cat -n filename.py`), then write\n",
    "its COMPLETE new content. Do not use sed for multi-line changes.\n",
    "```mswea_bash_command\n",
    "cat <<'EOF' > filename.py\n",
    "<the complete new content of the file>\n",
    "EOF\n",
    "```\n",
    "Replace text within a single line:\n",
    "```mswea_bash_command\n",
    "sed -i 's/old_string/new_string/g' filename.py\n",
    "```\n",
    "Show lines 10-20 with line numbers:\n",
    "```mswea_bash_command\n",
    "nl -ba filename.py | sed -n '10,20p'\n",
    "```\n",
    "\"\"\"\n",
    "\n",
    "\n",
    "def render(template, **variables):\n",
    "    return Template(template, undefined=StrictUndefined).render(**variables)\n",
    "\n",
    "\n",
    "print(render(INSTANCE_TEMPLATE, task=\"Make the tests pass.\")[:300], \"…\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5da7878d",
   "metadata": {},
   "source": [
    "**Where the templates come from.** Both are adapted from `agent.system_template` and `agent.instance_template` in mini-swe-agent's `src/minisweagent/config/default.yaml`; the instance template in `config/mini_textbased.yaml`, which the final section loads, is nearly identical. They are not verbatim copies:\n",
    "\n",
    "- **Taken over verbatim:** the task line (*\"Please solve this issue: {{task}}\"*), the six-step recommended workflow with the sentinel instruction, and the three important rules (one action per response, the fence, a new subshell per command). The workflow steps build on each other: the script created in step 2 is the one re-run in step 4, so these lines are kept word for word.\n",
    "- **Added:** the instance template gets *\"You are in a Python repository at /repo (no git available)\"*, which describes our container: `python:3.12-slim` has no git. A recipe for **multi-line edits** is added as well: read the file, then write its complete new content with `cat <<'EOF'`. Without it, a 7B model tends to put a multi-line fix into one `sed` command, gets the quoting wrong, and retries the same broken command until the step limit is reached.\n",
    "- **Clarified:** mini's system template asks for *\"ONE command (or commands connected with && or ||)\"*. It does not mention pipes, although its own recipes use them (`nl -ba … | sed -n …`). We changed the rule to say that a pipeline counts as one command. Note that the harness does not check this rule at all: `parse_action` only counts fenced blocks, and whatever the block contains goes to `bash -lc` unchanged. The rule asks the model for one logical step per turn.\n",
    "- **Shortened:** the command examples: the `sed` recipes are cut from four variants to one.\n",
    "- **Removed:** the `<system_information>{{system}} {{release}} …</system_information>` block, the *\"Formatting your response\"* example (the system template already carries one), the macOS hint (`sed -i ''`) and the catch-all *\"any other command\"* example.\n",
    "\n",
    "**The template syntax.** Both strings are **Jinja2** templates, the templating language mini keeps its prompts in. `render` above is the whole API we use of it: `Template(source).render(**variables)`.\n",
    "\n",
    "| Syntax | Meaning |\n",
    "|---|---|\n",
    "| `{{task}}` | insert the value of the variable `task` |\n",
    "| `{{actions \\| length}}` | insert a value through a **filter**; `length` yields the number of elements |\n",
    "| `{% if … %} … {% else %} … {% endif %}` | a control block: it selects what is rendered and produces no text of its own |\n",
    "| `{%- …` and `… -%}` | the same tags, with the whitespace on that side removed |\n",
    "\n",
    "Whitespace control earns its place because the rendered string reaches the model verbatim: a control tag on a line of its own would otherwise leave an empty line where it stood. The two templates above use `{{…}}` alone; the observation template and the format-error template below also use the conditional form.\n",
    "\n",
    "Three design decisions are hidden in these two strings:\n",
    "\n",
    "- **`StrictUndefined`**: a misspelled template variable raises an error instead of silently leaving a hole in the prompt. (Try `render(INSTANCE_TEMPLATE)` without `task=`.)\n",
    "- **The odd fence name `mswea_bash_command`.** Models write ```` ```bash ```` blocks all the time, in their reasoning and in examples. A tag nobody uses by accident separates *\"this is my action\"* from *\"here is an example\"*.\n",
    "- **The recommended workflow** (analyse → write a reproduction script → fix → re-run the script → test edge cases → submit) is a fixed plan for the task, written into the prompt instead of into code.\n",
    "\n",
    "**Concept.** The system prompt defines the agent's **action space** (one shell command per step) and its **output format**. The workflow list is task decomposition by prompt (→ [L-Decomp](http://christianherta.de/lehre/ai-agents/lecture-03/lecture-03-Decomp.html)): the model is *asked* to follow the plan, nothing *enforces* it."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4e42cbcb",
   "metadata": {},
   "source": [
    "## Output: Parsing the Action\n",
    "\n",
    "The model returns free text. The harness has to find exactly one action in it. mini's text-based model uses a regular expression over the fenced block:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "eca74c17",
   "metadata": {},
   "outputs": [],
   "source": [
    "ACTION_REGEX = r\"```mswea_bash_command\\s*\\n(.*?)\\n```\"\n",
    "\n",
    "\n",
    "class FormatError(Exception):\n",
    "    \"\"\"The model's reply does not contain exactly one action.\"\"\"\n",
    "\n",
    "\n",
    "def parse_action(text):\n",
    "    actions = re.findall(ACTION_REGEX, text, re.DOTALL)\n",
    "    if len(actions) != 1:\n",
    "        raise FormatError(f\"Expected exactly 1 action, found {len(actions)}.\")\n",
    "    return actions[0].strip()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "28493e45",
   "metadata": {},
   "source": [
    "**The regex, piece by piece** (it is mini's default `action_regex`):\n",
    "\n",
    "| Part | Matches |\n",
    "|---|---|\n",
    "| ```` ```mswea_bash_command ```` | the opening fence with its tag; plain ```` ```bash ```` blocks are ignored |\n",
    "| `\\s*\\n` | optional whitespace, then a newline: the command starts on the next line |\n",
    "| `(.*?)` | the command, the only capture group, so `findall` returns just the command |\n",
    "| ```` \\n``` ```` | the closing fence at the start of a line |\n",
    "\n",
    "- **`re.DOTALL`** lets `.` match newlines, so multi-line commands (heredocs) are captured.\n",
    "- **The lazy `.*?`** stops at the *first* closing fence. A greedy `.*` would merge two blocks into one match, including the text between them.\n",
    "- **Edge cases:** a line starting with ```` ``` ```` inside the command (e.g. a heredoc that writes Markdown) ends the capture early; an empty block yields the empty command `\"\"`; a one-line block ```` ```mswea_bash_command ls``` ```` does not match at all."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "53e6df90",
   "metadata": {},
   "outputs": [],
   "source": [
    "good = \"Let me look around first.\\n\\n```mswea_bash_command\\nls -la\\n```\"\n",
    "print(\"parsed:\", repr(parse_action(good)))\n",
    "\n",
    "for bad in [\"I think we should run ls.\", good + \"\\n\\n\" + good]:\n",
    "    try:\n",
    "        parse_action(bad)\n",
    "    except FormatError as e:\n",
    "        print(\"FormatError:\", e)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6beb543a",
   "metadata": {},
   "source": [
    "Why **exactly one**? One action gives one observation. The model sees the result of every command before it chooses the next, which is the interleaving that makes ReAct work. What to do *with* a `FormatError` comes later; the first loops simply stop on it.\n",
    "\n",
    "**Blocks, not commands.** `parse_action` counts **blocks**, not the commands inside one. A block holding a whole script (several lines, `;`, a loop) passes, and `bash -lc` runs all of it; mini's parser behaves the same. The prompt's \"ONE command\" rule is therefore a request to the model, not a check. A real check would need a bash parser: a heredoc spans several lines but is one command, a `;` inside quotes separates nothing, and `bash -c \"…\"` hides a whole script in one command. It would also reject the multi-line heredocs the prompt itself recommends. The rule serves the model's checking: with one command per turn, the model sees each result before it decides the next step. A script is executed in full anyway: later commands run even when an earlier one failed (unless joined with `&&`), the return code reports only the last command, and all outputs arrive mixed in one observation. The submit command `echo COMPLETE_TASK_AND_SUBMIT_FINAL_OUTPUT` (the **sentinel**, see the Termination section below) has an extra constraint: it is only recognised on the first line of output, so it must not follow other commands."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "74d09b92",
   "metadata": {},
   "source": [
    "## Environment: A Sandboxed Shell\n",
    "\n",
    "The environment turns a command into an **observation**. First, who runs what: the model only produces text, and **the harness executes every command**. What differs is *who wrote the command*, and that decides *where* it runs:\n",
    "\n",
    "| | Who writes the command | Where the harness runs it |\n",
    "|---|---|---|\n",
    "| **Actions** | the model (parsed from its reply) | inside the container, via `podman exec` |\n",
    "| **The harness's own commands** | us, as fixed code: `podman run`, `git reset`, `git diff` | on the host |\n",
    "\n",
    "The sandbox exists because of the first row: the content of those commands comes from a language model, so the harness runs them only where they cannot do damage. The second row is ordinary program code and runs like any other script.\n",
    "\n",
    "mini's `DockerEnvironment` starts one long-lived container (`sleep 2h`) and runs each command with `docker exec`. It accepts any compatible executable (`executable=\"podman\"`, or the environment variable `MSWEA_DOCKER_EXECUTABLE`), so podman works the same way.\n",
    "\n",
    "**The container is not mini's default.** The `mini` command and the `hello_world.py` example use `LocalEnvironment`, which runs each model-chosen command **directly on the host** with `subprocess.Popen(command, shell=True, …)`, without any sandbox. And even `DockerEnvironment` sets no security flags of its own: its `run_args` default to just `[\"--rm\"]`. Isolation in mini is something you configure, not something you get.\n",
    "\n",
    "We start the container the same way, and lock it down:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5a1cbd81",
   "metadata": {},
   "outputs": [],
   "source": [
    "def start_container(image=IMAGE, workdir=SANDBOX):\n",
    "    cmd = [\n",
    "        \"podman\", \"run\", \"-d\", \"--rm\",\n",
    "        \"--network=none\",                    # no internet: nothing to download, nothing to leak\n",
    "        \"--cap-drop=ALL\",                    # no Linux capabilities, even as root in the container\n",
    "        \"--memory=1g\", \"--pids-limit=256\",   # a fork bomb or a memory leak stays inside\n",
    "        \"-v\", f\"{workdir}:/repo:Z\",          # the toy repo is the only host directory it sees\n",
    "        \"-w\", \"/repo\",\n",
    "        image, \"sleep\", \"2h\",                # keep it alive; we exec commands into it\n",
    "    ]\n",
    "    return subprocess.run(cmd, capture_output=True, text=True, check=True).stdout.strip()\n",
    "\n",
    "\n",
    "CONTAINER = start_container()\n",
    "print(\"container:\", CONTAINER[:12])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3a2cffc9",
   "metadata": {},
   "source": [
    "Each command runs as `bash -lc <command>` in a **new** process. The observation is a dict: the combined stdout/stderr, the return code, and an error note if something went wrong on *our* side (a timeout)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bb71859a",
   "metadata": {},
   "outputs": [],
   "source": [
    "ENV_VARS = {\"PAGER\": \"cat\", \"MANPAGER\": \"cat\", \"LESS\": \"-R\", \"PIP_PROGRESS_BAR\": \"off\", \"TQDM_DISABLE\": \"1\"}\n",
    "\n",
    "def execute(command, timeout=30, container=None):\n",
    "    \"\"\"Run one bash command in the container and return the observation dict.\"\"\"\n",
    "    env_flags = [f\"--env={key}={value}\" for key, value in ENV_VARS.items()]\n",
    "    cmd = [\"podman\", \"exec\", \"-w\", \"/repo\", *env_flags, container or CONTAINER, \"bash\", \"-lc\", command]\n",
    "    try:\n",
    "        result = subprocess.run(cmd, text=True, timeout=timeout, encoding=\"utf-8\", errors=\"replace\",\n",
    "                                stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n",
    "        return {\"output\": result.stdout, \"returncode\": result.returncode, \"exception_info\": \"\"}\n",
    "    except subprocess.TimeoutExpired as e:\n",
    "        output = e.output.decode(\"utf-8\", errors=\"replace\") if isinstance(e.output, bytes) else (e.output or \"\")\n",
    "        return {\"output\": output, \"returncode\": -1, \"exception_info\": f\"Command timed out after {timeout}s.\"}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cf6ebf8c",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(execute(\"python --version && ls\"))\n",
    "print(execute(\"cd stats && pwd\"))\n",
    "print(execute(\"pwd\"))                     # back in /repo: the cd above is gone\n",
    "print(execute(\"python -m unittest -q 2>&1 | tail -3\"))\n",
    "print(execute(\"sleep 5\", timeout=2))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b85b0c50",
   "metadata": {},
   "source": [
    "Things to notice:\n",
    "\n",
    "- **stderr is merged into stdout.** The model has to see error messages; they are often the most useful part of an observation.\n",
    "- **A non-zero return code is not a harness error.** A failing test run is exactly the information the model is looking for. Only *our* problems (timeouts) go into `exception_info`.\n",
    "- **Every command gets a fresh subshell**, so `cd` and `export` do not persist. That is mini's deliberate choice: simple, reproducible, and no shell can end up stuck in a broken state. SWE-agent, the team's earlier agent, kept a persistent shell session instead ([Yang et al., 2024](https://arxiv.org/html/2405.15793)). The prompt tells the model about the choice and how to work with it (prefix the action with `cd /path/to/working/dir && …`).\n",
    "- **`PAGER=cat` and friends.** A command that opens an interactive pager (`git log`, `man`) would otherwise wait forever for a key press that never comes (Lieret et al., 2026).\n",
    "\n",
    "(The timeout kills `podman exec`, but a process inside the container may keep running. The container's own lifetime, `sleep 2h`, is the final limit. mini has the same property.)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bff06e6a",
   "metadata": {},
   "source": [
    "## A Minimal Agent Loop\n",
    "\n",
    "Now we glue the pieces together: query → parse → execute → append the observation, and repeat."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f2291a75",
   "metadata": {},
   "outputs": [],
   "source": [
    "def render_observation(output):\n",
    "    return f\"<returncode>{output['returncode']}</returncode>\\n<output>\\n{output['output']}</output>\"\n",
    "\n",
    "\n",
    "def minimal_agent(task, max_steps=6):\n",
    "    messages = [\n",
    "        {\"role\": \"system\", \"content\": render(SYSTEM_TEMPLATE)},\n",
    "        {\"role\": \"user\", \"content\": render(INSTANCE_TEMPLATE, task=task)},\n",
    "    ]\n",
    "    for _ in range(max_steps):\n",
    "        reply = litellm.completion(model=MODEL, messages=messages).choices[0].message.content  # think + choose\n",
    "        messages.append({\"role\": \"assistant\", \"content\": reply})\n",
    "        try:\n",
    "            output = execute(parse_action(reply))                                              # act\n",
    "        except FormatError as e:           # not handled yet: stop and show where\n",
    "            print(f\"STOPPED by FormatError: {e}\\n\")\n",
    "            break\n",
    "        messages.append({\"role\": \"user\", \"content\": render_observation(output)})               # observe\n",
    "    return messages"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e2e0d585",
   "metadata": {},
   "source": [
    "That's the whole idea in a dozen lines; the `try` only makes a format error stop the run visibly. A small printer to read the trace:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "118ab57b",
   "metadata": {},
   "outputs": [],
   "source": [
    "def show(messages, width=1200):\n",
    "    for m in messages:\n",
    "        print(f\"── {m['role'].upper()} \" + \"─\" * 60)\n",
    "        text = m[\"content\"] or \"\"\n",
    "        print(text if len(text) <= width else text[:width] + f\"\\n… [{len(text) - width} more characters]\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c78f80b7",
   "metadata": {},
   "outputs": [],
   "source": [
    "make_toy_repo()\n",
    "trace = minimal_agent(\"Create a file hello.py that prints 'Hello from the sandbox', then run it.\")\n",
    "show(trace[2:])     # skip system prompt and task"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e85b5b21",
   "metadata": {},
   "source": [
    "Read the trace as a ReAct trace: THOUGHT, action, observation, THOUGHT, …. Note that the observation arrives as a **`user`** message: to the model, the environment speaks in the user's voice. (With tool calling it gets a role of its own, see below.)\n",
    "\n",
    "What is wrong with this loop:\n",
    "\n",
    "1. **It never stops by itself.** It runs `max_steps` times, even when the task was finished after two steps, and it has no way to know whether the task was finished at all.\n",
    "2. **One badly formatted reply ends the run.** The loop catches `FormatError` only to stop; it does not recover.\n",
    "3. **Any output goes into the history unfiltered.** One `cat` of a large file fills the context window.\n",
    "4. **No budget** except the hard-coded step count.\n",
    "\n",
    "We fix these one at a time."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e768c59a",
   "metadata": {},
   "source": [
    "## Termination: Knowing When to Stop\n",
    "\n",
    "A run can end in three ways: the agent says it is **done**, a **budget** is exhausted, or something **breaks**. mini implements all of them the same way: an exception that carries an `exit` message. The loop then needs only one check: *is the last message an exit message?*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "430a388d",
   "metadata": {},
   "outputs": [],
   "source": [
    "class InterruptAgentFlow(Exception):\n",
    "    \"\"\"Interrupts the normal step; carries the messages to append to the history.\"\"\"\n",
    "\n",
    "    def __init__(self, *messages):\n",
    "        super().__init__()\n",
    "        self.messages = messages\n",
    "\n",
    "\n",
    "class Submitted(InterruptAgentFlow):\n",
    "    \"\"\"The agent says it is done.\"\"\"\n",
    "\n",
    "\n",
    "class LimitsExceeded(InterruptAgentFlow):\n",
    "    \"\"\"A budget is exhausted.\"\"\"\n",
    "\n",
    "\n",
    "def exit_message(status, submission=\"\"):\n",
    "    return {\"role\": \"exit\", \"content\": status, \"extra\": {\"exit_status\": status, \"submission\": submission}}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0e1cf50b",
   "metadata": {},
   "source": [
    "**How does the agent say \"done\"?** By running a **sentinel command**, `echo COMPLETE_TASK_AND_SUBMIT_FINAL_OUTPUT`. The *environment* recognises the sentinel as the first line of a successful command's output. Anything printed after it becomes the **submission**, so `echo SENTINEL && cat answer.txt` hands in a result together with the signal. No extra tool and no special parsing are needed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7f8df495",
   "metadata": {},
   "outputs": [],
   "source": [
    "SENTINEL = \"COMPLETE_TASK_AND_SUBMIT_FINAL_OUTPUT\"\n",
    "\n",
    "\n",
    "def check_finished(output):\n",
    "    lines = output[\"output\"].lstrip().splitlines(keepends=True)\n",
    "    if lines and lines[0].strip() == SENTINEL and output[\"returncode\"] == 0:\n",
    "        submission = \"\".join(lines[1:])\n",
    "        raise Submitted({**exit_message(\"Submitted\", submission), \"content\": submission})\n",
    "\n",
    "\n",
    "def check_limits(n_calls, n_tokens, step_limit, token_limit):\n",
    "    if 0 < step_limit <= n_calls or 0 < token_limit <= n_tokens:     # 0 = no limit, as in mini\n",
    "        raise LimitsExceeded(exit_message(\"LimitsExceeded\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fb4864d7",
   "metadata": {},
   "source": [
    "The loop is now `while` rather than `for`. The body is a single `try`, and every interruption just appends its messages:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8e0e5388",
   "metadata": {},
   "outputs": [],
   "source": [
    "def agent_v2(task, step_limit=15, token_limit=200_000):\n",
    "    messages = [\n",
    "        {\"role\": \"system\", \"content\": render(SYSTEM_TEMPLATE)},\n",
    "        {\"role\": \"user\", \"content\": render(INSTANCE_TEMPLATE, task=task)},\n",
    "    ]\n",
    "    n_calls = n_tokens = 0\n",
    "    while messages[-1][\"role\"] != \"exit\":\n",
    "        try:\n",
    "            check_limits(n_calls, n_tokens, step_limit, token_limit)\n",
    "            response = litellm.completion(model=MODEL, messages=messages)\n",
    "            n_calls += 1\n",
    "            n_tokens += response.usage.total_tokens\n",
    "            reply = response.choices[0].message.content or \"\"\n",
    "            messages.append({\"role\": \"assistant\", \"content\": reply})\n",
    "            output = execute(parse_action(reply))\n",
    "            check_finished(output)                      # may raise Submitted\n",
    "            messages.append({\"role\": \"user\", \"content\": render_observation(output)})\n",
    "        except FormatError as e:                        # still problem 2: stop, fixed in the next section\n",
    "            print(f\"STOPPED by FormatError: {e}\\n\")\n",
    "            break\n",
    "        except InterruptAgentFlow as e:\n",
    "            messages.extend(e.messages)\n",
    "    print(f\"{n_calls} model calls, {n_tokens} tokens processed\")\n",
    "    return messages"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "da90b5c7",
   "metadata": {},
   "outputs": [],
   "source": [
    "make_toy_repo()\n",
    "trace = agent_v2(\"Create a file hello.py that prints 'Hello from the sandbox', run it, then submit.\")\n",
    "show(trace[2:])\n",
    "print(trace[-1].get(\"extra\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "94cebe33",
   "metadata": {},
   "source": [
    "The `exit` role is not a role the API knows. It never reaches the model, because the loop ends as soon as it is appended.\n",
    "\n",
    "**A note on the token budget.** `total_tokens` counts the *whole prompt* again on every call. With a history that grows by roughly $\\ell$ tokens per step, call $t$ processes about $t\\ell$ tokens, so $n$ steps cost about $\\ell\\,n^2/2$ in total: **quadratic** in the number of steps. That is why long agent runs get expensive, and why history management matters (→ [L-Memory](http://christianherta.de/lehre/ai-agents/lecture-09/lecture-09-Memory.html)).\n",
    "\n",
    "mini has four limits, two of them on by default: steps and wall-clock time are `0`, meaning no limit; **money** is $3 per task; and consecutive format errors are capped at three in a row (next section). Adding a wall-clock limit is one more `if`.\n",
    "\n",
    "**Concept.** The exit message is the **terminal state** of an episode; the step limit is a **horizon** (→ [L-MDP](http://christianherta.de/lehre/ai-agents/lecture-05/lecture-05-MDP.html)). mini ends an episode only on the agent's own signal or on a budget, never on a judgement of *whether the work is correct*. That judgement belongs to the evaluation, after the run."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "abe1baff",
   "metadata": {},
   "source": [
    "## Errors Become Observations\n",
    "\n",
    "The mini-swe-agent team's rule for known failures:\n",
    "\n",
    "> *\"When known exceptions arise (timeouts, format errors, etc.), let's just tell the LM and let it handle it itself.\"* (Lieret et al., 2026)\n",
    "\n",
    "So a `FormatError` no longer ends the run: it becomes a **message to the model** that explains what went wrong. We redefine it as an interruption that carries that message:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2bd4a25b",
   "metadata": {},
   "outputs": [],
   "source": [
    "FORMAT_ERROR_TEMPLATE = \"\"\"\\\n",
    "{% if finish_reason in [\"length\", \"tool_calls\"] -%}\n",
    "Your previous response reached the output token limit (finish_reason={{finish_reason}}) before you\n",
    "produced a complete action, so it was cut off. Respond more concisely and provide exactly one action\n",
    "in the required format. If you need to think more, do so briefly.\n",
    "{%- else -%}\n",
    "Format error:\n",
    "\n",
    "<error>\n",
    "{{error}}\n",
    "</error>\n",
    "\n",
    "Here is general guidance on how to format your response:\n",
    "\n",
    "Please always provide EXACTLY ONE action in triple backticks, found {{actions|length}} actions.\n",
    "\n",
    "Please format your action in triple backticks as shown in <response_example>.\n",
    "\n",
    "<response_example>\n",
    "Here are some thoughts about why you want to perform the action.\n",
    "\n",
    "```mswea_bash_command\n",
    "<action>\n",
    "```\n",
    "</response_example>\n",
    "\n",
    "If you have completed your assignment, please consult the first message about how to\n",
    "submit your solution (you will not be able to continue working on this task after that).\n",
    "{%- endif %}\"\"\"\n",
    "\n",
    "\n",
    "class FormatError(InterruptAgentFlow):\n",
    "    \"\"\"The model's reply does not contain exactly one action.\"\"\"\n",
    "\n",
    "\n",
    "def parse_action(text, finish_reason=\"\"):\n",
    "    actions = re.findall(ACTION_REGEX, text, re.DOTALL)\n",
    "    if len(actions) != 1:\n",
    "        error = f\"Expected exactly 1 action, found {len(actions)}.\"\n",
    "        content = render(FORMAT_ERROR_TEMPLATE, error=error, actions=actions, finish_reason=finish_reason)\n",
    "        raise FormatError({\"role\": \"user\", \"content\": content,\n",
    "                           \"extra\": {\"n_actions\": len(actions), \"model_response\": text}})\n",
    "    return actions[0].strip()\n",
    "\n",
    "\n",
    "for text, reason in [(\"I would run ls now.\", \"stop\"), (\"Let me begin by carefully considering\", \"length\")]:\n",
    "    try:\n",
    "        parse_action(text, reason)\n",
    "    except FormatError as e:\n",
    "        print(f\"── finish_reason={reason} \" + \"─\" * 40)\n",
    "        print(e.messages[0][\"content\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a8e60c87",
   "metadata": {},
   "source": [
    "Two more robustness pieces:\n",
    "\n",
    "- **A cap on consecutive format errors.** Three bad replies *in a row* end the run with `RepeatedFormatError`; any clean step resets the counter. So this is not really a budget. It detects a model that is **stuck**.\n",
    "- **Retries for API errors**, with backoff, except for errors that a retry cannot fix (wrong key, unknown model, context window exceeded) — mini's `abort_exceptions`.\n",
    "\n",
    "Note that the two kinds of failure have nothing in common. A format error means the reply **arrived** and says the wrong thing; retrying the same request would only produce it again, so it is answered with a message. An API error means the reply **did not arrive**; the model never learns that it happened.\n",
    "\n",
    "`prepare_messages_for_api` in the same cell belongs to neither. It is the boundary between our own bookkeeping and the request: our messages carry an `extra` field of things the chat API has no vocabulary for, and only `role` and `content` are sent. The name is mini's own, where it is a method of the model class."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "982a0b08",
   "metadata": {},
   "outputs": [],
   "source": [
    "def prepare_messages_for_api(messages):\n",
    "    \"\"\"Our messages carry an \"extra\" field; the chat API knows role and content.\"\"\"\n",
    "    return [{\"role\": m[\"role\"], \"content\": m[\"content\"]} for m in messages]\n",
    "\n",
    "\n",
    "ABORT_EXCEPTIONS = (litellm.exceptions.AuthenticationError, litellm.exceptions.NotFoundError,\n",
    "                    litellm.exceptions.ContextWindowExceededError)\n",
    "\n",
    "\n",
    "# Retries for model call API errors: the reply did not arrive. A format error is not an API error —\n",
    "# the reply arrived and says the wrong thing — and is never retried.\n",
    "def query_with_retry(messages, model=MODEL, attempts=3, **kwargs):\n",
    "    for attempt in range(attempts):\n",
    "        try:\n",
    "            return litellm.completion(model=model, messages=messages, **kwargs)\n",
    "        except ABORT_EXCEPTIONS:\n",
    "            raise\n",
    "        except Exception:\n",
    "            if attempt == attempts - 1:\n",
    "                raise\n",
    "            time.sleep(2 ** attempt)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "49efffb2",
   "metadata": {},
   "source": [
    "The loop, with the new lines marked `# NEW`. Since `FormatError` is a subclass of `InterruptAgentFlow`, its `except` clause has to come first:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1f78c596-2b10-40d2-8566-2ca9fba6d614",
   "metadata": {},
   "outputs": [],
   "source": [
    "def agent_v3(\n",
    "    task: str,\n",
    "    step_limit: int = 15,\n",
    "    token_limit: int = 200_000,\n",
    "    max_consecutive_format_errors: int = 3,  # NEW\n",
    ") -> list[dict]:\n",
    "    \"\"\"Runs the main agent loop to solve a given task.\n",
    "\n",
    "    Calls & Exception Mapping:\n",
    "    -------------------------\n",
    "    - check_limits(...)              -> raises LimitsExceeded\n",
    "    - query_with_retry(...)           -> raises API/Network errors (e.g., ContextWindowExceededError)\n",
    "    - parse_action(...)               -> raises FormatError\n",
    "    - execute(...)                    -> executes action inside container environment\n",
    "    - check_finished(...)             -> raises Submitted\n",
    "    \"\"\"\n",
    "    messages = [\n",
    "        {\"role\": \"system\", \"content\": render(SYSTEM_TEMPLATE)},\n",
    "        {\"role\": \"user\", \"content\": render(INSTANCE_TEMPLATE, task=task)},\n",
    "    ]\n",
    "\n",
    "    n_calls = 0\n",
    "    n_tokens = 0\n",
    "    n_consecutive_format_errors = 0  # NEW\n",
    "\n",
    "    while messages[-1][\"role\"] != \"exit\":\n",
    "        try:\n",
    "            # 1. Budget enforcement (Raises: LimitsExceeded)\n",
    "            check_limits(n_calls, n_tokens, step_limit, token_limit)\n",
    "\n",
    "            # 2. Model call (Raises: API errors)\n",
    "            api_messages = prepare_messages_for_api(messages)  # NEW\n",
    "            response = query_with_retry(api_messages)  # NEW\n",
    "\n",
    "            n_calls += 1\n",
    "            n_tokens += response.usage.total_tokens\n",
    "            reply = response.choices[0].message.content or \"\"\n",
    "\n",
    "            # 3. Format validation (Raises: FormatError)\n",
    "            # Validated BEFORE appending assistant message to keep invalid turns out of context history.\n",
    "            action = parse_action(reply, response.choices[0].finish_reason)  # NEW\n",
    "            messages.append({\"role\": \"assistant\", \"content\": reply})\n",
    "\n",
    "            # 4. Action execution & termination check (Raises: Submitted)\n",
    "            output = execute(action)\n",
    "            check_finished(output)\n",
    "\n",
    "            # Successful step: record observation and reset format error counter\n",
    "            messages.append({\"role\": \"user\", \"content\": render_observation(output)})\n",
    "            n_consecutive_format_errors = 0  # NEW\n",
    "\n",
    "        except FormatError as e:  # NEW: tell the model, go on\n",
    "            # Tell the model what went wrong via prompt feedback and continue\n",
    "            n_consecutive_format_errors += 1\n",
    "            messages.extend(e.messages)\n",
    "\n",
    "            # Check if consecutive format errors exceed the max threshold (0 = no limit)\n",
    "            if 0 < max_consecutive_format_errors <= n_consecutive_format_errors:\n",
    "                messages.append(exit_message(\"RepeatedFormatError\"))\n",
    "\n",
    "        except InterruptAgentFlow as e:\n",
    "            # Catch flow control interrupts (e.g., LimitsExceeded, Submitted)\n",
    "            messages.extend(e.messages)\n",
    "\n",
    "    print(f\"{n_calls} model calls, {n_tokens} tokens processed\")\n",
    "    return messages"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5b32d5ef",
   "metadata": {},
   "source": [
    "The malformed reply never enters the history, though the failure is not concealed: `parse_action` raises before the assistant message is appended, and the correction that takes its place states what went wrong (*Expected exactly 1 action, found 0*) and how to write the action. A reply declared wrong is still an example of the wrong format in the model's own context, and a stuck model would contribute three of them to a history that is paid for on every later call. The text is recorded rather than lost: `extra[\"model_response\"]` holds it, and `prepare_messages_for_api` drops `extra` before sending, so the trajectory keeps what the model wrote without showing it again.\n",
    "\n",
    "A failed command is treated the opposite way: the command and its error both stay, as the pair the next step is derived from. The line is not *successful* against *failed* but **observation** against **protocol violation** — a failing test run is a fact about the repository, a reply the harness cannot read is a fact about the reply alone. That decides what counts as information, not what it costs: the failure is still paid for in the context window, and shaping the observation is the only thing mini does about it.\n",
    "\n",
    "The template is mini's, including the branch on `finish_reason`: a reply cut off at `max_tokens` is told to *\"respond more concisely\"* rather than to *\"use the right format\"* — same symptom, different cause, different advice. The rest restates the contract and shows a `<response_example>`, because the reply that broke it is no longer there to be corrected."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2b339811",
   "metadata": {},
   "source": [
    "## Observation Shaping: Protecting the Context Window\n",
    "\n",
    "History is linear: whatever enters it stays and is sent again on every call. One `cat` of a large log would fill the context window for the rest of the run. mini's observation template therefore **truncates**: up to 10,000 characters are shown in full; beyond that the model sees the first and last 5,000 characters and a warning that tells it how to do better."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bd72072d",
   "metadata": {},
   "outputs": [],
   "source": [
    "OBSERVATION_TEMPLATE = \"\"\"\\\n",
    "{% if output.exception_info -%}\n",
    "<exception>{{output.exception_info}}</exception>\n",
    "{% endif -%}\n",
    "<returncode>{{output.returncode}}</returncode>\n",
    "{% if output.output | length < 10000 -%}\n",
    "<output>\n",
    "{{ output.output -}}\n",
    "</output>\n",
    "{%- else -%}\n",
    "<warning>\n",
    "The output of your last command was too long. Please try a command that produces less output,\n",
    "e.g. use head, tail, grep or sed -n to view a part of a file.\n",
    "</warning>\n",
    "<output_head>\n",
    "{{ output.output[:5000] }}\n",
    "</output_head>\n",
    "<elided_chars>\n",
    "{{ output.output | length - 10000 }} characters elided\n",
    "</elided_chars>\n",
    "<output_tail>\n",
    "{{ output.output[-5000:] }}\n",
    "</output_tail>\n",
    "{%- endif %}\"\"\"\n",
    "\n",
    "\n",
    "def render_observation(output):\n",
    "    return render(OBSERVATION_TEMPLATE, output=output)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "57a3acd1",
   "metadata": {},
   "outputs": [],
   "source": [
    "big = execute(\"seq 1 100000\")\n",
    "obs = render_observation(big)\n",
    "print(f\"raw output: {len(big['output']):,} characters -> observation: {len(obs):,} characters\")\n",
    "print(obs[:241], \"\\n…\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd75a6af",
   "metadata": {},
   "source": [
    "We just *redefined* `render_observation`. `agent_v3` looks the name up each time it is called, so it now uses the new template without being rewritten. The same holds for `parse_action` above. Convenient in a notebook; in real code, this is what configuration objects are for (see the refactoring below).\n",
    "\n",
    "**Concept.** Every token of an observation is paid for again on every later step and occupies the finite **context window** (→ [L-Att](http://christianherta.de/lehre/ai-agents/lecture-07/lecture-07-Att.html)). mini never summarises or drops old messages: the history is the full trajectory. That makes it the baseline against which **compaction** and memory strategies are measured (→ [L-Memory](http://christianherta.de/lehre/ai-agents/lecture-09/lecture-09-Memory.html)). The warning text is a small piece of **agent–computer interface** design: the observation tells the model how to act better, which is the idea SWE-agent is built on ([Yang et al., 2024](https://arxiv.org/html/2405.15793)).\n",
    "\n",
    "**Truncation bounds the size of an observation, not its position.** Every failed attempt that is kept remains in the middle of the history for the rest of the run, and the middle is where a long input is used least reliably: accuracy on material placed there falls well below accuracy on material at the beginning or the end of the context ([Liu et al., 2024](https://arxiv.org/html/2307.03172)). A traceback that was the most useful thing in the context at step 4 describes, by step 20, a state the repository is no longer in — it has become a distractor that is still paid for on every call. mini accepts this deliberately, in exchange for a trajectory that is exactly what the model saw; removing superseded attempts is what compaction does instead, and it gives that property up."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ed26f05c",
   "metadata": {},
   "source": [
    "## A Real Task: Fixing the Bug\n",
    "\n",
    "The loop is now complete enough for a real (if tiny) software-engineering task:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "118ece74",
   "metadata": {},
   "outputs": [],
   "source": [
    "TASK = (\n",
    "    \"The unit tests fail. Run them with `python -m unittest -v`, find the bug in the `stats` package \"\n",
    "    \"and fix it. Do not modify the tests.\"\n",
    ")\n",
    "\n",
    "\n",
    "def verify():\n",
    "    \"\"\"Our check, outside the loop: do the tests pass, and what did the model's commands change?\"\"\"\n",
    "    tests = execute(\"python -m unittest -q 2>&1 | tail -1\")\n",
    "    print(\"tests:\", tests[\"output\"].strip())\n",
    "    print(git(\"diff\") or \"(no changes)\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5c68ceaa",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "make_toy_repo()\n",
    "trace = agent_v3(TASK)\n",
    "show(trace[2:])\n",
    "print(trace[-1][\"extra\"][\"exit_status\"])\n",
    "verify()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d8b403d9",
   "metadata": {},
   "source": [
    "Whether this succeeds depends a lot on the model. Typical failure modes of small models are worth reading in the trace: forgetting the fence, editing the test instead of the code, a `sed` expression with broken quoting, submitting without re-running the tests, or repeating one ineffective edit until the budget is exhausted — an import appended to `stats/__init__.py`, which the test does not import, followed by the same test run, again and again. Note the separation: the model **claims** success by sending the sentinel; `verify()` **checks** it. The two can disagree."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d155dc16",
   "metadata": {},
   "source": [
    "## From Text Actions to Tool Calling\n",
    "\n",
    "Most model APIs today can **call tools**: the request declares functions as JSON Schema, and the model answers with a structured `tool_calls` field instead of a fenced block. No regex is needed. mini-swe-agent v2 uses this by default (`LitellmModel`); the text-based variant we built is `LitellmTextbasedModel`, reached by an explicit `-c mini_textbased.yaml`. mini's own recommendation for practice is unambiguous: text parsing *\"was the method used for mini-swe-agent v1.0 and the original SWE-agent. As of mini-swe-agent v2.0, we strongly recommend to use toolcalls instead\"* (`models/utils/actions_text.py`). The tool-calling model's only tool is `bash`, with a four-word description. The system prompt below is a single sentence, because the format contract has moved into the schema: there is no fence to name and no block to count."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8ce4bb00",
   "metadata": {},
   "outputs": [],
   "source": [
    "BASH_TOOL = {\n",
    "    \"type\": \"function\",\n",
    "    \"function\": {\n",
    "        \"name\": \"bash\",\n",
    "        \"description\": \"Execute a bash command\",\n",
    "        \"parameters\": {\n",
    "            \"type\": \"object\",\n",
    "            \"properties\": {\"command\": {\"type\": \"string\", \"description\": \"The bash command to execute\"}},\n",
    "            \"required\": [\"command\"],\n",
    "        },\n",
    "    },\n",
    "}\n",
    "\n",
    "tool_messages = [\n",
    "    {\"role\": \"system\", \"content\": \"You can run bash commands in a Linux container. The repository is at /repo.\"},\n",
    "    {\"role\": \"user\", \"content\": \"How many Python files are there under /repo? Use the bash tool.\"},\n",
    "]\n",
    "response = litellm.completion(model=MODEL, messages=tool_messages, tools=[BASH_TOOL])\n",
    "msg = response.choices[0].message\n",
    "print(\"content:   \", msg.content)\n",
    "print(\"tool_calls:\", msg.tool_calls)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "84c9e510",
   "metadata": {},
   "source": [
    "The observation goes back with its own role, `tool`, and the `tool_call_id` it answers, so a model that issues several calls can match results to calls:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0f8fc205",
   "metadata": {},
   "outputs": [],
   "source": [
    "if not msg.tool_calls:\n",
    "    print(\"No tool call: the model answered in plain text. In mini's tool-calling model this is a FormatError.\")\n",
    "else:\n",
    "    call = msg.tool_calls[0]\n",
    "    command = json.loads(call.function.arguments)[\"command\"]\n",
    "    print(\"command:\", command)\n",
    "    output = execute(command)\n",
    "    tool_messages += [\n",
    "        msg.model_dump(exclude_none=True),\n",
    "        {\"role\": \"tool\", \"tool_call_id\": call.id, \"content\": render_observation(output)},\n",
    "    ]\n",
    "    final = litellm.completion(model=MODEL, messages=tool_messages, tools=[BASH_TOOL])\n",
    "    print(\"answer: \", final.choices[0].message.content)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0228237a",
   "metadata": {},
   "source": [
    "| | Text actions (what we built) | Tool calling |\n",
    "|---|---|---|\n",
    "| Action extraction | regex over the reply | `message.tool_calls`, JSON arguments |\n",
    "| Typical format errors | no block, two blocks | no tool call, invalid JSON, unknown tool |\n",
    "| Observation role | `user` | `tool` + `tool_call_id` |\n",
    "| Reasoning | the THOUGHT in the text | `content` next to the call, or a separate thinking field |\n",
    "| Actions per turn | exactly one, enforced by the parser | one or more, and mini's prompt asks for **at least one** |\n",
    "| Requirements | any chat model | model *and* provider must support tools |\n",
    "\n",
    "**The one-action rule is reversed, not carried over.** In text mode the rule is enforced where the reply is read: `parse_action` counts blocks and rejects anything but one. In tool-calling mode mini asks for the opposite — *\"Your response MUST include AT LEAST ONE bash tool call\"* (`config/mini.yaml`) — and `parse_toolcall_actions` returns every call it finds, which `execute_actions` then runs in order, one `tool` observation per call. The `tool_call_id` pairing is what makes a turn with several actions unambiguous. The request for a THOUGHT survives the move as prose (*\"your response SHOULD include reasoning text\"*), since no schema can ask for reasoning.\n",
    "\n",
    "What is given up is the interleaving. A model that issues three calls in one turn chooses the second and the third before it has seen the result of the first, which is precisely the property *exactly one* protects — traded for fewer round trips.\n",
    "\n",
    "One caution: when an Ollama model has no native tool calling, LiteLLM falls back to a JSON mode (BerriAI, 2026). The code looks the same, but the mechanism underneath is different.\n",
    "\n",
    "**Concept.** Both variants give the agent **one generic tool**. The alternative is many specialised tools (`open_file`, `edit_lines`, `search_dir`, …). SWE-agent designed such an interface carefully ([Yang et al., 2024](https://arxiv.org/html/2405.15793)); CodeAct argues for code itself as the unified action space ([Wang et al., 2024](https://arxiv.org/html/2402.01030)). With mini-swe-agent the SWE-agent team went back to bash alone: *\"as LMs have become more capable, a lot of this is not needed at all to build a useful agent!\"* (Lieret & Jimenez, 2026). Which design wins depends on the model, which is why the question is still open (→ [L-ReAct](http://christianherta.de/lehre/ai-agents/lecture-02/lecture-02-ReAct.html))."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1f348a9a",
   "metadata": {},
   "source": [
    "## Refactoring: Model, Environment, Agent\n",
    "\n",
    "Our functions share global state (`MODEL`, `CONTAINER`) and the loop does everything itself. mini-swe-agent splits the same code into three classes with small interfaces, so that each part can be **swapped** independently: another model class, a Docker/Singularity/remote environment, an interactive agent. Here is our code in that shape. The model class below is the **text-based** one, which mini keeps for providers and local models without native tool calling — and which is what this notebook can teach from, since prompt, parser and correction message are all visible in it. The tool-calling class is the same interface with a different body: `query` reads `message.tool_calls` instead of matching a regular expression, and nothing in `Agent` changes.\n",
    "\n",
    "**Model:** messages in, one assistant message with the parsed action out."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2a54b533",
   "metadata": {},
   "outputs": [],
   "source": [
    "class TextModel:\n",
    "    def __init__(self, model_name=MODEL, **model_kwargs):\n",
    "        self.model_name, self.model_kwargs = model_name, model_kwargs\n",
    "\n",
    "    def query(self, messages):\n",
    "        api_messages = prepare_messages_for_api(messages)\n",
    "        response = query_with_retry(api_messages, model=self.model_name, **self.model_kwargs)\n",
    "        reply = response.choices[0].message.content or \"\"\n",
    "        extra = {\"tokens\": response.usage.total_tokens}\n",
    "        try:\n",
    "            action = parse_action(reply, response.choices[0].finish_reason)\n",
    "        except FormatError as e:           # the reply is already in e.messages[0][\"extra\"]; add what it cost\n",
    "            e.messages[0][\"extra\"] |= extra\n",
    "            raise\n",
    "        return {\"role\": \"assistant\", \"content\": reply, \"extra\": {**extra, \"action\": action}}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eca1ca12",
   "metadata": {},
   "source": [
    "**Environment:** one command in, one observation out. The environment detects the sentinel, as `LocalEnvironment._check_finished` does in mini."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ed91d3c5",
   "metadata": {},
   "outputs": [],
   "source": [
    "class PodmanEnvironment:\n",
    "    def __init__(self, image=IMAGE, workdir=SANDBOX, timeout=30):\n",
    "        self.timeout = timeout\n",
    "        self.container = start_container(image, workdir)\n",
    "\n",
    "    def execute(self, command):\n",
    "        output = execute(command, self.timeout, container=self.container)\n",
    "        check_finished(output)\n",
    "        return output\n",
    "\n",
    "    def close(self):\n",
    "        subprocess.run([\"podman\", \"rm\", \"-f\", self.container], capture_output=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1f2e045e",
   "metadata": {},
   "source": [
    "**Agent:** the loop, split the way mini splits it: `run` loops over `step`, and `step` = `execute_actions(query())`. Each method is a place to hook in: a subclass overrides one method and inherits the rest. The trajectory is saved in `finally`, i.e. after **every** step, so a crashed run still leaves a file."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e1ee829a",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Agent:\n",
    "    def __init__(self, model, env, step_limit=15, token_limit=200_000,\n",
    "                 max_consecutive_format_errors=3, output_path=None):\n",
    "        self.model, self.env = model, env\n",
    "        self.step_limit, self.token_limit = step_limit, token_limit\n",
    "        self.max_consecutive_format_errors = max_consecutive_format_errors\n",
    "        self.output_path = output_path\n",
    "        self.messages = []\n",
    "        self.n_calls = self.n_tokens = self.n_consecutive_format_errors = 0\n",
    "\n",
    "    def add_messages(self, *messages):\n",
    "        self.messages.extend(messages)\n",
    "        return list(messages)\n",
    "\n",
    "    def run(self, task):\n",
    "        self.messages = []\n",
    "        self.add_messages({\"role\": \"system\", \"content\": render(SYSTEM_TEMPLATE)},\n",
    "                          {\"role\": \"user\", \"content\": render(INSTANCE_TEMPLATE, task=task)})\n",
    "        while self.messages[-1][\"role\"] != \"exit\":\n",
    "            try:\n",
    "                self.step()\n",
    "                self.n_consecutive_format_errors = 0\n",
    "            except FormatError as e:\n",
    "                # the call was billed, but query() never returned to count it\n",
    "                self.n_tokens += e.messages[0][\"extra\"][\"tokens\"]\n",
    "                self.n_consecutive_format_errors += 1\n",
    "                self.add_messages(*e.messages)\n",
    "                if 0 < self.max_consecutive_format_errors <= self.n_consecutive_format_errors:\n",
    "                    self.add_messages(exit_message(\"RepeatedFormatError\"))\n",
    "            except InterruptAgentFlow as e:\n",
    "                self.add_messages(*e.messages)\n",
    "            finally:\n",
    "                self.save()\n",
    "        return self.messages[-1][\"extra\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6cc9992d",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Agent(Agent):    # continued: the three methods one loop iteration consists of\n",
    "    def step(self):\n",
    "        return self.execute_actions(self.query())\n",
    "\n",
    "    def query(self):\n",
    "        check_limits(self.n_calls, self.n_tokens, self.step_limit, self.token_limit)\n",
    "        self.n_calls += 1\n",
    "        message = self.model.query(self.messages)\n",
    "        self.n_tokens += message[\"extra\"][\"tokens\"]\n",
    "        return self.add_messages(message)[0]\n",
    "\n",
    "    def execute_actions(self, message):\n",
    "        output = self.env.execute(message[\"extra\"][\"action\"])\n",
    "        return self.add_messages({\"role\": \"user\", \"content\": render_observation(output),\n",
    "                                  \"extra\": {\"returncode\": output[\"returncode\"]}})\n",
    "\n",
    "    def save(self):\n",
    "        if not self.output_path:\n",
    "            return\n",
    "        last = self.messages[-1].get(\"extra\", {})\n",
    "        data = {\"info\": {\"model\": self.model.model_name, \"api_calls\": self.n_calls, \"tokens\": self.n_tokens,\n",
    "                         \"exit_status\": last.get(\"exit_status\", \"\"), \"submission\": last.get(\"submission\", \"\")},\n",
    "                \"messages\": self.messages}\n",
    "        self.output_path.parent.mkdir(parents=True, exist_ok=True)\n",
    "        self.output_path.write_text(json.dumps(data, indent=2))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bbe2cc4c",
   "metadata": {},
   "source": [
    "This is now essentially mini's `DefaultAgent`. The control flow:\n",
    "\n",
    "<div class=\"mermaid-figure\" style=\"max-width:100%;overflow-x:auto\">\n",
    "<svg style=\"width:100%;max-width:1059.984375px;height:auto\" id=\"mmd-1\" xmlns=\"http://www.w3.org/2000/svg\" class=\"flowchart\" viewBox=\"0 0 1059.984375 962.7750244140625\" role=\"graphics-document document\" aria-roledescription=\"flowchart-v2\"><style>#mmd-1{font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mmd-1 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mmd-1 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mmd-1 .error-icon{fill:#552222;}#mmd-1 .error-text{fill:#552222;stroke:#552222;}#mmd-1 .edge-thickness-normal{stroke-width:1px;}#mmd-1 .edge-thickness-thick{stroke-width:3.5px;}#mmd-1 .edge-pattern-solid{stroke-dasharray:0;}#mmd-1 .edge-thickness-invisible{stroke-width:0;fill:none;}#mmd-1 .edge-pattern-dashed{stroke-dasharray:3;}#mmd-1 .edge-pattern-dotted{stroke-dasharray:2;}#mmd-1 .marker{fill:#333333;stroke:#333333;}#mmd-1 .marker.cross{stroke:#333333;}#mmd-1 svg{font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;}#mmd-1 p{margin:0;}#mmd-1 .label{font-family:\"trebuchet ms\",verdana,arial,sans-serif;color:#333;}#mmd-1 .cluster-label text{fill:#333;}#mmd-1 .cluster-label span{color:#333;}#mmd-1 .cluster-label span p{background-color:transparent;}#mmd-1 .label text,#mmd-1 span{fill:#333;color:#333;}#mmd-1 .node rect,#mmd-1 .node circle,#mmd-1 .node ellipse,#mmd-1 .node polygon,#mmd-1 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mmd-1 .rough-node .label text,#mmd-1 .node .label text,#mmd-1 .image-shape .label,#mmd-1 .icon-shape .label{text-anchor:middle;}#mmd-1 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mmd-1 .rough-node .label,#mmd-1 .node .label,#mmd-1 .image-shape .label,#mmd-1 .icon-shape .label{text-align:center;}#mmd-1 .node.clickable{cursor:pointer;}#mmd-1 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mmd-1 .arrowheadPath{fill:#333333;}#mmd-1 .edgePath .path{stroke:#333333;stroke-width:1px;}#mmd-1 .flowchart-link{stroke:#333333;fill:none;}#mmd-1 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mmd-1 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mmd-1 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mmd-1 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mmd-1 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mmd-1 .cluster text{fill:#333;}#mmd-1 .cluster span{color:#333;}#mmd-1 .node .collapsed-indicator{fill:#aaaa33;stroke:none;opacity:0.6;}#mmd-1 .node .collapsed-separator{stroke:#aaaa33;stroke-width:0.75px;}#mmd-1 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mmd-1 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mmd-1 rect.text{fill:none;stroke-width:0;}#mmd-1 .icon-shape,#mmd-1 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mmd-1 .icon-shape p,#mmd-1 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mmd-1 .icon-shape .label rect,#mmd-1 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mmd-1 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mmd-1 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mmd-1 .node .neo-node{stroke:#9370DB;}#mmd-1 [data-look=\"neo\"].node rect,#mmd-1 [data-look=\"neo\"].cluster rect,#mmd-1 [data-look=\"neo\"].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mmd-1 [data-look=\"neo\"].swimlane.cluster rect{filter:none;}#mmd-1 [data-look=\"neo\"].node path{stroke:#9370DB;stroke-width:1px;}#mmd-1 [data-look=\"neo\"].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mmd-1 [data-look=\"neo\"].node .neo-line path{stroke:#9370DB;filter:none;}#mmd-1 [data-look=\"neo\"].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mmd-1 [data-look=\"neo\"].node circle .state-start{fill:#000000;}#mmd-1 [data-look=\"neo\"].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mmd-1 [data-look=\"neo\"].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#mmd-1 :root{--mermaid-font-family:\"trebuchet ms\",verdana,arial,sans-serif;}</style><g><marker id=\"mmd-1_flowchart-v2-pointEnd\" class=\"marker flowchart-v2\" viewBox=\"0 0 10 10\" refX=\"5\" refY=\"5\" markerUnits=\"userSpaceOnUse\" markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\"><path d=\"M 0 0 L 10 5 L 0 10 z\" class=\"arrowMarkerPath\" style=\"stroke-width: 1; stroke-dasharray: 1, 0;\"></path></marker><marker id=\"mmd-1_flowchart-v2-pointStart\" class=\"marker flowchart-v2\" viewBox=\"0 0 10 10\" refX=\"4.5\" refY=\"5\" markerUnits=\"userSpaceOnUse\" markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\"><path d=\"M 0 5 L 10 10 L 10 0 z\" class=\"arrowMarkerPath\" style=\"stroke-width: 1; stroke-dasharray: 1, 0;\"></path></marker><marker id=\"mmd-1_flowchart-v2-pointEnd-margin\" class=\"marker flowchart-v2\" viewBox=\"0 0 11.5 14\" refX=\"11.5\" refY=\"7\" markerUnits=\"userSpaceOnUse\" markerWidth=\"10.5\" markerHeight=\"14\" orient=\"auto\"><path d=\"M 0 0 L 11.5 7 L 0 14 z\" class=\"arrowMarkerPath\" style=\"stroke-width: 0; stroke-dasharray: 1, 0;\"></path></marker><marker id=\"mmd-1_flowchart-v2-pointStart-margin\" class=\"marker flowchart-v2\" viewBox=\"0 0 11.5 14\" refX=\"1\" refY=\"7\" markerUnits=\"userSpaceOnUse\" markerWidth=\"11.5\" markerHeight=\"14\" orient=\"auto\"><polygon points=\"0,7 11.5,14 11.5,0\" class=\"arrowMarkerPath\" style=\"stroke-width: 0; stroke-dasharray: 1, 0;\"></polygon></marker><marker id=\"mmd-1_flowchart-v2-circleEnd\" class=\"marker flowchart-v2\" viewBox=\"0 0 10 10\" refX=\"11\" refY=\"5\" markerUnits=\"userSpaceOnUse\" markerWidth=\"11\" markerHeight=\"11\" orient=\"auto\"><circle cx=\"5\" cy=\"5\" r=\"5\" class=\"arrowMarkerPath\" style=\"stroke-width: 1; stroke-dasharray: 1, 0;\"></circle></marker><marker id=\"mmd-1_flowchart-v2-circleStart\" class=\"marker flowchart-v2\" viewBox=\"0 0 10 10\" refX=\"-1\" refY=\"5\" markerUnits=\"userSpaceOnUse\" markerWidth=\"11\" markerHeight=\"11\" orient=\"auto\"><circle cx=\"5\" cy=\"5\" r=\"5\" class=\"arrowMarkerPath\" style=\"stroke-width: 1; stroke-dasharray: 1, 0;\"></circle></marker><marker id=\"mmd-1_flowchart-v2-circleEnd-margin\" class=\"marker flowchart-v2\" viewBox=\"0 0 10 10\" refY=\"5\" refX=\"12.25\" markerUnits=\"userSpaceOnUse\" markerWidth=\"14\" markerHeight=\"14\" orient=\"auto\"><circle cx=\"5\" cy=\"5\" r=\"5\" class=\"arrowMarkerPath\" style=\"stroke-width: 0; stroke-dasharray: 1, 0;\"></circle></marker><marker id=\"mmd-1_flowchart-v2-circleStart-margin\" class=\"marker flowchart-v2\" viewBox=\"0 0 10 10\" refX=\"-2\" refY=\"5\" markerUnits=\"userSpaceOnUse\" markerWidth=\"14\" markerHeight=\"14\" orient=\"auto\"><circle cx=\"5\" cy=\"5\" r=\"5\" class=\"arrowMarkerPath\" style=\"stroke-width: 0; stroke-dasharray: 1, 0;\"></circle></marker><marker id=\"mmd-1_flowchart-v2-crossEnd\" class=\"marker cross flowchart-v2\" viewBox=\"0 0 11 11\" refX=\"12\" refY=\"5.2\" markerUnits=\"userSpaceOnUse\" markerWidth=\"11\" markerHeight=\"11\" orient=\"auto\"><path d=\"M 1,1 l 9,9 M 10,1 l -9,9\" class=\"arrowMarkerPath\" style=\"stroke-width: 2; stroke-dasharray: 1, 0;\"></path></marker><marker id=\"mmd-1_flowchart-v2-crossStart\" class=\"marker cross flowchart-v2\" viewBox=\"0 0 11 11\" refX=\"-1\" refY=\"5.2\" markerUnits=\"userSpaceOnUse\" markerWidth=\"11\" markerHeight=\"11\" orient=\"auto\"><path d=\"M 1,1 l 9,9 M 10,1 l -9,9\" class=\"arrowMarkerPath\" style=\"stroke-width: 2; stroke-dasharray: 1, 0;\"></path></marker><marker id=\"mmd-1_flowchart-v2-crossEnd-margin\" class=\"marker cross flowchart-v2\" viewBox=\"0 0 15 15\" refX=\"17.7\" refY=\"7.5\" markerUnits=\"userSpaceOnUse\" markerWidth=\"12\" markerHeight=\"12\" orient=\"auto\"><path d=\"M 1,1 L 14,14 M 1,14 L 14,1\" class=\"arrowMarkerPath\" style=\"stroke-width: 2.5;\"></path></marker><marker id=\"mmd-1_flowchart-v2-crossStart-margin\" class=\"marker cross flowchart-v2\" viewBox=\"0 0 15 15\" refX=\"-3.5\" refY=\"7.5\" markerUnits=\"userSpaceOnUse\" markerWidth=\"12\" markerHeight=\"12\" orient=\"auto\"><path d=\"M 1,1 L 14,14 M 1,14 L 14,1\" class=\"arrowMarkerPath\" style=\"stroke-width: 2.5; stroke-dasharray: 1, 0;\"></path></marker><g class=\"root\"><g class=\"clusters\"><g class=\"cluster \" id=\"mmd-1-run\" data-look=\"classic\"><rect style=\"\" x=\"625.1875\" y=\"8\" width=\"426.796875\" height=\"946.7750091552734\"></rect><g class=\"cluster-label \" transform=\"translate(783.890625, 8)\"><g><rect class=\"background\" style=\"stroke: none\"></rect><text y=\"-10.1\" style=\"\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">Agent.run(task)</tspan></tspan></text></g></g></g></g><g class=\"edgePaths\"><path d=\"M775.844,97.6L775.844,101.767C775.844,105.933,775.844,114.267,775.844,121.933C775.844,129.6,775.844,136.6,775.844,140.1L775.844,143.6\" id=\"mmd-1-L_A_B_0\" class=\" edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link\" style=\";\" data-edge=\"true\" data-et=\"edge\" data-id=\"L_A_B_0\" data-points=\"W3sieCI6Nzc1Ljg0Mzc1LCJ5Ijo5Ny41OTk5OTg0NzQxMjExfSx7IngiOjc3NS44NDM3NSwieSI6MTIyLjU5OTk5ODQ3NDEyMTF9LHsieCI6Nzc1Ljg0Mzc1LCJ5IjoxNDcuNTk5OTk4NDc0MTIxMX1d\" data-look=\"classic\" marker-end=\"url(#mmd-1_flowchart-v2-pointEnd)\"></path><path d=\"M779.826,194.6L780.532,198.767C781.238,202.933,782.65,211.267,783.356,222.709C784.063,234.151,784.063,248.703,784.063,255.978L784.063,263.254\" id=\"mmd-1-L_B_C_0\" class=\" edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link\" style=\";\" data-edge=\"true\" data-et=\"edge\" data-id=\"L_B_C_0\" data-points=\"W3sieCI6Nzc5LjgyNjAzMDkyNzgzNTEsInkiOjE5NC41OTk5OTg0NzQxMjExfSx7IngiOjc4NC4wNjI1LCJ5IjoyMTkuNTk5OTk4NDc0MTIxMX0seyJ4Ijo3ODQuMDYyNSwieSI6MjY3LjI1MzkwNjI0OTk5OTk0fV0=\" data-look=\"classic\" marker-end=\"url(#mmd-1_flowchart-v2-pointEnd)\"></path><path d=\"M802.311,373.497L809.418,390.631C816.525,407.765,830.738,442.032,837.845,468.816C844.951,495.6,844.951,514.9,844.951,524.55L844.951,534.2\" id=\"mmd-1-L_C_D_0\" class=\" edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link\" style=\";\" data-edge=\"true\" data-et=\"edge\" data-id=\"L_C_D_0\" data-points=\"W3sieCI6ODAyLjMxMTM2MjA0ODgzNzQsInkiOjM3My40OTcyMzE3MDExNjI2Nn0seyJ4Ijo4NDQuOTUxMTcxODc1LCJ5Ijo0NzYuMzAwMDAzMDUxNzU3OH0seyJ4Ijo4NDQuOTUxMTcxODc1LCJ5Ijo1MzguMjAwMDA0NTc3NjM2N31d\" data-look=\"classic\" marker-end=\"url(#mmd-1_flowchart-v2-pointEnd)\"></path><path d=\"M762.587,370.27L753.278,387.942C743.97,405.614,725.353,440.957,716.045,472.862C706.736,504.767,706.736,533.233,706.736,555.55C706.736,577.867,706.736,594.033,722.868,613.627C739,633.221,771.263,656.243,787.395,667.754L803.526,679.264\" id=\"mmd-1-L_C_E_0\" class=\" edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link\" style=\";\" data-edge=\"true\" data-et=\"edge\" data-id=\"L_C_E_0\" data-points=\"W3sieCI6NzYyLjU4Njg2NDAzMDk2MjUsInkiOjM3MC4yNzA0NTc3ODA5NjI1NH0seyJ4Ijo3MDYuNzM2MzI4MTI1LCJ5Ijo0NzYuMzAwMDAzMDUxNzU3OH0seyJ4Ijo3MDYuNzM2MzI4MTI1LCJ5Ijo1NjEuNzAwMDA0NTc3NjM2N30seyJ4Ijo3MDYuNzM2MzI4MTI1LCJ5Ijo2MTAuMjAwMDA0NTc3NjM2N30seyJ4Ijo4MDYuNzgyMjY5MDI5Mzc2NywieSI6NjgxLjU4NzY1NzQyMzI2MDF9XQ==\" data-look=\"classic\" marker-end=\"url(#mmd-1_flowchart-v2-pointEnd)\"></path><path d=\"M844.951,585.2L844.951,589.367C844.951,593.533,844.951,601.867,845.303,610.501C845.654,619.136,846.357,628.072,846.708,632.541L847.06,637.009\" id=\"mmd-1-L_D_E_0\" class=\" edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link\" style=\";\" data-edge=\"true\" data-et=\"edge\" data-id=\"L_D_E_0\" data-points=\"W3sieCI6ODQ0Ljk1MTE3MTg3NSwieSI6NTg1LjIwMDAwNDU3NzYzNjd9LHsieCI6ODQ0Ljk1MTE3MTg3NSwieSI6NjEwLjIwMDAwNDU3NzYzNjd9LHsieCI6ODQ3LjM3MzU0NTAyNzk1MjksInkiOjY0MC45OTYzODE0MjQ2ODM3fV0=\" data-look=\"classic\" marker-end=\"url(#mmd-1_flowchart-v2-pointEnd)\"></path><path d=\"M895.502,677.532L908.288,666.31C921.074,655.088,946.645,632.644,959.431,613.339C972.217,594.033,972.217,577.867,972.217,555.55C972.217,533.233,972.217,504.767,972.217,466.067C972.217,427.367,972.217,378.433,972.217,335.65C972.217,292.867,972.217,256.233,952.398,233.022C932.58,209.81,892.942,200.021,873.124,195.126L853.305,190.231\" id=\"mmd-1-L_E_B_0\" class=\" edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link\" style=\";\" data-edge=\"true\" data-et=\"edge\" data-id=\"L_E_B_0\" data-points=\"W3sieCI6ODk1LjUwMjI4NjY4NzY4OTgsInkiOjY3Ny41MzIzNjkzOTAzMjY1fSx7IngiOjk3Mi4yMTY3OTY4NzUsInkiOjYxMC4yMDAwMDQ1Nzc2MzY3fSx7IngiOjk3Mi4yMTY3OTY4NzUsInkiOjU2MS43MDAwMDQ1Nzc2MzY3fSx7IngiOjk3Mi4yMTY3OTY4NzUsInkiOjQ3Ni4zMDAwMDMwNTE3NTc4fSx7IngiOjk3Mi4yMTY3OTY4NzUsInkiOjMyOS41fSx7IngiOjk3Mi4yMTY3OTY4NzUsInkiOjIxOS41OTk5OTg0NzQxMjExfSx7IngiOjg0OS40MjE4NzUsInkiOjE4OS4yNzIyNDMxODUzMzkxNn1d\" data-look=\"classic\" marker-end=\"url(#mmd-1_flowchart-v2-pointEnd)\"></path><path d=\"M853.17,794.175L853.17,800.092C853.17,806.008,853.17,817.842,853.17,829.008C853.17,840.175,853.17,850.675,853.17,855.925L853.17,861.175\" id=\"mmd-1-L_E_F_0\" class=\" edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link\" style=\";\" data-edge=\"true\" data-et=\"edge\" data-id=\"L_E_F_0\" data-points=\"W3sieCI6ODUzLjE2OTkyMTg3NDk5OTksInkiOjc5NC4xNzUwMTA2ODExNTI1fSx7IngiOjg1My4xNjk5MjE4NzUsInkiOjgyOS42NzUwMTA2ODExNTIzfSx7IngiOjg1My4xNjk5MjE4NzUsInkiOjg2NS4xNzUwMTA2ODExNTIzfV0=\" data-look=\"classic\" marker-end=\"url(#mmd-1_flowchart-v2-pointEnd)\"></path><path d=\"M734.861,194.6L727.594,198.767C720.328,202.933,705.795,211.267,682.324,219.974C658.854,228.682,626.447,237.764,610.243,242.304L594.039,246.845\" id=\"mmd-1-L_B_step_0\" class=\" edge-thickness-normal edge-pattern-dotted edge-thickness-normal edge-pattern-solid flowchart-link\" style=\";\" data-edge=\"true\" data-et=\"edge\" data-id=\"L_B_step_0\" data-points=\"W3sieCI6NzM0Ljg2MDcwMzkzMDQxMjMsInkiOjE5NC41OTk5OTg0NzQxMjExfSx7IngiOjY5MS4yNjE3MTg3NSwieSI6MjE5LjU5OTk5ODQ3NDEyMTF9LHsieCI6NTkwLjE4NzUsInkiOjI0Ny45MjQ3NDExMzU0MzAxfV0=\" data-look=\"classic\" marker-end=\"url(#mmd-1_flowchart-v2-pointEnd)\"></path></g><g class=\"edgeLabels\"><g class=\"edgeLabel\"><g class=\"label\" data-id=\"L_A_B_0\" transform=\"translate(0, 0)\"><text y=\"-10.1\" text-anchor=\"middle\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\" text-anchor=\"middle\"></tspan></text></g></g><g><rect class=\"background\" style=\"stroke: none\"></rect></g><g class=\"edgeLabel\"><g class=\"label\" data-id=\"L_B_C_0\" transform=\"translate(0, 0)\"><text y=\"-10.1\" text-anchor=\"middle\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\" text-anchor=\"middle\"></tspan></text></g></g><g><rect class=\"background\" style=\"stroke: none\"></rect></g><g class=\"edgeLabel\" transform=\"translate(844.951171875, 476.3000030517578)\"><g class=\"label\" data-id=\"L_C_D_0\" transform=\"translate(-0.21875, -36.900001525878906)\"><g><rect class=\"background\" style=\"\" x=\"-69.59375\" y=\"0\" width=\"139.625\" height=\"73.80000305175781\"></rect><text y=\"-10.1\" text-anchor=\"middle\" style=\"\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\" text-anchor=\"middle\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">InterruptAgentFlow</tspan></tspan><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"1em\" dy=\"1.1em\" text-anchor=\"middle\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">(Submitted,</tspan></tspan><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"2.1em\" dy=\"1.1em\" text-anchor=\"middle\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">LimitsExceeded,</tspan></tspan><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"3.2em\" dy=\"1.1em\" text-anchor=\"middle\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">FormatError)</tspan></tspan></text></g></g></g><g class=\"edgeLabel\" transform=\"translate(706.736328125, 561.7000045776367)\"><g class=\"label\" data-id=\"L_C_E_0\" transform=\"translate(-0.05078125, -10.5)\"><g><rect class=\"background\" style=\"\" x=\"-10.8984375\" y=\"0\" width=\"21.8984375\" height=\"21\"></rect><text y=\"-10.1\" text-anchor=\"middle\" style=\"\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\" text-anchor=\"middle\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">no</tspan></tspan></text></g></g></g><g class=\"edgeLabel\"><g class=\"label\" data-id=\"L_D_E_0\" transform=\"translate(0, 0)\"><text y=\"-10.1\" text-anchor=\"middle\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\" text-anchor=\"middle\"></tspan></text></g></g><g><rect class=\"background\" style=\"stroke: none\"></rect></g><g class=\"edgeLabel\" transform=\"translate(972.216796875, 476.3000030517578)\"><g class=\"label\" data-id=\"L_E_B_0\" transform=\"translate(-0.05078125, -10.5)\"><g><rect class=\"background\" style=\"\" x=\"-10.8984375\" y=\"0\" width=\"21.8984375\" height=\"21\"></rect><text y=\"-10.1\" text-anchor=\"middle\" style=\"\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\" text-anchor=\"middle\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">no</tspan></tspan></text></g></g></g><g class=\"edgeLabel\" transform=\"translate(853.169921875, 829.6750106811523)\"><g class=\"label\" data-id=\"L_E_F_0\" transform=\"translate(0, -10.5)\"><g><rect class=\"background\" style=\"\" x=\"-14.453125\" y=\"0\" width=\"28.90625\" height=\"21\"></rect><text y=\"-10.1\" text-anchor=\"middle\" style=\"\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\" text-anchor=\"middle\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">yes</tspan></tspan></text></g></g></g><g class=\"edgeLabel\"><g class=\"label\" data-id=\"L_B_step_0\" transform=\"translate(0, 0)\"><text y=\"-10.1\" text-anchor=\"middle\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\" text-anchor=\"middle\"></tspan></text></g></g><g><rect class=\"background\" style=\"stroke: none\"></rect></g></g><g class=\"nodes\"><g class=\"root\" transform=\"translate(0, 236.5999984741211)\"><g class=\"clusters\"><g class=\"cluster \" id=\"mmd-1-step\" data-look=\"classic\"><rect style=\"\" x=\"8\" y=\"8\" width=\"582.1875\" height=\"169.8000030517578\"></rect><g class=\"cluster-label \" transform=\"translate(255.515625, 8)\"><g><rect class=\"background\" style=\"stroke: none\"></rect><text y=\"-10.1\" style=\"\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">Agent.step()</tspan></tspan></text></g></g></g></g><g class=\"edgePaths\"><path d=\"M245.141,92.9L251.391,92.9C257.641,92.9,270.141,92.9,281.974,92.9C293.807,92.9,304.974,92.9,310.557,92.9L316.141,92.9\" id=\"mmd-1-L_Q_X_0\" class=\" edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link\" style=\";\" data-edge=\"true\" data-et=\"edge\" data-id=\"L_Q_X_0\" data-points=\"W3sieCI6MjQ1LjE0MDYyNSwieSI6OTIuOTAwMDAxNTI1ODc4OX0seyJ4IjoyODIuNjQwNjI1LCJ5Ijo5Mi45MDAwMDE1MjU4Nzg5fSx7IngiOjMyMC4xNDA2MjUsInkiOjkyLjkwMDAwMTUyNTg3ODl9XQ==\" data-look=\"classic\" marker-end=\"url(#mmd-1_flowchart-v2-pointEnd)\"></path></g><g class=\"edgeLabels\"><g class=\"edgeLabel\"><g class=\"label\" data-id=\"L_Q_X_0\" transform=\"translate(0, 0)\"><text y=\"-10.1\" text-anchor=\"middle\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\" text-anchor=\"middle\"></tspan></text></g></g><g><rect class=\"background\" style=\"stroke: none\"></rect></g></g><g class=\"nodes\"><g class=\"node default  \" id=\"mmd-1-flowchart-Q-14\" data-look=\"classic\" transform=\"translate(145.3203125, 92.9000015258789)\"><rect class=\"basic label-container\" style=\"\" x=\"-99.8203125\" y=\"-49.900001525878906\" width=\"199.640625\" height=\"99.80000305175781\"></rect><g class=\"label\" style=\"\" transform=\"translate(0, -34.900001525878906)\"><rect></rect><g><rect class=\"background\" style=\"stroke: none\"></rect><text y=\"-10.1\" style=\"\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">Agent.query()</tspan></tspan><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">check</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> budgets</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> →</tspan></tspan><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"2.1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">Model.query</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> →</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> add</tspan></tspan><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"3.2em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">message</tspan></tspan></text></g></g></g><g class=\"node default  \" id=\"mmd-1-flowchart-X-15\" data-look=\"classic\" transform=\"translate(436.4140625, 92.9000015258789)\"><rect class=\"basic label-container\" style=\"\" x=\"-116.2734375\" y=\"-41.099998474121094\" width=\"232.546875\" height=\"82.19999694824219\"></rect><g class=\"label\" style=\"\" transform=\"translate(0, -26.099998474121094)\"><rect></rect><g><rect class=\"background\" style=\"stroke: none\"></rect><text y=\"-10.1\" style=\"\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">Agent.execute_actions()</tspan></tspan><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">Environment.execute</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> →</tspan></tspan><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"2.1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">add</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> observation</tspan></tspan></text></g></g></g></g></g><g class=\"node default  \" id=\"mmd-1-flowchart-A-0\" data-look=\"classic\" transform=\"translate(775.84375, 65.29999923706055)\"><rect class=\"basic label-container\" style=\"\" x=\"-97.1484375\" y=\"-32.29999923706055\" width=\"194.296875\" height=\"64.5999984741211\"></rect><g class=\"label\" style=\"\" transform=\"translate(0, -17.299999237060547)\"><rect></rect><g><rect class=\"background\" style=\"stroke: none\"></rect><text y=\"-10.1\" style=\"\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">initialise</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> messages</tspan></tspan><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">(system</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> +</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> task)</tspan></tspan></text></g></g></g><g class=\"node default  \" id=\"mmd-1-flowchart-B-1\" data-look=\"classic\" transform=\"translate(775.84375, 171.0999984741211)\"><rect class=\"basic label-container\" style=\"\" x=\"-73.578125\" y=\"-23.5\" width=\"147.15625\" height=\"47\"></rect><g class=\"label\" style=\"\" transform=\"translate(0, -8.5)\"><rect></rect><g><rect class=\"background\" style=\"stroke: none\"></rect><text y=\"-10.1\" style=\"\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">Agent.step()</tspan></tspan></text></g></g></g><g class=\"node default  \" id=\"mmd-1-flowchart-C-3\" data-look=\"classic\" transform=\"translate(784.0625, 329.5)\"><polygon points=\"62.24609375,0 124.4921875,-62.24609375 62.24609375,-124.4921875 0,-62.24609375\" class=\"label-container\" transform=\"translate(-61.74609375, 62.24609375)\"></polygon><g class=\"label\" style=\"\" transform=\"translate(0, -8.5)\"><rect></rect><g><rect class=\"background\" style=\"stroke: none\"></rect><text y=\"-10.1\" style=\"\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">exception?</tspan></tspan></text></g></g></g><g class=\"node default  \" id=\"mmd-1-flowchart-D-5\" data-look=\"classic\" transform=\"translate(844.951171875, 561.7000045776367)\"><rect class=\"basic label-container\" style=\"\" x=\"-92.265625\" y=\"-23.5\" width=\"184.53125\" height=\"47\"></rect><g class=\"label\" style=\"\" transform=\"translate(0, -8.5)\"><rect></rect><g><rect class=\"background\" style=\"stroke: none\"></rect><text y=\"-10.1\" style=\"\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">add</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> its</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> messages</tspan></tspan></text></g></g></g><g class=\"node default  \" id=\"mmd-1-flowchart-E-7\" data-look=\"classic\" transform=\"translate(853.169921875, 714.6875076293945)\"><polygon points=\"79.48749923706055,0 158.9749984741211,-79.48749923706055 79.48749923706055,-158.9749984741211 0,-79.48749923706055\" class=\"label-container\" transform=\"translate(-78.98749923706055, 79.48749923706055)\"></polygon><g class=\"label\" style=\"\" transform=\"translate(0, -17.299999237060547)\"><rect></rect><g><rect class=\"background\" style=\"stroke: none\"></rect><text y=\"-10.1\" style=\"\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">last</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> message</tspan></tspan><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">role</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> ==</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> exit?</tspan></tspan></text></g></g></g><g class=\"node default  \" id=\"mmd-1-flowchart-F-13\" data-look=\"classic\" transform=\"translate(853.169921875, 897.4750099182129)\"><rect class=\"basic label-container\" style=\"\" x=\"-93.5859375\" y=\"-32.29999923706055\" width=\"187.171875\" height=\"64.5999984741211\"></rect><g class=\"label\" style=\"\" transform=\"translate(0, -17.299999237060547)\"><rect></rect><g><rect class=\"background\" style=\"stroke: none\"></rect><text y=\"-10.1\" style=\"\"><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"-0.1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">return</tspan><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\"> exit_status,</tspan></tspan><tspan class=\"text-outer-tspan row\" x=\"0\" y=\"1em\" dy=\"1.1em\"><tspan font-style=\"normal\" class=\"text-inner-tspan\" font-weight=\"normal\">submission</tspan></tspan></text></g></g></g></g></g></g><defs><filter id=\"mmd-1-drop-shadow\" height=\"130%\" width=\"130%\"><feDropShadow dx=\"4\" dy=\"4\" stdDeviation=\"0\" flood-opacity=\"0.06\" flood-color=\"#000000\"></feDropShadow></filter></defs><defs><filter id=\"mmd-1-drop-shadow-small\" height=\"150%\" width=\"150%\"><feDropShadow dx=\"2\" dy=\"2\" stdDeviation=\"0\" flood-opacity=\"0.06\" flood-color=\"#000000\"></feDropShadow></filter></defs></svg>\n",
    "</div>\n",
    "\n",
    "| Ours | mini-swe-agent | Differences in mini |\n",
    "|---|---|---|\n",
    "| `TextModel.query` | `LitellmTextbasedModel.query` | cost instead of tokens; stores the whole response object in `extra` |\n",
    "| `PodmanEnvironment` | `DockerEnvironment(executable=\"podman\")` | config object; forwards env vars; `execute` takes the action as a dict |\n",
    "| `Agent.run / step / query / execute_actions` | `DefaultAgent`, same four methods | wall-clock limit; templates get *all* config values as variables |\n",
    "| `Agent.save` | `DefaultAgent.save` / `serialize` | also stores the full config of all three parts |\n",
    "\n",
    "**Concept.** The loop is a small **state machine**: states *query* and *execute*, transitions on the exception type, one accepting state *exit* (→ [L-Orch](http://christianherta.de/lehre/ai-agents/lecture-11/lecture-11-Orch.html)). Writing it as a state machine is what lets frameworks add checkpoints, branches and human approval steps."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b16c1ecd",
   "metadata": {},
   "outputs": [],
   "source": [
    "make_toy_repo()\n",
    "env = PodmanEnvironment()\n",
    "agent = Agent(TextModel(), env, output_path=Path(\"trajectories/ours-fix-median.traj.json\"))\n",
    "result = agent.run(TASK)\n",
    "print(result[\"exit_status\"], f\"after {agent.n_calls} model calls, {agent.n_tokens} tokens\")\n",
    "verify()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e76a3779",
   "metadata": {},
   "source": [
    "## Trajectories\n",
    "\n",
    "The saved file is the **trajectory**: every message of the run plus some metadata. mini's authors point out that, with a linear history, there is *no difference* between what the model saw and what is logged, which makes debugging unusually easy. The one exception is a malformed reply: it is logged in the format-error message's metadata without ever entering the history. One line per step:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "28073d63",
   "metadata": {},
   "outputs": [],
   "source": [
    "data = json.loads(Path(\"trajectories/ours-fix-median.traj.json\").read_text())\n",
    "print(data[\"info\"])\n",
    "steps = [m for m in data[\"messages\"] if m.get(\"extra\", {}).keys() & {\"action\", \"model_response\"}]\n",
    "for i, m in enumerate(steps, 1):\n",
    "    extra = m[\"extra\"]\n",
    "    text = extra.get(\"model_response\", m[\"content\"]).strip()          # the reply, wherever it was kept\n",
    "    thought = text.splitlines()[0][:70] if text else \"\"\n",
    "    action = extra[\"action\"].replace(\"\\n\", \" ⏎ \")[:60] if \"action\" in extra else \"<format error>\"\n",
    "    print(f\"{i:>2}. {thought:<70} | $ {action}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ae8da573",
   "metadata": {},
   "source": [
    "**Concept.** The trajectory is one **episode** of an MDP (→ [L-MDP](http://christianherta.de/lehre/ai-agents/lecture-05/lecture-05-MDP.html)):\n",
    "\n",
    "| MDP | Our agent |\n",
    "|---|---|\n",
    "| state $s_t$ | the files in `/repo` plus the message history |\n",
    "| observation $o_t$ | return code + output of the last command; the model sees only the history, so the problem is **partially observable** |\n",
    "| action $a_t$ | one bash command (with its THOUGHT) |\n",
    "| transition | the container executing the command |\n",
    "| reward | none during the run; at the end: *do the tests pass?* A sparse, terminal reward that the agent never sees |\n",
    "| terminal state / horizon | the `exit` message / `step_limit` |\n",
    "\n",
    "Trajectories are also what **evaluation** works on (→ [L-Eval](http://christianherta.de/lehre/ai-agents/lecture-10/lecture-10-Eval.html)). SWE-bench scores an agent by running tests on the final patch it produces for real GitHub issues ([Jimenez et al., 2024](https://arxiv.org/html/2310.06770)). That is our `verify()` at scale, and it ignores how the agent got there. Reading trajectories is how you find out *why* it failed."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a27aea08",
   "metadata": {},
   "source": [
    "## Safety: A Human in the Loop\n",
    "\n",
    "The container limits the **damage** a bad command can do. A human in the loop decides **whether** it runs. mini's `InteractiveAgent` has three modes: `confirm` (ask before each command), `yolo` (never ask) and `human` (the human types the commands), plus a whitelist of regexes for commands that run without asking. In our class structure this is a single overridden method:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "65a67ddf",
   "metadata": {},
   "outputs": [],
   "source": [
    "class ConfirmingAgent(Agent):\n",
    "    def __init__(self, *args, mode=\"confirm\", whitelist=(r\"^(ls|cat|nl|grep|head|tail)\\b\",), ask=input, **kwargs):\n",
    "        super().__init__(*args, **kwargs)\n",
    "        self.mode, self.whitelist, self.ask = mode, whitelist, ask\n",
    "\n",
    "    def execute_actions(self, message):\n",
    "        command = message[\"extra\"][\"action\"]\n",
    "        if self.mode == \"confirm\" and not any(re.match(p, command) for p in self.whitelist):\n",
    "            answer = self.ask(f\"Execute?\\n  {command}\\n[y = run, anything else = reject with that comment] \")\n",
    "            if answer.strip().lower() not in (\"y\", \"yes\"):\n",
    "                raise InterruptAgentFlow({\"role\": \"user\", \"content\": f\"The user rejected this command: {answer}\"})\n",
    "        return super().execute_actions(message)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "477d971a",
   "metadata": {},
   "source": [
    "A rejection is, again, just an observation: the model reads the user's comment and tries something else.\n",
    "\n",
    "Look closely at the whitelist, though: `re.match(r\"^(ls|…)\\b\", \"ls; rm -rf stats\")` **matches**. A prefix check on a shell string says nothing about what the string does. The whitelist is a convenience, not a security boundary; the container is the boundary (→ [L-Gateway](http://christianherta.de/lehre/ai-agents/lecture-13/lecture-13-Gateway.html))."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1e056bf3",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(bool(re.match(r\"^(ls|cat|nl|grep|head|tail)\\b\", \"ls; rm -rf stats\")))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "11fd5485",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Interactive: answer the prompts below. For a non-interactive run pass ask=lambda prompt: \"y\".\n",
    "make_toy_repo()\n",
    "agent = ConfirmingAgent(TextModel(), env, step_limit=10)\n",
    "print(agent.run(TASK)[\"exit_status\"])\n",
    "verify()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c4d3a995",
   "metadata": {},
   "source": [
    "## The Real Thing: mini-swe-agent\n",
    "\n",
    "Now the same task with the original package. We use its text-based config (`mini_textbased.yaml`), its text-based LiteLLM model and its `DockerEnvironment` with podman as the executable and our mount and security flags. Two local-model adjustments: cost tracking is switched off (Ollama has no prices), and since the default money budget can therefore never trigger, we set a step limit."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "12511035",
   "metadata": {},
   "outputs": [],
   "source": [
    "# %pip install 'mini-swe-agent==2.4.6'          # or, from a clone: %pip install -e path/to/mini-swe-agent\n",
    "import yaml\n",
    "\n",
    "os.environ[\"MSWEA_SILENT_STARTUP\"] = \"1\"          # must be set before the import\n",
    "from minisweagent import package_dir\n",
    "from minisweagent.agents.default import DefaultAgent\n",
    "from minisweagent.environments.docker import DockerEnvironment\n",
    "from minisweagent.models.litellm_textbased_model import LitellmTextbasedModel\n",
    "\n",
    "import logging\n",
    "logging.getLogger(\"minisweagent\").setLevel(logging.WARNING)   # mini logs every container command at DEBUG\n",
    "\n",
    "config = yaml.safe_load((package_dir / \"config\" / \"mini_textbased.yaml\").read_text())\n",
    "config"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3a6dc0ec",
   "metadata": {},
   "outputs": [],
   "source": [
    "make_toy_repo()\n",
    "mini_env = DockerEnvironment(\n",
    "    image=IMAGE, executable=\"podman\", cwd=\"/repo\",\n",
    "    run_args=[\"--rm\", \"--network=none\", \"--cap-drop=ALL\", \"-v\", f\"{SANDBOX}:/repo:Z\"],\n",
    "    **config[\"environment\"],\n",
    ")\n",
    "mini_model = LitellmTextbasedModel(model_name=MODEL, cost_tracking=\"ignore_errors\", **config[\"model\"])\n",
    "mini_agent = DefaultAgent(\n",
    "    mini_model, mini_env,\n",
    "    **(config[\"agent\"] | {\"step_limit\": 15, \"output_path\": Path(\"trajectories/mini-fix-median.traj.json\")}),\n",
    ")\n",
    "mini_result = mini_agent.run(TASK)\n",
    "print(mini_result[\"exit_status\"], f\"after {mini_agent.n_calls} model calls\")\n",
    "verify()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "79ac5cd3",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "Compare the two trajectory files side by side: same message structure, same roles, same observation format. The differences are mini's much longer instance template (more command recipes, platform-specific hints for macOS `sed`) and the bookkeeping in `info`. Now `agents/default.py` should read like something you have written yourself.\n",
    "\n",
    "Clean up the containers:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c93890f8",
   "metadata": {},
   "outputs": [],
   "source": [
    "env.close()\n",
    "subprocess.run([\"podman\", \"rm\", \"-f\", CONTAINER, mini_env.container_id], capture_output=True)\n",
    "print(\"containers removed\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e4555919",
   "metadata": {},
   "source": [
    "## What mini-swe-agent Leaves Out\n",
    "\n",
    "Every one of these omissions is deliberate, and each is a topic of its own:\n",
    "\n",
    "- **A persistent shell.** Every command runs in a fresh subshell, so a `cd`, an `export` or an activated virtual environment is gone by the next step: the prompt has to ask for `cd /repo && …` instead, and no long-running or interactive process is possible. SWE-agent keeps one shell session open for the whole run ([Yang et al., 2024](https://arxiv.org/html/2405.15793)). The session makes that state persist; it also introduces state the model cannot see unless it asks, and a shell that can hang on a pager or on a command waiting for input.\n",
    "- **History management.** The history grows until the budget or the context window runs out; nothing is summarised or dropped (→ [L-Memory](http://christianherta.de/lehre/ai-agents/lecture-09/lecture-09-Memory.html)).\n",
    "- **Search over alternatives.** One trajectory, no backtracking and no comparison of candidate fixes (→ [L-ToT](http://christianherta.de/lehre/ai-agents/lecture-04/lecture-04-ToT.html)).\n",
    "- **Detection of a repetition.** Nothing compares a step with the steps before it, so a model alternating the same edit and the same test run is stopped only by a budget. The comparison itself is a set lookup; what to do on a match — warn the model, refuse the command, end the run — is the part that needs deciding.\n",
    "- **An enforced workflow.** Reproduce → fix → verify is a suggestion in the prompt, not a state machine in code (→ [L-Orch](http://christianherta.de/lehre/ai-agents/lecture-11/lecture-11-Orch.html)).\n",
    "- **Several agents.** No planner/worker split, no reviewer (→ [L-MAS](http://christianherta.de/lehre/ai-agents/lecture-12/lecture-12-MAS.html)).\n",
    "- **Evaluation at scale.** One task, one run, no statistics. Models are stochastic, and one success proves little (→ [L-Eval](http://christianherta.de/lehre/ai-agents/lecture-10/lecture-10-Eval.html)).\n",
    "\n",
    "**Things to try.**\n",
    "\n",
    "1. Turn `TextModel` into a `ToolCallModel` using `BASH_TOOL`; what changes in `Agent`? (Answer: almost nothing. That is the point of the split.)\n",
    "2. Add a wall-clock budget to `check_limits`.\n",
    "3. Add naive compaction: above a token threshold, replace the content of old observations with `[elided]`. Does the agent still finish?\n",
    "4. Write three commands that pass the whitelist in `ConfirmingAgent` but do something else.\n",
    "5. Run the bug fix five times per model with two models. How often does each succeed, and how different are the trajectories?\n",
    "6. Give the toy repo a harder bug (e.g. `mean([])` should raise `ValueError` with a clear message, and a test that checks the message).\n",
    "7. Replace `PodmanEnvironment` with one that keeps a single shell open (`podman exec -i … bash`, commands written to its stdin) and reads the output up to a marker echoed after each command. Which commands behave differently now, what does the harness have to do when one of them never returns, and what does each of the two designs cost?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2018621d",
   "metadata": {},
   "source": [
    "## References\n",
    "\n",
    "**Peer-reviewed papers**\n",
    "\n",
    "- Jimenez, Carlos E., et al. \"SWE-bench: Can Language Models Resolve Real-World GitHub Issues?\" International Conference on Learning Representations. Vol. 2024. 2024. [arXiv:2310.06770](https://arxiv.org/html/2310.06770).\n",
    "- Liu, Nelson F., et al. \"Lost in the Middle: How Language Models Use Long Contexts.\" Transactions of the Association for Computational Linguistics, vol. 12, 2024. [arXiv:2307.03172](https://arxiv.org/html/2307.03172).\n",
    "- Wang, Xingyao, et al. \"Executable Code Actions Elicit Better LLM Agents.\" International Conference on Machine Learning. Vol. 235. 2024. [arXiv:2402.01030](https://arxiv.org/html/2402.01030).\n",
    "- Yang, John, et al. \"SWE-agent: Agent-Computer Interfaces Enable Automated Software Engineering.\" Advances in Neural Information Processing Systems. Vol. 37. 2024. [arXiv:2405.15793](https://arxiv.org/html/2405.15793).\n",
    "- Yao, Shunyu, et al. \"ReAct: Synergizing Reasoning and Acting in Language Models.\" International Conference on Learning Representations. Vol. 2023. 2023. [arXiv:2210.03629](https://arxiv.org/html/2210.03629).\n",
    "\n",
    "**Blogs, documentation & other web sources**\n",
    "\n",
    "- BerriAI. \"LiteLLM: Call 100+ LLM APIs in OpenAI Format — Documentation.\" 2026. <https://docs.litellm.ai/>\n",
    "- Lieret, Kilian A., and Carlos E. Jimenez. *mini-swe-agent: The Minimal AI Software Engineering Agent*. GitHub repository, v2.4.6, 2026. <https://github.com/SWE-agent/mini-swe-agent>\n",
    "- Lieret, Kilian, et al. \"Minimal AI agent tutorial.\" 2026. <https://minimal-agent.com/>"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}