@tanstack/ai-code-mode 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.
Files changed (40) hide show
  1. package/README.md +196 -0
  2. package/dist/esm/agent-store.d.ts +21 -0
  3. package/dist/esm/agent-store.js +31 -0
  4. package/dist/esm/agent-store.js.map +1 -0
  5. package/dist/esm/bindings/tool-to-binding.d.ts +24 -0
  6. package/dist/esm/bindings/tool-to-binding.js +78 -0
  7. package/dist/esm/bindings/tool-to-binding.js.map +1 -0
  8. package/dist/esm/code-wrapper.d.ts +9 -0
  9. package/dist/esm/code-wrapper.js +18 -0
  10. package/dist/esm/code-wrapper.js.map +1 -0
  11. package/dist/esm/create-code-mode-tool.d.ts +50 -0
  12. package/dist/esm/create-code-mode-tool.js +142 -0
  13. package/dist/esm/create-code-mode-tool.js.map +1 -0
  14. package/dist/esm/create-code-mode.d.ts +41 -0
  15. package/dist/esm/create-code-mode.js +12 -0
  16. package/dist/esm/create-code-mode.js.map +1 -0
  17. package/dist/esm/create-system-prompt.d.ts +24 -0
  18. package/dist/esm/create-system-prompt.js +66 -0
  19. package/dist/esm/create-system-prompt.js.map +1 -0
  20. package/dist/esm/index.d.ts +10 -0
  21. package/dist/esm/index.js +23 -0
  22. package/dist/esm/index.js.map +1 -0
  23. package/dist/esm/strip-typescript.d.ts +23 -0
  24. package/dist/esm/strip-typescript.js +52 -0
  25. package/dist/esm/strip-typescript.js.map +1 -0
  26. package/dist/esm/type-generator/json-schema-to-ts.d.ts +31 -0
  27. package/dist/esm/type-generator/json-schema-to-ts.js +100 -0
  28. package/dist/esm/type-generator/json-schema-to-ts.js.map +1 -0
  29. package/dist/esm/types.d.ts +176 -0
  30. package/package.json +62 -0
  31. package/src/agent-store.ts +43 -0
  32. package/src/bindings/tool-to-binding.ts +132 -0
  33. package/src/code-wrapper.ts +24 -0
  34. package/src/create-code-mode-tool.ts +254 -0
  35. package/src/create-code-mode.ts +35 -0
  36. package/src/create-system-prompt.ts +95 -0
  37. package/src/index.ts +55 -0
  38. package/src/strip-typescript.ts +94 -0
  39. package/src/type-generator/json-schema-to-ts.ts +188 -0
  40. package/src/types.ts +225 -0
package/README.md ADDED
@@ -0,0 +1,196 @@
1
+ # @tanstack/ai-code-mode
2
+
3
+ Code Mode for TanStack AI — let LLMs write and execute TypeScript in secure sandboxes with typed tool access.
4
+
5
+ ## Overview
6
+
7
+ Code Mode gives your AI agent an `execute_typescript` tool. Instead of one tool call per action, the LLM writes a small TypeScript program that orchestrates multiple tool calls with loops, conditionals, `Promise.all`, and data transformations — all running in an isolated sandbox.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ pnpm add @tanstack/ai-code-mode
13
+ ```
14
+
15
+ You also need an isolate driver:
16
+
17
+ ```bash
18
+ # Node.js (fastest, uses V8 isolates via isolated-vm)
19
+ pnpm add @tanstack/ai-isolate-node
20
+
21
+ # QuickJS WASM (browser-compatible, no native deps)
22
+ pnpm add @tanstack/ai-isolate-quickjs
23
+
24
+ # Cloudflare Workers (edge execution)
25
+ pnpm add @tanstack/ai-isolate-cloudflare
26
+ ```
27
+
28
+ ## Quick Start
29
+
30
+ ```typescript
31
+ import { chat, toolDefinition } from '@tanstack/ai'
32
+ import { createCodeMode } from '@tanstack/ai-code-mode'
33
+ import { createNodeIsolateDriver } from '@tanstack/ai-isolate-node'
34
+ import { z } from 'zod'
35
+
36
+ // Define tools that the LLM can call from inside the sandbox
37
+ const weatherTool = toolDefinition({
38
+ name: 'fetchWeather',
39
+ description: 'Get weather for a city',
40
+ inputSchema: z.object({ location: z.string() }),
41
+ outputSchema: z.object({ temperature: z.number(), condition: z.string() }),
42
+ }).server(async ({ location }) => {
43
+ // Your implementation
44
+ return { temperature: 72, condition: 'sunny' }
45
+ })
46
+
47
+ // Create the execute_typescript tool and system prompt
48
+ const { tool, systemPrompt } = createCodeMode({
49
+ driver: createNodeIsolateDriver(),
50
+ tools: [weatherTool],
51
+ })
52
+
53
+ const result = await chat({
54
+ adapter: yourAdapter,
55
+ model: 'gpt-4o',
56
+ systemPrompts: ['You are a helpful assistant.', systemPrompt],
57
+ tools: [tool],
58
+ messages: [
59
+ { role: 'user', content: 'Compare weather in Tokyo, Paris, and NYC' },
60
+ ],
61
+ })
62
+ ```
63
+
64
+ The LLM will generate code like:
65
+
66
+ ```typescript
67
+ const cities = ['Tokyo', 'Paris', 'NYC']
68
+ const results = await Promise.all(
69
+ cities.map((city) => external_fetchWeather({ location: city })),
70
+ )
71
+ const warmest = results.reduce((prev, curr) =>
72
+ curr.temperature > prev.temperature ? curr : prev,
73
+ )
74
+ return { warmestCity: warmest.location, temperature: warmest.temperature }
75
+ ```
76
+
77
+ ## API Reference
78
+
79
+ ### `createCodeMode(config)`
80
+
81
+ Creates both the `execute_typescript` tool and its matching system prompt. This is the recommended entry point.
82
+
83
+ **Config:**
84
+
85
+ - `driver` — An `IsolateDriver` (Node, QuickJS, or Cloudflare)
86
+ - `tools` — Array of `ServerTool` or `ToolDefinition` instances. Exposed as `external_*` functions in the sandbox
87
+ - `timeout` — Execution timeout in ms (default: 30000)
88
+ - `memoryLimit` — Memory limit in MB (default: 128, supported by Node and QuickJS drivers)
89
+ - `getSkillBindings` — Optional async function returning dynamic bindings
90
+
91
+ ### `createCodeModeTool(config)` / `createCodeModeSystemPrompt(config)`
92
+
93
+ Lower-level functions if you need only the tool or only the prompt. `createCodeMode` calls both internally.
94
+
95
+ ### Advanced
96
+
97
+ These utilities are used internally and exported for custom pipelines:
98
+
99
+ - **`stripTypeScript(code)`** — Strips TypeScript syntax using esbuild.
100
+ - **`toolsToBindings(tools, prefix?)`** — Converts tools to `ToolBinding` records for sandbox injection.
101
+ - **`generateTypeStubs(bindings, options?)`** — Generates TypeScript type declarations from tool bindings.
102
+
103
+ ## Driver Selection Guide
104
+
105
+ | Driver | Best For | Native Deps | Browser | Memory Limit |
106
+ | --------------------------------- | -------------------------------------------- | ------------------- | ------- | ------------ |
107
+ | `@tanstack/ai-isolate-node` | Server-side Node.js apps | Yes (`isolated-vm`) | No | Yes |
108
+ | `@tanstack/ai-isolate-quickjs` | Browser, edge, or no-native-dep environments | No (WASM) | Yes | Yes |
109
+ | `@tanstack/ai-isolate-cloudflare` | Cloudflare Workers deployments | No | N/A | N/A |
110
+
111
+ ## Custom Events
112
+
113
+ Code Mode emits custom events during execution that you can observe via the TanStack AI event system:
114
+
115
+ | Event | Description |
116
+ | ----------------------------- | --------------------------------------------------- |
117
+ | `code_mode:execution_started` | Emitted when code execution begins |
118
+ | `code_mode:console` | Emitted for each `console.log/error/warn/info` call |
119
+ | `code_mode:external_call` | Emitted before each `external_*` function call |
120
+ | `code_mode:external_result` | Emitted after a successful `external_*` call |
121
+ | `code_mode:external_error` | Emitted when an `external_*` call fails |
122
+
123
+ ## Models eval (development)
124
+
125
+ The benchmark lives in a **separate workspace package** so `@tanstack/ai-code-mode` does not depend on `@tanstack/ai-isolate-node` (avoids an Nx build cycle). See `models-eval/package.json` (`@tanstack/ai-code-mode-models-eval`).
126
+
127
+ 1. `packages/typescript/ai-code-mode/models-eval/pull-models.sh` — pull recommended Ollama models
128
+ 2. `pnpm --filter @tanstack/ai-code-mode-models-eval eval:capture` — run models and capture raw outputs/telemetry only (no judge LLM call)
129
+ 3. `pnpm --filter @tanstack/ai-code-mode-models-eval eval:judge` — judge latest captured session from logs (no model rerun)
130
+ 4. `pnpm --filter @tanstack/ai-code-mode-models-eval eval` — single-pass run+judge (legacy convenience mode)
131
+ 5. `pnpm --filter @tanstack/ai-code-mode-models-eval eval -- --ollama-only` — only Ollama models from `eval-config.ts`
132
+ 6. `pnpm --filter @tanstack/ai-code-mode-models-eval eval -- --ollama-only --models qwen3-coder` — one or more model ids (comma-separated)
133
+
134
+ Judge-phase flags:
135
+
136
+ - `--judge-latest` judge latest captured session
137
+ - `--rejudge` re-run judging even if logs already contain judge fields
138
+
139
+ The default list omits some small Ollama models that rarely complete code-mode successfully (see comments in `eval-config.ts`). You can still benchmark them with `--models granite4:3b` etc. if pulled locally.
140
+
141
+ ### Model comparison metrics
142
+
143
+ The models eval now tracks seven decision-oriented metrics plus an overall rating:
144
+
145
+ - `accuracy` (1-10): numerical/factual correctness vs gold report
146
+ - `comprehensiveness` (1-10): whether the response covers everything requested by the user query
147
+ - `typescriptQuality` (1-10): quality/readability/type-safety of generated TypeScript
148
+ - `codeModeEfficiency` (1-10): how efficiently the model uses code-mode/tooling to reach the answer
149
+ - `speedTier` (1-5): relative wall-clock speed against peers in the same category (`local` or `cloud`)
150
+ - `tokenEfficiencyTier` (1-5): relative token efficiency against peers in the same category
151
+ - `stabilityTier` (1-5): success consistency over the latest 5 logged runs for that model
152
+ - `stars` (1-3): weighted rollup score across all metrics
153
+
154
+ Raw run telemetry also includes compile/runtime failures, redundant schema checks, total tool calls, TTFT, token totals, stability sample size/rate, and per-model logs.
155
+
156
+ ### Methodology
157
+
158
+ Canonical output is written to `packages/typescript/ai-code-mode/models-eval/results.json` after each capture or judge run.
159
+
160
+ - Benchmark: single code-mode benchmark prompt over the in-memory `customers` / `products` / `purchases` dataset
161
+ - Primary quality scores (judge): `accuracy`, `comprehensiveness`, `typescriptQuality`, `codeModeEfficiency`
162
+ - Computed comparative scores: `speedTier`, `tokenEfficiencyTier`, `stabilityTier`
163
+ - Stability definition: a run is "stable" if it has no top-level run error, produces a non-empty candidate report, and has at least one successful `execute_typescript` call
164
+ - Star rollup weights:
165
+ - accuracy: 25%
166
+ - comprehensiveness: 15%
167
+ - typescriptQuality: 15%
168
+ - codeModeEfficiency (with compile/runtime failure penalty): 10%
169
+ - speedTier: 10%
170
+ - tokenEfficiencyTier: 10%
171
+ - stabilityTier: 15%
172
+
173
+ ### Model comparison table
174
+
175
+ The table below is transcribed from canonical `models-eval/results.json` (session `2026-03-26T15:38:44.006Z`).
176
+
177
+ | Provider | Model | Category | Stars | Accuracy | Comprehensiveness | TypeScript | Code-Mode | Speed Tier | Token Tier | Stability Tier |
178
+ | --------- | ----------------------------- | -------- | ----- | -------- | ----------------- | ---------- | --------- | ---------- | ---------- | -------------- |
179
+ | Ollama | `gpt-oss:20b` | local | ★★★ | 10 | 8 | 5 | 5 | 5 | 5 | 5 |
180
+ | Ollama | `nemotron-cascade-2` | local | ★★☆ | 3 | 5 | 6 | 5 | 1 | 5 | 5 |
181
+ | Anthropic | `claude-haiku-4-5` | cloud | ★★★ | 10 | 10 | 6 | 7 | 3 | 2 | 5 |
182
+ | OpenAI | `gpt-4o-mini` | cloud | ★★★ | 10 | 8 | 7 | 9 | 3 | 1 | 5 |
183
+ | Gemini | `gemini-2.5-flash` | cloud | ★★★ | 10 | 8 | 7 | 10 | 4 | 2 | 5 |
184
+ | xAI | `grok-4-1-fast-non-reasoning` | cloud | ★★★ | 10 | 8 | 6 | 10 | 4 | 5 | 5 |
185
+ | Groq | `llama-3.3-70b-versatile` | cloud | ★★★ | 10 | 7 | 6 | 9 | 5 | 3 | 4 |
186
+ | Groq | `qwen/qwen3-32b` | cloud | ★★☆ | 10 | 8 | 5 | 4 | 1 | 2 | 5 |
187
+
188
+ Suggested interpretation:
189
+
190
+ - **Local-first**: favor `stars >= 2` with high speed tier.
191
+ - **Cloud-first quality**: favor high `accuracy` + `typescriptQuality`, then compare stars.
192
+ - **Cost-sensitive**: prioritize `tokenEfficiencyTier` and `speedTier` together.
193
+
194
+ ## License
195
+
196
+ MIT
@@ -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 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,31 @@
1
+ class InMemoryAgentStore {
2
+ constructor() {
3
+ this.sessions = /* @__PURE__ */ new Map();
4
+ }
5
+ get(name) {
6
+ return Promise.resolve(this.sessions.get(name) ?? null);
7
+ }
8
+ set(name, session) {
9
+ this.sessions.set(name, session);
10
+ return Promise.resolve();
11
+ }
12
+ delete(name) {
13
+ this.sessions.delete(name);
14
+ return Promise.resolve();
15
+ }
16
+ list() {
17
+ return Promise.resolve(Array.from(this.sessions.keys()));
18
+ }
19
+ }
20
+ function generateAgentName() {
21
+ const hex = Array.from(
22
+ { length: 8 },
23
+ () => Math.floor(Math.random() * 16).toString(16)
24
+ ).join("");
25
+ return `agent_${hex}`;
26
+ }
27
+ export {
28
+ InMemoryAgentStore,
29
+ generateAgentName
30
+ };
31
+ //# 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 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,EAA/C,cAAA;AACL,SAAQ,+BAAe,IAAA;AAAA,EAA0B;AAAA,EAEjD,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,24 @@
1
+ import { CodeModeTool, ToolBinding } from '../types.js';
2
+ /**
3
+ * Convert an array of TanStack AI tools to a Record of ToolBindings
4
+ *
5
+ * @param tools - Array of tools to convert
6
+ * @param prefix - Optional prefix to add to binding names (e.g., 'external_')
7
+ */
8
+ export declare function toolsToBindings(tools: Array<CodeModeTool>, prefix?: string): Record<string, ToolBinding>;
9
+ /**
10
+ * Convert a single TanStack AI tool to a ToolBinding
11
+ *
12
+ * @param tool - Tool to convert
13
+ * @param prefix - Optional prefix to add to binding name (e.g., 'external_')
14
+ * @throws Error if the tool doesn't have an execute function
15
+ */
16
+ export declare function toolToBinding(tool: CodeModeTool, prefix?: string): ToolBinding;
17
+ /**
18
+ * Create event-aware bindings that emit custom events for each external function call.
19
+ * Wraps each binding's execute function to emit events before and after execution.
20
+ *
21
+ * @param bindings - Original tool bindings
22
+ * @param emitCustomEvent - Callback to emit custom events to the stream
23
+ */
24
+ export declare function createEventAwareBindings(bindings: Record<string, ToolBinding>, emitCustomEvent: (eventName: string, data: Record<string, any>) => void): Record<string, ToolBinding>;
@@ -0,0 +1,78 @@
1
+ import { convertSchemaToJsonSchema } 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
+ let execute;
17
+ if ("execute" in tool && typeof tool.execute === "function") {
18
+ const toolExecute = tool.execute;
19
+ execute = (args, context) => {
20
+ return Promise.resolve(toolExecute(args, context));
21
+ };
22
+ } else if ("__toolSide" in tool && tool.__toolSide === "definition") {
23
+ throw new Error(
24
+ `Tool "${tool.name}" is a ToolDefinition without an execute function. Call .server(fn) to provide an implementation before using with Code Mode.`
25
+ );
26
+ } else {
27
+ throw new Error(
28
+ `Tool "${tool.name}" does not have an execute function. Code Mode requires tools with implementations.`
29
+ );
30
+ }
31
+ return {
32
+ name: `${prefix}${tool.name}`,
33
+ description: tool.description,
34
+ inputSchema,
35
+ outputSchema,
36
+ execute
37
+ };
38
+ }
39
+ function createEventAwareBindings(bindings, emitCustomEvent) {
40
+ const wrapped = {};
41
+ for (const [name, binding] of Object.entries(bindings)) {
42
+ wrapped[name] = {
43
+ ...binding,
44
+ execute: async (args) => {
45
+ emitCustomEvent("code_mode:external_call", {
46
+ function: name,
47
+ args,
48
+ timestamp: Date.now()
49
+ });
50
+ const startTime = Date.now();
51
+ try {
52
+ const toolContext = { emitCustomEvent };
53
+ const result = await binding.execute(args, toolContext);
54
+ emitCustomEvent("code_mode:external_result", {
55
+ function: name,
56
+ result,
57
+ duration: Date.now() - startTime
58
+ });
59
+ return result;
60
+ } catch (error) {
61
+ emitCustomEvent("code_mode:external_error", {
62
+ function: name,
63
+ error: error instanceof Error ? error.message : String(error),
64
+ duration: Date.now() - startTime
65
+ });
66
+ throw error;
67
+ }
68
+ }
69
+ };
70
+ }
71
+ return wrapped;
72
+ }
73
+ export {
74
+ createEventAwareBindings,
75
+ toolToBinding,
76
+ toolsToBindings
77
+ };
78
+ //# 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 { convertSchemaToJsonSchema } 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 // Get execute function\n // ServerTool has execute, ToolDefinition (without .server()) does not\n let execute: (\n args: unknown,\n context?: ToolExecutionContext,\n ) => Promise<unknown>\n\n if ('execute' in tool && typeof tool.execute === 'function') {\n const toolExecute = tool.execute\n execute = (args: unknown, context?: ToolExecutionContext) => {\n // Pass context to the underlying tool so it can emit custom events\n return Promise.resolve(toolExecute(args, context))\n }\n } else if ('__toolSide' in tool && tool.__toolSide === 'definition') {\n throw new Error(\n `Tool \"${tool.name}\" is a ToolDefinition without an execute function. ` +\n `Call .server(fn) to provide an implementation before using with Code Mode.`,\n )\n } else {\n throw new Error(\n `Tool \"${tool.name}\" does not have an execute function. ` +\n `Code Mode requires tools with implementations.`,\n )\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: (eventName: string, data: Record<string, any>) => void,\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":";AAUO,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;AAIJ,MAAI;AAKJ,MAAI,aAAa,QAAQ,OAAO,KAAK,YAAY,YAAY;AAC3D,UAAM,cAAc,KAAK;AACzB,cAAU,CAAC,MAAe,YAAmC;AAE3D,aAAO,QAAQ,QAAQ,YAAY,MAAM,OAAO,CAAC;AAAA,IACnD;AAAA,EACF,WAAW,gBAAgB,QAAQ,KAAK,eAAe,cAAc;AACnE,UAAM,IAAI;AAAA,MACR,SAAS,KAAK,IAAI;AAAA,IAAA;AAAA,EAGtB,OAAO;AACL,UAAM,IAAI;AAAA,MACR,SAAS,KAAK,IAAI;AAAA,IAAA;AAAA,EAGtB;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,142 @@
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
+ } = config;
28
+ if (tools.length === 0) {
29
+ throw new Error("At least one tool must be provided to createCodeModeTool");
30
+ }
31
+ const staticBindings = toolsToBindings(tools, "external_");
32
+ const definition = toolDefinition({
33
+ name: "execute_typescript",
34
+ description: buildToolDescription(tools),
35
+ inputSchema: executeTypescriptInputSchema,
36
+ outputSchema: executeTypescriptOutputSchema
37
+ });
38
+ return definition.server(
39
+ async (input, toolContext) => {
40
+ const { typescriptCode } = input;
41
+ const emitCustomEvent = toolContext?.emitCustomEvent || (() => {
42
+ });
43
+ if (!typescriptCode || typeof typescriptCode !== "string") {
44
+ return {
45
+ success: false,
46
+ error: {
47
+ message: "typescriptCode must be a non-empty string",
48
+ name: "ValidationError"
49
+ }
50
+ };
51
+ }
52
+ let isolateContext = null;
53
+ emitCustomEvent("code_mode:execution_started", {
54
+ timestamp: Date.now(),
55
+ codeLength: typescriptCode.length
56
+ });
57
+ try {
58
+ let strippedCode;
59
+ try {
60
+ strippedCode = await stripTypeScript(typescriptCode);
61
+ } catch (error) {
62
+ return {
63
+ success: false,
64
+ error: {
65
+ message: error instanceof Error ? error.message : String(error),
66
+ name: "TypeScriptError"
67
+ }
68
+ };
69
+ }
70
+ const skillBindings = getSkillBindings ? await getSkillBindings() : {};
71
+ const allBindings = { ...staticBindings, ...skillBindings };
72
+ const eventAwareBindings = createEventAwareBindings(
73
+ allBindings,
74
+ emitCustomEvent
75
+ );
76
+ isolateContext = await driver.createContext({
77
+ bindings: eventAwareBindings,
78
+ timeout,
79
+ memoryLimit
80
+ });
81
+ const executionResult = await isolateContext.execute(strippedCode);
82
+ if (executionResult.logs && executionResult.logs.length > 0) {
83
+ for (const log of executionResult.logs) {
84
+ let level = "log";
85
+ let message = log;
86
+ if (log.startsWith("ERROR: ")) {
87
+ level = "error";
88
+ message = log.slice(7);
89
+ } else if (log.startsWith("WARN: ")) {
90
+ level = "warn";
91
+ message = log.slice(6);
92
+ } else if (log.startsWith("INFO: ")) {
93
+ level = "info";
94
+ message = log.slice(6);
95
+ }
96
+ emitCustomEvent("code_mode:console", {
97
+ level,
98
+ message,
99
+ timestamp: Date.now()
100
+ });
101
+ }
102
+ }
103
+ if (executionResult.success) {
104
+ return {
105
+ success: true,
106
+ result: executionResult.value,
107
+ logs: executionResult.logs
108
+ };
109
+ } else {
110
+ return {
111
+ success: false,
112
+ error: executionResult.error ? {
113
+ message: executionResult.error.message,
114
+ name: executionResult.error.name
115
+ } : { message: "Unknown execution error" },
116
+ logs: executionResult.logs
117
+ };
118
+ }
119
+ } catch (error) {
120
+ return {
121
+ success: false,
122
+ error: {
123
+ message: error instanceof Error ? error.message : String(error),
124
+ name: error instanceof Error ? error.name : "Error"
125
+ }
126
+ };
127
+ } finally {
128
+ if (isolateContext) {
129
+ await isolateContext.dispose();
130
+ }
131
+ }
132
+ }
133
+ );
134
+ }
135
+ function buildToolDescription(tools) {
136
+ const externalFunctions = tools.map((t) => `external_${t.name}`).join(", ");
137
+ return `Execute TypeScript code in a secure sandbox environment. The code can use these external API functions: ${externalFunctions}. All external_* calls are async and must be awaited. Return a value to pass results back. Use console.log() for debugging.`;
138
+ }
139
+ export {
140
+ createCodeModeTool
141
+ };
142
+ //# 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 } = 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 esbuild)\n let strippedCode: string\n try {\n strippedCode = await stripTypeScript(typescriptCode)\n } catch (error) {\n // Type/syntax error from esbuild\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 externalFunctions = tools.map((t) => `external_${t.name}`).join(', ')\n\n return (\n `Execute TypeScript code in a secure sandbox environment. ` +\n `The code can use these external API functions: ${externalFunctions}. ` +\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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"}