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: 8 additions & 3 deletions nemo_gym/sandbox/providers/opensandbox/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,12 @@ async def serialize_handle(self, handle: SandboxHandle, *, scope: str | None = N
return {"sandbox_id": handle.sandbox_id}

async def connect(self, descriptor: Mapping[str, Any]) -> SandboxHandle:
"""Rebuild a live handle from an OpenSandbox sandbox id via the SDK."""
"""Rebuild a live handle from an OpenSandbox sandbox id via the SDK.

Health-checks unless the caller opts out: a sandbox id only proves the
workload exists, not that its exec daemon is listening yet, so an
unchecked handle turns that gap into a 502 on the first call.
"""
Sandbox, _, _, _, _ = _require_opensandbox_sdk()
sandbox_id = str(descriptor["sandbox_id"])
timeout_s = self._create.connect_attempt_timeout_s
Expand All @@ -669,7 +674,7 @@ async def connect(self, descriptor: Mapping[str, Any]) -> SandboxHandle:
sandbox_id,
connection_config=self._connection_config(request_timeout_s=timeout_s),
connect_timeout=timedelta(seconds=timeout_s),
skip_health_check=True,
skip_health_check=self._create.skip_health_check,
),
timeout=timeout_s,
)
Expand Down Expand Up @@ -838,7 +843,7 @@ async def _connect_after_create(self, handle: SandboxHandle, spec: SandboxSpec)
handle.sandbox_id,
connection_config=self._connection_config(),
connect_timeout=timedelta(seconds=attempt_timeout_s),
skip_health_check=True,
skip_health_check=self._create.skip_health_check,
),
timeout=attempt_timeout_s,
)
Expand Down
6 changes: 4 additions & 2 deletions resources_servers/litmus_agent/configs/litmus_agent.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ litmus_agent:
use_server_proxy: true
create:
request_timeout_s: 1200
timeout_s: 1200
skip_health_check: true
# Must exceed ready_timeout_s below: this bounds the whole create
# call, which includes the readiness wait.
timeout_s: 1500
skip_health_check: false
retries: 10
retry_delay_s: 5.0
retry_max_delay_s: 90.0
Expand Down
6 changes: 4 additions & 2 deletions responses_api_agents/mini_swe_agent_2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,10 @@ sandbox: # name referenced by the agent's sandbox_provider
use_server_proxy: true
create:
request_timeout_s: 1200
timeout_s: 1200
skip_health_check: true
# Must exceed ready_timeout_s above: this bounds the whole create call,
# which includes the readiness wait.
timeout_s: 1500
skip_health_check: false
retries: 10
retry_delay_s: 5.0
retry_max_delay_s: 90.0
Expand Down
21 changes: 21 additions & 0 deletions tests/unit_tests/test_opensandbox_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -1000,3 +1000,24 @@ async def test_create_attribution_run_id_generated(
def test_attribution_invalid_key_prefix_raises(key_prefix: str) -> None:
with pytest.raises(ValueError, match="key_prefix"):
opensandbox_provider.OpenSandboxAttributionConfig(key_prefix=key_prefix)


async def test_connect_health_checks_by_default(fake_opensandbox_sdk: None) -> None:
"""An unchecked handle would defer the exec-daemon startup gap to the first call."""
provider = opensandbox_provider.OpenSandboxProvider(probe={"command": None})

await provider.connect({"sandbox_id": "sandbox-9"})

assert FakeSandbox.connected_kwargs["skip_health_check"] is False


async def test_connect_honours_skip_health_check_opt_out(fake_opensandbox_sdk: None) -> None:
"""Callers that explicitly opt out still get an unchecked handle."""
provider = opensandbox_provider.OpenSandboxProvider(
create={"skip_health_check": True},
probe={"command": None},
)

await provider.connect({"sandbox_id": "sandbox-9"})

assert FakeSandbox.connected_kwargs["skip_health_check"] is True
6 changes: 4 additions & 2 deletions tests/unit_tests/test_sandbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,8 @@ async def connect(cls, sandbox_id: str, **kwargs: Any) -> "FakeSDKSandbox":
assert handle.sandbox_id == "sdk-sandbox-1"
assert isinstance(handle.raw, FakeSDKSandbox)
connect_call = FakeSDKSandbox.connect_calls[0]
assert connect_call["skip_health_check"] is True
# This provider does not opt out, so the reconnect health-checks too.
assert connect_call["skip_health_check"] is False
connection_kwargs = dict(connect_call["connection_config"].kwargs)
# Transport identity is asserted in test_opensandbox_provider.py.
connection_kwargs.pop("transport", None)
Expand Down Expand Up @@ -1329,5 +1330,6 @@ async def connect(cls, sandbox_id: str, **kwargs: Any) -> "FakeSDKSandbox":
assert isinstance(handle.raw, FakeSDKSandbox)
connect_call = FakeSDKSandbox.connect_calls[0]
assert connect_call["sandbox_id"] == "sdk-sandbox-9"
assert connect_call["skip_health_check"] is True
# connect() health-checks by default so the handle it returns is usable.
assert connect_call["skip_health_check"] is False
assert connect_call["connection_config"].kwargs["domain"] == "sandbox.example"
Loading