Metadata-Version: 2.5
Name: openai-agents-prized
Version: 0.1.0
Summary: Prized Sandboxes (Linux microVMs) as a sandbox client for the OpenAI Agents SDK
Project-URL: Homepage, https://prized.dev/docs/sandboxes
Project-URL: Documentation, https://prized.dev/docs/sandboxes-openai-agents
Project-URL: API reference, https://prized.dev/docs/sandboxes-api
Author-email: Prized <team@prized.dev>
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: agents,firecracker,microvm,openai,openai-agents,prized,sandbox
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
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 :: Artificial Intelligence
Classifier: Typing :: Typed
Requires-Python: <4.0,>=3.10
Requires-Dist: httpx<1.0.0,>=0.27.0
Requires-Dist: openai-agents<0.26.0,>=0.23.1
Description-Content-Type: text/markdown

# openai-agents-prized

[Prized Sandboxes](https://prized.dev/docs/sandboxes) as a sandbox client for the [OpenAI Agents SDK](https://openai.github.io/openai-agents-python/sandbox/clients/). A `SandboxAgent` runs its shell commands and file edits in a Prized sandbox, a Linux microVM that is deleted when the run ends.

## Install

```bash
pip install openai-agents-prized
export PRIZED_API_KEY=dcp_...
export OPENAI_API_KEY=sk-...
```

Make the Prized key at [prized.dev/dashboard/workspace/api-keys](https://prized.dev/dashboard/workspace/api-keys) with **Full access**, or **Custom** with **Sandboxes: Write**. Python 3.10 or later, `openai-agents` 0.23.1 or later, below 0.26.

## Run an agent

```python
import asyncio

from agents import Runner
from agents.run import RunConfig
from agents.sandbox import SandboxAgent, SandboxRunConfig

from openai_agents_prized import PrizedSandboxClient, PrizedSandboxClientOptions


async def main() -> None:
    agent = SandboxAgent(name="coder", instructions="Work in the sandbox with your tools.")
    run_config = RunConfig(
        sandbox=SandboxRunConfig(
            client=PrizedSandboxClient(),
            options=PrizedSandboxClientOptions(vcpu=2, memory_mb=4096),
        )
    )
    result = await Runner.run(
        agent, "Write fizzbuzz.py, run it for 15, and show me the output.", run_config=run_config
    )
    print(result.final_output)


asyncio.run(main())
```

The agent's `exec_command`, `write_stdin`, and `apply_patch` tools run in the sandbox as the user `prized`, in `/home/prized/work`. A manifest on the SDK's default root (`/workspace`) is placed there too.

## Options

`PrizedSandboxClientOptions` maps to the Sandbox API's [create](https://prized.dev/docs/sandboxes-api#create):

| Option | Default | Effect |
| --- | --- | --- |
| `template` | `prized-base-v1` | `prized-agent-v1` adds Claude Code and Codex |
| `vcpu`, `memory_mb`, `disk_gb` | The template's | The sandbox's shape |
| `env_vars`, `labels` | None | Set for every command; yours to filter on |
| `auto_pause_min`, `auto_delete_min`, `max_runtime_min` | Off, off, 1,440 (60 on the free tier) | Automatic pause and delete |
| `pause_on_exit` | `False` | Pause instead of delete at the end of a run, so `resume()` continues in the same sandbox with its files and installs (the SDK ends the run's commands before the pause) |
| `timeouts` | | `PrizedSandboxTimeouts`: per-command default, startup, and archive timeouts |

`PrizedSandboxClient(api_key=..., api_url=...)` reads `PRIZED_API_KEY` and `PRIZED_API_URL` when they are not passed.

## Pause and resume

The client implements the SDK's session lifecycle: `RunState` round trips, snapshots, and `resume()`. With `pause_on_exit=True`, a paused sandbox keeps memory and disk for the price of storage, and the resumed run reuses it without restoring anything. Without it, the sandbox is deleted and a resumed run starts a new one and restores the workspace from the session's snapshot.

## Moving from Runloop

`openai-agents` removed `RunloopSandboxClient`. Swap the client and options; the agent stays the same:

| Runloop | Prized |
| --- | --- |
| `RunloopSandboxClient()` | `PrizedSandboxClient()` |
| `RunloopSandboxClientOptions(blueprint_name=...)` | `PrizedSandboxClientOptions(template=...)` |
| `env_vars`, `pause_on_exit` | Same names |
| `metadata` | `labels` |
| `exposed_ports`, tunnels, gateways, MCP, managed secrets, mounts | Not supported |

Runloop session state cannot be resumed on Prized; start new runs.

## Limits

- **No root.** Commands run as `prized` without sudo, so manifest users other than `prized`, manifest groups, and mounts are refused before a sandbox is created.
- **No inbound network.** Sandboxes reach the internet, but nothing reaches them: no exposed ports.
- **Commands.** A command that outlives `exec_command`'s yield keeps running, and `write_stdin` polls it or types into it (with `tty=True`, Ctrl-C included). It runs until it exits or the session ends, unless the tool call passes a `timeout`. A command run with `exec` takes up to an hour (`PrizedSandboxTimeouts.exec_timeout_unbounded_s`) and keeps the first 4 MiB of its output and of its errors.
- **Snapshots.** Symlinks are kept as links, so a virtualenv in the workspace comes back working in a replacement sandbox; hard-linked files come back as separate copies.
- **Run time.** 24 hours of running by default, up to 7 days with `max_runtime_min`; on the free tier 60 minutes, 2 vCPU and 4 GB.
- **Keys.** Code in the sandbox, the model's included, can read `env_vars`. Keep your Prized key out of them.

Refusals from the API raise `PrizedAPIError` with the API's [error code](https://prized.dev/docs/sandboxes-api#errors); sandbox failures inside a run surface as the SDK's own `SandboxError` types.

## When something fails

A failed or cancelled create deletes the sandbox it made, and a failed resume pauses the sandbox it woke; if even that cannot reach the API, a warning names the sandbox. An answer that never came is settled by reading the sandbox, so a pause that landed is never followed by a delete. `close()` waits for cleanup a cancellation left running. A command whose answer is lost is never sent again, and its error says which of three it was: it never reached the sandbox, it may or may not have run, or it ran but the answer could not be read.

## Development

```bash
uv sync
uv run pytest                                          # offline, against an in-process fake of the API
PRIZED_LIVE_TESTS=1 PRIZED_API_KEY=dcp_... uv run pytest -m live   # the SDK's lifecycle test on real sandboxes
PRIZED_API_KEY=dcp_... uv run python scripts/live_agent.py         # a coding agent end to end, scripted model turns
```

Apache-2.0.
