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

# AI Task Node

> Instruct an LLM to interact with a webpage

The **AI Task node** uses natural language instructions to perform actions inside a real browser.
It is the most flexible node type and is ideal for handling dynamic UI, multi-step interactions, and workflows that benefit from LLM reasoning.

Common actions include:

<CardGroup cols={2}>
  <Card title="Navigate" icon="compass" horizontal>
    Navigate to and through pages
  </Card>

  <Card title="Fill forms" icon="list" horizontal>
    Enter and submit structured data
  </Card>

  <Card title="Use files" icon="file" horizontal>
    Read, upload, or download files
  </Card>

  <Card title="Extract data" icon="chart-line" horizontal>
    Scrape data from a webpage
  </Card>
</CardGroup>

***

## Configuration

### Instructions

The core of an AI Task node is a **natural language instruction block**.
You describe what the agent should do, and the LLM executes those steps in the browser.

#### Recommended Structure

To achieve the most reliable behavior, structure your instructions with:

* **Goal**: What the node is trying to accomplish
* **Ordered steps**: A sequence of specific actions
* **Edge cases**: Known variations the agent must handle
* **Success criteria**: Observable conditions indicating completion

Example:

```
Your goal is to submit the consultation form for the current patient:
1.	Click “New Consultation”
2.	Fill the form fields with the provided data
3.	Upload any provided attachments
4.	Click “Create”

Edge cases:
- If a modal appears, close it before continuing
- If the page asks for confirmation, accept it

Success criteria:
Once you see the “Consultation Submitted” banner, the task is complete.
```

### Dynamic Variables

Dynamic variables make your instructions reusable across multiple runs with different inputs.
Variables are passed at execution time and referenced with the `{{.var_name}}` syntax.

Example:

```
Navigate to the patient search page:
1.	Enter {{.patient_name}} into the search bar
2.	Select the matching result
3.	Fill {{.diagnosis}}
4.	Click Submit
...
```

#### Naming Rules

Variable names must:

* Start with a letter or underscore
* Contain only letters, numbers, and underscores
* Not include special characters such as `@`, `-`, `.`, or spaces

Valid: `{{.user_name}}`, `{{.email}}`, `{{.api_key}}`

Invalid: `{{.user-name}}`, `{{.my@var}}`, `{{.1st_item}}`

### Advanced Templating

AI Task instructions support full **Go Template** syntax, enabling conditionals, loops, and structured data.

<AccordionGroup>
  <Accordion title="Advanced: Conditionals">
    Use `if` statements to conditionally adjust behavior:

    ```
    {{if .is_premium}}
    Navigate to the premium dashboard and enable all features.
    {{else}}
    Navigate to the free dashboard.
    {{end}}
    ```

    The corresponding variable values should be:

    ```json theme={null}
    {"is_premium": true}
    ```
  </Accordion>

  <Accordion title="Advanced: Loops">
    Iterate through lists or arrays.

    **Simple array:**

    ```
    Fill the form with the following items:
    {{range .items}}
    - Enter "{{.}}" in the next field
    {{end}}
    ```

    **Array of objects:**

    ```
    Add products to the cart:
    {{range .products}}
    - {{.name}}: {{.price}}
    {{end}}
    ```

    The corresponding variable values should be:

    ```json theme={null}
    {"items": ["Item 1", "Item 2", "Item 3"]}
    ```

    Via SDK, you'd pass:

    ```json theme={null}
    {
      "inputs": {
        "products": [
          {"name": "Widget A", "price": "$10"},
          {"name": "Widget B", "price": "$20"}
        ]
      }
    }
    ```

    <Info>
      Inside a `range`, `{{.}}` refers to the current item.
      For objects, use fields like `{{.name}}` and `{{.price}}`.
    </Info>
  </Accordion>

  <Accordion title="Advanced: Nested Data">
    Access nested JSON structures:

    ```
    User: {{.user.name}} ({{.user.email}})

    {{if .user.verified}}
    Proceed to checkout.
    {{else}}
    Please verify your email before continuing.
    {{end}}
    ```

    The corresponding variable values should be:

    ```json theme={null}
    {"user": {"name": "Jane Smith", "email": "jane@example.com", "verified": true}}
    ```
  </Accordion>
</AccordionGroup>

## Model Selection

Choose the model that best fits the complexity of the task:

<Card title="Asteroid Fast" icon="zap" horizontal>
  Lowest latency. Best for simple, fast interactions.
</Card>

<Card title="Asteroid Balanced" icon="lightbulb" horizontal>
  Default model. Balanced speed and accuracy.
</Card>

<Card title="Asteroid Max" icon="brain" horizontal>
  Highest intelligence and reasoning depth for complex flows.
</Card>

## Script

By default an AI Task node runs **fully agentically** — the model picks tool calls turn by turn using the `Instructions` below. To make a node run a pre-approved Playwright script first, set its **Script** field. The presence of a script will make the node attempt to run the script before any LLM involvement.

In the graph editor, the **Script** field sits at the top of the node's **Instructions** tab. Selecting a `.js` file from the node's shared directory turns the node into a scripted node and reveals a small "If the script fails" picker beside it. Removing the script returns the node to fully agentic behaviour.

In API or YAML exports, the same switch is the `script_filepath` field on the AI Task node — a node is scripted iff `script_filepath` is set.

<Card title="Agent filesystem" icon="folder-open" href="/fundamentals/files" horizontal>
  Read how `shared/` keeps files across runs for the same agent
</Card>

### If the script fails

When a script is selected, the node exposes a failure-behaviour picker.

<CardGroup cols={2}>
  <Card title="Fall back to AI" icon="sparkles" horizontal>
    The script's output (or failure context) is attached to the LLM turn and the AI agent recovers and continues the task using the `Instructions`.
  </Card>

  <Card title="Cancel" icon="ban" horizontal>
    The execution is cancelled immediately with reason `script_failed`. No LLM fallback. Also fires when the referenced script is missing on disk.
  </Card>
</CardGroup>

<Tip>
  Use [Astro](/astro/getting-started) to recommend areas of the workflows that can be scripted, and to write and test them for you.
</Tip>

### Where scripts live

Scripts live under the agent's persistent **`shared/`** tree (see [Agent filesystem](/fundamentals/files)). The runtime resolves `script_filepath` **relative to the node's own shared directory**:

```
shared/<node-slug>/<script_filepath>
```

* `<node-slug>` is derived from the node's display name (lowercased, punctuation stripped) and is added automatically by the runtime — authors never encode it, so renaming a node never breaks the path.
* `script_filepath` itself is the part you author. Typical values: `scripts/find_patient.js`, `scripts/login.js`, `scripts/submit_order.js`.
* Name the file after the action it performs in `lower_snake_case`. The directory already groups by node — the filename should communicate *what* the script does. Avoid generic names like `scripts/main.js` or `scripts/index.js`.

For example, a node named "Find Patient" with `script_filepath: scripts/find_patient.js` resolves on disk in the sandbox to `/home/agent/shared/find_patient/scripts/find_patient.js`.

### Placeholders inside the script

Inside the `.js` script file itself, two substitution systems run before the script executes:

1. **`__PLACEHOLDER__`** — Double underscores around an `UPPER_SNAKE_CASE` name (e.g. `__PATIENT_NAME__`). Before the script runs, a lightweight LLM pass reads the script plus the node's **Instructions** and **execution data**, then produces a `{NAME: value}` map. The runtime substitutes those values into the script text before handing it to Playwright. If the substitution call cannot resolve every placeholder, the node falls back to the LLM (or cancels under `freeze: true`) — the script is never executed with literal `__VAR__` strings.
2. **`##CREDENTIAL##`** — Vault secrets, substituted at the tool boundary from the credential store (see [Agent profiles](/fundamentals/profiles)). Separate from `__PLACEHOLDER__` resolution and never passed through the LLM.

Both syntaxes can appear in the same script:

```javascript theme={null}
module.exports = async (page) => {
  await page.fill('#username', '##USERNAME##');
  await page.fill('#password', '##PASSWORD##');
  await page.click('button[type="submit"]');

  await page.fill('#patient-name', '__PATIENT_NAME__');
  await page.fill('#dob', '__DATE_OF_BIRTH__');
  await page.click('#save');

  return { saved: true };
};
```

### Runtime behaviour

The stored script runs against the live browser session (the same browser the LLM would have used). Then:

* If a **selector transition** matches immediately after the script (eagerly checked), the runtime takes it and skips the LLM. Fast.
* If the script **succeeded** and the node has **exactly one** outbound transition, the runtime takes it directly. No LLM. Fast.
* Otherwise, the runtime invokes the LLM with the script's output added as context — the agent decides what to do next (pick among multiple transitions, recover from a partial failure, etc).

Scripts return values from their `module.exports`:

* **Object** (e.g. `return { patient_id: id }`) — each top-level key becomes an output variable available to downstream nodes' `# Execution Data`.
* **String** — wrapped under a single `script_output` variable.
* **Throw** — treated as a failure; behaviour then depends on `freeze`.

## AI Capabilities

Enable specific capabilities depending on what the node needs to perform:

<Card title="Web Browsing Essentials" icon="globe" href="/fundamentals/ai-capabilities#web-browsing-essentials" horizontal>
  Basic navigation, clicking, typing, and interaction
</Card>

<Card title="Advanced Web Browsing" icon="compass" href="/fundamentals/ai-capabilities#advanced-web-browsing-toolkit" horizontal>
  Complex navigation, dynamic UIs, and robust action handling
</Card>

<Card title="Computer Vision" icon="eye" href="/fundamentals/ai-capabilities#computer-vision" horizontal>
  Visual understanding of the page and image-based interaction
</Card>

<Card title="Communication" icon="message" href="/fundamentals/ai-capabilities#communication" horizontal>
  Exchange messages and emails with the user during execution
</Card>

<Card title="File System" icon="folder" href="/fundamentals/ai-capabilities#file-system" horizontal>
  Upload, download, read, and write files
</Card>

<Card title="Memory & Storage" icon="database" href="/fundamentals/ai-capabilities#memory-%26-storage" horizontal>
  Store and retrieve data across execution steps
</Card>

<Card title="Google Sheets" icon="table" href="/fundamentals/ai-capabilities#google-sheets" horizontal>
  Read from and write to Google Sheets
</Card>

<Card title="Authentication" icon="lock" href="/fundamentals/ai-capabilities#authentication" horizontal>
  Generate and manage authentication tokens
</Card>

<Card title="Context & Utilities" icon="info" href="/fundamentals/ai-capabilities#context-%26-utilities" horizontal>
  Access contextual data and system utilities
</Card>

<Info>
  Explore all available features in **[AI Capabilities](/fundamentals/ai-capabilities)**.
</Info>

<Warning>
  **Critical: Basic Browser Interaction Tools Required**

  **Always ensure Basic Web Interaction tools are enabled for AI Task nodes.** This capability is enabled by default and provides essential tools for clicking, typing, selecting elements, and interacting with the DOM.

  * Basic Web Interaction is required for AI Task nodes to function properly
  * Disabling this capability will prevent the agent from performing basic browser interactions
  * You should not disable this capability unless you have a very specific reason

  For more details, see [AI Capabilities](/fundamentals/ai-capabilities#web-browsing-essentials).
</Warning>

***

## Transitions and Failure Handling

<Warning>
  **Critical: AI Task Nodes Must Have Failure Paths**

  **All AI Task nodes must have a connection to an Output node via a failure path.** This is essential for proper error handling and workflow completion.

  * Every AI Task node should have at least one transition (typically an AI Transition) that connects to an Output node configured for failure scenarios
  * Without a failure path, your workflow may not properly handle errors, unexpected conditions, or edge cases
  * This ensures that unexpected conditions, missing elements, or interpretation errors are surfaced correctly in your workflow

  For more details, see [Transitions](/fundamentals/transitions#failure-transitions) and [Output Nodes](/fundamentals/nodes/output).
</Warning>

***

## API / YAML Reference

When configuring an AI Task node via the API, SDK, or MCP, use the following type identifier:

| Field            | Value                                                                                                                                                                                                                                                                                                              |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Node type        | `ai`                                                                                                                                                                                                                                                                                                               |
| Transition types | `ai`, `selector`                                                                                                                                                                                                                                                                                                   |
| Optional         | `script_filepath`: relative `.js` path inside the node's shared directory that turns the node into a fast-path scripted node (see rules below). `freeze`: when `true`, script failure (or a missing script file) cancels the execution instead of falling back to the LLM. Only meaningful with `script_filepath`. |

Default AI Task node (`settings.yaml`):

```yaml theme={null}
label: "Submit Form"
type: ai
tools:
  - go_to_url
  - dom_browser_interaction
model: "asteroid_balanced"
transitions:
  - to: success_output
    type: ai
  - to: failure_output
    type: ai
  - to: confirmation_page
    type: selector
    name: "Confirmation Visible"
    selector: ".confirmation-banner"
```

Scripted AI Task node with LLM fallback (script failure → AI recovers):

```yaml theme={null}
label: "Find Patient"
type: ai
tools:
  - dom_browser_interaction
model: "asteroid_balanced"
script_filepath: scripts/find_patient.js
transitions:
  - to: patient_found
    type: ai
  - to: not_found
    type: ai
```

Frozen scripted AI Task node (no LLM — script failure cancels the execution):

```yaml theme={null}
label: "Login"
type: ai
tools:
  - dom_browser_interaction
model: "asteroid_balanced"
script_filepath: scripts/login.js
freeze: true
transitions:
  - to: dashboard
    type: ai
```

The node's instructions are stored in a separate `instructions.md` file in the same directory. The Playwright script referenced by `script_filepath` lives in the agent's shared directory at `shared/<node-slug>/<script_filepath>` and is shipped to the sandbox at execution time.

***

## Additional Settings

### Batch Actions

Enable parallel steps for faster execution when the workflow allows it.

### Snapshot Compression

Reduce context size by compressing browser snapshots captured during execution.
