|
| 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 | +}); |
0 commit comments