@sandagent/sandbox-e2b 0.1.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +228 -0
- package/dist/__tests__/e2b-sandbox.test.d.ts +2 -0
- package/dist/__tests__/e2b-sandbox.test.d.ts.map +1 -0
- package/dist/__tests__/e2b-sandbox.test.js +262 -0
- package/dist/__tests__/e2b-sandbox.test.js.map +1 -0
- package/dist/e2b-sandbox.d.ts +139 -0
- package/dist/e2b-sandbox.d.ts.map +1 -0
- package/dist/e2b-sandbox.js +544 -0
- package/dist/e2b-sandbox.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# @sandagent/sandbox-e2b
|
|
2
|
+
|
|
3
|
+
E2B sandbox adapter for SandAgent - run agents in secure cloud sandboxes.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
`@sandagent/sandbox-e2b` provides an E2B-based sandbox implementation for SandAgent. E2B offers secure, isolated cloud environments with:
|
|
8
|
+
|
|
9
|
+
- Fast startup times
|
|
10
|
+
- Persistent storage (up to 30 days when paused)
|
|
11
|
+
- Sandbox reuse by name
|
|
12
|
+
- Support for custom templates
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @sandagent/sandbox-e2b @sandagent/manager
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
You'll also need an E2B API key. Sign up at [e2b.dev](https://e2b.dev) to get one.
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { E2BSandbox } from '@sandagent/sandbox-e2b';
|
|
26
|
+
import { SandAgent } from '@sandagent/manager';
|
|
27
|
+
|
|
28
|
+
// Create sandbox adapter
|
|
29
|
+
// Runner is automatically downloaded from npm if runnerBundlePath is not provided
|
|
30
|
+
const sandbox = new E2BSandbox({
|
|
31
|
+
apiKey: process.env.E2B_API_KEY!,
|
|
32
|
+
template: 'base', // E2B template ID
|
|
33
|
+
env: {
|
|
34
|
+
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!,
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Use with SandAgent
|
|
39
|
+
const agent = new SandAgent({
|
|
40
|
+
sandbox,
|
|
41
|
+
runner: {
|
|
42
|
+
kind: 'claude-agent-sdk',
|
|
43
|
+
model: 'claude-sonnet-4-20250514',
|
|
44
|
+
outputFormat: 'stream',
|
|
45
|
+
},
|
|
46
|
+
env: {
|
|
47
|
+
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!,
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const stream = await agent.stream({
|
|
52
|
+
messages: [{ role: 'user', content: 'Hello!' }],
|
|
53
|
+
workspace: { path: '/workspace' },
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Usage with AI Provider
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import { createSandAgent } from '@sandagent/ai-provider';
|
|
61
|
+
import { E2BSandbox } from '@sandagent/sandbox-e2b';
|
|
62
|
+
import { generateText } from 'ai';
|
|
63
|
+
|
|
64
|
+
// Runner is automatically downloaded from npm
|
|
65
|
+
const sandagent = createSandAgent({
|
|
66
|
+
sandbox: new E2BSandbox({
|
|
67
|
+
apiKey: process.env.E2B_API_KEY!,
|
|
68
|
+
}),
|
|
69
|
+
env: {
|
|
70
|
+
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const { text } = await generateText({
|
|
75
|
+
model: sandagent('sonnet'),
|
|
76
|
+
prompt: 'Create a hello world program',
|
|
77
|
+
});
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Configuration Options
|
|
81
|
+
|
|
82
|
+
### E2BSandboxOptions
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
interface E2BSandboxOptions {
|
|
86
|
+
// Required: E2B API key (or set E2B_API_KEY env var)
|
|
87
|
+
apiKey?: string;
|
|
88
|
+
|
|
89
|
+
// E2B template to use (default: "base")
|
|
90
|
+
template?: string;
|
|
91
|
+
|
|
92
|
+
// Sandbox timeout in seconds (default: 3600 = 1 hour)
|
|
93
|
+
// Hobby tier: max 1 hour, Pro tier: max 24 hours
|
|
94
|
+
timeout?: number;
|
|
95
|
+
|
|
96
|
+
// Path to runner bundle.mjs (optional)
|
|
97
|
+
// If not provided, automatically downloads @sandagent/runner-cli from npm
|
|
98
|
+
runnerBundlePath?: string;
|
|
99
|
+
|
|
100
|
+
// Path to template directory to upload
|
|
101
|
+
templatesPath?: string;
|
|
102
|
+
|
|
103
|
+
// Sandbox name for reuse (optional)
|
|
104
|
+
// If provided, will try to find existing sandbox by name
|
|
105
|
+
name?: string;
|
|
106
|
+
|
|
107
|
+
// Environment variables for the sandbox
|
|
108
|
+
env?: Record<string, string>;
|
|
109
|
+
|
|
110
|
+
// Agent template (default, coder, analyst, researcher)
|
|
111
|
+
agentTemplate?: string;
|
|
112
|
+
|
|
113
|
+
// Working directory inside sandbox (default: '/workspace')
|
|
114
|
+
workdir?: string;
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Sandbox Reuse
|
|
119
|
+
|
|
120
|
+
E2B supports sandbox persistence and reuse:
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
const sandbox = new E2BSandbox({
|
|
124
|
+
apiKey: process.env.E2B_API_KEY!,
|
|
125
|
+
name: 'my-project-sandbox', // Unique name for this sandbox
|
|
126
|
+
// runnerBundlePath is optional - runner is auto-downloaded from npm
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// First call: creates new sandbox
|
|
130
|
+
await sandbox.attach();
|
|
131
|
+
|
|
132
|
+
// Later calls: reuses existing sandbox by name
|
|
133
|
+
await sandbox.attach();
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**E2B Limitations (Beta):**
|
|
137
|
+
- Sandbox can be paused for up to 30 days
|
|
138
|
+
- Continuous runtime limits:
|
|
139
|
+
- Hobby tier: max 1 hour
|
|
140
|
+
- Pro tier: max 24 hours
|
|
141
|
+
- See: https://e2b.dev/docs/sandbox/persistence
|
|
142
|
+
|
|
143
|
+
## Advanced Usage
|
|
144
|
+
|
|
145
|
+
### Custom Templates
|
|
146
|
+
|
|
147
|
+
Upload your own templates to the sandbox:
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
const sandbox = new E2BSandbox({
|
|
151
|
+
apiKey: process.env.E2B_API_KEY!,
|
|
152
|
+
// runnerBundlePath is optional - runner is auto-downloaded from npm
|
|
153
|
+
templatesPath: './templates/coder', // Upload custom template files
|
|
154
|
+
agentTemplate: 'coder',
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Multiple Sandboxes
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
// Development sandbox
|
|
162
|
+
const devSandbox = new E2BSandbox({
|
|
163
|
+
apiKey: process.env.E2B_API_KEY!,
|
|
164
|
+
name: 'dev-sandbox',
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// Production sandbox
|
|
168
|
+
const prodSandbox = new E2BSandbox({
|
|
169
|
+
apiKey: process.env.E2B_API_KEY!,
|
|
170
|
+
name: 'prod-sandbox',
|
|
171
|
+
timeout: 86400, // 24 hours (Pro tier)
|
|
172
|
+
});
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Environment Variables
|
|
176
|
+
|
|
177
|
+
The sandbox accepts environment variables that will be available to all commands:
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
const sandbox = new E2BSandbox({
|
|
181
|
+
apiKey: process.env.E2B_API_KEY!,
|
|
182
|
+
env: {
|
|
183
|
+
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!,
|
|
184
|
+
GITHUB_TOKEN: process.env.GITHUB_TOKEN,
|
|
185
|
+
DATABASE_URL: process.env.DATABASE_URL,
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Requirements
|
|
191
|
+
|
|
192
|
+
- Node.js 20+
|
|
193
|
+
- E2B API key (get one at [e2b.dev](https://e2b.dev))
|
|
194
|
+
- `@sandagent/manager` package
|
|
195
|
+
|
|
196
|
+
**Note:** `@sandagent/runner-cli` is automatically downloaded from npm when the sandbox initializes. You don't need to install it locally unless you want to use a custom bundle.
|
|
197
|
+
|
|
198
|
+
## API Reference
|
|
199
|
+
|
|
200
|
+
### E2BSandbox
|
|
201
|
+
|
|
202
|
+
Implements the `SandboxAdapter` interface from `@sandagent/manager`.
|
|
203
|
+
|
|
204
|
+
#### Methods
|
|
205
|
+
|
|
206
|
+
**attach(): Promise<SandboxHandle>**
|
|
207
|
+
|
|
208
|
+
Attaches to an E2B sandbox. If a name is provided and a sandbox with that name exists, connects to it. Otherwise, creates a new sandbox.
|
|
209
|
+
|
|
210
|
+
**getHandle(): SandboxHandle | null**
|
|
211
|
+
|
|
212
|
+
Returns the current sandbox handle if attached, null otherwise.
|
|
213
|
+
|
|
214
|
+
**getEnv(): Record<string, string>**
|
|
215
|
+
|
|
216
|
+
Returns the environment variables configured for this sandbox.
|
|
217
|
+
|
|
218
|
+
**getAgentTemplate(): string**
|
|
219
|
+
|
|
220
|
+
Returns the agent template name.
|
|
221
|
+
|
|
222
|
+
**getWorkdir(): string**
|
|
223
|
+
|
|
224
|
+
Returns the working directory path.
|
|
225
|
+
|
|
226
|
+
## License
|
|
227
|
+
|
|
228
|
+
Apache-2.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"e2b-sandbox.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/e2b-sandbox.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { E2BSandbox } from "../e2b-sandbox.js";
|
|
3
|
+
describe("E2BSandbox", () => {
|
|
4
|
+
const originalEnv = process.env;
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
process.env = { ...originalEnv };
|
|
7
|
+
vi.clearAllMocks();
|
|
8
|
+
});
|
|
9
|
+
afterEach(() => {
|
|
10
|
+
process.env = originalEnv;
|
|
11
|
+
});
|
|
12
|
+
describe("constructor", () => {
|
|
13
|
+
it("should create an instance with default options", () => {
|
|
14
|
+
const sandbox = new E2BSandbox();
|
|
15
|
+
expect(sandbox).toBeInstanceOf(E2BSandbox);
|
|
16
|
+
});
|
|
17
|
+
it("should accept custom options", () => {
|
|
18
|
+
const sandbox = new E2BSandbox({
|
|
19
|
+
apiKey: "test-api-key",
|
|
20
|
+
template: "python",
|
|
21
|
+
timeout: 7200, // 2 hours in seconds
|
|
22
|
+
});
|
|
23
|
+
expect(sandbox).toBeInstanceOf(E2BSandbox);
|
|
24
|
+
});
|
|
25
|
+
it("should use E2B_API_KEY from environment", () => {
|
|
26
|
+
process.env.E2B_API_KEY = "env-api-key";
|
|
27
|
+
const sandbox = new E2BSandbox();
|
|
28
|
+
expect(sandbox).toBeInstanceOf(E2BSandbox);
|
|
29
|
+
});
|
|
30
|
+
it("should accept name option for sandbox reuse", () => {
|
|
31
|
+
const sandbox = new E2BSandbox({
|
|
32
|
+
apiKey: "test-api-key",
|
|
33
|
+
name: "my-sandbox",
|
|
34
|
+
template: "base",
|
|
35
|
+
});
|
|
36
|
+
expect(sandbox).toBeInstanceOf(E2BSandbox);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
describe("attach", () => {
|
|
40
|
+
it("should implement SandboxAdapter interface", () => {
|
|
41
|
+
const sandbox = new E2BSandbox();
|
|
42
|
+
expect(typeof sandbox.attach).toBe("function");
|
|
43
|
+
});
|
|
44
|
+
it("should throw error when E2B_API_KEY is not set", async () => {
|
|
45
|
+
// Remove API key to test error handling
|
|
46
|
+
delete process.env.E2B_API_KEY;
|
|
47
|
+
const sandbox = new E2BSandbox();
|
|
48
|
+
// Should throw an error about missing API key
|
|
49
|
+
await expect(sandbox.attach()).rejects.toThrow(/E2B API key not found/);
|
|
50
|
+
console.log("[Test Info] E2B_API_KEY not set - this test verifies proper error handling.\n" +
|
|
51
|
+
"To run integration tests with E2B, set E2B_API_KEY environment variable.");
|
|
52
|
+
});
|
|
53
|
+
it("should throw error when SDK is not installed (with API key set)", async () => {
|
|
54
|
+
// Set API key but SDK won't be installed in test environment
|
|
55
|
+
process.env.E2B_API_KEY = "test-api-key";
|
|
56
|
+
const sandbox = new E2BSandbox();
|
|
57
|
+
// Should throw an error (SDK not found or auth error)
|
|
58
|
+
try {
|
|
59
|
+
await sandbox.attach();
|
|
60
|
+
// If we get here, the SDK is installed - that's also valid
|
|
61
|
+
console.log("[Test Info] E2B SDK is installed. Integration tests would run with valid API key.");
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
expect(error).toBeDefined();
|
|
65
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
66
|
+
// Either SDK not found or API error is expected
|
|
67
|
+
console.log(`[Test Info] Expected error: ${errorMessage}\n` +
|
|
68
|
+
"Install e2b package to enable E2B sandbox: npm install e2b");
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
describe("E2BSandbox Configuration", () => {
|
|
74
|
+
it("should support different templates", () => {
|
|
75
|
+
const templates = ["base", "python", "nodejs", "code-interpreter"];
|
|
76
|
+
for (const template of templates) {
|
|
77
|
+
const sandbox = new E2BSandbox({ template });
|
|
78
|
+
expect(sandbox).toBeInstanceOf(E2BSandbox);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
it("should support custom timeouts in seconds", () => {
|
|
82
|
+
// E2B timeout is now in seconds (for API clarity)
|
|
83
|
+
const timeouts = [1800, 3600, 7200, 86400]; // 30min, 1hr, 2hr, 24hr
|
|
84
|
+
for (const timeout of timeouts) {
|
|
85
|
+
const sandbox = new E2BSandbox({ timeout });
|
|
86
|
+
expect(sandbox).toBeInstanceOf(E2BSandbox);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
it("should support name for sandbox reuse", () => {
|
|
90
|
+
const names = ["sandbox-1", "my-project-sandbox", "user-123-sandbox"];
|
|
91
|
+
for (const name of names) {
|
|
92
|
+
const sandbox = new E2BSandbox({ name });
|
|
93
|
+
expect(sandbox).toBeInstanceOf(E2BSandbox);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
it("should use name for sandbox identification (business-defined)", () => {
|
|
97
|
+
// Name is determined by business layer and can include template info if needed
|
|
98
|
+
const sandbox1 = new E2BSandbox({
|
|
99
|
+
name: "project-base-user123",
|
|
100
|
+
template: "base",
|
|
101
|
+
});
|
|
102
|
+
const sandbox2 = new E2BSandbox({
|
|
103
|
+
name: "project-python-user123",
|
|
104
|
+
template: "python",
|
|
105
|
+
});
|
|
106
|
+
expect(sandbox1).toBeInstanceOf(E2BSandbox);
|
|
107
|
+
expect(sandbox2).toBeInstanceOf(E2BSandbox);
|
|
108
|
+
// Different names means different sandboxes
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
describe("E2BSandbox Name-based Reuse", () => {
|
|
112
|
+
it("should support all options together", () => {
|
|
113
|
+
const sandbox = new E2BSandbox({
|
|
114
|
+
apiKey: "test-key",
|
|
115
|
+
template: "nodejs",
|
|
116
|
+
timeout: 3600,
|
|
117
|
+
name: "my-project",
|
|
118
|
+
runnerBundlePath: "/path/to/runner.js",
|
|
119
|
+
templatesPath: "/path/to/templates",
|
|
120
|
+
});
|
|
121
|
+
expect(sandbox).toBeInstanceOf(E2BSandbox);
|
|
122
|
+
});
|
|
123
|
+
it("should create sandbox without name (no reuse)", () => {
|
|
124
|
+
// When no name is provided, a new sandbox is always created
|
|
125
|
+
const sandbox = new E2BSandbox({
|
|
126
|
+
apiKey: "test-key",
|
|
127
|
+
template: "base",
|
|
128
|
+
});
|
|
129
|
+
expect(sandbox).toBeInstanceOf(E2BSandbox);
|
|
130
|
+
});
|
|
131
|
+
it("should support name with special characters", () => {
|
|
132
|
+
const sandbox = new E2BSandbox({
|
|
133
|
+
name: "project-user_123-dev",
|
|
134
|
+
});
|
|
135
|
+
expect(sandbox).toBeInstanceOf(E2BSandbox);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
describe("E2BSandbox Timeout Configuration", () => {
|
|
139
|
+
it("should default to 1 hour (3600 seconds)", () => {
|
|
140
|
+
// The default timeout aligns with E2B hobby tier limits
|
|
141
|
+
const sandbox = new E2BSandbox();
|
|
142
|
+
expect(sandbox).toBeInstanceOf(E2BSandbox);
|
|
143
|
+
});
|
|
144
|
+
it("should accept timeout for pro tier (up to 24 hours)", () => {
|
|
145
|
+
// Pro tier supports up to 24 hours continuous runtime
|
|
146
|
+
const sandbox = new E2BSandbox({
|
|
147
|
+
timeout: 86400, // 24 hours in seconds
|
|
148
|
+
});
|
|
149
|
+
expect(sandbox).toBeInstanceOf(E2BSandbox);
|
|
150
|
+
});
|
|
151
|
+
it("should handle short timeouts", () => {
|
|
152
|
+
const sandbox = new E2BSandbox({
|
|
153
|
+
timeout: 300, // 5 minutes
|
|
154
|
+
});
|
|
155
|
+
expect(sandbox).toBeInstanceOf(E2BSandbox);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
describe("E2BSandbox Metadata Usage", () => {
|
|
159
|
+
it("should document metadata fields used for querying", () => {
|
|
160
|
+
// The sandbox uses these metadata fields:
|
|
161
|
+
// - sandagentId: The session/agent ID
|
|
162
|
+
// - sandagentName: The sandbox name for reuse (if provided, business-defined)
|
|
163
|
+
const sandbox = new E2BSandbox({
|
|
164
|
+
name: "my-project-python-user123", // Name includes all info needed for identification
|
|
165
|
+
template: "python",
|
|
166
|
+
});
|
|
167
|
+
expect(sandbox).toBeInstanceOf(E2BSandbox);
|
|
168
|
+
// When creating, metadata will include:
|
|
169
|
+
// { sandagentId: "...", sandagentName: "my-project-python-user123" }
|
|
170
|
+
// The name is used for sandbox reuse, determined by business layer
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
describe("E2BSandbox Reuse", () => {
|
|
174
|
+
beforeEach(() => {
|
|
175
|
+
process.env.E2B_API_KEY = "test-api-key";
|
|
176
|
+
});
|
|
177
|
+
it("should return same handle when attach() is called multiple times", async () => {
|
|
178
|
+
const sandbox = new E2BSandbox({
|
|
179
|
+
name: "test-reuse-sandbox",
|
|
180
|
+
});
|
|
181
|
+
try {
|
|
182
|
+
const handle1 = await sandbox.attach();
|
|
183
|
+
const handle2 = await sandbox.attach();
|
|
184
|
+
// Should return the same handle instance (cached in currentHandle)
|
|
185
|
+
expect(handle1).toBe(handle2);
|
|
186
|
+
expect(sandbox.getHandle()).toBe(handle1);
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
// Expected in test environment without real API
|
|
190
|
+
expect(error).toBeDefined();
|
|
191
|
+
console.log("[Test Info] E2B API not available - test verifies reuse logic structure");
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
it("should skip initialization when reusing existing sandbox", async () => {
|
|
195
|
+
// This test verifies the reuse logic
|
|
196
|
+
// In a real scenario with E2B API, it would:
|
|
197
|
+
// 1. First call: create new sandbox, needsInit = true
|
|
198
|
+
// 2. Second call (different instance, same name): find existing, needsInit = false
|
|
199
|
+
const sandbox1 = new E2BSandbox({
|
|
200
|
+
name: "test-sandbox-reuse",
|
|
201
|
+
});
|
|
202
|
+
// First attach - would create new sandbox
|
|
203
|
+
try {
|
|
204
|
+
const handle1 = await sandbox1.attach();
|
|
205
|
+
expect(handle1).toBeDefined();
|
|
206
|
+
// If successful, sandbox was created
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
// Expected in test environment without real API
|
|
210
|
+
expect(error).toBeDefined();
|
|
211
|
+
console.log("[Test Info] E2B API not available - test verifies reuse logic structure");
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
it("should create new sandbox when name is not provided", async () => {
|
|
215
|
+
const sandbox1 = new E2BSandbox({
|
|
216
|
+
// No name provided
|
|
217
|
+
});
|
|
218
|
+
const sandbox2 = new E2BSandbox({
|
|
219
|
+
// No name provided
|
|
220
|
+
});
|
|
221
|
+
// Both should be able to attach (would create different sandboxes)
|
|
222
|
+
// In test environment, this will fail without real API, but structure is correct
|
|
223
|
+
expect(sandbox1).toBeInstanceOf(E2BSandbox);
|
|
224
|
+
expect(sandbox2).toBeInstanceOf(E2BSandbox);
|
|
225
|
+
});
|
|
226
|
+
it("should use name for sandbox identification", () => {
|
|
227
|
+
const sandboxName = "my-project-sandbox";
|
|
228
|
+
const sandbox = new E2BSandbox({
|
|
229
|
+
name: sandboxName,
|
|
230
|
+
});
|
|
231
|
+
expect(sandbox).toBeInstanceOf(E2BSandbox);
|
|
232
|
+
// The name is stored and used in attach() to find existing sandbox
|
|
233
|
+
});
|
|
234
|
+
it("should support template-based naming strategy", () => {
|
|
235
|
+
const template = "default";
|
|
236
|
+
const sandboxName = `sandagent-${template}`;
|
|
237
|
+
const sandbox = new E2BSandbox({
|
|
238
|
+
name: sandboxName,
|
|
239
|
+
template,
|
|
240
|
+
});
|
|
241
|
+
expect(sandbox).toBeInstanceOf(E2BSandbox);
|
|
242
|
+
// This matches the pattern used in route.ts
|
|
243
|
+
});
|
|
244
|
+
it("should support user-session-based naming strategy", () => {
|
|
245
|
+
const userId = "user-123";
|
|
246
|
+
const sessionId = "session-456";
|
|
247
|
+
const sandboxName = `user-${userId}-session-${sessionId}`;
|
|
248
|
+
const sandbox = new E2BSandbox({
|
|
249
|
+
name: sandboxName,
|
|
250
|
+
});
|
|
251
|
+
expect(sandbox).toBeInstanceOf(E2BSandbox);
|
|
252
|
+
});
|
|
253
|
+
it("should support project-based naming strategy", () => {
|
|
254
|
+
const projectId = "project-789";
|
|
255
|
+
const sandboxName = `project-${projectId}`;
|
|
256
|
+
const sandbox = new E2BSandbox({
|
|
257
|
+
name: sandboxName,
|
|
258
|
+
});
|
|
259
|
+
expect(sandbox).toBeInstanceOf(E2BSandbox);
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
//# sourceMappingURL=e2b-sandbox.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"e2b-sandbox.test.js","sourceRoot":"","sources":["../../src/__tests__/e2b-sandbox.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import type { SandboxAdapter, SandboxHandle } from "@sandagent/manager";
|
|
2
|
+
/**
|
|
3
|
+
* Options for creating an E2BSandbox instance
|
|
4
|
+
*/
|
|
5
|
+
export interface E2BSandboxOptions {
|
|
6
|
+
/** E2B API key (defaults to E2B_API_KEY env var) */
|
|
7
|
+
apiKey?: string;
|
|
8
|
+
/** E2B template to use (default: "base") */
|
|
9
|
+
template?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Timeout for sandbox in seconds.
|
|
12
|
+
* This is the maximum time the sandbox can run continuously.
|
|
13
|
+
* - Hobby tier: max 1 hour (3600s)
|
|
14
|
+
* - Pro tier: max 24 hours (86400s)
|
|
15
|
+
* Default: 3600 (1 hour)
|
|
16
|
+
*
|
|
17
|
+
* Note: Sandbox can be paused for up to 30 days with E2B's persistence feature.
|
|
18
|
+
*/
|
|
19
|
+
timeout?: number;
|
|
20
|
+
/** Path to runner bundle.js (required for running sandagent) */
|
|
21
|
+
runnerBundlePath?: string;
|
|
22
|
+
/** Path to template directory to upload */
|
|
23
|
+
templatesPath?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Sandbox name for reuse (similar to Daytona).
|
|
26
|
+
* If provided, will try to find an existing sandbox by name (via metadata) first.
|
|
27
|
+
* If not found, creates a new sandbox with this name stored in metadata.
|
|
28
|
+
* If not provided, a new sandbox is always created.
|
|
29
|
+
*
|
|
30
|
+
* The name should be determined by the business layer and can include
|
|
31
|
+
* template/user/project information as needed for differentiation.
|
|
32
|
+
*/
|
|
33
|
+
name?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Environment variables to set in the sandbox.
|
|
36
|
+
* These will be available to all commands executed in the sandbox.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* env: {
|
|
41
|
+
* ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!,
|
|
42
|
+
* GITHUB_TOKEN: process.env.GITHUB_TOKEN,
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
env?: Record<string, string>;
|
|
47
|
+
/**
|
|
48
|
+
* Agent template to use (e.g., "default", "coder", "analyst", "researcher").
|
|
49
|
+
* This is different from the E2B sandbox template.
|
|
50
|
+
*
|
|
51
|
+
* @default 'default'
|
|
52
|
+
*/
|
|
53
|
+
agentTemplate?: string;
|
|
54
|
+
/**
|
|
55
|
+
* Working directory for the agent inside the sandbox.
|
|
56
|
+
* Will be created if it doesn't exist.
|
|
57
|
+
*
|
|
58
|
+
* @default '/workspace'
|
|
59
|
+
*/
|
|
60
|
+
workdir?: string;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* E2B-based sandbox implementation.
|
|
64
|
+
*
|
|
65
|
+
* This adapter supports sandbox reuse based on sandbox name (similar to Daytona).
|
|
66
|
+
* When a name is provided, it will attempt to find an existing sandbox
|
|
67
|
+
* by that name (stored in metadata) first. If not found, creates a new sandbox
|
|
68
|
+
* with that name in metadata.
|
|
69
|
+
*
|
|
70
|
+
* If no name is provided, a new sandbox is always created.
|
|
71
|
+
*
|
|
72
|
+
* Note on E2B limitations (as of beta):
|
|
73
|
+
* - Sandbox can be paused for up to 30 days
|
|
74
|
+
* - Continuous runtime depends on tier:
|
|
75
|
+
* - Hobby: max 1 hour
|
|
76
|
+
* - Pro: max 24 hours
|
|
77
|
+
* - See: https://e2b.dev/docs/sandbox/persistence#limitations-while-in-beta
|
|
78
|
+
*/
|
|
79
|
+
export declare class E2BSandbox implements SandboxAdapter {
|
|
80
|
+
private readonly apiKey?;
|
|
81
|
+
private readonly template;
|
|
82
|
+
private readonly timeout;
|
|
83
|
+
private readonly runnerBundlePath?;
|
|
84
|
+
private readonly templatesPath?;
|
|
85
|
+
private readonly name?;
|
|
86
|
+
private readonly env;
|
|
87
|
+
private readonly agentTemplate;
|
|
88
|
+
private readonly workdir;
|
|
89
|
+
/** Current handle for the sandbox instance */
|
|
90
|
+
private currentHandle;
|
|
91
|
+
/** Default timeout in seconds (1 hour for hobby tier) */
|
|
92
|
+
private static readonly DEFAULT_TIMEOUT_SEC;
|
|
93
|
+
/** Custom template prefix - templates starting with this have pre-installed dependencies */
|
|
94
|
+
private static readonly CUSTOM_TEMPLATE_PREFIX;
|
|
95
|
+
constructor(options?: E2BSandboxOptions);
|
|
96
|
+
/** Default E2B templates that don't have pre-installed dependencies */
|
|
97
|
+
private static readonly DEFAULT_TEMPLATES;
|
|
98
|
+
/**
|
|
99
|
+
* Check if using a custom sandagent template with pre-installed dependencies.
|
|
100
|
+
* Custom templates either:
|
|
101
|
+
* - Start with "sandagent" prefix (alias)
|
|
102
|
+
* - Are not in the default templates list (template ID)
|
|
103
|
+
*/
|
|
104
|
+
private isCustomTemplate;
|
|
105
|
+
/**
|
|
106
|
+
* Get the environment variables configured for this sandbox.
|
|
107
|
+
*/
|
|
108
|
+
getEnv(): Record<string, string>;
|
|
109
|
+
/**
|
|
110
|
+
* Get the agent template configured for this sandbox.
|
|
111
|
+
*/
|
|
112
|
+
getAgentTemplate(): string;
|
|
113
|
+
/**
|
|
114
|
+
* Get the working directory configured for this sandbox.
|
|
115
|
+
*/
|
|
116
|
+
getWorkdir(): string;
|
|
117
|
+
/**
|
|
118
|
+
* Get the runner command to execute in the sandbox.
|
|
119
|
+
* Returns different commands based on whether a local bundle or npm package is used.
|
|
120
|
+
*/
|
|
121
|
+
getRunnerCommand(): string[];
|
|
122
|
+
/**
|
|
123
|
+
* Find an existing sandbox by name and connect to it.
|
|
124
|
+
* Sandbox.connect() will automatically resume if paused.
|
|
125
|
+
* See: https://e2b.dev/docs/sandbox/persistence
|
|
126
|
+
*
|
|
127
|
+
* @returns Connected sandbox instance if found, null otherwise
|
|
128
|
+
*/
|
|
129
|
+
private findSandboxByName;
|
|
130
|
+
getHandle(): SandboxHandle | null;
|
|
131
|
+
attach(): Promise<SandboxHandle>;
|
|
132
|
+
/**
|
|
133
|
+
* Create a new sandbox with metadata for later querying
|
|
134
|
+
*/
|
|
135
|
+
private createNewSandbox;
|
|
136
|
+
private initializeSandbox;
|
|
137
|
+
private collectFiles;
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=e2b-sandbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"e2b-sandbox.d.ts","sourceRoot":"","sources":["../src/e2b-sandbox.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,cAAc,EACd,aAAa,EACd,MAAM,oBAAoB,CAAC;AAG5B;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,2CAA2C;IAC3C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;;;;;;;;;OAWG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE7B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,UAAW,YAAW,cAAc;IAC/C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAyB;IAC7C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IAEjC,8CAA8C;IAC9C,OAAO,CAAC,aAAa,CAA8B;IAEnD,yDAAyD;IACzD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAQ;IAEnD,4FAA4F;IAC5F,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAAe;gBAEjD,OAAO,GAAE,iBAAsB;IAa3C,uEAAuE;IACvE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAmC;IAE5E;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;IASxB;;OAEG;IACH,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAIhC;;OAEG;IACH,gBAAgB,IAAI,MAAM;IAI1B;;OAEG;IACH,UAAU,IAAI,MAAM;IAIpB;;;OAGG;IACH,gBAAgB,IAAI,MAAM,EAAE;IAa5B;;;;;;OAMG;YACW,iBAAiB;IAyC/B,SAAS,IAAI,aAAa,GAAG,IAAI;IAI3B,MAAM,IAAI,OAAO,CAAC,aAAa,CAAC;IAqDtC;;OAEG;YACW,gBAAgB;YAyBhB,iBAAiB;IAkH/B,OAAO,CAAC,YAAY;CA2BrB"}
|
|
@@ -0,0 +1,544 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { Sandbox } from "e2b";
|
|
4
|
+
/**
|
|
5
|
+
* E2B-based sandbox implementation.
|
|
6
|
+
*
|
|
7
|
+
* This adapter supports sandbox reuse based on sandbox name (similar to Daytona).
|
|
8
|
+
* When a name is provided, it will attempt to find an existing sandbox
|
|
9
|
+
* by that name (stored in metadata) first. If not found, creates a new sandbox
|
|
10
|
+
* with that name in metadata.
|
|
11
|
+
*
|
|
12
|
+
* If no name is provided, a new sandbox is always created.
|
|
13
|
+
*
|
|
14
|
+
* Note on E2B limitations (as of beta):
|
|
15
|
+
* - Sandbox can be paused for up to 30 days
|
|
16
|
+
* - Continuous runtime depends on tier:
|
|
17
|
+
* - Hobby: max 1 hour
|
|
18
|
+
* - Pro: max 24 hours
|
|
19
|
+
* - See: https://e2b.dev/docs/sandbox/persistence#limitations-while-in-beta
|
|
20
|
+
*/
|
|
21
|
+
export class E2BSandbox {
|
|
22
|
+
apiKey;
|
|
23
|
+
template;
|
|
24
|
+
timeout;
|
|
25
|
+
runnerBundlePath;
|
|
26
|
+
templatesPath;
|
|
27
|
+
name;
|
|
28
|
+
env;
|
|
29
|
+
agentTemplate;
|
|
30
|
+
workdir;
|
|
31
|
+
/** Current handle for the sandbox instance */
|
|
32
|
+
currentHandle = null;
|
|
33
|
+
/** Default timeout in seconds (1 hour for hobby tier) */
|
|
34
|
+
static DEFAULT_TIMEOUT_SEC = 3600;
|
|
35
|
+
/** Custom template prefix - templates starting with this have pre-installed dependencies */
|
|
36
|
+
static CUSTOM_TEMPLATE_PREFIX = "sandagent";
|
|
37
|
+
constructor(options = {}) {
|
|
38
|
+
this.apiKey = options.apiKey ?? process.env.E2B_API_KEY;
|
|
39
|
+
this.template = options.template ?? "base";
|
|
40
|
+
// Default to 1 hour (hobby tier limit), convert to milliseconds for E2B SDK
|
|
41
|
+
this.timeout = (options.timeout ?? E2BSandbox.DEFAULT_TIMEOUT_SEC) * 1000;
|
|
42
|
+
this.runnerBundlePath = options.runnerBundlePath;
|
|
43
|
+
this.templatesPath = options.templatesPath;
|
|
44
|
+
this.name = options.name;
|
|
45
|
+
this.env = options.env ?? {};
|
|
46
|
+
this.agentTemplate = options.agentTemplate ?? "default";
|
|
47
|
+
this.workdir = options.workdir ?? "/workspace";
|
|
48
|
+
}
|
|
49
|
+
/** Default E2B templates that don't have pre-installed dependencies */
|
|
50
|
+
static DEFAULT_TEMPLATES = ["base", "code-interpreter-v1"];
|
|
51
|
+
/**
|
|
52
|
+
* Check if using a custom sandagent template with pre-installed dependencies.
|
|
53
|
+
* Custom templates either:
|
|
54
|
+
* - Start with "sandagent" prefix (alias)
|
|
55
|
+
* - Are not in the default templates list (template ID)
|
|
56
|
+
*/
|
|
57
|
+
isCustomTemplate() {
|
|
58
|
+
// If starts with sandagent prefix, it's definitely custom
|
|
59
|
+
if (this.template.startsWith(E2BSandbox.CUSTOM_TEMPLATE_PREFIX)) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
// If not a known default template, assume it's a custom template ID
|
|
63
|
+
return !E2BSandbox.DEFAULT_TEMPLATES.includes(this.template);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Get the environment variables configured for this sandbox.
|
|
67
|
+
*/
|
|
68
|
+
getEnv() {
|
|
69
|
+
return this.env;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Get the agent template configured for this sandbox.
|
|
73
|
+
*/
|
|
74
|
+
getAgentTemplate() {
|
|
75
|
+
return this.agentTemplate;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Get the working directory configured for this sandbox.
|
|
79
|
+
*/
|
|
80
|
+
getWorkdir() {
|
|
81
|
+
return this.workdir;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Get the runner command to execute in the sandbox.
|
|
85
|
+
* Returns different commands based on whether a local bundle or npm package is used.
|
|
86
|
+
*/
|
|
87
|
+
getRunnerCommand() {
|
|
88
|
+
if (this.runnerBundlePath && fs.existsSync(this.runnerBundlePath)) {
|
|
89
|
+
// Local bundle is uploaded to ${workdir}/runner/bundle.mjs
|
|
90
|
+
return ["node", `${this.workdir}/runner/bundle.mjs`, "run"];
|
|
91
|
+
}
|
|
92
|
+
if (this.isCustomTemplate()) {
|
|
93
|
+
// Custom template has sandagent as system command in /usr/local/bin
|
|
94
|
+
return ["sandagent", "run"];
|
|
95
|
+
}
|
|
96
|
+
// npm installed runner-cli in workspace
|
|
97
|
+
return [`${this.workdir}/node_modules/.bin/sandagent`, "run"];
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Find an existing sandbox by name and connect to it.
|
|
101
|
+
* Sandbox.connect() will automatically resume if paused.
|
|
102
|
+
* See: https://e2b.dev/docs/sandbox/persistence
|
|
103
|
+
*
|
|
104
|
+
* @returns Connected sandbox instance if found, null otherwise
|
|
105
|
+
*/
|
|
106
|
+
async findSandboxByName(name) {
|
|
107
|
+
try {
|
|
108
|
+
// Use Sandbox.list() with metadata query
|
|
109
|
+
const paginator = Sandbox.list({
|
|
110
|
+
apiKey: this.apiKey,
|
|
111
|
+
query: {
|
|
112
|
+
metadata: {
|
|
113
|
+
sandagentName: name,
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
// Get the first page of results
|
|
118
|
+
const sandboxes = await paginator.nextItems();
|
|
119
|
+
if (sandboxes.length === 0) {
|
|
120
|
+
console.log(`[E2B] No existing sandbox found for name: ${name}`);
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
const sandboxInfo = sandboxes[0];
|
|
124
|
+
console.log(`[E2B] Found existing sandbox by name: ${name}, id: ${sandboxInfo.sandboxId}, state: ${sandboxInfo.state}`);
|
|
125
|
+
// Connect to sandbox (will auto-resume if paused)
|
|
126
|
+
const sandbox = await Sandbox.connect(sandboxInfo.sandboxId, {
|
|
127
|
+
apiKey: this.apiKey,
|
|
128
|
+
timeoutMs: this.timeout,
|
|
129
|
+
});
|
|
130
|
+
console.log(`[E2B] Successfully connected to sandbox: ${sandboxInfo.sandboxId}`);
|
|
131
|
+
return sandbox;
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
console.warn(`[E2B] Failed to find/connect sandbox by name:`, error);
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
getHandle() {
|
|
139
|
+
return this.currentHandle;
|
|
140
|
+
}
|
|
141
|
+
async attach() {
|
|
142
|
+
if (!this.apiKey) {
|
|
143
|
+
throw new Error("E2B API key not found. Please set E2B_API_KEY environment variable or pass apiKey option.");
|
|
144
|
+
}
|
|
145
|
+
// Return existing handle if already attached
|
|
146
|
+
if (this.currentHandle) {
|
|
147
|
+
return this.currentHandle;
|
|
148
|
+
}
|
|
149
|
+
let instance;
|
|
150
|
+
let needsInit = false;
|
|
151
|
+
// Use this.name if provided
|
|
152
|
+
const sandboxName = this.name;
|
|
153
|
+
// If name is provided, try to find and connect to existing sandbox
|
|
154
|
+
if (sandboxName) {
|
|
155
|
+
console.log(`[E2B] Looking for existing sandbox with name: ${sandboxName}`);
|
|
156
|
+
const existingSandbox = await this.findSandboxByName(sandboxName);
|
|
157
|
+
if (existingSandbox) {
|
|
158
|
+
instance = existingSandbox;
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
// No existing sandbox found or connection failed, create new one
|
|
162
|
+
instance = await this.createNewSandbox(sandboxName);
|
|
163
|
+
needsInit = true;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
// No name provided - always create new sandbox
|
|
168
|
+
console.log(`[E2B] No name provided, creating new sandbox`);
|
|
169
|
+
instance = await this.createNewSandbox();
|
|
170
|
+
needsInit = true;
|
|
171
|
+
}
|
|
172
|
+
const handle = new E2BHandle(instance, this.env);
|
|
173
|
+
// Initialize sandbox if it's new (upload files, install dependencies)
|
|
174
|
+
if (needsInit) {
|
|
175
|
+
await this.initializeSandbox(handle);
|
|
176
|
+
}
|
|
177
|
+
// Store the handle
|
|
178
|
+
this.currentHandle = handle;
|
|
179
|
+
return handle;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Create a new sandbox with metadata for later querying
|
|
183
|
+
*/
|
|
184
|
+
async createNewSandbox(name) {
|
|
185
|
+
const metadata = {};
|
|
186
|
+
// Use provided name or fallback to this.name
|
|
187
|
+
const sandboxName = name || this.name;
|
|
188
|
+
// Add name to metadata if provided (for sandbox reuse)
|
|
189
|
+
if (sandboxName) {
|
|
190
|
+
metadata.sandagentName = sandboxName;
|
|
191
|
+
}
|
|
192
|
+
console.log(`[E2B] Creating new sandbox with template "${this.template}"${sandboxName ? `, name "${sandboxName}"` : ""}, timeout=${this.timeout / 1000}s`);
|
|
193
|
+
const instance = await Sandbox.create(this.template, {
|
|
194
|
+
apiKey: this.apiKey,
|
|
195
|
+
timeoutMs: this.timeout,
|
|
196
|
+
metadata,
|
|
197
|
+
});
|
|
198
|
+
console.log(`[E2B] Sandbox created: ${instance.sandboxId}`);
|
|
199
|
+
return instance;
|
|
200
|
+
}
|
|
201
|
+
async initializeSandbox(handle) {
|
|
202
|
+
// Step 0: Create workspace directory using E2B file API
|
|
203
|
+
console.log(`[E2B] Creating workspace directory: ${this.workdir}`);
|
|
204
|
+
try {
|
|
205
|
+
await handle.getInstance().files.makeDir(this.workdir);
|
|
206
|
+
}
|
|
207
|
+
catch (err) {
|
|
208
|
+
// Directory might already exist, ignore
|
|
209
|
+
console.log(`[E2B] mkdir warning (may already exist): ${err}`);
|
|
210
|
+
}
|
|
211
|
+
// If using custom template with pre-installed dependencies, skip npm installs
|
|
212
|
+
if (this.isCustomTemplate()) {
|
|
213
|
+
console.log(`[E2B] Using custom template "${this.template}", skipping dependency installs`);
|
|
214
|
+
// Ensure workspace has correct permissions
|
|
215
|
+
try {
|
|
216
|
+
await handle.runCommand(`chmod 777 ${this.workdir} 2>/dev/null || true`);
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
// Ignore permission errors
|
|
220
|
+
}
|
|
221
|
+
// Copy template files from /opt/sandagent/templates if exists (similar to Daytona)
|
|
222
|
+
try {
|
|
223
|
+
const copyTemplateResult = await handle.runCommand(`if [ -d "/opt/sandagent/templates" ]; then ` +
|
|
224
|
+
`cp -r /opt/sandagent/templates/. ${this.workdir}/ 2>&1 && ` +
|
|
225
|
+
`echo "Template files copied"; ` +
|
|
226
|
+
`else echo "No templates in image"; fi`);
|
|
227
|
+
if (copyTemplateResult.stdout) {
|
|
228
|
+
console.log(`[E2B] ${copyTemplateResult.stdout.trim()}`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
catch (err) {
|
|
232
|
+
const error = err;
|
|
233
|
+
console.log(`[E2B] Template copy warning: ${error.result?.stderr || error.result?.stdout || "unknown error"}`);
|
|
234
|
+
// Not fatal - templates might be uploaded via templatesPath instead
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
// Step 1: Install claude-agent-sdk to workspace
|
|
239
|
+
console.log(`[E2B] Installing @anthropic-ai/claude-agent-sdk to ${this.workdir}`);
|
|
240
|
+
const sdkInstallResult = await handle.runCommand(`cd ${this.workdir} && npm install @anthropic-ai/claude-agent-sdk`);
|
|
241
|
+
if (sdkInstallResult.exitCode !== 0) {
|
|
242
|
+
console.error(`[E2B] Failed to install claude-agent-sdk: ${sdkInstallResult.stderr}`);
|
|
243
|
+
throw new Error(`Failed to install @anthropic-ai/claude-agent-sdk: ${sdkInstallResult.stderr}`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
// Step 2: Setup runner - either upload local bundle, use pre-installed, or install from npm
|
|
247
|
+
if (this.runnerBundlePath && fs.existsSync(this.runnerBundlePath)) {
|
|
248
|
+
// Option A: Upload local runner bundle to workspace
|
|
249
|
+
const bundleContent = fs.readFileSync(this.runnerBundlePath);
|
|
250
|
+
const bundleFileName = path.basename(this.runnerBundlePath);
|
|
251
|
+
const runnerFiles = [
|
|
252
|
+
{
|
|
253
|
+
path: `runner/${bundleFileName}`,
|
|
254
|
+
content: bundleContent,
|
|
255
|
+
},
|
|
256
|
+
];
|
|
257
|
+
console.log(`[E2B] Uploading runner bundle (${bundleFileName}) to ${this.workdir}`);
|
|
258
|
+
await handle.upload(runnerFiles, this.workdir);
|
|
259
|
+
console.log(`[E2B] Runner bundle uploaded`);
|
|
260
|
+
}
|
|
261
|
+
else if (this.isCustomTemplate()) {
|
|
262
|
+
// Option B: Using custom template - runner-cli is pre-installed
|
|
263
|
+
console.log(`[E2B] Using pre-installed runner-cli from template`);
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
// Option C: Install runner-cli to workspace from npm
|
|
267
|
+
console.log(`[E2B] No runnerBundlePath provided, installing @sandagent/runner-cli to ${this.workdir}`);
|
|
268
|
+
const installResult = await handle.runCommand(`cd ${this.workdir} && npm install @sandagent/runner-cli@beta`);
|
|
269
|
+
if (installResult.exitCode !== 0) {
|
|
270
|
+
console.error(`[E2B] Failed to install runner-cli: ${installResult.stderr}`);
|
|
271
|
+
throw new Error(`Failed to install @sandagent/runner-cli: ${installResult.stderr}`);
|
|
272
|
+
}
|
|
273
|
+
console.log(`[E2B] Successfully installed @sandagent/runner-cli to ${this.workdir}`);
|
|
274
|
+
}
|
|
275
|
+
// Upload template to workdir (where runner will execute)
|
|
276
|
+
if (this.templatesPath && fs.existsSync(this.templatesPath)) {
|
|
277
|
+
const templateFiles = this.collectFiles(this.templatesPath, "");
|
|
278
|
+
console.log(`[E2B] Uploading ${templateFiles.length} template files to ${this.workdir}`);
|
|
279
|
+
await handle.upload(templateFiles, this.workdir);
|
|
280
|
+
}
|
|
281
|
+
else if (this.templatesPath) {
|
|
282
|
+
console.warn(`[E2B] Template path not found: ${this.templatesPath}, skipping`);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
collectFiles(dir, prefix) {
|
|
286
|
+
const files = [];
|
|
287
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
288
|
+
for (const entry of entries) {
|
|
289
|
+
const fullPath = path.join(dir, entry.name);
|
|
290
|
+
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
291
|
+
if (entry.isDirectory()) {
|
|
292
|
+
// Skip node_modules and .git only
|
|
293
|
+
if (entry.name === "node_modules" || entry.name === ".git") {
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
files.push(...this.collectFiles(fullPath, relativePath));
|
|
297
|
+
}
|
|
298
|
+
else if (entry.isFile()) {
|
|
299
|
+
files.push({
|
|
300
|
+
path: relativePath,
|
|
301
|
+
content: fs.readFileSync(fullPath),
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return files;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Handle for an active E2B sandbox
|
|
310
|
+
*/
|
|
311
|
+
class E2BHandle {
|
|
312
|
+
instance;
|
|
313
|
+
sandboxEnv;
|
|
314
|
+
workdir;
|
|
315
|
+
constructor(instance, sandboxEnv = {}, workdir = "/workspace") {
|
|
316
|
+
this.instance = instance;
|
|
317
|
+
this.sandboxEnv = sandboxEnv;
|
|
318
|
+
this.workdir = workdir;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Get the sandbox ID (useful for external tracking)
|
|
322
|
+
*/
|
|
323
|
+
getSandboxId() {
|
|
324
|
+
return this.instance.sandboxId;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Get the underlying E2B sandbox instance
|
|
328
|
+
*/
|
|
329
|
+
getInstance() {
|
|
330
|
+
return this.instance;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Escape a string for safe use in shell commands
|
|
334
|
+
* Uses single quotes and escapes any single quotes within the string
|
|
335
|
+
*/
|
|
336
|
+
shellEscape(arg) {
|
|
337
|
+
// If the argument contains no special characters, return as-is
|
|
338
|
+
if (/^[a-zA-Z0-9._\-\/=]+$/.test(arg)) {
|
|
339
|
+
return arg;
|
|
340
|
+
}
|
|
341
|
+
// Wrap in single quotes and escape any single quotes within
|
|
342
|
+
// Replace ' with '\'' (end quote, escaped quote, start quote)
|
|
343
|
+
return `'${arg.replace(/'/g, "'\\''")}'`;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Build a shell-safe command string from an array of arguments
|
|
347
|
+
*/
|
|
348
|
+
buildShellCommand(command) {
|
|
349
|
+
return command.map((arg) => this.shellEscape(arg)).join(" ");
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Run a command and wait for completion (used internally)
|
|
353
|
+
*/
|
|
354
|
+
async runCommand(cmd) {
|
|
355
|
+
return this.instance.commands.run(cmd);
|
|
356
|
+
}
|
|
357
|
+
exec(command, opts) {
|
|
358
|
+
const self = this;
|
|
359
|
+
const signal = opts?.signal;
|
|
360
|
+
// Merge sandbox-level env with call-level env (call-level takes precedence)
|
|
361
|
+
// Add NODE_PATH so Node can find packages, and PATH to find bin commands
|
|
362
|
+
const envWithNodePath = {
|
|
363
|
+
...this.sandboxEnv,
|
|
364
|
+
...opts?.env,
|
|
365
|
+
NODE_PATH: `${this.workdir}/node_modules`,
|
|
366
|
+
PATH: `${this.workdir}/node_modules/.bin:/usr/local/bin:/usr/bin:/bin`,
|
|
367
|
+
};
|
|
368
|
+
// Build shell-safe command string with proper escaping
|
|
369
|
+
const baseCommand = this.buildShellCommand(command);
|
|
370
|
+
// Build export statements for all env vars
|
|
371
|
+
const envExports = Object.entries(envWithNodePath)
|
|
372
|
+
.filter(([key]) => key === "NODE_PATH" || key === "PATH")
|
|
373
|
+
.map(([key, value]) => `export ${key}="${value.replace(/"/g, '\\"')}"`)
|
|
374
|
+
.join(" && ");
|
|
375
|
+
// Wrap command to capture PID for potential termination
|
|
376
|
+
const pidFile = `/tmp/sandagent-${Date.now()}-${Math.random().toString(36).substring(7)}.pid`;
|
|
377
|
+
const shellCommand = `(${envExports} && ${baseCommand}) & echo $! > ${pidFile}; wait $!; EXIT_CODE=$?; rm -f ${pidFile}; exit $EXIT_CODE`;
|
|
378
|
+
// Debug: log environment variables being passed to sandbox
|
|
379
|
+
console.log("[E2B] Executing command:", baseCommand);
|
|
380
|
+
console.log("[E2B] PID file:", pidFile);
|
|
381
|
+
console.log("[E2B] Environment variables:", Object.keys(envWithNodePath));
|
|
382
|
+
console.log("[E2B] ANTHROPIC_API_KEY present:", !!envWithNodePath.ANTHROPIC_API_KEY);
|
|
383
|
+
if (envWithNodePath.ANTHROPIC_API_KEY) {
|
|
384
|
+
console.log("[E2B] ANTHROPIC_API_KEY prefix:", envWithNodePath.ANTHROPIC_API_KEY.substring(0, 10) + "...");
|
|
385
|
+
}
|
|
386
|
+
return {
|
|
387
|
+
[Symbol.asyncIterator]() {
|
|
388
|
+
const chunks = [];
|
|
389
|
+
let finished = false;
|
|
390
|
+
let error = null;
|
|
391
|
+
let resolveNext = null;
|
|
392
|
+
// Monitor abort signal and kill the process
|
|
393
|
+
const abortHandler = async () => {
|
|
394
|
+
console.log("[E2B] Abort signal received, terminating process...");
|
|
395
|
+
console.log("[E2B] PID file:", pidFile);
|
|
396
|
+
finished = true;
|
|
397
|
+
error = new Error("Operation aborted");
|
|
398
|
+
error.name = "AbortError";
|
|
399
|
+
// Try to kill the process using the PID file
|
|
400
|
+
try {
|
|
401
|
+
// Check if PID file exists and kill the process
|
|
402
|
+
const killCmd = `if [ -f ${pidFile} ]; then PID=$(cat ${pidFile}); echo "Killing PID: $PID"; kill -TERM $PID 2>&1 || echo "Kill failed"; rm -f ${pidFile}; else echo "No PID file found"; fi`;
|
|
403
|
+
// Execute kill command asynchronously (don't wait for result)
|
|
404
|
+
self.instance.commands
|
|
405
|
+
.run(killCmd, {
|
|
406
|
+
timeoutMs: 5000,
|
|
407
|
+
})
|
|
408
|
+
.then((result) => {
|
|
409
|
+
console.log("[E2B] Kill command output:", result.stdout);
|
|
410
|
+
if (result.stderr) {
|
|
411
|
+
console.log("[E2B] Kill command stderr:", result.stderr);
|
|
412
|
+
}
|
|
413
|
+
})
|
|
414
|
+
.catch((err) => {
|
|
415
|
+
console.error("[E2B] Failed to execute kill command:", err);
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
catch (err) {
|
|
419
|
+
console.error("[E2B] Failed to send termination signal:", err);
|
|
420
|
+
}
|
|
421
|
+
if (resolveNext) {
|
|
422
|
+
resolveNext();
|
|
423
|
+
resolveNext = null;
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
if (signal) {
|
|
427
|
+
console.log("[E2B] Adding abort signal listener");
|
|
428
|
+
signal.addEventListener("abort", abortHandler);
|
|
429
|
+
}
|
|
430
|
+
else {
|
|
431
|
+
console.log("[E2B] No signal provided");
|
|
432
|
+
}
|
|
433
|
+
const commandPromise = self.instance.commands.run(shellCommand, {
|
|
434
|
+
cwd: opts?.cwd,
|
|
435
|
+
envs: envWithNodePath,
|
|
436
|
+
timeoutMs: 0, // 0 = no timeout for LLM operations
|
|
437
|
+
onStdout: (data) => {
|
|
438
|
+
const chunk = new TextEncoder().encode(data);
|
|
439
|
+
chunks.push(chunk);
|
|
440
|
+
if (resolveNext) {
|
|
441
|
+
resolveNext();
|
|
442
|
+
resolveNext = null;
|
|
443
|
+
}
|
|
444
|
+
},
|
|
445
|
+
onStderr: (data) => {
|
|
446
|
+
console.error(`[E2B stderr] ${data}`);
|
|
447
|
+
},
|
|
448
|
+
});
|
|
449
|
+
commandPromise
|
|
450
|
+
.then((result) => {
|
|
451
|
+
console.log("[E2B] Command completed with exit code:", result.exitCode);
|
|
452
|
+
finished = true;
|
|
453
|
+
if (resolveNext) {
|
|
454
|
+
resolveNext();
|
|
455
|
+
resolveNext = null;
|
|
456
|
+
}
|
|
457
|
+
})
|
|
458
|
+
.catch((err) => {
|
|
459
|
+
error = err instanceof Error ? err : new Error(String(err));
|
|
460
|
+
// Log AbortError appropriately
|
|
461
|
+
if (error.name === "AbortError") {
|
|
462
|
+
console.log("[E2B] Command execution aborted by user");
|
|
463
|
+
}
|
|
464
|
+
else {
|
|
465
|
+
console.error("[E2B] Command execution error:", error.message);
|
|
466
|
+
}
|
|
467
|
+
if (resolveNext) {
|
|
468
|
+
resolveNext();
|
|
469
|
+
resolveNext = null;
|
|
470
|
+
}
|
|
471
|
+
})
|
|
472
|
+
.finally(() => {
|
|
473
|
+
// Remove event listener when iterator completes
|
|
474
|
+
if (signal) {
|
|
475
|
+
signal.removeEventListener("abort", abortHandler);
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
return {
|
|
479
|
+
async next() {
|
|
480
|
+
// Check if signal is aborted and no more chunks
|
|
481
|
+
if (signal?.aborted && chunks.length === 0) {
|
|
482
|
+
console.log("[E2B] Signal aborted, stopping iteration");
|
|
483
|
+
return { value: undefined, done: true };
|
|
484
|
+
}
|
|
485
|
+
if (chunks.length > 0) {
|
|
486
|
+
return { value: chunks.shift(), done: false };
|
|
487
|
+
}
|
|
488
|
+
if (finished && chunks.length === 0) {
|
|
489
|
+
return { value: undefined, done: true };
|
|
490
|
+
}
|
|
491
|
+
if (error) {
|
|
492
|
+
throw error;
|
|
493
|
+
}
|
|
494
|
+
await new Promise((resolve) => {
|
|
495
|
+
resolveNext = resolve;
|
|
496
|
+
});
|
|
497
|
+
if (chunks.length > 0) {
|
|
498
|
+
return { value: chunks.shift(), done: false };
|
|
499
|
+
}
|
|
500
|
+
if (error) {
|
|
501
|
+
throw error;
|
|
502
|
+
}
|
|
503
|
+
return { value: undefined, done: true };
|
|
504
|
+
},
|
|
505
|
+
};
|
|
506
|
+
},
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
async upload(files, targetDir) {
|
|
510
|
+
for (const file of files) {
|
|
511
|
+
const fullPath = `${targetDir}/${file.path}`;
|
|
512
|
+
const dirPath = fullPath.substring(0, fullPath.lastIndexOf("/"));
|
|
513
|
+
if (dirPath) {
|
|
514
|
+
try {
|
|
515
|
+
await this.instance.files.makeDir(dirPath);
|
|
516
|
+
}
|
|
517
|
+
catch {
|
|
518
|
+
// Directory might already exist
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
const content = file.content instanceof Uint8Array
|
|
522
|
+
? file.content.buffer.slice(file.content.byteOffset, file.content.byteOffset + file.content.byteLength)
|
|
523
|
+
: file.content;
|
|
524
|
+
await this.instance.files.write(fullPath, content);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
async readFile(filePath) {
|
|
528
|
+
const exists = await this.instance.files.exists(filePath);
|
|
529
|
+
if (!exists) {
|
|
530
|
+
console.error(`[E2B] File not found: ${filePath}`);
|
|
531
|
+
return "";
|
|
532
|
+
}
|
|
533
|
+
// E2B files.read() defaults to text format and returns Promise<string>
|
|
534
|
+
const content = await this.instance.files.read(filePath);
|
|
535
|
+
return content;
|
|
536
|
+
}
|
|
537
|
+
async destroy() {
|
|
538
|
+
// Note: We don't kill the sandbox here to allow reuse
|
|
539
|
+
// The sandbox will auto-terminate based on the configured timeout
|
|
540
|
+
// or can be paused for up to 30 days with E2B's persistence feature
|
|
541
|
+
console.log(`[E2B] Sandbox ${this.instance.sandboxId} handle destroyed (sandbox continues running for reuse)`);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
//# sourceMappingURL=e2b-sandbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"e2b-sandbox.js","sourceRoot":"","sources":["../src/e2b-sandbox.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAA0B,MAAM,kBAAkB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sandagent/sandbox-e2b",
|
|
3
|
+
"version": "0.1.0-beta.0",
|
|
4
|
+
"description": "E2B sandbox adapter for SandAgent",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"dev": "tsc --watch",
|
|
21
|
+
"clean": "rm -rf dist",
|
|
22
|
+
"typecheck": "tsc --noEmit",
|
|
23
|
+
"lint": "echo 'no lint configured'",
|
|
24
|
+
"test": "vitest run --passWithNoTests"
|
|
25
|
+
},
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "https://github.com/vikadata/sandagent.git",
|
|
29
|
+
"directory": "packages/sandbox-e2b"
|
|
30
|
+
},
|
|
31
|
+
"license": "Apache-2.0",
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public",
|
|
34
|
+
"tag": "beta"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=20.0.0"
|
|
38
|
+
},
|
|
39
|
+
"keywords": [
|
|
40
|
+
"sandbox",
|
|
41
|
+
"e2b",
|
|
42
|
+
"sandagent",
|
|
43
|
+
"adapter"
|
|
44
|
+
],
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@sandagent/manager": "workspace:*",
|
|
47
|
+
"e2b": "^2.9.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/node": "^20.10.0",
|
|
51
|
+
"typescript": "^5.3.0",
|
|
52
|
+
"vitest": "^1.6.1"
|
|
53
|
+
}
|
|
54
|
+
}
|