Skip to content

Commit 63ef618

Browse files
mishushakovclaude
andcommitted
feat: add optional name parameter to createSnapshot and return snapshot names
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 4065ecd commit 63ef618

11 files changed

Lines changed: 89 additions & 22 deletions

File tree

.changeset/snapshot-name.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@e2b/python-sdk': patch
3+
'e2b': patch
4+
---
5+
6+
add optional name parameter to createSnapshot and return snapshot names

packages/js-sdk/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export type {
6363
SnapshotInfo,
6464
SnapshotListOpts,
6565
SnapshotPaginator,
66+
CreateSnapshotOpts,
6667
} from './sandbox/sandboxApi'
6768

6869
export type { McpServer } from './sandbox/mcp'

packages/js-sdk/src/sandbox/index.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
SnapshotListOpts,
2525
SnapshotInfo,
2626
SnapshotPaginator,
27+
CreateSnapshotOpts,
2728
} from './sandboxApi'
2829
import { getSignature } from './signature'
2930
import { compareVersions } from 'compare-versions'
@@ -609,7 +610,7 @@ export class Sandbox extends SandboxApi {
609610
*
610611
* Use the returned `snapshotId` with `Sandbox.create(snapshotId)` to create a new sandbox from the snapshot.
611612
*
612-
* @param opts connection options.
613+
* @param opts snapshot creation options including optional name and connection options.
613614
*
614615
* @returns snapshot information including the snapshot ID.
615616
*
@@ -619,17 +620,17 @@ export class Sandbox extends SandboxApi {
619620
* await sandbox.files.write('/app/state.json', '{"step": 1}')
620621
*
621622
* // Create a snapshot
622-
* const snapshot = await sandbox.createSnapshot()
623+
* const snapshot = await sandbox.createSnapshot({ name: 'my-snapshot' })
623624
*
624625
* // Create a new sandbox from the snapshot
625626
* const newSandbox = await Sandbox.create(snapshot.snapshotId)
626627
* ```
627628
*/
628-
async createSnapshot(opts?: SandboxApiOpts): Promise<SnapshotInfo> {
629-
return await SandboxApi.createSnapshot(
630-
this.sandboxId,
631-
this.resolveApiOpts(opts)
632-
)
629+
async createSnapshot(opts?: CreateSnapshotOpts): Promise<SnapshotInfo> {
630+
return await SandboxApi.createSnapshot(this.sandboxId, {
631+
...this.resolveApiOpts(opts),
632+
name: opts?.name,
633+
})
633634
}
634635

635636
/**

packages/js-sdk/src/sandbox/sandboxApi.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,23 @@ export interface SnapshotInfo {
283283
* Can be used with Sandbox.create() to create a new sandbox from this snapshot.
284284
*/
285285
snapshotId: string
286+
287+
/**
288+
* Full names of the snapshot template including team namespace and tag (e.g. team-slug/my-snapshot:v2).
289+
*/
290+
names: string[]
291+
}
292+
293+
/**
294+
* Options for creating a snapshot.
295+
*/
296+
export interface CreateSnapshotOpts extends SandboxApiOpts {
297+
/**
298+
* Optional name for the snapshot template.
299+
* If a snapshot template with this name already exists, a new build will be assigned
300+
* to the existing template instead of creating a new one.
301+
*/
302+
name?: string
286303
}
287304

288305
/**
@@ -688,13 +705,13 @@ export class SandboxApi {
688705
* The snapshot is a persistent image that survives sandbox deletion.
689706
*
690707
* @param sandboxId sandbox ID to create snapshot from.
691-
* @param opts connection options.
708+
* @param opts snapshot creation options including optional name and connection options.
692709
*
693710
* @returns snapshot information including the snapshot name that can be used with Sandbox.create().
694711
*/
695712
static async createSnapshot(
696713
sandboxId: string,
697-
opts?: SandboxApiOpts
714+
opts?: CreateSnapshotOpts
698715
): Promise<SnapshotInfo> {
699716
const config = new ConnectionConfig(opts)
700717
const client = new ApiClient(config)
@@ -705,7 +722,7 @@ export class SandboxApi {
705722
sandboxID: sandboxId,
706723
},
707724
},
708-
body: {},
725+
body: opts?.name ? { name: opts.name } : {},
709726
signal: config.getSignal(opts?.requestTimeoutMs),
710727
})
711728

@@ -720,6 +737,7 @@ export class SandboxApi {
720737

721738
return {
722739
snapshotId: res.data!.snapshotID,
740+
names: res.data!.names ?? [],
723741
}
724742
}
725743

@@ -1045,6 +1063,7 @@ export class SnapshotPaginator extends BasePaginator<SnapshotInfo> {
10451063
return (res.data ?? []).map(
10461064
(snapshot: components['schemas']['SnapshotInfo']) => ({
10471065
snapshotId: snapshot.snapshotID,
1066+
names: snapshot.names ?? [],
10481067
})
10491068
)
10501069
}

packages/python-sdk/e2b/sandbox/sandbox_api.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,8 @@ class SnapshotInfo:
296296

297297
snapshot_id: str
298298
"""Snapshot identifier — template ID with tag, or namespaced name with tag (e.g. my-snapshot:latest). Can be used with Sandbox.create() to create a new sandbox from this snapshot."""
299+
names: List[str] = field(default_factory=list)
300+
"""Full names of the snapshot template including team namespace and tag (e.g. team-slug/my-snapshot:v2)."""
299301

300302

301303
class PaginatorBase:

packages/python-sdk/e2b/sandbox_async/main.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,7 @@ async def beta_pause(
694694
@overload
695695
async def create_snapshot(
696696
self,
697+
name: Optional[str] = None,
697698
**opts: Unpack[ApiParams],
698699
) -> SnapshotInfo:
699700
"""
@@ -705,14 +706,17 @@ async def create_snapshot(
705706
706707
Use the returned `snapshot_id` with `AsyncSandbox.create(snapshot_id)` to create a new sandbox from the snapshot.
707708
708-
:return: Snapshot information including the snapshot ID
709+
:param name: Optional name for the snapshot template. If a snapshot template with this name already exists, a new build will be assigned to the existing template instead of creating a new one.
710+
711+
:return: Snapshot information including the snapshot ID and names
709712
"""
710713
...
711714

712715
@overload
713716
@staticmethod
714717
async def create_snapshot(
715718
sandbox_id: str,
719+
name: Optional[str] = None,
716720
**opts: Unpack[ApiParams],
717721
) -> SnapshotInfo:
718722
"""
@@ -721,14 +725,16 @@ async def create_snapshot(
721725
The sandbox will be paused while the snapshot is being created.
722726
723727
:param sandbox_id: Sandbox ID
728+
:param name: Optional name for the snapshot template. If a snapshot template with this name already exists, a new build will be assigned to the existing template instead of creating a new one.
724729
725-
:return: Snapshot information including the snapshot ID
730+
:return: Snapshot information including the snapshot ID and names
726731
"""
727732
...
728733

729734
@class_method_variant("_cls_create_snapshot")
730735
async def create_snapshot(
731736
self,
737+
name: Optional[str] = None,
732738
**opts: Unpack[ApiParams],
733739
) -> SnapshotInfo:
734740
"""
@@ -740,10 +746,13 @@ async def create_snapshot(
740746
741747
Use the returned `snapshot_id` with `AsyncSandbox.create(snapshot_id)` to create a new sandbox from the snapshot.
742748
743-
:return: Snapshot information including the snapshot ID
749+
:param name: Optional name for the snapshot template. If a snapshot template with this name already exists, a new build will be assigned to the existing template instead of creating a new one.
750+
751+
:return: Snapshot information including the snapshot ID and names
744752
"""
745753
return await SandboxApi._cls_create_snapshot(
746754
sandbox_id=self.sandbox_id,
755+
name=name,
747756
**self.connection_config.get_api_params(**opts),
748757
)
749758

packages/python-sdk/e2b/sandbox_async/paginator.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,5 +121,9 @@ async def next_items(self) -> List[SnapshotInfo]:
121121
raise SandboxException(f"{res.parsed.message}: Request failed")
122122

123123
return [
124-
SnapshotInfo(snapshot_id=snapshot.snapshot_id) for snapshot in res.parsed
124+
SnapshotInfo(
125+
snapshot_id=snapshot.snapshot_id,
126+
names=list(snapshot.names) if snapshot.names else [],
127+
)
128+
for snapshot in res.parsed
125129
]

packages/python-sdk/e2b/sandbox_async/sandbox_api.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ async def _cls_get_metrics(
297297
async def _cls_create_snapshot(
298298
cls,
299299
sandbox_id: str,
300+
name: Optional[str] = None,
300301
**opts: Unpack[ApiParams],
301302
) -> SnapshotInfo:
302303
config = ConnectionConfig(**opts)
@@ -305,7 +306,9 @@ async def _cls_create_snapshot(
305306
res = await post_sandboxes_sandbox_id_snapshots.asyncio_detailed(
306307
sandbox_id,
307308
client=api_client,
308-
body=PostSandboxesSandboxIDSnapshotsBody(),
309+
body=PostSandboxesSandboxIDSnapshotsBody(
310+
name=name if name is not None else UNSET
311+
),
309312
)
310313

311314
if res.status_code == 404:
@@ -320,7 +323,10 @@ async def _cls_create_snapshot(
320323
if isinstance(res.parsed, Error):
321324
raise SandboxException(f"{res.parsed.message}: Request failed")
322325

323-
return SnapshotInfo(snapshot_id=res.parsed.snapshot_id)
326+
return SnapshotInfo(
327+
snapshot_id=res.parsed.snapshot_id,
328+
names=list(res.parsed.names) if res.parsed.names else [],
329+
)
324330

325331
@classmethod
326332
async def _cls_delete_snapshot(

packages/python-sdk/e2b/sandbox_sync/main.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,7 @@ def beta_pause(
691691
@overload
692692
def create_snapshot(
693693
self,
694+
name: Optional[str] = None,
694695
**opts: Unpack[ApiParams],
695696
) -> SnapshotInfo:
696697
"""
@@ -702,14 +703,17 @@ def create_snapshot(
702703
703704
Use the returned `snapshot_id` with `Sandbox.create(snapshot_id)` to create a new sandbox from the snapshot.
704705
705-
:return: Snapshot information including the snapshot ID
706+
:param name: Optional name for the snapshot template. If a snapshot template with this name already exists, a new build will be assigned to the existing template instead of creating a new one.
707+
708+
:return: Snapshot information including the snapshot ID and names
706709
"""
707710
...
708711

709712
@overload
710713
@staticmethod
711714
def create_snapshot(
712715
sandbox_id: str,
716+
name: Optional[str] = None,
713717
**opts: Unpack[ApiParams],
714718
) -> SnapshotInfo:
715719
"""
@@ -718,14 +722,16 @@ def create_snapshot(
718722
The sandbox will be paused while the snapshot is being created.
719723
720724
:param sandbox_id: Sandbox ID
725+
:param name: Optional name for the snapshot template. If a snapshot template with this name already exists, a new build will be assigned to the existing template instead of creating a new one.
721726
722-
:return: Snapshot information including the snapshot ID
727+
:return: Snapshot information including the snapshot ID and names
723728
"""
724729
...
725730

726731
@class_method_variant("_cls_create_snapshot")
727732
def create_snapshot(
728733
self,
734+
name: Optional[str] = None,
729735
**opts: Unpack[ApiParams],
730736
) -> SnapshotInfo:
731737
"""
@@ -737,10 +743,13 @@ def create_snapshot(
737743
738744
Use the returned `snapshot_id` with `Sandbox.create(snapshot_id)` to create a new sandbox from the snapshot.
739745
740-
:return: Snapshot information including the snapshot ID
746+
:param name: Optional name for the snapshot template. If a snapshot template with this name already exists, a new build will be assigned to the existing template instead of creating a new one.
747+
748+
:return: Snapshot information including the snapshot ID and names
741749
"""
742750
return SandboxApi._cls_create_snapshot(
743751
sandbox_id=self.sandbox_id,
752+
name=name,
744753
**self.connection_config.get_api_params(**opts),
745754
)
746755

packages/python-sdk/e2b/sandbox_sync/paginator.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,5 +121,9 @@ def next_items(self) -> List[SnapshotInfo]:
121121
raise SandboxException(f"{res.parsed.message}: Request failed")
122122

123123
return [
124-
SnapshotInfo(snapshot_id=snapshot.snapshot_id) for snapshot in res.parsed
124+
SnapshotInfo(
125+
snapshot_id=snapshot.snapshot_id,
126+
names=list(snapshot.names) if snapshot.names else [],
127+
)
128+
for snapshot in res.parsed
125129
]

0 commit comments

Comments
 (0)