Skip to content

Commit b95293b

Browse files
authored
feat(sandbox): expose underlying provider sandbox instances (#1068)
1 parent f36545c commit b95293b

5 files changed

Lines changed: 72 additions & 16 deletions

File tree

‎.changeset/tall-lions-give.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"@voltagent/sandbox-e2b": patch
3+
---
4+
5+
feat: expose the underlying E2B SDK sandbox instance from `E2BSandbox`.
6+
7+
- Added a public `getSandbox()` method that returns the original `e2b` `Sandbox` instance so provider-specific APIs (for example `files.read`) can be used directly.
8+
- Added `E2BSandboxInstance` type export for the underlying SDK sandbox type.

‎.changeset/wet-bees-poke.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"@voltagent/sandbox-daytona": patch
3+
---
4+
5+
feat: expose the underlying Daytona SDK sandbox instance from `DaytonaSandbox`.
6+
7+
- Added a public `getSandbox()` method that returns the original `@daytonaio/sdk` `Sandbox` instance so provider-specific APIs can be used directly.
8+
- Added `DaytonaSandboxInstance` type export for the underlying SDK sandbox type.

‎packages/sandbox-daytona/src/index.ts‎

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import * as daytonaModule from "@daytonaio/sdk";
2+
import type { Sandbox as DaytonaOriginalSandbox } from "@daytonaio/sdk";
23
import {
34
type WorkspaceSandbox,
45
type WorkspaceSandboxExecuteOptions,
56
type WorkspaceSandboxResult,
67
normalizeCommandAndArgs,
78
} from "@voltagent/core";
89

10+
export type DaytonaSandboxInstance = DaytonaOriginalSandbox;
11+
912
export type DaytonaSandboxOptions = {
1013
apiKey?: string;
1114
apiUrl?: string;
@@ -29,17 +32,6 @@ type DaytonaExecResult = {
2932
};
3033
};
3134

32-
type DaytonaSandboxInstance = {
33-
process: {
34-
executeCommand: (
35-
command: string,
36-
cwd?: string,
37-
env?: Record<string, string>,
38-
timeoutSeconds?: number,
39-
) => Promise<DaytonaExecResult>;
40-
};
41-
};
42-
4335
type DaytonaClient = {
4436
create: (
4537
params?: Record<string, unknown>,
@@ -157,7 +149,7 @@ export class DaytonaSandbox implements WorkspaceSandbox {
157149
return await client.create(this.createParams, options);
158150
}
159151

160-
private async getSandbox(): Promise<DaytonaSandboxInstance> {
152+
private async resolveSandbox(): Promise<DaytonaSandboxInstance> {
161153
if (this.sandbox) {
162154
return this.sandbox;
163155
}
@@ -175,6 +167,14 @@ export class DaytonaSandbox implements WorkspaceSandbox {
175167
return this.sandboxPromise;
176168
}
177169

170+
/**
171+
* Returns the underlying Daytona SDK sandbox instance.
172+
* Use this when you need Daytona-specific APIs beyond `execute`.
173+
*/
174+
async getSandbox(): Promise<DaytonaSandboxInstance> {
175+
return this.resolveSandbox();
176+
}
177+
178178
async execute(options: WorkspaceSandboxExecuteOptions): Promise<WorkspaceSandboxResult> {
179179
const startTime = Date.now();
180180
const normalized = normalizeCommandAndArgs(options.command ?? "", options.args);
@@ -197,7 +197,7 @@ export class DaytonaSandbox implements WorkspaceSandbox {
197197
};
198198
}
199199

200-
const sandbox = await this.getSandbox();
200+
const sandbox = await this.resolveSandbox();
201201
const maxOutputBytes =
202202
options.maxOutputBytes === undefined
203203
? this.maxOutputBytes

‎packages/sandbox-e2b/src/index.ts‎

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ import type {
33
WorkspaceSandboxExecuteOptions,
44
WorkspaceSandboxResult,
55
} from "@voltagent/core";
6+
import type { Sandbox as E2BOriginalSandbox } from "e2b";
67
import * as e2bModule from "e2b";
78

9+
export type E2BSandboxInstance = E2BOriginalSandbox;
10+
811
export type E2BSandboxOptions = {
912
apiKey?: string;
1013
template?: string;
@@ -376,7 +379,7 @@ export class E2BSandbox implements WorkspaceSandbox {
376379
return await Sandbox.create(createOptions);
377380
}
378381

379-
private async getSandbox(): Promise<E2BSdkSandbox> {
382+
private async resolveSandbox(): Promise<E2BSdkSandbox> {
380383
if (this.sandbox) {
381384
return this.sandbox;
382385
}
@@ -394,6 +397,14 @@ export class E2BSandbox implements WorkspaceSandbox {
394397
return this.sandboxPromise;
395398
}
396399

400+
/**
401+
* Returns the underlying E2B SDK sandbox instance.
402+
* Use this when you need E2B-specific APIs beyond `execute`.
403+
*/
404+
async getSandbox(): Promise<E2BSandboxInstance> {
405+
return (await this.resolveSandbox()) as unknown as E2BSandboxInstance;
406+
}
407+
397408
private async killCommand(sandbox: E2BSdkSandbox, handle?: E2BCommandHandle): Promise<void> {
398409
if (!handle) {
399410
return;
@@ -473,7 +484,7 @@ export class E2BSandbox implements WorkspaceSandbox {
473484
timedOut = true;
474485
resolve(null);
475486
}, remaining);
476-
this.getSandbox()
487+
this.resolveSandbox()
477488
.then((resolved) => {
478489
if (settled) {
479490
return;
@@ -491,7 +502,7 @@ export class E2BSandbox implements WorkspaceSandbox {
491502
reject(error);
492503
});
493504
})
494-
: await this.getSandbox();
505+
: await this.resolveSandbox();
495506

496507
if (!sandbox) {
497508
return {

‎website/docs/workspaces/sandbox.md‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,35 @@ const daytonaWorkspace = new Workspace({
127127
});
128128
```
129129

130+
If you need provider-specific APIs, keep a reference to the provider and access its native SDK instance:
131+
132+
```ts
133+
import { E2BSandbox } from "@voltagent/sandbox-e2b";
134+
135+
const sandbox = new E2BSandbox({
136+
apiKey: process.env.E2B_API_KEY,
137+
});
138+
139+
const workspace = new Workspace({ sandbox });
140+
141+
const e2bSandbox = await sandbox.getSandbox();
142+
const bytes = await e2bSandbox.files.read("/workspace/file.txt", { format: "bytes" });
143+
```
144+
145+
```ts
146+
import { DaytonaSandbox } from "@voltagent/sandbox-daytona";
147+
148+
const sandbox = new DaytonaSandbox({
149+
apiKey: process.env.DAYTONA_API_KEY,
150+
apiUrl: "http://localhost:3000",
151+
});
152+
153+
const workspace = new Workspace({ sandbox });
154+
155+
const daytonaSandbox = await sandbox.getSandbox();
156+
const response = await daytonaSandbox.process.executeCommand("ls -la");
157+
```
158+
130159
## Custom sandbox provider
131160

132161
You can implement `WorkspaceSandbox` and plug it into `Workspace` directly.

0 commit comments

Comments
 (0)