Repository navigation
feat(sdk): filesystem-only snapshots via mode on createSnapshot - #1925
Conversation
🦋 Changeset detectedLatest commit: 920a48b 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 920a48b. Bugbot is set up for automated code reviews on this repo. Configure here. |
Package ArtifactsBuilt from a052157. Download artifacts from this workflow run. JS SDK ( npm install ./e2b-dockerfile-utils-0.1.1-feature-fs-only-snapshot.0.tgz ./e2b-2.54.1-feature-fs-only-snapshot.0.tgzCLI ( npm install ./e2b-cli-2.21.2-feature-fs-only-snapshot.0.tgzCode Interpreter JS SDK ( npm install ./e2b-code-interpreter-2.8.3-feature-fs-only-snapshot.0.tgzDesktop JS SDK ( npm install ./e2b-desktop-2.4.1-feature-fs-only-snapshot.0.tgzPython SDK ( pip install ./e2b_dockerfile_utils-0.1.0+feature.fs.only.snapshot-py3-none-any.whl ./e2b-2.54.0+feature.fs.only.snapshot-py3-none-any.whlCode Interpreter Python SDK ( pip install ./e2b_code_interpreter-2.10.3+feature.fs.only.snapshot-py3-none-any.whlDesktop Python SDK ( pip install ./e2b_desktop-2.6.1+feature.fs.only.snapshot-py3-none-any.whl |
5920e38 to
7ca14e0
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. |
f8d85fb to
9b64cdf
Compare
There was a problem hiding this comment.
I reviewed this PR and didn't find any bugs. Because it adds a new cross-SDK API option (keepMemory/keep_memory) touching sandbox snapshot lifecycle, a server-side feature flag with 400/409 refusal semantics, and a spec pin bump across 23 generated and hand-written files in both SDKs, a human look would still be worthwhile.
What was reviewed: the memory/keepMemory wiring from spec (openapi.yml, envd.yaml, filesystem.proto, runtime-ref bump) through generated clients into js-sdk's sandboxApi.ts/index.ts and both Python sync/async main.py/sandbox_api.py; confirmed keep_memory is keyword-only in both Python variants and mirrors the existing keepMemory pattern already used for pause; checked that an omitted option serializes to nothing on the wire (undefined dropped from the JS request body, UNSET in the Python model) matching the documented "API default applies" behavior; and reviewed the new JS/Python tests, which correctly skip on the 400 snapshot_filesystem_only_disabled case and otherwise assert cold-boot via a changed kernel boot id.
Extended reasoning...
The diff adds a filesystem-only snapshot option end-to-end: spec/runtime-ref pin bump plus regenerated clients, and hand-written additions to js-sdk sandboxApi.ts/index.ts and python-sdk sandbox_sync/sandbox_async main.py/sandbox_api.py, with new tests and a changeset. No injection/auth/crypto surface is touched; the sensitive aspect is correctly wiring a new persistence-affecting option across two SDK languages and keeping it consistent with the spec-sync convention. The PR author's own description flags this as a draft pending a production API rollout (to avoid silently downgrading filesystem-only requests to full snapshots against an older API), and an earlier automated review (Devin) left six inline comments on these same files that have no visible resolution signal in the metadata available to me — both are reasons a human should still weigh in even though no bugs were found in this pass.
This review covers commit 7ca14e0, which is no longer the latest commit on this pull request; later commits are not covered by it.
9b64cdf to
bc31550
Compare
`createSnapshot({ keepMemory: false })` (JS) and
`create_snapshot(keep_memory=False)` (Python) send `memory: false` on the
snapshot request, mirroring the pause option: only the filesystem is
persisted, so the snapshot is smaller and faster to take, and sandboxes
created from it cold-boot instead of restoring memory. The source sandbox
keeps running either way. Omitted, nothing is sent and the API default (a
full memory snapshot) applies.
The runtime spec pin (spec/runtime-ref) moves to the e2b-dev/runtime
commit that carries the API change, and both clients are regenerated
from it with the repo's codegen. The pin bump also brings the spec
changes landed upstream since the previous pin (18 September): the
team_id description, cached node admission fields, the
secret_limit_reached error code and 409 body, the envd metrics change
from mem_total_mib/mem_used_mib to oom_kills, and is_symlink on the
filesystem proto. The last one is honoured: newer envd reports a
symlink's target type in `type` and marks the link with is_symlink, so
both filesystem mappers now report FileType.SYMLINK when the flag is
set and keep the old enum mapping otherwise, with unit tests for links
to a file and to a directory. Nothing else in the regenerated files is
read by SDK code.
keep_memory is keyword-only in Python. Both SDKs document the two
refusals: status 400 (snapshot_filesystem_only_disabled) while the
feature is off for the team, and 409
(snapshot_filesystem_only_unsupported_node) when the sandbox's node
runs an orchestrator that predates the option.
The SDK tests prove the snapshot kind rather than only the file copy:
the source keeps its kernel boot id across the snapshot and the sandbox
created from it reports a different one, which a memory snapshot
cannot produce. The boot id is read with a command, not files.read,
because envd serves procfs files as an empty 200. Where the feature is
off for the team the API answers 400 and the tests skip with that
reason.
Signed-off-by: Babis Chalios <babis.chalios@e2b.dev>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
bc31550 to
917f733
Compare
createSnapshot / create_snapshot take `mode` instead of the unreleased `keepMemory` / `keep_memory`. pause() and the lifecycle onTimeout pause object form accept the same `mode`; their `keepMemory` / `keep_memory` is deprecated in favor of it and keeps working. The new `SnapshotMode` type is exported from both SDKs. One resolver maps `mode` (or the deprecated flag) onto the API's `memory` / `autoPauseMemory` field so the three call sites can't drift. It rejects an unknown mode and passing both options with InvalidArgumentError / InvalidArgumentException before any request is sent. An unset mode still omits the field, leaving the API default (a full snapshot) in effect. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
`createSnapshot({ kind: 'filesystem' })` (JS) and
`create_snapshot(kind="filesystem")` (Python) replace the unreleased
`mode` option on snapshot creation. `pause()` and the lifecycle
onTimeout pause object form keep `mode`; both still take the shared
`SnapshotMode` values `'full' | 'filesystem'`.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This reverts commit b43363a. createSnapshot goes back to `mode`, so createSnapshot, pause() and the lifecycle onTimeout pause object form share one option name for the same `SnapshotMode` values instead of splitting them between `kind` and `mode`. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Summary
Adds
mode: 'full' | 'filesystem'(exported asSnapshotMode) tocreateSnapshot/create_snapshot. With'filesystem', the SDK sendsmemory: falseon the snapshot request and the API takes a filesystem-only snapshot: only the filesystem is persisted, so the snapshot is smaller and faster to take, and sandboxes created from it cold-boot instead of restoring memory. The source sandbox keeps running either way. When omitted, nothing is sent and the API default, a full memory snapshot, applies.The same
modeis accepted bypause()and by thelifecycle.onTimeout/lifecycle["on_timeout"]pause object form. Their existingkeepMemory/keep_memoryoption is deprecated in favor of it (keepMemory: falseismode: 'filesystem') and keeps working. One resolver mapsmode(or the deprecated flag) onto the wirememory/autoPauseMemoryfield for all three call sites; it rejects an unknown mode and passing both options withInvalidArgumentError/InvalidArgumentExceptionbefore any request is sent.Spec copy updated from the API, both generated clients regenerated, docstrings and a changeset (minor for both SDKs) included.
Usage
Server side
The API support merged in e2b-dev/belt#4073 on top of the orchestrator support in e2b-dev/belt#4049. The API refuses
memory: falsewith 400snapshot_filesystem_only_disabledwhile the feature is not enabled for the team, and with 409snapshot_filesystem_only_unsupported_nodewhen the sandbox's node runs an orchestrator that predates the field. A request is never downgraded to a memory snapshot by a server that understands the field.Why this is a draft
An API deployment from before e2b-dev/belt#4073 accepts the request body, ignores
memory, and takes a memory snapshot while answering 201. Releasing this before production runs the new API would let callers ask for a filesystem-only snapshot and silently get a full one. Keep this in draft until production has the API build, then release.The SDK tests for the new option call the live API with
mode: 'filesystem'. Where the feature is off for the test team the API answers 400 and the tests skip with that reason; where it is on, they prove the snapshot kind: the source keeps its kernel boot id across the snapshot and the sandbox created from it reports a different one, which a memory snapshot cannot produce. Against an API that predates the field those assertions fail, by design.Verification
main; Python modules compile; the JS SDK typechecks.spec/runtime-refis bumped to the e2b-dev/runtime commit that carries the API change and both clients are regenerated withmake codegen, so the Generated files check passes. The bump also pulls in the upstream spec changes since the previous pin (team id description, cached node admission fields, thesecret_limit_reachederror code, envdoom_killsreplacing the memory counters,is_symlinkon the filesystem proto); none of them is read by SDK code outside the generated files.modeis keyword-only in Python (pausekeepskeep_memorypositional for compatibility). Both SDKs document the 400 and 409 refusals oncreateSnapshot/create_snapshot.mode→memory/autoPauseMemorymapping, the deprecated flag, and the rejected combinations; the filesystem-mode integration tests (snapshot, pause, timeout auto-pause) pass against production in JS and Python sync/async.files.readbecause envd serves procfs files as an empty 200, and skip on the 400snapshot_filesystem_only_disabledrefusal.🤖 Generated with Claude Code