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

# Functions

> Run published Sutro Functions through the Python SDK.

Use `run_function()` for one request and `batch_run_function()` for many rows.

Call the Function by name and pass the input fields it expects. Sutro uses the Function's published setup automatically.

<Note>
  Use the Function name only. Do not include a namespace, owner, or revision. The authenticated API key determines which customer namespace is searched, and the currently published revision is resolved automatically.
</Note>

<Warning>
  Only text Functions are supported today. Image, PDF, and other multimodal Functions are not yet runnable through `run_function()` or `batch_run_function()`.
</Warning>

## Running a Function

```python theme={null}
run_function(
    name: str,
    input_data: dict | BaseModel,
    langsmith_metadata: Optional[Dict[str, Any]] = None,
    langsmith_tags: Optional[List[str]] = None,
)
```

### Parameters

* `name` — Function name to execute.
* `input_data` — Input object matching the Function inputs. Can be a plain dictionary or a Pydantic model.
* `langsmith_metadata` — Optional trace metadata when LangSmith tracing is enabled.
* `langsmith_tags` — Optional trace tags when LangSmith tracing is enabled.

### Return shape

Most Functions return one of two payload shapes. For the full response reference, see [Running a Function](/functions-api-reference/running-functions).

Classification-style Functions return one primary answer:

```json theme={null}
{
  "response": "qualified",
  "confidence": 0.91,
  "predictions": [
    { "label": "qualified", "confidence": 0.91 },
    { "label": "not_qualified", "confidence": 0.09 }
  ],
  "rationale": "The lead matches the qualification rubric.",
  "usage": {
    "input_tokens": 173,
    "output_tokens": 42,
    "system_prompt": "Return one lead qualification label."
  }
}
```

Structured extraction Functions return an object:

```json theme={null}
{
  "output": {
    "company": "Acme Labs",
    "segment": "B2B analytics",
    "region": "APAC"
  },
  "rationale": "The requested fields are present in the input.",
  "confidence": 0.82,
  "usage": {
    "input_tokens": 244,
    "output_tokens": 66,
    "system_prompt": "Extract the requested lead fields."
  }
}
```

There is no `run_id` in this response.

### Examples

Replace `lead-qualifier` with your published Function name and add the correct input data (structured to adhere to the Function's input schema).

Using a dictionary:

```python theme={null}
import sutro as so

result = so.run_function(
    name="lead-qualifier",
    input_data={
        "query": "Find cybersecurity leaders evaluating AI vendors.",
        "region": "APAC",
    },
)

print(result)
```

Using a Pydantic model:

```python theme={null}
import sutro as so
from pydantic import BaseModel

class LeadInput(BaseModel):
    query: str
    region: str | None = None

result = so.run_function(
    name="lead-qualifier",
    input_data=LeadInput(
        query="Find cybersecurity leaders evaluating AI vendors.",
        region="APAC",
    ),
)

print(result)
```

## Running a Function in Batch

```python theme={null}
batch_run_function(
    name: str,
    data: List[dict] | pd.DataFrame | pl.DataFrame | str,
    job_priority: int | None = 0,
    output_column: str = "inference_result",
    dry_run: bool = False,
    stay_attached: bool = False,
    job_name: Optional[str] = None,
    description: Optional[str] = None,
    langsmith_metadata: Optional[Dict[str, Any]] = None,
    langsmith_tags: Optional[List[str]] = None,
)
```

`batch_run_function()` submits many rows to the same Function.

### Parameters

* `name` — Function name to execute.
* `data` — One of:
  * `List[dict]`
  * `pandas.DataFrame`
  * `polars.DataFrame`
  * local `.csv` or `.parquet` file path
  * pre-signed download URL pointing to a `.csv` or `.parquet` file
* `job_priority` — Batch priority level. Defaults to `0`.
* `output_column` — Output column name for downstream results.
* `dry_run` — If `True`, submit a cost-estimate job instead of full inference. The SDK maps this to the Batch API's `cost_estimate` request field.
* `stay_attached` — If `True`, stay attached to the job and stream progress.
* `job_name` — Optional job name.
* `description` — Optional job description.
* `langsmith_metadata` — Optional trace metadata when LangSmith tracing is enabled.
* `langsmith_tags` — Optional trace tags when LangSmith tracing is enabled.

<Note>
  When `data` is a local CSV or Parquet path, the SDK reads the file locally and submits rows whose column names must match the Function inputs.
</Note>

<Warning>
  Dataset IDs are not supported by `batch_run_function()`. Use a list of dictionaries, a DataFrame, or a local CSV/Parquet file path.
</Warning>

### Examples

Using a list of dictionaries:

```python theme={null}
import sutro as so

job_id = so.batch_run_function(
    name="lead-qualifier",
    data=[
        {
            "query": "Find cybersecurity leaders evaluating AI vendors.",
            "region": "APAC",
        },
        {
            "query": "Find sales operations leaders replacing manual enrichment.",
            "region": "EMEA",
        },
    ],
)

print(job_id)
```

Using a Polars DataFrame:

```python theme={null}
import polars as pl
import sutro as so

df = pl.DataFrame(
    {
        "query": [
            "Find cybersecurity leaders evaluating AI vendors.",
            "Find sales operations leaders replacing manual enrichment.",
        ],
        "region": ["APAC", "EMEA"],
    }
)

job_id = so.batch_run_function(
    name="lead-qualifier",
    data=df,
)

print(job_id)
```

Using a local file path:

```python theme={null}
import sutro as so

job_id = so.batch_run_function(
    name="lead-qualifier",
    data="./lead_inputs.csv",
)

print(job_id)
```

### Working with batch results

Batch jobs run asynchronously. Use `await_job_completion()` to wait for completion and retrieve results:

```python theme={null}
import sutro as so

job_id = so.batch_run_function(
    name="lead-qualifier",
    data=[
        {
            "query": "Find cybersecurity leaders evaluating AI vendors.",
            "region": "APAC",
        }
    ],
)

results_df = so.await_job_completion(job_id)
print(results_df)
```

By default, `get_job_results()` and `await_job_completion()` unpack JSON outputs when possible. For a Function that returns `label` and `rationale`, the result DataFrame may contain columns such as:

```text theme={null}
shape: (1, 3)
┌───────────┬─────────────────────────────────────────────┬──────────────────┐
│ label     ┆ rationale                                   ┆ confidence_score │
│ ---       ┆ ---                                         ┆ ---              │
│ str       ┆ str                                         ┆ f64              │
╞═══════════╪═════════════════════════════════════════════╪══════════════════╡
│ qualified ┆ The lead matches the qualification rubric.  ┆ 1.0              │
└───────────┴─────────────────────────────────────────────┴──────────────────┘
```

To inspect the raw JSON string instead, disable JSON unpacking:

```python theme={null}
import json
import sutro as so

raw_results_df = so.get_job_results(job_id, unpack_json=False)

first_result = json.loads(raw_results_df["inference_result"][0])
content = first_result.get("content", first_result)

print(content)
print(first_result.get("reasoning_content"))
print(raw_results_df["confidence_score"][0])
```

For lower-volume or synchronous workloads, use [`run_function()`](#running-a-function).
