Files
wehub-resource-sync 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
chore: import upstream snapshot with attribution
2026-07-13 13:40:13 +08:00

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);
},
}),
};
}