agentscope-ai / agentscope-ai/agentscope-java
[Feature]: e2b: auto-prune old NATIVE_SNAPSHOT snapshots per sandbox to cap cloud storage
- Lingua principale
- Java
- Stelle
- 5.6k
- Fork
- 1.3k
- Merge medio
- 4g 12h
- PR unite (30g)
- 77
Descrizione
### Problem
In `agentscope-extensions-sandbox-e2b`, `E2bPersistenceMode.NATIVE_SNAPSHOT` calls `POST /sandboxes/{id}/snapshots` on every `stop()` (`E2bSandbox.doPersistWorkspace()`). The resulting snapshots are team-level, persistent, TTL-less E2B resources — AgentScope never deletes them, so they accumulate indefinitely and cloud storage costs grow unbounded. Locally, `LocalSnapshotSpec` writes `{sessionId}.tar` and only the latest `snapshotId` is ever referenced (the file is overwritten on each persist), so older cloud snapshots are dead storage that can never be used again.
### Proposal
1. `E2bPlatformHttp`: add `listSnapshots(sandboxId)` (`GET /snapshots?sandboxID=...`) and `deleteSnapshot(snapshotId)` (`DELETE /templates/{snapshotId}`, treating `404` as idempotent — mirrors the E2B Python SDKs `delete_snapshot()`, since the public OpenAPI has no dedicated `/snapshots` DELETE endpoint).
2. Add a configurable `snapshotRetention` (default `1`; `<=0` disables pruning), wired through `E2bSandboxClientOptions` and exposed on `E2bFilesystemSpec`.
3. In `NATIVE_SNAPSHOT` mode, after a successful snapshot create, list the sandboxs snapshots, exclude the just-created one, and delete the rest. Failures are best-effort — warn only, never block persistence.
### Notes / trade-offs
- `GET /snapshots` returns no `createdAt`, so keeping `N > 1` cannot be time-ordered; a default of `1` (only the snapshot referenced by the local `.tar`) is the safe choice.
- The kept snapshot is always the newest — the one the local `.tar` references — so pruning never removes a live recovery point.
- Snapshots survive sandbox deletion, so pruning still works after a sandbox is killed.
- E2Bs `createSnapshot` API has no `memory`/`keepMemory` option (filesystem-only is only available on the `pause` path), so the memory-image overhead cannot be avoided; pruning is the pragmatic mitigation for storage growth.
### Open question: should we also support pause-based persistence?
Beyond pruning, the maintainers may want to consider a second persistence mode (`E2bPersistenceMode.FILESYSTEM_ONLY`) built on the E2B `pause` API (`POST /sandboxes/{id}/pause` with `{"memory": false}`), which captures **filesystem-only** snapshots — no memory image, so faster to create and significantly cheaper to store. Recovery would `connect()` the same paused sandbox (AgentScope already has that path), and paused sandboxes are kept indefinitely with no TTL.
Trade-offs vs. the current snapshot approach:
- **Pros**: true filesystem-only persistence (the memory image is pure waste for the "persist files between calls" use case); no tar transfer cost; resumes the same sandbox.
- **Cons**: not portable to a new sandbox (no reusable snapshot id for cloning); if the sandbox dies while running (e.g. timeout `kill`), there is no backup to restore from — workspace is lost and can only be rebuilt from the manifest; shutdown must not kill the paused sandbox, so paused sandboxes linger on the account and need an explicit cleanup policy.
Would the maintainers be open to adding this as an opt-in mode, or should pruning alone be the scope of this change?
### Related
- `E2bSandbox.java`, `E2bPlatformHttp.java`, `E2bPersistenceMode.java`, `E2bSandboxClientOptions.java`
Guida per i contributori
Apri la guida per i contributori
Valutazione
Questa issue non è ancora stata valutata.