e30e75b5d4
Changesets / Create Version PR (push) Has been cancelled
Deploy Shadcn Registry / Deploy Production (push) Has been cancelled
Template Metrics / LOC + Bundle Size (push) Has been cancelled
Code Quality / Oxlint + Oxfmt (push) Has been cancelled
Code Quality / Template Sync (push) Has been cancelled
Code Quality / Build Changed Packages (push) Has been cancelled
Code Quality / Test Changed Packages (push) Has been cancelled
Deploy Expo Example / Deploy Production (push) Has been cancelled
Deploy Ink Example / Deploy Production (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.12) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.12) (push) Has been cancelled
79 lines
2.5 KiB
TypeScript
79 lines
2.5 KiB
TypeScript
import { tool, zodSchema } from "ai";
|
|
import z from "zod";
|
|
import {
|
|
fetchPreviewUrl,
|
|
provisionSandbox,
|
|
type SandboxExec,
|
|
} from "../../blaxel-sandbox";
|
|
|
|
export function createSandboxTools({
|
|
sessionId,
|
|
}: {
|
|
sessionId: string | undefined;
|
|
}) {
|
|
let sandboxExec: SandboxExec | null = null;
|
|
|
|
return {
|
|
provisionSandbox: tool({
|
|
description:
|
|
"Provision (or resume) the cloud sandbox for this session. Call this once before using exec.",
|
|
inputSchema: zodSchema(z.object({})),
|
|
execute: async () => {
|
|
if (!sessionId) {
|
|
return { error: "No sessionId provided in the request body." };
|
|
}
|
|
try {
|
|
const sandbox = await provisionSandbox(sessionId);
|
|
sandboxExec = sandbox.exec;
|
|
return {
|
|
status: "ready",
|
|
workingDir: "/workspace",
|
|
previewUrl: sandbox.previewUrl,
|
|
};
|
|
} catch (err) {
|
|
return {
|
|
error: err instanceof Error ? err.message : String(err),
|
|
};
|
|
}
|
|
},
|
|
}),
|
|
refreshCanvas: tool({
|
|
description:
|
|
"Fetch the live preview URL from the sandbox and return it to the client to refresh the canvas. Call after starting the dev server or making changes.",
|
|
inputSchema: zodSchema(z.object({})),
|
|
execute: async () => {
|
|
if (!sessionId) return { error: "No sessionId in request." };
|
|
try {
|
|
const url = await fetchPreviewUrl(sessionId);
|
|
return { url };
|
|
} catch (err) {
|
|
return {
|
|
error: err instanceof Error ? err.message : String(err),
|
|
};
|
|
}
|
|
},
|
|
}),
|
|
exec: tool({
|
|
description:
|
|
"Run a shell command in the live sandbox. Use this to read/write files, install deps, start servers, etc. " +
|
|
"The sandbox does not have Python, lsof, or pkill pre-installed. Prefer Node-based file edits in Node apps. " +
|
|
"Before cat/heredoc file writes, create all parent folders so missing directories do not cause partial writes.",
|
|
inputSchema: zodSchema(
|
|
z.object({
|
|
command: z.string().describe("Shell command to run."),
|
|
cwd: z
|
|
.string()
|
|
.optional()
|
|
.describe("Working directory (default: /workspace)."),
|
|
}),
|
|
),
|
|
execute: async ({ command, cwd }) => {
|
|
if (!sandboxExec) {
|
|
return { error: "Call provisionSandbox first." };
|
|
}
|
|
return sandboxExec(command, cwd);
|
|
},
|
|
}),
|
|
};
|
|
}
|