Metadata-Version: 2.4
Name: rescale-ai-client
Version: 0.1.0
Summary: Standalone HTTP client for hosted and local Rescale AI inference servers
Project-URL: Repository, https://github.com/rescale/rescale-ai-client
Author: Rescale
License-Expression: Apache-2.0
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering
Requires-Python: >=3.10
Requires-Dist: numpy>=1.24
Requires-Dist: pydantic>=2.7
Requires-Dist: python-multipart
Provides-Extra: dev
Requires-Dist: datamodel-code-generator>=0.31.2; extra == 'dev'
Requires-Dist: pytest>=7; extra == 'dev'
Provides-Extra: jupyter
Requires-Dist: jupyter-bokeh>=4.0; extra == 'jupyter'
Requires-Dist: panel>=1.0; extra == 'jupyter'
Requires-Dist: pyvista>=0.40; extra == 'jupyter'
Requires-Dist: trame>=2.0; extra == 'jupyter'
Provides-Extra: mesh
Requires-Dist: pyvista>=0.40; extra == 'mesh'
Provides-Extra: optimization
Requires-Dist: scipy>=1.10; extra == 'optimization'
Provides-Extra: ssh
Requires-Dist: paramiko>=3.4; extra == 'ssh'
Description-Content-Type: text/markdown

# rescale-ai-client

Standalone Python client for [Rescale AI](https://rescale.com) hosted and local inference servers.
Communicates over the shared HTTP API. No `rescale_ai` package dependency.

## Installation

```bash
pip install rescale-ai-client
```

For mesh loading, prediction plotting, or VTK mesh helpers (`.vtp` and `.vtm`):

```bash
pip install "rescale-ai-client[mesh]"
```

For interactive 3D notebook plots:

```bash
pip install "rescale-ai-client[mesh,jupyter]"
```

This extra also installs `jupyter_bokeh`, which Panel needs for interactive rendering
in VSCode notebooks.

For development:

```bash
pip install -e ".[dev]"
```

## Protocol Sync

The committed wire DTOs under `src/rescale_ai_client/_generated/` are generated from the
closed-source inference server OpenAPI schema snapshot at
`openapi/inference-server.openapi.json`.

Update flow:

```bash
# from the closed-source rescale_ai repo
PYTHONPATH=/path/to/rescale_ai \
  /path/to/rescale_ai/.venv/bin/python \
  - <<'PY'
from pathlib import Path
from rescale_ai.inference.server.openapi_compat import export_openapi_schema

export_openapi_schema(
    Path("/path/to/rescale-ai-client/openapi/inference-server.openapi.json")
)
PY

# from this repo
python scripts/generate_protocol_models.py
python scripts/generate_protocol_models.py --check
```

## Releasing

Releases are published by GitHub Actions with `uv build` and `uv publish`.

One-time setup:

1. In GitHub, create an environment named `pypi` under **Settings -> Environments**.
2. In PyPI, add a trusted publisher for:
   - Owner: `rescale`
   - Repository: `rescale-ai-client`
   - Workflow: `release.yml`
   - Environment: `pypi`

No PyPI API token needs to be stored in GitHub secrets for this workflow. PyPI issues
a short-lived publish credential to the tagged GitHub Actions run through OIDC.

Publish a release:

```bash
uv version 0.1.1
git commit -am "Release 0.1.1"
git tag -a v0.1.1 -m v0.1.1
git push origin main
git push origin v0.1.1
```

The workflow runs tests, verifies generated protocol models, builds both wheel and
source distributions, smoke-tests both artifacts, and publishes to PyPI.

## Quickstart

Server-available models:

```python
from rescale_ai_client import InferenceClient

client = InferenceClient.connect(base_url="http://127.0.0.1:65432")
catalog = client.list_models()

model = catalog.model("MyModel").latest()
prediction = client.run_inference(
    "/path/to/case.vtm",
    parameters={"mach": 0.82},
    model_name=model.model_name,
    version_number=model.version_number,
)

print(prediction.global_predictions)
prediction.save("/tmp/result.vtm")
```

No-mesh core install, summary-only inference:

```python
from rescale_ai_client import InferenceClient

client = InferenceClient.connect(base_url="http://127.0.0.1:65432")
summary = client.run_inference_summary(
    "/path/to/case.vtm",
    parameters={"mach": 0.82},
    model_name="MyModel",
    version_number=7,
)

print(summary.global_predictions)
print(summary.prediction_id)
```

Offline local-installer bundle flow:

```python
from rescale_ai_client import InferenceClient

client = InferenceClient.connect(base_url="http://127.0.0.1:65432")

installed = client.install_bundle(
    "/path/to/MyModel_v0_local_inference.zip"
)

prediction = client.run_inference(
    "/path/to/case.vtm",
    parameters={"mach": 0.82},
    model_version_path=installed.model_version_path,
)

print(installed.model_name, installed.version_number)
print(prediction.global_predictions)
```

Headless license lease refresh:

```python
from rescale_ai_client import InferenceClient

client = InferenceClient.connect(base_url="https://inference.rescale.com")
lease = client.request_license_lease(
    "eyJ...activation...",
    requested_offline_days=31,
)

print(lease.machine_id_hash)
print(lease.expires_at)
print(lease.lease_token)
```

### `extensions` for optional future data

Most JSON request methods accept an optional `extensions={...}` payload. This is the additive
escape hatch for future server features that should not force a client upgrade.

Example: send optional request hints during prediction:

```python
from rescale_ai_client import InferenceClient

client = InferenceClient.connect(base_url="http://127.0.0.1:65432")

summary = client.run_inference_summary(
    "/path/to/case.vtm",
    parameters={"mach": 0.82},
    model_name="MyModel",
    version_number=7,
    extensions={
        "rescale": {
            "ui_session": "demo-123",
            "include_debug": True,
        }
    },
)

print(summary.extensions)
print(summary.warnings)
```

Example: read capability-style or server-added metadata from typed responses:

```python
from rescale_ai_client import InferenceClient

client = InferenceClient.connect(base_url="http://127.0.0.1:65432")

server_info = client.server_info()
print(server_info.capabilities)

metadata = client.get_model_version_metadata(
    model_name="MyModel",
    version_number=7,
)
print(metadata.extensions)
print(metadata.warnings)
```

Design rules:

- `extensions` are optional and additive
- unknown request extensions are ignored by the server
- unknown response extensions are ignored by clients
- if a field becomes core contract, it should graduate into a typed top-level field

## API

### `InferenceClient.connect(*, base_url=None, host=None, port=None, url=None, timeout=600.0)`

Factory method. If omitted, defaults to local loopback at `http://127.0.0.1:65432`. `base_url` first. `host` / `port` and `url` remain convenience inputs. Scheme-less non-local endpoints default to HTTPS; explicit HTTP for non-local endpoints raises an `InsecureConnectionWarning` and stores the message on `client.insecure_transport_warning`.

### `InferenceClient.connect_via_ssh(*, ssh_user_host, remote_port=65432, ...)`

SSH tunnel helper. `ssh_user_host` required. If `remote_port` is omitted, defaults to `65432`.

### `run_inference(vtp, parameters=None, *, model=None, model_version_path=None, model_name=None, model_uuid=None, version_number=None, ...)`

Canonical Python entrypoint. The `vtp` argument name is kept for compatibility, but path inputs may be `.vtp` or `.vtm`; `.vtm` paths are sent to the inference server so block structure is preserved. Same shape for hosted and local servers. CamelCase aliases still work, but new code should use snake_case.
JSON request methods also accept `extensions=...` for optional future payloads.

### `run_inference_summary(...)`

Lightweight entrypoint for core installs without the optional mesh dependencies. Returns typed prediction metadata plus global scalar outputs without constructing a `pyvista` mesh.

### `list_models(...)`

Returns a typed `ListModelsResult` with helpers like `.model("name")`, `.get("name", version_number=7)`, and `.model("name").latest()`.

### `request_license_lease(activation_token, *, requested_offline_days=31, machine_id_hash=None, ...)`

Requests a machine-bound offline lease from the hosted license endpoint. If `machine_id_hash` is omitted, the SDK derives a stable local machine hash automatically.

### `inspect_bundle(...)` / `install_bundle(...)`

Inspect, upload, and install an offline local-inference bundle zip into the local installer. `install_bundle(...)` is idempotent: same content is a no-op, changed content updates the installed version.

### `get_model_version_metadata(version_number, *, model_name=None, model_uuid=None, ...)`

Fetches typed metadata for one model version.

### `get_loaded_model()`

Returns the server's current active-model bookkeeping status.

### `server_info()`

Returns typed inference server capability and compatibility metadata:

- `api_version`
- `supported_api_versions`
- `schema_revision`
- `server_build`
- `capabilities`

### `Client`

Compatibility alias for one release. Use `InferenceClient` for new code.

## License

Apache-2.0
