Metadata-Version: 2.5
Name: digiarena
Version: 0.3.0
Summary: Python SDK for DigiArena (digiarena.org): browse hosted robot-simulation scenes, deploy cloud gyms, submit to benchmarks.
Project-URL: Homepage, https://digiarena.org
Project-URL: Repository, https://github.com/Grounded-Intelligence-Initiative/digiarena-client-python
Project-URL: Documentation, https://digiarena.org/docs/api
Author-email: Xiatao Sun <sunxiatao@gmail.com>
License: Apache-2.0
License-File: LICENSE
Keywords: benchmark,gaussian-splatting,gymnasium,real2sim,robotics,simulation
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.10
Requires-Dist: world-engine-client[gym,img]>=0.4
Provides-Extra: gym
Provides-Extra: img
Provides-Extra: render
Requires-Dist: world-engine-client[render]>=0.4; extra == 'render'
Description-Content-Type: text/markdown

# digiarena (PyPI: `digiarena`)

Python SDK for [DigiArena](https://digiarena.org) — browse hosted
robot-simulation scenes, deploy them as cloud gyms, and submit to benchmarks.

```bash
pip install digiarena
# Camera images are rendered on your machine; add this for image observations:
pip install 'digiarena[render]' && python -m playwright install chromium
```

```python
import digiarena as da

da.login()                                   # paste an API key from digiarena.org → Settings
# Continue the exact browser attempt without resetting:
with da.attach("hosted-session-id") as env:
    obs, info = env.observe()
    print(info["episode_id"], obs["rgb"].keys())

# Or launch an independent session from an accessible scene in one call
# (env.close() also tears the session down):
with da.make("alice/kitchen_001", task="pick_mug_to_sink") as env:
    obs, info = env.reset(seed=0)
    obs, reward, terminated, truncated, info = env.step(env.action_space.sample())

# Or keep the handle for the viewer URL, logs and lifetime extension:
scenes = da.scenes.list(query="kitchen")
gym = da.deploy(scene="kitchen_001", task="pick_mug_to_sink")
env = gym.connect()                          # → world_engine_client.RemoteEnv
obs, info = env.reset(seed=0)
obs, r, term, trunc, info = env.step(action)
gym.close()
```

CLI with the same surface:

```
digiarena login
digiarena scenes list --query kitchen
digiarena deploy --scene kitchen_001
digiarena leaderboard tabletop-v1
digiarena usage
```

## Layering

`digiarena` depends on and reuses
[`world-engine-client`](https://github.com/Grounded-Intelligence-Initiative/world-engine-client-python)
(`connect(token, url) → RemoteEnv`). This package covers everything from your
account to that token — scene gallery, cloud deploy, benchmark submission,
leaderboards, usage — and never reimplements the wire protocol.

- Light dependencies: numpy, Pillow (camera images) and Gymnasium (spaces),
  all via `world-engine-client`. No torch or opencv. `import digiarena` loads
  only the stdlib and numpy; Pillow and Gymnasium load on first use.
- Every call hits the public REST API (`/api/v1/*`) with
  `Authorization: Bearer da_live_...` — the SDK is a thin wrapper you could
  replace with curl.
- Typed errors with actionable "Possible fixes" (the World Engine style).
- Endpoints still in later platform milestones (benchmark submission) raise `NotImplementedYetError` with the server's own
  guidance — the SDK surface is stable ahead of them.

Scene content never transits your machine: there is no upload()/download().
Content is authored in the platform's browser editor; public scenes are used
directly via `da.deploy()` without forking. Private scenes require ownership or
platform admin access. Pass `images=False` to deploy/attach for state-only operation.

Camera images are drawn on your computer, not on the platform: the hosted session
simulates physics and sends the poses with each step, and a headless Chrome on your
machine renders the same scene the browser shows. This needs the `render` extra and
a Chrome with hardware WebGL (`chrome://gpu`); without the extra, asking for images
fails before any request. Scene assets are downloaded once per session into a
temporary cache that `env.close()` deletes.

## Remote simulation

`da.attach(session_id)` uses resume semantics and pauses the current attempt.
`env.observe()` and `env.render()` never advance physics. `env.reset(seed=...)`
starts a new episode; `env.step(action)` advances one negotiated control interval.
`env.close()` releases control; `gym.close()` tears down a launched session.
A live Python controller survives browser closure. Lost/uncertain actions are
never retried automatically: reconnect or explicitly reset to recover.

Images are RGB `uint8` arrays in `obs['rgb']`, keyed by configured camera name.
Use `cameras=['wrist']` for a subset and `env.as_gymnasium()` for the optional
Gymnasium adapter.

Runnable examples are in the repository's
[`examples/`](https://github.com/Grounded-Intelligence-Initiative/digiarena-client-python/tree/main/examples)
directory (not part of the installed package): `attach.py`, `reachable_pose.py`, and
`deploy_policy.py`. `measure_remote.py` records throughput and soak measurements.
`vla_smolvla.py` runs a real VLA (SmolVLA via LeRobot, `pip install 'lerobot[smolvla]'`)
on your machine against a remote session, and `measure_link.py` reports what your
network link does to stepping: steps per second, latency and bandwidth used, for
state only, one camera and all cameras.

To check the whole path end to end, start Simulate in the browser editor, copy
the session id from the Inspector's Python API card, and send the end effector
to a pose while watching the browser:

```bash
python examples/reachable_pose.py SESSION_ID                       # small offset from the start pose
python examples/reachable_pose.py SESSION_ID --pos 0.45 0.0 0.30   # absolute position, metres
python examples/reachable_pose.py SESSION_ID --pos 0.45 0 0.3 --rot 3.14 0 0 --state-only
digiarena attach SESSION_ID --state-only                           # inspect without stepping
```

## Development

```bash
pip install -e '.[img,gym]' pytest && python -m pytest
```

The tests use a stub control plane and a fake simulator; no platform is needed.

## Credentials

`DIGIARENA_API_KEY` env var (CI/batch) → `~/.config/digiarena/credentials`
(written by `da.login()` / `digiarena login`, mode 0600).
`DIGIARENA_API_URL` overrides the endpoint for staging deployments.
