feat: daytona sandboxes (#59)

* feat: daytona sandboxes

Signed-off-by: Ivan Dagelic <dagelic.ivan@gmail.com>

* fix: change daytona snapshot namespace

Signed-off-by: Ivan Dagelic <dagelic.ivan@gmail.com>

* update yarn.lock and run formatter

---------

Signed-off-by: Ivan Dagelic <dagelic.ivan@gmail.com>
Co-authored-by: Brace Sproul <braceasproul@gmail.com>
This commit is contained in:
Ivan Dagelic 2025-05-31 00:59:14 +02:00 • committed by GitHub
parent c0d312601f
commit 65b68a1a42
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 323 additions and 323 deletions

View file

@ -43,8 +43,8 @@ ANTHROPIC_API_KEY=""
OPENAI_API_KEY="" OPENAI_API_KEY=""
GOOGLE_API_KEY="" GOOGLE_API_KEY=""
# E2B API key for accessing and modifying the code in the cloud sandbox. # Daytona API key for accessing and modifying the code in the cloud sandbox.
E2B_API_KEY="" DAYTONA_API_KEY=""
# Your GitHub PAT with access to the repositories you want to modify. # Your GitHub PAT with access to the repositories you want to modify.
GITHUB_PAT="" GITHUB_PAT=""

View file

@ -9,8 +9,8 @@ ANTHROPIC_API_KEY=""
OPENAI_API_KEY="" OPENAI_API_KEY=""
GOOGLE_API_KEY="" GOOGLE_API_KEY=""
# E2B API key for accessing and modifying the code in the cloud sandbox. # Daytona API key for accessing and modifying the code in the cloud sandbox.
E2B_API_KEY="" DAYTONA_API_KEY=""
# Your GitHub PAT with access to the repositories you want to modify. # Your GitHub PAT with access to the repositories you want to modify.
GITHUB_PAT="" GITHUB_PAT=""

View file

@ -1,29 +0,0 @@
# Always start from the base E2B image
FROM e2bdev/code-interpreter:latest
# Install dependencies in a single layer
RUN apt-get update && apt-get install -y \
git \
curl \
ripgrep \
python3 \
python3-pip \
&& rm -rf /var/lib/apt/lists/*
# Install Node.js (LTS version) via NodeSource
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - \
&& apt-get install -y nodejs \
&& rm -rf /var/lib/apt/lists/*
# Update corepack to latest version (to avoid outdated signature issues)
RUN npm install -g corepack@latest
# Enable corepack for yarn and pnpm (creates shims)
RUN corepack enable yarn pnpm
# Pre-download specific versions to avoid download on first use
RUN corepack prepare yarn@stable --activate \
&& corepack prepare pnpm@latest --activate
# Set the working directory
WORKDIR /app

View file

@ -1,18 +0,0 @@
# This is a config for E2B sandbox template.
# You can use template ID (eh0860emqx28qyxmbctu) to create a sandbox:
# Python SDK
# from e2b import Sandbox, AsyncSandbox
# sandbox = Sandbox("eh0860emqx28qyxmbctu") # Sync sandbox
# sandbox = await AsyncSandbox.create("eh0860emqx28qyxmbctu") # Async sandbox
# JS SDK
# import { Sandbox } from 'e2b'
# const sandbox = await Sandbox.create('eh0860emqx28qyxmbctu')
team_id = "af4eaf9c-3d40-415c-bb98-4831c47745cf"
memory_mb = 2_048
cpu_count = 4
start_cmd = "/root/.jupyter/start-up.sh"
dockerfile = "e2b.Dockerfile"
template_id = "eh0860emqx28qyxmbctu"

View file

@ -22,7 +22,7 @@
"run:from-plan": "npx tsx scripts/run-from-plan.ts" "run:from-plan": "npx tsx scripts/run-from-plan.ts"
}, },
"dependencies": { "dependencies": {
"@e2b/code-interpreter": "1.2.0-beta.4", "@daytonaio/sdk": "^0.18.1",
"@langchain/anthropic": "^0.3.20", "@langchain/anthropic": "^0.3.20",
"@langchain/core": "^0.3.56", "@langchain/core": "^0.3.56",
"@langchain/google-genai": "^0.2.9", "@langchain/google-genai": "^0.2.9",

View file

@ -3,6 +3,7 @@ import { Client } from "@langchain/langgraph-sdk";
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
import { graph } from "../src/index.js"; import { graph } from "../src/index.js";
import { createLogger, LogLevel } from "../src/utils/logger.js"; import { createLogger, LogLevel } from "../src/utils/logger.js";
import { SANDBOX_ROOT_DIR } from "../src/constants.js";
const logger = createLogger(LogLevel.INFO, "From Plan Script"); const logger = createLogger(LogLevel.INFO, "From Plan Script");
@ -88,11 +89,11 @@ The user wants to implement a GitHub OAuth authentication server in the \`/apps/
3. Making pull requests and pushing changes 3. Making pull requests and pushing changes
## Codebase Files and Descriptions ## Codebase Files and Descriptions
- **Project root**: \`/home/user/open-swe/\` - Main monorepo directory - **Project root**: \`${SANDBOX_ROOT_DIR}/open-swe/\` - Main monorepo directory
- **Apps directory**: \`/home/user/open-swe/apps/\` - Contains multiple apps including auth, docs, and open-swe - **Apps directory**: \`${SANDBOX_ROOT_DIR}/open-swe/apps/\` - Contains multiple apps including auth, docs, and open-swe
- **Auth app directory**: \`/home/user/open-swe/apps/auth/\` - Target directory for implementation, currently contains only scaffolding - **Auth app directory**: \`${SANDBOX_ROOT_DIR}/open-swe/apps/auth/\` - Target directory for implementation, currently contains only scaffolding
- **Auth package.json**: \`/home/user/open-swe/apps/auth/package.json\` - Contains basic TypeScript/Node.js setup with name "@open-swe/auth", includes dev dependencies for TypeScript, Jest, ESLint, Prettier - **Auth package.json**: \`${SANDBOX_ROOT_DIR}/open-swe/apps/auth/package.json\` - Contains basic TypeScript/Node.js setup with name "@open-swe/auth", includes dev dependencies for TypeScript, Jest, ESLint, Prettier
- **Auth src directory**: \`/home/user/open-swe/apps/auth/src/\` - Contains only an empty \`index.ts\` file - **Auth src directory**: \`${SANDBOX_ROOT_DIR}/open-swe/apps/auth/src/\` - Contains only an empty \`index.ts\` file
- **Auth config files**: Directory includes standard config files (.gitignore, .dockerignore, .prettierrc, eslint.config.js, jest.config.js, tsconfig.json, turbo.json) - **Auth config files**: Directory includes standard config files (.gitignore, .dockerignore, .prettierrc, eslint.config.js, jest.config.js, tsconfig.json, turbo.json)
## Key Repository Insights and Learnings ## Key Repository Insights and Learnings

View file

@ -3,3 +3,5 @@ export const TIMEOUT_MS = 300_000; // 5 minutes
export const TIMEOUT_EXTENSION_OPT = { export const TIMEOUT_EXTENSION_OPT = {
timeoutMs: TIMEOUT_MS, timeoutMs: TIMEOUT_MS,
}; };
export const SANDBOX_ROOT_DIR = "/home/daytona";
export const SNAPSHOT_NAME = "daytonaio/langchain-open-swe:0.1.0";

View file

@ -7,7 +7,7 @@ import {
} from "../tools/index.js"; } from "../tools/index.js";
import { getRepoAbsolutePath } from "../utils/git/index.js"; import { getRepoAbsolutePath } from "../utils/git/index.js";
import { formatPlanPrompt } from "../utils/plan-prompt.js"; import { formatPlanPrompt } from "../utils/plan-prompt.js";
import { pauseSandbox } from "../utils/sandbox.js"; import { stopSandbox } from "../utils/sandbox.js";
import { createLogger, LogLevel } from "../utils/logger.js"; import { createLogger, LogLevel } from "../utils/logger.js";
import { getCurrentTask } from "../utils/current-task.js"; import { getCurrentTask } from "../utils/current-task.js";
import { getMessageContentString } from "../utils/message/content.js"; import { getMessageContentString } from "../utils/message/content.js";
@ -134,11 +134,11 @@ export async function generateAction(
]); ]);
const hasToolCalls = !!response.tool_calls?.length; const hasToolCalls = !!response.tool_calls?.length;
// No tool calls means the graph is going to end. Pause the sandbox. // No tool calls means the graph is going to end. Stop the sandbox.
let newSandboxSessionId: string | undefined; let newSandboxSessionId: string | undefined;
if (!hasToolCalls && state.sandboxSessionId) { if (!hasToolCalls && state.sandboxSessionId) {
logger.info("No tool calls found. Pausing sandbox..."); logger.info("No tool calls found. Stopping sandbox...");
newSandboxSessionId = await pauseSandbox(state.sandboxSessionId); newSandboxSessionId = await stopSandbox(state.sandboxSessionId);
} }
logger.info("Generated action", { logger.info("Generated action", {

View file

@ -1,4 +1,4 @@
import { Sandbox } from "@e2b/code-interpreter"; import { Sandbox } from "@daytonaio/sdk";
import { createLogger, LogLevel } from "../utils/logger.js"; import { createLogger, LogLevel } from "../utils/logger.js";
import { import {
GraphState, GraphState,
@ -6,7 +6,6 @@ import {
GraphUpdate, GraphUpdate,
TargetRepository, TargetRepository,
} from "../types.js"; } from "../types.js";
import { TIMEOUT_EXTENSION_OPT } from "../constants.js";
import { import {
checkoutBranch, checkoutBranch,
configureGitUserInRepo, configureGitUserInRepo,
@ -15,11 +14,11 @@ import {
pullLatestChanges, pullLatestChanges,
} from "../utils/git/index.js"; } from "../utils/git/index.js";
import { getSandboxErrorFields } from "../utils/sandbox-error-fields.js"; import { getSandboxErrorFields } from "../utils/sandbox-error-fields.js";
import { daytonaClient } from "../utils/sandbox.js";
import { SNAPSHOT_NAME } from "../constants.js";
const logger = createLogger(LogLevel.INFO, "Initialize"); const logger = createLogger(LogLevel.INFO, "Initialize");
const SANDBOX_TEMPLATE_ID = "eh0860emqx28qyxmbctu";
async function cloneRepo(sandbox: Sandbox, targetRepository: TargetRepository) { async function cloneRepo(sandbox: Sandbox, targetRepository: TargetRepository) {
if (!process.env.GITHUB_PAT) { if (!process.env.GITHUB_PAT) {
throw new Error("GITHUB_PAT environment variable not set."); throw new Error("GITHUB_PAT environment variable not set.");
@ -39,10 +38,7 @@ async function cloneRepo(sandbox: Sandbox, targetRepository: TargetRepository) {
logger.info("Cloning repository", { logger.info("Cloning repository", {
command: gitCloneCommand.join(" "), command: gitCloneCommand.join(" "),
}); });
return await sandbox.commands.run( return await sandbox.process.executeCommand(gitCloneCommand.join(" "));
gitCloneCommand.join(" "),
TIMEOUT_EXTENSION_OPT,
);
} catch (e) { } catch (e) {
const errorFields = getSandboxErrorFields(e); const errorFields = getSandboxErrorFields(e);
logger.error("Failed to clone repository", errorFields ?? e); logger.error("Failed to clone repository", errorFields ?? e);
@ -78,13 +74,10 @@ export async function initialize(
sandboxSessionId, sandboxSessionId,
}); });
// Resume the sandbox if the session ID is in the config. // Resume the sandbox if the session ID is in the config.
const newSandbox = await Sandbox.resume( const existingSandbox = await daytonaClient().get(sandboxSessionId);
sandboxSessionId, await pullLatestChanges(absoluteRepoDir, existingSandbox);
TIMEOUT_EXTENSION_OPT,
);
await pullLatestChanges(absoluteRepoDir, newSandbox);
return { return {
sandboxSessionId: newSandbox.sandboxId, sandboxSessionId: existingSandbox.id,
}; };
} catch (e) { } catch (e) {
// Error thrown, log it and continue. Will create a new sandbox session since the resumption failed. // Error thrown, log it and continue. Will create a new sandbox session since the resumption failed.
@ -93,16 +86,15 @@ export async function initialize(
} }
logger.info("Creating sandbox..."); logger.info("Creating sandbox...");
const sandbox = await Sandbox.create( const sandbox = await daytonaClient().create({
SANDBOX_TEMPLATE_ID, image: SNAPSHOT_NAME,
TIMEOUT_EXTENSION_OPT, });
);
const res = await cloneRepo(sandbox, targetRepository); const res = await cloneRepo(sandbox, targetRepository);
if (res.error) { if (res.exitCode !== 0) {
// TODO: This should probably be an interrupt. // TODO: This should probably be an interrupt.
logger.error("Failed to clone repository", res.error); logger.error("Failed to clone repository", res.result);
throw new Error(`Failed to clone repository.\n${res.error}`); throw new Error(`Failed to clone repository.\n${res.result}`);
} }
logger.info("Repository cloned successfully."); logger.info("Repository cloned successfully.");
@ -123,7 +115,7 @@ export async function initialize(
} }
return { return {
sandboxSessionId: sandbox.sandboxId, sandboxSessionId: sandbox.id,
targetRepository, targetRepository,
}; };
} }

View file

@ -5,7 +5,7 @@ import {
HumanInterrupt, HumanInterrupt,
HumanResponse, HumanResponse,
} from "@langchain/langgraph/prebuilt"; } from "@langchain/langgraph/prebuilt";
import { resumeSandbox } from "../utils/sandbox.js"; import { startSandbox } from "../utils/sandbox.js";
export async function interruptPlan(state: GraphState): Promise<Command> { export async function interruptPlan(state: GraphState): Promise<Command> {
const { proposedPlan } = state; const { proposedPlan } = state;
@ -36,8 +36,7 @@ export async function interruptPlan(state: GraphState): Promise<Command> {
} }
if (interruptRes.type === "accept") { if (interruptRes.type === "accept") {
const newSandboxSessionId = (await resumeSandbox(state.sandboxSessionId)) const newSandboxSessionId = (await startSandbox(state.sandboxSessionId)).id;
.sandboxId;
// Plan was accepted, route to the generate-action node to start taking actions. // Plan was accepted, route to the generate-action node to start taking actions.
return new Command({ return new Command({
@ -55,8 +54,7 @@ export async function interruptPlan(state: GraphState): Promise<Command> {
} }
if (interruptRes.type === "edit") { if (interruptRes.type === "edit") {
const newSandboxSessionId = (await resumeSandbox(state.sandboxSessionId)) const newSandboxSessionId = (await startSandbox(state.sandboxSessionId)).id;
.sandboxId;
// Plan was edited, route to the generate-action node to start taking actions. // Plan was edited, route to the generate-action node to start taking actions.
const editedPlan = (interruptRes.args as ActionRequest).args.plan const editedPlan = (interruptRes.args as ActionRequest).args.plan

View file

@ -1,5 +1,4 @@
import { GraphConfig, GraphState, GraphUpdate, PlanItem } from "../types.js"; import { GraphConfig, GraphState, GraphUpdate, PlanItem } from "../types.js";
import { Sandbox } from "@e2b/code-interpreter";
import { import {
checkoutBranchAndCommit, checkoutBranchAndCommit,
createPullRequest, createPullRequest,
@ -13,6 +12,7 @@ import { loadModel, Task } from "../utils/load-model.js";
import { formatPlanPromptWithSummaries } from "../utils/plan-prompt.js"; import { formatPlanPromptWithSummaries } from "../utils/plan-prompt.js";
import { isHumanMessage, ToolMessage } from "@langchain/core/messages"; import { isHumanMessage, ToolMessage } from "@langchain/core/messages";
import { getMessageContentString } from "../utils/message/content.js"; import { getMessageContentString } from "../utils/message/content.js";
import { daytonaClient } from "../utils/sandbox.js";
const logger = createLogger(LogLevel.INFO, "Open PR"); const logger = createLogger(LogLevel.INFO, "Open PR");
@ -66,7 +66,7 @@ export async function openPullRequest(
); );
} }
const sandbox = await Sandbox.connect(sandboxSessionId); const sandbox = await daytonaClient().get(sandboxSessionId);
const { owner, repo } = state.targetRepository; const { owner, repo } = state.targetRepository;

View file

@ -2,7 +2,7 @@ import { isAIMessage } from "@langchain/core/messages";
import { GraphState } from "../types.js"; import { GraphState } from "../types.js";
import { HumanInterrupt, HumanResponse } from "@langchain/langgraph/prebuilt"; import { HumanInterrupt, HumanResponse } from "@langchain/langgraph/prebuilt";
import { END, interrupt, Command } from "@langchain/langgraph"; import { END, interrupt, Command } from "@langchain/langgraph";
import { pauseSandbox, resumeSandbox } from "../utils/sandbox.js"; import { stopSandbox, startSandbox } from "../utils/sandbox.js";
const constructDescription = (helpRequest: string): string => { const constructDescription = (helpRequest: string): string => {
return `The agent has requested help. Here is the help request: return `The agent has requested help. Here is the help request:
@ -21,7 +21,7 @@ export async function requestHelp(state: GraphState): Promise<Command> {
if (!sandboxSessionId) { if (!sandboxSessionId) {
throw new Error("Sandbox session ID not found."); throw new Error("Sandbox session ID not found.");
} }
await pauseSandbox(sandboxSessionId); await stopSandbox(sandboxSessionId);
const toolCall = lastMessage.tool_calls[0]; const toolCall = lastMessage.tool_calls[0];
@ -52,7 +52,7 @@ export async function requestHelp(state: GraphState): Promise<Command> {
if (typeof interruptRes.args !== "string") { if (typeof interruptRes.args !== "string") {
throw new Error("Interrupt response expected to be a string."); throw new Error("Interrupt response expected to be a string.");
} }
await resumeSandbox(sandboxSessionId); await startSandbox(sandboxSessionId);
return new Command({ return new Command({
goto: "generate-action", goto: "generate-action",
update: { update: {

View file

@ -11,13 +11,13 @@ import {
getChangedFilesStatus, getChangedFilesStatus,
getRepoAbsolutePath, getRepoAbsolutePath,
} from "../utils/git/index.js"; } from "../utils/git/index.js";
import { Sandbox } from "@e2b/code-interpreter";
import { import {
formatBadArgsError, formatBadArgsError,
zodSchemaToString, zodSchemaToString,
} from "../utils/zod-to-string.js"; } from "../utils/zod-to-string.js";
import { Command } from "@langchain/langgraph"; import { Command } from "@langchain/langgraph";
import { truncateOutput } from "../utils/truncate-outputs.js"; import { truncateOutput } from "../utils/truncate-outputs.js";
import { daytonaClient } from "../utils/sandbox.js";
const logger = createLogger(LogLevel.INFO, "TakeAction"); const logger = createLogger(LogLevel.INFO, "TakeAction");
@ -127,7 +127,7 @@ export async function takeAction(
// Always check if there are changed files after running a tool. // Always check if there are changed files after running a tool.
// If there are, commit them. // If there are, commit them.
const sandbox = await Sandbox.connect(state.sandboxSessionId); const sandbox = await daytonaClient().get(state.sandboxSessionId);
const changedFiles = await getChangedFilesStatus( const changedFiles = await getChangedFilesStatus(
getRepoAbsolutePath(state.targetRepository), getRepoAbsolutePath(state.targetRepository),
sandbox, sandbox,

View file

@ -7,7 +7,7 @@ import { sessionPlanTool } from "../../../tools/index.js";
import { GraphConfig } from "../../../types.js"; import { GraphConfig } from "../../../types.js";
import { loadModel, Task } from "../../../utils/load-model.js"; import { loadModel, Task } from "../../../utils/load-model.js";
import { PlannerGraphState, PlannerGraphUpdate } from "../types.js"; import { PlannerGraphState, PlannerGraphUpdate } from "../types.js";
import { pauseSandbox } from "../../../utils/sandbox.js"; import { stopSandbox } from "../../../utils/sandbox.js";
const systemPrompt = `You are operating as a terminal-based agentic coding assistant built by LangChain. It wraps LLM models to enable natural language interaction with a local codebase. You are expected to be precise, safe, and helpful. const systemPrompt = `You are operating as a terminal-based agentic coding assistant built by LangChain. It wraps LLM models to enable natural language interaction with a local codebase. You are expected to be precise, safe, and helpful.
@ -68,8 +68,8 @@ export async function generatePlan(
let newSessionId: string | undefined; let newSessionId: string | undefined;
if (state.sandboxSessionId) { if (state.sandboxSessionId) {
// Pause before returning, as the next step will be to interrupt the graph. // Stop before returning, as the next step will be to interrupt the graph.
newSessionId = await pauseSandbox(state.sandboxSessionId); newSessionId = await stopSandbox(state.sandboxSessionId);
} }
return { return {

View file

@ -2,11 +2,12 @@ import { tool } from "@langchain/core/tools";
import { z } from "zod"; import { z } from "zod";
import { applyPatch } from "diff"; import { applyPatch } from "diff";
import { GraphState } from "../types.js"; import { GraphState } from "../types.js";
import { Sandbox } from "@e2b/code-interpreter";
import { readFile, writeFile } from "../utils/read-write.js"; import { readFile, writeFile } from "../utils/read-write.js";
import { getCurrentTaskInput } from "@langchain/langgraph"; import { getCurrentTaskInput } from "@langchain/langgraph";
import { fixGitPatch } from "../utils/diff.js"; import { fixGitPatch } from "../utils/diff.js";
import { createLogger, LogLevel } from "../utils/logger.js"; import { createLogger, LogLevel } from "../utils/logger.js";
import { daytonaClient } from "../utils/sandbox.js";
import { SANDBOX_ROOT_DIR } from "../constants.js";
const logger = createLogger(LogLevel.INFO, "ApplyPatchTool"); const logger = createLogger(LogLevel.INFO, "ApplyPatchTool");
@ -19,9 +20,9 @@ const applyPatchToolSchema = z.object({
file_path: z.string().describe("The file path to apply the diff to."), file_path: z.string().describe("The file path to apply the diff to."),
workdir: z workdir: z
.string() .string()
.default("/home/user") .default(SANDBOX_ROOT_DIR)
.describe( .describe(
"The working directory for the command. Ensure this path is NOT included in any command arguments, as it will be added automatically. Defaults to '/home/user' as this is the root directory of the sandbox.", `The working directory for the command. Ensure this path is NOT included in any command arguments, as it will be added automatically. Defaults to '${SANDBOX_ROOT_DIR}' as this is the root directory of the sandbox.`,
), ),
}); });
@ -38,7 +39,7 @@ export const applyPatchTool = tool(
const { diff, file_path, workdir } = input; const { diff, file_path, workdir } = input;
const sandbox = await Sandbox.connect(sandboxSessionId); const sandbox = await daytonaClient().get(sandboxSessionId);
const { success: readFileSuccess, output: readFileOutput } = await readFile( const { success: readFileSuccess, output: readFileOutput } = await readFile(
sandbox, sandbox,

View file

@ -1,11 +1,12 @@
import { tool } from "@langchain/core/tools"; import { tool } from "@langchain/core/tools";
import { z } from "zod"; import { z } from "zod";
import { Sandbox } from "@e2b/code-interpreter"; import { Sandbox } from "@daytonaio/sdk";
import { GraphState } from "../types.js"; import { GraphState } from "../types.js";
import { getCurrentTaskInput } from "@langchain/langgraph"; import { getCurrentTaskInput } from "@langchain/langgraph";
import { TIMEOUT_MS } from "../constants.js";
import { getSandboxErrorFields } from "../utils/sandbox-error-fields.js"; import { getSandboxErrorFields } from "../utils/sandbox-error-fields.js";
import { createLogger, LogLevel } from "../utils/logger.js"; import { createLogger, LogLevel } from "../utils/logger.js";
import { daytonaClient } from "../utils/sandbox.js";
import { SANDBOX_ROOT_DIR } from "../constants.js";
const logger = createLogger(LogLevel.INFO, "ShellTool"); const logger = createLogger(LogLevel.INFO, "ShellTool");
@ -20,9 +21,9 @@ const shellToolSchema = z.object({
command: z.array(z.string()).describe("The command to run"), command: z.array(z.string()).describe("The command to run"),
workdir: z workdir: z
.string() .string()
.default("/home/user") .default(SANDBOX_ROOT_DIR)
.describe( .describe(
"The working directory for the command. Ensure this path is NOT included in any command arguments, as it will be added automatically. Defaults to '/home/user' as this is the root directory of the sandbox.", `The working directory for the command. Ensure this path is NOT included in any command arguments, as it will be added automatically. Defaults to '${SANDBOX_ROOT_DIR}' as this is the root directory of the sandbox.`,
), ),
timeout: z timeout: z
.number() .number()
@ -48,28 +49,29 @@ export const shellTool = tool(
); );
} }
sandbox = await Sandbox.connect(sandboxSessionId); sandbox = await daytonaClient().get(sandboxSessionId);
const { command, workdir, timeout } = input; const { command, workdir, timeout } = input;
const result = await sandbox.commands.run(command.join(" "), { const response = await sandbox.process.executeCommand(
timeoutMs: timeout ?? DEFAULT_COMMAND_TIMEOUT, command.join(" "),
cwd: workdir, workdir,
envs: DEFAULT_ENV, DEFAULT_ENV,
}); timeout ?? DEFAULT_COMMAND_TIMEOUT,
);
if (result.error) { if (response.exitCode !== 0) {
logger.error("Failed to run command", { logger.error("Failed to run command", {
error: result.error, error: response.result,
error_result: result, error_result: response,
input, input,
}); });
return { return {
result: `Command failed. Exit code: ${result.exitCode}\nError: ${result.error}\nStderr:\n${result.stderr}`, result: `Command failed. Exit code: ${response.exitCode}\nResult: ${response.result}\nStdout:\n${response.artifacts?.stdout}`,
status: "error", status: "error",
}; };
} }
return { return {
result: result.stdout, result: response.result,
status: "success", status: "success",
}; };
} catch (e) { } catch (e) {
@ -80,7 +82,7 @@ export const shellTool = tool(
error: errorFields, error: errorFields,
}); });
return { return {
result: `Command failed. Exit code: ${errorFields.exitCode}\nError: ${errorFields.error}\nStderr:\n${errorFields.stderr}\nStdout:\n${errorFields.stdout}`, result: `Command failed. Exit code: ${errorFields.exitCode}\nError: ${errorFields.result}\nStdout:\n${errorFields.artifacts?.stdout}`,
status: "error", status: "error",
}; };
} }
@ -97,17 +99,6 @@ export const shellTool = tool(
"FAILED TO RUN COMMAND: " + "FAILED TO RUN COMMAND: " +
(e instanceof Error ? e.message : "Unknown error"), (e instanceof Error ? e.message : "Unknown error"),
); );
} finally {
try {
if (sandbox) {
// Add an extra 5 min timeout to the sandbox.
await sandbox.setTimeout(TIMEOUT_MS);
}
} catch (_) {
logger.warn(
"Failed to set timeout for sandbox inside 'finally' block for shell tool.",
);
}
} }
}, },
{ {

View file

@ -1,9 +1,10 @@
import { Octokit } from "@octokit/rest"; import { Octokit } from "@octokit/rest";
import { CommandResult, Sandbox } from "@e2b/code-interpreter"; import { Sandbox } from "@daytonaio/sdk";
import { createLogger, LogLevel } from "../logger.js"; import { createLogger, LogLevel } from "../logger.js";
import { GraphConfig, TargetRepository } from "../../types.js"; import { GraphConfig, TargetRepository } from "../../types.js";
import { TIMEOUT_MS } from "../../constants.js"; import { TIMEOUT_MS, SANDBOX_ROOT_DIR } from "../../constants.js";
import { getSandboxErrorFields } from "../sandbox-error-fields.js"; import { getSandboxErrorFields } from "../sandbox-error-fields.js";
import { ExecuteResponse } from "@daytonaio/sdk/dist/types/ExecuteResponse.js";
const logger = createLogger(LogLevel.INFO, "GitUtil"); const logger = createLogger(LogLevel.INFO, "GitUtil");
@ -15,7 +16,7 @@ export function getRepoAbsolutePath(
throw new Error("No repository name provided"); throw new Error("No repository name provided");
} }
return `/home/user/${repoName}`; return `${SANDBOX_ROOT_DIR}/${repoName}`;
} }
export function getBranchName(config: GraphConfig): string { export function getBranchName(config: GraphConfig): string {
@ -31,27 +32,27 @@ export async function checkoutBranch(
absoluteRepoDir: string, absoluteRepoDir: string,
branchName: string, branchName: string,
sandbox: Sandbox, sandbox: Sandbox,
): Promise<CommandResult | false> { ): Promise<ExecuteResponse | false> {
logger.info(`Checking out branch '${branchName}'...`); logger.info(`Checking out branch '${branchName}'...`);
try { try {
const getCurrentBranchOutput = await sandbox.commands.run( const getCurrentBranchOutput = await sandbox.process.executeCommand(
"git branch --show-current", "git branch --show-current",
{ cwd: absoluteRepoDir }, absoluteRepoDir,
undefined,
TIMEOUT_MS,
); );
await sandbox.setTimeout(TIMEOUT_MS);
if (getCurrentBranchOutput.exitCode !== 0) { if (getCurrentBranchOutput.exitCode !== 0) {
logger.error(`Failed to get current branch`, { logger.error(`Failed to get current branch`, {
getCurrentBranchOutput, getCurrentBranchOutput,
}); });
} else { } else {
const currentBranch = getCurrentBranchOutput.stdout.trim(); const currentBranch = getCurrentBranchOutput.result.trim();
if (currentBranch === branchName) { if (currentBranch === branchName) {
logger.info(`Already on branch '${branchName}'. No checkout needed.`); logger.info(`Already on branch '${branchName}'. No checkout needed.`);
return { return {
stdout: `Already on branch ${branchName}`, result: `Already on branch ${branchName}`,
stderr: "",
exitCode: 0, exitCode: 0,
}; };
} }
@ -75,11 +76,12 @@ export async function checkoutBranch(
`Checking if branch 'refs/heads/${branchName}' exists using 'git rev-parse --verify --quiet'`, `Checking if branch 'refs/heads/${branchName}' exists using 'git rev-parse --verify --quiet'`,
); );
// Check if branch exists using git rev-parse for robustness // Check if branch exists using git rev-parse for robustness
const checkBranchExistsOutput = await sandbox.commands.run( const checkBranchExistsOutput = await sandbox.process.executeCommand(
`git rev-parse --verify --quiet "refs/heads/${branchName}"`, `git rev-parse --verify --quiet "refs/heads/${branchName}"`,
{ cwd: absoluteRepoDir }, absoluteRepoDir,
undefined,
TIMEOUT_MS,
); );
await sandbox.setTimeout(TIMEOUT_MS);
if (checkBranchExistsOutput.exitCode === 0) { if (checkBranchExistsOutput.exitCode === 0) {
// Branch exists (rev-parse exit code 0 means success) // Branch exists (rev-parse exit code 0 means success)
@ -94,7 +96,7 @@ export async function checkoutBranch(
if ( if (
errorFields && errorFields &&
errorFields.exitCode === 1 && errorFields.exitCode === 1 &&
errorFields.stderr === "" errorFields.result === ""
) { ) {
checkoutCommand = `git checkout -b "${branchName}"`; checkoutCommand = `git checkout -b "${branchName}"`;
} else { } else {
@ -110,9 +112,12 @@ export async function checkoutBranch(
} }
try { try {
const gitCheckoutOutput = await sandbox.commands.run(checkoutCommand, { const gitCheckoutOutput = await sandbox.process.executeCommand(
cwd: absoluteRepoDir, checkoutCommand,
}); absoluteRepoDir,
undefined,
TIMEOUT_MS,
);
if (gitCheckoutOutput.exitCode !== 0) { if (gitCheckoutOutput.exitCode !== 0) {
logger.error(`Failed to checkout branch`, { logger.error(`Failed to checkout branch`, {
@ -212,20 +217,24 @@ export async function configureGitUserInRepo(
): Promise<void> { ): Promise<void> {
let needsGitConfig = false; let needsGitConfig = false;
try { try {
const nameCheck = await sandbox.commands.run("git config user.name", { const nameCheck = await sandbox.process.executeCommand(
cwd: absoluteRepoDir, "git config user.name",
}); absoluteRepoDir,
await sandbox.setTimeout(TIMEOUT_MS); undefined,
const emailCheck = await sandbox.commands.run("git config user.email", { TIMEOUT_MS,
cwd: absoluteRepoDir, );
}); const emailCheck = await sandbox.process.executeCommand(
await sandbox.setTimeout(TIMEOUT_MS); "git config user.email",
absoluteRepoDir,
undefined,
TIMEOUT_MS,
);
if ( if (
nameCheck.exitCode !== 0 || nameCheck.exitCode !== 0 ||
nameCheck.stdout.trim() === "" || nameCheck.result.trim() === "" ||
emailCheck.exitCode !== 0 || emailCheck.exitCode !== 0 ||
emailCheck.stdout.trim() === "" emailCheck.result.trim() === ""
) { ) {
needsGitConfig = true; needsGitConfig = true;
} }
@ -244,11 +253,12 @@ export async function configureGitUserInRepo(
const { userName, userEmail } = await getGitUserDetailsFromGitHub(); const { userName, userEmail } = await getGitUserDetailsFromGitHub();
if (userName) { if (userName) {
const configUserNameOutput = await sandbox.commands.run( const configUserNameOutput = await sandbox.process.executeCommand(
`git config user.name "${userName}"`, `git config user.name "${userName}"`,
{ cwd: absoluteRepoDir }, absoluteRepoDir,
undefined,
TIMEOUT_MS,
); );
await sandbox.setTimeout(TIMEOUT_MS);
if (configUserNameOutput.exitCode !== 0) { if (configUserNameOutput.exitCode !== 0) {
logger.error(`Failed to set git user.name`, { logger.error(`Failed to set git user.name`, {
configUserNameOutput, configUserNameOutput,
@ -259,11 +269,12 @@ export async function configureGitUserInRepo(
} }
if (userEmail) { if (userEmail) {
const configUserEmailOutput = await sandbox.commands.run( const configUserEmailOutput = await sandbox.process.executeCommand(
`git config user.email "${userEmail}"`, `git config user.email "${userEmail}"`,
{ cwd: absoluteRepoDir }, absoluteRepoDir,
undefined,
TIMEOUT_MS,
); );
await sandbox.setTimeout(TIMEOUT_MS);
if (configUserEmailOutput.exitCode !== 0) { if (configUserEmailOutput.exitCode !== 0) {
logger.error(`Failed to set git user.email`, { logger.error(`Failed to set git user.email`, {
configUserEmailOutput, configUserEmailOutput,
@ -283,13 +294,14 @@ export async function commitAll(
absoluteRepoDir: string, absoluteRepoDir: string,
message: string, message: string,
sandbox: Sandbox, sandbox: Sandbox,
): Promise<CommandResult | false> { ): Promise<ExecuteResponse | false> {
try { try {
const gitAddOutput = await sandbox.commands.run( const gitAddOutput = await sandbox.process.executeCommand(
`git add -A && git commit -m "${message}"`, `git add -A && git commit -m "${message}"`,
{ cwd: absoluteRepoDir }, absoluteRepoDir,
undefined,
TIMEOUT_MS,
); );
await sandbox.setTimeout(TIMEOUT_MS);
if (gitAddOutput.exitCode !== 0) { if (gitAddOutput.exitCode !== 0) {
logger.error(`Failed to commit all changes to git repository`, { logger.error(`Failed to commit all changes to git repository`, {
@ -315,7 +327,7 @@ export async function commitAllAndPush(
absoluteRepoDir: string, absoluteRepoDir: string,
message: string, message: string,
sandbox: Sandbox, sandbox: Sandbox,
): Promise<CommandResult | false> { ): Promise<ExecuteResponse | false> {
try { try {
const commitOutput = await commitAll(absoluteRepoDir, message, sandbox); const commitOutput = await commitAll(absoluteRepoDir, message, sandbox);
@ -326,10 +338,12 @@ export async function commitAllAndPush(
return false; return false;
} }
const gitPushOutput = await sandbox.commands.run(pushCurrentBranchCmd, { const gitPushOutput = await sandbox.process.executeCommand(
cwd: absoluteRepoDir, pushCurrentBranchCmd,
}); absoluteRepoDir,
await sandbox.setTimeout(TIMEOUT_MS); undefined,
TIMEOUT_MS,
);
if (gitPushOutput.exitCode !== 0) { if (gitPushOutput.exitCode !== 0) {
logger.error(`Failed to push changes to git repository`, { logger.error(`Failed to push changes to git repository`, {
@ -357,9 +371,12 @@ export async function getChangedFilesStatus(
absoluteRepoDir: string, absoluteRepoDir: string,
sandbox: Sandbox, sandbox: Sandbox,
): Promise<string[]> { ): Promise<string[]> {
const gitStatusOutput = await sandbox.commands.run("git status --porcelain", { const gitStatusOutput = await sandbox.process.executeCommand(
cwd: absoluteRepoDir, "git status --porcelain",
}); absoluteRepoDir,
undefined,
TIMEOUT_MS,
);
if (gitStatusOutput.exitCode !== 0) { if (gitStatusOutput.exitCode !== 0) {
logger.error(`Failed to get changed files status`, { logger.error(`Failed to get changed files status`, {
@ -368,7 +385,7 @@ export async function getChangedFilesStatus(
return []; return [];
} }
return gitStatusOutput.stdout return gitStatusOutput.result
.split("\n") .split("\n")
.map((line) => line.trim()) .map((line) => line.trim())
.filter((line) => line !== ""); .filter((line) => line !== "");
@ -453,12 +470,14 @@ export async function createPullRequest({
export async function pullLatestChanges( export async function pullLatestChanges(
absoluteRepoDir: string, absoluteRepoDir: string,
sandbox: Sandbox, sandbox: Sandbox,
): Promise<CommandResult | false> { ): Promise<ExecuteResponse | false> {
try { try {
const gitPullOutput = await sandbox.commands.run("git pull", { const gitPullOutput = await sandbox.process.executeCommand(
cwd: absoluteRepoDir, "git pull",
}); absoluteRepoDir,
await sandbox.setTimeout(TIMEOUT_MS); undefined,
TIMEOUT_MS,
);
return gitPullOutput; return gitPullOutput;
} catch (e) { } catch (e) {
const errorFields = getSandboxErrorFields(e); const errorFields = getSandboxErrorFields(e);

View file

@ -1,6 +1,5 @@
import { Sandbox } from "@e2b/code-interpreter"; import { Sandbox } from "@daytonaio/sdk";
import { createLogger, LogLevel } from "./logger.js"; import { createLogger, LogLevel } from "./logger.js";
import { TIMEOUT_MS } from "../constants.js";
import { getSandboxErrorFields } from "./sandbox-error-fields.js"; import { getSandboxErrorFields } from "./sandbox-error-fields.js";
import { traceable } from "langsmith/traceable"; import { traceable } from "langsmith/traceable";
@ -15,9 +14,10 @@ async function handleCreateFile(
) { ) {
try { try {
const touchCommand = `touch "${filePath}"`; const touchCommand = `touch "${filePath}"`;
const touchOutput = await sandbox.commands.run(touchCommand, { const touchOutput = await sandbox.process.executeCommand(
cwd: args?.workDir, touchCommand,
}); args?.workDir,
);
return touchOutput; return touchOutput;
} catch (e) { } catch (e) {
const errorFields = getSandboxErrorFields(e); const errorFields = getSandboxErrorFields(e);
@ -44,9 +44,10 @@ async function readFileFunc(
output: string; output: string;
}> { }> {
try { try {
const readOutput = await sandbox.commands.run(`cat "${filePath}"`, { const readOutput = await sandbox.process.executeCommand(
cwd: args?.workDir, `cat "${filePath}"`,
}); args?.workDir,
);
if (readOutput.exitCode !== 0) { if (readOutput.exitCode !== 0) {
logger.error(`Error reading file '${filePath}' from sandbox via cat:`, { logger.error(`Error reading file '${filePath}' from sandbox via cat:`, {
@ -54,13 +55,13 @@ async function readFileFunc(
}); });
return { return {
success: false, success: false,
output: `FAILED TO READ FILE from sandbox '${filePath}'. Exit code: ${readOutput.exitCode}.\nStderr: ${readOutput.stderr}\nStdout: ${readOutput.stdout}`, output: `FAILED TO READ FILE from sandbox '${filePath}'. Exit code: ${readOutput.exitCode}.\nResult: ${readOutput.result}\nStdout: ${readOutput.artifacts?.stdout}`,
}; };
} }
return { return {
success: true, success: true,
output: readOutput.stdout, output: readOutput.result,
}; };
} catch (e: any) { } catch (e: any) {
if (e instanceof Error && e.message.includes("No such file or directory")) { if (e instanceof Error && e.message.includes("No such file or directory")) {
@ -87,7 +88,7 @@ async function readFileFunc(
let outputMessage = `FAILED TO EXECUTE READ COMMAND for sandbox '${filePath}'.`; let outputMessage = `FAILED TO EXECUTE READ COMMAND for sandbox '${filePath}'.`;
const errorFields = getSandboxErrorFields(e); const errorFields = getSandboxErrorFields(e);
if (errorFields) { if (errorFields) {
outputMessage += `\nExit code: ${errorFields.exitCode}\nStderr: ${errorFields.stderr}\nStdout: ${errorFields.stdout}`; outputMessage += `\nExit code: ${errorFields.exitCode}\nResult: ${errorFields.result}\nStdout: ${errorFields.artifacts?.stdout}`;
} else { } else {
outputMessage += ` Error: ${(e as Error).message || String(e)}`; outputMessage += ` Error: ${(e as Error).message || String(e)}`;
} }
@ -100,17 +101,6 @@ async function readFileFunc(
success: false, success: false,
output: outputMessage, output: outputMessage,
}; };
} finally {
try {
if (sandbox) {
// Add an extra 5 min timeout to the sandbox.
await sandbox.setTimeout(TIMEOUT_MS);
}
} catch (_) {
logger.warn(
"Failed to set timeout for sandbox inside 'finally' block for read file.",
);
}
} }
} }
@ -134,9 +124,10 @@ async function writeFileFunc(
const writeCommand = `cat > "${filePath}" << '${delimiter}' const writeCommand = `cat > "${filePath}" << '${delimiter}'
${content} ${content}
${delimiter}`; ${delimiter}`;
const writeOutput = await sandbox.commands.run(writeCommand, { const writeOutput = await sandbox.process.executeCommand(
cwd: args?.workDir, writeCommand,
}); args?.workDir,
);
if (writeOutput.exitCode !== 0) { if (writeOutput.exitCode !== 0) {
logger.error(`Error writing file '${filePath}' to sandbox via cat:`, { logger.error(`Error writing file '${filePath}' to sandbox via cat:`, {
@ -144,14 +135,9 @@ ${delimiter}`;
}); });
return { return {
success: false, success: false,
output: `FAILED TO WRITE FILE to sandbox '${filePath}'. Exit code: ${writeOutput.exitCode}\nStderr: ${writeOutput.stderr}\nStdout: ${writeOutput.stdout}`, output: `FAILED TO WRITE FILE to sandbox '${filePath}'. Exit code: ${writeOutput.exitCode}\nResult: ${writeOutput.result}\nStdout: ${writeOutput.artifacts?.stdout}`,
}; };
} }
if (writeOutput.stderr) {
logger.warn(
`Stderr while writing file '${filePath}' to sandbox via cat: ${writeOutput.stderr}`,
);
}
return { return {
success: true, success: true,
output: `Successfully wrote file '${filePath}' to sandbox via cat.`, output: `Successfully wrote file '${filePath}' to sandbox via cat.`,
@ -169,7 +155,7 @@ ${delimiter}`;
let outputMessage = `FAILED TO EXECUTE WRITE COMMAND for sandbox '${filePath}'.`; let outputMessage = `FAILED TO EXECUTE WRITE COMMAND for sandbox '${filePath}'.`;
const errorFields = getSandboxErrorFields(e); const errorFields = getSandboxErrorFields(e);
if (errorFields) { if (errorFields) {
outputMessage += `\nExit code: ${errorFields.exitCode}\nStderr: ${errorFields.stderr}\nStdout: ${errorFields.stdout}`; outputMessage += `\nExit code: ${errorFields.exitCode}\nResult: ${errorFields.result}\nStdout: ${errorFields.artifacts?.stdout}`;
} else { } else {
outputMessage += ` Error: ${(e as Error).message || String(e)}`; outputMessage += ` Error: ${(e as Error).message || String(e)}`;
} }
@ -178,17 +164,6 @@ ${delimiter}`;
success: false, success: false,
output: outputMessage, output: outputMessage,
}; };
} finally {
try {
if (sandbox) {
// Add an extra 5 min timeout to the sandbox.
await sandbox.setTimeout(TIMEOUT_MS);
}
} catch (_) {
logger.warn(
"Failed to set timeout for sandbox inside 'finally' block for write file.",
);
}
} }
} }

View file

@ -1,8 +1,8 @@
import { CommandResult } from "@e2b/code-interpreter"; import { ExecuteResponse } from "@daytonaio/sdk/dist/types/ExecuteResponse.js";
export function getSandboxErrorFields( export function getSandboxErrorFields(
error: unknown, error: unknown,
): CommandResult | undefined { ): ExecuteResponse | undefined {
if ( if (
!error || !error ||
typeof error !== "object" || typeof error !== "object" ||
@ -16,5 +16,5 @@ export function getSandboxErrorFields(
return undefined; return undefined;
} }
return error.result as CommandResult; return error.result as unknown as ExecuteResponse;
} }

View file

@ -1,28 +1,52 @@
import { Sandbox } from "@e2b/code-interpreter"; import { Daytona, Sandbox, SandboxState } from "@daytonaio/sdk";
// Singleton instance of Daytona
let daytonaInstance: Daytona | null = null;
/** /**
* Pauses the sandbox. Either pass an existing sandbox client, or a sandbox session ID. * Returns a shared Daytona instance
*/
export function daytonaClient(): Daytona {
if (!daytonaInstance) {
daytonaInstance = new Daytona();
}
return daytonaInstance;
}
/**
* Stops the sandbox. Either pass an existing sandbox client, or a sandbox session ID.
* If no sandbox client is provided, the sandbox will be connected to. * If no sandbox client is provided, the sandbox will be connected to.
* @param sandboxSessionId The ID of the sandbox to pause. * @param sandboxSessionId The ID of the sandbox to stop.
* @param sandbox The sandbox client to pause. If not provided, the sandbox will be connected to. * @param sandbox The sandbox client to stop. If not provided, the sandbox will be connected to.
* @returns The sandbox session ID. * @returns The sandbox session ID.
*/ */
export async function pauseSandbox( export async function stopSandbox(sandboxSessionId: string): Promise<string> {
sandboxSessionId: string, const sandbox = await daytonaClient().get(sandboxSessionId);
sandbox?: Sandbox, if (
): Promise<string> { sandbox.instance.state == SandboxState.STOPPED ||
const sandboxClient = sandbox ?? (await Sandbox.connect(sandboxSessionId)); sandbox.instance.state == SandboxState.ARCHIVED
return await sandboxClient.pause(); ) {
return sandboxSessionId;
} else if (sandbox.instance.state == "started") {
await daytonaClient().stop(sandbox);
}
return sandbox.id;
} }
/** /**
* Resumes the sandbox. * Starts the sandbox.
* @param sandboxSessionId The ID of the sandbox to resume. * @param sandboxSessionId The ID of the sandbox to start.
* @returns The sandbox client. * @returns The sandbox client.
*/ */
export async function resumeSandbox( export async function startSandbox(sandboxSessionId: string): Promise<Sandbox> {
sandboxSessionId: string, const sandbox = await daytonaClient().get(sandboxSessionId);
): Promise<Sandbox> { if (
return await Sandbox.resume(sandboxSessionId); sandbox.instance.state == SandboxState.STOPPED ||
sandbox.instance.state == SandboxState.ARCHIVED
) {
await daytonaClient().start(sandbox);
}
return sandbox;
} }

206
yarn.lock
View file

@ -449,13 +449,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@bufbuild/protobuf@npm:^2.2.2":
version: 2.5.0
resolution: "@bufbuild/protobuf@npm:2.5.0"
checksum: ff7f015e3ab7243461ac480efcc58a6b36473fef036aaa118361eb45871587d97a0bebc9daf77127ef86cdf08f1af990469e51c54b59b1818997c032dd221407
languageName: node
linkType: hard
"@cfworker/json-schema@npm:^4.0.2": "@cfworker/json-schema@npm:^4.0.2":
version: 4.1.1 version: 4.1.1
resolution: "@cfworker/json-schema@npm:4.1.1" resolution: "@cfworker/json-schema@npm:4.1.1"
@ -479,25 +472,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@connectrpc/connect-web@npm:2.0.0-rc.3":
version: 2.0.0-rc.3
resolution: "@connectrpc/connect-web@npm:2.0.0-rc.3"
peerDependencies:
"@bufbuild/protobuf": ^2.2.0
"@connectrpc/connect": 2.0.0-rc.3
checksum: 2889806b7161507f20d01a472b8173ea8fec4db664e89a3c46b2a04690abafb3b73a7541334d34b70be5d4867b2c4e51558bec7dfb3cead061f66fcc42076f8d
languageName: node
linkType: hard
"@connectrpc/connect@npm:2.0.0-rc.3":
version: 2.0.0-rc.3
resolution: "@connectrpc/connect@npm:2.0.0-rc.3"
peerDependencies:
"@bufbuild/protobuf": ^2.2.0
checksum: 78e993f48b4ff7dd290a919eb34578ca97848f12576a1fb8e988af50a100c6aa790c2cfaa0aca6fae658e56c652c81db5be9cbf650a4a69f18fa0a8a3b94b58d
languageName: node
linkType: hard
"@dabh/diagnostics@npm:^2.0.2": "@dabh/diagnostics@npm:^2.0.2":
version: 2.0.3 version: 2.0.3
resolution: "@dabh/diagnostics@npm:2.0.3" resolution: "@dabh/diagnostics@npm:2.0.3"
@ -509,12 +483,54 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@e2b/code-interpreter@npm:1.2.0-beta.4": "@daytonaio/api-client@npm:^0.19.1":
version: 1.2.0-beta.4 version: 0.19.1
resolution: "@e2b/code-interpreter@npm:1.2.0-beta.4" resolution: "@daytonaio/api-client@npm:0.19.1"
dependencies: dependencies:
e2b: 1.2.0-beta.4 axios: ^1.6.1
checksum: c08fb0381482156301f1147bf5cf71bab7c817afa7c02613bde3dc1b8c7011f9aca14b9edd1e4e9c365cec486818b8d3e5c54b1e7bcc70248bdf722a5b4026bd checksum: fc5402ff535b4299d9e5124795f02e09f86f22d0e07153943452e2771038c803fe11153d52c9b5f1b618bd17d18a4af76aa421547f640b86cbcdc6dec1d4d063
languageName: node
linkType: hard
"@daytonaio/sdk@npm:^0.18.1":
version: 0.18.1
resolution: "@daytonaio/sdk@npm:0.18.1"
dependencies:
"@daytonaio/api-client": ^0.19.1
"@dotenvx/dotenvx": ^1.25.1
axios: ^1.6.0
form-data: ^4.0.0
uuid: ^11.0.3
checksum: a3e0afd4e60a8f631f78579e8defed206dcd97ebe6e005d3bb75bb0e289be7bbf51e68075c255638beba98eea272f642a2c6872dbc6689d0d8bab7ba660fd475
languageName: node
linkType: hard
"@dotenvx/dotenvx@npm:^1.25.1":
version: 1.44.1
resolution: "@dotenvx/dotenvx@npm:1.44.1"
dependencies:
commander: ^11.1.0
dotenv: ^16.4.5
eciesjs: ^0.4.10
execa: ^5.1.1
fdir: ^6.2.0
ignore: ^5.3.0
object-treeify: 1.1.33
picomatch: ^4.0.2
which: ^4.0.0
bin:
dotenvx: src/cli/dotenvx.js
git-dotenvx: src/cli/dotenvx.js
checksum: a868270e4fdb0d3ac307fc44728630dbfb3a17685799de8483fdb3e2e8543cc4eb6f576fe6284804d0aeccbf9cbf5ca4b14906ff554d090960f3223d88db93b5
languageName: node
linkType: hard
"@ecies/ciphers@npm:^0.2.3":
version: 0.2.3
resolution: "@ecies/ciphers@npm:0.2.3"
peerDependencies:
"@noble/ciphers": ^1.0.0
checksum: fdf01fd5e687a74802df60d21ff9be5aa6cdf692dcf671186e94eb17e9c260a4652b64c7127b277af20c35d3ccc733003cefb2fdaee93e8b516fa71d317d503f
languageName: node languageName: node
linkType: hard linkType: hard
@ -2416,6 +2432,29 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@noble/ciphers@npm:^1.3.0":
version: 1.3.0
resolution: "@noble/ciphers@npm:1.3.0"
checksum: 19722c35475df9bc78db60d261d0b5ef8a6d722561efc2135453f943eaa421b492195dc666e3e4df2b755bca3739e04f04b9c660198559f5dd05d3cfbf1b9e92
languageName: node
linkType: hard
"@noble/curves@npm:^1.9.1":
version: 1.9.1
resolution: "@noble/curves@npm:1.9.1"
dependencies:
"@noble/hashes": 1.8.0
checksum: 4f3483a1001538d2f55516cdcb19319d1eaef79550633f670e7d570b989cdbc0129952868b72bb67643329746b8ffefe8e4cd791c8cc35574e05a37f873eef42
languageName: node
linkType: hard
"@noble/hashes@npm:1.8.0, @noble/hashes@npm:^1.8.0":
version: 1.8.0
resolution: "@noble/hashes@npm:1.8.0"
checksum: c94e98b941963676feaba62475b1ccfa8341e3f572adbb3b684ee38b658df44100187fa0ef4220da580b13f8d27e87d5492623c8a02ecc61f23fb9960c7918f5
languageName: node
linkType: hard
"@nodelib/fs.scandir@npm:2.1.5": "@nodelib/fs.scandir@npm:2.1.5":
version: 2.1.5 version: 2.1.5
resolution: "@nodelib/fs.scandir@npm:2.1.5" resolution: "@nodelib/fs.scandir@npm:2.1.5"
@ -2608,7 +2647,7 @@ __metadata:
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "@open-swe/agent@workspace:apps/open-swe" resolution: "@open-swe/agent@workspace:apps/open-swe"
dependencies: dependencies:
"@e2b/code-interpreter": 1.2.0-beta.4 "@daytonaio/sdk": ^0.18.1
"@eslint/eslintrc": ^3.1.0 "@eslint/eslintrc": ^3.1.0
"@eslint/js": ^9.19.0 "@eslint/js": ^9.19.0
"@jest/globals": ^29.7.0 "@jest/globals": ^29.7.0
@ -5375,7 +5414,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"axios@npm:^1.4.0, axios@npm:^1.6.2": "axios@npm:^1.4.0, axios@npm:^1.6.0, axios@npm:^1.6.1, axios@npm:^1.6.2":
version: 1.9.0 version: 1.9.0
resolution: "axios@npm:1.9.0" resolution: "axios@npm:1.9.0"
dependencies: dependencies:
@ -6240,6 +6279,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"commander@npm:^11.1.0":
version: 11.1.0
resolution: "commander@npm:11.1.0"
checksum: fd1a8557c6b5b622c89ecdfde703242ab7db3b628ea5d1755784c79b8e7cb0d74d65b4a262289b533359cd58e1bfc0bf50245dfbcd2954682a6f367c828b79ef
languageName: node
linkType: hard
"commander@npm:^13.0.0": "commander@npm:^13.0.0":
version: 13.1.0 version: 13.1.0
resolution: "commander@npm:13.1.0" resolution: "commander@npm:13.1.0"
@ -6254,13 +6300,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"compare-versions@npm:^6.1.0":
version: 6.1.1
resolution: "compare-versions@npm:6.1.1"
checksum: 73fe6c4f52d22efe28f0a3be10df2afd704e10b3593360cd963e86b33a7a263c263b41a1361b69c30a0fe68bfa70fef90860c1cf2ef41502629d4402890fcd57
languageName: node
linkType: hard
"concat-map@npm:0.0.1": "concat-map@npm:0.0.1":
version: 0.0.1 version: 0.0.1
resolution: "concat-map@npm:0.0.1" resolution: "concat-map@npm:0.0.1"
@ -6876,7 +6915,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"dotenv@npm:^16.4.7": "dotenv@npm:^16.4.5, dotenv@npm:^16.4.7":
version: 16.5.0 version: 16.5.0
resolution: "dotenv@npm:16.5.0" resolution: "dotenv@npm:16.5.0"
checksum: 6543fe87b5ddf2d60dd42df6616eec99148a5fc150cb4530fef5bda655db5204a3afa0e6f25f7cd64b20657ace4d79c0ef974bec32fdb462cad18754191e7a90 checksum: 6543fe87b5ddf2d60dd42df6616eec99148a5fc150cb4530fef5bda655db5204a3afa0e6f25f7cd64b20657ace4d79c0ef974bec32fdb462cad18754191e7a90
@ -6894,20 +6933,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"e2b@npm:1.2.0-beta.4":
version: 1.2.0-beta.4
resolution: "e2b@npm:1.2.0-beta.4"
dependencies:
"@bufbuild/protobuf": ^2.2.2
"@connectrpc/connect": 2.0.0-rc.3
"@connectrpc/connect-web": 2.0.0-rc.3
compare-versions: ^6.1.0
openapi-fetch: ^0.9.7
platform: ^1.3.6
checksum: 98adde94c74d18313d71fca2fdc8bf99992940238e667f797d99e1b1987887b2ef20cd94d4275cf4033026f74486929a090fb3789def02a20b3361693f6950ae
languageName: node
linkType: hard
"eastasianwidth@npm:^0.2.0": "eastasianwidth@npm:^0.2.0":
version: 0.2.0 version: 0.2.0
resolution: "eastasianwidth@npm:0.2.0" resolution: "eastasianwidth@npm:0.2.0"
@ -6915,6 +6940,18 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"eciesjs@npm:^0.4.10":
version: 0.4.15
resolution: "eciesjs@npm:0.4.15"
dependencies:
"@ecies/ciphers": ^0.2.3
"@noble/ciphers": ^1.3.0
"@noble/curves": ^1.9.1
"@noble/hashes": ^1.8.0
checksum: 133a0ded69da0579d7082fe89b6a15225cf5cf503f653438355c2106cfc42576ab75835421f6a1ad099b9b802f389fc0077e72a951fd0e7dbc5c1e5220457ac9
languageName: node
linkType: hard
"ee-first@npm:1.1.1": "ee-first@npm:1.1.1":
version: 1.1.1 version: 1.1.1
resolution: "ee-first@npm:1.1.1" resolution: "ee-first@npm:1.1.1"
@ -7879,7 +7916,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"execa@npm:^5.0.0": "execa@npm:^5.0.0, execa@npm:^5.1.1":
version: 5.1.1 version: 5.1.1
resolution: "execa@npm:5.1.1" resolution: "execa@npm:5.1.1"
dependencies: dependencies:
@ -8189,6 +8226,18 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"fdir@npm:^6.2.0":
version: 6.4.5
resolution: "fdir@npm:6.4.5"
peerDependencies:
picomatch: ^3 || ^4
peerDependenciesMeta:
picomatch:
optional: true
checksum: 14efd2d6617a6f9fb314916ccff64e00bdb96216f26542ec9dfa532ed60a7ebb45463f7009aa215c14071566bf43caeb8ba268ccb52a11e6b51e4aaa8cb58d81
languageName: node
linkType: hard
"fdir@npm:^6.4.4": "fdir@npm:^6.4.4":
version: 6.4.4 version: 6.4.4
resolution: "fdir@npm:6.4.4" resolution: "fdir@npm:6.4.4"
@ -9284,7 +9333,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"ignore@npm:^5.2.0, ignore@npm:^5.3.1": "ignore@npm:^5.2.0, ignore@npm:^5.3.0, ignore@npm:^5.3.1":
version: 5.3.2 version: 5.3.2
resolution: "ignore@npm:5.3.2" resolution: "ignore@npm:5.3.2"
checksum: 2acfd32a573260ea522ea0bfeff880af426d68f6831f973129e2ba7363f422923cf53aab62f8369cbf4667c7b25b6f8a3761b34ecdb284ea18e87a5262a865be checksum: 2acfd32a573260ea522ea0bfeff880af426d68f6831f973129e2ba7363f422923cf53aab62f8369cbf4667c7b25b6f8a3761b34ecdb284ea18e87a5262a865be
@ -12549,6 +12598,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"object-treeify@npm:1.1.33":
version: 1.1.33
resolution: "object-treeify@npm:1.1.33"
checksum: 3af7f889349571ee73f5bdfb5ac478270c85eda8bcba950b454eb598ce41759a1ed6b0b43fbd624cb449080a4eb2df906b602e5138b6186b9563b692231f1694
languageName: node
linkType: hard
"object.assign@npm:^4.1.4, object.assign@npm:^4.1.7": "object.assign@npm:^4.1.4, object.assign@npm:^4.1.7":
version: 4.1.7 version: 4.1.7
resolution: "object.assign@npm:4.1.7" resolution: "object.assign@npm:4.1.7"
@ -12703,15 +12759,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"openapi-fetch@npm:^0.9.7":
version: 0.9.8
resolution: "openapi-fetch@npm:0.9.8"
dependencies:
openapi-typescript-helpers: ^0.0.8
checksum: 32a32698942b12b4c2fe2249eb90f745fa8dfde16d3312966e009fb7aaf7a233f883536ed58b1cdd58b6cafd6b55784e6aa7d13fefaf7c990929868e335d6cbe
languageName: node
linkType: hard
"openapi-types@npm:^12.0.0, openapi-types@npm:^12.1.3": "openapi-types@npm:^12.0.0, openapi-types@npm:^12.1.3":
version: 12.1.3 version: 12.1.3
resolution: "openapi-types@npm:12.1.3" resolution: "openapi-types@npm:12.1.3"
@ -12719,13 +12766,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"openapi-typescript-helpers@npm:^0.0.8":
version: 0.0.8
resolution: "openapi-typescript-helpers@npm:0.0.8"
checksum: e309d7d297cf78308c41c324ffe094c3ef194117bf104b5300e45535d158265f665c69e810a143f1d3db7020575c3041e370d2ee93fc8094f5aabc14a366fc39
languageName: node
linkType: hard
"optionator@npm:^0.9.3": "optionator@npm:^0.9.3":
version: 0.9.4 version: 0.9.4
resolution: "optionator@npm:0.9.4" resolution: "optionator@npm:0.9.4"
@ -13111,13 +13151,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"platform@npm:^1.3.6":
version: 1.3.6
resolution: "platform@npm:1.3.6"
checksum: 6f472a09c61d418c7e26c1c16d0bdc029549d512dbec6526216a1e59ec68100d07007d0097dcba69dddad883d6f2a83361b4bdfe0094a3d9a2af24158643d85e
languageName: node
linkType: hard
"pony-cause@npm:^1.1.1": "pony-cause@npm:^1.1.1":
version: 1.1.1 version: 1.1.1
resolution: "pony-cause@npm:1.1.1" resolution: "pony-cause@npm:1.1.1"
@ -16184,7 +16217,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"uuid@npm:^11.0.5, uuid@npm:^11.1.0": "uuid@npm:^11.0.3, uuid@npm:^11.0.5, uuid@npm:^11.1.0":
version: 11.1.0 version: 11.1.0
resolution: "uuid@npm:11.1.0" resolution: "uuid@npm:11.1.0"
bin: bin:
@ -16403,6 +16436,17 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"which@npm:^4.0.0":
version: 4.0.0
resolution: "which@npm:4.0.0"
dependencies:
isexe: ^3.1.1
bin:
node-which: bin/which.js
checksum: f17e84c042592c21e23c8195108cff18c64050b9efb8459589116999ea9da6dd1509e6a1bac3aeebefd137be00fabbb61b5c2bc0aa0f8526f32b58ee2f545651
languageName: node
linkType: hard
"which@npm:^5.0.0": "which@npm:^5.0.0":
version: 5.0.0 version: 5.0.0
resolution: "which@npm:5.0.0" resolution: "which@npm:5.0.0"