mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-09-30 08:03:15 +00:00
fix(daytona): make sandbox snapshot configurable (#1220)
This commit is contained in:
parent
b829cef97a
commit
226e6c8263
3 changed files with 81 additions and 4 deletions
|
|
@ -49,7 +49,7 @@ Set the `SANDBOX_TYPE` environment variable to switch providers. Each provider h
|
||||||
| `SANDBOX_TYPE` | Integration file | Required env vars |
|
| `SANDBOX_TYPE` | Integration file | Required env vars |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `langsmith` (default) | `agent/integrations/langsmith.py` | `LANGSMITH_API_KEY_PROD`, `SANDBOX_TYPE="langsmith"` |
|
| `langsmith` (default) | `agent/integrations/langsmith.py` | `LANGSMITH_API_KEY_PROD`, `SANDBOX_TYPE="langsmith"` |
|
||||||
| `daytona` | `agent/integrations/daytona.py` | `DAYTONA_API_KEY`, `SANDBOX_TYPE="daytona"` |
|
| `daytona` | `agent/integrations/daytona.py` | `DAYTONA_API_KEY`, `SANDBOX_TYPE="daytona"`, optional `DAYTONA_SANDBOX_SNAPSHOT` |
|
||||||
| `runloop` | `agent/integrations/runloop.py` | `RUNLOOP_API_KEY`, `SANDBOX_TYPE="runloop"` |
|
| `runloop` | `agent/integrations/runloop.py` | `RUNLOOP_API_KEY`, `SANDBOX_TYPE="runloop"` |
|
||||||
| `modal` | `agent/integrations/modal.py` | Modal credentials, `SANDBOX_TYPE="modal"` |
|
| `modal` | `agent/integrations/modal.py` | Modal credentials, `SANDBOX_TYPE="modal"` |
|
||||||
| `local` | `agent/integrations/local.py` | None (no isolation — development only), `SANDBOX_TYPE="local"` |
|
| `local` | `agent/integrations/local.py` | None (no isolation — development only), `SANDBOX_TYPE="local"` |
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,15 @@ import os
|
||||||
from daytona import CreateSandboxFromSnapshotParams, Daytona, DaytonaConfig
|
from daytona import CreateSandboxFromSnapshotParams, Daytona, DaytonaConfig
|
||||||
from langchain_daytona import DaytonaSandbox
|
from langchain_daytona import DaytonaSandbox
|
||||||
|
|
||||||
# TODO: Update this to include your specific sandbox configuration
|
DEFAULT_DAYTONA_SANDBOX_SNAPSHOT = "daytonaio/sandbox:0.6.0"
|
||||||
DAYTONA_SANDBOX_PARAMS = CreateSandboxFromSnapshotParams(snapshot="daytonaio/sandbox:0.6.0")
|
DAYTONA_SANDBOX_SNAPSHOT_ENV = "DAYTONA_SANDBOX_SNAPSHOT"
|
||||||
|
|
||||||
|
|
||||||
|
def _get_daytona_sandbox_params() -> CreateSandboxFromSnapshotParams:
|
||||||
|
snapshot = os.getenv(DAYTONA_SANDBOX_SNAPSHOT_ENV, DEFAULT_DAYTONA_SANDBOX_SNAPSHOT).strip()
|
||||||
|
if not snapshot:
|
||||||
|
raise ValueError(f"{DAYTONA_SANDBOX_SNAPSHOT_ENV} must not be empty")
|
||||||
|
return CreateSandboxFromSnapshotParams(snapshot=snapshot)
|
||||||
|
|
||||||
|
|
||||||
def create_daytona_sandbox(sandbox_id: str | None = None):
|
def create_daytona_sandbox(sandbox_id: str | None = None):
|
||||||
|
|
@ -17,6 +24,6 @@ def create_daytona_sandbox(sandbox_id: str | None = None):
|
||||||
if sandbox_id:
|
if sandbox_id:
|
||||||
sandbox = daytona.get(sandbox_id)
|
sandbox = daytona.get(sandbox_id)
|
||||||
else:
|
else:
|
||||||
sandbox = daytona.create(params=DAYTONA_SANDBOX_PARAMS)
|
sandbox = daytona.create(params=_get_daytona_sandbox_params())
|
||||||
|
|
||||||
return DaytonaSandbox(sandbox=sandbox)
|
return DaytonaSandbox(sandbox=sandbox)
|
||||||
|
|
|
||||||
70
tests/test_daytona_integration.py
Normal file
70
tests/test_daytona_integration.py
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
import importlib.util
|
||||||
|
import sys
|
||||||
|
import types
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
|
||||||
|
|
||||||
|
class _FakeCreateSandboxFromSnapshotParams:
|
||||||
|
def __init__(self, *, snapshot: str):
|
||||||
|
self.snapshot = snapshot
|
||||||
|
|
||||||
|
|
||||||
|
class _FakeDaytonaConfig:
|
||||||
|
def __init__(self, *, api_key: str):
|
||||||
|
self.api_key = api_key
|
||||||
|
|
||||||
|
|
||||||
|
class _FakeDaytonaSandbox:
|
||||||
|
def __init__(self, *, sandbox):
|
||||||
|
self.sandbox = sandbox
|
||||||
|
|
||||||
|
|
||||||
|
def _load_daytona_module(monkeypatch):
|
||||||
|
fake_daytona = types.ModuleType("daytona")
|
||||||
|
fake_daytona.CreateSandboxFromSnapshotParams = _FakeCreateSandboxFromSnapshotParams
|
||||||
|
fake_daytona.DaytonaConfig = _FakeDaytonaConfig
|
||||||
|
fake_daytona.Daytona = object
|
||||||
|
|
||||||
|
fake_langchain_daytona = types.ModuleType("langchain_daytona")
|
||||||
|
fake_langchain_daytona.DaytonaSandbox = _FakeDaytonaSandbox
|
||||||
|
|
||||||
|
monkeypatch.setitem(sys.modules, "daytona", fake_daytona)
|
||||||
|
monkeypatch.setitem(sys.modules, "langchain_daytona", fake_langchain_daytona)
|
||||||
|
module_path = ROOT / "agent" / "integrations" / "daytona.py"
|
||||||
|
spec = importlib.util.spec_from_file_location("daytona_under_test", module_path)
|
||||||
|
assert spec is not None and spec.loader is not None
|
||||||
|
module = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(module)
|
||||||
|
return module
|
||||||
|
|
||||||
|
|
||||||
|
def test_daytona_params_default_to_existing_snapshot(monkeypatch):
|
||||||
|
monkeypatch.delenv("DAYTONA_SANDBOX_SNAPSHOT", raising=False)
|
||||||
|
module = _load_daytona_module(monkeypatch)
|
||||||
|
|
||||||
|
params = module._get_daytona_sandbox_params()
|
||||||
|
|
||||||
|
assert params.snapshot == "daytonaio/sandbox:0.6.0"
|
||||||
|
|
||||||
|
|
||||||
|
def test_daytona_params_use_env_snapshot(monkeypatch):
|
||||||
|
monkeypatch.setenv("DAYTONA_SANDBOX_SNAPSHOT", "custom/snapshot:1.0")
|
||||||
|
module = _load_daytona_module(monkeypatch)
|
||||||
|
|
||||||
|
params = module._get_daytona_sandbox_params()
|
||||||
|
|
||||||
|
assert params.snapshot == "custom/snapshot:1.0"
|
||||||
|
|
||||||
|
|
||||||
|
def test_daytona_params_reject_empty_snapshot(monkeypatch):
|
||||||
|
monkeypatch.setenv("DAYTONA_SANDBOX_SNAPSHOT", " ")
|
||||||
|
module = _load_daytona_module(monkeypatch)
|
||||||
|
|
||||||
|
try:
|
||||||
|
module._get_daytona_sandbox_params()
|
||||||
|
except ValueError as exc:
|
||||||
|
assert "DAYTONA_SANDBOX_SNAPSHOT must not be empty" in str(exc)
|
||||||
|
else:
|
||||||
|
raise AssertionError("expected empty Daytona snapshot to fail")
|
||||||
Loading…
Add table
Reference in a new issue