/** * Build the ES module source that runs inside the dynamic Worker. * * The module exports a `WorkerEntrypoint` subclass with an `evaluate` * method that: * 1. Captures console output into `__logs`. * 2. Creates a recursive `tools` Proxy that dispatches calls via RPC. * 3. Executes the normalised user code with a `Promise.race` timeout. * 4. Returns `{ result, error?, logs }`. * * Tool args cross the dispatcher boundary via Workers RPC, not JSON, so * `Uint8Array` / `ArrayBuffer` survive intact. `Blob` / `File` aren't on * RPC's structured-clone allow-list, so we encode them to a tagged * envelope (`__encodeBinary`) and the host rehydrates them. This is * required for any tool whose upstream wants `multipart/form-data` * (OpenAI Files API, etc.). */export const buildExecutorModule = (body: string, timeoutMs: number): string => [ 'import { WorkerEntrypoint } from "cloudflare:workers";', "", "export default class CodeExecutor extends WorkerEntrypoint {", " async evaluate(__dispatcher) {", " const __logs = [];", ' console.log = (...a) => { __logs.push(a.map(String).join(" ")); };', ' console.warn = (...a) => { __logs.push("[warn] " + a.map(String).join(" ")); };', ' console.error = (...a) => { __logs.push("[error] " + a.map(String).join(" ")); };', " const __serializeErrorValue = (value) => {", " if (value instanceof Error) {", " return {", " __type: 'Error',", " name: value.name,", " message: value.message,", " };", " }", " if (value === null || typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {", " return value;", " }", " try {", " return JSON.parse(JSON.stringify(value));", " } catch {", " return String(value);", " }", " };", " const __renderMessage = (value) => {", " if (typeof value === 'string') return value;", " if (value && typeof value === 'object' && value.__type === 'Error' && typeof value.message === 'string') {", " return value.message;", " }", " if (value instanceof Error) return value.message;", " if (value && typeof value === 'object' && typeof value.message === 'string') return value.message;", " if (typeof value === 'undefined') return 'Unknown error';", " if (value && typeof value === 'object') {", " try {", " return JSON.stringify(value);", " } catch {", " return String(value);", " }", " }", " return String(value);", " };", " const __serializeThrownError = (err) => {", " const primary = __serializeErrorValue(err);", " return {", " kind: 'unknown',", " message: __renderMessage(primary),", " primary,", " failures: [],", " defects: [],", " interrupted: false,", " };", " };", "", // Blob/File aren't on Workers RPC's structured-clone allow-list, so // we encode them to a tagged ArrayBuffer envelope before the call and // the host rehydrates them — and symmetrically the host encodes // Blob/File results which we rehydrate here. ArrayBuffer / typed // arrays cross natively. " const __isPlainObject = (v) => {", " const p = Object.getPrototypeOf(v);", " return p === Object.prototype || p === null;", " };", " const __isBinaryEnvelope = (v) =>", " v && typeof v === 'object' && v.__executorBinary === 1 &&", " v.buffer instanceof ArrayBuffer && typeof v.type === 'string';", " const __encodeBinary = async (value, seen = new WeakSet()) => {", " if (value === null || typeof value !== 'object') return value;", " if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) return value;", " if (seen.has(value)) throw new Error('Tool RPC payload contains a circular reference');", " seen.add(value);", " if (typeof File !== 'undefined' && value instanceof File) {", " const out = {", " __executorBinary: 1,", " kind: 'file',", " type: value.type,", " name: value.name,", " lastModified: value.lastModified,", " buffer: await value.arrayBuffer(),", " };", " seen.delete(value);", " return out;", " }", " if (value instanceof Blob) {", " const out = { __executorBinary: 1, kind: 'blob', type: value.type, buffer: await value.arrayBuffer() };", " seen.delete(value);", " return out;", " }", " if (Array.isArray(value)) {", " const out = await Promise.all(value.map((item) => __encodeBinary(item, seen)));", " seen.delete(value);", " return out;", " }", " if (!__isPlainObject(value)) { seen.delete(value); return value; }", " const out = {};", " for (const [k, v] of Object.entries(value)) out[k] = await __encodeBinary(v, seen);", " seen.delete(value);", " return out;", " };", " const __decodeBinary = (value, seen = new WeakSet()) => {", " if (value === null || typeof value !== 'object') return value;", " if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) return value;", " if (seen.has(value)) throw new Error('Tool RPC payload contains a circular reference');", " seen.add(value);", " if (__isBinaryEnvelope(value)) {", " seen.delete(value);", " if (value.kind === 'file' && typeof value.name === 'string') {", " return new File([value.buffer], value.name, {", " type: value.type,", " ...(typeof value.lastModified === 'number' ? { lastModified: value.lastModified } : {}),", " });", " }", " return new Blob([value.buffer], { type: value.type });", " }", " if (Array.isArray(value)) { const out = value.map((item) => __decodeBinary(item, seen)); seen.delete(value); return out; }", " if (!__isPlainObject(value)) { seen.delete(value); return value; }", " const out = {};", " for (const [k, v] of Object.entries(value)) out[k] = __decodeBinary(v, seen);", " seen.delete(value);", " return out;", " };", " const __publicToolErrorMessage = (error) => {", " const values = [error && error.primary, ...(Array.isArray(error && error.failures) ? error.failures : [])];", " for (const value of values) {", " if (value && value.__type === 'Error' && value.name === 'ExecutionToolError' && typeof value.message === 'string') return value.message;", " }", " if (error && typeof error.message === 'string' && error.message.startsWith('Internal tool error')) return error.message;", " return null;", " };", " const __makeToolsProxy = (path = []) => new Proxy(() => undefined, {", " get(_target, prop) {", " if (prop === 'then' || typeof prop === 'symbol') return undefined;", " return __makeToolsProxy([...path, String(prop)]);", " },", " apply(_target, _thisArg, args) {", " const toolPath = path.join('.');", " if (!toolPath) throw new Error('Tool path missing in invocation');", " return (async () => {", " const encoded = await __encodeBinary(args[0]);", " const data = await __dispatcher.call(toolPath, encoded);", " if (!data.ok) throw new Error(__publicToolErrorMessage(data.error) || 'Internal tool error');", " return __decodeBinary(data.result);", " })();", " },", " });", " const tools = __makeToolsProxy();", "", " try {", " const result = await Promise.race([", " (async () => {", body, " })(),", " new Promise((_, reject) =>", ` setTimeout(() => reject(new Error("Execution timed out after ${timeoutMs}ms")), ${timeoutMs})`, " ),", " ]);", " return { result, logs: __logs };", " } catch (err) {", " return { result: undefined, error: __serializeThrownError(err), logs: __logs };", " }", " }", "}", ].join("\n");
/**
* Build the ES module source that runs inside the dynamic Worker.
*
* The module exports a `WorkerEntrypoint` subclass with an `evaluate`
* method that:
* 1. Captures console output into `__logs`.
* 2. Creates a recursive `tools` Proxy that dispatches calls via RPC.
* 3. Executes the normalised user code with a `Promise.race` timeout.
* 4. Returns `{ result, error?, logs }`.
*
* Tool args cross the dispatcher boundary via Workers RPC, not JSON, so
* `Uint8Array` / `ArrayBuffer` survive intact. `Blob` / `File` aren't on
* RPC's structured-clone allow-list, so we encode them to a tagged
* envelope (`__encodeBinary`) and the host rehydrates them. This is
* required for any tool whose upstream wants `multipart/form-data`
* (OpenAI Files API, etc.).
*/
export const buildExecutorModule = (body: string, timeoutMs: number): string =>
[
'import { WorkerEntrypoint } from "cloudflare:workers";',
"",
"export default class CodeExecutor extends WorkerEntrypoint {",
" async evaluate(__dispatcher) {",
" const __logs = [];",
' console.log = (...a) => { __logs.push(a.map(String).join(" ")); };',
' console.warn = (...a) => { __logs.push("[warn] " + a.map(String).join(" ")); };',
' console.error = (...a) => { __logs.push("[error] " + a.map(String).join(" ")); };',
" const __serializeErrorValue = (value) => {",
" if (value instanceof Error) {",
" return {",
" __type: 'Error',",
" name: value.name,",
" message: value.message,",
" };",
" }",
" if (value === null || typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {",
" return value;",
" }",
" try {",
" return JSON.parse(JSON.stringify(value));",
" } catch {",
" return String(value);",
" }",
" };",
" const __renderMessage = (value) => {",
" if (typeof value === 'string') return value;",
" if (value && typeof value === 'object' && value.__type === 'Error' && typeof value.message === 'string') {",
" return value.message;",
" }",
" if (value instanceof Error) return value.message;",
" if (value && typeof value === 'object' && typeof value.message === 'string') return value.message;",
" if (typeof value === 'undefined') return 'Unknown error';",
" if (value && typeof value === 'object') {",
" try {",
" return JSON.stringify(value);",
" } catch {",
" return String(value);",
" }",
" }",
" return String(value);",
" };",
" const __serializeThrownError = (err) => {",
" const primary = __serializeErrorValue(err);",
" return {",
" kind: 'unknown',",
" message: __renderMessage(primary),",
" primary,",
" failures: [],",
" defects: [],",
" interrupted: false,",
" };",
" };",
"",
// Blob/File aren't on Workers RPC's structured-clone allow-list, so
// we encode them to a tagged ArrayBuffer envelope before the call and
// the host rehydrates them — and symmetrically the host encodes
// Blob/File results which we rehydrate here. ArrayBuffer / typed
// arrays cross natively.
" const __isPlainObject = (v) => {",
" const p = Object.getPrototypeOf(v);",
" return p === Object.prototype || p === null;",
" };",
" const __isBinaryEnvelope = (v) =>",
" v && typeof v === 'object' && v.__executorBinary === 1 &&",
" v.buffer instanceof ArrayBuffer && typeof v.type === 'string';",
" const __encodeBinary = async (value, seen = new WeakSet()) => {",
" if (value === null || typeof value !== 'object') return value;",
" if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) return value;",
" if (seen.has(value)) throw new Error('Tool RPC payload contains a circular reference');",
" seen.add(value);",
" if (typeof File !== 'undefined' && value instanceof File) {",
" const out = {",
" __executorBinary: 1,",
" kind: 'file',",
" type: value.type,",
" name: value.name,",
" lastModified: value.lastModified,",
" buffer: await value.arrayBuffer(),",
" };",
" seen.delete(value);",
" return out;",
" }",
" if (value instanceof Blob) {",
" const out = { __executorBinary: 1, kind: 'blob', type: value.type, buffer: await value.arrayBuffer() };",
" seen.delete(value);",
" return out;",
" }",
" if (Array.isArray(value)) {",
" const out = await Promise.all(value.map((item) => __encodeBinary(item, seen)));",
" seen.delete(value);",
" return out;",
" }",
" if (!__isPlainObject(value)) { seen.delete(value); return value; }",
" const out = {};",
" for (const [k, v] of Object.entries(value)) out[k] = await __encodeBinary(v, seen);",
" seen.delete(value);",
" return out;",
" };",
" const __decodeBinary = (value, seen = new WeakSet()) => {",
" if (value === null || typeof value !== 'object') return value;",
" if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) return value;",
" if (seen.has(value)) throw new Error('Tool RPC payload contains a circular reference');",
" seen.add(value);",
" if (__isBinaryEnvelope(value)) {",
" seen.delete(value);",
" if (value.kind === 'file' && typeof value.name === 'string') {",
" return new File([value.buffer], value.name, {",
" type: value.type,",
" ...(typeof value.lastModified === 'number' ? { lastModified: value.lastModified } : {}),",
" });",
" }",
" return new Blob([value.buffer], { type: value.type });",
" }",
" if (Array.isArray(value)) { const out = value.map((item) => __decodeBinary(item, seen)); seen.delete(value); return out; }",
" if (!__isPlainObject(value)) { seen.delete(value); return value; }",
" const out = {};",
" for (const [k, v] of Object.entries(value)) out[k] = __decodeBinary(v, seen);",
" seen.delete(value);",
" return out;",
" };",
" const __publicToolErrorMessage = (error) => {",
" const values = [error && error.primary, ...(Array.isArray(error && error.failures) ? error.failures : [])];",
" for (const value of values) {",
" if (value && value.__type === 'Error' && value.name === 'ExecutionToolError' && typeof value.message === 'string') return value.message;",
" }",
" if (error && typeof error.message === 'string' && error.message.startsWith('Internal tool error')) return error.message;",
" return null;",
" };",
" const __makeToolsProxy = (path = []) => new Proxy(() => undefined, {",
" get(_target, prop) {",
" if (prop === 'then' || typeof prop === 'symbol') return undefined;",
" return __makeToolsProxy([...path, String(prop)]);",
" },",
" apply(_target, _thisArg, args) {",
" const toolPath = path.join('.');",
" if (!toolPath) throw new Error('Tool path missing in invocation');",
" return (async () => {",
" const encoded = await __encodeBinary(args[0]);",
" const data = await __dispatcher.call(toolPath, encoded);",
" if (!data.ok) throw new Error(__publicToolErrorMessage(data.error) || 'Internal tool error');",
" return __decodeBinary(data.result);",
" })();",
" },",
" });",
" const tools = __makeToolsProxy();",
"",
" try {",
" const result = await Promise.race([",
" (async () => {",
body,
" })(),",
" new Promise((_, reject) =>",
` setTimeout(() => reject(new Error("Execution timed out after ${timeoutMs}ms")), ${timeoutMs})`,
" ),",
" ]);",
" return { result, logs: __logs };",
" } catch (err) {",
" return { result: undefined, error: __serializeThrownError(err), logs: __logs };",
" }",
" }",
"}",
].join("\n");