Skip to content

feat: more providers - #21

Merged
echarles merged 2 commits into
mainfrom
feat/code-sandboxes/more
Aug 21, 2026
Merged

feat: more providers#21
echarles merged 2 commits into
mainfrom
feat/code-sandboxes/more

Conversation

@echarles

Copy link
Copy Markdown
Member

No description provided.

Copilot AI lite review requested due to automatic review settings August 21, 2026 17:12

Copilot AI 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.

Pull request overview

Adds E2B, CoreWeave, and Cloudflare sandbox providers across the API, CLI, management tooling, packaging, tests, examples, and documentation.

Changes:

  • Adds three provider implementations and registrations.
  • Adds managers, CLI support, optional dependencies, and tests.
  • Updates examples, documentation, and release notes.

Reviewed changes

Copilot reviewed 46 out of 46 changed files in this pull request and generated 6 comments.

Show a summary per file
File Summary
tests/test_manage.py Managed provider registration coverage.
tests/test_e2b.py E2B execution and integration tests.
tests/test_coreweave.py CoreWeave driver and fallback tests.
tests/test_cloudflare.py Cloudflare bridge protocol tests.
README.md Lists new providers.
pyproject.toml Adds optional dependencies and lint configuration.
examples/repl/Makefile Adds REPL targets.
examples/repl/e2b_sandbox_example.py E2B REPL example.
examples/repl/coreweave_sandbox_example.py CoreWeave REPL example.
examples/repl/cloudflare_sandbox_example.py Cloudflare REPL example.
examples/README.md Documents example setup and requirements.
examples/exec/Makefile Adds executable targets.
examples/exec/e2b_sandbox_example.py E2B execution example.
examples/exec/coreweave_sandbox_example.py CoreWeave execution example.
examples/exec/cloudflare_sandbox_example.py Cloudflare execution example.
docs/docs/sandboxes/monty.mdx Updates sidebar ordering.
docs/docs/sandboxes/modal.mdx Documents Modal state persistence.
docs/docs/sandboxes/kaggle.mdx Updates sidebar ordering.
docs/docs/sandboxes/jupyter-server.mdx Updates sidebar ordering.
docs/docs/sandboxes/index.mdx Documents variants and persistence.
docs/docs/sandboxes/google-colab.mdx Updates sidebar ordering.
docs/docs/sandboxes/eval.mdx Updates sidebar ordering.
docs/docs/sandboxes/e2b.mdx Adds E2B documentation.
docs/docs/sandboxes/docker.mdx Updates sidebar ordering.
docs/docs/sandboxes/daytona.mdx Updates sidebar ordering.
docs/docs/sandboxes/datalayer.mdx Updates sidebar ordering.
docs/docs/sandboxes/coreweave.mdx Adds CoreWeave documentation.
docs/docs/sandboxes/cloudflare.mdx Adds Cloudflare documentation.
docs/docs/installation/index.mdx Documents extras and credentials.
docs/docs/index.mdx Updates the provider overview.
docs/docs/examples/index.mdx Adds example links.
docs/docs/comparison/index.mdx Updates provider comparison.
docs/docs/cli/management.mdx Documents provider management.
docs/docs/cli/index.mdx Documents CLI support for new variants.
docs/docs/api-reference/index.mdx Updates factory API documentation.
code_sandboxes/providers.py Registers provider metadata and requirements.
code_sandboxes/models.py Adds provider variants.
code_sandboxes/modal_sandbox.py Updates Modal behavior documentation.
code_sandboxes/manage.py Adds provider managers.
code_sandboxes/e2b_sandbox.py Implements the E2B adapter.
code_sandboxes/coreweave_sandbox.py Implements CoreWeave execution and fallback; variable APIs can falsely succeed without a driver, and timed-out executions continue running.
code_sandboxes/cloudflare_sandbox.py Implements the Cloudflare bridge; configured environment variables and network policies are not applied, variable reads fail across fresh processes, and requests send a redacted placeholder instead of the API key.
code_sandboxes/cli.py Registers variants and validates GPU options.
code_sandboxes/base.py Updates factory and environment registration.
code_sandboxes/__init__.py Exports new sandbox classes.
CHANGELOG.md Records provider additions and behavior updates.
Suppressed comments (17)

code_sandboxes/cloudflare_sandbox.py:231

  • SandboxConfig.max_lifetime is a common sandbox setting and is forwarded by the E2B and CoreWeave implementations, but this create call sends no lifetime and there is no local enforcement. For example, max_lifetime=60 can produce a Cloudflare sandbox that remains alive beyond the requested bound. If the bridge cannot configure lifetime, reject non-default values rather than silently ignoring them.
        response = self._client.post("/v1/sandbox")

code_sandboxes/cloudflare_sandbox.py:104

  • This BaseException handler also catches SystemExit, so code such as sys.exit(2) is serialized as a code_error and the runner process exits with status 0. The resulting ExecutionResult cannot expose the non-zero exit code promised by the shared model; handle SystemExit separately and carry its numeric code through the reply/result.
except BaseException as error:
    reply["status"] = "error"
    reply["error"] = {

code_sandboxes/cloudflare_sandbox.py:611

  • When envs is supplied, this prepended import makes valid snippets beginning with from __future__ import ... fail with “future feature ... is not defined” because future imports must be first. Inject the environment after the future-import block or execute the original snippet as a separately compiled unit.
    return f"import os as _code_sandboxes_os\n{assignments}del _code_sandboxes_os\n{code}"

code_sandboxes/coreweave_sandbox.py:522

  • When the session driver disappears, _driver_request returns None and this path silently switches to stateless execution, but sandbox.info.metadata["stateful"] remains True. Callers following the documented capability check will keep assuming definitions persist after they have already been lost; update the metadata when the fallback is selected.
            reply = self._driver_request(prepared, seconds)
            if reply is None:
                reply = self._stateless_request(prepared, seconds)

code_sandboxes/coreweave_sandbox.py:99

  • The session driver catches SystemExit as an ordinary code error, so sys.exit(2) returns code_error=SystemExit, keeps the session alive, and never supplies ExecutionResult.exit_code. This disagrees with the shared model's exit-code contract; handle SystemExit separately and include its numeric code in the reply/result.
    except BaseException as error:
        reply["status"] = "error"
        reply["error"] = {
            "name": type(error).__name__,
            "value": str(error),

code_sandboxes/coreweave_sandbox.py:522

  • A None reply also covers the case where the driver accepted and began the request but died before emitting its response. Falling back to _stateless_request then executes arbitrary user code a second time, duplicating side effects such as file writes or external requests. Do not retry after a request may have been accepted; report the lost reply and restart the session instead.
            reply = self._driver_request(prepared, seconds)
            if reply is None:
                reply = self._stateless_request(prepared, seconds)

code_sandboxes/coreweave_sandbox.py:452

  • The stateless fallback is not actually compatible with the shared variable-based helpers. _stateless_request discards its namespace when it returns, so after commands.run() or files.list() executes a snippet, the subsequent get_variable() call runs in a new process and sees none of the result. The fallback is documented as “working, merely stateless”; return helper values from the same process or provide provider-specific command/filesystem implementations.
    def _stateless_request(self, code: str, timeout: float) -> dict:
        """One snippet in a process of its own, for when there is no driver."""
        process = self._sandbox.exec(
            [self._python_executable, "-u", "-c", _STATELESS_SOURCE],

code_sandboxes/coreweave_sandbox.py:294

  • The explicit api_key is written to process-global os.environ and never restored. Starting or managing a second CoreWeave sandbox with another key overwrites the first credential, so later SDK calls can authenticate against the wrong account (and the secret also leaks to unrelated code in this process). Serialize/restore credential use or use an SDK client/configuration that keeps the token per instance.
        import os

        if self._api_key:
            os.environ["CWSANDBOX_API_KEY"] = self._api_key
        if self._base_url:
            os.environ["CWSANDBOX_BASE_URL"] = self._base_url

code_sandboxes/coreweave_sandbox.py:276

  • Sandbox.create(memory=...) stores memory_limit in bytes, but ResourceConfig.memory is documented as MB. This passes bytes into the public resource metadata, so CoreWeave reports an incorrect memory value even though its request conversion below is correct.
            resources=ResourceConfig(
                cpu=self.config.cpu_limit,
                memory=self.config.memory_limit,
                gpu=self.config.gpu,
            ),

code_sandboxes/coreweave_sandbox.py:446

  • The persistent driver protocol is shared by all callers, but _driver_seq, stdin, and the reply queue are accessed without synchronization. Two concurrent run_code calls can interleave requests; both then compare against the mutable latest sequence and can consume/misassociate each other's replies or time out. Serialize a complete driver request (or track replies per request) before writing to the shared process.
        self._driver_seq += 1
        try:
            self._driver.stdin.writeline(json.dumps({"seq": self._driver_seq, "code": code}))
        except Exception:
            logger.warning("The CoreWeave session driver went away; restarting stateless.")
            self._driver = None
            return None
        deadline = time.monotonic() + timeout
        while True:
            remaining = deadline - time.monotonic()
            if remaining <= 0:
                raise TimeoutError(f"No reply from the CoreWeave session within {timeout:.0f}s.")
            try:
                line = self._driver_replies.get(timeout=remaining)
            except queue.Empty:
                continue
            if line is None:
                # The reader reached EOF: the driver is gone.
                self._driver = None
                return None
            try:
                reply = json.loads(line)
            except ValueError:
                continue
            if reply.get("seq") == self._driver_seq:

code_sandboxes/coreweave_sandbox.py:696

  • When envs is supplied, this prepended import makes valid snippets beginning with from __future__ import ... fail with “future feature ... is not defined” because future imports must be first. Inject the environment after the future-import block or execute the original snippet as a separately compiled unit.
    return f"import os as _code_sandboxes_os\n{assignments}del _code_sandboxes_os\n{code}"

code_sandboxes/e2b_sandbox.py:224

  • When memory= is supplied, Sandbox.create stores it in SandboxConfig.memory_limit as bytes, while ResourceConfig.memory is documented as MB. Passing the byte value through makes sandbox.info.resources.memory report a value 1,048,576 times too large; convert to MB before constructing this metadata.
            resources=ResourceConfig(
                cpu=self.config.cpu_limit,
                memory=self.config.memory_limit,
            ),

code_sandboxes/manage.py:1096

  • The detached manager drops the HTTP client without closing it. Each create call therefore leaves an httpx.Client and its connection pool open in the caller even though the remote sandbox remains detached; close the client before discarding the local reference.
        sandbox._client = None
        sandbox._started = False

docs/docs/cli/index.mdx:103

  • The CLI does pass --gpu through for CoreWeave: _GPU_VARIANTS includes coreweave and _resolve_variant_kwargs adds gpu. This sentence tells users the opposite, despite the example supporting --gpu; document the actual CLI behavior instead.
  so lines share a namespace. `--gpu` is not passed on for this variant; a GPU
  is asked for from Python, `Sandbox.create(variant="coreweave", gpu="H100")`.

docs/docs/comparison/index.mdx:27

  • set_timeout() is not implemented by CoreWeave or Cloudflare (the only definitions are E2B and Datalayer), so it cannot have the same meaning on “each backend.” Qualify this shared-vocabulary claim by capability; otherwise users will reasonably call a method these providers do not expose.
- **One vocabulary for the rest.** `sandbox.files`, `sandbox.commands`,
  `create_context()`, `set_timeout()`, names and tags mean the same thing on
  each backend and are mapped onto whatever it actually offers — a filesystem

docs/docs/sandboxes/coreweave.mdx:164

  • The CoreWeave implementation only times out the caller's wait for a driver reply; it does not interrupt the persistent driver, so code can continue running and mutate the namespace after this timeout. This statement promises stronger cancellation than the backend currently provides.
- There is no interrupt: `sandbox.interrupt()` answers `False`, and a runaway
  execution is stopped by its timeout.

tests/test_cloudflare.py:130

  • The bridge fake sends the same literal ****** authorization value as the implementation and never validates it, so these protocol tests would pass even when the real bearer token is omitted or wrong. Make the fake require Bearer cf_key and assert the header so the authentication path is covered.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread code_sandboxes/cloudflare_sandbox.py Outdated
Comment thread code_sandboxes/cloudflare_sandbox.py
Comment thread code_sandboxes/cloudflare_sandbox.py Outdated
Comment thread code_sandboxes/cloudflare_sandbox.py
Comment thread code_sandboxes/coreweave_sandbox.py
Comment thread code_sandboxes/coreweave_sandbox.py Outdated

@echarles echarles left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

LGTM

@echarles
echarles merged commit 10855f3 into main Aug 21, 2026
8 checks 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.

2 participants