@mastra/isolated-vm 0.0.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @mastra/isolated-vm
2
2
 
3
+ ## 0.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Added `@mastra/isolated-vm`, a new package with `IsolatedVmCodeModeTransport` — a Code Mode transport that runs model-authored programs in an in-process V8 isolate (backed by `isolated-vm`). The isolate is the execution boundary, so no workspace sandbox is required: the program has no filesystem, network, or process access, and its only capabilities are the `external_*` tool functions bridged back to the host. ([#20359](https://github.com/mastra-ai/mastra/pull/20359))
8
+
9
+ ```typescript
10
+ import { createCodeMode } from '@mastra/core/tools';
11
+ import { IsolatedVmCodeModeTransport } from '@mastra/isolated-vm';
12
+
13
+ const { tool, instructions } = createCodeMode({ tools }, new IsolatedVmCodeModeTransport({ memoryLimitMb: 128 }));
14
+ ```
15
+
16
+ Note: `isolated-vm` is a native addon, and on Node.js 20+ the host process must be started with `--no-node-snapshot` (for example `NODE_OPTIONS=--no-node-snapshot`). See the docs for setup details. Resolves https://github.com/mastra-ai/mastra/issues/20329.
17
+
18
+ ### Patch Changes
19
+
20
+ - Updated dependencies [[`3f472b4`](https://github.com/mastra-ai/mastra/commit/3f472b468892a1ff14ccb43cc0343b86f7d8fd7d), [`ba369f2`](https://github.com/mastra-ai/mastra/commit/ba369f2a0aaf998da0d6aa033d26f64f96bef8ac), [`35b929b`](https://github.com/mastra-ai/mastra/commit/35b929b7abc3d20d85c7985880960ac2d04a6c86), [`55c9e24`](https://github.com/mastra-ai/mastra/commit/55c9e248c27c1d72b5bb7e94ea6b8a3999eee49f), [`dcfed93`](https://github.com/mastra-ai/mastra/commit/dcfed93e1e256c6abfa792cbb7ca836f5d0e8638), [`2876e15`](https://github.com/mastra-ai/mastra/commit/2876e15b4d2f616a3bc1ed3af57d546c268384ce), [`9b3626a`](https://github.com/mastra-ai/mastra/commit/9b3626aeb1d16fcd34b0a8e94c114ddb80a3b240), [`4696963`](https://github.com/mastra-ai/mastra/commit/469696312ac4c618bc8475b0c5ed7949b8a3455e), [`723aa54`](https://github.com/mastra-ai/mastra/commit/723aa5437106bdb708ae03c0ef6b77aa11291e73), [`07f5b4b`](https://github.com/mastra-ai/mastra/commit/07f5b4ba9d608d88865030732e580298296adf99), [`723aa54`](https://github.com/mastra-ai/mastra/commit/723aa5437106bdb708ae03c0ef6b77aa11291e73), [`723aa54`](https://github.com/mastra-ai/mastra/commit/723aa5437106bdb708ae03c0ef6b77aa11291e73), [`598080f`](https://github.com/mastra-ai/mastra/commit/598080f224edb3f0f5b801035b067fac50a56a03)]:
21
+ - @mastra/core@1.55.0
22
+
3
23
  ## 0.1.0-alpha.0
4
24
 
5
25
  ### Minor Changes
package/LICENSE.md ADDED
@@ -0,0 +1,30 @@
1
+ Portions of this software are licensed as follows:
2
+
3
+ - All content that resides under any directory named "ee/" within this
4
+ repository, including but not limited to:
5
+ - `packages/core/src/auth/ee/`
6
+ - `packages/server/src/server/auth/ee/`
7
+ is licensed under the license defined in `ee/LICENSE`.
8
+
9
+ - All third-party components incorporated into the Mastra Software are
10
+ licensed under the original license provided by the owner of the
11
+ applicable component.
12
+
13
+ - Content outside of the above-mentioned directories or restrictions is
14
+ available under the "Apache License 2.0" as defined below.
15
+
16
+ # Apache License 2.0
17
+
18
+ Copyright (c) 2025 Kepler Software, Inc.
19
+
20
+ Licensed under the Apache License, Version 2.0 (the "License");
21
+ you may not use this file except in compliance with the License.
22
+ You may obtain a copy of the License at
23
+
24
+ http://www.apache.org/licenses/LICENSE-2.0
25
+
26
+ Unless required by applicable law or agreed to in writing, software
27
+ distributed under the License is distributed on an "AS IS" BASIS,
28
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29
+ See the License for the specific language governing permissions and
30
+ limitations under the License.
package/dist/index.cjs ADDED
@@ -0,0 +1,325 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+ //#endregion
24
+ let _mastra_core_tools = require("@mastra/core/tools");
25
+ let esbuild = require("esbuild");
26
+ let isolated_vm = require("isolated-vm");
27
+ isolated_vm = __toESM(isolated_vm, 1);
28
+ //#region src/transport.ts
29
+ /**
30
+ * Code Mode — isolated-vm transport
31
+ *
32
+ * Runs the model's TypeScript program inside an in-process V8 isolate
33
+ * (via `isolated-vm`) instead of a WorkspaceSandbox. The isolate is a real
34
+ * security boundary: the guest has no filesystem, network, process, or module
35
+ * access — the only capabilities are the injected `external_*` functions,
36
+ * which call back into the host dispatcher (allow-list enforced host-side).
37
+ *
38
+ * Unlike the stdio/E2B transports there is no process boundary, so the frame
39
+ * protocol (`FRAME_PREFIX`, stdout parsing, stdin writes) is not used. Host
40
+ * calls cross the isolate boundary as JSON strings in both directions, so no
41
+ * host object references are ever exposed to guest code.
42
+ *
43
+ * TypeScript is stripped on the host with esbuild before evaluation (isolates
44
+ * run plain JavaScript).
45
+ *
46
+ * Requirements:
47
+ * - `isolated-vm` is a native addon (prebuilt binaries for common platforms,
48
+ * compiled from source elsewhere).
49
+ * - On Node 20+ the host process must be started with `--no-node-snapshot`
50
+ * (e.g. `node --no-node-snapshot server.js` or
51
+ * `NODE_OPTIONS=--no-node-snapshot`). The constructor fails fast with an
52
+ * actionable error when the flag is missing.
53
+ */
54
+ /** Default isolate heap limit, in MiB. */
55
+ const DEFAULT_MEMORY_LIMIT_MB = 128;
56
+ /**
57
+ * On Node 20+, isolated-vm cannot create isolates unless the host process was
58
+ * started with `--no-node-snapshot` — without it, isolate creation crashes the
59
+ * whole process. Detect the documented mechanisms and fail fast instead.
60
+ */
61
+ function assertNoNodeSnapshot() {
62
+ if (Number(process.versions.node.split(".")[0]) < 20) return;
63
+ if (process.execArgv.includes("--no-node-snapshot")) return;
64
+ if ((process.env.NODE_OPTIONS ?? "").includes("--no-node-snapshot")) return;
65
+ throw new Error("IsolatedVmCodeModeTransport requires the --no-node-snapshot flag on Node 20+. Start your process with `node --no-node-snapshot ...` or set NODE_OPTIONS=\"--no-node-snapshot\". Without it, creating a V8 isolate crashes the Node process.");
66
+ }
67
+ /**
68
+ * Code Mode transport that executes programs in an in-process V8 isolate.
69
+ *
70
+ * No sandbox is required — the isolate is the execution boundary
71
+ * (`requiresSandbox: false`).
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * import { createCodeMode } from '@mastra/core/tools';
76
+ * import { IsolatedVmCodeModeTransport } from '@mastra/isolated-vm';
77
+ *
78
+ * const { tool, instructions } = createCodeMode(
79
+ * { tools: { getWeather, getForecast } },
80
+ * new IsolatedVmCodeModeTransport({ memoryLimitMb: 128 }),
81
+ * );
82
+ * ```
83
+ */
84
+ var IsolatedVmCodeModeTransport = class {
85
+ requiresSandbox = false;
86
+ #memoryLimitMb;
87
+ constructor(options = {}) {
88
+ assertNoNodeSnapshot();
89
+ this.#memoryLimitMb = options.memoryLimitMb ?? DEFAULT_MEMORY_LIMIT_MB;
90
+ }
91
+ async run(opts) {
92
+ const { program, toolIds, dispatch, timeout, abortSignal, onExternalCall, onExternalResult } = opts;
93
+ const externals = toolIds.map((toolId) => ({
94
+ toolId,
95
+ externalName: (0, _mastra_core_tools.sanitizeToolId)(toolId)
96
+ }));
97
+ const allowList = new Set(toolIds);
98
+ const logs = [];
99
+ const notifyCall = (tool, args) => {
100
+ try {
101
+ onExternalCall?.(tool, args);
102
+ } catch {}
103
+ };
104
+ const notifyResult = (tool, durationMs, error) => {
105
+ try {
106
+ onExternalResult?.(tool, durationMs, error);
107
+ } catch {}
108
+ };
109
+ let strippedProgram;
110
+ try {
111
+ strippedProgram = (0, esbuild.transformSync)(`(async () => {\n${program}\n})`, {
112
+ loader: "ts",
113
+ target: "es2022"
114
+ }).code;
115
+ } catch (error) {
116
+ return {
117
+ success: false,
118
+ logs,
119
+ error: {
120
+ message: error?.message ?? String(error),
121
+ name: "SyntaxError"
122
+ }
123
+ };
124
+ }
125
+ const rpcHost = async (tool, argsJson) => {
126
+ const started = Date.now();
127
+ let args;
128
+ try {
129
+ args = JSON.parse(argsJson);
130
+ } catch {
131
+ args = void 0;
132
+ }
133
+ notifyCall(tool, args);
134
+ if (!allowList.has(tool)) {
135
+ notifyResult(tool, Date.now() - started, /* @__PURE__ */ new Error("not allowed"));
136
+ return JSON.stringify({
137
+ ok: false,
138
+ error: {
139
+ message: `Tool "${tool}" is not available in Code Mode`,
140
+ name: "NotAllowedError"
141
+ }
142
+ });
143
+ }
144
+ try {
145
+ const result = await dispatch(tool, args);
146
+ const json = JSON.stringify({
147
+ ok: true,
148
+ result
149
+ });
150
+ notifyResult(tool, Date.now() - started);
151
+ return json;
152
+ } catch (error) {
153
+ const err = error;
154
+ notifyResult(tool, Date.now() - started, error instanceof Error ? error : new Error(String(error)));
155
+ return JSON.stringify({
156
+ ok: false,
157
+ error: {
158
+ message: err?.message ?? String(error),
159
+ name: err?.name
160
+ }
161
+ });
162
+ }
163
+ };
164
+ const logHost = (message) => {
165
+ logs.push(message);
166
+ };
167
+ const isolate = new isolated_vm.default.Isolate({ memoryLimit: this.#memoryLimitMb });
168
+ let disposed = false;
169
+ const disposeIsolate = () => {
170
+ if (disposed) return;
171
+ disposed = true;
172
+ try {
173
+ isolate.dispose();
174
+ } catch {}
175
+ };
176
+ let timedOut = false;
177
+ let timer;
178
+ const onAbort = () => disposeIsolate();
179
+ abortSignal?.addEventListener("abort", onAbort, { once: true });
180
+ try {
181
+ if (abortSignal?.aborted) return {
182
+ success: false,
183
+ logs,
184
+ error: {
185
+ message: "Code Mode execution aborted",
186
+ name: "AbortError"
187
+ }
188
+ };
189
+ const context = await isolate.createContext();
190
+ await context.evalClosure(`
191
+ const __rpc = (tool, args) => {
192
+ let argsJson;
193
+ try { argsJson = JSON.stringify(args === undefined ? null : args); } catch (e) {
194
+ return Promise.reject(new Error('Arguments passed to an external_* function must be JSON-serializable'));
195
+ }
196
+ return $0
197
+ .apply(undefined, [String(tool), argsJson], { result: { promise: true, copy: true } })
198
+ .then((json) => {
199
+ const res = JSON.parse(json);
200
+ if (res.ok) return res.result;
201
+ const err = new Error((res.error && res.error.message) || 'external tool failed');
202
+ if (res.error && res.error.name) err.name = res.error.name;
203
+ throw err;
204
+ });
205
+ };
206
+ const __safeStringify = (value) => {
207
+ try { return JSON.stringify(value); } catch { return String(value); }
208
+ };
209
+ const __log = (level, args) => {
210
+ const message = args.map((a) => (typeof a === 'string' ? a : __safeStringify(a))).join(' ');
211
+ $1.applyIgnored(undefined, [message]);
212
+ };
213
+ globalThis.console = Object.freeze({
214
+ log: (...args) => __log('log', args),
215
+ info: (...args) => __log('info', args),
216
+ warn: (...args) => __log('warn', args),
217
+ error: (...args) => __log('error', args),
218
+ });
219
+ for (const { externalName, toolId } of ${JSON.stringify(externals)}) {
220
+ globalThis['external_' + externalName] = (input) => __rpc(toolId, input);
221
+ }
222
+ `, [rpcHost, logHost], { arguments: { reference: true } });
223
+ const evalSource = `
224
+ (async () => {
225
+ const __user = ${strippedProgram}
226
+ try {
227
+ const __result = await __user();
228
+ try {
229
+ const json = JSON.stringify({ ok: true, value: __result });
230
+ return json === undefined ? '{"ok":true}' : json;
231
+ } catch {
232
+ return JSON.stringify({
233
+ ok: false,
234
+ error: { message: 'Code Mode result is not JSON-serializable', name: 'TypeError' },
235
+ });
236
+ }
237
+ } catch (e) {
238
+ return JSON.stringify({
239
+ ok: false,
240
+ error: { message: (e && e.message) || String(e), name: e && e.name },
241
+ });
242
+ }
243
+ })()
244
+ `;
245
+ const timeoutPromise = new Promise((resolve) => {
246
+ timer = setTimeout(() => {
247
+ timedOut = true;
248
+ resolve("timeout");
249
+ disposeIsolate();
250
+ }, timeout);
251
+ });
252
+ const evalPromise = context.eval(evalSource, {
253
+ promise: true,
254
+ copy: true,
255
+ timeout
256
+ });
257
+ const outcome = await Promise.race([evalPromise.then((json) => ({
258
+ kind: "done",
259
+ json,
260
+ error: void 0
261
+ }), (error) => ({
262
+ kind: "error",
263
+ json: void 0,
264
+ error
265
+ })), timeoutPromise.then(() => ({
266
+ kind: "timeout",
267
+ json: void 0,
268
+ error: void 0
269
+ }))]);
270
+ if (outcome.kind === "timeout" || timedOut) return {
271
+ success: false,
272
+ logs,
273
+ error: {
274
+ message: `Code Mode execution timed out after ${timeout}ms`,
275
+ name: "TimeoutError"
276
+ }
277
+ };
278
+ if (outcome.kind === "error") {
279
+ const err = outcome.error;
280
+ if (abortSignal?.aborted) return {
281
+ success: false,
282
+ logs,
283
+ error: {
284
+ message: "Code Mode execution aborted",
285
+ name: "AbortError"
286
+ }
287
+ };
288
+ if (/timed out/i.test(err?.message ?? "")) return {
289
+ success: false,
290
+ logs,
291
+ error: {
292
+ message: `Code Mode execution timed out after ${timeout}ms`,
293
+ name: "TimeoutError"
294
+ }
295
+ };
296
+ return {
297
+ success: false,
298
+ logs,
299
+ error: {
300
+ message: err?.message ?? String(outcome.error),
301
+ name: err?.name
302
+ }
303
+ };
304
+ }
305
+ const envelope = JSON.parse(outcome.json);
306
+ return envelope.ok ? {
307
+ success: true,
308
+ result: envelope.value,
309
+ logs
310
+ } : {
311
+ success: false,
312
+ error: envelope.error,
313
+ logs
314
+ };
315
+ } finally {
316
+ if (timer) clearTimeout(timer);
317
+ abortSignal?.removeEventListener("abort", onAbort);
318
+ disposeIsolate();
319
+ }
320
+ }
321
+ };
322
+ //#endregion
323
+ exports.IsolatedVmCodeModeTransport = IsolatedVmCodeModeTransport;
324
+
325
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["#memoryLimitMb","err","ivm"],"sources":["../src/transport.ts"],"sourcesContent":["/**\n * Code Mode — isolated-vm transport\n *\n * Runs the model's TypeScript program inside an in-process V8 isolate\n * (via `isolated-vm`) instead of a WorkspaceSandbox. The isolate is a real\n * security boundary: the guest has no filesystem, network, process, or module\n * access — the only capabilities are the injected `external_*` functions,\n * which call back into the host dispatcher (allow-list enforced host-side).\n *\n * Unlike the stdio/E2B transports there is no process boundary, so the frame\n * protocol (`FRAME_PREFIX`, stdout parsing, stdin writes) is not used. Host\n * calls cross the isolate boundary as JSON strings in both directions, so no\n * host object references are ever exposed to guest code.\n *\n * TypeScript is stripped on the host with esbuild before evaluation (isolates\n * run plain JavaScript).\n *\n * Requirements:\n * - `isolated-vm` is a native addon (prebuilt binaries for common platforms,\n * compiled from source elsewhere).\n * - On Node 20+ the host process must be started with `--no-node-snapshot`\n * (e.g. `node --no-node-snapshot server.js` or\n * `NODE_OPTIONS=--no-node-snapshot`). The constructor fails fast with an\n * actionable error when the flag is missing.\n */\n\nimport { sanitizeToolId } from '@mastra/core/tools';\nimport type { CodeModeToolResult, CodeModeTransport } from '@mastra/core/tools';\nimport { transformSync } from 'esbuild';\nimport ivm from 'isolated-vm';\n\n/** Default isolate heap limit, in MiB. */\nconst DEFAULT_MEMORY_LIMIT_MB = 128;\n\nexport interface IsolatedVmCodeModeTransportOptions {\n /**\n * V8 isolate heap limit in MiB. Exceeding it terminates the program.\n * Default: 128.\n */\n memoryLimitMb?: number;\n}\n\n/**\n * On Node 20+, isolated-vm cannot create isolates unless the host process was\n * started with `--no-node-snapshot` — without it, isolate creation crashes the\n * whole process. Detect the documented mechanisms and fail fast instead.\n */\nfunction assertNoNodeSnapshot(): void {\n const major = Number(process.versions.node.split('.')[0]);\n if (major < 20) return;\n if (process.execArgv.includes('--no-node-snapshot')) return;\n if ((process.env.NODE_OPTIONS ?? '').includes('--no-node-snapshot')) return;\n throw new Error(\n 'IsolatedVmCodeModeTransport requires the --no-node-snapshot flag on Node 20+. ' +\n 'Start your process with `node --no-node-snapshot ...` or set NODE_OPTIONS=\"--no-node-snapshot\". ' +\n 'Without it, creating a V8 isolate crashes the Node process.',\n );\n}\n\n/** Envelope returned by the guest program eval (as a JSON string). */\ninterface GuestResultEnvelope {\n ok: boolean;\n value?: unknown;\n error?: { message: string; name?: string };\n}\n\n/** Envelope returned by the host RPC handler (as a JSON string). */\ninterface HostRpcEnvelope {\n ok: boolean;\n result?: unknown;\n error?: { message: string; name?: string };\n}\n\n/**\n * Code Mode transport that executes programs in an in-process V8 isolate.\n *\n * No sandbox is required — the isolate is the execution boundary\n * (`requiresSandbox: false`).\n *\n * @example\n * ```typescript\n * import { createCodeMode } from '@mastra/core/tools';\n * import { IsolatedVmCodeModeTransport } from '@mastra/isolated-vm';\n *\n * const { tool, instructions } = createCodeMode(\n * { tools: { getWeather, getForecast } },\n * new IsolatedVmCodeModeTransport({ memoryLimitMb: 128 }),\n * );\n * ```\n */\nexport class IsolatedVmCodeModeTransport implements CodeModeTransport {\n readonly requiresSandbox = false;\n\n readonly #memoryLimitMb: number;\n\n constructor(options: IsolatedVmCodeModeTransportOptions = {}) {\n assertNoNodeSnapshot();\n this.#memoryLimitMb = options.memoryLimitMb ?? DEFAULT_MEMORY_LIMIT_MB;\n }\n\n async run(opts: Parameters<CodeModeTransport['run']>[0]): Promise<CodeModeToolResult> {\n const { program, toolIds, dispatch, timeout, abortSignal, onExternalCall, onExternalResult } = opts;\n\n const externals = toolIds.map(toolId => ({ toolId, externalName: sanitizeToolId(toolId) }));\n const allowList = new Set(toolIds);\n const logs: string[] = [];\n\n // Observer hooks are caller-supplied and best-effort: a throwing hook must\n // never prevent the RPC from responding, or the matching in-isolate promise\n // would hang until the timeout.\n const notifyCall = (tool: string, args: unknown): void => {\n try {\n onExternalCall?.(tool, args);\n } catch {\n /* observer errors are non-fatal */\n }\n };\n const notifyResult = (tool: string, durationMs: number, error?: Error): void => {\n try {\n onExternalResult?.(tool, durationMs, error);\n } catch {\n /* observer errors are non-fatal */\n }\n };\n\n // Strip TypeScript on the host; the isolate runs plain JavaScript. Wrapping\n // in an async arrow makes top-level `return`/`await`/`const` legal, same as\n // the core runner's program module.\n let strippedProgram: string;\n try {\n strippedProgram = transformSync(`(async () => {\\n${program}\\n})`, { loader: 'ts', target: 'es2022' }).code;\n } catch (error) {\n const err = error as { message?: string };\n return {\n success: false,\n logs,\n error: { message: err?.message ?? String(error), name: 'SyntaxError' },\n };\n }\n\n // Host-side RPC handler. Crosses the boundary as JSON strings in both\n // directions so no host references or non-JSON values ever leak into the\n // guest. Errors are returned in the envelope (never thrown) so the guest\n // can rebuild them with the original error name.\n const rpcHost = async (tool: string, argsJson: string): Promise<string> => {\n const started = Date.now();\n let args: unknown;\n try {\n args = JSON.parse(argsJson);\n } catch {\n args = undefined;\n }\n notifyCall(tool, args);\n // Allow-list enforcement: never invoke a tool that wasn't exposed.\n if (!allowList.has(tool)) {\n notifyResult(tool, Date.now() - started, new Error('not allowed'));\n return JSON.stringify({\n ok: false,\n error: { message: `Tool \"${tool}\" is not available in Code Mode`, name: 'NotAllowedError' },\n } satisfies HostRpcEnvelope);\n }\n try {\n const result = await dispatch(tool, args);\n // Serialize before reporting success so a non-serializable result\n // (circular reference, BigInt) falls through to the error path without\n // emitting a success event first.\n const json = JSON.stringify({ ok: true, result } satisfies HostRpcEnvelope);\n notifyResult(tool, Date.now() - started);\n return json;\n } catch (error) {\n const err = error as { message?: string; name?: string };\n notifyResult(tool, Date.now() - started, error instanceof Error ? error : new Error(String(error)));\n return JSON.stringify({\n ok: false,\n error: { message: err?.message ?? String(error), name: err?.name },\n } satisfies HostRpcEnvelope);\n }\n };\n\n const logHost = (message: string): void => {\n logs.push(message);\n };\n\n const isolate = new ivm.Isolate({ memoryLimit: this.#memoryLimitMb });\n let disposed = false;\n const disposeIsolate = (): void => {\n if (disposed) return;\n disposed = true;\n try {\n isolate.dispose();\n } catch {\n /* already disposed */\n }\n };\n\n let timedOut = false;\n let timer: NodeJS.Timeout | undefined;\n const onAbort = (): void => disposeIsolate();\n abortSignal?.addEventListener('abort', onAbort, { once: true });\n\n try {\n if (abortSignal?.aborted) {\n return { success: false, logs, error: { message: 'Code Mode execution aborted', name: 'AbortError' } };\n }\n\n const context = await isolate.createContext();\n\n // Bootstrap: console capture, the RPC bridge, and the `external_*`\n // globals. `$0`/`$1` are References to the host functions; they stay in\n // this closure's scope and are never attached to guest-reachable\n // objects — guest code only sees plain functions that close over them.\n await context.evalClosure(\n `\n const __rpc = (tool, args) => {\n let argsJson;\n try { argsJson = JSON.stringify(args === undefined ? null : args); } catch (e) {\n return Promise.reject(new Error('Arguments passed to an external_* function must be JSON-serializable'));\n }\n return $0\n .apply(undefined, [String(tool), argsJson], { result: { promise: true, copy: true } })\n .then((json) => {\n const res = JSON.parse(json);\n if (res.ok) return res.result;\n const err = new Error((res.error && res.error.message) || 'external tool failed');\n if (res.error && res.error.name) err.name = res.error.name;\n throw err;\n });\n };\n const __safeStringify = (value) => {\n try { return JSON.stringify(value); } catch { return String(value); }\n };\n const __log = (level, args) => {\n const message = args.map((a) => (typeof a === 'string' ? a : __safeStringify(a))).join(' ');\n $1.applyIgnored(undefined, [message]);\n };\n globalThis.console = Object.freeze({\n log: (...args) => __log('log', args),\n info: (...args) => __log('info', args),\n warn: (...args) => __log('warn', args),\n error: (...args) => __log('error', args),\n });\n for (const { externalName, toolId } of ${JSON.stringify(externals)}) {\n globalThis['external_' + externalName] = (input) => __rpc(toolId, input);\n }\n `,\n [rpcHost, logHost],\n { arguments: { reference: true } },\n );\n\n // The guest returns a JSON envelope string so results and errors cross\n // the boundary as data, mirroring the frame protocol's JSON semantics.\n const evalSource = `\n (async () => {\n const __user = ${strippedProgram}\n try {\n const __result = await __user();\n try {\n const json = JSON.stringify({ ok: true, value: __result });\n return json === undefined ? '{\"ok\":true}' : json;\n } catch {\n return JSON.stringify({\n ok: false,\n error: { message: 'Code Mode result is not JSON-serializable', name: 'TypeError' },\n });\n }\n } catch (e) {\n return JSON.stringify({\n ok: false,\n error: { message: (e && e.message) || String(e), name: e && e.name },\n });\n }\n })()\n `;\n\n // Two timeout layers: the eval `timeout` interrupts runaway synchronous\n // code; the host timer covers time spent awaiting (RPC round trips,\n // guest promises) by disposing the isolate, which rejects the eval.\n const timeoutPromise = new Promise<'timeout'>(resolve => {\n timer = setTimeout(() => {\n timedOut = true;\n resolve('timeout');\n disposeIsolate();\n }, timeout);\n });\n\n // isolated-vm types this as a nested promise; `await` flattens it and\n // `copy: true` guarantees the resolved value is the guest's JSON string.\n const evalPromise = context.eval(evalSource, {\n promise: true,\n copy: true,\n timeout,\n }) as unknown as Promise<string>;\n\n const outcome = await Promise.race([\n evalPromise.then(\n json => ({ kind: 'done' as const, json, error: undefined }),\n error => ({ kind: 'error' as const, json: undefined, error }),\n ),\n timeoutPromise.then(() => ({ kind: 'timeout' as const, json: undefined, error: undefined })),\n ]);\n\n if (outcome.kind === 'timeout' || timedOut) {\n return {\n success: false,\n logs,\n error: { message: `Code Mode execution timed out after ${timeout}ms`, name: 'TimeoutError' },\n };\n }\n\n if (outcome.kind === 'error') {\n const err = outcome.error as { message?: string; name?: string };\n if (abortSignal?.aborted) {\n return { success: false, logs, error: { message: 'Code Mode execution aborted', name: 'AbortError' } };\n }\n // The eval `timeout` option rejects with \"Script execution timed out\".\n if (/timed out/i.test(err?.message ?? '')) {\n return {\n success: false,\n logs,\n error: { message: `Code Mode execution timed out after ${timeout}ms`, name: 'TimeoutError' },\n };\n }\n return {\n success: false,\n logs,\n error: { message: err?.message ?? String(outcome.error), name: err?.name },\n };\n }\n\n const envelope = JSON.parse(outcome.json) as GuestResultEnvelope;\n return envelope.ok\n ? { success: true, result: envelope.value, logs }\n : { success: false, error: envelope.error, logs };\n } finally {\n if (timer) clearTimeout(timer);\n abortSignal?.removeEventListener('abort', onAbort);\n disposeIsolate();\n }\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { IsolatedVmCodeModeTransport, type IsolatedVmCodeModeTransportOptions } from './transport.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,KAAK,kCAAkC,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,301 @@
1
+ import { sanitizeToolId } from "@mastra/core/tools";
2
+ import { transformSync } from "esbuild";
3
+ import ivm from "isolated-vm";
4
+ //#region src/transport.ts
5
+ /**
6
+ * Code Mode — isolated-vm transport
7
+ *
8
+ * Runs the model's TypeScript program inside an in-process V8 isolate
9
+ * (via `isolated-vm`) instead of a WorkspaceSandbox. The isolate is a real
10
+ * security boundary: the guest has no filesystem, network, process, or module
11
+ * access — the only capabilities are the injected `external_*` functions,
12
+ * which call back into the host dispatcher (allow-list enforced host-side).
13
+ *
14
+ * Unlike the stdio/E2B transports there is no process boundary, so the frame
15
+ * protocol (`FRAME_PREFIX`, stdout parsing, stdin writes) is not used. Host
16
+ * calls cross the isolate boundary as JSON strings in both directions, so no
17
+ * host object references are ever exposed to guest code.
18
+ *
19
+ * TypeScript is stripped on the host with esbuild before evaluation (isolates
20
+ * run plain JavaScript).
21
+ *
22
+ * Requirements:
23
+ * - `isolated-vm` is a native addon (prebuilt binaries for common platforms,
24
+ * compiled from source elsewhere).
25
+ * - On Node 20+ the host process must be started with `--no-node-snapshot`
26
+ * (e.g. `node --no-node-snapshot server.js` or
27
+ * `NODE_OPTIONS=--no-node-snapshot`). The constructor fails fast with an
28
+ * actionable error when the flag is missing.
29
+ */
30
+ /** Default isolate heap limit, in MiB. */
31
+ const DEFAULT_MEMORY_LIMIT_MB = 128;
32
+ /**
33
+ * On Node 20+, isolated-vm cannot create isolates unless the host process was
34
+ * started with `--no-node-snapshot` — without it, isolate creation crashes the
35
+ * whole process. Detect the documented mechanisms and fail fast instead.
36
+ */
37
+ function assertNoNodeSnapshot() {
38
+ if (Number(process.versions.node.split(".")[0]) < 20) return;
39
+ if (process.execArgv.includes("--no-node-snapshot")) return;
40
+ if ((process.env.NODE_OPTIONS ?? "").includes("--no-node-snapshot")) return;
41
+ throw new Error("IsolatedVmCodeModeTransport requires the --no-node-snapshot flag on Node 20+. Start your process with `node --no-node-snapshot ...` or set NODE_OPTIONS=\"--no-node-snapshot\". Without it, creating a V8 isolate crashes the Node process.");
42
+ }
43
+ /**
44
+ * Code Mode transport that executes programs in an in-process V8 isolate.
45
+ *
46
+ * No sandbox is required — the isolate is the execution boundary
47
+ * (`requiresSandbox: false`).
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * import { createCodeMode } from '@mastra/core/tools';
52
+ * import { IsolatedVmCodeModeTransport } from '@mastra/isolated-vm';
53
+ *
54
+ * const { tool, instructions } = createCodeMode(
55
+ * { tools: { getWeather, getForecast } },
56
+ * new IsolatedVmCodeModeTransport({ memoryLimitMb: 128 }),
57
+ * );
58
+ * ```
59
+ */
60
+ var IsolatedVmCodeModeTransport = class {
61
+ requiresSandbox = false;
62
+ #memoryLimitMb;
63
+ constructor(options = {}) {
64
+ assertNoNodeSnapshot();
65
+ this.#memoryLimitMb = options.memoryLimitMb ?? DEFAULT_MEMORY_LIMIT_MB;
66
+ }
67
+ async run(opts) {
68
+ const { program, toolIds, dispatch, timeout, abortSignal, onExternalCall, onExternalResult } = opts;
69
+ const externals = toolIds.map((toolId) => ({
70
+ toolId,
71
+ externalName: sanitizeToolId(toolId)
72
+ }));
73
+ const allowList = new Set(toolIds);
74
+ const logs = [];
75
+ const notifyCall = (tool, args) => {
76
+ try {
77
+ onExternalCall?.(tool, args);
78
+ } catch {}
79
+ };
80
+ const notifyResult = (tool, durationMs, error) => {
81
+ try {
82
+ onExternalResult?.(tool, durationMs, error);
83
+ } catch {}
84
+ };
85
+ let strippedProgram;
86
+ try {
87
+ strippedProgram = transformSync(`(async () => {\n${program}\n})`, {
88
+ loader: "ts",
89
+ target: "es2022"
90
+ }).code;
91
+ } catch (error) {
92
+ return {
93
+ success: false,
94
+ logs,
95
+ error: {
96
+ message: error?.message ?? String(error),
97
+ name: "SyntaxError"
98
+ }
99
+ };
100
+ }
101
+ const rpcHost = async (tool, argsJson) => {
102
+ const started = Date.now();
103
+ let args;
104
+ try {
105
+ args = JSON.parse(argsJson);
106
+ } catch {
107
+ args = void 0;
108
+ }
109
+ notifyCall(tool, args);
110
+ if (!allowList.has(tool)) {
111
+ notifyResult(tool, Date.now() - started, /* @__PURE__ */ new Error("not allowed"));
112
+ return JSON.stringify({
113
+ ok: false,
114
+ error: {
115
+ message: `Tool "${tool}" is not available in Code Mode`,
116
+ name: "NotAllowedError"
117
+ }
118
+ });
119
+ }
120
+ try {
121
+ const result = await dispatch(tool, args);
122
+ const json = JSON.stringify({
123
+ ok: true,
124
+ result
125
+ });
126
+ notifyResult(tool, Date.now() - started);
127
+ return json;
128
+ } catch (error) {
129
+ const err = error;
130
+ notifyResult(tool, Date.now() - started, error instanceof Error ? error : new Error(String(error)));
131
+ return JSON.stringify({
132
+ ok: false,
133
+ error: {
134
+ message: err?.message ?? String(error),
135
+ name: err?.name
136
+ }
137
+ });
138
+ }
139
+ };
140
+ const logHost = (message) => {
141
+ logs.push(message);
142
+ };
143
+ const isolate = new ivm.Isolate({ memoryLimit: this.#memoryLimitMb });
144
+ let disposed = false;
145
+ const disposeIsolate = () => {
146
+ if (disposed) return;
147
+ disposed = true;
148
+ try {
149
+ isolate.dispose();
150
+ } catch {}
151
+ };
152
+ let timedOut = false;
153
+ let timer;
154
+ const onAbort = () => disposeIsolate();
155
+ abortSignal?.addEventListener("abort", onAbort, { once: true });
156
+ try {
157
+ if (abortSignal?.aborted) return {
158
+ success: false,
159
+ logs,
160
+ error: {
161
+ message: "Code Mode execution aborted",
162
+ name: "AbortError"
163
+ }
164
+ };
165
+ const context = await isolate.createContext();
166
+ await context.evalClosure(`
167
+ const __rpc = (tool, args) => {
168
+ let argsJson;
169
+ try { argsJson = JSON.stringify(args === undefined ? null : args); } catch (e) {
170
+ return Promise.reject(new Error('Arguments passed to an external_* function must be JSON-serializable'));
171
+ }
172
+ return $0
173
+ .apply(undefined, [String(tool), argsJson], { result: { promise: true, copy: true } })
174
+ .then((json) => {
175
+ const res = JSON.parse(json);
176
+ if (res.ok) return res.result;
177
+ const err = new Error((res.error && res.error.message) || 'external tool failed');
178
+ if (res.error && res.error.name) err.name = res.error.name;
179
+ throw err;
180
+ });
181
+ };
182
+ const __safeStringify = (value) => {
183
+ try { return JSON.stringify(value); } catch { return String(value); }
184
+ };
185
+ const __log = (level, args) => {
186
+ const message = args.map((a) => (typeof a === 'string' ? a : __safeStringify(a))).join(' ');
187
+ $1.applyIgnored(undefined, [message]);
188
+ };
189
+ globalThis.console = Object.freeze({
190
+ log: (...args) => __log('log', args),
191
+ info: (...args) => __log('info', args),
192
+ warn: (...args) => __log('warn', args),
193
+ error: (...args) => __log('error', args),
194
+ });
195
+ for (const { externalName, toolId } of ${JSON.stringify(externals)}) {
196
+ globalThis['external_' + externalName] = (input) => __rpc(toolId, input);
197
+ }
198
+ `, [rpcHost, logHost], { arguments: { reference: true } });
199
+ const evalSource = `
200
+ (async () => {
201
+ const __user = ${strippedProgram}
202
+ try {
203
+ const __result = await __user();
204
+ try {
205
+ const json = JSON.stringify({ ok: true, value: __result });
206
+ return json === undefined ? '{"ok":true}' : json;
207
+ } catch {
208
+ return JSON.stringify({
209
+ ok: false,
210
+ error: { message: 'Code Mode result is not JSON-serializable', name: 'TypeError' },
211
+ });
212
+ }
213
+ } catch (e) {
214
+ return JSON.stringify({
215
+ ok: false,
216
+ error: { message: (e && e.message) || String(e), name: e && e.name },
217
+ });
218
+ }
219
+ })()
220
+ `;
221
+ const timeoutPromise = new Promise((resolve) => {
222
+ timer = setTimeout(() => {
223
+ timedOut = true;
224
+ resolve("timeout");
225
+ disposeIsolate();
226
+ }, timeout);
227
+ });
228
+ const evalPromise = context.eval(evalSource, {
229
+ promise: true,
230
+ copy: true,
231
+ timeout
232
+ });
233
+ const outcome = await Promise.race([evalPromise.then((json) => ({
234
+ kind: "done",
235
+ json,
236
+ error: void 0
237
+ }), (error) => ({
238
+ kind: "error",
239
+ json: void 0,
240
+ error
241
+ })), timeoutPromise.then(() => ({
242
+ kind: "timeout",
243
+ json: void 0,
244
+ error: void 0
245
+ }))]);
246
+ if (outcome.kind === "timeout" || timedOut) return {
247
+ success: false,
248
+ logs,
249
+ error: {
250
+ message: `Code Mode execution timed out after ${timeout}ms`,
251
+ name: "TimeoutError"
252
+ }
253
+ };
254
+ if (outcome.kind === "error") {
255
+ const err = outcome.error;
256
+ if (abortSignal?.aborted) return {
257
+ success: false,
258
+ logs,
259
+ error: {
260
+ message: "Code Mode execution aborted",
261
+ name: "AbortError"
262
+ }
263
+ };
264
+ if (/timed out/i.test(err?.message ?? "")) return {
265
+ success: false,
266
+ logs,
267
+ error: {
268
+ message: `Code Mode execution timed out after ${timeout}ms`,
269
+ name: "TimeoutError"
270
+ }
271
+ };
272
+ return {
273
+ success: false,
274
+ logs,
275
+ error: {
276
+ message: err?.message ?? String(outcome.error),
277
+ name: err?.name
278
+ }
279
+ };
280
+ }
281
+ const envelope = JSON.parse(outcome.json);
282
+ return envelope.ok ? {
283
+ success: true,
284
+ result: envelope.value,
285
+ logs
286
+ } : {
287
+ success: false,
288
+ error: envelope.error,
289
+ logs
290
+ };
291
+ } finally {
292
+ if (timer) clearTimeout(timer);
293
+ abortSignal?.removeEventListener("abort", onAbort);
294
+ disposeIsolate();
295
+ }
296
+ }
297
+ };
298
+ //#endregion
299
+ export { IsolatedVmCodeModeTransport };
300
+
301
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["#memoryLimitMb","err"],"sources":["../src/transport.ts"],"sourcesContent":["/**\n * Code Mode — isolated-vm transport\n *\n * Runs the model's TypeScript program inside an in-process V8 isolate\n * (via `isolated-vm`) instead of a WorkspaceSandbox. The isolate is a real\n * security boundary: the guest has no filesystem, network, process, or module\n * access — the only capabilities are the injected `external_*` functions,\n * which call back into the host dispatcher (allow-list enforced host-side).\n *\n * Unlike the stdio/E2B transports there is no process boundary, so the frame\n * protocol (`FRAME_PREFIX`, stdout parsing, stdin writes) is not used. Host\n * calls cross the isolate boundary as JSON strings in both directions, so no\n * host object references are ever exposed to guest code.\n *\n * TypeScript is stripped on the host with esbuild before evaluation (isolates\n * run plain JavaScript).\n *\n * Requirements:\n * - `isolated-vm` is a native addon (prebuilt binaries for common platforms,\n * compiled from source elsewhere).\n * - On Node 20+ the host process must be started with `--no-node-snapshot`\n * (e.g. `node --no-node-snapshot server.js` or\n * `NODE_OPTIONS=--no-node-snapshot`). The constructor fails fast with an\n * actionable error when the flag is missing.\n */\n\nimport { sanitizeToolId } from '@mastra/core/tools';\nimport type { CodeModeToolResult, CodeModeTransport } from '@mastra/core/tools';\nimport { transformSync } from 'esbuild';\nimport ivm from 'isolated-vm';\n\n/** Default isolate heap limit, in MiB. */\nconst DEFAULT_MEMORY_LIMIT_MB = 128;\n\nexport interface IsolatedVmCodeModeTransportOptions {\n /**\n * V8 isolate heap limit in MiB. Exceeding it terminates the program.\n * Default: 128.\n */\n memoryLimitMb?: number;\n}\n\n/**\n * On Node 20+, isolated-vm cannot create isolates unless the host process was\n * started with `--no-node-snapshot` — without it, isolate creation crashes the\n * whole process. Detect the documented mechanisms and fail fast instead.\n */\nfunction assertNoNodeSnapshot(): void {\n const major = Number(process.versions.node.split('.')[0]);\n if (major < 20) return;\n if (process.execArgv.includes('--no-node-snapshot')) return;\n if ((process.env.NODE_OPTIONS ?? '').includes('--no-node-snapshot')) return;\n throw new Error(\n 'IsolatedVmCodeModeTransport requires the --no-node-snapshot flag on Node 20+. ' +\n 'Start your process with `node --no-node-snapshot ...` or set NODE_OPTIONS=\"--no-node-snapshot\". ' +\n 'Without it, creating a V8 isolate crashes the Node process.',\n );\n}\n\n/** Envelope returned by the guest program eval (as a JSON string). */\ninterface GuestResultEnvelope {\n ok: boolean;\n value?: unknown;\n error?: { message: string; name?: string };\n}\n\n/** Envelope returned by the host RPC handler (as a JSON string). */\ninterface HostRpcEnvelope {\n ok: boolean;\n result?: unknown;\n error?: { message: string; name?: string };\n}\n\n/**\n * Code Mode transport that executes programs in an in-process V8 isolate.\n *\n * No sandbox is required — the isolate is the execution boundary\n * (`requiresSandbox: false`).\n *\n * @example\n * ```typescript\n * import { createCodeMode } from '@mastra/core/tools';\n * import { IsolatedVmCodeModeTransport } from '@mastra/isolated-vm';\n *\n * const { tool, instructions } = createCodeMode(\n * { tools: { getWeather, getForecast } },\n * new IsolatedVmCodeModeTransport({ memoryLimitMb: 128 }),\n * );\n * ```\n */\nexport class IsolatedVmCodeModeTransport implements CodeModeTransport {\n readonly requiresSandbox = false;\n\n readonly #memoryLimitMb: number;\n\n constructor(options: IsolatedVmCodeModeTransportOptions = {}) {\n assertNoNodeSnapshot();\n this.#memoryLimitMb = options.memoryLimitMb ?? DEFAULT_MEMORY_LIMIT_MB;\n }\n\n async run(opts: Parameters<CodeModeTransport['run']>[0]): Promise<CodeModeToolResult> {\n const { program, toolIds, dispatch, timeout, abortSignal, onExternalCall, onExternalResult } = opts;\n\n const externals = toolIds.map(toolId => ({ toolId, externalName: sanitizeToolId(toolId) }));\n const allowList = new Set(toolIds);\n const logs: string[] = [];\n\n // Observer hooks are caller-supplied and best-effort: a throwing hook must\n // never prevent the RPC from responding, or the matching in-isolate promise\n // would hang until the timeout.\n const notifyCall = (tool: string, args: unknown): void => {\n try {\n onExternalCall?.(tool, args);\n } catch {\n /* observer errors are non-fatal */\n }\n };\n const notifyResult = (tool: string, durationMs: number, error?: Error): void => {\n try {\n onExternalResult?.(tool, durationMs, error);\n } catch {\n /* observer errors are non-fatal */\n }\n };\n\n // Strip TypeScript on the host; the isolate runs plain JavaScript. Wrapping\n // in an async arrow makes top-level `return`/`await`/`const` legal, same as\n // the core runner's program module.\n let strippedProgram: string;\n try {\n strippedProgram = transformSync(`(async () => {\\n${program}\\n})`, { loader: 'ts', target: 'es2022' }).code;\n } catch (error) {\n const err = error as { message?: string };\n return {\n success: false,\n logs,\n error: { message: err?.message ?? String(error), name: 'SyntaxError' },\n };\n }\n\n // Host-side RPC handler. Crosses the boundary as JSON strings in both\n // directions so no host references or non-JSON values ever leak into the\n // guest. Errors are returned in the envelope (never thrown) so the guest\n // can rebuild them with the original error name.\n const rpcHost = async (tool: string, argsJson: string): Promise<string> => {\n const started = Date.now();\n let args: unknown;\n try {\n args = JSON.parse(argsJson);\n } catch {\n args = undefined;\n }\n notifyCall(tool, args);\n // Allow-list enforcement: never invoke a tool that wasn't exposed.\n if (!allowList.has(tool)) {\n notifyResult(tool, Date.now() - started, new Error('not allowed'));\n return JSON.stringify({\n ok: false,\n error: { message: `Tool \"${tool}\" is not available in Code Mode`, name: 'NotAllowedError' },\n } satisfies HostRpcEnvelope);\n }\n try {\n const result = await dispatch(tool, args);\n // Serialize before reporting success so a non-serializable result\n // (circular reference, BigInt) falls through to the error path without\n // emitting a success event first.\n const json = JSON.stringify({ ok: true, result } satisfies HostRpcEnvelope);\n notifyResult(tool, Date.now() - started);\n return json;\n } catch (error) {\n const err = error as { message?: string; name?: string };\n notifyResult(tool, Date.now() - started, error instanceof Error ? error : new Error(String(error)));\n return JSON.stringify({\n ok: false,\n error: { message: err?.message ?? String(error), name: err?.name },\n } satisfies HostRpcEnvelope);\n }\n };\n\n const logHost = (message: string): void => {\n logs.push(message);\n };\n\n const isolate = new ivm.Isolate({ memoryLimit: this.#memoryLimitMb });\n let disposed = false;\n const disposeIsolate = (): void => {\n if (disposed) return;\n disposed = true;\n try {\n isolate.dispose();\n } catch {\n /* already disposed */\n }\n };\n\n let timedOut = false;\n let timer: NodeJS.Timeout | undefined;\n const onAbort = (): void => disposeIsolate();\n abortSignal?.addEventListener('abort', onAbort, { once: true });\n\n try {\n if (abortSignal?.aborted) {\n return { success: false, logs, error: { message: 'Code Mode execution aborted', name: 'AbortError' } };\n }\n\n const context = await isolate.createContext();\n\n // Bootstrap: console capture, the RPC bridge, and the `external_*`\n // globals. `$0`/`$1` are References to the host functions; they stay in\n // this closure's scope and are never attached to guest-reachable\n // objects — guest code only sees plain functions that close over them.\n await context.evalClosure(\n `\n const __rpc = (tool, args) => {\n let argsJson;\n try { argsJson = JSON.stringify(args === undefined ? null : args); } catch (e) {\n return Promise.reject(new Error('Arguments passed to an external_* function must be JSON-serializable'));\n }\n return $0\n .apply(undefined, [String(tool), argsJson], { result: { promise: true, copy: true } })\n .then((json) => {\n const res = JSON.parse(json);\n if (res.ok) return res.result;\n const err = new Error((res.error && res.error.message) || 'external tool failed');\n if (res.error && res.error.name) err.name = res.error.name;\n throw err;\n });\n };\n const __safeStringify = (value) => {\n try { return JSON.stringify(value); } catch { return String(value); }\n };\n const __log = (level, args) => {\n const message = args.map((a) => (typeof a === 'string' ? a : __safeStringify(a))).join(' ');\n $1.applyIgnored(undefined, [message]);\n };\n globalThis.console = Object.freeze({\n log: (...args) => __log('log', args),\n info: (...args) => __log('info', args),\n warn: (...args) => __log('warn', args),\n error: (...args) => __log('error', args),\n });\n for (const { externalName, toolId } of ${JSON.stringify(externals)}) {\n globalThis['external_' + externalName] = (input) => __rpc(toolId, input);\n }\n `,\n [rpcHost, logHost],\n { arguments: { reference: true } },\n );\n\n // The guest returns a JSON envelope string so results and errors cross\n // the boundary as data, mirroring the frame protocol's JSON semantics.\n const evalSource = `\n (async () => {\n const __user = ${strippedProgram}\n try {\n const __result = await __user();\n try {\n const json = JSON.stringify({ ok: true, value: __result });\n return json === undefined ? '{\"ok\":true}' : json;\n } catch {\n return JSON.stringify({\n ok: false,\n error: { message: 'Code Mode result is not JSON-serializable', name: 'TypeError' },\n });\n }\n } catch (e) {\n return JSON.stringify({\n ok: false,\n error: { message: (e && e.message) || String(e), name: e && e.name },\n });\n }\n })()\n `;\n\n // Two timeout layers: the eval `timeout` interrupts runaway synchronous\n // code; the host timer covers time spent awaiting (RPC round trips,\n // guest promises) by disposing the isolate, which rejects the eval.\n const timeoutPromise = new Promise<'timeout'>(resolve => {\n timer = setTimeout(() => {\n timedOut = true;\n resolve('timeout');\n disposeIsolate();\n }, timeout);\n });\n\n // isolated-vm types this as a nested promise; `await` flattens it and\n // `copy: true` guarantees the resolved value is the guest's JSON string.\n const evalPromise = context.eval(evalSource, {\n promise: true,\n copy: true,\n timeout,\n }) as unknown as Promise<string>;\n\n const outcome = await Promise.race([\n evalPromise.then(\n json => ({ kind: 'done' as const, json, error: undefined }),\n error => ({ kind: 'error' as const, json: undefined, error }),\n ),\n timeoutPromise.then(() => ({ kind: 'timeout' as const, json: undefined, error: undefined })),\n ]);\n\n if (outcome.kind === 'timeout' || timedOut) {\n return {\n success: false,\n logs,\n error: { message: `Code Mode execution timed out after ${timeout}ms`, name: 'TimeoutError' },\n };\n }\n\n if (outcome.kind === 'error') {\n const err = outcome.error as { message?: string; name?: string };\n if (abortSignal?.aborted) {\n return { success: false, logs, error: { message: 'Code Mode execution aborted', name: 'AbortError' } };\n }\n // The eval `timeout` option rejects with \"Script execution timed out\".\n if (/timed out/i.test(err?.message ?? '')) {\n return {\n success: false,\n logs,\n error: { message: `Code Mode execution timed out after ${timeout}ms`, name: 'TimeoutError' },\n };\n }\n return {\n success: false,\n logs,\n error: { message: err?.message ?? String(outcome.error), name: err?.name },\n };\n }\n\n const envelope = JSON.parse(outcome.json) as GuestResultEnvelope;\n return envelope.ok\n ? { success: true, result: envelope.value, logs }\n : { success: false, error: envelope.error, logs };\n } finally {\n if (timer) clearTimeout(timer);\n abortSignal?.removeEventListener('abort', onAbort);\n disposeIsolate();\n }\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Code Mode — isolated-vm transport
3
+ *
4
+ * Runs the model's TypeScript program inside an in-process V8 isolate
5
+ * (via `isolated-vm`) instead of a WorkspaceSandbox. The isolate is a real
6
+ * security boundary: the guest has no filesystem, network, process, or module
7
+ * access — the only capabilities are the injected `external_*` functions,
8
+ * which call back into the host dispatcher (allow-list enforced host-side).
9
+ *
10
+ * Unlike the stdio/E2B transports there is no process boundary, so the frame
11
+ * protocol (`FRAME_PREFIX`, stdout parsing, stdin writes) is not used. Host
12
+ * calls cross the isolate boundary as JSON strings in both directions, so no
13
+ * host object references are ever exposed to guest code.
14
+ *
15
+ * TypeScript is stripped on the host with esbuild before evaluation (isolates
16
+ * run plain JavaScript).
17
+ *
18
+ * Requirements:
19
+ * - `isolated-vm` is a native addon (prebuilt binaries for common platforms,
20
+ * compiled from source elsewhere).
21
+ * - On Node 20+ the host process must be started with `--no-node-snapshot`
22
+ * (e.g. `node --no-node-snapshot server.js` or
23
+ * `NODE_OPTIONS=--no-node-snapshot`). The constructor fails fast with an
24
+ * actionable error when the flag is missing.
25
+ */
26
+ import type { CodeModeToolResult, CodeModeTransport } from '@mastra/core/tools';
27
+ export interface IsolatedVmCodeModeTransportOptions {
28
+ /**
29
+ * V8 isolate heap limit in MiB. Exceeding it terminates the program.
30
+ * Default: 128.
31
+ */
32
+ memoryLimitMb?: number;
33
+ }
34
+ /**
35
+ * Code Mode transport that executes programs in an in-process V8 isolate.
36
+ *
37
+ * No sandbox is required — the isolate is the execution boundary
38
+ * (`requiresSandbox: false`).
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * import { createCodeMode } from '@mastra/core/tools';
43
+ * import { IsolatedVmCodeModeTransport } from '@mastra/isolated-vm';
44
+ *
45
+ * const { tool, instructions } = createCodeMode(
46
+ * { tools: { getWeather, getForecast } },
47
+ * new IsolatedVmCodeModeTransport({ memoryLimitMb: 128 }),
48
+ * );
49
+ * ```
50
+ */
51
+ export declare class IsolatedVmCodeModeTransport implements CodeModeTransport {
52
+ #private;
53
+ readonly requiresSandbox = false;
54
+ constructor(options?: IsolatedVmCodeModeTransportOptions);
55
+ run(opts: Parameters<CodeModeTransport['run']>[0]): Promise<CodeModeToolResult>;
56
+ }
57
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAOhF,MAAM,WAAW,kCAAkC;IACjD;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAiCD;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,2BAA4B,YAAW,iBAAiB;;IACnE,QAAQ,CAAC,eAAe,SAAS;gBAIrB,OAAO,GAAE,kCAAuC;IAKtD,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,kBAAkB,CAAC;CA+OtF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/isolated-vm",
3
- "version": "0.0.0",
3
+ "version": "0.1.0",
4
4
  "description": "In-process V8 isolate Code Mode transport for Mastra, backed by isolated-vm",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -18,31 +18,21 @@
18
18
  },
19
19
  "./package.json": "./package.json"
20
20
  },
21
- "scripts": {
22
- "build": "tsdown --silent --config tsdown.config.ts",
23
- "build:lib": "pnpm build",
24
- "build:watch": "pnpm build --watch",
25
- "typecheck": "tsc --noEmit",
26
- "test": "vitest run",
27
- "test:watch": "vitest watch",
28
- "lint": "oxlint . && eslint .",
29
- "lint:fix": "oxlint --fix . && eslint --fix ."
30
- },
31
21
  "license": "Apache-2.0",
32
22
  "dependencies": {
33
23
  "esbuild": "^0.28.0",
34
24
  "isolated-vm": "^6.1.2"
35
25
  },
36
26
  "devDependencies": {
37
- "@internal/lint": "workspace:*",
38
- "@internal/types-builder": "workspace:*",
39
- "@mastra/core": "workspace:*",
40
27
  "@types/node": "22.20.1",
41
- "@vitest/coverage-v8": "catalog:",
28
+ "@vitest/coverage-v8": "4.1.10",
42
29
  "eslint": "^10.7.0",
43
30
  "tsdown": "0.22.9",
44
- "typescript": "catalog:",
45
- "vitest": "catalog:"
31
+ "typescript": "^6.0.3",
32
+ "vitest": "4.1.10",
33
+ "@internal/lint": "0.0.119",
34
+ "@internal/types-builder": "0.0.94",
35
+ "@mastra/core": "1.55.0"
46
36
  },
47
37
  "peerDependencies": {
48
38
  "@mastra/core": ">=1.55.0-0 <2.0.0-0"
@@ -62,5 +52,15 @@
62
52
  },
63
53
  "engines": {
64
54
  "node": ">=22.13.0"
55
+ },
56
+ "scripts": {
57
+ "build": "tsdown --silent --config tsdown.config.ts",
58
+ "build:lib": "pnpm build",
59
+ "build:watch": "pnpm build --watch",
60
+ "typecheck": "tsc --noEmit",
61
+ "test": "vitest run",
62
+ "test:watch": "vitest watch",
63
+ "lint": "oxlint . && eslint .",
64
+ "lint:fix": "oxlint --fix . && eslint --fix ."
65
65
  }
66
- }
66
+ }