Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions agent/tools/sandbox_client.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# /// script
# requires-python = ">=3.10"
# dependencies = ["huggingface_hub>=0.20.0", "httpx>=0.27.0"]
# dependencies = ["huggingface_hub>=1.12.0", "httpx>=0.27.0"]
# ///
"""
Sandbox Tools — Agent-native primitives for HF Space dev-mode sandboxes.
Expand Down Expand Up @@ -615,18 +615,19 @@ def _check_cancel():
kwargs = {
"from_id": template,
"to_id": space_id,
"repo_type": "space",
"private": private,
"hardware": hardware,
"space_hardware": hardware,
}
if sleep_time is not None:
kwargs["sleep_time"] = sleep_time
kwargs["space_sleep_time"] = sleep_time

api.duplicate_space(**kwargs)
api.duplicate_repo(**kwargs)
_log(f"Space created: https://huggingface.co/spaces/{space_id}")

_check_cancel()

# ``duplicate_space`` sends hardware and sleepTimeSeconds in the
# ``duplicate_repo`` sends hardware and sleepTimeSeconds in the
# initial create request. Avoid a second /hardware call: deployed HF
# OAuth tokens can 401 on that endpoint for a just-created private
# Space even though duplication itself succeeded. We rely on the
Expand Down
109 changes: 97 additions & 12 deletions tests/unit/test_sandbox_private_spaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,28 @@ def _fail_metadata_update(*args, **kwargs):
raise AssertionError("sandbox creation should not update Space metadata")


def _capture_duplicate_repo_call(
captured,
*,
from_id,
to_id,
repo_type,
private,
space_hardware,
space_sleep_time=None,
):
captured.update(
{
"from_id": from_id,
"to_id": to_id,
"repo_type": repo_type,
"private": private,
"space_hardware": space_hardware,
"space_sleep_time": space_sleep_time,
}
)


def test_sandbox_client_defaults_to_private_spaces(monkeypatch):
duplicate_kwargs = {}
logs: list[str] = []
Expand All @@ -22,8 +44,25 @@ class FakeApi:
def __init__(self, token=None):
self.token = token

def duplicate_space(self, **kwargs):
duplicate_kwargs.update(kwargs)
def duplicate_repo(
self,
*,
from_id,
to_id,
repo_type,
private,
space_hardware,
space_sleep_time=None,
):
_capture_duplicate_repo_call(
duplicate_kwargs,
from_id=from_id,
to_id=to_id,
repo_type=repo_type,
private=private,
space_hardware=space_hardware,
space_sleep_time=space_sleep_time,
)

def request_space_hardware(self, space_id, hardware, sleep_time=None):
requested_hardware.append((space_id, hardware, sleep_time))
Expand All @@ -45,8 +84,9 @@ def get_space_runtime(self, space_id):

Sandbox.create(owner="alice", token="hf-token", log=logs.append)

assert duplicate_kwargs["repo_type"] == "space"
assert duplicate_kwargs["private"] is True
assert duplicate_kwargs["hardware"] == "cpu-basic"
assert duplicate_kwargs["space_hardware"] == "cpu-basic"
assert requested_hardware == []
assert not any("sleep time" in log for log in logs)

Expand All @@ -67,7 +107,16 @@ class FakeApi:
def __init__(self, token=None):
self.token = token

def duplicate_space(self, **kwargs):
def duplicate_repo(
self,
*,
from_id,
to_id,
repo_type,
private,
space_hardware,
space_sleep_time=None,
):
pass

def request_space_hardware(self, space_id, hardware, sleep_time=None):
Expand Down Expand Up @@ -107,8 +156,25 @@ class FakeApi:
def __init__(self, token=None):
self.token = token

def duplicate_space(self, **kwargs):
duplicate_kwargs.update(kwargs)
def duplicate_repo(
self,
*,
from_id,
to_id,
repo_type,
private,
space_hardware,
space_sleep_time=None,
):
_capture_duplicate_repo_call(
duplicate_kwargs,
from_id=from_id,
to_id=to_id,
repo_type=repo_type,
private=private,
space_hardware=space_hardware,
space_sleep_time=space_sleep_time,
)

def request_space_hardware(self, space_id, hardware, sleep_time=None):
requested_hardware.append((space_id, hardware, sleep_time))
Expand Down Expand Up @@ -137,8 +203,9 @@ def get_space_runtime(self, space_id):
)

assert sandbox.space_id.startswith("alice/sandbox-")
assert duplicate_kwargs["hardware"] == "t4-small"
assert duplicate_kwargs["sleep_time"] == 2700
assert duplicate_kwargs["repo_type"] == "space"
assert duplicate_kwargs["space_hardware"] == "t4-small"
assert duplicate_kwargs["space_sleep_time"] == 2700
assert requested_hardware == []
assert "Using duplicated Space hardware: t4-small" in logs
assert "Using duplicated Space sleep time: 2700s" in logs
Expand All @@ -153,8 +220,25 @@ class FakeApi:
def __init__(self, token=None):
self.token = token

def duplicate_space(self, **kwargs):
duplicate_kwargs.update(kwargs)
def duplicate_repo(
self,
*,
from_id,
to_id,
repo_type,
private,
space_hardware,
space_sleep_time=None,
):
_capture_duplicate_repo_call(
duplicate_kwargs,
from_id=from_id,
to_id=to_id,
repo_type=repo_type,
private=private,
space_hardware=space_hardware,
space_sleep_time=space_sleep_time,
)

def request_space_hardware(self, space_id, hardware, sleep_time=None):
requested_hardware.append((space_id, hardware, sleep_time))
Expand All @@ -180,8 +264,9 @@ def get_space_runtime(self, space_id):
log=logs.append,
)

assert duplicate_kwargs["hardware"] == "cpu-basic"
assert duplicate_kwargs["sleep_time"] == 2700
assert duplicate_kwargs["repo_type"] == "space"
assert duplicate_kwargs["space_hardware"] == "cpu-basic"
assert duplicate_kwargs["space_sleep_time"] == 2700
assert requested_hardware == []
assert "Using duplicated Space hardware: cpu-basic" in logs
assert (
Expand Down
Loading