@tanstack/ai-code-mode 0.3.0 → 0.3.1
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/dist/esm/agent-store.d.ts +21 -0
- package/dist/esm/agent-store.js +29 -0
- package/dist/esm/agent-store.js.map +1 -0
- package/dist/esm/bindings/tool-to-binding.d.ts +25 -0
- package/dist/esm/bindings/tool-to-binding.js +94 -0
- package/dist/esm/bindings/tool-to-binding.js.map +1 -0
- package/dist/esm/code-wrapper.d.ts +9 -0
- package/dist/esm/code-wrapper.js +18 -0
- package/dist/esm/code-wrapper.js.map +1 -0
- package/dist/esm/create-code-mode-tool.d.ts +50 -0
- package/dist/esm/create-code-mode-tool.js +146 -0
- package/dist/esm/create-code-mode-tool.js.map +1 -0
- package/dist/esm/create-code-mode.d.ts +23 -0
- package/dist/esm/create-code-mode.js +19 -0
- package/dist/esm/create-code-mode.js.map +1 -0
- package/dist/esm/create-discovery-tool.d.ts +28 -0
- package/dist/esm/create-discovery-tool.js +62 -0
- package/dist/esm/create-discovery-tool.js.map +1 -0
- package/dist/esm/create-system-prompt.d.ts +24 -0
- package/dist/esm/create-system-prompt.js +76 -0
- package/dist/esm/create-system-prompt.js.map +1 -0
- package/dist/esm/index.d.ts +11 -0
- package/dist/esm/index.js +25 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/strip-typescript.d.ts +44 -0
- package/dist/esm/strip-typescript.js +49 -0
- package/dist/esm/strip-typescript.js.map +1 -0
- package/dist/esm/type-generator/json-schema-to-ts.d.ts +31 -0
- package/dist/esm/type-generator/json-schema-to-ts.js +100 -0
- package/dist/esm/type-generator/json-schema-to-ts.js.map +1 -0
- package/dist/esm/types.d.ts +238 -0
- package/package.json +3 -3
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface AgentSession {
|
|
2
|
+
name: string;
|
|
3
|
+
systemPrompt: string;
|
|
4
|
+
memory: Record<string, unknown>;
|
|
5
|
+
createdAt: number;
|
|
6
|
+
lastUsedAt: number;
|
|
7
|
+
}
|
|
8
|
+
export interface AgentStore {
|
|
9
|
+
get: (name: string) => Promise<AgentSession | null>;
|
|
10
|
+
set: (name: string, session: AgentSession) => Promise<void>;
|
|
11
|
+
delete: (name: string) => Promise<void>;
|
|
12
|
+
list: () => Promise<Array<string>>;
|
|
13
|
+
}
|
|
14
|
+
export declare class InMemoryAgentStore implements AgentStore {
|
|
15
|
+
private readonly sessions;
|
|
16
|
+
get(name: string): Promise<AgentSession | null>;
|
|
17
|
+
set(name: string, session: AgentSession): Promise<void>;
|
|
18
|
+
delete(name: string): Promise<void>;
|
|
19
|
+
list(): Promise<Array<string>>;
|
|
20
|
+
}
|
|
21
|
+
export declare function generateAgentName(): string;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
class InMemoryAgentStore {
|
|
2
|
+
sessions = /* @__PURE__ */ new Map();
|
|
3
|
+
get(name) {
|
|
4
|
+
return Promise.resolve(this.sessions.get(name) ?? null);
|
|
5
|
+
}
|
|
6
|
+
set(name, session) {
|
|
7
|
+
this.sessions.set(name, session);
|
|
8
|
+
return Promise.resolve();
|
|
9
|
+
}
|
|
10
|
+
delete(name) {
|
|
11
|
+
this.sessions.delete(name);
|
|
12
|
+
return Promise.resolve();
|
|
13
|
+
}
|
|
14
|
+
list() {
|
|
15
|
+
return Promise.resolve(Array.from(this.sessions.keys()));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function generateAgentName() {
|
|
19
|
+
const hex = Array.from(
|
|
20
|
+
{ length: 8 },
|
|
21
|
+
() => Math.floor(Math.random() * 16).toString(16)
|
|
22
|
+
).join("");
|
|
23
|
+
return `agent_${hex}`;
|
|
24
|
+
}
|
|
25
|
+
export {
|
|
26
|
+
InMemoryAgentStore,
|
|
27
|
+
generateAgentName
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=agent-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-store.js","sources":["../../src/agent-store.ts"],"sourcesContent":["export interface AgentSession {\n name: string\n systemPrompt: string\n memory: Record<string, unknown>\n createdAt: number\n lastUsedAt: number\n}\n\nexport interface AgentStore {\n get: (name: string) => Promise<AgentSession | null>\n set: (name: string, session: AgentSession) => Promise<void>\n delete: (name: string) => Promise<void>\n list: () => Promise<Array<string>>\n}\n\nexport class InMemoryAgentStore implements AgentStore {\n private readonly sessions = new Map<string, AgentSession>()\n\n get(name: string): Promise<AgentSession | null> {\n return Promise.resolve(this.sessions.get(name) ?? null)\n }\n\n set(name: string, session: AgentSession): Promise<void> {\n this.sessions.set(name, session)\n return Promise.resolve()\n }\n\n delete(name: string): Promise<void> {\n this.sessions.delete(name)\n return Promise.resolve()\n }\n\n list(): Promise<Array<string>> {\n return Promise.resolve(Array.from(this.sessions.keys()))\n }\n}\n\nexport function generateAgentName(): string {\n const hex = Array.from({ length: 8 }, () =>\n Math.floor(Math.random() * 16).toString(16),\n ).join('')\n return `agent_${hex}`\n}\n"],"names":[],"mappings":"AAeO,MAAM,mBAAyC;AAAA,EACnC,+BAAe,IAAA;AAAA,EAEhC,IAAI,MAA4C;AAC9C,WAAO,QAAQ,QAAQ,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI;AAAA,EACxD;AAAA,EAEA,IAAI,MAAc,SAAsC;AACtD,SAAK,SAAS,IAAI,MAAM,OAAO;AAC/B,WAAO,QAAQ,QAAA;AAAA,EACjB;AAAA,EAEA,OAAO,MAA6B;AAClC,SAAK,SAAS,OAAO,IAAI;AACzB,WAAO,QAAQ,QAAA;AAAA,EACjB;AAAA,EAEA,OAA+B;AAC7B,WAAO,QAAQ,QAAQ,MAAM,KAAK,KAAK,SAAS,KAAA,CAAM,CAAC;AAAA,EACzD;AACF;AAEO,SAAS,oBAA4B;AAC1C,QAAM,MAAM,MAAM;AAAA,IAAK,EAAE,QAAQ,EAAA;AAAA,IAAK,MACpC,KAAK,MAAM,KAAK,WAAW,EAAE,EAAE,SAAS,EAAE;AAAA,EAAA,EAC1C,KAAK,EAAE;AACT,SAAO,SAAS,GAAG;AACrB;"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ToolExecutionContext } from '@tanstack/ai';
|
|
2
|
+
import { CodeModeTool, ToolBinding } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Convert an array of TanStack AI tools to a Record of ToolBindings
|
|
5
|
+
*
|
|
6
|
+
* @param tools - Array of tools to convert
|
|
7
|
+
* @param prefix - Optional prefix to add to binding names (e.g., 'external_')
|
|
8
|
+
*/
|
|
9
|
+
export declare function toolsToBindings(tools: Array<CodeModeTool>, prefix?: string): Record<string, ToolBinding>;
|
|
10
|
+
/**
|
|
11
|
+
* Convert a single TanStack AI tool to a ToolBinding
|
|
12
|
+
*
|
|
13
|
+
* @param tool - Tool to convert
|
|
14
|
+
* @param prefix - Optional prefix to add to binding name (e.g., 'external_')
|
|
15
|
+
* @throws Error if the tool doesn't have an execute function
|
|
16
|
+
*/
|
|
17
|
+
export declare function toolToBinding(tool: CodeModeTool, prefix?: string): ToolBinding;
|
|
18
|
+
/**
|
|
19
|
+
* Create event-aware bindings that emit custom events for each external function call.
|
|
20
|
+
* Wraps each binding's execute function to emit events before and after execution.
|
|
21
|
+
*
|
|
22
|
+
* @param bindings - Original tool bindings
|
|
23
|
+
* @param emitCustomEvent - Callback to emit custom events to the stream
|
|
24
|
+
*/
|
|
25
|
+
export declare function createEventAwareBindings(bindings: Record<string, ToolBinding>, emitCustomEvent: ToolExecutionContext['emitCustomEvent']): Record<string, ToolBinding>;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { convertSchemaToJsonSchema, isStandardSchema, parseWithStandardSchema } from "@tanstack/ai";
|
|
2
|
+
function toolsToBindings(tools, prefix = "") {
|
|
3
|
+
const bindings = {};
|
|
4
|
+
for (const tool of tools) {
|
|
5
|
+
const bindingName = `${prefix}${tool.name}`;
|
|
6
|
+
bindings[bindingName] = toolToBinding(tool, prefix);
|
|
7
|
+
}
|
|
8
|
+
return bindings;
|
|
9
|
+
}
|
|
10
|
+
function toolToBinding(tool, prefix = "") {
|
|
11
|
+
const inputSchema = convertSchemaToJsonSchema(tool.inputSchema) || {
|
|
12
|
+
type: "object",
|
|
13
|
+
properties: {}
|
|
14
|
+
};
|
|
15
|
+
const outputSchema = tool.outputSchema ? convertSchemaToJsonSchema(tool.outputSchema) : void 0;
|
|
16
|
+
if (typeof tool.execute !== "function") {
|
|
17
|
+
throw new Error(
|
|
18
|
+
`Tool "${tool.name}" does not have an execute function. Code Mode requires server tools with implementations.`
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
const toolExecute = tool.execute;
|
|
22
|
+
const execute = async (args, context) => {
|
|
23
|
+
let input = args;
|
|
24
|
+
if (tool.inputSchema && isStandardSchema(tool.inputSchema)) {
|
|
25
|
+
try {
|
|
26
|
+
input = parseWithStandardSchema(tool.inputSchema, args);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
const message = error instanceof Error ? error.message : "Validation failed";
|
|
29
|
+
throw new Error(
|
|
30
|
+
`Input validation failed for tool ${tool.name}: ${message}`
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
let result = await Promise.resolve(toolExecute(input, context));
|
|
35
|
+
if (tool.outputSchema && isStandardSchema(tool.outputSchema)) {
|
|
36
|
+
try {
|
|
37
|
+
result = parseWithStandardSchema(tool.outputSchema, result);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
const message = error instanceof Error ? error.message : "Validation failed";
|
|
40
|
+
throw new Error(
|
|
41
|
+
`Output validation failed for tool ${tool.name}: ${message}`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return result;
|
|
46
|
+
};
|
|
47
|
+
return {
|
|
48
|
+
name: `${prefix}${tool.name}`,
|
|
49
|
+
description: tool.description,
|
|
50
|
+
inputSchema,
|
|
51
|
+
outputSchema,
|
|
52
|
+
execute
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function createEventAwareBindings(bindings, emitCustomEvent) {
|
|
56
|
+
const wrapped = {};
|
|
57
|
+
for (const [name, binding] of Object.entries(bindings)) {
|
|
58
|
+
wrapped[name] = {
|
|
59
|
+
...binding,
|
|
60
|
+
execute: async (args) => {
|
|
61
|
+
emitCustomEvent("code_mode:external_call", {
|
|
62
|
+
function: name,
|
|
63
|
+
args,
|
|
64
|
+
timestamp: Date.now()
|
|
65
|
+
});
|
|
66
|
+
const startTime = Date.now();
|
|
67
|
+
try {
|
|
68
|
+
const toolContext = { emitCustomEvent };
|
|
69
|
+
const result = await binding.execute(args, toolContext);
|
|
70
|
+
emitCustomEvent("code_mode:external_result", {
|
|
71
|
+
function: name,
|
|
72
|
+
result,
|
|
73
|
+
duration: Date.now() - startTime
|
|
74
|
+
});
|
|
75
|
+
return result;
|
|
76
|
+
} catch (error) {
|
|
77
|
+
emitCustomEvent("code_mode:external_error", {
|
|
78
|
+
function: name,
|
|
79
|
+
error: error instanceof Error ? error.message : String(error),
|
|
80
|
+
duration: Date.now() - startTime
|
|
81
|
+
});
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
return wrapped;
|
|
88
|
+
}
|
|
89
|
+
export {
|
|
90
|
+
createEventAwareBindings,
|
|
91
|
+
toolToBinding,
|
|
92
|
+
toolsToBindings
|
|
93
|
+
};
|
|
94
|
+
//# sourceMappingURL=tool-to-binding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-to-binding.js","sources":["../../../src/bindings/tool-to-binding.ts"],"sourcesContent":["import {\n convertSchemaToJsonSchema,\n isStandardSchema,\n parseWithStandardSchema,\n} from '@tanstack/ai'\nimport type { ToolExecutionContext } from '@tanstack/ai'\nimport type { CodeModeTool, ToolBinding } from '../types'\n\n/**\n * Convert an array of TanStack AI tools to a Record of ToolBindings\n *\n * @param tools - Array of tools to convert\n * @param prefix - Optional prefix to add to binding names (e.g., 'external_')\n */\nexport function toolsToBindings(\n tools: Array<CodeModeTool>,\n prefix: string = '',\n): Record<string, ToolBinding> {\n const bindings: Record<string, ToolBinding> = {}\n\n for (const tool of tools) {\n const bindingName = `${prefix}${tool.name}`\n bindings[bindingName] = toolToBinding(tool, prefix)\n }\n\n return bindings\n}\n\n/**\n * Convert a single TanStack AI tool to a ToolBinding\n *\n * @param tool - Tool to convert\n * @param prefix - Optional prefix to add to binding name (e.g., 'external_')\n * @throws Error if the tool doesn't have an execute function\n */\nexport function toolToBinding(\n tool: CodeModeTool,\n prefix: string = '',\n): ToolBinding {\n // Convert schemas (Zod or Standard Schema) to JSON Schema\n const inputSchema = convertSchemaToJsonSchema(tool.inputSchema) || {\n type: 'object',\n properties: {},\n }\n\n const outputSchema = tool.outputSchema\n ? convertSchemaToJsonSchema(tool.outputSchema)\n : undefined\n\n if (typeof tool.execute !== 'function') {\n throw new Error(\n `Tool \"${tool.name}\" does not have an execute function. ` +\n `Code Mode requires server tools with implementations.`,\n )\n }\n\n const toolExecute = tool.execute\n const execute = async (args: unknown, context?: ToolExecutionContext) => {\n let input = args\n if (tool.inputSchema && isStandardSchema(tool.inputSchema)) {\n try {\n input = parseWithStandardSchema(tool.inputSchema, args)\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Validation failed'\n throw new Error(\n `Input validation failed for tool ${tool.name}: ${message}`,\n )\n }\n }\n\n let result = await Promise.resolve(toolExecute(input, context))\n\n if (tool.outputSchema && isStandardSchema(tool.outputSchema)) {\n try {\n result = parseWithStandardSchema(tool.outputSchema, result)\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Validation failed'\n throw new Error(\n `Output validation failed for tool ${tool.name}: ${message}`,\n )\n }\n }\n\n return result\n }\n\n return {\n name: `${prefix}${tool.name}`,\n description: tool.description,\n inputSchema,\n outputSchema,\n execute,\n }\n}\n\n/**\n * Create event-aware bindings that emit custom events for each external function call.\n * Wraps each binding's execute function to emit events before and after execution.\n *\n * @param bindings - Original tool bindings\n * @param emitCustomEvent - Callback to emit custom events to the stream\n */\nexport function createEventAwareBindings(\n bindings: Record<string, ToolBinding>,\n emitCustomEvent: ToolExecutionContext['emitCustomEvent'],\n): Record<string, ToolBinding> {\n const wrapped: Record<string, ToolBinding> = {}\n\n for (const [name, binding] of Object.entries(bindings)) {\n wrapped[name] = {\n ...binding,\n execute: async (args: unknown) => {\n // Emit call event\n emitCustomEvent('code_mode:external_call', {\n function: name,\n args,\n timestamp: Date.now(),\n })\n\n const startTime = Date.now()\n try {\n // Create context for the underlying tool so it can also emit events\n const toolContext: ToolExecutionContext = { emitCustomEvent }\n const result = await binding.execute(args, toolContext)\n\n // Emit result event\n emitCustomEvent('code_mode:external_result', {\n function: name,\n result,\n duration: Date.now() - startTime,\n })\n\n return result\n } catch (error) {\n // Emit error event\n emitCustomEvent('code_mode:external_error', {\n function: name,\n error: error instanceof Error ? error.message : String(error),\n duration: Date.now() - startTime,\n })\n throw error\n }\n },\n }\n }\n\n return wrapped\n}\n"],"names":[],"mappings":";AAcO,SAAS,gBACd,OACA,SAAiB,IACY;AAC7B,QAAM,WAAwC,CAAA;AAE9C,aAAW,QAAQ,OAAO;AACxB,UAAM,cAAc,GAAG,MAAM,GAAG,KAAK,IAAI;AACzC,aAAS,WAAW,IAAI,cAAc,MAAM,MAAM;AAAA,EACpD;AAEA,SAAO;AACT;AASO,SAAS,cACd,MACA,SAAiB,IACJ;AAEb,QAAM,cAAc,0BAA0B,KAAK,WAAW,KAAK;AAAA,IACjE,MAAM;AAAA,IACN,YAAY,CAAA;AAAA,EAAC;AAGf,QAAM,eAAe,KAAK,eACtB,0BAA0B,KAAK,YAAY,IAC3C;AAEJ,MAAI,OAAO,KAAK,YAAY,YAAY;AACtC,UAAM,IAAI;AAAA,MACR,SAAS,KAAK,IAAI;AAAA,IAAA;AAAA,EAGtB;AAEA,QAAM,cAAc,KAAK;AACzB,QAAM,UAAU,OAAO,MAAe,YAAmC;AACvE,QAAI,QAAQ;AACZ,QAAI,KAAK,eAAe,iBAAiB,KAAK,WAAW,GAAG;AAC1D,UAAI;AACF,gBAAQ,wBAAwB,KAAK,aAAa,IAAI;AAAA,MACxD,SAAS,OAAO;AACd,cAAM,UACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,cAAM,IAAI;AAAA,UACR,oCAAoC,KAAK,IAAI,KAAK,OAAO;AAAA,QAAA;AAAA,MAE7D;AAAA,IACF;AAEA,QAAI,SAAS,MAAM,QAAQ,QAAQ,YAAY,OAAO,OAAO,CAAC;AAE9D,QAAI,KAAK,gBAAgB,iBAAiB,KAAK,YAAY,GAAG;AAC5D,UAAI;AACF,iBAAS,wBAAwB,KAAK,cAAc,MAAM;AAAA,MAC5D,SAAS,OAAO;AACd,cAAM,UACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,cAAM,IAAI;AAAA,UACR,qCAAqC,KAAK,IAAI,KAAK,OAAO;AAAA,QAAA;AAAA,MAE9D;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,MAAM,GAAG,MAAM,GAAG,KAAK,IAAI;AAAA,IAC3B,aAAa,KAAK;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;AASO,SAAS,yBACd,UACA,iBAC6B;AAC7B,QAAM,UAAuC,CAAA;AAE7C,aAAW,CAAC,MAAM,OAAO,KAAK,OAAO,QAAQ,QAAQ,GAAG;AACtD,YAAQ,IAAI,IAAI;AAAA,MACd,GAAG;AAAA,MACH,SAAS,OAAO,SAAkB;AAEhC,wBAAgB,2BAA2B;AAAA,UACzC,UAAU;AAAA,UACV;AAAA,UACA,WAAW,KAAK,IAAA;AAAA,QAAI,CACrB;AAED,cAAM,YAAY,KAAK,IAAA;AACvB,YAAI;AAEF,gBAAM,cAAoC,EAAE,gBAAA;AAC5C,gBAAM,SAAS,MAAM,QAAQ,QAAQ,MAAM,WAAW;AAGtD,0BAAgB,6BAA6B;AAAA,YAC3C,UAAU;AAAA,YACV;AAAA,YACA,UAAU,KAAK,QAAQ;AAAA,UAAA,CACxB;AAED,iBAAO;AAAA,QACT,SAAS,OAAO;AAEd,0BAAgB,4BAA4B;AAAA,YAC1C,UAAU;AAAA,YACV,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,YAC5D,UAAU,KAAK,QAAQ;AAAA,UAAA,CACxB;AACD,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,IAAA;AAAA,EAEJ;AAEA,SAAO;AACT;"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wrap user code in an async IIFE to support top-level await
|
|
3
|
+
*
|
|
4
|
+
* The code is wrapped so that:
|
|
5
|
+
* 1. Top-level await works
|
|
6
|
+
* 2. Return values are captured and serialized (for isolate boundary transfer)
|
|
7
|
+
* 3. Errors propagate correctly
|
|
8
|
+
*/
|
|
9
|
+
export declare function wrapCode(code: string): string;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
function wrapCode(code) {
|
|
2
|
+
return `
|
|
3
|
+
(async function() {
|
|
4
|
+
try {
|
|
5
|
+
const __userResult = await (async function() {
|
|
6
|
+
${code}
|
|
7
|
+
})();
|
|
8
|
+
return JSON.stringify(__userResult);
|
|
9
|
+
} catch (__error) {
|
|
10
|
+
throw __error;
|
|
11
|
+
}
|
|
12
|
+
})()
|
|
13
|
+
`;
|
|
14
|
+
}
|
|
15
|
+
export {
|
|
16
|
+
wrapCode
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=code-wrapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-wrapper.js","sources":["../../src/code-wrapper.ts"],"sourcesContent":["/**\n * Wrap user code in an async IIFE to support top-level await\n *\n * The code is wrapped so that:\n * 1. Top-level await works\n * 2. Return values are captured and serialized (for isolate boundary transfer)\n * 3. Errors propagate correctly\n */\nexport function wrapCode(code: string): string {\n // Results must be serialized to JSON because objects can't be transferred\n // directly across the isolate boundary in isolated-vm\n return `\n(async function() {\n try {\n const __userResult = await (async function() {\n${code}\n })();\n return JSON.stringify(__userResult);\n } catch (__error) {\n throw __error;\n }\n})()\n`\n}\n"],"names":[],"mappings":"AAQO,SAAS,SAAS,MAAsB;AAG7C,SAAO;AAAA;AAAA;AAAA;AAAA,EAIP,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQN;"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ServerTool } from '@tanstack/ai';
|
|
3
|
+
import { CodeModeToolConfig } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Schema for the execute_typescript tool input
|
|
6
|
+
*/
|
|
7
|
+
declare const executeTypescriptInputSchema: z.ZodObject<{
|
|
8
|
+
typescriptCode: z.ZodString;
|
|
9
|
+
}, z.core.$strip>;
|
|
10
|
+
/**
|
|
11
|
+
* Schema for the execute_typescript tool output
|
|
12
|
+
*/
|
|
13
|
+
declare const executeTypescriptOutputSchema: z.ZodObject<{
|
|
14
|
+
success: z.ZodBoolean;
|
|
15
|
+
result: z.ZodOptional<z.ZodUnknown>;
|
|
16
|
+
logs: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
17
|
+
error: z.ZodOptional<z.ZodObject<{
|
|
18
|
+
message: z.ZodString;
|
|
19
|
+
name: z.ZodOptional<z.ZodString>;
|
|
20
|
+
line: z.ZodOptional<z.ZodNumber>;
|
|
21
|
+
}, z.core.$strip>>;
|
|
22
|
+
}, z.core.$strip>;
|
|
23
|
+
export type ExecuteTypescriptInput = z.infer<typeof executeTypescriptInputSchema>;
|
|
24
|
+
export type ExecuteTypescriptOutput = z.infer<typeof executeTypescriptOutputSchema>;
|
|
25
|
+
/**
|
|
26
|
+
* Create an execute_typescript tool that can be used alongside other agent tools.
|
|
27
|
+
*
|
|
28
|
+
* This tool allows an LLM to execute TypeScript code in a secure sandbox.
|
|
29
|
+
* Tools passed in the config become `external_*` functions available inside the sandbox.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* import { createCodeMode } from '@tanstack/ai-code-mode'
|
|
34
|
+
* import { createNodeIsolateDriver } from '@tanstack/ai-isolate-node'
|
|
35
|
+
*
|
|
36
|
+
* const { tool, systemPrompt } = createCodeMode({
|
|
37
|
+
* driver: createNodeIsolateDriver(),
|
|
38
|
+
* tools: [weatherTool, dbTool], // Become external_fetchWeather, external_dbQuery
|
|
39
|
+
* timeout: 30000,
|
|
40
|
+
* })
|
|
41
|
+
*
|
|
42
|
+
* chat({
|
|
43
|
+
* systemPrompts: [myPrompt, systemPrompt],
|
|
44
|
+
* tools: [tool, searchTool, emailTool],
|
|
45
|
+
* messages,
|
|
46
|
+
* })
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare function createCodeModeTool(config: CodeModeToolConfig): ServerTool<typeof executeTypescriptInputSchema, typeof executeTypescriptOutputSchema, 'execute_typescript'>;
|
|
50
|
+
export {};
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { toolDefinition } from "@tanstack/ai";
|
|
3
|
+
import { toolsToBindings, createEventAwareBindings } from "./bindings/tool-to-binding.js";
|
|
4
|
+
import { stripTypeScript } from "./strip-typescript.js";
|
|
5
|
+
const executeTypescriptInputSchema = z.object({
|
|
6
|
+
typescriptCode: z.string().describe(
|
|
7
|
+
"TypeScript code to execute in the sandbox. Use external_* functions to call available APIs. Return a value to pass results back."
|
|
8
|
+
)
|
|
9
|
+
});
|
|
10
|
+
const executeTypescriptOutputSchema = z.object({
|
|
11
|
+
success: z.boolean().describe("Whether execution completed without errors"),
|
|
12
|
+
result: z.unknown().optional().describe("Return value from the executed code"),
|
|
13
|
+
logs: z.array(z.string()).optional().describe("Console output captured during execution"),
|
|
14
|
+
error: z.object({
|
|
15
|
+
message: z.string(),
|
|
16
|
+
name: z.string().optional(),
|
|
17
|
+
line: z.number().optional()
|
|
18
|
+
}).optional().describe("Error details if execution failed")
|
|
19
|
+
});
|
|
20
|
+
function createCodeModeTool(config) {
|
|
21
|
+
const {
|
|
22
|
+
driver,
|
|
23
|
+
tools,
|
|
24
|
+
timeout = 3e4,
|
|
25
|
+
memoryLimit = 128,
|
|
26
|
+
getSkillBindings,
|
|
27
|
+
transpile = stripTypeScript
|
|
28
|
+
} = config;
|
|
29
|
+
if (tools.length === 0) {
|
|
30
|
+
throw new Error("At least one tool must be provided to createCodeModeTool");
|
|
31
|
+
}
|
|
32
|
+
const staticBindings = toolsToBindings(tools, "external_");
|
|
33
|
+
const definition = toolDefinition({
|
|
34
|
+
name: "execute_typescript",
|
|
35
|
+
description: buildToolDescription(tools),
|
|
36
|
+
inputSchema: executeTypescriptInputSchema,
|
|
37
|
+
outputSchema: executeTypescriptOutputSchema
|
|
38
|
+
});
|
|
39
|
+
return definition.server(
|
|
40
|
+
async (input, toolContext) => {
|
|
41
|
+
const { typescriptCode } = input;
|
|
42
|
+
const emitCustomEvent = toolContext?.emitCustomEvent || (() => {
|
|
43
|
+
});
|
|
44
|
+
if (!typescriptCode || typeof typescriptCode !== "string") {
|
|
45
|
+
return {
|
|
46
|
+
success: false,
|
|
47
|
+
error: {
|
|
48
|
+
message: "typescriptCode must be a non-empty string",
|
|
49
|
+
name: "ValidationError"
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
let isolateContext = null;
|
|
54
|
+
emitCustomEvent("code_mode:execution_started", {
|
|
55
|
+
timestamp: Date.now(),
|
|
56
|
+
codeLength: typescriptCode.length
|
|
57
|
+
});
|
|
58
|
+
try {
|
|
59
|
+
let strippedCode;
|
|
60
|
+
try {
|
|
61
|
+
strippedCode = await transpile(typescriptCode);
|
|
62
|
+
} catch (error) {
|
|
63
|
+
return {
|
|
64
|
+
success: false,
|
|
65
|
+
error: {
|
|
66
|
+
message: error instanceof Error ? error.message : String(error),
|
|
67
|
+
name: "TypeScriptError"
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const skillBindings = getSkillBindings ? await getSkillBindings() : {};
|
|
72
|
+
const allBindings = { ...staticBindings, ...skillBindings };
|
|
73
|
+
const eventAwareBindings = createEventAwareBindings(
|
|
74
|
+
allBindings,
|
|
75
|
+
emitCustomEvent
|
|
76
|
+
);
|
|
77
|
+
isolateContext = await driver.createContext({
|
|
78
|
+
bindings: eventAwareBindings,
|
|
79
|
+
timeout,
|
|
80
|
+
memoryLimit
|
|
81
|
+
});
|
|
82
|
+
const executionResult = await isolateContext.execute(strippedCode);
|
|
83
|
+
if (executionResult.logs && executionResult.logs.length > 0) {
|
|
84
|
+
for (const log of executionResult.logs) {
|
|
85
|
+
let level = "log";
|
|
86
|
+
let message = log;
|
|
87
|
+
if (log.startsWith("ERROR: ")) {
|
|
88
|
+
level = "error";
|
|
89
|
+
message = log.slice(7);
|
|
90
|
+
} else if (log.startsWith("WARN: ")) {
|
|
91
|
+
level = "warn";
|
|
92
|
+
message = log.slice(6);
|
|
93
|
+
} else if (log.startsWith("INFO: ")) {
|
|
94
|
+
level = "info";
|
|
95
|
+
message = log.slice(6);
|
|
96
|
+
}
|
|
97
|
+
emitCustomEvent("code_mode:console", {
|
|
98
|
+
level,
|
|
99
|
+
message,
|
|
100
|
+
timestamp: Date.now()
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (executionResult.success) {
|
|
105
|
+
return {
|
|
106
|
+
success: true,
|
|
107
|
+
result: executionResult.value,
|
|
108
|
+
logs: executionResult.logs
|
|
109
|
+
};
|
|
110
|
+
} else {
|
|
111
|
+
return {
|
|
112
|
+
success: false,
|
|
113
|
+
error: executionResult.error ? {
|
|
114
|
+
message: executionResult.error.message,
|
|
115
|
+
name: executionResult.error.name
|
|
116
|
+
} : { message: "Unknown execution error" },
|
|
117
|
+
logs: executionResult.logs
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
} catch (error) {
|
|
121
|
+
return {
|
|
122
|
+
success: false,
|
|
123
|
+
error: {
|
|
124
|
+
message: error instanceof Error ? error.message : String(error),
|
|
125
|
+
name: error instanceof Error ? error.name : "Error"
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
} finally {
|
|
129
|
+
if (isolateContext) {
|
|
130
|
+
await isolateContext.dispose();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
function buildToolDescription(tools) {
|
|
137
|
+
const eager = tools.filter((t) => !t.lazy);
|
|
138
|
+
const hasLazy = tools.some((t) => t.lazy);
|
|
139
|
+
const externalFunctions = eager.map((t) => `external_${t.name}`).join(", ");
|
|
140
|
+
const discoverable = hasLazy ? ` Additional functions can be discovered via the discover_tools tool.` : "";
|
|
141
|
+
return `Execute TypeScript code in a secure sandbox environment. The code can use these external API functions: ${externalFunctions}.${discoverable} All external_* calls are async and must be awaited. Return a value to pass results back. Use console.log() for debugging.`;
|
|
142
|
+
}
|
|
143
|
+
export {
|
|
144
|
+
createCodeModeTool
|
|
145
|
+
};
|
|
146
|
+
//# sourceMappingURL=create-code-mode-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-code-mode-tool.js","sources":["../../src/create-code-mode-tool.ts"],"sourcesContent":["import { z } from 'zod'\nimport { toolDefinition } from '@tanstack/ai'\nimport {\n createEventAwareBindings,\n toolsToBindings,\n} from './bindings/tool-to-binding'\nimport { stripTypeScript } from './strip-typescript'\nimport type { ServerTool, ToolExecutionContext } from '@tanstack/ai'\nimport type {\n CodeModeTool,\n CodeModeToolConfig,\n CodeModeToolResult,\n IsolateContext,\n} from './types'\n\n/**\n * Schema for the execute_typescript tool input\n */\nconst executeTypescriptInputSchema = z.object({\n typescriptCode: z\n .string()\n .describe(\n 'TypeScript code to execute in the sandbox. ' +\n 'Use external_* functions to call available APIs. ' +\n 'Return a value to pass results back.',\n ),\n})\n\n/**\n * Schema for the execute_typescript tool output\n */\nconst executeTypescriptOutputSchema = z.object({\n success: z.boolean().describe('Whether execution completed without errors'),\n result: z\n .unknown()\n .optional()\n .describe('Return value from the executed code'),\n logs: z\n .array(z.string())\n .optional()\n .describe('Console output captured during execution'),\n error: z\n .object({\n message: z.string(),\n name: z.string().optional(),\n line: z.number().optional(),\n })\n .optional()\n .describe('Error details if execution failed'),\n})\n\nexport type ExecuteTypescriptInput = z.infer<\n typeof executeTypescriptInputSchema\n>\nexport type ExecuteTypescriptOutput = z.infer<\n typeof executeTypescriptOutputSchema\n>\n\n/**\n * Create an execute_typescript tool that can be used alongside other agent tools.\n *\n * This tool allows an LLM to execute TypeScript code in a secure sandbox.\n * Tools passed in the config become `external_*` functions available inside the sandbox.\n *\n * @example\n * ```typescript\n * import { createCodeMode } from '@tanstack/ai-code-mode'\n * import { createNodeIsolateDriver } from '@tanstack/ai-isolate-node'\n *\n * const { tool, systemPrompt } = createCodeMode({\n * driver: createNodeIsolateDriver(),\n * tools: [weatherTool, dbTool], // Become external_fetchWeather, external_dbQuery\n * timeout: 30000,\n * })\n *\n * chat({\n * systemPrompts: [myPrompt, systemPrompt],\n * tools: [tool, searchTool, emailTool],\n * messages,\n * })\n * ```\n */\nexport function createCodeModeTool(\n config: CodeModeToolConfig,\n): ServerTool<\n typeof executeTypescriptInputSchema,\n typeof executeTypescriptOutputSchema,\n 'execute_typescript'\n> {\n const {\n driver,\n tools,\n timeout = 30000,\n memoryLimit = 128,\n getSkillBindings,\n transpile = stripTypeScript,\n } = config\n\n // Validate tools\n if (tools.length === 0) {\n throw new Error('At least one tool must be provided to createCodeModeTool')\n }\n\n // Transform tools to bindings with external_ prefix (static bindings)\n const staticBindings = toolsToBindings(tools, 'external_')\n\n // Create the tool definition\n const definition = toolDefinition({\n name: 'execute_typescript' as const,\n description: buildToolDescription(tools),\n inputSchema: executeTypescriptInputSchema,\n outputSchema: executeTypescriptOutputSchema,\n })\n\n // Return server tool with execute function that accepts context\n return definition.server(\n async (\n input,\n toolContext?: ToolExecutionContext,\n ): Promise<CodeModeToolResult> => {\n const { typescriptCode } = input\n\n // Get emitCustomEvent from context or use no-op\n const emitCustomEvent = toolContext?.emitCustomEvent || (() => {})\n\n if (!typescriptCode || typeof typescriptCode !== 'string') {\n return {\n success: false,\n error: {\n message: 'typescriptCode must be a non-empty string',\n name: 'ValidationError',\n },\n }\n }\n\n // Create a fresh sandbox context for this execution\n let isolateContext: IsolateContext | null = null\n\n // Emit execution started event immediately\n emitCustomEvent('code_mode:execution_started', {\n timestamp: Date.now(),\n codeLength: typescriptCode.length,\n })\n\n try {\n // Step 1: Strip TypeScript (also serves as syntax validation via the\n // transpiler — sucrase by default, or a user-supplied `transpile`)\n let strippedCode: string\n try {\n strippedCode = await transpile(typescriptCode)\n } catch (error) {\n // Type/syntax error from the transpiler\n return {\n success: false,\n error: {\n message: error instanceof Error ? error.message : String(error),\n name: 'TypeScriptError',\n },\n }\n }\n\n // Step 2: Get dynamic skill bindings if available\n const skillBindings = getSkillBindings ? await getSkillBindings() : {}\n\n // Step 3: Merge static and dynamic bindings, then wrap with event awareness\n const allBindings = { ...staticBindings, ...skillBindings }\n const eventAwareBindings = createEventAwareBindings(\n allBindings,\n emitCustomEvent,\n )\n\n // Step 4: Create sandbox context with event-aware bindings\n isolateContext = await driver.createContext({\n bindings: eventAwareBindings,\n timeout,\n memoryLimit,\n })\n\n // Step 5: Execute the code in the sandbox\n const executionResult = await isolateContext.execute(strippedCode)\n\n // Emit console logs as custom events\n if (executionResult.logs && executionResult.logs.length > 0) {\n for (const log of executionResult.logs) {\n // Parse log level from prefix (added by sandbox console implementation)\n let level: 'log' | 'warn' | 'error' | 'info' = 'log'\n let message = log\n\n if (log.startsWith('ERROR: ')) {\n level = 'error'\n message = log.slice(7)\n } else if (log.startsWith('WARN: ')) {\n level = 'warn'\n message = log.slice(6)\n } else if (log.startsWith('INFO: ')) {\n level = 'info'\n message = log.slice(6)\n }\n\n emitCustomEvent('code_mode:console', {\n level,\n message,\n timestamp: Date.now(),\n })\n }\n }\n\n if (executionResult.success) {\n return {\n success: true,\n result: executionResult.value,\n logs: executionResult.logs,\n }\n } else {\n return {\n success: false,\n error: executionResult.error\n ? {\n message: executionResult.error.message,\n name: executionResult.error.name,\n }\n : { message: 'Unknown execution error' },\n logs: executionResult.logs,\n }\n }\n } catch (error) {\n return {\n success: false,\n error: {\n message: error instanceof Error ? error.message : String(error),\n name: error instanceof Error ? error.name : 'Error',\n },\n }\n } finally {\n // Always clean up the sandbox context\n if (isolateContext) {\n await isolateContext.dispose()\n }\n }\n },\n )\n}\n\n/**\n * Build the tool description including available external functions\n */\nfunction buildToolDescription(tools: Array<CodeModeTool>): string {\n const eager = tools.filter((t) => !t.lazy)\n const hasLazy = tools.some((t) => t.lazy)\n const externalFunctions = eager.map((t) => `external_${t.name}`).join(', ')\n\n const discoverable = hasLazy\n ? ` Additional functions can be discovered via the discover_tools tool.`\n : ''\n\n return (\n `Execute TypeScript code in a secure sandbox environment. ` +\n `The code can use these external API functions: ${externalFunctions}.${discoverable} ` +\n `All external_* calls are async and must be awaited. ` +\n `Return a value to pass results back. Use console.log() for debugging.`\n )\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { CodeModeToolConfig, CreateCodeModeResult } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Create the `execute_typescript` tool, its matching system prompt, and (when
|
|
4
|
+
* any tools are marked `lazy: true`) a `discover_tools` companion tool.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { createCodeMode } from '@tanstack/ai-code-mode'
|
|
9
|
+
* import { createNodeIsolateDriver } from '@tanstack/ai-isolate-node'
|
|
10
|
+
*
|
|
11
|
+
* const { tools, systemPrompt } = createCodeMode({
|
|
12
|
+
* driver: createNodeIsolateDriver(),
|
|
13
|
+
* tools: [weatherTool, rarelyUsedTool], // mark rarelyUsedTool lazy: true
|
|
14
|
+
* })
|
|
15
|
+
*
|
|
16
|
+
* chat({
|
|
17
|
+
* systemPrompts: [myPrompt, systemPrompt],
|
|
18
|
+
* tools: [...tools, ...otherTools],
|
|
19
|
+
* messages,
|
|
20
|
+
* })
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function createCodeMode(config: CodeModeToolConfig): CreateCodeModeResult;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createCodeModeTool } from "./create-code-mode-tool.js";
|
|
2
|
+
import { createCodeModeSystemPrompt } from "./create-system-prompt.js";
|
|
3
|
+
import { createDiscoveryTool } from "./create-discovery-tool.js";
|
|
4
|
+
function createCodeMode(config) {
|
|
5
|
+
const tool = createCodeModeTool(config);
|
|
6
|
+
const systemPrompt = createCodeModeSystemPrompt(config);
|
|
7
|
+
const lazyTools = config.tools.filter((t) => t.lazy);
|
|
8
|
+
const discoveryTool = lazyTools.length > 0 ? createDiscoveryTool(lazyTools, config.lazyToolsConfig) : null;
|
|
9
|
+
return {
|
|
10
|
+
tool,
|
|
11
|
+
discoveryTool,
|
|
12
|
+
tools: discoveryTool ? [tool, discoveryTool] : [tool],
|
|
13
|
+
systemPrompt
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export {
|
|
17
|
+
createCodeMode
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=create-code-mode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-code-mode.js","sources":["../../src/create-code-mode.ts"],"sourcesContent":["import { createCodeModeTool } from './create-code-mode-tool'\nimport { createCodeModeSystemPrompt } from './create-system-prompt'\nimport { createDiscoveryTool } from './create-discovery-tool'\nimport type { CodeModeToolConfig, CreateCodeModeResult } from './types'\n\n/**\n * Create the `execute_typescript` tool, its matching system prompt, and (when\n * any tools are marked `lazy: true`) a `discover_tools` companion tool.\n *\n * @example\n * ```typescript\n * import { createCodeMode } from '@tanstack/ai-code-mode'\n * import { createNodeIsolateDriver } from '@tanstack/ai-isolate-node'\n *\n * const { tools, systemPrompt } = createCodeMode({\n * driver: createNodeIsolateDriver(),\n * tools: [weatherTool, rarelyUsedTool], // mark rarelyUsedTool lazy: true\n * })\n *\n * chat({\n * systemPrompts: [myPrompt, systemPrompt],\n * tools: [...tools, ...otherTools],\n * messages,\n * })\n * ```\n */\nexport function createCodeMode(\n config: CodeModeToolConfig,\n): CreateCodeModeResult {\n const tool = createCodeModeTool(config)\n const systemPrompt = createCodeModeSystemPrompt(config)\n\n const lazyTools = config.tools.filter((t) => t.lazy)\n const discoveryTool =\n lazyTools.length > 0\n ? createDiscoveryTool(lazyTools, config.lazyToolsConfig)\n : null\n\n return {\n tool,\n discoveryTool,\n tools: discoveryTool ? [tool, discoveryTool] : [tool],\n systemPrompt,\n }\n}\n"],"names":[],"mappings":";;;AA0BO,SAAS,eACd,QACsB;AACtB,QAAM,OAAO,mBAAmB,MAAM;AACtC,QAAM,eAAe,2BAA2B,MAAM;AAEtD,QAAM,YAAY,OAAO,MAAM,OAAO,CAAC,MAAM,EAAE,IAAI;AACnD,QAAM,gBACJ,UAAU,SAAS,IACf,oBAAoB,WAAW,OAAO,eAAe,IACrD;AAEN,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,OAAO,gBAAgB,CAAC,MAAM,aAAa,IAAI,CAAC,IAAI;AAAA,IACpD;AAAA,EAAA;AAEJ;"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { LazyToolsConfig, ServerTool } from '@tanstack/ai';
|
|
3
|
+
import { CodeModeTool } from './types.js';
|
|
4
|
+
declare const discoverInputSchema: z.ZodObject<{
|
|
5
|
+
toolNames: z.ZodArray<z.ZodString>;
|
|
6
|
+
}, z.core.$strip>;
|
|
7
|
+
declare const discoverOutputSchema: z.ZodObject<{
|
|
8
|
+
tools: z.ZodArray<z.ZodObject<{
|
|
9
|
+
name: z.ZodString;
|
|
10
|
+
description: z.ZodString;
|
|
11
|
+
typeStub: z.ZodString;
|
|
12
|
+
}, z.core.$strip>>;
|
|
13
|
+
errors: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
14
|
+
}, z.core.$strip>;
|
|
15
|
+
/**
|
|
16
|
+
* Build the `discover_tools` sibling tool for Code Mode lazy tools. The model
|
|
17
|
+
* calls it with lazy tool names and receives each one's TypeScript type stub +
|
|
18
|
+
* description, which it can then use to write correctly-typed `external_*`
|
|
19
|
+
* calls inside `execute_typescript`. The bindings themselves are always present
|
|
20
|
+
* in the sandbox — this only reveals documentation.
|
|
21
|
+
*
|
|
22
|
+
* Tools are catalogued in `external_<name>` form to match the "Discoverable
|
|
23
|
+
* APIs" section of the Code Mode system prompt; lookups tolerate either form.
|
|
24
|
+
* `lazyToolsConfig.includeDescription` controls how much of each tool's
|
|
25
|
+
* description appears in this tool's own catalog (mirroring the system prompt).
|
|
26
|
+
*/
|
|
27
|
+
export declare function createDiscoveryTool(lazyTools: Array<CodeModeTool>, lazyToolsConfig?: LazyToolsConfig): ServerTool<typeof discoverInputSchema, typeof discoverOutputSchema, 'discover_tools'>;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { renderLazyCatalogEntry, toolDefinition } from "@tanstack/ai";
|
|
3
|
+
import { toolToBinding } from "./bindings/tool-to-binding.js";
|
|
4
|
+
import { generateTypeStubs } from "./type-generator/json-schema-to-ts.js";
|
|
5
|
+
const discoverInputSchema = z.object({
|
|
6
|
+
toolNames: z.array(z.string()).describe(
|
|
7
|
+
'Names of tools to discover, exactly as shown in the Discoverable APIs catalog. The external_ prefix is optional — both "external_fetchStocks" and "fetchStocks" resolve.'
|
|
8
|
+
)
|
|
9
|
+
});
|
|
10
|
+
const discoverOutputSchema = z.object({
|
|
11
|
+
tools: z.array(
|
|
12
|
+
z.object({
|
|
13
|
+
name: z.string().describe("The sandbox function name, e.g. external_fetchStocks"),
|
|
14
|
+
description: z.string(),
|
|
15
|
+
typeStub: z.string().describe("TypeScript declaration for the function")
|
|
16
|
+
})
|
|
17
|
+
),
|
|
18
|
+
errors: z.array(z.string()).optional()
|
|
19
|
+
});
|
|
20
|
+
const EXTERNAL_PREFIX = "external_";
|
|
21
|
+
function stripExternalPrefix(name) {
|
|
22
|
+
return name.startsWith(EXTERNAL_PREFIX) ? name.slice(EXTERNAL_PREFIX.length) : name;
|
|
23
|
+
}
|
|
24
|
+
function createDiscoveryTool(lazyTools, lazyToolsConfig) {
|
|
25
|
+
const lazyMap = new Map(lazyTools.map((t) => [t.name, t]));
|
|
26
|
+
const include = lazyToolsConfig?.includeDescription ?? "none";
|
|
27
|
+
const catalog = lazyTools.map(
|
|
28
|
+
(t) => renderLazyCatalogEntry(
|
|
29
|
+
`${EXTERNAL_PREFIX}${t.name}`,
|
|
30
|
+
t.description,
|
|
31
|
+
include
|
|
32
|
+
)
|
|
33
|
+
).join(", ");
|
|
34
|
+
return toolDefinition({
|
|
35
|
+
name: "discover_tools",
|
|
36
|
+
description: `Discover full TypeScript signatures for additional sandbox APIs before using them inside execute_typescript. Discoverable tools: [${catalog}]. Pass the names exactly as shown (the external_ prefix is optional).`,
|
|
37
|
+
inputSchema: discoverInputSchema,
|
|
38
|
+
outputSchema: discoverOutputSchema
|
|
39
|
+
}).server(async ({ toolNames }) => {
|
|
40
|
+
const tools = [];
|
|
41
|
+
const errors = [];
|
|
42
|
+
for (const name of toolNames) {
|
|
43
|
+
const tool = lazyMap.get(stripExternalPrefix(name));
|
|
44
|
+
if (!tool) {
|
|
45
|
+
errors.push(`Unknown tool: '${name}'. Discoverable tools: [${catalog}]`);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const binding = toolToBinding(tool, EXTERNAL_PREFIX);
|
|
49
|
+
const typeStub = generateTypeStubs({ [binding.name]: binding });
|
|
50
|
+
tools.push({
|
|
51
|
+
name: binding.name,
|
|
52
|
+
description: tool.description,
|
|
53
|
+
typeStub
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return errors.length > 0 ? { tools, errors } : { tools };
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
export {
|
|
60
|
+
createDiscoveryTool
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=create-discovery-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-discovery-tool.js","sources":["../../src/create-discovery-tool.ts"],"sourcesContent":["import { z } from 'zod'\nimport { renderLazyCatalogEntry, toolDefinition } from '@tanstack/ai'\nimport { toolToBinding } from './bindings/tool-to-binding'\nimport { generateTypeStubs } from './type-generator/json-schema-to-ts'\nimport type { LazyToolsConfig, ServerTool } from '@tanstack/ai'\nimport type { CodeModeTool } from './types'\n\nconst discoverInputSchema = z.object({\n toolNames: z\n .array(z.string())\n .describe(\n 'Names of tools to discover, exactly as shown in the Discoverable APIs ' +\n 'catalog. The external_ prefix is optional — both \"external_fetchStocks\" ' +\n 'and \"fetchStocks\" resolve.',\n ),\n})\n\nconst discoverOutputSchema = z.object({\n tools: z.array(\n z.object({\n name: z\n .string()\n .describe('The sandbox function name, e.g. external_fetchStocks'),\n description: z.string(),\n typeStub: z.string().describe('TypeScript declaration for the function'),\n }),\n ),\n errors: z.array(z.string()).optional(),\n})\n\nconst EXTERNAL_PREFIX = 'external_'\n\n/**\n * Strip a single leading `external_` prefix so the model can pass either the\n * catalog name (`external_fetchStocks`) or the bare name (`fetchStocks`).\n */\nfunction stripExternalPrefix(name: string): string {\n return name.startsWith(EXTERNAL_PREFIX)\n ? name.slice(EXTERNAL_PREFIX.length)\n : name\n}\n\n/**\n * Build the `discover_tools` sibling tool for Code Mode lazy tools. The model\n * calls it with lazy tool names and receives each one's TypeScript type stub +\n * description, which it can then use to write correctly-typed `external_*`\n * calls inside `execute_typescript`. The bindings themselves are always present\n * in the sandbox — this only reveals documentation.\n *\n * Tools are catalogued in `external_<name>` form to match the \"Discoverable\n * APIs\" section of the Code Mode system prompt; lookups tolerate either form.\n * `lazyToolsConfig.includeDescription` controls how much of each tool's\n * description appears in this tool's own catalog (mirroring the system prompt).\n */\nexport function createDiscoveryTool(\n lazyTools: Array<CodeModeTool>,\n lazyToolsConfig?: LazyToolsConfig,\n): ServerTool<\n typeof discoverInputSchema,\n typeof discoverOutputSchema,\n 'discover_tools'\n> {\n const lazyMap = new Map(lazyTools.map((t) => [t.name, t]))\n const include = lazyToolsConfig?.includeDescription ?? 'none'\n const catalog = lazyTools\n .map((t) =>\n renderLazyCatalogEntry(\n `${EXTERNAL_PREFIX}${t.name}`,\n t.description,\n include,\n ),\n )\n .join(', ')\n\n return toolDefinition({\n name: 'discover_tools' as const,\n description:\n `Discover full TypeScript signatures for additional sandbox APIs before ` +\n `using them inside execute_typescript. Discoverable tools: [${catalog}]. ` +\n `Pass the names exactly as shown (the external_ prefix is optional).`,\n inputSchema: discoverInputSchema,\n outputSchema: discoverOutputSchema,\n }).server(async ({ toolNames }) => {\n const tools: Array<{\n name: string\n description: string\n typeStub: string\n }> = []\n const errors: Array<string> = []\n\n for (const name of toolNames) {\n const tool = lazyMap.get(stripExternalPrefix(name))\n if (!tool) {\n errors.push(`Unknown tool: '${name}'. Discoverable tools: [${catalog}]`)\n continue\n }\n const binding = toolToBinding(tool, EXTERNAL_PREFIX)\n const typeStub = generateTypeStubs({ [binding.name]: binding })\n tools.push({\n name: binding.name,\n description: tool.description,\n typeStub,\n })\n }\n\n return errors.length > 0 ? { tools, errors } : { tools }\n })\n}\n"],"names":[],"mappings":";;;;AAOA,MAAM,sBAAsB,EAAE,OAAO;AAAA,EACnC,WAAW,EACR,MAAM,EAAE,OAAA,CAAQ,EAChB;AAAA,IACC;AAAA,EAAA;AAIN,CAAC;AAED,MAAM,uBAAuB,EAAE,OAAO;AAAA,EACpC,OAAO,EAAE;AAAA,IACP,EAAE,OAAO;AAAA,MACP,MAAM,EACH,SACA,SAAS,sDAAsD;AAAA,MAClE,aAAa,EAAE,OAAA;AAAA,MACf,UAAU,EAAE,OAAA,EAAS,SAAS,yCAAyC;AAAA,IAAA,CACxE;AAAA,EAAA;AAAA,EAEH,QAAQ,EAAE,MAAM,EAAE,OAAA,CAAQ,EAAE,SAAA;AAC9B,CAAC;AAED,MAAM,kBAAkB;AAMxB,SAAS,oBAAoB,MAAsB;AACjD,SAAO,KAAK,WAAW,eAAe,IAClC,KAAK,MAAM,gBAAgB,MAAM,IACjC;AACN;AAcO,SAAS,oBACd,WACA,iBAKA;AACA,QAAM,UAAU,IAAI,IAAI,UAAU,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AACzD,QAAM,UAAU,iBAAiB,sBAAsB;AACvD,QAAM,UAAU,UACb;AAAA,IAAI,CAAC,MACJ;AAAA,MACE,GAAG,eAAe,GAAG,EAAE,IAAI;AAAA,MAC3B,EAAE;AAAA,MACF;AAAA,IAAA;AAAA,EACF,EAED,KAAK,IAAI;AAEZ,SAAO,eAAe;AAAA,IACpB,MAAM;AAAA,IACN,aACE,qIAC8D,OAAO;AAAA,IAEvE,aAAa;AAAA,IACb,cAAc;AAAA,EAAA,CACf,EAAE,OAAO,OAAO,EAAE,gBAAgB;AACjC,UAAM,QAID,CAAA;AACL,UAAM,SAAwB,CAAA;AAE9B,eAAW,QAAQ,WAAW;AAC5B,YAAM,OAAO,QAAQ,IAAI,oBAAoB,IAAI,CAAC;AAClD,UAAI,CAAC,MAAM;AACT,eAAO,KAAK,kBAAkB,IAAI,2BAA2B,OAAO,GAAG;AACvE;AAAA,MACF;AACA,YAAM,UAAU,cAAc,MAAM,eAAe;AACnD,YAAM,WAAW,kBAAkB,EAAE,CAAC,QAAQ,IAAI,GAAG,SAAS;AAC9D,YAAM,KAAK;AAAA,QACT,MAAM,QAAQ;AAAA,QACd,aAAa,KAAK;AAAA,QAClB;AAAA,MAAA,CACD;AAAA,IACH;AAEA,WAAO,OAAO,SAAS,IAAI,EAAE,OAAO,OAAA,IAAW,EAAE,MAAA;AAAA,EACnD,CAAC;AACH;"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { CodeModeToolConfig } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Create a system prompt snippet that documents the execute_typescript tool
|
|
4
|
+
* and all available external_* functions.
|
|
5
|
+
*
|
|
6
|
+
* Add this to your system prompts array when using createCodeModeTool.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { createCodeMode } from '@tanstack/ai-code-mode'
|
|
11
|
+
* import { createNodeIsolateDriver } from '@tanstack/ai-isolate-node'
|
|
12
|
+
*
|
|
13
|
+
* const { tool, systemPrompt } = createCodeMode({
|
|
14
|
+
* driver: createNodeIsolateDriver(),
|
|
15
|
+
* tools: [weatherTool, dbTool],
|
|
16
|
+
* })
|
|
17
|
+
*
|
|
18
|
+
* chat({
|
|
19
|
+
* systemPrompts: ['You are a helpful assistant.', systemPrompt],
|
|
20
|
+
* tools: [tool, ...otherTools],
|
|
21
|
+
* })
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare function createCodeModeSystemPrompt(config: CodeModeToolConfig): string;
|