integrate-sdk 0.9.3-dev.0 → 0.9.4-dev.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.
Files changed (62) hide show
  1. package/dist/adapters/auto-routes.js +713 -15
  2. package/dist/adapters/index.js +713 -15
  3. package/dist/adapters/nextjs.js +713 -15
  4. package/dist/adapters/node.js +713 -15
  5. package/dist/adapters/svelte-kit.js +713 -15
  6. package/dist/adapters/tanstack-start.js +713 -15
  7. package/dist/ai/anthropic.d.ts +11 -0
  8. package/dist/ai/anthropic.d.ts.map +1 -1
  9. package/dist/ai/anthropic.js +552 -2
  10. package/dist/ai/google.d.ts +11 -0
  11. package/dist/ai/google.d.ts.map +1 -1
  12. package/dist/ai/google.js +561 -2
  13. package/dist/ai/index.js +648 -8
  14. package/dist/ai/openai.d.ts +11 -0
  15. package/dist/ai/openai.d.ts.map +1 -1
  16. package/dist/ai/openai.js +550 -2
  17. package/dist/ai/vercel-ai.d.ts +13 -0
  18. package/dist/ai/vercel-ai.d.ts.map +1 -1
  19. package/dist/ai/vercel-ai.js +536 -2
  20. package/dist/code-mode/executor.d.ts +99 -0
  21. package/dist/code-mode/executor.d.ts.map +1 -0
  22. package/dist/code-mode/executor.js +207 -0
  23. package/dist/code-mode/index.d.ts +12 -0
  24. package/dist/code-mode/index.d.ts.map +1 -0
  25. package/dist/code-mode/index.js +527 -0
  26. package/dist/code-mode/runtime-stub.d.ts +16 -0
  27. package/dist/code-mode/runtime-stub.d.ts.map +1 -0
  28. package/dist/code-mode/runtime-stub.js +72 -0
  29. package/dist/code-mode/tool-builder.d.ts +83 -0
  30. package/dist/code-mode/tool-builder.d.ts.map +1 -0
  31. package/dist/code-mode/tool-builder.js +524 -0
  32. package/dist/code-mode/type-generator.d.ts +22 -0
  33. package/dist/code-mode/type-generator.d.ts.map +1 -0
  34. package/dist/code-mode/type-generator.js +217 -0
  35. package/dist/index.js +713 -15
  36. package/dist/oauth.js +713 -15
  37. package/dist/server.d.ts +1 -0
  38. package/dist/server.d.ts.map +1 -1
  39. package/dist/server.js +724 -16
  40. package/dist/src/ai/anthropic.d.ts +11 -0
  41. package/dist/src/ai/anthropic.d.ts.map +1 -1
  42. package/dist/src/ai/google.d.ts +11 -0
  43. package/dist/src/ai/google.d.ts.map +1 -1
  44. package/dist/src/ai/openai.d.ts +11 -0
  45. package/dist/src/ai/openai.d.ts.map +1 -1
  46. package/dist/src/ai/vercel-ai.d.ts +13 -0
  47. package/dist/src/ai/vercel-ai.d.ts.map +1 -1
  48. package/dist/src/code-mode/executor.d.ts +99 -0
  49. package/dist/src/code-mode/executor.d.ts.map +1 -0
  50. package/dist/src/code-mode/index.d.ts +12 -0
  51. package/dist/src/code-mode/index.d.ts.map +1 -0
  52. package/dist/src/code-mode/runtime-stub.d.ts +16 -0
  53. package/dist/src/code-mode/runtime-stub.d.ts.map +1 -0
  54. package/dist/src/code-mode/tool-builder.d.ts +83 -0
  55. package/dist/src/code-mode/tool-builder.d.ts.map +1 -0
  56. package/dist/src/code-mode/type-generator.d.ts +22 -0
  57. package/dist/src/code-mode/type-generator.d.ts.map +1 -0
  58. package/dist/src/config/types.d.ts +55 -0
  59. package/dist/src/config/types.d.ts.map +1 -1
  60. package/dist/src/server.d.ts.map +1 -1
  61. package/package.json +15 -6
  62. package/server.ts +9 -0
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Code Mode: shared `execute_code` tool builder
3
+ *
4
+ * Used by every AI helper (`getVercelAITools`, `getOpenAITools`,
5
+ * `getAnthropicTools`, `getGoogleTools`) so that when Code Mode is the
6
+ * selected mode they return a single `execute_code` tool instead of one
7
+ * tool per MCP entry. Each helper wraps the returned `execute` into its
8
+ * own SDK-specific tool envelope.
9
+ */
10
+ import type { MCPClient } from "../client.js";
11
+ import type { MCPContext } from "../config/types.js";
12
+ import type { MCPTool } from "../protocol/messages.js";
13
+ import { type ExecuteSandboxCodeResult } from "./executor.js";
14
+ export declare const CODE_MODE_TOOL_NAME = "execute_code";
15
+ export interface CodeModeToolOptions {
16
+ /** Enabled MCP tools (already fetched by the caller). */
17
+ tools: MCPTool[];
18
+ /** Provider tokens to forward to the sandbox. */
19
+ providerTokens?: Record<string, string>;
20
+ /** Multi-tenant user context. */
21
+ context?: MCPContext;
22
+ /**
23
+ * Integration IDs enabled on this client (comma-separated or array).
24
+ * Forwarded as `x-integrations` so the MCP server can scope tool dispatch.
25
+ */
26
+ integrationIds?: string[];
27
+ /**
28
+ * Sandbox + callback overrides. Everything is optional — defaults come
29
+ * from the server client's `__oauthConfig.codeMode` block (set by
30
+ * `createMCPServer`) or from `INTEGRATE_PUBLIC_URL`.
31
+ */
32
+ sandbox?: {
33
+ publicUrl?: string;
34
+ runtime?: "node24" | "node22";
35
+ timeoutMs?: number;
36
+ vcpus?: number;
37
+ networkPolicy?: "allow-all" | "deny-all" | {
38
+ allow?: string[];
39
+ subnets?: {
40
+ allow?: string[];
41
+ deny?: string[];
42
+ };
43
+ };
44
+ };
45
+ }
46
+ export interface CodeModeToolDefinition {
47
+ name: string;
48
+ description: string;
49
+ parameters: {
50
+ type: "object";
51
+ properties: {
52
+ code: {
53
+ type: "string";
54
+ description: string;
55
+ };
56
+ };
57
+ required: ["code"];
58
+ additionalProperties: false;
59
+ };
60
+ execute: (input: {
61
+ code: string;
62
+ }) => Promise<ExecuteSandboxCodeResult>;
63
+ }
64
+ export declare function resolveCodeModeClientConfig(client: MCPClient<any>): {
65
+ publicUrl?: string;
66
+ runtime?: "node24" | "node22";
67
+ timeoutMs?: number;
68
+ vcpus?: number;
69
+ networkPolicy?: "allow-all" | "deny-all" | {
70
+ allow?: string[];
71
+ subnets?: {
72
+ allow?: string[];
73
+ deny?: string[];
74
+ };
75
+ };
76
+ };
77
+ /**
78
+ * Build the `execute_code` tool definition. The returned `execute` function
79
+ * is what the AI provider SDK ultimately invokes when the model picks the
80
+ * tool.
81
+ */
82
+ export declare function buildCodeModeTool(client: MCPClient<any>, options: CodeModeToolOptions): CodeModeToolDefinition;
83
+ //# sourceMappingURL=tool-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-builder.d.ts","sourceRoot":"","sources":["../../../src/code-mode/tool-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAAsB,KAAK,wBAAwB,EAAE,MAAM,eAAe,CAAC;AAGlF,eAAO,MAAM,mBAAmB,iBAAiB,CAAC;AAElD,MAAM,WAAW,mBAAmB;IAClC,yDAAyD;IACzD,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,iDAAiD;IACjD,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,iCAAiC;IACjC,OAAO,CAAC,EAAE,UAAU,CAAC;IACrB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B;;;;OAIG;IACH,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,OAAO,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;QAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,aAAa,CAAC,EAAE,WAAW,GAAG,UAAU,GAAG;YAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;YAAC,OAAO,CAAC,EAAE;gBAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;gBAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;aAAE,CAAA;SAAE,CAAC;KAClH,CAAC;CACH;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE;QACV,IAAI,EAAE,QAAQ,CAAC;QACf,UAAU,EAAE;YACV,IAAI,EAAE;gBAAE,IAAI,EAAE,QAAQ,CAAC;gBAAC,WAAW,EAAE,MAAM,CAAA;aAAE,CAAC;SAC/C,CAAC;QACF,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC;QACnB,oBAAoB,EAAE,KAAK,CAAC;KAC7B,CAAC;IACF,OAAO,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,wBAAwB,CAAC,CAAC;CACzE;AAuBD,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,GAAG;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,WAAW,GAAG,UAAU,GAAG;QAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,OAAO,CAAC,EAAE;YAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;SAAE,CAAA;KAAE,CAAC;CAClH,CAGA;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,EACtB,OAAO,EAAE,mBAAmB,GAC3B,sBAAsB,CA6DxB"}
@@ -0,0 +1,524 @@
1
+ // ../utils/naming.ts
2
+ function snakeToCamel(str) {
3
+ return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
4
+ }
5
+ function toolNameToMethod(toolName) {
6
+ const withoutPrefix = toolName.replace(/^[^_]+_/, "");
7
+ return snakeToCamel(withoutPrefix);
8
+ }
9
+
10
+ // type-generator.ts
11
+ var RESERVED_TS = new Set([
12
+ "break",
13
+ "case",
14
+ "catch",
15
+ "class",
16
+ "const",
17
+ "continue",
18
+ "debugger",
19
+ "default",
20
+ "delete",
21
+ "do",
22
+ "else",
23
+ "enum",
24
+ "export",
25
+ "extends",
26
+ "false",
27
+ "finally",
28
+ "for",
29
+ "function",
30
+ "if",
31
+ "import",
32
+ "in",
33
+ "instanceof",
34
+ "new",
35
+ "null",
36
+ "return",
37
+ "super",
38
+ "switch",
39
+ "this",
40
+ "throw",
41
+ "true",
42
+ "try",
43
+ "typeof",
44
+ "var",
45
+ "void",
46
+ "while",
47
+ "with",
48
+ "as",
49
+ "implements",
50
+ "interface",
51
+ "let",
52
+ "package",
53
+ "private",
54
+ "protected",
55
+ "public",
56
+ "static",
57
+ "yield"
58
+ ]);
59
+ function safeIdent(name) {
60
+ if (!/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name) || RESERVED_TS.has(name)) {
61
+ return JSON.stringify(name);
62
+ }
63
+ return name;
64
+ }
65
+ function integrationFromToolName(toolName) {
66
+ const idx = toolName.indexOf("_");
67
+ return idx === -1 ? toolName : toolName.slice(0, idx);
68
+ }
69
+ function jsonSchemaToTs(schema, indent) {
70
+ if (!schema || typeof schema !== "object")
71
+ return "unknown";
72
+ const s = schema;
73
+ if (Array.isArray(s.enum) && s.enum.length > 0) {
74
+ return s.enum.map((v) => typeof v === "string" ? JSON.stringify(v) : typeof v === "number" || typeof v === "boolean" ? String(v) : "unknown").join(" | ");
75
+ }
76
+ if (Array.isArray(s.type)) {
77
+ return s.type.map((t2) => jsonSchemaToTs({ ...s, type: t2 }, indent)).join(" | ");
78
+ }
79
+ const t = s.type;
80
+ switch (t) {
81
+ case "string":
82
+ return "string";
83
+ case "number":
84
+ case "integer":
85
+ return "number";
86
+ case "boolean":
87
+ return "boolean";
88
+ case "null":
89
+ return "null";
90
+ case "array": {
91
+ const items = s.items;
92
+ if (Array.isArray(items))
93
+ return "unknown[]";
94
+ const inner = jsonSchemaToTs(items, indent);
95
+ return /[|&]/.test(inner) ? `Array<${inner}>` : `${inner}[]`;
96
+ }
97
+ case "object":
98
+ return objectShape(s, indent);
99
+ default:
100
+ if (s.properties && typeof s.properties === "object")
101
+ return objectShape(s, indent);
102
+ return "unknown";
103
+ }
104
+ }
105
+ function objectShape(schema, indent) {
106
+ const props = schema.properties && typeof schema.properties === "object" ? schema.properties : {};
107
+ const keys = Object.keys(props);
108
+ if (keys.length === 0) {
109
+ return schema.additionalProperties === false ? "Record<string, never>" : "Record<string, unknown>";
110
+ }
111
+ const required = new Set(Array.isArray(schema.required) ? schema.required : []);
112
+ const inner = indent + " ";
113
+ const lines = ["{"];
114
+ for (const key of keys) {
115
+ const prop = props[key];
116
+ const desc = prop && typeof prop.description === "string" ? prop.description : undefined;
117
+ if (desc)
118
+ lines.push(`${inner}/** ${desc.replace(/\*\//g, "*\\/")} */`);
119
+ const optional = required.has(key) ? "" : "?";
120
+ const type = jsonSchemaToTs(prop, inner);
121
+ lines.push(`${inner}${safeIdent(key)}${optional}: ${type};`);
122
+ }
123
+ lines.push(`${indent}}`);
124
+ return lines.join(`
125
+ `);
126
+ }
127
+ function argsType(schema) {
128
+ if (!schema)
129
+ return "Record<string, unknown>";
130
+ const hasProps = schema.properties && Object.keys(schema.properties).length > 0;
131
+ if (!hasProps)
132
+ return "Record<string, unknown>";
133
+ return objectShape(schema, " ");
134
+ }
135
+ function methodHasRequiredArgs(schema) {
136
+ if (!schema || !schema.properties)
137
+ return false;
138
+ const req = Array.isArray(schema.required) ? schema.required : [];
139
+ return req.length > 0;
140
+ }
141
+ function formatDescription(desc, indent) {
142
+ if (!desc)
143
+ return "";
144
+ const cleaned = desc.replace(/\*\//g, "*\\/").trim();
145
+ if (!cleaned.includes(`
146
+ `))
147
+ return `${indent}/** ${cleaned} */
148
+ `;
149
+ const lines = cleaned.split(`
150
+ `).map((l) => `${indent} * ${l}`).join(`
151
+ `);
152
+ return `${indent}/**
153
+ ${lines}
154
+ ${indent} */
155
+ `;
156
+ }
157
+ function generateCodeModeTypes(tools) {
158
+ const byIntegration = {};
159
+ for (const tool of tools) {
160
+ const integration = integrationFromToolName(tool.name);
161
+ (byIntegration[integration] ??= []).push(tool);
162
+ }
163
+ const methodMap = {};
164
+ const integrationCounts = {};
165
+ const sections = [];
166
+ const integrationIds = Object.keys(byIntegration).sort();
167
+ sections.push("/**");
168
+ sections.push(" * Integrate SDK — available APIs inside `execute_code`.");
169
+ sections.push(" * Every method is async and returns the MCP tool-call response.");
170
+ sections.push(" * Call them via the exported `client` object, e.g.");
171
+ sections.push(" * const repos = await client.github.listRepos();");
172
+ sections.push(" */");
173
+ sections.push("");
174
+ for (const integrationId of integrationIds) {
175
+ const integrationTools = byIntegration[integrationId].slice().sort((a, b) => a.name.localeCompare(b.name));
176
+ integrationCounts[integrationId] = integrationTools.length;
177
+ const interfaceName = pascalCase(integrationId) + "Client";
178
+ sections.push(`export interface ${interfaceName} {`);
179
+ for (const tool of integrationTools) {
180
+ const methodName = toolNameToMethod(tool.name);
181
+ methodMap[`${integrationId}.${methodName}`] = tool.name;
182
+ sections.push(formatDescription(tool.description, " "));
183
+ const argType = argsType(tool.inputSchema);
184
+ const argIsOptional = !methodHasRequiredArgs(tool.inputSchema);
185
+ const paramName = argIsOptional ? "args?" : "args";
186
+ sections.push(` ${safeIdent(methodName)}(${paramName}: ${argType}): Promise<ToolResult>;`);
187
+ }
188
+ sections.push("}");
189
+ sections.push("");
190
+ }
191
+ sections.push("export interface ToolResult {");
192
+ sections.push(" content: Array<{ type: 'text' | 'image' | 'resource'; text?: string; data?: string; mimeType?: string; [key: string]: unknown }>;");
193
+ sections.push(" isError?: boolean;");
194
+ sections.push(" structuredContent?: Record<string, unknown>;");
195
+ sections.push("}");
196
+ sections.push("");
197
+ sections.push("export interface Client {");
198
+ for (const integrationId of integrationIds) {
199
+ const interfaceName = pascalCase(integrationId) + "Client";
200
+ sections.push(` ${safeIdent(integrationId)}: ${interfaceName};`);
201
+ }
202
+ sections.push("}");
203
+ sections.push("");
204
+ sections.push("export declare const client: Client;");
205
+ return {
206
+ source: sections.filter((line, idx, arr) => !(line === "" && arr[idx - 1] === "")).join(`
207
+ `),
208
+ methodMap,
209
+ integrationCounts
210
+ };
211
+ }
212
+ function pascalCase(id) {
213
+ return id.split(/[^A-Za-z0-9]/).filter(Boolean).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join("") || "Unknown";
214
+ }
215
+
216
+ // runtime-stub.ts
217
+ var RUNTIME_STUB_SOURCE = `// runtime.mjs — generated by integrate-sdk code mode
218
+ const MCP_URL = process.env.INTEGRATE_MCP_URL;
219
+ const SESSION_TOKEN = process.env.INTEGRATE_SESSION_TOKEN;
220
+ const PROVIDER_TOKENS = process.env.INTEGRATE_PROVIDER_TOKENS || '';
221
+ const INTEGRATIONS_HEADER = process.env.INTEGRATE_INTEGRATIONS || '';
222
+ const CONTEXT_JSON = process.env.INTEGRATE_CONTEXT || '';
223
+
224
+ if (!MCP_URL) {
225
+ throw new Error('INTEGRATE_MCP_URL is not set — the sandbox cannot reach the MCP route.');
226
+ }
227
+
228
+ function camelToSnake(str) {
229
+ return str.replace(/[A-Z]/g, (letter) => '_' + letter.toLowerCase());
230
+ }
231
+
232
+ async function callTool(toolName, args) {
233
+ const headers = {
234
+ 'Content-Type': 'application/json',
235
+ 'x-integrate-code-mode': '1',
236
+ };
237
+ if (SESSION_TOKEN) headers['Authorization'] = 'Bearer ' + SESSION_TOKEN;
238
+ if (PROVIDER_TOKENS) headers['x-integrate-tokens'] = PROVIDER_TOKENS;
239
+ if (INTEGRATIONS_HEADER) headers['x-integrations'] = INTEGRATIONS_HEADER;
240
+ if (CONTEXT_JSON) headers['x-integrate-context'] = CONTEXT_JSON;
241
+
242
+ const res = await fetch(MCP_URL, {
243
+ method: 'POST',
244
+ headers,
245
+ body: JSON.stringify({ name: toolName, arguments: args || {} }),
246
+ });
247
+
248
+ const text = await res.text();
249
+ let payload;
250
+ try {
251
+ payload = text ? JSON.parse(text) : null;
252
+ } catch {
253
+ payload = { content: [{ type: 'text', text }] };
254
+ }
255
+
256
+ if (!res.ok) {
257
+ const message = (payload && (payload.error || payload.message)) || 'Tool call failed: HTTP ' + res.status;
258
+ const err = new Error(message);
259
+ err.status = res.status;
260
+ err.toolName = toolName;
261
+ throw err;
262
+ }
263
+
264
+ return payload;
265
+ }
266
+
267
+ function createIntegrationProxy(integrationId) {
268
+ return new Proxy({}, {
269
+ get(_target, methodName) {
270
+ if (typeof methodName !== 'string') return undefined;
271
+ return (args) => callTool(integrationId + '_' + camelToSnake(methodName), args);
272
+ },
273
+ });
274
+ }
275
+
276
+ export const client = new Proxy({}, {
277
+ get(_target, integrationId) {
278
+ if (typeof integrationId !== 'string') return undefined;
279
+ return createIntegrationProxy(integrationId);
280
+ },
281
+ });
282
+
283
+ export { callTool };
284
+ `;
285
+
286
+ // executor.ts
287
+ var sandboxFactoryOverride = null;
288
+ function __setSandboxFactoryForTests(factory) {
289
+ sandboxFactoryOverride = factory;
290
+ }
291
+ async function loadSandboxFactory() {
292
+ if (sandboxFactoryOverride)
293
+ return sandboxFactoryOverride;
294
+ try {
295
+ const dynamicImport = new Function("specifier", "return import(specifier)");
296
+ const pkg = "@" + "vercel/sandbox";
297
+ const mod = await dynamicImport(pkg);
298
+ return mod.Sandbox ?? mod.default?.Sandbox ?? mod;
299
+ } catch (err) {
300
+ throw new Error("Code Mode requires the optional peer dependency `@vercel/sandbox`. " + "Install it with `npm install @vercel/sandbox` (or `bun add @vercel/sandbox`).");
301
+ }
302
+ }
303
+ var RESULT_SENTINEL = "__INTEGRATE_RESULT__";
304
+ function wrapUserCode(code) {
305
+ return `// user.mjs — wrapped by integrate-sdk code mode
306
+ import { client, callTool } from './runtime.mjs';
307
+
308
+ (async () => {
309
+ try {
310
+ const __result = await (async () => {
311
+ ${code}
312
+ })();
313
+ if (typeof __result !== 'undefined') {
314
+ process.stdout.write('\\n' + ${JSON.stringify(RESULT_SENTINEL)} + JSON.stringify(__result) + '\\n');
315
+ }
316
+ } catch (err) {
317
+ const payload = {
318
+ message: err && err.message ? err.message : String(err),
319
+ name: err && err.name,
320
+ stack: err && err.stack,
321
+ toolName: err && err.toolName,
322
+ status: err && err.status,
323
+ };
324
+ process.stderr.write('\\n' + ${JSON.stringify(RESULT_SENTINEL)} + JSON.stringify({ error: payload }) + '\\n');
325
+ process.exit(1);
326
+ }
327
+ })();
328
+ `;
329
+ }
330
+ function defaultNetworkPolicy(mcpUrl) {
331
+ try {
332
+ const host = new URL(mcpUrl).hostname;
333
+ return { allow: [host] };
334
+ } catch {
335
+ return { allow: [] };
336
+ }
337
+ }
338
+ function extractResult(stream) {
339
+ const idx = stream.lastIndexOf(RESULT_SENTINEL);
340
+ if (idx === -1)
341
+ return { cleaned: stream };
342
+ const before = stream.slice(0, idx).replace(/\n$/, "");
343
+ const rest = stream.slice(idx + RESULT_SENTINEL.length);
344
+ const newlineIdx = rest.indexOf(`
345
+ `);
346
+ const payload = newlineIdx === -1 ? rest : rest.slice(0, newlineIdx);
347
+ const after = newlineIdx === -1 ? "" : rest.slice(newlineIdx + 1);
348
+ try {
349
+ return { cleaned: (before + after).trimEnd(), result: JSON.parse(payload) };
350
+ } catch {
351
+ return { cleaned: stream };
352
+ }
353
+ }
354
+ async function executeSandboxCode(options) {
355
+ const startedAt = Date.now();
356
+ const runtime = options.runtime ?? "node22";
357
+ const timeoutMs = options.timeoutMs ?? 60000;
358
+ const networkPolicy = options.networkPolicy ?? defaultNetworkPolicy(options.mcpUrl);
359
+ let sandbox = null;
360
+ try {
361
+ const Sandbox = await loadSandboxFactory();
362
+ sandbox = await Sandbox.create({
363
+ runtime,
364
+ timeout: timeoutMs,
365
+ resources: options.vcpus ? { vcpus: options.vcpus } : undefined,
366
+ networkPolicy
367
+ });
368
+ const runtimeContent = Buffer.from(RUNTIME_STUB_SOURCE, "utf-8");
369
+ const userContent = Buffer.from(wrapUserCode(options.code), "utf-8");
370
+ await sandbox.writeFiles([
371
+ { path: "runtime.mjs", content: runtimeContent },
372
+ { path: "user.mjs", content: userContent }
373
+ ]);
374
+ const env = {
375
+ INTEGRATE_MCP_URL: options.mcpUrl
376
+ };
377
+ if (options.sessionToken)
378
+ env.INTEGRATE_SESSION_TOKEN = options.sessionToken;
379
+ if (options.providerTokens && Object.keys(options.providerTokens).length > 0) {
380
+ env.INTEGRATE_PROVIDER_TOKENS = JSON.stringify(options.providerTokens);
381
+ }
382
+ if (options.integrationsHeader)
383
+ env.INTEGRATE_INTEGRATIONS = options.integrationsHeader;
384
+ if (options.context)
385
+ env.INTEGRATE_CONTEXT = JSON.stringify(options.context);
386
+ const cmd = await sandbox.runCommand({
387
+ cmd: "node",
388
+ args: ["user.mjs"],
389
+ env
390
+ });
391
+ const [stdoutRaw, stderrRaw] = await Promise.all([cmd.stdout(), cmd.stderr()]);
392
+ const stdoutExtract = extractResult(stdoutRaw);
393
+ const stderrExtract = extractResult(stderrRaw);
394
+ return {
395
+ success: cmd.exitCode === 0,
396
+ exitCode: cmd.exitCode,
397
+ result: stdoutExtract.result ?? stderrExtract.result,
398
+ stdout: stdoutExtract.cleaned,
399
+ stderr: stderrExtract.cleaned,
400
+ durationMs: Date.now() - startedAt
401
+ };
402
+ } catch (err) {
403
+ return {
404
+ success: false,
405
+ exitCode: -1,
406
+ stdout: "",
407
+ stderr: "",
408
+ durationMs: Date.now() - startedAt,
409
+ error: err instanceof Error ? err.message : String(err)
410
+ };
411
+ } finally {
412
+ if (sandbox) {
413
+ try {
414
+ await sandbox.stop();
415
+ } catch {}
416
+ }
417
+ }
418
+ }
419
+
420
+ // ../utils/env.ts
421
+ function getEnv(key) {
422
+ try {
423
+ const getImportMeta = new Function('return typeof import.meta !== "undefined" ? import.meta : undefined');
424
+ const importMeta = getImportMeta();
425
+ if (importMeta && typeof importMeta.env === "object" && importMeta.env !== null) {
426
+ const value = importMeta.env[key];
427
+ if (value !== undefined && value !== null && value !== "") {
428
+ return String(value);
429
+ }
430
+ }
431
+ } catch {}
432
+ if (typeof process !== "undefined" && process.env) {
433
+ const value = process.env[key];
434
+ if (value !== undefined && value !== null && value !== "") {
435
+ return value;
436
+ }
437
+ }
438
+ return;
439
+ }
440
+
441
+ // tool-builder.ts
442
+ var CODE_MODE_TOOL_NAME = "execute_code";
443
+ var DEFAULT_INSTRUCTIONS = [
444
+ "You are given a single tool: `execute_code`. Instead of calling individual MCP tools,",
445
+ "you write a short async TypeScript/JavaScript snippet that uses the typed `client`",
446
+ "object below, and the snippet runs in an isolated sandbox which dispatches the actual",
447
+ "tool calls. Chain multiple operations together in one snippet whenever possible —",
448
+ "that is the whole point of this tool.",
449
+ "",
450
+ "Rules:",
451
+ "- The snippet is the body of an `async` function. Use `await` freely.",
452
+ "- Use `return <value>` at the end to hand a structured result back to the caller;",
453
+ " the caller receives it as JSON.",
454
+ "- Use `console.log(...)` for intermediate observations you want to read later.",
455
+ "- Throw / let errors propagate; the runtime will surface them with a non-zero exit.",
456
+ "- Each method call returns an object of shape `ToolResult` (see types below).",
457
+ " The payload usually lives in `result.content[0].text` as JSON — parse it if needed.",
458
+ "- You cannot import npm packages. Only the pre-imported `client` and standard",
459
+ " globals (`fetch`, `console`, `JSON`, ...) are available.",
460
+ "",
461
+ "API surface:"
462
+ ].join(`
463
+ `);
464
+ function resolveCodeModeClientConfig(client) {
465
+ const oauthConfig = client.__oauthConfig;
466
+ return oauthConfig?.codeMode ?? {};
467
+ }
468
+ function buildCodeModeTool(client, options) {
469
+ const { tools, providerTokens, context, integrationIds } = options;
470
+ const generated = generateCodeModeTypes(tools);
471
+ const serverCodeModeConfig = resolveCodeModeClientConfig(client);
472
+ const sandboxOverrides = options.sandbox ?? {};
473
+ const description = `${DEFAULT_INSTRUCTIONS}
474
+
475
+ \`\`\`typescript
476
+ ${generated.source}
477
+ \`\`\``;
478
+ const execute = async ({ code }) => {
479
+ const publicUrl = sandboxOverrides.publicUrl ?? serverCodeModeConfig.publicUrl ?? getEnv("INTEGRATE_PUBLIC_URL");
480
+ if (!publicUrl) {
481
+ return {
482
+ success: false,
483
+ exitCode: -1,
484
+ stdout: "",
485
+ stderr: "",
486
+ durationMs: 0,
487
+ error: "Code Mode requires `codeMode.publicUrl` in createMCPServer config (or the INTEGRATE_PUBLIC_URL env var). " + "The sandbox uses it to call back into /api/integrate/mcp."
488
+ };
489
+ }
490
+ const mcpUrl = publicUrl.replace(/\/$/, "") + "/api/integrate/mcp";
491
+ return executeSandboxCode({
492
+ code,
493
+ mcpUrl,
494
+ providerTokens,
495
+ context,
496
+ integrationsHeader: integrationIds && integrationIds.length > 0 ? integrationIds.join(",") : undefined,
497
+ runtime: sandboxOverrides.runtime ?? serverCodeModeConfig.runtime,
498
+ timeoutMs: sandboxOverrides.timeoutMs ?? serverCodeModeConfig.timeoutMs,
499
+ vcpus: sandboxOverrides.vcpus ?? serverCodeModeConfig.vcpus,
500
+ networkPolicy: sandboxOverrides.networkPolicy ?? serverCodeModeConfig.networkPolicy
501
+ });
502
+ };
503
+ return {
504
+ name: CODE_MODE_TOOL_NAME,
505
+ description,
506
+ parameters: {
507
+ type: "object",
508
+ properties: {
509
+ code: {
510
+ type: "string",
511
+ description: "The TypeScript/JavaScript snippet to execute. It is wrapped in an async IIFE, so you may use top-level await and return a final value."
512
+ }
513
+ },
514
+ required: ["code"],
515
+ additionalProperties: false
516
+ },
517
+ execute
518
+ };
519
+ }
520
+ export {
521
+ resolveCodeModeClientConfig,
522
+ buildCodeModeTool,
523
+ CODE_MODE_TOOL_NAME
524
+ };
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Code Mode: TypeScript type generator
3
+ *
4
+ * Converts enabled MCPTool definitions into a TypeScript API surface
5
+ * (`.d.ts`-style string) grouped by integration namespace. The output is
6
+ * embedded in the `execute_code` tool description so the LLM can write
7
+ * code against a typed `client.<integration>.<method>(...)` API.
8
+ */
9
+ import type { MCPTool } from "../protocol/messages.js";
10
+ export interface GeneratedTypes {
11
+ /** The full TypeScript source to embed in the LLM prompt. */
12
+ source: string;
13
+ /** Map from dotted method path (e.g. `github.createIssue`) to MCP tool name. */
14
+ methodMap: Record<string, string>;
15
+ /** Per-integration tool counts, useful for logging. */
16
+ integrationCounts: Record<string, number>;
17
+ }
18
+ /**
19
+ * Build the TypeScript API surface from a set of enabled MCP tools.
20
+ */
21
+ export declare function generateCodeModeTypes(tools: MCPTool[]): GeneratedTypes;
22
+ //# sourceMappingURL=type-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"type-generator.d.ts","sourceRoot":"","sources":["../../../src/code-mode/type-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAmB,MAAM,yBAAyB,CAAC;AAGxE,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,uDAAuD;IACvD,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC3C;AAgHD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,cAAc,CA6DtE"}