fix: Initialize sandbox after planning (#6)

* fix: Initialize sandbox after planning

* fix routing in interrupt node

* cr
This commit is contained in:
Brace Sproul 2025-05-22 11:40:54 -07:00 • committed by GitHub
parent 220e36c9f8
commit 424124c286
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 22 additions and 24 deletions

View file

@ -45,22 +45,21 @@ function takeActionOrEnd(state: GraphState): typeof END | "take-action" {
}
const workflow = new StateGraph(GraphAnnotation, GraphConfiguration)
.addNode("initialize", initialize)
.addNode("generate-plan", generatePlan)
.addNode("rewrite-plan", rewritePlan)
.addNode("interrupt-plan", interruptPlan, {
// TODO: Hookup `Command` in interruptPlan node so this actually works.
ends: [END, "rewrite-plan", "generate-action"],
ends: [END, "rewrite-plan", "initialize"],
})
.addNode("initialize", initialize)
.addNode("generate-action", generateAction)
.addNode("take-action", takeAction)
.addEdge(START, "initialize")
.addEdge("initialize", "generate-plan")
.addEdge(START, "generate-plan")
// TODO: Update routing to work w/ new interrupt node.
.addConditionalEdges("generate-plan", routeAfterPlan, ["interrupt-plan", END])
// Always interrupt after rewriting the plan.
.addEdge("rewrite-plan", "interrupt-plan")
.addEdge("generate-plan", "generate-action")
.addEdge("initialize", "generate-action")
.addConditionalEdges("generate-action", takeActionOrEnd, ["take-action", END])
.addEdge("take-action", "generate-action");

View file

@ -46,8 +46,14 @@ export async function initialize(
const { sandbox_session_id, target_repository, sandbox_language } =
config.configurable;
if (sandbox_session_id) {
// Session already initialized. Return early.
return {};
try {
// Resume the sandbox if the session ID is in the config.
await Sandbox.resume(sandbox_session_id, TIMEOUT_EXTENSION_OPT);
return {};
} catch (e) {
// Error thrown, log it and continue. Will create a new sandbox session since the resumption failed.
console.error("Failed to get sandbox session.", e);
}
}
if (!sandbox_language || !target_repository) {
@ -57,23 +63,16 @@ export async function initialize(
}
if (sandbox_language === "js") {
const sandbox = await Sandbox.create(JS_SANDBOX_TEMPLATE_ID);
const sandbox = await Sandbox.create(
JS_SANDBOX_TEMPLATE_ID,
TIMEOUT_EXTENSION_OPT,
);
config.configurable.sandbox_session_id = sandbox.sandboxId;
const res = await cloneRepo(sandbox, target_repository);
if (res.error) {
let errorMessage = "Failed to clone repository.";
if (res.error) {
// Basic redaction attempt for the token in the URL if present in the error
errorMessage +=
": " + res.error.replace(/:\/\/[^@]+@/, "://<REDACTED_TOKEN>@");
} else if (typeof res.error === "string") {
errorMessage +=
": " + res.error.replace(/:\/\/[^@]+@/, "://<REDACTED_TOKEN>@");
} else {
errorMessage += " An unknown error occurred.";
}
throw new Error(errorMessage);
// TODO: This should probably be an interrupt.
throw new Error(`Failed to clone repository.\n${res.error}`);
}
return {};
}

View file

@ -31,9 +31,9 @@ export function interruptPlan(state: GraphState): Command {
})[0];
if (interruptRes.type === "accept") {
// Plan was accepted, route to the generate action node.
// Plan was accepted, route to the initialize node.
return new Command({
goto: "generate-action",
goto: "initialize",
update: {
plan: proposedPlan.map((p) => ({
id: uuidv4(),
@ -45,12 +45,12 @@ export function interruptPlan(state: GraphState): Command {
}
if (interruptRes.type === "edit") {
// Plan was edited, route to the generate action node.
// Plan was edited, route to the initialize node.
const editedPlan = (interruptRes.args as ActionRequest).args.plan
.split(":::")
.map((step: string) => step.trim());
return new Command({
goto: "generate-action",
goto: "initialize",
update: {
plan: editedPlan.map((p: string) => ({
id: uuidv4(),