> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tinyfish.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# How TinyAgent works

> Understand what happens between sending a goal and getting structured results back, and where TinyFish's web-native model fits in

TinyAgent takes a URL and a goal written in plain English, works through the site in a live browser, and returns a structured result. Two parts share the work: TinyFish's [web-native model](https://www.tinyfish.ai/mako) decides what to do next on each page, and the agent around it carries out those decisions in the browser and manages the run.

## The model decides, the agent acts

Each step of a run is a loop. The model looks at the page, picks the element and the action that move the goal forward, and the agent performs that action in the browser. The page changes, and the model reads it again.

```mermaid theme={null}
flowchart LR
  req["<b>Request</b><br/>url · goal<br/>output_schema (optional)"]

  subgraph agent["TinyAgent: runs the browser, manages the run, returns the result"]
    run["<b>Manage run</b><br/>Mode · limits<br/>Profiles · Vault"]
    browser["<b>Live browser</b><br/>Carries out each action"]
    done["<b>Return result</b><br/>Ends the run"]
  end

  subgraph model["Web model: decides the next step on each page"]
    decide["<b>Next action</b><br/>for this page"]
  end

  out["<b>Result</b><br/>Structured JSON"]

  req -- "API · Python & TS SDKs" --> run
  run --> browser
  browser -- page --> decide
  decide -- action --> browser
  browser --> done --> out
  events["<b>Streamed events</b><br/>STARTED · STREAMING_URL<br/>PROGRESS (one per step) · COMPLETE"]
  agent -. "streams while it runs" .-> events

  classDef accent stroke:#D74B28,stroke-width:1.5px;
  class decide accent;
  style model stroke:#D74B28,fill:transparent;
  style agent fill:transparent;
```

| Part | What it does |
| - | - |
| TinyFish's web-native model | Reads page elements as structured semantics, meaning what each element is for and how it behaves. It picks the relevant element and the next action, and keeps page state across a multi-page workflow. |
| TinyAgent | Runs the browser and carries out each action the model picks. It handles model inference, browser infrastructure, proxies, retries and storage, and returns the result along with a streaming URL, logs and screenshots. |

The split exists because operating a website is an execution job, not a reasoning job. A general-purpose model can plan almost anything, but on a live site the hard part is narrower and repeats every step: find the right control on a page that changed last week, act on it, check what happened, and do it again dozens of times without losing track. The model inside TinyAgent is built only for that job. It reads the page as meaning, not as raw HTML or pixels, so each step carries what that step needs instead of the whole page.

> [!NOTE]
>
> TinyAgent isn't a general-purpose chatbot with a browser attached. Keep using the assistant or agent you already have for conversation and planning, and hand TinyAgent the work that has to happen on a website: logging in, filling forms, paging through results, and extracting data.

## One run, step by step

The quick start sends TinyAgent to `https://scrapeme.live/shop` with the goal "Extract the first 2 product names and prices." When you stream the run, each event maps to part of the loop above.

| Event | What happened |
| - | - |
| `STARTED` | The run was created. The event carries its `run_id`. |
| `STREAMING_URL` | The browser is live. Open the URL to watch the agent work. |
| `PROGRESS` "Visit the page to extract product information" | The model chose an action and the agent performed it. `purpose` describes the action. |
| `PROGRESS` "Check for product information on the page" | The next action, chosen from what the page shows now. |
| `COMPLETE` | The run finished. `result` holds the two products as JSON. |

To see the decisions as they happen, print each `PROGRESS` event's `purpose`:

**Python**

```py theme={null}
from tinyfish import TinyFish, CompleteEvent

client = TinyFish()

with client.agent.stream(
    url="https://scrapeme.live/shop",
    goal="Extract the first 2 product names and prices. Return as JSON.",
    on_streaming_url=lambda e: print(f"Watch live: {e.streaming_url}"),
    on_progress=lambda e: print(f"Step: {e.purpose}"),
) as stream:
    for event in stream:
        if isinstance(event, CompleteEvent):
            print("Status:", event.status)
            print("Result:", event.result_json)
```

**TypeScript**

```ts theme={null}
import { TinyFish, EventType } from "@tiny-fish/sdk";

const client = new TinyFish();

const stream = await client.agent.stream(
  {
    url: "https://scrapeme.live/shop",
    goal: "Extract the first 2 product names and prices. Return as JSON.",
  },
  {
    onStreamingUrl: (e) => console.log(`Watch live: ${e.streaming_url}`),
    onProgress: (e) => console.log(`Step: ${e.purpose}`),
  },
);

for await (const event of stream) {
  if (event.type === EventType.COMPLETE) {
    console.log("Status:", event.status);
    console.log("Result:", event.result);
  }
}
```

The printed purposes are the same trail you see in the Playground, and they're the first place to look when a run stops early.

Here are the steps recorded for a real run: `linear.app/pricing` with the goal "Extract all pricing plan details from this page including plan name, monthly price, and what's included" and an output schema. It took 5 steps and 47 seconds.

| Time | Step | What happened |
| - | - | - |
| 0s | Navigate to Linear pricing page | The agent opened the URL in a live browser. |
| 9s | Extract all pricing plan details | The model read the loaded page and chose to extract the plans. |
| 13s | Extract detailed pricing plans and features | The next action, chosen from what the first extraction found. At about 25 seconds, it was the longest step. |
| 42s | Return extracted pricing plan details | The model decided it had what the goal asked for and returned it. |
| 47s | Task completed | The run finished as `COMPLETED` and `result` held the four plans as JSON. |

The model named every step itself, from what it saw on the page at that moment. Nothing in the goal told it to navigate first or to extract twice.

## How it connects

Everything else in TinyAgent shapes this loop: what the model works toward, how long it may keep going, and what comes back.

| Concept | How it relates to the loop | Read more |
| - | - | - |
| Goal | What the model works toward on every step. A specific goal means fewer wasted steps. | [Goals](https://docs.tinyfish.ai/key-concepts/goals.md) |
| Mode, max steps, max duration | `mode` sets how the agent reacts to an unexpected state. `max_steps` (default 150) and `max_duration_seconds` cap how long the loop runs. | [Agent Mode, Max Steps, and Max Duration](https://docs.tinyfish.ai/agent/explanation/agent-modes.md) |
| Run | Every call creates a run with a lifecycle. `COMPLETED` means the run finished, not that the goal succeeded, so always check `result`. | [Runs](https://docs.tinyfish.ai/agent/explanation/runs.md) |
| Output schema | Pins the shape of `result`, so every run of the same goal returns the same fields. | [Get structured output](https://docs.tinyfish.ai/agent/how-to/structured-output.md) |
| Profiles and Vault | A profile lets the agent start already signed in. Vault lets it log in without exposing credentials to the model. | [Log in with Vault](https://docs.tinyfish.ai/agent/how-to/vault-login.md), [Browser profiles](https://docs.tinyfish.ai/agent/api/profiles/browser-context-profiles.md) |
| Endpoints | `/run`, `/run-async`, `/run-batch` and `/run-sse` start the same agent and only change how you get results back. | [Endpoints](https://docs.tinyfish.ai/agent/api/agent/endpoints.md) |

## Related

> [card] [Runs](https://docs.tinyfish.ai/agent/explanation/runs.md)
>
> Run lifecycle, statuses, and what COMPLETED means

> [card] [Agent Mode, Max Steps, and Max Duration](https://docs.tinyfish.ai/agent/explanation/agent-modes.md)
>
> Default vs Strict mode, step and time limits

> [card] [Configure Agent Mode and Max Steps](https://docs.tinyfish.ai/agent/how-to/agent-mode-max-steps.md)
>
> Set the limits that bound the loop

> [card] [Endpoints](https://docs.tinyfish.ai/agent/api/agent/endpoints.md)
>
> Request schema and stream event types


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.