Metadata-Version: 2.4
Name: tidefold-client
Version: 0.0.226
Summary: Python client for starting and following tidefold workflow runs
Author: tidefold
License-Expression: Apache-2.0
License-File: LICENSE
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.13
Classifier: Operating System :: OS Independent
Classifier: Typing :: Typed
Requires-Dist: httpx>=0.27.0,<1.0.0
Requires-Python: >=3.13, <4.0
Description-Content-Type: text/markdown

# tidefold-client

A small Python client for starting workflow runs on a tidefold deployment,
waiting for them, and reading what they produced.

```sh
pip install "tidefold-client==<your platform version>"
```

Install the version that matches your deployment's platform release. The
client warns when it talks to a server on a different release. There is no
compatibility promise across versions.

## Quick start

```python
from tidefold_client import Client

client = Client.from_env()  # TIDEFOLD_API_URL, TIDEFOLD_API_TOKEN

run = client.workflows.start(
    "invoice_review",
    inputs={"reference": "INV-1042"},
    files={"document": "invoice.pdf"},
    subject="INV-1042",
)
run.wait(timeout=1800)
print(run.results()["marked_results"])
```

`TIDEFOLD_API_URL` is the API root: `https://<your host>/api` on a
deployment, `http://localhost:8000` on a local stack. There is no default.

## The API token

An administrator creates tokens under **Settings → API tokens**. A token is
shown once; keep it in a secret store and pass it through the environment.
Grant only the scopes your script needs:

| Scope | Needed for |
| --- | --- |
| `workflow_read` | `workflows.list()`, `workflows.get_id()`, `workflows.start()` by name |
| `run_create` | `workflows.start()` |
| `run_file_write` | `files.upload()`, `workflows.start()` with `files` |
| `run_read` | `runs.get()`, `runs.wait()`, `runs.results()`, `runs.usage()`, `files.download()` |
| `run_cancel` | `runs.cancel()` |
| `inbox_read` | `runs.requests()` |

"Own data only" visibility suits scripts: the token then sees only the runs
it started. A local stack running without auth takes no token.

## The subclients

The client has one subclient per resource, all sharing one session.

**`client.workflows`**

- `start(name, *, inputs, files, subject, correlation_id)` uploads each
  file and starts a run on the workflow's latest published release
  (`channel="draft"` runs the current draft). It returns a `Run` at once.
  `workflow_id=` starts by id instead of name.
- `list()` returns the workflows the token can see; `get_id(name)` resolves
  a name to its stable id.

**`client.runs`**, each taking a run id

- `get()` reads the run as it stands.
- `wait()` polls until the run ends. It returns the run on `COMPLETED` and
  raises `RunFailed`, `RunCancelled` or `WaitTimeout`. A server restarting
  during a deploy is waited out.
- `results()` returns `results` per step and `marked_results`, the outputs
  the workflow declares. `usage()`, `requests()` and `cancel()` do what
  their names say.

**`client.files`**

- `upload(path)` declares the file, uploads it to the signed URL (never
  with the token) and finalizes it; it returns the file's record.
- `download(file_id, path)` saves a file, such as a produced document.

A `Run` is `client.runs` with the id filled in: `run.wait()`,
`run.results()` and so on. `client.run(run_id)` gives one for a run started
earlier.

**Starting is not idempotent.** The client never retries `start()`, and
calling it twice starts two runs, even with the same `correlation_id`.

## Errors

Every exception derives from `TidefoldError`.

| Exception | Meaning |
| --- | --- |
| `AuthError` | 401: token missing, wrong, expired or revoked |
| `PermissionDenied` | 403: the token lacks the scope named in the message |
| `NotFound` | 404: no such run or file; for a workflow, also a category the token cannot see |
| `Conflict` | 409: workflow never published, or results read while the run is still running |
| `InvalidRequest` | 400, 413, 422: a missing input, an oversized or unsupported file |
| `UploadError` | a file did not upload; no run was started |
| `RunFailed`, `RunCancelled`, `WaitTimeout` | raised by `wait()` |
| `NetworkError` | the server could not be reached after retries |

## License

Apache-2.0.
