UNPKG

@tanstack/ai-code-mode

Version:

Code Mode for TanStack AI - LLM-driven code execution in secure sandboxes

143 lines (142 loc) 5.01 kB
import { z } from "zod"; import { toolDefinition } from "@tanstack/ai"; import { toolsToBindings, createEventAwareBindings } from "./bindings/tool-to-binding.js"; import { stripTypeScript } from "./strip-typescript.js"; const executeTypescriptInputSchema = z.object({ typescriptCode: z.string().describe( "TypeScript code to execute in the sandbox. Use external_* functions to call available APIs. Return a value to pass results back." ) }); const executeTypescriptOutputSchema = z.object({ success: z.boolean().describe("Whether execution completed without errors"), result: z.unknown().optional().describe("Return value from the executed code"), logs: z.array(z.string()).optional().describe("Console output captured during execution"), error: z.object({ message: z.string(), name: z.string().optional(), line: z.number().optional() }).optional().describe("Error details if execution failed") }); function createCodeModeTool(config) { const { driver, tools, timeout = 3e4, memoryLimit = 128, getSkillBindings } = config; if (tools.length === 0) { throw new Error("At least one tool must be provided to createCodeModeTool"); } const staticBindings = toolsToBindings(tools, "external_"); const definition = toolDefinition({ name: "execute_typescript", description: buildToolDescription(tools), inputSchema: executeTypescriptInputSchema, outputSchema: executeTypescriptOutputSchema }); return definition.server( async (input, toolContext) => { const { typescriptCode } = input; const emitCustomEvent = toolContext?.emitCustomEvent || (() => { }); if (!typescriptCode || typeof typescriptCode !== "string") { return { success: false, error: { message: "typescriptCode must be a non-empty string", name: "ValidationError" } }; } let isolateContext = null; emitCustomEvent("code_mode:execution_started", { timestamp: Date.now(), codeLength: typescriptCode.length }); try { let strippedCode; try { strippedCode = await stripTypeScript(typescriptCode); } catch (error) { return { success: false, error: { message: error instanceof Error ? error.message : String(error), name: "TypeScriptError" } }; } const skillBindings = getSkillBindings ? await getSkillBindings() : {}; const allBindings = { ...staticBindings, ...skillBindings }; const eventAwareBindings = createEventAwareBindings( allBindings, emitCustomEvent ); isolateContext = await driver.createContext({ bindings: eventAwareBindings, timeout, memoryLimit }); const executionResult = await isolateContext.execute(strippedCode); if (executionResult.logs && executionResult.logs.length > 0) { for (const log of executionResult.logs) { let level = "log"; let message = log; if (log.startsWith("ERROR: ")) { level = "error"; message = log.slice(7); } else if (log.startsWith("WARN: ")) { level = "warn"; message = log.slice(6); } else if (log.startsWith("INFO: ")) { level = "info"; message = log.slice(6); } emitCustomEvent("code_mode:console", { level, message, timestamp: Date.now() }); } } if (executionResult.success) { return { success: true, result: executionResult.value, logs: executionResult.logs }; } else { return { success: false, error: executionResult.error ? { message: executionResult.error.message, name: executionResult.error.name } : { message: "Unknown execution error" }, logs: executionResult.logs }; } } catch (error) { return { success: false, error: { message: error instanceof Error ? error.message : String(error), name: error instanceof Error ? error.name : "Error" } }; } finally { if (isolateContext) { await isolateContext.dispose(); } } } ); } function buildToolDescription(tools) { const externalFunctions = tools.map((t) => `external_${t.name}`).join(", "); return `Execute TypeScript code in a secure sandbox environment. The code can use these external API functions: ${externalFunctions}. All external_* calls are async and must be awaited. Return a value to pass results back. Use console.log() for debugging.`; } export { createCodeModeTool }; //# sourceMappingURL=create-code-mode-tool.js.map