Developing a web-browsing AI agent from scratch.

Notes on how I built a web-browsing AI agent to book tennis courts for me.

I connected the agent to a Telegram Chatbot so that I can book tennis courts from anywhere via text message.

For example, I can say: “hey are there any courts free tmrw 6-7 pm?” and the agent would go and check. Then I’d follow-up with “book a court for me and Joe Doe” and the agent would book it.

The agent was built when vision models where good, but not perfect. It required a few hacks to get it to navigate websites reliably. For example, when the agent (say, Claude) wants to click on a button, I would give different LLM (say, Gemini) a zoomed-in picture of that button for a second opinion.

Here is a sketch of the architecture of the AI agent:

┌─────────────────────────────────────────────────────────────────────────────────┐
│                           WEB BROWSING AGENT SYSTEM                             │
└─────────────────────────────────────────────────────────────────────────────────┘

                              ┌─────────────────┐
                              │  USER INTERFACE │
                              │                 │
                              │ • Telegram Bot  │
                              │ • Direct API    │
                              └─────────┬───────┘
                                        │
                                        │ Task Request
                                        ▼
    ┌─────────────────────────────────────────────────────────────────────────────┐
    │                        AGENT CONTROLLER                                     │
    │  ┌─────────────────────────────────────────────────────────────────────┐    │
    │  │                    MAIN AGENT LOOP                                  │    │
    │  │                                                                     │    │
    │  │  • System & Task Prompts (src/prompts.py)                           │    │
    │  │  • Message Management                                               │    │
    │  │  • Tool Orchestration                                               │    │
    │  │  • Response Parsing                                                 │    │
    │  │  • Self-reflection & Validation                                     │    │
    │  └─────────────────────────────────────────────────────────────────────┘    │
    └─────────────────┬───────────────────────────────────────────────────────────┘
                      │
                      │ LLM Calls
                      ▼
    ┌─────────────────────────────────────────────────────────────────────────────┐
    │                      MULTI-MODEL LLM LAYER                                  │
    │                                                                             │
    │  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐              │
    │  │   Claude 3.5    │  │    GPT-4o       │  │  Gemini 1.5     │              │
    │  │    Sonnet       │  │                 │  │   Pro/Flash     │              │
    │  │  (Primary)      │  │   (Fallback)    │  │(Images + Tables)│              │
    │  └─────────────────┘  └─────────────────┘  └─────────────────┘              │
    │                                                                             │
    │  • Vision + Text Processing                                                 │
    │  • Tool Function Calling                                                    │
    │  • Overload Handling & Retry Logic                                          │
    └─────────────────┬───────────────────────────────────────────────────────────┘
                      │
                      │ Tool Calls
                      ▼
    ┌─────────────────────────────────────────────────────────────────────────────┐
    │                        BROWSER TOOLS LAYER                                  │
    │                                                                             │
    │  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐              │
    │  │     CLICK       │  │   TYPE_TEXT     │  │     SCROLL      │              │
    │  │                 │  │                 │  │                 │              │
    │  │ • Click on UI   │  │ • Input text    │  │ • Scroll up/    │              │
    │  │   elements      │  │   into fields   │  │   down pages    │              │
    │  │ • Use element   │  │ • Focus & type  │  │ • Navigate      │              │
    │  │   coordinates   │  │                 │  │   content       │              │
    │  └─────────────────┘  └─────────────────┘  └─────────────────┘              │
    │                                                                             │
    │  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐              │
    │  │  MAKE_SCREENSHOT│  │   GO_BACK       │  │ ANALYZE_BOOKING │              │
    │  │                 │  │                 │  │     _TABLE      │              │
    │  │ • Full page     │  │ • Browser back  │  │                 │              │
    │  │   screenshots   │  │   navigation    │  │ • Parse table   │              │
    │  │ • Visual        │  │ • History       │  │   data with LLM │              │
    │  │   observation   │  │   management    │  │ • Extract       │              │
    │  └─────────────────┘  └─────────────────┘  │   availability  │              │
    │                                            └─────────────────┘              │
    └─────────────────┬───────────────────────────────────────────────────────────┘
                      │
                      │ Browser Control
                      ▼
    ┌────────────────────────────────────────────────────────────────────────────┐
    │                     BROWSER AUTOMATION LAYER                               │
    │                                                                            │
    │  ┌─────────────────────────────────────────────────────────────────────┐   │
    │  │                      PLAYWRIGHT ENGINE                              │   │
    │  │                                                                     │   │
    │  │  • Chromium Browser Control                                         │   │
    │  │  • Page Navigation & Interaction                                    │   │
    │  │  • Clickable Element Detection & Annotation                         │   │
    │  │  • Screenshot Capture                                               │   │
    │  │  • JavaScript Execution                                             │   │
    │  └─────────────────────────────────────────────────────────────────────┘   │
    │                                                                            │
    │  ┌─────────────────────────────────────────────────────────────────────┐   │
    │  │                   WEB ELEMENT ANNOTATOR                             │   │
    │  │                                                                     │   │
    │  │  • JavaScript for clickable element detection (mark_page.js)        │   │
    │  │  • UI element labeling with numbers                                 │   │
    │  │  • Coordinates (x,y) extraction for CLICK tool                      │   │
    │  └─────────────────────────────────────────────────────────────────────┘   │
    │                                                                            │
    └─────────────────┬──────────────────────────────────────────────────────────┘
                      │
                      │ Web Requests
                      ▼
    ┌─────────────────────────────────────────────────────────────────────────────┐
    │                         TARGET WEBSITE                                      │
    │                                                                             │
    │                  • Tennis Court Booking Systems                             │
    │                  • Dynamic Web Applications                                 │
    │                  • Complex UI Interactions                                  │
    │                                                                             │
    └─────────────────────────────────────────────────────────────────────────────┘