Skip to content

Commit 32bfd65

Browse files
committed
Add GPU sandbox provisioning, image builds, and computer actions
1 parent 1a9eb35 commit 32bfd65

14 files changed

Lines changed: 1456 additions & 35 deletions

File tree

‎README.md‎

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,3 +1042,89 @@ their explicit-name behavior and continue to report build conflicts directly.
10421042
## License
10431043

10441044
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
1045+
1046+
### GPU sandboxes
1047+
1048+
Build a GPU-ready image from a remote Dockerfile context, then select a GPU when
1049+
creating the sandbox. GPU image publication happens after the ordinary build;
1050+
`enable_gpu_builds=True` makes the build helpers wait for `gpu_image_ready` and
1051+
keeps CPU-only images out of GPU cache reuse. Local/prebuilt Docker image imports
1052+
do not support GPU publication.
1053+
1054+
```python
1055+
from hyperbrowser import Hyperbrowser
1056+
1057+
client = Hyperbrowser()
1058+
image = client.sandboxes.get_or_build_image(
1059+
context_path="./gpu-image", # Your CUDA-compatible Dockerfile and context
1060+
enable_gpu_builds=True,
1061+
)
1062+
sandbox = client.sandboxes.create({
1063+
"image_name": image.image_name,
1064+
"image_id": image.image_id,
1065+
"gpu": "H100",
1066+
"gpu_count": 2,
1067+
"preempt": False, # Require on-demand capacity; account enablement required
1068+
"region": "us",
1069+
"cpu": 8,
1070+
"memory_mib": 32768,
1071+
"disk_mib": 65536,
1072+
"exposed_ports": [{"port": 8000, "auth": True}],
1073+
})
1074+
try:
1075+
# create() can return status='provisioning', runtime=None, and token=None.
1076+
sandbox.wait_until_ready(timeout=20 * 60)
1077+
result = sandbox.exec("nvidia-smi -L")
1078+
print(result.stdout)
1079+
sandbox.update_network({"allow_out": ["example.com"], "deny_out": []})
1080+
finally:
1081+
sandbox.stop()
1082+
```
1083+
1084+
`gpu_count` defaults to one and accepts 1–8; the API checks that the requested
1085+
GPU, CPU, and memory combination is available. Omitted `preempt` (or `True`)
1086+
allows spot capacity. `False` requires on-demand capacity. GPU launches require
1087+
`region="us"`; `runtime_class="gvisor-cpu"` is inferred by the API. The disk is
1088+
quota-limited ephemeral storage, from 12 GiB (the default) up to 512 GiB, subject
1089+
to your plan and host capacity. Snapshots, volume mounts, and startup secrets are
1090+
not supported for GPU launches.
1091+
1092+
`wait_until_ready()` returns the same handle, retries transient reads with
1093+
backoff, and reports failures with the sandbox ID and close reason. Its timeout
1094+
is independent of `timeout_minutes`, which controls the sandbox lifetime.
1095+
Timeout or cancellation stops only the wait. For synchronous cancellation, pass
1096+
a `threading.Event` as `cancel_event`; it is checked between HTTP reads. Async
1097+
clients support the same methods with `await`, and the waiting task can be
1098+
cancelled. After cancelling a wait, use the saved ID to inspect or stop the
1099+
sandbox. `get()` and `list()` can also return provisioning sandboxes; the list
1100+
API's existing `status="active"` filter includes provisioning requests.
1101+
1102+
GPU handles expose `gpu_type`, `gpu_count`, `preempt`, `runtime_class`,
1103+
`capabilities`, `recording_enabled`, and `close_reason`. Existing files, commands,
1104+
PTY, exposed-port authentication, and network-update methods work after readiness.
1105+
`credits_used` and termination details remain available through `info()`.
1106+
1107+
For a custom image that starts an X11 desktop and installs the receiver's input
1108+
and screenshot tools, use the sandbox runtime computer-action endpoint:
1109+
1110+
```python
1111+
screenshot = sandbox.computer_action({"action": "screenshot"})
1112+
sandbox.computer_action({"action": "click", "x": 300, "y": 200})
1113+
sandbox.computer_action({"action": "type_text", "text": "Hello"})
1114+
```
1115+
1116+
These calls belong inside the sandbox's active lifetime (before `stop()`). They
1117+
use the sandbox runtime token, including token refresh, and accept the existing
1118+
computer-action TypedDicts and legacy Pydantic request models. The image owns
1119+
display startup; runtime readiness does not imply desktop readiness. Set
1120+
`enable_recording=True` at creation to record a supported image's display and
1121+
retrieve the video through `client.sessions.get_video_recording_url(sandbox.id)`.
1122+
1123+
GPU cache lookup verifies the API's latest 100 completed builds. An older image
1124+
may be rebuilt when its GPU readiness cannot be verified from that window.
1125+
For live validation, set `HYPERBROWSER_API_KEY` and
1126+
`HYPERBROWSER_GPU_IMAGE_NAME` (an already published image containing `nvidia-smi`),
1127+
then run `pytest tests/sandbox/e2e/test_gpu.py`. Optional `HYPERBROWSER_GPU_TYPE`,
1128+
`HYPERBROWSER_GPU_COUNT`, and `HYPERBROWSER_GPU_PREEMPT=false` select the GPU
1129+
configuration; `HYPERBROWSER_GPU_DESKTOP=1` also checks screenshots. These tests
1130+
create billable sandboxes and stop them in cleanup.

0 commit comments

Comments
 (0)