Metadata-Version: 2.4
Name: plato-sdk-v2
Version: 2.125.1
Summary: Python SDK for the Plato API
Author-email: Plato <support@plato.so>
License-Expression: MIT
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Typing :: Typed
Requires-Python: <3.14,>=3.11
Requires-Dist: aiohttp==3.14.1
Requires-Dist: blake3==1.0.8
Requires-Dist: boto3==1.42.52
Requires-Dist: cloudpickle==3.1.2
Requires-Dist: cryptography==46.0.7
Requires-Dist: datamodel-code-generator==0.53.0
Requires-Dist: email-validator==2.3.0
Requires-Dist: fastmcp==3.2.0
Requires-Dist: gitpython==3.1.50
Requires-Dist: google-genai==1.59.0
Requires-Dist: httpx==0.28.1
Requires-Dist: jinja2==3.1.6
Requires-Dist: jsonschema==4.23.0
Requires-Dist: litellm==1.90.0
Requires-Dist: openapi-pydantic==0.5.1
Requires-Dist: opentelemetry-api==1.39.1
Requires-Dist: opentelemetry-exporter-otlp-proto-http==1.39.1
Requires-Dist: opentelemetry-instrumentation-system-metrics==0.60b1
Requires-Dist: opentelemetry-sdk==1.39.1
Requires-Dist: pathspec==1.0.4
Requires-Dist: pydantic-settings==2.14.2
Requires-Dist: pydantic==2.12.5
Requires-Dist: python-dotenv==1.2.2
Requires-Dist: pyyaml==6.0.3
Requires-Dist: requests==2.33.0
Requires-Dist: rich==14.2.0
Requires-Dist: tenacity==9.1.2
Requires-Dist: tomli==2.4.0
Requires-Dist: typer==0.21.1
Provides-Extra: db-cleanup
Requires-Dist: aiomysql>=0.2; extra == 'db-cleanup'
Requires-Dist: aiosqlite>=0.20; extra == 'db-cleanup'
Requires-Dist: asyncpg>=0.29; extra == 'db-cleanup'
Requires-Dist: sqlalchemy[asyncio]>=2.0; extra == 'db-cleanup'
Provides-Extra: dev
Requires-Dist: basedpyright>=1.18; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
Requires-Dist: pytest>=9.1.1; extra == 'dev'
Requires-Dist: ruff>=0.1; extra == 'dev'
Provides-Extra: segmentation
Requires-Dist: numpy>=1.24.0; extra == 'segmentation'
Requires-Dist: pillow>=10.0.0; extra == 'segmentation'
Provides-Extra: worlds
Requires-Dist: dvc; extra == 'worlds'
Requires-Dist: dvc-s3; extra == 'worlds'
Description-Content-Type: text/markdown

# Plato Python SDK

Python SDK for the Plato platform.

## Installation

```bash
pip install plato-sdk-v2
```

Or with uv:

```bash
uv add plato-sdk-v2
```

Agent support is in the base package — there is no `[agents]` extra. The declared
extras are `dev`, `segmentation`, `worlds` and `db-cleanup` (see `pyproject.toml`).

## Configuration

Create a `.env` file in your project root:

```bash
PLATO_API_KEY=your-api-key
PLATO_BASE_URL=https://plato.so  # optional, defaults to https://plato.so
```

Or set environment variables directly:

```bash
export PLATO_API_KEY=your-api-key
```

## Agents

Agents run inside Plato VMs. The first-party agent is `computer-use` (browser
automation, install: `pip install plato-agent-computer-use`); custom agents
subclass `plato.agents.BaseAgent` — see `plato/agents/base.py` for the interface
and the module docstring in `plato/agents/__init__.py` for the exported API and
worked examples.

### CLI Usage

```bash
# List available agents
plato agent list

# Get agent config schema
plato agent schema computer-use

# Publish a custom agent to Plato PyPI
plato agent publish ./my-agent
```

---

## Sessions & Environments

### Flow 1: Create Session from Environments

Use this when you want to spin up environments for development, testing, or custom automation.

```python
import asyncio
from plato.v2 import AsyncPlato, Env

async def main():
    plato = AsyncPlato()

    # Create session with one or more environments
    # (heartbeat starts automatically to keep session alive)
    session = await plato.sessions.create(
        envs=[
            Env.simulator("gitea", dataset="blank", alias="gitea"),
            Env.simulator("kanboard", alias="kanboard"),
        ],
        timeout=600,
    )

    # Reset environments to initial state
    await session.reset()

    # Get public URLs for browser access
    public_urls = await session.get_public_url()
    for alias, url in public_urls.items():
        print(f"{alias}: {url}")

    # Get state mutations from all environments
    state = await session.get_state()
    print(state)

    # Cleanup
    await session.close()
    await plato.close()

asyncio.run(main())
```

### Flow 2: Create Session from Test Case

Use this when running evaluations against predefined test cases. This flow includes evaluation at the end.

```python
import asyncio
from plato.v2 import AsyncPlato

async def main():
    plato = AsyncPlato()

    # Create session from a test case public ID.
    # Unlike `envs=`/`artifacts=`, this auto-resets for mutation logging,
    # so no explicit session.reset() is needed.
    session = await plato.sessions.create(testcase="tc_abc123", timeout=600)

    # Get public URLs for browser access
    public_urls = await session.get_public_url()
    for alias, url in public_urls.items():
        print(f"{alias}: {url}")

    # Evaluate task completion
    evaluation = await session.evaluate()
    print(f"Task completed: {evaluation}")

    # Cleanup
    await session.close()
    await plato.close()

asyncio.run(main())
```

## Environment Configuration

Two ways to specify environments:

```python
from plato.v2 import Env

# 1. From simulator (most common)
Env.simulator("gitea")                          # default tag
Env.simulator("gitea", tag="staging")           # specific tag
Env.simulator("gitea", dataset="blank")         # specific dataset
Env.simulator("gitea", alias="my-git")          # custom alias

# 2. From artifact ID
Env.artifact("artifact-abc123")
Env.artifact("artifact-abc123", alias="my-env")
```

## Per-Environment Operations

Access individual environments within a session:

```python
# Get all environments
for env in session.envs:
    print(f"{env.alias}: {env.job_id}")

# Get specific environment by alias
gitea = session.get_env("gitea")

if gitea:
    # Execute shell command
    result = await gitea.execute("whoami", timeout=30)
    print(result)

    # Get state for this environment only
    state = await gitea.get_state()

    # Reset this environment only
    await gitea.reset()
```

## Sync Client

A synchronous client is also available:

```python
from plato.v2 import Plato, Env

plato = Plato()

session = plato.sessions.create(
    envs=[Env.simulator("gitea", alias="gitea")],
    timeout=600,
)

session.reset()

public_urls = session.get_public_url()
state = session.get_state()

session.close()
plato.close()
```

## Documentation

- [Generating Simulator SDKs](docs/GENERATING_SIM_SDKS.md) - How to create API clients for simulators
- [Building Simulators](BUILDING_SIMS.md) - Internal docs for snapshotting simulators

Part of the [useplato/plato-client](https://github.com/useplato/plato-client) monorepo.
