Skip to content

feat(sandbox): add E2B-compatible remote backend - #18

Open
Yunnglin wants to merge 2 commits into
mainfrom
feat/e2b-sandbox
Open

Yunnglin wants to merge 2 commits into
mainfrom
feat/e2b-sandbox

Conversation

@Yunnglin

@Yunnglin Yunnglin commented Nov 9, 2026 •

Copy link
Copy Markdown
Collaborator

What changes

Add an optional E2B-compatible remote backend so callers can run existing sandbox tools and upload directories without a local Docker daemon. It supports official E2B and Aliyun Agent Sandbox through the existing sandbox/manager factories and typed configuration models.

  • Keep SDK connections/retries, template resolution and remote sandbox execution in separate modules with clear ownership. Reuse the local manager registry, pool, tool execution and archive helpers.
  • Resolve existing templates or build deterministic image/resource aliases, share concurrent builds, handle eventual template visibility, and bound live sandboxes/builds.
  • Preserve command arguments, output and exit codes; kill timed-out commands; use fixed sandbox lifetimes and run metadata for cleanup. Credentials are redacted in diagnostics.
  • Add optional Docker cap_add forwarding, used by the SWE-bench harness. Allow explicit None CPU/memory limits so the companion grader can preserve the original unrestricted Docker behavior; existing Docker defaults remain 4 GiB / 2 CPUs.
  • Reject impossible resource pools before creating a remote sandbox, and default this manager's pools to E2B. Both issues were found during final review and have regression tests.

Install the optional SDK with pip install 'ms-enclave[e2b]' on Python 3.11+. The base package continues to support Python 3.10 without the E2B extra.

Validation

  • pytest tests/test_e2b_helpers.py tests/test_e2b_sandbox.py tests/test_tool.py -q -p no:warnings: 59 passed using Python 3.12 (eval312), including cached local Docker/notebook tool regressions. Backend tests use fakes and do not call paid services.
  • make lint: passed with all new files staged.
  • Review follow-up: 41 focused configuration/E2B/helper tests passed. Explicit unrestricted limits were also checked in a real cached Docker container (Memory=0, CpuQuota=0). CI lint passed on 20aace6b4cf564984a27ccb2cd710fc9c5f985a1.
  • Real official E2B and Aliyun checks completed during implementation: create/build/reuse, command/upload/timeout, gold and empty-patch grading across eight SWE-bench variants through EvalScope, native-agent small-sample runs, and metadata-filtered CLI cleanup. The eight-variant grading matrix used one instance per variant, not the full datasets. Direct pool initialization changes were subsequently verified with fake-SDK regressions.
  • Separate local Docker SYS_ADMIN verification passed. Large official benchmark Docker image comparisons were skipped by agreement because downloads were too slow; no official Docker scoring-parity claim is made.

Integration

EvalScope's companion PR #2036 uses this backend and supplies its bundled converted-image mapping. The E2B classes/configuration must be available in an ms-enclave release before the companion integration can use a normal PyPI installation. No release version has been guessed or published by this PR.

Normal shutdown attempts one kill per owned sandbox; a failed kill is logged and fixed provider lifetime remains a fallback. Removing a local handle does not prove provider cleanup succeeded; the real cleanup checks queried provider state and found no remaining resources from the validation runs.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Critical capacity-accounting and lifecycle bugs can block sandbox creation indefinitely, leak live sandboxes, and leave cancelled commands running when pooled sandboxes are reused.

5 open issues
What changed in this PR

Adds an optional E2B-compatible remote backend for official E2B and Aliyun Agent Sandbox, integrating with existing factories, managers, and tools without requiring a local Docker daemon.

Changes:

  • Adds typed configuration, SDK connection handling, template resolution, remote execution, and archive uploads.
  • Integrates remote sandbox management, concurrency limits, pools, and existing shell/Python tools.
  • Adds fake-provider regression tests, an optional SDK dependency, and Docker capability forwarding.
File Description
tests/​test_tool.py Updates expected Python tool backend compatibility.
tests/​test_e2b_sandbox.py Tests remote execution, lifecycle, pools, and SDK failures with fakes.
tests/​test_e2b_helpers.py Tests endpoint handling and deterministic template names.
pyproject.toml Adds the E2B extra and Hypothesis test dependency.
ms_enclave/​sandbox/​utils/​e2b_helpers.py Adds image, endpoint, naming, and redaction helpers.
ms_enclave/​sandbox/​tools/​sandbox_tools/​shell_executor.py Enables shell execution on E2B.
ms_enclave/​sandbox/​tools/​sandbox_tools/​python_executor.py Enables Python execution on E2B.
ms_enclave/​sandbox/​model/​config.py Adds E2B configuration models and Docker capabilities.
ms_enclave/​sandbox/​model/​base.py Adds E2B sandbox and manager types.
ms_enclave/​sandbox/​model/​__init__.py Exports E2B configuration models.
ms_enclave/​sandbox/​manager/​e2b_manager.py Adds remote lifecycle, capacity limits, and pool integration.
ms_enclave/​sandbox/​manager/​__init__.py Exports the E2B manager.
ms_enclave/​sandbox/​boxes/​e2b_template.py Resolves, builds, and caches remote templates.
ms_enclave/​sandbox/​boxes/​e2b_sandbox.py Implements remote commands, uploads, and lifecycle operations.
ms_enclave/​sandbox/​boxes/​e2b_connection.py Isolates optional SDK imports, connection settings, and retries.
ms_enclave/​sandbox/​boxes/​docker_sandbox.py Forwards configured additional Linux capabilities.
ms_enclave/​sandbox/​boxes/​base.py Adds typed E2B configuration handling to the factory.
ms_enclave/​sandbox/​boxes/​__init__.py Exports and registers the E2B sandbox.

Review effort: Balanced

Comment on lines +176 to +177
except Exception as exc:
return self._result(command, ExecutionStatus.ERROR, -1, '', self._conn.redact(str(exc)), started)
Comment on lines +70 to +71
await self._templates.resolve(cfg, run_id=self.run_id)
await self._slots.acquire()
except BaseException:
self._slots.release()
raise
self._sandboxes[sandbox.id] = sandbox
await sandbox.stop()
finally:
self._sandbox_locks.pop(sandbox_id, None)
self._slots.release()
Comment on lines +100 to +103
size = pool_size or self.config.pool_size
if size > self.config.max_sandboxes:
raise ValueError(f'pool_size={size} exceeds E2B max_sandboxes={self.config.max_sandboxes}')
return await super().initialize_pool(pool_size, sandbox_type or SandboxType.E2B, config)
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.

2 participants