From 54c89faadc85c88712e3f5717be18cf6dc6b6a6f Mon Sep 17 00:00:00 2001 From: Lewis Tunstall Date: Fri, 8 May 2026 14:11:12 +0200 Subject: [PATCH 1/2] Use duplicate_repo for sandbox Spaces Co-authored-by: OpenAI Codex --- agent/tools/sandbox_client.py | 11 ++++++----- tests/unit/test_sandbox_private_spaces.py | 21 ++++++++++++--------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/agent/tools/sandbox_client.py b/agent/tools/sandbox_client.py index 1871d8fc..d1644fc9 100644 --- a/agent/tools/sandbox_client.py +++ b/agent/tools/sandbox_client.py @@ -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. @@ -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 diff --git a/tests/unit/test_sandbox_private_spaces.py b/tests/unit/test_sandbox_private_spaces.py index 31332ee3..4c9cd00a 100644 --- a/tests/unit/test_sandbox_private_spaces.py +++ b/tests/unit/test_sandbox_private_spaces.py @@ -22,7 +22,7 @@ class FakeApi: def __init__(self, token=None): self.token = token - def duplicate_space(self, **kwargs): + def duplicate_repo(self, **kwargs): duplicate_kwargs.update(kwargs) def request_space_hardware(self, space_id, hardware, sleep_time=None): @@ -45,8 +45,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) @@ -67,7 +68,7 @@ class FakeApi: def __init__(self, token=None): self.token = token - def duplicate_space(self, **kwargs): + def duplicate_repo(self, **kwargs): pass def request_space_hardware(self, space_id, hardware, sleep_time=None): @@ -107,7 +108,7 @@ class FakeApi: def __init__(self, token=None): self.token = token - def duplicate_space(self, **kwargs): + def duplicate_repo(self, **kwargs): duplicate_kwargs.update(kwargs) def request_space_hardware(self, space_id, hardware, sleep_time=None): @@ -137,8 +138,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 @@ -153,7 +155,7 @@ class FakeApi: def __init__(self, token=None): self.token = token - def duplicate_space(self, **kwargs): + def duplicate_repo(self, **kwargs): duplicate_kwargs.update(kwargs) def request_space_hardware(self, space_id, hardware, sleep_time=None): @@ -180,8 +182,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 ( From c6e6942ce018243d0201a69f3ec62c6ce68af532 Mon Sep 17 00:00:00 2001 From: Lewis Tunstall Date: Fri, 8 May 2026 14:19:11 +0200 Subject: [PATCH 2/2] Tighten duplicate_repo sandbox fakes Co-authored-by: OpenAI Codex --- tests/unit/test_sandbox_private_spaces.py | 96 +++++++++++++++++++++-- 1 file changed, 89 insertions(+), 7 deletions(-) diff --git a/tests/unit/test_sandbox_private_spaces.py b/tests/unit/test_sandbox_private_spaces.py index 4c9cd00a..b05b0ab2 100644 --- a/tests/unit/test_sandbox_private_spaces.py +++ b/tests/unit/test_sandbox_private_spaces.py @@ -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] = [] @@ -22,8 +44,25 @@ class FakeApi: def __init__(self, token=None): self.token = token - def duplicate_repo(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)) @@ -68,7 +107,16 @@ class FakeApi: def __init__(self, token=None): self.token = token - def duplicate_repo(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): @@ -108,8 +156,25 @@ class FakeApi: def __init__(self, token=None): self.token = token - def duplicate_repo(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)) @@ -155,8 +220,25 @@ class FakeApi: def __init__(self, token=None): self.token = token - def duplicate_repo(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))