mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-09-30 10:23:14 +00:00
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:
parent
c0d312601f
commit
65b68a1a42
21 changed files with 323 additions and 323 deletions
|
|
@ -43,8 +43,8 @@ ANTHROPIC_API_KEY=""
|
|||
OPENAI_API_KEY=""
|
||||
GOOGLE_API_KEY=""
|
||||
|
||||
# E2B API key for accessing and modifying the code in the cloud sandbox.
|
||||
E2B_API_KEY=""
|
||||
# Daytona API key for accessing and modifying the code in the cloud sandbox.
|
||||
DAYTONA_API_KEY=""
|
||||
|
||||
# Your GitHub PAT with access to the repositories you want to modify.
|
||||
GITHUB_PAT=""
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ ANTHROPIC_API_KEY=""
|
|||
OPENAI_API_KEY=""
|
||||
GOOGLE_API_KEY=""
|
||||
|
||||
# E2B API key for accessing and modifying the code in the cloud sandbox.
|
||||
E2B_API_KEY=""
|
||||
# Daytona API key for accessing and modifying the code in the cloud sandbox.
|
||||
DAYTONA_API_KEY=""
|
||||
|
||||
# Your GitHub PAT with access to the repositories you want to modify.
|
||||
GITHUB_PAT=""
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
"run:from-plan": "npx tsx scripts/run-from-plan.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@e2b/code-interpreter": "1.2.0-beta.4",
|
||||
"@daytonaio/sdk": "^0.18.1",
|
||||
"@langchain/anthropic": "^0.3.20",
|
||||
"@langchain/core": "^0.3.56",
|
||||
"@langchain/google-genai": "^0.2.9",
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { Client } from "@langchain/langgraph-sdk";
|
|||
import { v4 as uuidv4 } from "uuid";
|
||||
import { graph } from "../src/index.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");
|
||||
|
||||
|
|
@ -88,11 +89,11 @@ The user wants to implement a GitHub OAuth authentication server in the \`/apps/
|
|||
3. Making pull requests and pushing changes
|
||||
|
||||
## Codebase Files and Descriptions
|
||||
- **Project root**: \`/home/user/open-swe/\` - Main monorepo directory
|
||||
- **Apps directory**: \`/home/user/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 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 src directory**: \`/home/user/open-swe/apps/auth/src/\` - Contains only an empty \`index.ts\` file
|
||||
- **Project root**: \`${SANDBOX_ROOT_DIR}/open-swe/\` - Main monorepo directory
|
||||
- **Apps directory**: \`${SANDBOX_ROOT_DIR}/open-swe/apps/\` - Contains multiple apps including auth, docs, and open-swe
|
||||
- **Auth app directory**: \`${SANDBOX_ROOT_DIR}/open-swe/apps/auth/\` - Target directory for implementation, currently contains only scaffolding
|
||||
- **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**: \`${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)
|
||||
|
||||
## Key Repository Insights and Learnings
|
||||
|
|
|
|||
|
|
@ -3,3 +3,5 @@ export const TIMEOUT_MS = 300_000; // 5 minutes
|
|||
export const TIMEOUT_EXTENSION_OPT = {
|
||||
timeoutMs: TIMEOUT_MS,
|
||||
};
|
||||
export const SANDBOX_ROOT_DIR = "/home/daytona";
|
||||
export const SNAPSHOT_NAME = "daytonaio/langchain-open-swe:0.1.0";
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
} from "../tools/index.js";
|
||||
import { getRepoAbsolutePath } from "../utils/git/index.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 { getCurrentTask } from "../utils/current-task.js";
|
||||
import { getMessageContentString } from "../utils/message/content.js";
|
||||
|
|
@ -134,11 +134,11 @@ export async function generateAction(
|
|||
]);
|
||||
|
||||
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;
|
||||
if (!hasToolCalls && state.sandboxSessionId) {
|
||||
logger.info("No tool calls found. Pausing sandbox...");
|
||||
newSandboxSessionId = await pauseSandbox(state.sandboxSessionId);
|
||||
logger.info("No tool calls found. Stopping sandbox...");
|
||||
newSandboxSessionId = await stopSandbox(state.sandboxSessionId);
|
||||
}
|
||||
|
||||
logger.info("Generated action", {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Sandbox } from "@e2b/code-interpreter";
|
||||
import { Sandbox } from "@daytonaio/sdk";
|
||||
import { createLogger, LogLevel } from "../utils/logger.js";
|
||||
import {
|
||||
GraphState,
|
||||
|
|
@ -6,7 +6,6 @@ import {
|
|||
GraphUpdate,
|
||||
TargetRepository,
|
||||
} from "../types.js";
|
||||
import { TIMEOUT_EXTENSION_OPT } from "../constants.js";
|
||||
import {
|
||||
checkoutBranch,
|
||||
configureGitUserInRepo,
|
||||
|
|
@ -15,11 +14,11 @@ import {
|
|||
pullLatestChanges,
|
||||
} from "../utils/git/index.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 SANDBOX_TEMPLATE_ID = "eh0860emqx28qyxmbctu";
|
||||
|
||||
async function cloneRepo(sandbox: Sandbox, targetRepository: TargetRepository) {
|
||||
if (!process.env.GITHUB_PAT) {
|
||||
throw new Error("GITHUB_PAT environment variable not set.");
|
||||
|
|
@ -39,10 +38,7 @@ async function cloneRepo(sandbox: Sandbox, targetRepository: TargetRepository) {
|
|||
logger.info("Cloning repository", {
|
||||
command: gitCloneCommand.join(" "),
|
||||
});
|
||||
return await sandbox.commands.run(
|
||||
gitCloneCommand.join(" "),
|
||||
TIMEOUT_EXTENSION_OPT,
|
||||
);
|
||||
return await sandbox.process.executeCommand(gitCloneCommand.join(" "));
|
||||
} catch (e) {
|
||||
const errorFields = getSandboxErrorFields(e);
|
||||
logger.error("Failed to clone repository", errorFields ?? e);
|
||||
|
|
@ -78,13 +74,10 @@ export async function initialize(
|
|||
sandboxSessionId,
|
||||
});
|
||||
// Resume the sandbox if the session ID is in the config.
|
||||
const newSandbox = await Sandbox.resume(
|
||||
sandboxSessionId,
|
||||
TIMEOUT_EXTENSION_OPT,
|
||||
);
|
||||
await pullLatestChanges(absoluteRepoDir, newSandbox);
|
||||
const existingSandbox = await daytonaClient().get(sandboxSessionId);
|
||||
await pullLatestChanges(absoluteRepoDir, existingSandbox);
|
||||
return {
|
||||
sandboxSessionId: newSandbox.sandboxId,
|
||||
sandboxSessionId: existingSandbox.id,
|
||||
};
|
||||
} catch (e) {
|
||||
// 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...");
|
||||
const sandbox = await Sandbox.create(
|
||||
SANDBOX_TEMPLATE_ID,
|
||||
TIMEOUT_EXTENSION_OPT,
|
||||
);
|
||||
const sandbox = await daytonaClient().create({
|
||||
image: SNAPSHOT_NAME,
|
||||
});
|
||||
|
||||
const res = await cloneRepo(sandbox, targetRepository);
|
||||
if (res.error) {
|
||||
if (res.exitCode !== 0) {
|
||||
// TODO: This should probably be an interrupt.
|
||||
logger.error("Failed to clone repository", res.error);
|
||||
throw new Error(`Failed to clone repository.\n${res.error}`);
|
||||
logger.error("Failed to clone repository", res.result);
|
||||
throw new Error(`Failed to clone repository.\n${res.result}`);
|
||||
}
|
||||
logger.info("Repository cloned successfully.");
|
||||
|
||||
|
|
@ -123,7 +115,7 @@ export async function initialize(
|
|||
}
|
||||
|
||||
return {
|
||||
sandboxSessionId: sandbox.sandboxId,
|
||||
sandboxSessionId: sandbox.id,
|
||||
targetRepository,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import {
|
|||
HumanInterrupt,
|
||||
HumanResponse,
|
||||
} from "@langchain/langgraph/prebuilt";
|
||||
import { resumeSandbox } from "../utils/sandbox.js";
|
||||
import { startSandbox } from "../utils/sandbox.js";
|
||||
|
||||
export async function interruptPlan(state: GraphState): Promise<Command> {
|
||||
const { proposedPlan } = state;
|
||||
|
|
@ -36,8 +36,7 @@ export async function interruptPlan(state: GraphState): Promise<Command> {
|
|||
}
|
||||
|
||||
if (interruptRes.type === "accept") {
|
||||
const newSandboxSessionId = (await resumeSandbox(state.sandboxSessionId))
|
||||
.sandboxId;
|
||||
const newSandboxSessionId = (await startSandbox(state.sandboxSessionId)).id;
|
||||
|
||||
// Plan was accepted, route to the generate-action node to start taking actions.
|
||||
return new Command({
|
||||
|
|
@ -55,8 +54,7 @@ export async function interruptPlan(state: GraphState): Promise<Command> {
|
|||
}
|
||||
|
||||
if (interruptRes.type === "edit") {
|
||||
const newSandboxSessionId = (await resumeSandbox(state.sandboxSessionId))
|
||||
.sandboxId;
|
||||
const newSandboxSessionId = (await startSandbox(state.sandboxSessionId)).id;
|
||||
|
||||
// Plan was edited, route to the generate-action node to start taking actions.
|
||||
const editedPlan = (interruptRes.args as ActionRequest).args.plan
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { GraphConfig, GraphState, GraphUpdate, PlanItem } from "../types.js";
|
||||
import { Sandbox } from "@e2b/code-interpreter";
|
||||
import {
|
||||
checkoutBranchAndCommit,
|
||||
createPullRequest,
|
||||
|
|
@ -13,6 +12,7 @@ import { loadModel, Task } from "../utils/load-model.js";
|
|||
import { formatPlanPromptWithSummaries } from "../utils/plan-prompt.js";
|
||||
import { isHumanMessage, ToolMessage } from "@langchain/core/messages";
|
||||
import { getMessageContentString } from "../utils/message/content.js";
|
||||
import { daytonaClient } from "../utils/sandbox.js";
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { isAIMessage } from "@langchain/core/messages";
|
|||
import { GraphState } from "../types.js";
|
||||
import { HumanInterrupt, HumanResponse } from "@langchain/langgraph/prebuilt";
|
||||
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 => {
|
||||
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) {
|
||||
throw new Error("Sandbox session ID not found.");
|
||||
}
|
||||
await pauseSandbox(sandboxSessionId);
|
||||
await stopSandbox(sandboxSessionId);
|
||||
|
||||
const toolCall = lastMessage.tool_calls[0];
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ export async function requestHelp(state: GraphState): Promise<Command> {
|
|||
if (typeof interruptRes.args !== "string") {
|
||||
throw new Error("Interrupt response expected to be a string.");
|
||||
}
|
||||
await resumeSandbox(sandboxSessionId);
|
||||
await startSandbox(sandboxSessionId);
|
||||
return new Command({
|
||||
goto: "generate-action",
|
||||
update: {
|
||||
|
|
|
|||
|
|
@ -11,13 +11,13 @@ import {
|
|||
getChangedFilesStatus,
|
||||
getRepoAbsolutePath,
|
||||
} from "../utils/git/index.js";
|
||||
import { Sandbox } from "@e2b/code-interpreter";
|
||||
import {
|
||||
formatBadArgsError,
|
||||
zodSchemaToString,
|
||||
} from "../utils/zod-to-string.js";
|
||||
import { Command } from "@langchain/langgraph";
|
||||
import { truncateOutput } from "../utils/truncate-outputs.js";
|
||||
import { daytonaClient } from "../utils/sandbox.js";
|
||||
|
||||
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.
|
||||
// If there are, commit them.
|
||||
const sandbox = await Sandbox.connect(state.sandboxSessionId);
|
||||
const sandbox = await daytonaClient().get(state.sandboxSessionId);
|
||||
const changedFiles = await getChangedFilesStatus(
|
||||
getRepoAbsolutePath(state.targetRepository),
|
||||
sandbox,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { sessionPlanTool } from "../../../tools/index.js";
|
|||
import { GraphConfig } from "../../../types.js";
|
||||
import { loadModel, Task } from "../../../utils/load-model.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.
|
||||
|
||||
|
|
@ -68,8 +68,8 @@ export async function generatePlan(
|
|||
|
||||
let newSessionId: string | undefined;
|
||||
if (state.sandboxSessionId) {
|
||||
// Pause before returning, as the next step will be to interrupt the graph.
|
||||
newSessionId = await pauseSandbox(state.sandboxSessionId);
|
||||
// Stop before returning, as the next step will be to interrupt the graph.
|
||||
newSessionId = await stopSandbox(state.sandboxSessionId);
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@ import { tool } from "@langchain/core/tools";
|
|||
import { z } from "zod";
|
||||
import { applyPatch } from "diff";
|
||||
import { GraphState } from "../types.js";
|
||||
import { Sandbox } from "@e2b/code-interpreter";
|
||||
import { readFile, writeFile } from "../utils/read-write.js";
|
||||
import { getCurrentTaskInput } from "@langchain/langgraph";
|
||||
import { fixGitPatch } from "../utils/diff.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");
|
||||
|
||||
|
|
@ -19,9 +20,9 @@ const applyPatchToolSchema = z.object({
|
|||
file_path: z.string().describe("The file path to apply the diff to."),
|
||||
workdir: z
|
||||
.string()
|
||||
.default("/home/user")
|
||||
.default(SANDBOX_ROOT_DIR)
|
||||
.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 sandbox = await Sandbox.connect(sandboxSessionId);
|
||||
const sandbox = await daytonaClient().get(sandboxSessionId);
|
||||
|
||||
const { success: readFileSuccess, output: readFileOutput } = await readFile(
|
||||
sandbox,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import { tool } from "@langchain/core/tools";
|
||||
import { z } from "zod";
|
||||
import { Sandbox } from "@e2b/code-interpreter";
|
||||
import { Sandbox } from "@daytonaio/sdk";
|
||||
import { GraphState } from "../types.js";
|
||||
import { getCurrentTaskInput } from "@langchain/langgraph";
|
||||
import { TIMEOUT_MS } from "../constants.js";
|
||||
import { getSandboxErrorFields } from "../utils/sandbox-error-fields.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");
|
||||
|
||||
|
|
@ -20,9 +21,9 @@ const shellToolSchema = z.object({
|
|||
command: z.array(z.string()).describe("The command to run"),
|
||||
workdir: z
|
||||
.string()
|
||||
.default("/home/user")
|
||||
.default(SANDBOX_ROOT_DIR)
|
||||
.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
|
||||
.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 result = await sandbox.commands.run(command.join(" "), {
|
||||
timeoutMs: timeout ?? DEFAULT_COMMAND_TIMEOUT,
|
||||
cwd: workdir,
|
||||
envs: DEFAULT_ENV,
|
||||
});
|
||||
const response = await sandbox.process.executeCommand(
|
||||
command.join(" "),
|
||||
workdir,
|
||||
DEFAULT_ENV,
|
||||
timeout ?? DEFAULT_COMMAND_TIMEOUT,
|
||||
);
|
||||
|
||||
if (result.error) {
|
||||
if (response.exitCode !== 0) {
|
||||
logger.error("Failed to run command", {
|
||||
error: result.error,
|
||||
error_result: result,
|
||||
error: response.result,
|
||||
error_result: response,
|
||||
input,
|
||||
});
|
||||
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",
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
result: result.stdout,
|
||||
result: response.result,
|
||||
status: "success",
|
||||
};
|
||||
} catch (e) {
|
||||
|
|
@ -80,7 +82,7 @@ export const shellTool = tool(
|
|||
error: errorFields,
|
||||
});
|
||||
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",
|
||||
};
|
||||
}
|
||||
|
|
@ -97,17 +99,6 @@ export const shellTool = tool(
|
|||
"FAILED TO RUN COMMAND: " +
|
||||
(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.",
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import { Octokit } from "@octokit/rest";
|
||||
import { CommandResult, Sandbox } from "@e2b/code-interpreter";
|
||||
import { Sandbox } from "@daytonaio/sdk";
|
||||
import { createLogger, LogLevel } from "../logger.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 { ExecuteResponse } from "@daytonaio/sdk/dist/types/ExecuteResponse.js";
|
||||
|
||||
const logger = createLogger(LogLevel.INFO, "GitUtil");
|
||||
|
||||
|
|
@ -15,7 +16,7 @@ export function getRepoAbsolutePath(
|
|||
throw new Error("No repository name provided");
|
||||
}
|
||||
|
||||
return `/home/user/${repoName}`;
|
||||
return `${SANDBOX_ROOT_DIR}/${repoName}`;
|
||||
}
|
||||
|
||||
export function getBranchName(config: GraphConfig): string {
|
||||
|
|
@ -31,27 +32,27 @@ export async function checkoutBranch(
|
|||
absoluteRepoDir: string,
|
||||
branchName: string,
|
||||
sandbox: Sandbox,
|
||||
): Promise<CommandResult | false> {
|
||||
): Promise<ExecuteResponse | false> {
|
||||
logger.info(`Checking out branch '${branchName}'...`);
|
||||
|
||||
try {
|
||||
const getCurrentBranchOutput = await sandbox.commands.run(
|
||||
const getCurrentBranchOutput = await sandbox.process.executeCommand(
|
||||
"git branch --show-current",
|
||||
{ cwd: absoluteRepoDir },
|
||||
absoluteRepoDir,
|
||||
undefined,
|
||||
TIMEOUT_MS,
|
||||
);
|
||||
await sandbox.setTimeout(TIMEOUT_MS);
|
||||
|
||||
if (getCurrentBranchOutput.exitCode !== 0) {
|
||||
logger.error(`Failed to get current branch`, {
|
||||
getCurrentBranchOutput,
|
||||
});
|
||||
} else {
|
||||
const currentBranch = getCurrentBranchOutput.stdout.trim();
|
||||
const currentBranch = getCurrentBranchOutput.result.trim();
|
||||
if (currentBranch === branchName) {
|
||||
logger.info(`Already on branch '${branchName}'. No checkout needed.`);
|
||||
return {
|
||||
stdout: `Already on branch ${branchName}`,
|
||||
stderr: "",
|
||||
result: `Already on branch ${branchName}`,
|
||||
exitCode: 0,
|
||||
};
|
||||
}
|
||||
|
|
@ -75,11 +76,12 @@ export async function checkoutBranch(
|
|||
`Checking if branch 'refs/heads/${branchName}' exists using 'git rev-parse --verify --quiet'`,
|
||||
);
|
||||
// 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}"`,
|
||||
{ cwd: absoluteRepoDir },
|
||||
absoluteRepoDir,
|
||||
undefined,
|
||||
TIMEOUT_MS,
|
||||
);
|
||||
await sandbox.setTimeout(TIMEOUT_MS);
|
||||
|
||||
if (checkBranchExistsOutput.exitCode === 0) {
|
||||
// Branch exists (rev-parse exit code 0 means success)
|
||||
|
|
@ -94,7 +96,7 @@ export async function checkoutBranch(
|
|||
if (
|
||||
errorFields &&
|
||||
errorFields.exitCode === 1 &&
|
||||
errorFields.stderr === ""
|
||||
errorFields.result === ""
|
||||
) {
|
||||
checkoutCommand = `git checkout -b "${branchName}"`;
|
||||
} else {
|
||||
|
|
@ -110,9 +112,12 @@ export async function checkoutBranch(
|
|||
}
|
||||
|
||||
try {
|
||||
const gitCheckoutOutput = await sandbox.commands.run(checkoutCommand, {
|
||||
cwd: absoluteRepoDir,
|
||||
});
|
||||
const gitCheckoutOutput = await sandbox.process.executeCommand(
|
||||
checkoutCommand,
|
||||
absoluteRepoDir,
|
||||
undefined,
|
||||
TIMEOUT_MS,
|
||||
);
|
||||
|
||||
if (gitCheckoutOutput.exitCode !== 0) {
|
||||
logger.error(`Failed to checkout branch`, {
|
||||
|
|
@ -212,20 +217,24 @@ export async function configureGitUserInRepo(
|
|||
): Promise<void> {
|
||||
let needsGitConfig = false;
|
||||
try {
|
||||
const nameCheck = await sandbox.commands.run("git config user.name", {
|
||||
cwd: absoluteRepoDir,
|
||||
});
|
||||
await sandbox.setTimeout(TIMEOUT_MS);
|
||||
const emailCheck = await sandbox.commands.run("git config user.email", {
|
||||
cwd: absoluteRepoDir,
|
||||
});
|
||||
await sandbox.setTimeout(TIMEOUT_MS);
|
||||
const nameCheck = await sandbox.process.executeCommand(
|
||||
"git config user.name",
|
||||
absoluteRepoDir,
|
||||
undefined,
|
||||
TIMEOUT_MS,
|
||||
);
|
||||
const emailCheck = await sandbox.process.executeCommand(
|
||||
"git config user.email",
|
||||
absoluteRepoDir,
|
||||
undefined,
|
||||
TIMEOUT_MS,
|
||||
);
|
||||
|
||||
if (
|
||||
nameCheck.exitCode !== 0 ||
|
||||
nameCheck.stdout.trim() === "" ||
|
||||
nameCheck.result.trim() === "" ||
|
||||
emailCheck.exitCode !== 0 ||
|
||||
emailCheck.stdout.trim() === ""
|
||||
emailCheck.result.trim() === ""
|
||||
) {
|
||||
needsGitConfig = true;
|
||||
}
|
||||
|
|
@ -244,11 +253,12 @@ export async function configureGitUserInRepo(
|
|||
const { userName, userEmail } = await getGitUserDetailsFromGitHub();
|
||||
|
||||
if (userName) {
|
||||
const configUserNameOutput = await sandbox.commands.run(
|
||||
const configUserNameOutput = await sandbox.process.executeCommand(
|
||||
`git config user.name "${userName}"`,
|
||||
{ cwd: absoluteRepoDir },
|
||||
absoluteRepoDir,
|
||||
undefined,
|
||||
TIMEOUT_MS,
|
||||
);
|
||||
await sandbox.setTimeout(TIMEOUT_MS);
|
||||
if (configUserNameOutput.exitCode !== 0) {
|
||||
logger.error(`Failed to set git user.name`, {
|
||||
configUserNameOutput,
|
||||
|
|
@ -259,11 +269,12 @@ export async function configureGitUserInRepo(
|
|||
}
|
||||
|
||||
if (userEmail) {
|
||||
const configUserEmailOutput = await sandbox.commands.run(
|
||||
const configUserEmailOutput = await sandbox.process.executeCommand(
|
||||
`git config user.email "${userEmail}"`,
|
||||
{ cwd: absoluteRepoDir },
|
||||
absoluteRepoDir,
|
||||
undefined,
|
||||
TIMEOUT_MS,
|
||||
);
|
||||
await sandbox.setTimeout(TIMEOUT_MS);
|
||||
if (configUserEmailOutput.exitCode !== 0) {
|
||||
logger.error(`Failed to set git user.email`, {
|
||||
configUserEmailOutput,
|
||||
|
|
@ -283,13 +294,14 @@ export async function commitAll(
|
|||
absoluteRepoDir: string,
|
||||
message: string,
|
||||
sandbox: Sandbox,
|
||||
): Promise<CommandResult | false> {
|
||||
): Promise<ExecuteResponse | false> {
|
||||
try {
|
||||
const gitAddOutput = await sandbox.commands.run(
|
||||
const gitAddOutput = await sandbox.process.executeCommand(
|
||||
`git add -A && git commit -m "${message}"`,
|
||||
{ cwd: absoluteRepoDir },
|
||||
absoluteRepoDir,
|
||||
undefined,
|
||||
TIMEOUT_MS,
|
||||
);
|
||||
await sandbox.setTimeout(TIMEOUT_MS);
|
||||
|
||||
if (gitAddOutput.exitCode !== 0) {
|
||||
logger.error(`Failed to commit all changes to git repository`, {
|
||||
|
|
@ -315,7 +327,7 @@ export async function commitAllAndPush(
|
|||
absoluteRepoDir: string,
|
||||
message: string,
|
||||
sandbox: Sandbox,
|
||||
): Promise<CommandResult | false> {
|
||||
): Promise<ExecuteResponse | false> {
|
||||
try {
|
||||
const commitOutput = await commitAll(absoluteRepoDir, message, sandbox);
|
||||
|
||||
|
|
@ -326,10 +338,12 @@ export async function commitAllAndPush(
|
|||
return false;
|
||||
}
|
||||
|
||||
const gitPushOutput = await sandbox.commands.run(pushCurrentBranchCmd, {
|
||||
cwd: absoluteRepoDir,
|
||||
});
|
||||
await sandbox.setTimeout(TIMEOUT_MS);
|
||||
const gitPushOutput = await sandbox.process.executeCommand(
|
||||
pushCurrentBranchCmd,
|
||||
absoluteRepoDir,
|
||||
undefined,
|
||||
TIMEOUT_MS,
|
||||
);
|
||||
|
||||
if (gitPushOutput.exitCode !== 0) {
|
||||
logger.error(`Failed to push changes to git repository`, {
|
||||
|
|
@ -357,9 +371,12 @@ export async function getChangedFilesStatus(
|
|||
absoluteRepoDir: string,
|
||||
sandbox: Sandbox,
|
||||
): Promise<string[]> {
|
||||
const gitStatusOutput = await sandbox.commands.run("git status --porcelain", {
|
||||
cwd: absoluteRepoDir,
|
||||
});
|
||||
const gitStatusOutput = await sandbox.process.executeCommand(
|
||||
"git status --porcelain",
|
||||
absoluteRepoDir,
|
||||
undefined,
|
||||
TIMEOUT_MS,
|
||||
);
|
||||
|
||||
if (gitStatusOutput.exitCode !== 0) {
|
||||
logger.error(`Failed to get changed files status`, {
|
||||
|
|
@ -368,7 +385,7 @@ export async function getChangedFilesStatus(
|
|||
return [];
|
||||
}
|
||||
|
||||
return gitStatusOutput.stdout
|
||||
return gitStatusOutput.result
|
||||
.split("\n")
|
||||
.map((line) => line.trim())
|
||||
.filter((line) => line !== "");
|
||||
|
|
@ -453,12 +470,14 @@ export async function createPullRequest({
|
|||
export async function pullLatestChanges(
|
||||
absoluteRepoDir: string,
|
||||
sandbox: Sandbox,
|
||||
): Promise<CommandResult | false> {
|
||||
): Promise<ExecuteResponse | false> {
|
||||
try {
|
||||
const gitPullOutput = await sandbox.commands.run("git pull", {
|
||||
cwd: absoluteRepoDir,
|
||||
});
|
||||
await sandbox.setTimeout(TIMEOUT_MS);
|
||||
const gitPullOutput = await sandbox.process.executeCommand(
|
||||
"git pull",
|
||||
absoluteRepoDir,
|
||||
undefined,
|
||||
TIMEOUT_MS,
|
||||
);
|
||||
return gitPullOutput;
|
||||
} catch (e) {
|
||||
const errorFields = getSandboxErrorFields(e);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { Sandbox } from "@e2b/code-interpreter";
|
||||
import { Sandbox } from "@daytonaio/sdk";
|
||||
import { createLogger, LogLevel } from "./logger.js";
|
||||
import { TIMEOUT_MS } from "../constants.js";
|
||||
import { getSandboxErrorFields } from "./sandbox-error-fields.js";
|
||||
import { traceable } from "langsmith/traceable";
|
||||
|
||||
|
|
@ -15,9 +14,10 @@ async function handleCreateFile(
|
|||
) {
|
||||
try {
|
||||
const touchCommand = `touch "${filePath}"`;
|
||||
const touchOutput = await sandbox.commands.run(touchCommand, {
|
||||
cwd: args?.workDir,
|
||||
});
|
||||
const touchOutput = await sandbox.process.executeCommand(
|
||||
touchCommand,
|
||||
args?.workDir,
|
||||
);
|
||||
return touchOutput;
|
||||
} catch (e) {
|
||||
const errorFields = getSandboxErrorFields(e);
|
||||
|
|
@ -44,9 +44,10 @@ async function readFileFunc(
|
|||
output: string;
|
||||
}> {
|
||||
try {
|
||||
const readOutput = await sandbox.commands.run(`cat "${filePath}"`, {
|
||||
cwd: args?.workDir,
|
||||
});
|
||||
const readOutput = await sandbox.process.executeCommand(
|
||||
`cat "${filePath}"`,
|
||||
args?.workDir,
|
||||
);
|
||||
|
||||
if (readOutput.exitCode !== 0) {
|
||||
logger.error(`Error reading file '${filePath}' from sandbox via cat:`, {
|
||||
|
|
@ -54,13 +55,13 @@ async function readFileFunc(
|
|||
});
|
||||
return {
|
||||
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 {
|
||||
success: true,
|
||||
output: readOutput.stdout,
|
||||
output: readOutput.result,
|
||||
};
|
||||
} catch (e: any) {
|
||||
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}'.`;
|
||||
const errorFields = getSandboxErrorFields(e);
|
||||
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 {
|
||||
outputMessage += ` Error: ${(e as Error).message || String(e)}`;
|
||||
}
|
||||
|
|
@ -100,17 +101,6 @@ async function readFileFunc(
|
|||
success: false,
|
||||
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}'
|
||||
${content}
|
||||
${delimiter}`;
|
||||
const writeOutput = await sandbox.commands.run(writeCommand, {
|
||||
cwd: args?.workDir,
|
||||
});
|
||||
const writeOutput = await sandbox.process.executeCommand(
|
||||
writeCommand,
|
||||
args?.workDir,
|
||||
);
|
||||
|
||||
if (writeOutput.exitCode !== 0) {
|
||||
logger.error(`Error writing file '${filePath}' to sandbox via cat:`, {
|
||||
|
|
@ -144,14 +135,9 @@ ${delimiter}`;
|
|||
});
|
||||
return {
|
||||
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 {
|
||||
success: true,
|
||||
output: `Successfully wrote file '${filePath}' to sandbox via cat.`,
|
||||
|
|
@ -169,7 +155,7 @@ ${delimiter}`;
|
|||
let outputMessage = `FAILED TO EXECUTE WRITE COMMAND for sandbox '${filePath}'.`;
|
||||
const errorFields = getSandboxErrorFields(e);
|
||||
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 {
|
||||
outputMessage += ` Error: ${(e as Error).message || String(e)}`;
|
||||
}
|
||||
|
|
@ -178,17 +164,6 @@ ${delimiter}`;
|
|||
success: false,
|
||||
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.",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { CommandResult } from "@e2b/code-interpreter";
|
||||
import { ExecuteResponse } from "@daytonaio/sdk/dist/types/ExecuteResponse.js";
|
||||
|
||||
export function getSandboxErrorFields(
|
||||
error: unknown,
|
||||
): CommandResult | undefined {
|
||||
): ExecuteResponse | undefined {
|
||||
if (
|
||||
!error ||
|
||||
typeof error !== "object" ||
|
||||
|
|
@ -16,5 +16,5 @@ export function getSandboxErrorFields(
|
|||
return undefined;
|
||||
}
|
||||
|
||||
return error.result as CommandResult;
|
||||
return error.result as unknown as ExecuteResponse;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
* @param sandboxSessionId The ID of the sandbox to pause.
|
||||
* @param sandbox The sandbox client to pause. If not provided, the sandbox will be connected to.
|
||||
* @param sandboxSessionId The ID of the sandbox to stop.
|
||||
* @param sandbox The sandbox client to stop. If not provided, the sandbox will be connected to.
|
||||
* @returns The sandbox session ID.
|
||||
*/
|
||||
export async function pauseSandbox(
|
||||
sandboxSessionId: string,
|
||||
sandbox?: Sandbox,
|
||||
): Promise<string> {
|
||||
const sandboxClient = sandbox ?? (await Sandbox.connect(sandboxSessionId));
|
||||
return await sandboxClient.pause();
|
||||
export async function stopSandbox(sandboxSessionId: string): Promise<string> {
|
||||
const sandbox = await daytonaClient().get(sandboxSessionId);
|
||||
if (
|
||||
sandbox.instance.state == SandboxState.STOPPED ||
|
||||
sandbox.instance.state == SandboxState.ARCHIVED
|
||||
) {
|
||||
return sandboxSessionId;
|
||||
} else if (sandbox.instance.state == "started") {
|
||||
await daytonaClient().stop(sandbox);
|
||||
}
|
||||
|
||||
return sandbox.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes the sandbox.
|
||||
* @param sandboxSessionId The ID of the sandbox to resume.
|
||||
* Starts the sandbox.
|
||||
* @param sandboxSessionId The ID of the sandbox to start.
|
||||
* @returns The sandbox client.
|
||||
*/
|
||||
export async function resumeSandbox(
|
||||
sandboxSessionId: string,
|
||||
): Promise<Sandbox> {
|
||||
return await Sandbox.resume(sandboxSessionId);
|
||||
export async function startSandbox(sandboxSessionId: string): Promise<Sandbox> {
|
||||
const sandbox = await daytonaClient().get(sandboxSessionId);
|
||||
if (
|
||||
sandbox.instance.state == SandboxState.STOPPED ||
|
||||
sandbox.instance.state == SandboxState.ARCHIVED
|
||||
) {
|
||||
await daytonaClient().start(sandbox);
|
||||
}
|
||||
return sandbox;
|
||||
}
|
||||
|
|
|
|||
206
yarn.lock
206
yarn.lock
|
|
@ -449,13 +449,6 @@ __metadata:
|
|||
languageName: node
|
||||
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":
|
||||
version: 4.1.1
|
||||
resolution: "@cfworker/json-schema@npm:4.1.1"
|
||||
|
|
@ -479,25 +472,6 @@ __metadata:
|
|||
languageName: node
|
||||
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":
|
||||
version: 2.0.3
|
||||
resolution: "@dabh/diagnostics@npm:2.0.3"
|
||||
|
|
@ -509,12 +483,54 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@e2b/code-interpreter@npm:1.2.0-beta.4":
|
||||
version: 1.2.0-beta.4
|
||||
resolution: "@e2b/code-interpreter@npm:1.2.0-beta.4"
|
||||
"@daytonaio/api-client@npm:^0.19.1":
|
||||
version: 0.19.1
|
||||
resolution: "@daytonaio/api-client@npm:0.19.1"
|
||||
dependencies:
|
||||
e2b: 1.2.0-beta.4
|
||||
checksum: c08fb0381482156301f1147bf5cf71bab7c817afa7c02613bde3dc1b8c7011f9aca14b9edd1e4e9c365cec486818b8d3e5c54b1e7bcc70248bdf722a5b4026bd
|
||||
axios: ^1.6.1
|
||||
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
|
||||
linkType: hard
|
||||
|
||||
|
|
@ -2416,6 +2432,29 @@ __metadata:
|
|||
languageName: node
|
||||
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":
|
||||
version: 2.1.5
|
||||
resolution: "@nodelib/fs.scandir@npm:2.1.5"
|
||||
|
|
@ -2608,7 +2647,7 @@ __metadata:
|
|||
version: 0.0.0-use.local
|
||||
resolution: "@open-swe/agent@workspace:apps/open-swe"
|
||||
dependencies:
|
||||
"@e2b/code-interpreter": 1.2.0-beta.4
|
||||
"@daytonaio/sdk": ^0.18.1
|
||||
"@eslint/eslintrc": ^3.1.0
|
||||
"@eslint/js": ^9.19.0
|
||||
"@jest/globals": ^29.7.0
|
||||
|
|
@ -5375,7 +5414,7 @@ __metadata:
|
|||
languageName: node
|
||||
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
|
||||
resolution: "axios@npm:1.9.0"
|
||||
dependencies:
|
||||
|
|
@ -6240,6 +6279,13 @@ __metadata:
|
|||
languageName: node
|
||||
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":
|
||||
version: 13.1.0
|
||||
resolution: "commander@npm:13.1.0"
|
||||
|
|
@ -6254,13 +6300,6 @@ __metadata:
|
|||
languageName: node
|
||||
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":
|
||||
version: 0.0.1
|
||||
resolution: "concat-map@npm:0.0.1"
|
||||
|
|
@ -6876,7 +6915,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dotenv@npm:^16.4.7":
|
||||
"dotenv@npm:^16.4.5, dotenv@npm:^16.4.7":
|
||||
version: 16.5.0
|
||||
resolution: "dotenv@npm:16.5.0"
|
||||
checksum: 6543fe87b5ddf2d60dd42df6616eec99148a5fc150cb4530fef5bda655db5204a3afa0e6f25f7cd64b20657ace4d79c0ef974bec32fdb462cad18754191e7a90
|
||||
|
|
@ -6894,20 +6933,6 @@ __metadata:
|
|||
languageName: node
|
||||
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":
|
||||
version: 0.2.0
|
||||
resolution: "eastasianwidth@npm:0.2.0"
|
||||
|
|
@ -6915,6 +6940,18 @@ __metadata:
|
|||
languageName: node
|
||||
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":
|
||||
version: 1.1.1
|
||||
resolution: "ee-first@npm:1.1.1"
|
||||
|
|
@ -7879,7 +7916,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"execa@npm:^5.0.0":
|
||||
"execa@npm:^5.0.0, execa@npm:^5.1.1":
|
||||
version: 5.1.1
|
||||
resolution: "execa@npm:5.1.1"
|
||||
dependencies:
|
||||
|
|
@ -8189,6 +8226,18 @@ __metadata:
|
|||
languageName: node
|
||||
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":
|
||||
version: 6.4.4
|
||||
resolution: "fdir@npm:6.4.4"
|
||||
|
|
@ -9284,7 +9333,7 @@ __metadata:
|
|||
languageName: node
|
||||
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
|
||||
resolution: "ignore@npm:5.3.2"
|
||||
checksum: 2acfd32a573260ea522ea0bfeff880af426d68f6831f973129e2ba7363f422923cf53aab62f8369cbf4667c7b25b6f8a3761b34ecdb284ea18e87a5262a865be
|
||||
|
|
@ -12549,6 +12598,13 @@ __metadata:
|
|||
languageName: node
|
||||
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":
|
||||
version: 4.1.7
|
||||
resolution: "object.assign@npm:4.1.7"
|
||||
|
|
@ -12703,15 +12759,6 @@ __metadata:
|
|||
languageName: node
|
||||
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":
|
||||
version: 12.1.3
|
||||
resolution: "openapi-types@npm:12.1.3"
|
||||
|
|
@ -12719,13 +12766,6 @@ __metadata:
|
|||
languageName: node
|
||||
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":
|
||||
version: 0.9.4
|
||||
resolution: "optionator@npm:0.9.4"
|
||||
|
|
@ -13111,13 +13151,6 @@ __metadata:
|
|||
languageName: node
|
||||
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":
|
||||
version: 1.1.1
|
||||
resolution: "pony-cause@npm:1.1.1"
|
||||
|
|
@ -16184,7 +16217,7 @@ __metadata:
|
|||
languageName: node
|
||||
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
|
||||
resolution: "uuid@npm:11.1.0"
|
||||
bin:
|
||||
|
|
@ -16403,6 +16436,17 @@ __metadata:
|
|||
languageName: node
|
||||
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":
|
||||
version: 5.0.0
|
||||
resolution: "which@npm:5.0.0"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue