Showing the changes to packages/kernel/runtime-quickjs/src (2 of 865 files). Show all
Unified · Split
| @@ -1,314 +1,186 @@ | ||
| 1 | 1 | import { describe, expect, it } from "@effect/vitest"; |
| 2 | +import * as Data from "effect/Data"; | |
| 2 | 3 | import * as Effect from "effect/Effect"; |
| 3 | −import * as Schema from "effect/Schema"; | |
| 4 | − | |
| 5 | −import { | |
| 6 | − allowAllToolInteractions, | |
| 7 | − makeToolInvokerFromTools, | |
| 8 | − toExecutorTool, | |
| 9 | −} from "@executor/codemode-core"; | |
| 10 | 4 | |
| 5 | +import type { SandboxToolInvoker } from "@executor/codemode-core"; | |
| 11 | 6 | import { makeQuickJsExecutor } from "./index"; |
| 12 | 7 | |
| 13 | −const numberPairInputSchema = Schema.standardSchemaV1( | |
| 14 | − Schema.Struct({ | |
| 15 | − a: Schema.Number, | |
| 16 | − b: Schema.Number, | |
| 17 | − }), | |
| 18 | −); | |
| 19 | − | |
| 20 | −const messageInputSchema = Schema.standardSchemaV1( | |
| 21 | − Schema.Struct({ | |
| 22 | − message: Schema.String, | |
| 23 | − }), | |
| 24 | −); | |
| 25 | − | |
| 26 | −const discoverInputSchema = Schema.standardSchemaV1( | |
| 27 | − Schema.Struct({ | |
| 28 | − query: Schema.String, | |
| 29 | − limit: Schema.optional(Schema.Number), | |
| 30 | − }), | |
| 31 | −); | |
| 32 | − | |
| 33 | −const describeToolInputSchema = Schema.standardSchemaV1( | |
| 34 | − Schema.Struct({ | |
| 35 | − path: Schema.String, | |
| 36 | − includeSchemas: Schema.optional(Schema.Boolean), | |
| 37 | − }), | |
| 38 | −); | |
| 39 | − | |
| 40 | −const repoInputSchema = Schema.standardSchemaV1( | |
| 41 | − Schema.Struct({ | |
| 42 | − owner: Schema.String, | |
| 43 | − repo: Schema.String, | |
| 44 | − }), | |
| 45 | −); | |
| 46 | − | |
| 47 | −const tools = { | |
| 48 | − "math.add": { | |
| 49 | − description: "Add two numbers", | |
| 50 | − inputSchema: numberPairInputSchema, | |
| 51 | − execute: ({ a, b }: { a: number; b: number }) => ({ sum: a + b }), | |
| 8 | +class UnknownToolError extends Data.TaggedError("UnknownToolError")<{ | |
| 9 | + readonly path: string; | |
| 10 | +}> {} | |
| 11 | + | |
| 12 | +const makeTestInvoker = ( | |
| 13 | + handlers: Record<string, (args: unknown) => unknown>, | |
| 14 | +): SandboxToolInvoker => ({ | |
| 15 | + invoke: ({ path, args }) => { | |
| 16 | + const handler = handlers[path]; | |
| 17 | + if (!handler) { | |
| 18 | + return Effect.fail(new UnknownToolError({ path })); | |
| 19 | + } | |
| 20 | + return Effect.try(() => handler(args)); | |
| 52 | 21 | }, |
| 53 | − "notifications.send": toExecutorTool({ | |
| 54 | − tool: { | |
| 55 | − description: "Send a message", | |
| 56 | − inputSchema: messageInputSchema, | |
| 57 | − execute: ({ message }: { message: string }) => ({ | |
| 58 | − delivered: true, | |
| 59 | − message, | |
| 60 | − }), | |
| 61 | − }, | |
| 62 | − metadata: { | |
| 63 | − interaction: "required", | |
| 64 | − }, | |
| 65 | − }), | |
| 66 | −}; | |
| 67 | − | |
| 68 | −describe("runtime-quickjs", () => { | |
| 69 | − it.effect("executes simple code and returns result", () => | |
| 70 | − Effect.gen(function* () { | |
| 71 | − const executor = makeQuickJsExecutor(); | |
| 72 | − const toolInvoker = makeToolInvokerFromTools({ tools }); | |
| 73 | − | |
| 74 | − const output = yield* executor.execute( | |
| 75 | − "return 1 + 2;", | |
| 76 | − toolInvoker, | |
| 77 | − ); | |
| 78 | − | |
| 79 | − expect(output.result).toBe(3); | |
| 80 | − expect(output.error).toBeUndefined(); | |
| 81 | − }), | |
| 82 | − ); | |
| 83 | − | |
| 84 | − it.effect("executes code with tool calls", () => | |
| 85 | − Effect.gen(function* () { | |
| 86 | − const executor = makeQuickJsExecutor(); | |
| 87 | − const toolInvoker = makeToolInvokerFromTools({ | |
| 88 | − tools, | |
| 89 | − onToolInteraction: allowAllToolInteractions, | |
| 90 | − }); | |
| 91 | − | |
| 92 | − const output = yield* executor.execute( | |
| 93 | − [ | |
| 94 | − "const math = await tools.math.add({ a: 19, b: 23 });", | |
| 95 | − "await tools.notifications.send({ message: `sum is ${math.sum}` });", | |
| 96 | − "return math;", | |
| 97 | − ].join("\n"), | |
| 98 | − toolInvoker, | |
| 99 | − ); | |
| 100 | − | |
| 101 | − expect(output.result).toEqual({ sum: 42 }); | |
| 102 | − expect(output.error).toBeUndefined(); | |
| 103 | − }), | |
| 104 | − ); | |
| 105 | − | |
| 106 | − it.effect("captures console output in logs", () => | |
| 107 | − Effect.gen(function* () { | |
| 108 | − const executor = makeQuickJsExecutor(); | |
| 109 | − const toolInvoker = makeToolInvokerFromTools({ tools }); | |
| 110 | − | |
| 111 | − const output = yield* executor.execute( | |
| 112 | − [ | |
| 113 | − 'console.log("hello from quickjs");', | |
| 114 | − 'console.warn("a warning");', | |
| 115 | − 'console.error("an error");', | |
| 116 | − "return 42;", | |
| 117 | − ].join("\n"), | |
| 118 | − toolInvoker, | |
| 119 | − ); | |
| 22 | +}); | |
| 120 | 23 | |
| 121 | − expect(output.result).toBe(42); | |
| 122 | − expect(output.logs).toContain("[log] hello from quickjs"); | |
| 123 | − expect(output.logs).toContain("[warn] a warning"); | |
| 124 | − expect(output.logs).toContain("[error] an error"); | |
| 125 | − }), | |
| 126 | − ); | |
| 24 | +const executor = makeQuickJsExecutor({ timeoutMs: 5_000 }); | |
| 127 | 25 | |
| 128 | − it.effect("reports execution errors without crashing", () => | |
| 26 | +describe("quickjs executor", () => { | |
| 27 | + it.effect("runs plain code", () => | |
| 129 | 28 | Effect.gen(function* () { |
| 130 | − const executor = makeQuickJsExecutor(); | |
| 131 | − const toolInvoker = makeToolInvokerFromTools({ tools }); | |
| 132 | − | |
| 133 | − const output = yield* executor.execute( | |
| 134 | − 'throw new Error("boom");', | |
| 135 | − toolInvoker, | |
| 29 | + const result = yield* executor.execute( | |
| 30 | + `return 1 + 2`, | |
| 31 | + makeTestInvoker({}), | |
| 136 | 32 | ); |
| 137 | − | |
| 138 | − expect(output.result).toBeNull(); | |
| 139 | − expect(output.error).toContain("boom"); | |
| 33 | + expect(result.result).toBe(3); | |
| 34 | + expect(result.error).toBeUndefined(); | |
| 140 | 35 | }), |
| 141 | 36 | ); |
| 142 | 37 | |
| 143 | − it.effect("handles tool call errors gracefully", () => | |
| 38 | + it.effect("invokes a tool and returns its result", () => | |
| 144 | 39 | Effect.gen(function* () { |
| 145 | − const failingTools = { | |
| 146 | − "broken.thing": { | |
| 147 | − description: "Always fails", | |
| 148 | − inputSchema: Schema.standardSchemaV1(Schema.Struct({})), | |
| 149 | − execute: () => { | |
| 150 | − throw new Error("tool is broken"); | |
| 151 | − }, | |
| 40 | + const invoker = makeTestInvoker({ | |
| 41 | + "math.add": (args) => { | |
| 42 | + const { a, b } = args as { a: number; b: number }; | |
| 43 | + return { sum: a + b }; | |
| 152 | 44 | }, |
| 153 | − }; | |
| 154 | − | |
| 155 | − const executor = makeQuickJsExecutor(); | |
| 156 | − const toolInvoker = makeToolInvokerFromTools({ | |
| 157 | − tools: failingTools, | |
| 158 | 45 | }); |
| 159 | 46 | |
| 160 | − const output = yield* executor.execute( | |
| 161 | − "return await tools.broken.thing({});", | |
| 162 | − toolInvoker, | |
| 47 | + const result = yield* executor.execute( | |
| 48 | + ` | |
| 49 | + const res = await tools.math.add({ a: 5, b: 3 }); | |
| 50 | + return res.sum; | |
| 51 | + `, | |
| 52 | + invoker, | |
| 163 | 53 | ); |
| 164 | 54 | |
| 165 | − expect(output.result).toBeNull(); | |
| 166 | − expect(output.error).toContain("tool is broken"); | |
| 55 | + expect(result.error).toBeUndefined(); | |
| 56 | + expect(result.result).toBe(8); | |
| 167 | 57 | }), |
| 168 | 58 | ); |
| 169 | 59 | |
| 170 | − it.effect("respects timeout", () => | |
| 60 | + it.effect("invokes multiple tools in sequence", () => | |
| 171 | 61 | Effect.gen(function* () { |
| 172 | − const executor = makeQuickJsExecutor({ | |
| 173 | − timeoutMs: 250, | |
| 62 | + const invoker = makeTestInvoker({ | |
| 63 | + "users.get": (args) => { | |
| 64 | + const { id } = args as { id: number }; | |
| 65 | + return { id, name: `User ${id}` }; | |
| 66 | + }, | |
| 67 | + "users.greet": (args) => { | |
| 68 | + const { name } = args as { name: string }; | |
| 69 | + return { message: `Hello, ${name}!` }; | |
| 70 | + }, | |
| 174 | 71 | }); |
| 175 | − const toolInvoker = makeToolInvokerFromTools({ tools }); | |
| 176 | 72 | |
| 177 | − const output = yield* executor.execute( | |
| 178 | − "while (true) {}", | |
| 179 | − toolInvoker, | |
| 73 | + const result = yield* executor.execute( | |
| 74 | + ` | |
| 75 | + const user = await tools.users.get({ id: 42 }); | |
| 76 | + const greeting = await tools.users.greet({ name: user.name }); | |
| 77 | + return greeting.message; | |
| 78 | + `, | |
| 79 | + invoker, | |
| 180 | 80 | ); |
| 181 | 81 | |
| 182 | − expect(output.result).toBeNull(); | |
| 183 | − expect(output.error).toContain("timed out"); | |
| 82 | + expect(result.error).toBeUndefined(); | |
| 83 | + expect(result.result).toBe("Hello, User 42!"); | |
| 184 | 84 | }), |
| 185 | 85 | ); |
| 186 | 86 | |
| 187 | − it.effect("network access is denied by default", () => | |
| 87 | + it.effect("handles tool errors", () => | |
| 188 | 88 | Effect.gen(function* () { |
| 189 | − const executor = makeQuickJsExecutor(); | |
| 190 | − const toolInvoker = makeToolInvokerFromTools({ tools }); | |
| 89 | + const invoker = makeTestInvoker({ | |
| 90 | + "db.query": () => { | |
| 91 | + throw new Error("connection refused"); | |
| 92 | + }, | |
| 93 | + }); | |
| 191 | 94 | |
| 192 | − const output = yield* executor.execute( | |
| 193 | − 'await fetch("https://example.com"); return 1;', | |
| 194 | − toolInvoker, | |
| 95 | + const result = yield* executor.execute( | |
| 96 | + ` | |
| 97 | + try { | |
| 98 | + await tools.db.query({ sql: "SELECT 1" }); | |
| 99 | + return "should not reach"; | |
| 100 | + } catch (e) { | |
| 101 | + return "caught: " + e.message; | |
| 102 | + } | |
| 103 | + `, | |
| 104 | + invoker, | |
| 195 | 105 | ); |
| 196 | 106 | |
| 197 | − expect(output.result).toBeNull(); | |
| 198 | − expect(output.error).toContain("fetch is disabled in QuickJS executor"); | |
| 107 | + expect(result.error).toBeUndefined(); | |
| 108 | + expect(result.result).toContain("caught:"); | |
| 199 | 109 | }), |
| 200 | 110 | ); |
| 201 | 111 | |
| 202 | − it.effect("multiple sequential tool calls work correctly", () => | |
| 112 | + it.effect("handles unknown tool path", () => | |
| 203 | 113 | Effect.gen(function* () { |
| 204 | − const executor = makeQuickJsExecutor(); | |
| 205 | − const toolInvoker = makeToolInvokerFromTools({ tools }); | |
| 206 | − | |
| 207 | − const output = yield* executor.execute( | |
| 208 | − [ | |
| 209 | − "const r1 = await tools.math.add({ a: 1, b: 2 });", | |
| 210 | − "const r2 = await tools.math.add({ a: r1.sum, b: 10 });", | |
| 211 | − "const r3 = await tools.math.add({ a: r2.sum, b: 100 });", | |
| 212 | − "return r3;", | |
| 213 | − ].join("\n"), | |
| 214 | − toolInvoker, | |
| 114 | + const invoker = makeTestInvoker({}); | |
| 115 | + | |
| 116 | + const result = yield* executor.execute( | |
| 117 | + ` | |
| 118 | + try { | |
| 119 | + await tools.nonexistent.thing({ x: 1 }); | |
| 120 | + return "should not reach"; | |
| 121 | + } catch (e) { | |
| 122 | + return "caught: " + e.message; | |
| 123 | + } | |
| 124 | + `, | |
| 125 | + invoker, | |
| 215 | 126 | ); |
| 216 | 127 | |
| 217 | − expect(output.result).toEqual({ sum: 113 }); | |
| 218 | − expect(output.error).toBeUndefined(); | |
| 128 | + expect(result.error).toBeUndefined(); | |
| 129 | + expect(result.result).toContain("caught:"); | |
| 219 | 130 | }), |
| 220 | 131 | ); |
| 221 | 132 | |
| 222 | − it.effect("does not expose internal executor bridge globals to user code", () => | |
| 133 | + it.effect("captures console.log output", () => | |
| 223 | 134 | Effect.gen(function* () { |
| 224 | − const executor = makeQuickJsExecutor(); | |
| 225 | − const toolInvoker = makeToolInvokerFromTools({ tools }); | |
| 226 | − | |
| 227 | − const output = yield* executor.execute( | |
| 228 | − [ | |
| 229 | − "return {", | |
| 230 | − " hasInvokeTool: typeof globalThis.__executor_invokeTool !== 'undefined',", | |
| 231 | − " hasLogBridge: typeof globalThis.__executor_log !== 'undefined',", | |
| 232 | − " globalKeys: Object.keys(globalThis).sort(),", | |
| 233 | − "};", | |
| 234 | − ].join("\n"), | |
| 235 | − toolInvoker, | |
| 135 | + const result = yield* executor.execute( | |
| 136 | + ` | |
| 137 | + console.log("hello from sandbox"); | |
| 138 | + console.warn("a warning"); | |
| 139 | + return "done"; | |
| 140 | + `, | |
| 141 | + makeTestInvoker({}), | |
| 236 | 142 | ); |
| 237 | 143 | |
| 238 | − expect(output.result).toEqual({ | |
| 239 | − hasInvokeTool: false, | |
| 240 | − hasLogBridge: false, | |
| 241 | − globalKeys: [], | |
| 242 | − }); | |
| 243 | − expect(output.error).toBeUndefined(); | |
| 144 | + expect(result.error).toBeUndefined(); | |
| 145 | + expect(result.result).toBe("done"); | |
| 146 | + expect(result.logs).toContainEqual("[log] hello from sandbox"); | |
| 147 | + expect(result.logs).toContainEqual("[warn] a warning"); | |
| 244 | 148 | }), |
| 245 | 149 | ); |
| 246 | 150 | |
| 247 | − it.effect("supports the documented discovery workflow shape", () => | |
| 151 | + it.effect("passes tool result into next tool call", () => | |
| 248 | 152 | Effect.gen(function* () { |
| 249 | − const executor = makeQuickJsExecutor(); | |
| 250 | − const toolInvoker = makeToolInvokerFromTools({ | |
| 251 | − tools: { | |
| 252 | − discover: { | |
| 253 | − inputSchema: discoverInputSchema, | |
| 254 | − execute: () => ({ | |
| 255 | − bestPath: "github.issues.list", | |
| 256 | − results: [ | |
| 257 | − { | |
| 258 | − path: "github.issues.list", | |
| 259 | − score: 0.99, | |
| 260 | − }, | |
| 261 | − ], | |
| 262 | − total: 1, | |
| 263 | − }), | |
| 264 | − }, | |
| 265 | − "describe.tool": { | |
| 266 | − inputSchema: describeToolInputSchema, | |
| 267 | − execute: ({ path }: { path: string; includeSchemas?: boolean }) => ({ | |
| 268 | − path, | |
| 269 | − contract: { | |
| 270 | − inputTypePreview: "{ owner: string; repo: string }", | |
| 271 | − }, | |
| 272 | − }), | |
| 273 | − }, | |
| 274 | − "github.issues.list": { | |
| 275 | − inputSchema: repoInputSchema, | |
| 276 | − execute: ({ owner, repo }: { owner: string; repo: string }) => ({ | |
| 277 | − owner, | |
| 278 | − repo, | |
| 279 | − issues: [{ id: "issue_1" }], | |
| 280 | − }), | |
| 281 | − }, | |
| 153 | + const invoker = makeTestInvoker({ | |
| 154 | + "stripe.customers.list": () => ({ | |
| 155 | + data: [ | |
| 156 | + { id: "cus_1", email: "alice@example.com" }, | |
| 157 | + { id: "cus_2", email: "bob@example.com" }, | |
| 158 | + ], | |
| 159 | + }), | |
| 160 | + "stripe.invoices.create": (args) => { | |
| 161 | + const { customer, amount } = args as { customer: string; amount: number }; | |
| 162 | + return { id: "inv_1", customer, amount }; | |
| 282 | 163 | }, |
| 283 | 164 | }); |
| 284 | 165 | |
| 285 | − const output = yield* executor.execute( | |
| 286 | − [ | |
| 287 | − 'const { results, bestPath } = await tools.discover({ query: "github issues", limit: 5 });', | |
| 288 | − "const path = bestPath ?? results[0]?.path;", | |
| 289 | − 'if (!path) throw new Error("No matching tools found.");', | |
| 290 | − "const detail = await tools.describe.tool({ path, includeSchemas: true });", | |
| 291 | − 'const issues = await tools.github.issues.list({ owner: "openai", repo: "codex" });', | |
| 292 | − "return { path, detail, issues };", | |
| 293 | − ].join("\n"), | |
| 294 | − toolInvoker, | |
| 166 | + const result = yield* executor.execute( | |
| 167 | + ` | |
| 168 | + const customers = await tools.stripe.customers.list(); | |
| 169 | + const invoice = await tools.stripe.invoices.create({ | |
| 170 | + customer: customers.data[0].id, | |
| 171 | + amount: 5000, | |
| 172 | + }); | |
| 173 | + return invoice; | |
| 174 | + `, | |
| 175 | + invoker, | |
| 295 | 176 | ); |
| 296 | 177 | |
| 297 | − expect(output.result).toEqual({ | |
| 298 | − path: "github.issues.list", | |
| 299 | − detail: { | |
| 300 | − path: "github.issues.list", | |
| 301 | − contract: { | |
| 302 | − inputTypePreview: "{ owner: string; repo: string }", | |
| 303 | − }, | |
| 304 | − }, | |
| 305 | − issues: { | |
| 306 | − owner: "openai", | |
| 307 | − repo: "codex", | |
| 308 | − issues: [{ id: "issue_1" }], | |
| 309 | − }, | |
| 178 | + expect(result.error).toBeUndefined(); | |
| 179 | + expect(result.result).toEqual({ | |
| 180 | + id: "inv_1", | |
| 181 | + customer: "cus_1", | |
| 182 | + amount: 5000, | |
| 310 | 183 | }); |
| 311 | − expect(output.error).toBeUndefined(); | |
| 312 | 184 | }), |
| 313 | 185 | ); |
| 314 | 186 | }); |
| @@ -1,8 +1,9 @@ | ||
| 1 | 1 | import type { |
| 2 | 2 | CodeExecutor, |
| 3 | 3 | ExecuteResult, |
| 4 | − ToolInvoker, | |
| 4 | + SandboxToolInvoker, | |
| 5 | 5 | } from "@executor/codemode-core"; |
| 6 | +import * as Data from "effect/Data"; | |
| 6 | 7 | import * as Effect from "effect/Effect"; |
| 7 | 8 | import { |
| 8 | 9 | getQuickJS, |
| @@ -11,6 +12,7 @@ import { · 2 unmodified lines | ||
| 11 | 12 | type QuickJSDeferredPromise, |
| 12 | 13 | type QuickJSHandle, |
| 13 | 14 | type QuickJSRuntime, |
| 15 | + type QuickJSWASMModule, | |
| 14 | 16 | } from "quickjs-emscripten"; |
| 15 | 17 | |
| 16 | 18 | export type QuickJsExecutorOptions = { |
| @@ -19,6 +21,20 @@ export type QuickJsExecutorOptions = { · 2 unmodified lines | ||
| 19 | 21 | maxStackSizeBytes?: number; |
| 20 | 22 | }; |
| 21 | 23 | |
| 24 | +// Allow pre-loading a QuickJS module (e.g. with custom WASM bytes for compiled binaries) | |
| 25 | +let preloadedModule: QuickJSWASMModule | null = null; | |
| 26 | + | |
| 27 | +export const setQuickJSModule = (mod: QuickJSWASMModule) => { | |
| 28 | + preloadedModule = mod; | |
| 29 | +}; | |
| 30 | + | |
| 31 | +const resolveQuickJS = (): Promise<QuickJSWASMModule> => | |
| 32 | + preloadedModule ? Promise.resolve(preloadedModule) : getQuickJS(); | |
| 33 | + | |
| 34 | +class QuickJsExecutionError extends Data.TaggedError("QuickJsExecutionError")<{ | |
| 35 | + readonly message: string; | |
| 36 | +}> {} | |
| 37 | + | |
| 22 | 38 | const DEFAULT_TIMEOUT_MS = 5 * 60_000; |
| 23 | 39 | const EXECUTION_FILENAME = "executor-quickjs-runtime.js"; |
| 24 | 40 | |
| @@ -178,7 +194,7 @@ const createLogBridge = ( · 153 unmodified lines | ||
| 178 | 194 | |
| 179 | 195 | const createToolBridge = ( |
| 180 | 196 | context: QuickJSContext, |
| 181 | − toolInvoker: ToolInvoker, | |
| 197 | + toolInvoker: SandboxToolInvoker, | |
| 182 | 198 | pendingDeferreds: Set<QuickJSDeferredPromise>, |
| 183 | 199 | ): QuickJSHandle => |
| 184 | 200 | context.newFunction("__executor_invokeTool", (pathHandle, argsHandle) => { |
| @@ -288,13 +304,13 @@ const drainAsync = async ( · 103 unmodified lines | ||
| 288 | 304 | const evaluateInQuickJs = async ( |
| 289 | 305 | options: QuickJsExecutorOptions, |
| 290 | 306 | code: string, |
| 291 | − toolInvoker: ToolInvoker, | |
| 307 | + toolInvoker: SandboxToolInvoker, | |
| 292 | 308 | ): Promise<ExecuteResult> => { |
| 293 | 309 | const timeoutMs = Math.max(100, options.timeoutMs ?? DEFAULT_TIMEOUT_MS); |
| 294 | 310 | const deadlineMs = Date.now() + timeoutMs; |
| 295 | 311 | const logs: string[] = []; |
| 296 | 312 | const pendingDeferreds = new Set<QuickJSDeferredPromise>(); |
| 297 | − const QuickJS = await getQuickJS(); | |
| 313 | + const QuickJS = await resolveQuickJS(); | |
| 298 | 314 | const runtime = QuickJS.newRuntime(); |
| 299 | 315 | |
| 300 | 316 | try { |
| @@ -399,16 +415,16 @@ const evaluateInQuickJs = async ( · 98 unmodified lines | ||
| 399 | 415 | const runInQuickJs = ( |
| 400 | 416 | options: QuickJsExecutorOptions, |
| 401 | 417 | code: string, |
| 402 | − toolInvoker: ToolInvoker, | |
| 403 | −): Effect.Effect<ExecuteResult, Error> => | |
| 418 | + toolInvoker: SandboxToolInvoker, | |
| 419 | +): Effect.Effect<ExecuteResult, QuickJsExecutionError> => | |
| 404 | 420 | Effect.tryPromise({ |
| 405 | 421 | try: () => evaluateInQuickJs(options, code, toolInvoker), |
| 406 | − catch: toError, | |
| 422 | + catch: (cause) => new QuickJsExecutionError({ message: String(cause) }), | |
| 407 | 423 | }); |
| 408 | 424 | |
| 409 | 425 | export const makeQuickJsExecutor = ( |
| 410 | 426 | options: QuickJsExecutorOptions = {}, |
| 411 | 427 | ): CodeExecutor => ({ |
| 412 | − execute: (code: string, toolInvoker: ToolInvoker) => | |
| 428 | + execute: (code: string, toolInvoker: SandboxToolInvoker) => | |
| 413 | 429 | runInQuickJs(options, code, toolInvoker), |
| 414 | 430 | }); |