Metadata-Version: 2.4
Name: hardsim
Version: 0.1.2
Summary: Hardsim Python SDK
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Provides-Extra: s3
Requires-Dist: boto3>=1.34.0; extra == "s3"

# Hardsim SDK (v0)

Phase 1 SDK goals:

- `submit(...)` / `run(...)` to create cloud simulation jobs
- `step(...)` alias for cloud-routed environment steps
- `status(...)`, `wait(...)`, and `download(...)` for lifecycle + artifacts
- `watch(...)` live terminal status stream for jobs
- `cancel(...)` for queued/running jobs
- `upload_input(...)` helper for local URDF/USD (default API presigned upload, optional direct S3 mode)
- `upload_input_asset(...)` helper that returns stable Hardsim `asset_id`
- `submit_assets(...)` one-call strict real submit (auto-upload local assets, then submit)
- Retries + typed exceptions for robust client behavior

Install from PyPI:

```bash
pip install hardsim
```

Install (editable during development):

```bash
pip install -e ./sdk
# optional direct-S3 upload helper dependencies:
pip install -e "./sdk[s3]"
```

Release process is documented in `docs/sdk-release.md`.

3-line usage:

```python
import hardsim as hs

job = hs.submit(robot="s3://bucket/franka.urdf", scene="table_top_v0", num_envs=64, steps=2000)
hs.wait(job.job_id)
paths = hs.download(job.job_id, "./outputs")
```

Environment variables:

- `HARDSIM_API_KEY` (required)
- `HARDSIM_API_URL` (default `http://localhost:8000`)
- `HARDSIM_HTTP_TIMEOUT_S` (default `30`)
- `HARDSIM_HTTP_RETRIES` (default `3`)
- `HARDSIM_HTTP_BACKOFF_S` (default `0.5`)
- `HARDSIM_INPUT_S3_BUCKET` (used for direct-S3 `upload_input(...)` fallback or explicit direct mode)
- `HARDSIM_INPUT_S3_PREFIX` (default `hardsim/inputs`)
- `HARDSIM_INPUT_S3_REGION` / `HARDSIM_INPUT_S3_ENDPOINT_URL` (optional)

Production base URL:

```bash
export HARDSIM_API_URL=https://api-sim.hardlightsim.com
```

Idempotent create (recommended for client retries):

```python
job = hs.step(
    robot="s3://bucket/franka.urdf",
    scene="table_top_v0",
    num_envs=64,
    steps=2000,
    control={"task_mode": "fr3_pick_lift_block_v1", "fix_base": True},
    idempotency_key="train-run-42-shard-0001",
)
```

Local file upload helper:

```python
import hardsim as hs

client = hs.HardsimClient.from_env()
robot_uri = client.upload_input("./assets/franka.urdf")
job = client.submit(robot=robot_uri, scene="table_top_v0", num_envs=64, steps=2000)
```

Asset ID flow (recommended for repeated jobs / dashboard parity):

```python
robot_asset_id = client.upload_input_asset("./assets/franka.urdf", asset_kind="robot")
scene_asset_id = client.upload_input_asset("./assets/cabinet_scene.usd", asset_kind="scene")

job = client.submit_assets(
    robot_asset_id=robot_asset_id,
    scene_asset_id=scene_asset_id,
    robot_asset_type="urdf",
    num_envs=64,
    steps=2000,
)
```

One-call strict real submit (recommended for enterprise jobs):

```python
import hardsim as hs

client = hs.HardsimClient.from_env()
job = client.submit_assets(
    robot_asset="./assets/franka.urdf",   # local path or s3:// URI
    scene_usd="./assets/cabinet_scene.usd",  # local path or s3:// URI
    num_envs=64,
    steps=2000,
    scene_id="franka_cabinet_oige_v1",
    control={"task_mode": "fr3_pick_lift_block_v1", "fix_base": True},
)
```

Direct-S3 upload mode (requires boto3 + AWS creds):

```python
robot_uri = client.upload_input(
    "./assets/franka.urdf",
    bucket="my-bucket",
    key_prefix="hardsim/inputs",
    prefer_presigned=False,
)
```

Managed training APIs:

- `create_training_run(...)`
- `get_training_run(run_id)`
- `wait_training_run(run_id, ...)`
- `watch_training_run(run_id, ...)`
- `pause_training_run(run_id)`, `resume_training_run(run_id)`, `cancel_training_run(run_id)`
- `list_run_checkpoints(run_id)`, `get_latest_checkpoint(run_id)`
- `checkpoint_init_asset_id` is supported on `create_training_run(...)`

Live terminal monitoring:

```python
import hardsim as hs

job = hs.submit(robot="s3://bucket/franka.urdf", scene="table_top_v0", num_envs=64, steps=2000)
hs.watch(job.job_id, poll_interval_s=2.0)

run = hs.create_training_run(
    project_id="proj_demo",
    name="managed-loop",
    rollout_template={"job_template": {"job_type": "rollout"}, "rollout_parallelism": 1, "episodes_per_iteration": 1},
    trainer_spec={"image_uri": "ghcr.io/acme/train:latest", "entrypoint": "python train.py", "resources": {"gpu": 1}},
    loop_policy={"max_iterations": 1},
)
hs.watch_training_run(run["run_id"], poll_interval_s=5.0)
```

Reference trainer image for `/v1/training-runs` testing:

- image source: `examples/managed_training/smoke_trainer/`
- usage doc: `docs/trainer-smoke-image.md`
