Skip to content

Commit 0d3aa48

Browse files
feat(daytona): adding sandbox integration (#188)
* feat: add support for Vercel sandbox * format * switch to deno * cr * format * rename * format * auto bump peer dep * format * feat(daytona): adding sandbox integration * format * test fix * format * add support for * add changesets * feat: add modal sandbox (#190) * feat: add modal sandbox * chore: format * cr --------- Co-authored-by: Hunter Lovell <40191806+hntrl@users.noreply.github.com>
1 parent 988b44c commit 0d3aa48

35 files changed

+8255
-158
lines changed

.changeset/modal-sandbox.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
"@langchain/modal": minor
3+
---
4+
5+
feat(modal): add Modal sandbox provider for DeepAgents
6+
7+
Adds `@langchain/modal` package providing Modal sandbox integration for the DeepAgents framework.
8+
9+
Features:
10+
- Command execution via `execute()` in isolated Modal containers
11+
- File operations via `uploadFiles()` and `downloadFiles()`
12+
- Initial file population via `initialFiles` option
13+
- Direct SDK access via `.client` and `.instance` properties
14+
- Configurable container images, timeouts, memory, GPU, volumes, and secrets
15+
- Type-safe options extending Modal SDK's `SandboxCreateParams`

.changeset/tiny-dolls-move.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@langchain/daytona": patch
3+
---
4+
5+
feat(daytona): adding sandbox integration

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,4 @@ jobs:
141141
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
142142
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
143143
DENO_DEPLOY_TOKEN: ${{ secrets.DENO_DEPLOY_TOKEN }}
144+
DAYTONA_API_KEY: ${{ secrets.DAYTONA_API_KEY }}

.pr-description.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
## Summary
2+
3+
Adds `@langchain/modal` package - a Modal sandbox provider for deepagents
4+
5+
## Changes
6+
7+
### New Package: `libs/providers/modal/`
8+
9+
- **`sandbox.ts`** - `ModalSandbox` class implementing `SandboxBackendProtocol`
10+
- Command execution via Modal SDK's `exec()`
11+
- File upload/download using Modal's file handle API
12+
- `initialFiles` support for pre-populating sandbox files
13+
- `.client` and `.instance` getters for direct SDK access
14+
- **`types.ts`** - Type definitions extending Modal SDK's `SandboxCreateParams`
15+
- Pass-through SDK options (timeoutMs, memoryMiB, gpu, cpu, etc.)
16+
- Wrapped options for volumes/secrets (accept names instead of objects)
17+
- Custom additions: `appName`, `imageName`, `initialFiles`, `auth`
18+
19+
- **`auth.ts`** - Authentication utilities
20+
- `getAuthCredentials()` resolves token from options or environment variables
21+
- Comprehensive error messages for missing credentials
22+
23+
- **Tests**
24+
- Unit tests with mocked Modal SDK (`sandbox.test.ts`, `auth.test.ts`)
25+
- Integration tests against real Modal infrastructure (`sandbox.int.test.ts`)
26+
27+
### New Example: `examples/sandbox/modal-sandbox.ts`
28+
29+
Demonstrates using `ModalSandbox` with `createDeepAgent` to run Python code in an isolated container.
30+
31+
---
32+
33+
## Usage
34+
35+
```typescript
36+
import { ModalSandbox } from "@langchain/modal";
37+
import { createDeepAgent } from "deepagents";
38+
39+
const sandbox = await ModalSandbox.create({
40+
imageName: "python:3.12-slim",
41+
timeoutMs: 600_000,
42+
initialFiles: {
43+
"main.py": "print('Hello from Modal!')",
44+
},
45+
});
46+
47+
const agent = createDeepAgent({
48+
model: yourModel,
49+
backend: sandbox,
50+
});
51+
```

examples/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
},
88
"dependencies": {
99
"deepagents": "workspace:*",
10+
"@langchain/modal": "workspace:*",
1011
"@langchain/anthropic": "^1.3.14",
1112
"@langchain/core": "^1.1.19",
13+
"@langchain/daytona": "workspace:*",
1214
"@langchain/deno": "workspace:*",
1315
"@langchain/node-vfs": "workspace:*",
1416
"@langchain/langgraph-checkpoint": "^1.0.0",
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/* eslint-disable no-console */
2+
/**
3+
* Daytona Sandbox Example
4+
*
5+
* This example demonstrates the Sandbox Execution Support feature of DeepAgents
6+
* using Daytona's cloud-based sandbox infrastructure. It shows how to:
7+
* 1. Create a Daytona Sandbox backend using the @langchain/daytona package
8+
* 2. Use the `execute` tool to run shell commands in an isolated environment
9+
* 3. Leverage file upload/download capabilities
10+
*
11+
* The DaytonaSandbox runs commands in an isolated cloud environment,
12+
* perfect for code execution, project scaffolding, and automation tasks
13+
* without requiring local Docker or any local setup.
14+
*
15+
* ## Prerequisites
16+
*
17+
* Set up Daytona authentication:
18+
*
19+
* 1. Go to https://app.daytona.io
20+
* 2. Create an account and get your API key
21+
* 3. Set it as environment variable:
22+
*
23+
* ```bash
24+
* export DAYTONA_API_KEY=your_api_key_here
25+
* ```
26+
*
27+
* ## Running the Example
28+
*
29+
* ```bash
30+
* # With environment variable
31+
* npx tsx examples/sandbox/daytona-sandbox.ts
32+
*
33+
* # Or with bun
34+
* bun run examples/sandbox/daytona-sandbox.ts
35+
* ```
36+
*/
37+
38+
import "dotenv/config";
39+
40+
import { HumanMessage, AIMessage } from "@langchain/core/messages";
41+
import { ChatAnthropic } from "@langchain/anthropic";
42+
43+
import { createDeepAgent } from "deepagents";
44+
import { DaytonaSandbox } from "@langchain/daytona";
45+
46+
// System prompt that leverages the execute capability
47+
const systemPrompt = `You are a powerful coding assistant with access to a cloud-based sandboxed shell environment.
48+
49+
You can execute shell commands to:
50+
- Analyze code and projects (e.g., find patterns, count lines, check dependencies)
51+
- Run build tools and scripts (npm, node, pip, make, etc.)
52+
- Scaffold new projects
53+
- Run tests and linters
54+
- Manipulate files and directories
55+
56+
## Tools Available
57+
58+
- **execute**: Run any shell command and see the output
59+
- **ls**: List directory contents
60+
- **read_file**: Read file contents
61+
- **write_file**: Create new files
62+
- **edit_file**: Modify existing files
63+
- **grep**: Search for patterns in files
64+
- **glob**: Find files matching patterns
65+
66+
## Best Practices
67+
68+
1. Start by exploring the workspace: \`ls\` or \`execute("ls -la")\`
69+
2. Use the right tool for the job:
70+
- Use \`execute\` for complex commands, pipelines, and running programs
71+
- Use \`read_file\` for viewing file contents
72+
- Use \`write_file\` for creating new files
73+
3. Chain commands when needed: \`execute("npm install && npm run build")\`
74+
4. Check exit codes to verify success
75+
76+
You're working in an isolated cloud sandbox powered by Daytona, so feel free to experiment!`;
77+
78+
// Create the Daytona Sandbox
79+
// This provisions a new isolated sandbox environment
80+
console.log("🚀 Creating Daytona Sandbox...\n");
81+
82+
const sandbox = await DaytonaSandbox.create({
83+
language: "typescript",
84+
autoStopInterval: 15, // Auto-stop after 15 minutes of inactivity
85+
labels: {
86+
purpose: "example",
87+
package: "deepagents",
88+
},
89+
});
90+
91+
console.log(`✅ Sandbox created with ID: ${sandbox.id}\n`);
92+
93+
try {
94+
// Create the agent with sandbox backend
95+
const agent = createDeepAgent({
96+
model: new ChatAnthropic({
97+
model: "claude-haiku-4-5",
98+
temperature: 0,
99+
}),
100+
systemPrompt,
101+
backend: sandbox,
102+
});
103+
104+
console.log("🤖 Running agent...\n");
105+
106+
const result = await agent.invoke({
107+
messages: [
108+
new HumanMessage(
109+
`Create a simple TypeScript file called hello.ts that prints "Hello from DeepAgents!".
110+
Then run it with npx tsx to verify it works.
111+
Finally, show me the output.`,
112+
),
113+
],
114+
});
115+
116+
// Show the final AI response
117+
const messages = result.messages;
118+
const lastAIMessage = messages.findLast(AIMessage.isInstance);
119+
120+
if (lastAIMessage) {
121+
console.log("\n📝 Agent Response:\n");
122+
console.log(lastAIMessage.content);
123+
}
124+
} finally {
125+
// Always cleanup the sandbox
126+
console.log("\n🧹 Cleaning up sandbox...");
127+
await sandbox.close();
128+
console.log("✅ Sandbox closed.");
129+
}

examples/sandbox/modal-sandbox.ts

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/* eslint-disable no-console */
2+
/**
3+
* Modal Sandbox Example
4+
*
5+
* This example demonstrates the Sandbox Execution Support feature of DeepAgents
6+
* using Modal's cloud-based sandbox infrastructure. It shows how to:
7+
* 1. Create a Modal Sandbox backend using the @langchain/modal package
8+
* 2. Use the `execute` tool to run shell commands in an isolated container
9+
* 3. Leverage file upload/download capabilities
10+
*
11+
* The ModalSandbox runs commands in an isolated container environment,
12+
* perfect for code execution, project scaffolding, and automation tasks
13+
* without requiring local Docker or any local setup.
14+
*
15+
* ## Prerequisites
16+
*
17+
* Set up Modal authentication:
18+
*
19+
* 1. Install the Modal CLI: `pip install modal`
20+
* 2. Run `modal setup` to authenticate
21+
* 3. Or set environment variables directly:
22+
*
23+
* ```bash
24+
* export MODAL_TOKEN_ID=your_token_id_here
25+
* export MODAL_TOKEN_SECRET=your_token_secret_here
26+
* ```
27+
*
28+
* ## Running the Example
29+
*
30+
* ```bash
31+
* # With environment variable
32+
* npx tsx examples/sandbox/modal-sandbox.ts
33+
*
34+
* # Or with bun
35+
* bun run examples/sandbox/modal-sandbox.ts
36+
* ```
37+
*/
38+
39+
import "dotenv/config";
40+
41+
import { HumanMessage, AIMessage } from "@langchain/core/messages";
42+
import { ChatAnthropic } from "@langchain/anthropic";
43+
44+
import { createDeepAgent } from "deepagents";
45+
import { ModalSandbox } from "@langchain/modal";
46+
47+
// System prompt that leverages the execute capability
48+
const systemPrompt = `You are a powerful coding assistant with access to a cloud-based sandboxed shell environment.
49+
50+
You can execute shell commands to:
51+
- Analyze code and projects (e.g., find patterns, count lines, check dependencies)
52+
- Run build tools and scripts (npm, node, pip, make, etc.)
53+
- Scaffold new projects
54+
- Run tests and linters
55+
- Manipulate files and directories
56+
57+
## Tools Available
58+
59+
- **execute**: Run any shell command and see the output
60+
- **ls**: List directory contents
61+
- **read_file**: Read file contents
62+
- **write_file**: Create new files
63+
- **edit_file**: Modify existing files
64+
- **grep**: Search for patterns in files
65+
- **glob**: Find files matching patterns
66+
67+
## Best Practices
68+
69+
1. Start by exploring the workspace: \`ls\` or \`execute("ls -la")\`
70+
2. Use the right tool for the job:
71+
- Use \`execute\` for complex commands, pipelines, and running programs
72+
- Use \`read_file\` for viewing file contents
73+
- Use \`write_file\` for creating new files
74+
3. Chain commands when needed: \`execute("npm install && npm run build")\`
75+
4. Check exit codes to verify success
76+
77+
You're working in an isolated cloud sandbox powered by Modal, so feel free to experiment!`;
78+
79+
async function main() {
80+
// Create the Modal Sandbox
81+
// This provisions a new isolated container environment
82+
console.log("🚀 Creating Modal Sandbox...\n");
83+
84+
const sandbox = await ModalSandbox.create({
85+
imageName: "python:3.12-slim", // Base image with Python
86+
timeoutMs: 600_000, // 10 minute timeout
87+
});
88+
89+
console.log(`✅ Sandbox created with ID: ${sandbox.id}\n`);
90+
91+
try {
92+
// Create the agent with sandbox backend
93+
const agent = createDeepAgent({
94+
model: new ChatAnthropic({
95+
model: "claude-haiku-4-5",
96+
temperature: 0,
97+
}),
98+
systemPrompt,
99+
backend: sandbox,
100+
});
101+
102+
console.log("🤖 Running agent...\n");
103+
104+
const result = await agent.invoke({
105+
messages: [
106+
new HumanMessage(
107+
`Create a simple Python file called hello.py that prints "Hello from DeepAgents!".
108+
Then run it with python to verify it works.
109+
Finally, show me the output.`,
110+
),
111+
],
112+
});
113+
114+
// Show the final AI response
115+
const messages = result.messages;
116+
const lastAIMessage = messages.findLast(AIMessage.isInstance);
117+
118+
if (lastAIMessage) {
119+
console.log("\n📝 Agent Response:\n");
120+
console.log(lastAIMessage.content);
121+
}
122+
} finally {
123+
// Always cleanup the sandbox
124+
console.log("\n🧹 Cleaning up sandbox...");
125+
await sandbox.close();
126+
console.log("✅ Sandbox closed.");
127+
}
128+
}
129+
130+
main().catch((error) => {
131+
console.error("Error:", error);
132+
process.exit(1);
133+
});

libs/providers/daytona/.npmignore

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Source files
2+
src/
3+
*.ts
4+
!*.d.ts
5+
6+
# Test files
7+
**/*.test.ts
8+
**/*.int.test.ts
9+
vitest.config.ts
10+
11+
# Config
12+
tsconfig.json
13+
tsdown.config.ts
14+
.tsdown/
15+
16+
# Development
17+
.env
18+
.env.*
19+
20+
# Editor
21+
.vscode/
22+
.idea/

libs/providers/daytona/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License
2+
3+
Copyright (c) LangChain, Inc.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

0 commit comments

Comments
 (0)