feat(sdk): filesystem-only snapshots (pause memory:false)#1465
Conversation
🦋 Changeset detectedLatest commit: f259b02 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
PR SummaryMedium Risk Overview Reviewed by Cursor Bugbot for commit f259b02. Bugbot is set up for automated code reviews on this repo. Configure here. |
Package ArtifactsBuilt from 0177a12. Download artifacts from this workflow run. JS SDK ( npm install ./e2b-2.30.7-feat-pause-filesystem-only.0.tgzCLI ( npm install ./e2b-cli-2.13.1-feat-pause-filesystem-only.0.tgzPython SDK ( pip install ./e2b-2.29.6+feat.pause.filesystem.only-py3-none-any.whl |
4b7cf94 to
d434332
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4b7cf94857
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
d434332 to
d54797f
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit d54797f. Configure here.
d54797f to
57674a0
Compare
mishushakov
left a comment
There was a problem hiding this comment.
everything looks good - only thing is that i believe the envd token should be persistent across pause/resume cycle.
please use SandboxPauseOpts consistently.
| * ``` | ||
| */ | ||
| async pause(opts?: ConnectionOpts): Promise<boolean> { | ||
| async pause(opts?: ConnectionOpts & { memory?: boolean }): Promise<boolean> { |
There was a problem hiding this comment.
we're not using the SandboxPauseOpts here
There was a problem hiding this comment.
This was anchored to the pre-amend commit — it's addressed in the latest commit (57674a071): both pause and betaPause now take the exported SandboxPauseOpts (and the static SandboxApi.pause/betaPause too), matching how createSnapshot uses CreateSnapshotOpts. resolveApiOpts spreads the opts through, so memory reaches SandboxApi.pause.
| /** | ||
| * @deprecated Use {@link Sandbox.pause} instead. | ||
| */ | ||
| async betaPause(opts?: ConnectionOpts): Promise<boolean> { |
There was a problem hiding this comment.
we're not using SandboxPauseOpts here
57674a0 to
59a8378
Compare
|
Per offline feedback from @mishushakov, renamed the SDK-facing parameter to make the drop-on-
The wire/spec field stays |
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Babis Chalios <babis.chalios@e2b.dev>
9e798d5 to
a6d3323
Compare
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
- Re-export SandboxPauseOpts from the package root so callers can
`import { SandboxPauseOpts } from 'e2b'` (the point of the named type).
- Fix Sandbox.pause @returns JSDoc: it returns a boolean (paused/already
paused), not a sandbox ID.
- Correct the resume test comments: connect() returns the same handle and its
credentials stay valid across a filesystem-only resume (no stale handle).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
mishushakov
left a comment
There was a problem hiding this comment.
all looks good - in the tests you can use sandbox.files.read instead of cat, but i am fine with either
4a0e4c2 to
1bed5d8
Compare
|
Done in 1bed5d8 — switched the reads to |
Per review (mishushakov): dogfood the SDK's filesystem API in its own tests. The rootfs marker and the kernel boot id are now written/read via files.write/files.read instead of echo/cat, in both Python tests and the JS test. files.read returns the full content for the /proc boot_id pseudo-file (verified against a live stack), so no cat fallback is needed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1bed5d8 to
f259b02
Compare
…form (#1471) ## Filesystem-only auto-pause (`onTimeout` object form) Adds an object form to the sandbox **lifecycle** `onTimeout` (`on_timeout` in Python) that controls the snapshot kind taken when a sandbox auto-pauses on timeout, via `keepMemory` (`keep_memory`). `onTimeout` now accepts either the existing bare action (`'pause'` / `'kill'`) or the object form `{ action, keepMemory }`. When `keepMemory` is `false` (with `action: 'pause'`), a timeout auto-pause takes a **filesystem-only** snapshot (no memory) instead of a full memory one, so the sandbox cold-boots (reboots) from disk on resume — losing running processes and open connections. Defaults to `true` (full memory snapshot), so existing callers are unaffected. **The bare string form is unchanged.** It's the create-time / auto-pause counterpart to the explicit `pause(keepMemory=false)` from #1465: same `keepMemory` naming, mapped onto the `autoPauseMemory` create field. ### Type safety The object form is a **discriminated union** on `action`: `keepMemory` is only valid with `action: 'pause'`. Pairing it with `action: 'kill'` is a **compile-time type error** (TS) / static error (`ty`), and is additionally rejected at runtime (`InvalidArgumentError` / `InvalidArgumentException`) for untyped callers. ### Behavior & validation - `keepMemory` only applies to a `pause` action. - **Incompatible with auto-resume** — auto-resume wakes a paused sandbox on inbound traffic by restoring its memory snapshot in place; a filesystem-only snapshot has no memory to restore (resuming cold-boots it), so it must be resumed explicitly via `connect()`. Combining `keepMemory: false` with `autoResume` is rejected client-side. ### Usage ```ts // JS/TS — filesystem-only auto-pause on timeout const sbx = await Sandbox.create({ lifecycle: { onTimeout: { action: 'pause', keepMemory: false } }, }) // bare string form still works (full memory snapshot) const sbx2 = await Sandbox.create({ lifecycle: { onTimeout: 'pause' } }) ``` ```python # Python sbx = Sandbox.create( lifecycle={"on_timeout": {"action": "pause", "keep_memory": False}} ) ``` ### Changes - `spec/openapi.yml`: `autoPauseMemory` on the create body (+ regenerated JS/Python clients). - JS `SandboxOnTimeout` discriminated union (`'pause' | 'kill' | { action: 'pause'; keepMemory? } | { action: 'kill' }`) and the Python `SandboxOnTimeoutPause` / `SandboxOnTimeoutKill` TypedDicts, wired through `createSandbox` / `_create_sandbox` (sync + async) to `autoPauseMemory`, with the client-side guards. - Tests: payload serialization + validation (offline, incl. the `action: 'kill'` type/runtime guard) and live cold-boot e2e in both SDKs; changeset (`e2b` + `@e2b/python-sdk`, minor). ### Backend dependency The live e2e tests exercise the real auto-pause→cold-boot path and require the infra-side `autoPauseMemory` support (e2b-dev/infra#3055), now merged and deployed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: Babis Chalios <babis.chalios@e2b.dev> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

Summary
Adds an optional
memoryflag topausein both the JS and Python SDKs. Whenmemoryisfalse, the pause captures only the filesystem (no memory snapshot); resuming such a snapshot cold-boots (reboots) the sandbox from disk — losing in-memory state, running processes, and open connections. Defaults totrue(full memory snapshot), so existing callers are unaffected.This is the SDK surface for the filesystem-only snapshot feature on the infra side.
Usage
memorydefaults totrue—pause()/pause({})behave exactly as before.What changed
memory: boolean(defaulttrue) onPOST /sandboxes/{sandboxID}/pause(SandboxPauseRequest); both API clients regenerated viamake codegen.Sandbox.pause/betaPauseaccept{ memory }→SandboxApi.pausesends the request body.pause(memory=...)/beta_pause→_cls_pause(sync + async) sendsSandboxPauseRequest(memory=...).tests/sandbox/snapshot.test.ts) and Python sync + async. All pass against a local stack;format/lint/typecheckclean.minorfore2band@e2b/python-sdk.Note (related infra observation, not addressed here)
While testing, a filesystem-only resume cold-boots into a different default exec context (
root//root) than a memory resume (user//home/user). The filesystem itself is fully intact; tests use absolute paths to be robust to this. Worth confirming on the infra reboot path whether the template's default user should be restored after a cold boot.🤖 Generated with Claude Code