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

# Agent to Function Conversion

> Convert agent executions into reusable function code

<Tip>
  STOP. Do not read past this section until you have read and followed [/quickstart.md](/quickstart.md).

  Goal: produce a reliable SDK automation script. The intended authoring flow is generate then edit, not write browser automation from scratch.

  Do not hand-write SDK code with element IDs, selectors, or form fields from memory. Element IDs, selectors, and field mappings must come from a live `observe()` call, CLI `notte page observe` output, or generated workflow code. Guessed browser targets fail on real pages.

  Use the Notte skill and CLI to inspect the live site, validate actions/selectors, handle auth/session state, and export workflow code with `notte sessions workflow-code` before using SDK docs or SDK code.

  SDK reference pages are for understanding, running, or editing generated workflow code. They are not the starting point for manually authoring the initial browser automation. SDK-first code is guesswork on real-world pages with dynamic selectors, auth state, CAPTCHAs, and anti-bot behavior.
</Tip>

Convert successful agent runs into deterministic function code that can be executed faster and cheaper than agents.

## Overview

After an agent completes a task, you can extract the steps as function code:

{/* @sniptest testers/agents/workflows/overview.py */}

```python theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    agent = client.Agent(session=session)
    result = agent.run(task="Navigate to pricing page and extract plans")

    if result.success:
        # Convert to function code
        function_code = agent.workflow.code()
        print(function_code.python_script)
```

## Why Convert to Functions?

| Aspect           | Agent                  | Function                  |
| ---------------- | ---------------------- | ------------------------- |
| **Execution**    | AI decides each step   | Predefined steps          |
| **Speed**        | Slower (LLM reasoning) | Faster (direct execution) |
| **Cost**         | Higher (LLM tokens)    | Lower (actions only)      |
| **Reliability**  | Can vary               | Deterministic             |
| **Adaptability** | Handles changes        | Breaks if page changes    |

**Use functions when:**

* The task is well-defined and repeatable
* Page structure is stable
* Speed and cost matter
* You need predictable execution

## Getting Function Code

### As Python Script

Get executable Python code:

{/* @sniptest testers/agents/workflows/get-python-script.py */}

```python get-python-script.py theme={null}
agent = client.Agent(session=session)
result = agent.run(task="Login and navigate to dashboard")

if result.success:
    # Get function code
    code = agent.workflow.code(as_workflow=True)

    print(code.python_script)
```

Example output:

{/* @sniptest testers/agents/workflows/example-output.py */}

```python theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    # Step 1: Navigate to login page
    session.execute(type="goto", url="https://example.com/login")

    # Step 2: Fill email field
    session.execute(type="fill", selector="input[name='email']", value="user@example.com")

    # Step 3: Fill password field
    session.execute(type="fill", selector="input[name='password']", value="********")

    # Step 4: Click login button
    session.execute(type="click", selector="button[type='submit']")

    # Step 5: Wait for dashboard
    session.execute(type="goto", url="https://example.com/dashboard")
```

### As Function Object

Create a reusable function:

{/* @sniptest testers/agents/workflows/create-function-object.py */}

```python create-function-object.py theme={null}
result = agent.run(task="Extract product data")

if result.success:
    # Create function from agent
    function = agent.workflow.create_function()

    print(f"Created function: {function.function_id}")

    # Run function later
    function_result = function.run()
```

## Running Functions

### Execute Generated Code

Copy and run the generated Python:

{/* @sniptest testers/agents/workflows/execute-generated-code.py */}

```python theme={null}
# Generated from agent
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")
    session.execute(type="click", selector="button.search")
    session.execute(type="fill", selector="input[name='query']", value="laptop")
    data = session.scrape(instructions="Extract product names")

print(data)
```

### Use Function API

Run via the function endpoint:

{/* @sniptest testers/agents/workflows/use-function-api.py */}

```python use-function-api.py theme={null}
agent.run(task="Complete task")

# Create function from successful agent
function = agent.workflow.create_function()

# Run multiple times
for query in ["laptop", "phone", "tablet"]:
```

## Use Cases

### 1. Prototyping with Agents

Use agents to figure out the automation, then convert:

{/* @sniptest testers/agents/workflows/prototyping-with-agents.py */}

```python prototyping-with-agents.py theme={null}
# Phase 1: Prototype with agent
agent = client.Agent(session=session)
result = agent.run(task="Find all products under $100")

if result.success:
    # Phase 2: Convert to function for production
    code = agent.workflow.code()

    # Save for production use
    with open("production_function.py", "w") as f:
        f.write(code.python_script)
```

### 2. Scheduled Tasks

Convert one-time agent runs to scheduled functions:

{/* @sniptest testers/agents/workflows/scheduled-tasks.py */}

```python scheduled-tasks.py theme={null}
agent = client.Agent(session=session)
result = agent.run(task="Extract daily price changes")

# Convert to function
function = agent.workflow.create_function()

# Schedule to run daily (via API or console)
# function.schedule(cron="0 9 * * *")
```

### 3. Cost Optimization

Run agents once, then use cheaper functions:

{/* @sniptest testers/agents/workflows/cost-optimization.py */}

```python cost-optimization.py theme={null}
agent = client.Agent(session=session)
result = agent.run(task="Complex data extraction")

# Recurring: Use function ($0.05 per run)
function = agent.workflow.create_function()

# Run 100 times - save $15 vs running agent each time
for i in range(100):
    function.run()
```

### 4. Testing Variations

Create function templates from agents:

{/* @sniptest testers/agents/workflows/testing-variations.py */}

```python testing-variations.py theme={null}
# Base workflow from agent
agent = client.Agent(session=session)
result = agent.run(task="Search and extract results")

code = agent.workflow.code()

# Modify code for variations
# - Different search queries
# - Different extraction logic
# - Different URLs
```

## Customizing Generated Code

### Add Parameters

Make functions reusable with parameters:

{/* @sniptest testers/agents/workflows/add-parameters.py */}

```python add-parameters.py theme={null}
    # Agent-generated base code
    code = agent.workflow.code()

    # Customize with parameters
    customized_code = f"""
def extract_products(search_query: str, max_results: int = 10):
    {code.python_script}
"""
```

### Add Error Handling

Enhance with production-ready error handling:

{/* @sniptest testers/agents/workflows/add-error-handling.py */}

```python add-error-handling.py theme={null}
    # Agent-generated code
    base_code = agent.workflow.code()

    enhanced_code = f"""
from notte_sdk import NotteClient
from loguru import logger

def run_function():
    client = NotteClient()
    try:
        with client.Session() as session:
            {base_code.python_script}
            return {{"success": True, "data": result}}
    except Exception as e:
        logger.error(f"Function failed: {{e}}")
```

### Optimize Selectors

Review and improve generated selectors:

{/* @sniptest testers/agents/workflows/optimize-selectors.py */}

```python optimize-selectors.py theme={null}
# Generated code might use:
session.execute(type="click", selector="div.container > button:nth-child(3)")

# Optimize to:
session.execute(type="click", selector="button[data-testid='submit']")
```

## Best Practices

### 1. Test Generated Functions

Always test before production:

{/* @sniptest testers/agents/workflows/test-generated-functions.py */}

```python test-generated-functions.py theme={null}
    agent.run(task="Complete task")

    # Generate function code
    code = agent.workflow.code()

# Test in fresh session
with client.Session() as session:
    exec(code.python_script)
```

### 2. Document the Source

Track which agent generated the function:

{/* @sniptest testers/agents/workflows/document-the-source.py */}

```python document-the-source.py theme={null}
result = agent.run(task="Extract product data")

function = agent.workflow.create_function()

# Add metadata
metadata = {
    "agent_id": agent.agent_id,
    "original_task": "Extract product data",
    "created_at": datetime.now().isoformat(),
    "success_rate": result.success,
}
```

### 3. Version Control

Store functions in git:

{/* @sniptest testers/agents/workflows/version-control.py */}

```python version-control.py theme={null}
agent = client.Agent(session=session)
agent.run(task="Extract products")

# Save function code
code = agent.workflow.code()

function_path = Path("functions/extract_products.py")
function_path.parent.mkdir(exist_ok=True)
```

### 4. Monitor Function Success

Track if functions continue to work:

{/* @sniptest testers/agents/workflows/monitor-function-success.py */}

```python theme={null}
from datetime import datetime


def run_monitored_function():
    try:
        function = client.Function(function_id="func_abc123")
        result = function.run()

        if result.status == "closed":
            log_success(datetime.now())
        else:
            alert_failure(result.result)

    except Exception as e:
        # Function broken - maybe page changed?
        # Time to re-run agent and regenerate
        alert_function_broken(e)
```

### 5. Regenerate When Pages Change

When functions break, use agents to update:

{/* @sniptest testers/agents/workflows/regenerate-when-pages-change.py */}

```python regenerate-when-pages-change.py theme={null}
# Old function failing
try:
    old_function.run()
except Exception:
    print("Function broken, regenerating...")

    with client.Session() as session:
        # Use agent to figure out new function
        agent = client.Agent(session=session)
        result = agent.run(task=original_task_description)

        if result.success:
            # Generate new function
```

## Limitations

Functions work best for:

* ✅ Stable, unchanging pages
* ✅ Deterministic tasks
* ✅ Known sequences of actions

Functions are not suitable for:

* ❌ Pages that change frequently
* ❌ Tasks requiring adaptation
* ❌ Complex decision-making

When pages change or tasks become complex, revert to agents.

## Next Steps

<CardGroup cols={2}>
  <Card title="Functions" icon="function" href="/concepts/functions">
    Deploy automations as serverless APIs
  </Card>

  <Card title="Actions" icon="hand-pointer" href="/sdk-reference/manual/session">
    Available session actions
  </Card>

  <Card title="Agent Configuration" icon="sliders" href="/features/agents/configuration">
    Optimize agent runs
  </Card>

  <Card title="Functions" icon="flower" href="/concepts/functions">
    Deploy and manage serverless functions
  </Card>
</CardGroup>
