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

# Models

> The dataclasses that the SDK returns for job runs, logs, files, tasks, and task runs.

```python theme={"system"}
from wherobots import RunView, TaskRun
```

## CreateRunPayload

```python theme={"system"}
CreateRunPayload(
    name: str,
    runtime: str | None = None,
    version: str = 'latest',
    timeout_seconds: int = 3600,
    run_python: RunPythonPayload | None = None,
    run_jar: RunJarPayload | None = None,
    environment: RunEnvironment | None = None,
)
```

Full payload for `POST /runs`.

#### Parameters

**name** `str` *required*

**runtime** `str | None` (default: None)

**version** `str` (default: 'latest')

**timeout\_seconds** `int` (default: 3600)

**run\_python** `RunPythonPayload | None` (default: None)

**run\_jar** `RunJarPayload | None` (default: None)

**environment** `RunEnvironment | None` (default: None)

## DirectoryPage

```python theme={"system"}
DirectoryPage(entries: list[FileEntry] = list(), next_cursor: str | None = None)
```

One page of a Files drive listing.

#### Parameters

**entries** `list[FileEntry]` (default: list())

The files and folders on this page.

**next\_cursor** `str | None` (default: None)

Cursor for the next page, or `None` on the last page.

## FileDependency

```python theme={"system"}
FileDependency(file_path: str, file_type: DependencyFileType | None = None)
```

A file-based dependency (JAR, wheel, zip, etc.).

#### Parameters

**file\_path** `str` *required*

**file\_type** `DependencyFileType | None` (default: None)

## FileEntry

```python theme={"system"}
FileEntry(
    name: str,
    path: str,
    is_dir: bool,
    size: int = 0,
    last_modified: datetime | None = None,
)
```

One file or folder in a Files drive listing.

#### Parameters

**name** `str` *required*

The entry's own name, without a trailing `/`.

**path** `str` *required*

The entry's path as the API reports it.

**is\_dir** `bool` *required*

`True` for a folder.

**size** `int` (default: 0)

Size in bytes (`0` for folders).

**last\_modified** `datetime | None` (default: None)

Last modification time, when the API reports one.

## FileUploadTarget

```python theme={"system"}
FileUploadTarget(destination: str, upload_url: str)
```

Where a Files upload lands, and the presigned URL to send it to.

#### Parameters

**destination** `str` *required*

The storage location the file will be written to.

**upload\_url** `str` *required*

Presigned PUT URL. It is a bearer credential, so `repr` hides it.

## KubeAppEvent

```python theme={"system"}
KubeAppEvent(
    id: str = '',
    create_time: str = '',
    update_time: str = '',
    code: str | None = None,
    message: str | None = None,
    event_meta: RunEventMeta | None = None,
)
```

Kubernetes application event (OpenAPI `KubeAppEvent`).

#### Parameters

**id** `str` (default: '')

**create\_time** `str` (default: '')

**update\_time** `str` (default: '')

**code** `str | None` (default: None)

**message** `str | None` (default: None)

**event\_meta** `RunEventMeta | None` (default: None)

## LogItem

```python theme={"system"}
LogItem(
    raw: str = '',
    timestamp: int | str | None = None,
    level: str | None = None,
    message: str | None = None,
    extra: dict[str, Any] = dict(),
)
```

A single log entry.

The `timestamp` field is typed as `Union[int, str, None]` because
the Wherobots API returns integer epoch values (e.g. `0`) while
other sources may use ISO-8601 strings.

#### Parameters

**raw** `str` (default: '')

**timestamp** `int | str | None` (default: None)

**level** `str | None` (default: None)

**message** `str | None` (default: None)

**extra** `dict[str, Any]` (default: dict())

## LogsResponse

```python theme={"system"}
LogsResponse(
    items: list[LogItem] = list(),
    next_page: int | str | None = None,
    current_page: int | str | None = None,
    raw: dict[str, Any] = dict(),
)
```

Response from `GET /runs/{id}/logs`.

The API returns `current_page` (int) and `next_page` (int) for
cursor-based pagination. `raw` holds the original server response
so callers can reach new fields without a SDK release.

#### Parameters

**items** `list[LogItem]` (default: list())

**next\_page** `int | str | None` (default: None)

**current\_page** `int | str | None` (default: None)

**raw** `dict[str, Any]` (default: dict())

## OffsetPage

```python theme={"system"}
OffsetPage(items: list[T], total: int, limit: int, offset: int)
```

One page of a limit/offset listing.

#### Parameters

**items** `list[T]` *required*

The items on this page.

**total** `int` *required*

How many items match in all, across every page.

**limit** `int` *required*

The page size the server applied.

**offset** `int` *required*

How many matching items precede this page.

### next\_offset

```python theme={"system"}
OffsetPage.next_offset: int | None
```

The `offset` of the next page, or `None` on the last page.

## OrganizationCustomer

```python theme={"system"}
OrganizationCustomer(
    id: str = '',
    create_time: str = '',
    update_time: str = '',
    email: str | None = None,
    name: str | None = None,
    roles: list[str] = list(),
)
```

A user/customer in the organization (OpenAPI `OrganizationCustomer`).

Returned on `RunView.triggeredBy` to identify the user who
submitted a run.

#### Parameters

**id** `str` (default: '')

**create\_time** `str` (default: '')

**update\_time** `str` (default: '')

**email** `str | None` (default: None)

**name** `str | None` (default: None)

**roles** `list[str]` (default: list())

## PyPiDependency

```python theme={"system"}
PyPiDependency(library_name: str, library_version: str)
```

A PyPI package dependency.

#### Parameters

**library\_name** `str` *required*

**library\_version** `str` *required*

## RunAppMeta

```python theme={"system"}
RunAppMeta(
    spark_ui_url: str | None = None,
    spark_eventlogs_url: str | None = None,
    resolved_version: str | None = None,
)
```

Application metadata attached to a run (OpenAPI `RunAppMeta`).

#### Parameters

**spark\_ui\_url** `str | None` (default: None)

**spark\_eventlogs\_url** `str | None` (default: None)

**resolved\_version** `str | None` (default: None)

## RunEnvironment

```python theme={"system"}
RunEnvironment(
    spark_configs: dict[str, str] | None = None,
    dependencies: list[dict[str, Any]] | None = None,
    spark_driver_disk_gb: int | None = None,
    spark_executor_disk_gb: int | None = None,
)
```

Environment configuration for a job run.

#### Parameters

**spark\_configs** `dict[str, str] | None` (default: None)

**dependencies** `list[dict[str, Any]] | None` (default: None)

**spark\_driver\_disk\_gb** `int | None` (default: None)

**spark\_executor\_disk\_gb** `int | None` (default: None)

## RunEventMeta

```python theme={"system"}
RunEventMeta(start_timestamp: int | None = None, end_timestamp: int | None = None)
```

Timestamp window attached to a `KubeAppEvent` (OpenAPI `RunEventMeta`).

#### Parameters

**start\_timestamp** `int | None` (default: None)

**end\_timestamp** `int | None` (default: None)

## RunJarPayload

```python theme={"system"}
RunJarPayload(uri: str, main_class: str = '', args: list[str] = list())
```

JAR execution payload.

Note: per the API spec, `mainClass` is optional on responses
(the server may infer it). Kept as a string here with `""` as
the "unset" sentinel so existing callers who read the field
unconditionally continue to work.

#### Parameters

**uri** `str` *required*

**main\_class** `str` (default: '')

**args** `list[str]` (default: list())

## RunKubeApp

```python theme={"system"}
RunKubeApp(
    id: str = '',
    create_time: str = '',
    update_time: str = '',
    instance_id: str = '',
    app_type: AppType | str | None = None,
    status: AppStatus | str | None = None,
    created_by_id: str | None = None,
    api_payload: dict[str, Any] | None = None,
    app_meta: RunAppMeta | None = None,
    events: list[KubeAppEvent] = list(),
    cpu_usage: int = 0,
    region_name: str = '',
    message: str | None = None,
)
```

Kubernetes application details for a run (OpenAPI `RunKubeApp`).

Forward-compat: `app_type` and `status` round-trip unknown
server values as raw strings rather than silently dropping them.

#### Parameters

**id** `str` (default: '')

**create\_time** `str` (default: '')

**update\_time** `str` (default: '')

**instance\_id** `str` (default: '')

**app\_type** `AppType | str | None` (default: None)

**status** `AppStatus | str | None` (default: None)

**created\_by\_id** `str | None` (default: None)

**api\_payload** `dict[str, Any] | None` (default: None)

**app\_meta** `RunAppMeta | None` (default: None)

**events** `list[KubeAppEvent]` (default: list())

**cpu\_usage** `int` (default: 0)

**region\_name** `str` (default: '')

**message** `str | None` (default: None)

## RunListPage

```python theme={"system"}
RunListPage(
    items: list[RunView] = list(),
    total: int = 0,
    next_page: str | None = None,
    previous_page: str | None = None,
    current_page: str | None = None,
    current_page_backwards: str | None = None,
    raw: dict[str, Any] = dict(),
)
```

Paginated list of runs (`GET /runs` response).

The Wherobots API returns string-based pagination cursors:
`next_page`, `previous_page`, `current_page`,
`current_page_backwards`.

#### Parameters

**items** `list[RunView]` (default: list())

**total** `int` (default: 0)

**next\_page** `str | None` (default: None)

**previous\_page** `str | None` (default: None)

**current\_page** `str | None` (default: None)

**current\_page\_backwards** `str | None` (default: None)

**raw** `dict[str, Any]` (default: dict())

### cursor

```python theme={"system"}
RunListPage.cursor: str | None
```

Alias for `next_page` — kept for backward compatibility.

## RunMetricsResponse

```python theme={"system"}
RunMetricsResponse(
    series_metrics: dict[str, Any] = dict(),
    instant_metrics: dict[str, Any] = dict(),
    extra: dict[str, Any] = dict(),
    raw: dict[str, Any] = dict(),
)
```

Response from `GET /runs/{id}/metrics`.

Per the OpenAPI spec the metrics blobs use snake\_case keys
(`series_metrics` / `instant_metrics`) and are typed as plain
`object` (the server's internal metric shape is not stable enough
to type against). The SDK exposes them as untyped dicts keyed by
metric name; callers can inspect `raw` for any new fields the
server adds.

#### Parameters

**series\_metrics** `dict[str, Any]` (default: dict())

**instant\_metrics** `dict[str, Any]` (default: dict())

**extra** `dict[str, Any]` (default: dict())

**raw** `dict[str, Any]` (default: dict())

## RunPythonPayload

```python theme={"system"}
RunPythonPayload(uri: str, args: list[str] = list())
```

Python script execution payload.

#### Parameters

**uri** `str` *required*

**args** `list[str]` (default: list())

## RunView

```python theme={"system"}
RunView(
    id: str,
    name: str,
    status: JobStatus | str | None = None,
    runtime: str | None = None,
    region: str | None = None,
    version: str | None = None,
    timeout_seconds: int | None = None,
    create_time: str | None = None,
    update_time: str | None = None,
    start_time: str | None = None,
    complete_time: str | None = None,
    run_python: RunPythonPayload | None = None,
    run_jar: RunJarPayload | None = None,
    environment: RunEnvironment | None = None,
    app_meta: RunAppMeta | None = None,
    kube_app: RunKubeApp | None = None,
    triggered_by: OrganizationCustomer | None = None,
    extra: dict[str, Any] = dict(),
    raw: dict[str, Any] = dict(),
)
```

Complete view of a job run (`GET /runs/{id}` response).

The Wherobots API nests payload fields (`runtime`, `runPython`,
`runJar`, `timeoutSeconds`, `environment`) under a `"payload"`
key.  `from_dict` transparently flattens these so callers can access
e.g. `view.runtime` directly.

Timestamp fields from the API use `createTime` / `startTime` /
`completeTime`; for convenience the parser also accepts the legacy
`createdAt` / `startedAt` / `completedAt` aliases.

Forward-compat:

* `status` is typed as `JobStatus | str | None` so a status value
  the SDK doesn't know about yet (e.g. a new terminal state added
  server-side) round-trips as the raw string instead of silently
  disappearing. Use `is_terminal_status` to check terminality
  without assuming the enum.
* `raw` holds the full server response dict, so newly added fields
  are always reachable even when the typed surface hasn't caught up.

#### Parameters

**id** `str` *required*

**name** `str` *required*

**status** `JobStatus | str | None` (default: None)

**runtime** `str | None` (default: None)

**region** `str | None` (default: None)

**version** `str | None` (default: None)

**timeout\_seconds** `int | None` (default: None)

**create\_time** `str | None` (default: None)

**update\_time** `str | None` (default: None)

**start\_time** `str | None` (default: None)

**complete\_time** `str | None` (default: None)

**run\_python** `RunPythonPayload | None` (default: None)

**run\_jar** `RunJarPayload | None` (default: None)

**environment** `RunEnvironment | None` (default: None)

**app\_meta** `RunAppMeta | None` (default: None)

**kube\_app** `RunKubeApp | None` (default: None)

**triggered\_by** `OrganizationCustomer | None` (default: None)

**extra** `dict[str, Any]` (default: dict())

**raw** `dict[str, Any]` (default: dict())

### completed\_at

```python theme={"system"}
RunView.completed_at: str | None
```

Alias kept for backward compatibility.

### created\_at

```python theme={"system"}
RunView.created_at: str | None
```

Alias kept for backward compatibility.

### started\_at

```python theme={"system"}
RunView.started_at: str | None
```

Alias kept for backward compatibility.

## StorageIntegration

```python theme={"system"}
StorageIntegration(
    id: str,
    name: str,
    path: str,
    region: str,
    type: str = 'INTEGRATION',
    create_time: str | None = None,
    update_time: str | None = None,
    role_arn: str | None = None,
    default_directory: str | None = None,
    raw: dict[str, Any] = dict(),
)
```

A storage source (managed or user-configured S3 integration).

Represents one entry from `GET /storage`. The `type` field
distinguishes the org's MANAGED bucket from external INTEGRATION
buckets the user has wired up.

#### Parameters

**id** `str` *required*

**name** `str` *required*

**path** `str` *required*

**region** `str` *required*

**type** `str` (default: 'INTEGRATION')

**create\_time** `str | None` (default: None)

**update\_time** `str | None` (default: None)

**role\_arn** `str | None` (default: None)

**default\_directory** `str | None` (default: None)

**raw** `dict[str, Any]` (default: dict())

### is\_managed

```python theme={"system"}
StorageIntegration.is_managed: bool
```

True if this is the org's managed storage source.

## Task

```python theme={"system"}
Task(
    name: str,
    display_name: str,
    description: str | None = None,
    regions: list[str] = list(),
    input_schema: dict[str, object] | None = None,
    output_schema: dict[str, object] | None = None,
    examples: list[TaskExample] = list(),
)
```

A task with the schemas of its inputs and outputs.

#### Parameters

**name** `str` *required*

**display\_name** `str` *required*

**description** `str | None` (default: None)

**regions** `list[str]` (default: list())

**input\_schema** `dict[str, object] | None` (default: None)

JSON Schema the run inputs must satisfy, when the task has one.

**output\_schema** `dict[str, object] | None` (default: None)

JSON Schema of a successful run's results, when the task has one.

**examples** `list[TaskExample]` (default: list())

Example inputs.

## TaskExample

```python theme={"system"}
TaskExample(name: str, inputs: dict[str, object] = dict())
```

A named set of example inputs for a task.

#### Parameters

**name** `str` *required*

What the example shows.

**inputs** `dict[str, object]` (default: dict())

Inputs to pass to `Tasks.run`.

## TaskRun

```python theme={"system"}
TaskRun(
    task_run_id: str,
    task_name: str,
    state: TaskRunState | str,
    region: str,
    submitted_at: datetime | None = None,
    started_at: datetime | None = None,
    ended_at: datetime | None = None,
    duration_seconds: int | None = None,
    name: str | None = None,
    inputs: dict[str, object] = dict(),
    results: dict[str, object] | None = None,
    cached: bool = False,
    error_message: str | None = None,
)
```

One run of a task, with its inputs and outcome.

#### Parameters

**task\_run\_id** `str` *required*

**task\_name** `str` *required*

**state** `TaskRunState | str` *required*

**region** `str` *required*

**submitted\_at** `datetime | None` (default: None)

**started\_at** `datetime | None` (default: None)

**ended\_at** `datetime | None` (default: None)

**duration\_seconds** `int | None` (default: None)

**name** `str | None` (default: None)

The name given to the run, if any.

**inputs** `dict[str, object]` (default: dict())

The inputs it ran with.

**results** `dict[str, object] | None` (default: None)

The task's outputs by name (one output reads `{"o0": ...}`) once
the run has succeeded.

**cached** `bool` (default: False)

Whether it returned a stored result from an earlier identical run.

**error\_message** `str | None` (default: None)

Why the run did not succeed.

### is\_active

```python theme={"system"}
TaskRun.is_active: bool
```

Return `True` while the run may still change state.

## TaskRunCost

```python theme={"system"}
TaskRunCost(
    task_run_id: str,
    total_cost_usd: Decimal,
    units: int,
    unit_type: str,
    is_settling: bool,
)
```

What a task run cost.

#### Parameters

**task\_run\_id** `str` *required*

The run's id.

**total\_cost\_usd** `Decimal` *required*

Total cost in US dollars.

**units** `int` *required*

Billed units.

**unit\_type** `str` *required*

What a unit measures.

**is\_settling** `bool` *required*

`True` while the cost may still change.

## TaskRunLogEntry

```python theme={"system"}
TaskRunLogEntry(timestamp: str, level: str, message: str)
```

One log line of a task run.

#### Parameters

**timestamp** `str` *required*

UTC instant to the nanosecond, as a string (`datetime` would round it).

**level** `str` *required*

Log level.

**message** `str` *required*

The line.

## TaskRunLogs

```python theme={"system"}
TaskRunLogs(
    task_run_id: str,
    entries: list[TaskRunLogEntry] = list(),
    next_since: str | None = None,
)
```

One page of a task run's logs.

#### Parameters

**task\_run\_id** `str` *required*

The run's id.

**entries** `list[TaskRunLogEntry]` (default: list())

Log lines, oldest first.

**next\_since** `str | None` (default: None)

Pass as `since` to fetch the lines after this page; `None` once
the run has finished and every line has been returned.

## TaskRunSummary

```python theme={"system"}
TaskRunSummary(
    task_run_id: str,
    task_name: str,
    state: TaskRunState | str,
    region: str,
    submitted_at: datetime | None = None,
    started_at: datetime | None = None,
    ended_at: datetime | None = None,
    duration_seconds: int | None = None,
)
```

One run of a task, as listings show it.

#### Parameters

**task\_run\_id** `str` *required*

The run's id.

**task\_name** `str` *required*

The task it ran.

**state** `TaskRunState | str` *required*

A `TaskRunState`, or the raw string for a state this SDK does not know.

**region** `str` *required*

The region it runs in.

**submitted\_at** `datetime | None` (default: None)

When it was submitted.

**started\_at** `datetime | None` (default: None)

When it started executing.

**ended\_at** `datetime | None` (default: None)

When it ended.

**duration\_seconds** `int | None` (default: None)

How long it executed (so far, while running).

### is\_active

```python theme={"system"}
TaskRunSummary.is_active: bool
```

Return `True` while the run may still change state.

## TaskSummary

```python theme={"system"}
TaskSummary(
    name: str,
    display_name: str,
    description: str | None = None,
    regions: list[str] = list(),
)
```

A task the caller's organization can run, as listings show it.

#### Parameters

**name** `str` *required*

The task's unique name; pass it to `Tasks.get` and `Tasks.run`.

**display\_name** `str` *required*

Human-readable name.

**description** `str | None` (default: None)

What the task does, when it says.

**regions** `list[str]` (default: list())

Regions the task can run in.

## TemporaryAwsCredentials

```python theme={"system"}
TemporaryAwsCredentials(
    access_key_id: str,
    secret_access_key: str,
    session_token: str,
    expiration: datetime,
    region: str,
)
```

Short-lived AWS STS credentials vended by `POST /storage/credentials`.

Scope is determined server-side from the requested S3 path: the
server picks the right backing bucket (managed / releases /
matching Storage Integration).

Security posture:

* **Masked in repr/str.** `repr(creds)` (and therefore `str(creds)`
  and any f-string interpolation) only show the last 4 characters of
  the access key ID. Secret + session token never appear.
* **Frozen.** Attribute injection is rejected; `wipe()` is the only
  mutator (via `object.__setattr__` internally).
* **No pickle / copy.** `__reduce__`, `__copy__`, and
  `__deepcopy__` raise `TypeError` so creds cannot be silently
  serialized to disk, queues, or another process.
* **Local eviction via `wipe()`.** Zeros the secret fields and
  poisons `expiration` so any subsequent `is_expired` check
  returns `True`. Python strings are immutable so the original
  bytes may linger on the heap until garbage collection, but this
  drops our last live reference. AWS-side revocation is not
  possible via the SDK; rely on the short TTL (typically 1 h).

#### Parameters

**access\_key\_id** `str` *required*

**secret\_access\_key** `str` *required*

**session\_token** `str` *required*

**expiration** `datetime` *required*

**region** `str` *required*

### is\_expired()

```python theme={"system"}
is_expired(leeway_seconds: int = 60) -> bool
```

True if these creds are within *leeway\_seconds* of expiry.

#### Parameters

**leeway\_seconds** `int` (default: 60)

### wipe()

```python theme={"system"}
wipe() -> None
```

Evict secret material from this object.

Overwrites `access_key_id` / `secret_access_key` /
`session_token` with empty strings and forces `expiration`
into the past so any post-wipe reuse is detected by
`is_expired`. Idempotent; safe to call multiple times.

## UtilizationStats

```python theme={"system"}
UtilizationStats(
    latest: float | None = None,
    max: float | None = None,
    avg: float | None = None,
    series: list[tuple[float, float]] = list(),
)
```

Aggregated utilization for a single metric (e.g. CPU or memory).

`series` is the raw time-series of `(timestamp, value)` points
as returned by the server, normalized to floats. `latest` /
`max` / `avg` are derived from that series for convenience.
All fields are `None` / empty when the metric was not present in
the response.

#### Parameters

**latest** `float | None` (default: None)

**max** `float | None` (default: None)

**avg** `float | None` (default: None)

**series** `list[tuple[float, float]]` (default: list())

### from\_metric()

```python theme={"system"}
UtilizationStats.from_metric(
    instant: dict[str, Any],
    series: dict[str, Any],
    keys: tuple[str, ...],
) -> UtilizationStats
```

Build stats from the server's untyped metric dicts.

#### Parameters

**instant** `dict[str, Any]` *required*

`RunMetricsResponse.instant_metrics`.

**series** `dict[str, Any]` *required*

`RunMetricsResponse.series_metrics`.

**keys** `tuple[str, ...]` *required*

Candidate metric names to look up, in priority order.
The first key found in *series* (or *instant* as a
fallback) is used. Multiple candidates are supported
because metric names are server-defined and untyped.

#### Returns

**return** `UtilizationStats`

A populated `UtilizationStats`, or an empty instance if
none of the candidate keys are present.

> [!NOTE]
>
> Tie-break is "first key with ≥1 parseable point wins" — once
> we begin parsing a given key we do not fall through to
> subsequent candidates, even if some points within that key
> are malformed. In practice the primary (UPPERCASE) production
> key matches and the lowercase aliases only get tried when the
> primary key is entirely absent from the response.


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