Skip to content

rename sandbox fields#16

Merged
steven-passynkov merged 1 commit into
mainfrom
rename-sandbox-timeout-fields
Apr 14, 2026
Merged

rename sandbox fields#16
steven-passynkov merged 1 commit into
mainfrom
rename-sandbox-timeout-fields

Conversation

@steven-passynkov

@steven-passynkov steven-passynkov commented Apr 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • rename sandbox and snapshot payload fields from memory_mib/disk_mib and timeout_min to memory/disk and second-based timeout
  • update shared config defaults, sync and async clients, and response models to match the new API contract
  • refresh the affected tests to cover the renamed request and response fields

Summary by CodeRabbit

  • API Updates
    • Renamed sandbox and snapshot resource parameters for clarity: memory_mibmemory, disk_mibdisk
    • Renamed timeout parameters: timeout_mintimeout (now expressed in seconds rather than minutes)
    • Updated timeout default constant with adjusted value semantics

@coderabbitai

coderabbitai Bot commented Apr 14, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR systematically renames resource configuration and API field names across the codebase: DEFAULT_TIMEOUT_MIN becomes DEFAULT_TIMEOUT, with parameter/field names changing from memory_mib to memory, disk_mib to disk, and timeout_min to timeout. The timeout semantic unit shifts from minutes to seconds, and all models, schemas, clients, and tests are updated accordingly.

Changes

Cohort / File(s) Summary
Client default timeout constants
leap0/_async/client.py, leap0/_sync/client.py
Replaced exported DEFAULT_TIMEOUT_MIN with DEFAULT_TIMEOUT in both sync and async client classes.
Sandbox API clients
leap0/_async/sandbox.py, leap0/_sync/sandbox.py
Updated create() method signatures: renamed memory_mibmemory and timeout_mintimeout parameters; updated imports to use new timeout constant.
Snapshots API clients
leap0/_async/snapshots.py, leap0/_sync/snapshots.py
Renamed resume() timeout parameter from timeout_min: int | None to timeout: int | None with updated docstring unit description.
Response schemas
leap0/_schemas/sandbox.py, leap0/_schemas/snapshot.py
Updated TypedDict field names: memory_mibmemory, disk_mibdisk; added timeout: int field to sandbox response schemas.
Configuration and model constants
leap0/models/config.py
Changed default timeout constant from DEFAULT_TIMEOUT_MIN = 5 to DEFAULT_TIMEOUT = 300.
Sandbox models
leap0/models/sandbox.py
Renamed dataclass fields: memory_mibmemory, disk_mibdisk in CreateSandboxParams, Sandbox, and SandboxStatus; updated timeout validation bounds from 480 (minutes) to 28800 (seconds); adjusted from_dict() parsing to read new field names.
Snapshot models
leap0/models/snapshot.py
Renamed ResumeSnapshotParams timeout field from timeout_mintimeout; updated Snapshot dataclass fields memory_mibmemory, disk_mibdisk; changed timeout validation range to 1..28800; updated from_dict() field mapping.
Async sandbox tests
tests/_async/test_sandboxes.py, tests/_async/test_snapshots.py
Updated mocked API response payloads and create() calls to use memory, disk, and timeout fields instead of memory_mib/disk_mib.
Sync sandbox tests
tests/_sync/test_sandboxes.py, tests/_sync/test_snapshots.py
Updated test fixtures and client invocations to use new field names; adjusted error message assertions to match "memory" instead of "memory_mib".
Model unit tests
tests/models/test_sandbox.py, tests/models/test_snapshot.py
Updated fixture input dictionaries to use memory, disk, and timeout instead of memory_mib/disk_mib when constructing Sandbox, SandboxStatus, and Snapshot objects.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • refactor async #7: Directly related through the same AsyncLeap0Client.DEFAULT_TIMEOUT_MINDEFAULT_TIMEOUT constant refactoring applied in this PR.

Poem

🐰 The fields are renamed, the constants reshaped,
From memory_mib to memory escaped,
The timeout now counts in seconds so true,
A million small changes, yet patterns so few! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.92% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'rename sandbox fields' directly summarizes the primary change: renaming multiple sandbox/snapshot payload fields across clients, models, and tests.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rename-sandbox-timeout-fields

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
leap0/_async/sandbox.py (1)

229-268: Consider aligning async create() telemetry flags with sync API parity.

SandboxesClient.create (sync) supports both otel_export and legacy telemetry, while async currently accepts only otel_export. Keeping parity reduces migration friction and surprises across clients.

Parity-oriented refactor (optional)
     async def create(
         self,
         *,
         template_name: str = DEFAULT_TEMPLATE_NAME,
         vcpu: int = DEFAULT_VCPU,
         memory: int = DEFAULT_MEMORY_MIB,
         timeout: int = DEFAULT_TIMEOUT,
         auto_pause: bool = False,
-        otel_export: bool = False,
+        otel_export: bool | None = None,
+        telemetry: bool | None = None,
         env_vars: dict[str, str] | None = None,
         network_policy: NetworkPolicyDict | None = None,
         http_timeout: float | None = None,
     ) -> AsyncSandboxT | SandboxData | SandboxStatus:
@@
-        params = CreateSandboxParams(
+        effective_otel_export = otel_export if otel_export is not None else bool(telemetry)
+        params = CreateSandboxParams(
             template_name=template_name,
             vcpu=vcpu,
             memory=memory,
             timeout=timeout,
             auto_pause=auto_pause,
-            otel_export=otel_export,
-            env_vars=_inject_otel_env(env_vars) if otel_export else env_vars,
+            otel_export=effective_otel_export,
+            env_vars=_inject_otel_env(env_vars) if effective_otel_export else env_vars,
             network_policy=network_policy,
         )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@leap0/_async/sandbox.py` around lines 229 - 268, The async create() method
lacks the legacy telemetry flag present in the sync SandboxesClient.create,
causing API parity issues; add an optional telemetry: bool | None parameter to
the async method signature, thread it through to CreateSandboxParams (alongside
otel_export) and ensure _inject_otel_env is invoked when either telemetry or
otel_export indicates telemetry should be enabled, keeping behavior consistent
with the sync implementation and preserving the otel_export-specific env
handling.
tests/_async/test_sandboxes.py (1)

19-23: Strengthen create-request assertions for renamed fields.

This test now exercises the new API shape, but it only asserts template_name. Please also assert the outbound payload uses memory/timeout and does not include legacy keys, so future regressions are caught early.

Proposed test assertion update
-            result = await AsyncSandboxesClient(async_mock_transport, sandbox_domain="s.dev").create(template_name="my-tpl", vcpu=2, memory=2048)
+            result = await AsyncSandboxesClient(async_mock_transport, sandbox_domain="s.dev").create(
+                template_name="my-tpl",
+                vcpu=2,
+                memory=2048,
+                timeout=300,
+            )
             args, kwargs = async_mock_transport.request_json.call_args
             assert args == ("POST", "/v1/sandbox")
             assert kwargs["json"]["template_name"] == "my-tpl"
+            assert kwargs["json"]["memory"] == 2048
+            assert kwargs["json"]["timeout"] == 300
+            assert "memory_mib" not in kwargs["json"]
+            assert "timeout_min" not in kwargs["json"]
             assert result.id == "sbx-1"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/_async/test_sandboxes.py` around lines 19 - 23, The test should also
assert the full outbound JSON payload uses the new field names and omits legacy
keys: after calling AsyncSandboxesClient(...).create(...), inspect
async_mock_transport.request_json.call_args and assert kwargs["json"]["vcpu"] ==
2 and kwargs["json"]["memory"] == 2048, assert there is a "timeout" key present
(use the default or configured value expected by create), and assert that legacy
keys such as "size" and "template" are not present in kwargs["json"] so
regressions are caught early.
tests/_sync/test_sandboxes.py (1)

18-22: Add explicit assertions for renamed request keys in sync create test.

Line 18 now exercises the renamed params, but the assertion block doesn’t verify emitted key names. Assert memory/timeout presence and legacy-key absence to lock this contract.

Proposed assertion hardening
-        result = SandboxesClient(mock_transport, sandbox_domain="s.dev").create(template_name="my-tpl", vcpu=2, memory=2048)
+        result = SandboxesClient(mock_transport, sandbox_domain="s.dev").create(
+            template_name="my-tpl",
+            vcpu=2,
+            memory=2048,
+            timeout=300,
+        )
         args, kwargs = mock_transport.request_json.call_args
         assert args == ("POST", "/v1/sandbox")
         assert kwargs["json"]["template_name"] == "my-tpl"
+        assert kwargs["json"]["memory"] == 2048
+        assert kwargs["json"]["timeout"] == 300
+        assert "memory_mib" not in kwargs["json"]
+        assert "timeout_min" not in kwargs["json"]
         assert result.id == "sbx-1"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/_sync/test_sandboxes.py` around lines 18 - 22, The test for
SandboxesClient.create is missing assertions that verify the renamed request
keys and the removal of legacy keys; after calling
SandboxesClient(...).create(...) inspect mock_transport.request_json.call_args
and add assertions that kwargs["json"] contains "memory" and "timeout" keys and
that the legacy keys (e.g., "memory_mb" and "timeout_seconds") are not present,
referencing the call via mock_transport.request_json.call_args and the
SandboxesClient.create invocation to locate the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@leap0/models/sandbox.py`:
- Around line 194-196: The code is silently defaulting missing/renamed sandbox
fields to 0 (memory/disk/timeout), so add a strict helper like
_require_int(data, key, legacy_key=None) that first checks data[key], falls back
to legacy_key if provided, raises ValueError if neither is present, and converts
to int catching TypeError/ValueError to raise a clear error; replace the three
int(data.get(...,0)) calls for "memory", "disk", and "timeout" with calls to
_require_int (passing legacy keys if the API had previous names) and apply the
same replacement to the similar parsing at the other occurrence noted (the block
at the other three fields around lines 227-229).

---

Nitpick comments:
In `@leap0/_async/sandbox.py`:
- Around line 229-268: The async create() method lacks the legacy telemetry flag
present in the sync SandboxesClient.create, causing API parity issues; add an
optional telemetry: bool | None parameter to the async method signature, thread
it through to CreateSandboxParams (alongside otel_export) and ensure
_inject_otel_env is invoked when either telemetry or otel_export indicates
telemetry should be enabled, keeping behavior consistent with the sync
implementation and preserving the otel_export-specific env handling.

In `@tests/_async/test_sandboxes.py`:
- Around line 19-23: The test should also assert the full outbound JSON payload
uses the new field names and omits legacy keys: after calling
AsyncSandboxesClient(...).create(...), inspect
async_mock_transport.request_json.call_args and assert kwargs["json"]["vcpu"] ==
2 and kwargs["json"]["memory"] == 2048, assert there is a "timeout" key present
(use the default or configured value expected by create), and assert that legacy
keys such as "size" and "template" are not present in kwargs["json"] so
regressions are caught early.

In `@tests/_sync/test_sandboxes.py`:
- Around line 18-22: The test for SandboxesClient.create is missing assertions
that verify the renamed request keys and the removal of legacy keys; after
calling SandboxesClient(...).create(...) inspect
mock_transport.request_json.call_args and add assertions that kwargs["json"]
contains "memory" and "timeout" keys and that the legacy keys (e.g., "memory_mb"
and "timeout_seconds") are not present, referencing the call via
mock_transport.request_json.call_args and the SandboxesClient.create invocation
to locate the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 74f68575-3401-4bd1-ad27-e366bd82c949

📥 Commits

Reviewing files that changed from the base of the PR and between 38551da and 9a0e4ef.

📒 Files selected for processing (17)
  • leap0/_async/client.py
  • leap0/_async/sandbox.py
  • leap0/_async/snapshots.py
  • leap0/_schemas/sandbox.py
  • leap0/_schemas/snapshot.py
  • leap0/_sync/client.py
  • leap0/_sync/sandbox.py
  • leap0/_sync/snapshots.py
  • leap0/models/config.py
  • leap0/models/sandbox.py
  • leap0/models/snapshot.py
  • tests/_async/test_sandboxes.py
  • tests/_async/test_snapshots.py
  • tests/_sync/test_sandboxes.py
  • tests/_sync/test_snapshots.py
  • tests/models/test_sandbox.py
  • tests/models/test_snapshot.py

Comment thread leap0/models/sandbox.py
Comment on lines +113 to +114
memory: int = DEFAULT_MEMORY_MIB
timeout: int = DEFAULT_TIMEOUT

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Consider a short compatibility window for the renamed public fields.

These names changed on public request/response models in-place, so downstream code still using memory_mib, disk_mib, or timeout_min will break on upgrade. If this is not meant to be a hard breaking release, keep deprecated aliases/properties for one cycle and serialize only the new wire names.

Also applies to: 175-177, 209-211

Comment thread leap0/models/sandbox.py
Comment on lines +194 to +196
memory=int(data.get("memory", 0)),
disk=int(data.get("disk", 0)),
timeout=int(data.get("timeout", 0)),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don't silently turn missing renamed fields into 0.

If the backend omits one of these keys—or still returns the legacy names during rollout—both parsers manufacture 0 values instead of surfacing the contract mismatch. That makes a mixed-version response look valid and can leak bogus resource limits to callers. Prefer failing fast here, or temporarily falling back to the legacy keys while the API rolls out.

💡 Minimal hard-fail / fallback shape
-            memory=int(data.get("memory", 0)),
-            disk=int(data.get("disk", 0)),
-            timeout=int(data.get("timeout", 0)),
+            memory=_require_int(data, "memory", legacy_key="memory_mib"),
+            disk=_require_int(data, "disk", legacy_key="disk_mib"),
+            timeout=_require_int(data, "timeout", legacy_key="timeout_min"),
def _require_int(data: Mapping[str, object], key: str, *, legacy_key: str | None = None) -> int:
    value = data.get(key)
    if value is None and legacy_key is not None:
        value = data.get(legacy_key)
    if value is None:
        raise ValueError(f"sandbox response missing required field {key!r}")
    try:
        return int(value)
    except (TypeError, ValueError) as err:
        raise ValueError(f"sandbox response has invalid {key!r}: {value!r}") from err

Also applies to: 227-229

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@leap0/models/sandbox.py` around lines 194 - 196, The code is silently
defaulting missing/renamed sandbox fields to 0 (memory/disk/timeout), so add a
strict helper like _require_int(data, key, legacy_key=None) that first checks
data[key], falls back to legacy_key if provided, raises ValueError if neither is
present, and converts to int catching TypeError/ValueError to raise a clear
error; replace the three int(data.get(...,0)) calls for "memory", "disk", and
"timeout" with calls to _require_int (passing legacy keys if the API had
previous names) and apply the same replacement to the similar parsing at the
other occurrence noted (the block at the other three fields around lines
227-229).

@steven-passynkov steven-passynkov merged commit 04dda87 into main Apr 14, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant