@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/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@tanstack/ai-code-mode",
3
+ "version": "0.1.0",
4
+ "description": "Code Mode for TanStack AI - LLM-driven code execution in secure sandboxes",
5
+ "author": "",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "license": "MIT",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/TanStack/ai.git",
13
+ "directory": "packages/typescript/ai-code-mode"
14
+ },
15
+ "type": "module",
16
+ "module": "./dist/esm/index.js",
17
+ "types": "./dist/esm/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/esm/index.d.ts",
21
+ "import": "./dist/esm/index.js"
22
+ }
23
+ },
24
+ "sideEffects": false,
25
+ "engines": {
26
+ "node": ">=18"
27
+ },
28
+ "files": [
29
+ "dist",
30
+ "src"
31
+ ],
32
+ "scripts": {
33
+ "build": "vite build",
34
+ "clean": "premove ./build ./dist",
35
+ "lint:fix": "eslint ./src --fix",
36
+ "test:build": "publint --strict",
37
+ "test:eslint": "eslint ./src",
38
+ "test:lib": "vitest",
39
+ "test:lib:dev": "pnpm test:lib --watch",
40
+ "test:types": "tsc"
41
+ },
42
+ "keywords": [
43
+ "ai",
44
+ "tanstack",
45
+ "code-mode",
46
+ "llm",
47
+ "sandbox",
48
+ "isolate"
49
+ ],
50
+ "dependencies": {
51
+ "esbuild": "^0.25.12"
52
+ },
53
+ "peerDependencies": {
54
+ "@tanstack/ai": "workspace:*",
55
+ "zod": "^3.0.0 || ^4.0.0"
56
+ },
57
+ "devDependencies": {
58
+ "@tanstack/ai": "workspace:*",
59
+ "@vitest/coverage-v8": "4.0.14",
60
+ "zod": "^4.2.0"
61
+ }
62
+ }
@@ -0,0 +1,43 @@
1
+ export interface AgentSession {
2
+ name: string
3
+ systemPrompt: string
4
+ memory: Record<string, unknown>
5
+ createdAt: number
6
+ lastUsedAt: number
7
+ }
8
+
9
+ export interface AgentStore {
10
+ get: (name: string) => Promise<AgentSession | null>
11
+ set: (name: string, session: AgentSession) => Promise<void>
12
+ delete: (name: string) => Promise<void>
13
+ list: () => Promise<Array<string>>
14
+ }
15
+
16
+ export class InMemoryAgentStore implements AgentStore {
17
+ private sessions = new Map<string, AgentSession>()
18
+
19
+ get(name: string): Promise<AgentSession | null> {
20
+ return Promise.resolve(this.sessions.get(name) ?? null)
21
+ }
22
+
23
+ set(name: string, session: AgentSession): Promise<void> {
24
+ this.sessions.set(name, session)
25
+ return Promise.resolve()
26
+ }
27
+
28
+ delete(name: string): Promise<void> {
29
+ this.sessions.delete(name)
30
+ return Promise.resolve()
31
+ }
32
+
33
+ list(): Promise<Array<string>> {
34
+ return Promise.resolve(Array.from(this.sessions.keys()))
35
+ }
36
+ }
37
+
38
+ export function generateAgentName(): string {
39
+ const hex = Array.from({ length: 8 }, () =>
40
+ Math.floor(Math.random() * 16).toString(16),
41
+ ).join('')
42
+ return `agent_${hex}`
43
+ }
@@ -0,0 +1,132 @@
1
+ import { convertSchemaToJsonSchema } from '@tanstack/ai'
2
+ import type { ToolExecutionContext } from '@tanstack/ai'
3
+ import type { CodeModeTool, ToolBinding } from '../types'
4
+
5
+ /**
6
+ * Convert an array of TanStack AI tools to a Record of ToolBindings
7
+ *
8
+ * @param tools - Array of tools to convert
9
+ * @param prefix - Optional prefix to add to binding names (e.g., 'external_')
10
+ */
11
+ export function toolsToBindings(
12
+ tools: Array<CodeModeTool>,
13
+ prefix: string = '',
14
+ ): Record<string, ToolBinding> {
15
+ const bindings: Record<string, ToolBinding> = {}
16
+
17
+ for (const tool of tools) {
18
+ const bindingName = `${prefix}${tool.name}`
19
+ bindings[bindingName] = toolToBinding(tool, prefix)
20
+ }
21
+
22
+ return bindings
23
+ }
24
+
25
+ /**
26
+ * Convert a single TanStack AI tool to a ToolBinding
27
+ *
28
+ * @param tool - Tool to convert
29
+ * @param prefix - Optional prefix to add to binding name (e.g., 'external_')
30
+ * @throws Error if the tool doesn't have an execute function
31
+ */
32
+ export function toolToBinding(
33
+ tool: CodeModeTool,
34
+ prefix: string = '',
35
+ ): ToolBinding {
36
+ // Convert schemas (Zod or Standard Schema) to JSON Schema
37
+ const inputSchema = convertSchemaToJsonSchema(tool.inputSchema) || {
38
+ type: 'object',
39
+ properties: {},
40
+ }
41
+
42
+ const outputSchema = tool.outputSchema
43
+ ? convertSchemaToJsonSchema(tool.outputSchema)
44
+ : undefined
45
+
46
+ // Get execute function
47
+ // ServerTool has execute, ToolDefinition (without .server()) does not
48
+ let execute: (
49
+ args: unknown,
50
+ context?: ToolExecutionContext,
51
+ ) => Promise<unknown>
52
+
53
+ if ('execute' in tool && typeof tool.execute === 'function') {
54
+ const toolExecute = tool.execute
55
+ execute = (args: unknown, context?: ToolExecutionContext) => {
56
+ // Pass context to the underlying tool so it can emit custom events
57
+ return Promise.resolve(toolExecute(args, context))
58
+ }
59
+ } else if ('__toolSide' in tool && tool.__toolSide === 'definition') {
60
+ throw new Error(
61
+ `Tool "${tool.name}" is a ToolDefinition without an execute function. ` +
62
+ `Call .server(fn) to provide an implementation before using with Code Mode.`,
63
+ )
64
+ } else {
65
+ throw new Error(
66
+ `Tool "${tool.name}" does not have an execute function. ` +
67
+ `Code Mode requires tools with implementations.`,
68
+ )
69
+ }
70
+
71
+ return {
72
+ name: `${prefix}${tool.name}`,
73
+ description: tool.description,
74
+ inputSchema,
75
+ outputSchema,
76
+ execute,
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Create event-aware bindings that emit custom events for each external function call.
82
+ * Wraps each binding's execute function to emit events before and after execution.
83
+ *
84
+ * @param bindings - Original tool bindings
85
+ * @param emitCustomEvent - Callback to emit custom events to the stream
86
+ */
87
+ export function createEventAwareBindings(
88
+ bindings: Record<string, ToolBinding>,
89
+ emitCustomEvent: (eventName: string, data: Record<string, any>) => void,
90
+ ): Record<string, ToolBinding> {
91
+ const wrapped: Record<string, ToolBinding> = {}
92
+
93
+ for (const [name, binding] of Object.entries(bindings)) {
94
+ wrapped[name] = {
95
+ ...binding,
96
+ execute: async (args: unknown) => {
97
+ // Emit call event
98
+ emitCustomEvent('code_mode:external_call', {
99
+ function: name,
100
+ args,
101
+ timestamp: Date.now(),
102
+ })
103
+
104
+ const startTime = Date.now()
105
+ try {
106
+ // Create context for the underlying tool so it can also emit events
107
+ const toolContext: ToolExecutionContext = { emitCustomEvent }
108
+ const result = await binding.execute(args, toolContext)
109
+
110
+ // Emit result event
111
+ emitCustomEvent('code_mode:external_result', {
112
+ function: name,
113
+ result,
114
+ duration: Date.now() - startTime,
115
+ })
116
+
117
+ return result
118
+ } catch (error) {
119
+ // Emit error event
120
+ emitCustomEvent('code_mode:external_error', {
121
+ function: name,
122
+ error: error instanceof Error ? error.message : String(error),
123
+ duration: Date.now() - startTime,
124
+ })
125
+ throw error
126
+ }
127
+ },
128
+ }
129
+ }
130
+
131
+ return wrapped
132
+ }
@@ -0,0 +1,24 @@
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 function wrapCode(code: string): string {
10
+ // Results must be serialized to JSON because objects can't be transferred
11
+ // directly across the isolate boundary in isolated-vm
12
+ return `
13
+ (async function() {
14
+ try {
15
+ const __userResult = await (async function() {
16
+ ${code}
17
+ })();
18
+ return JSON.stringify(__userResult);
19
+ } catch (__error) {
20
+ throw __error;
21
+ }
22
+ })()
23
+ `
24
+ }
@@ -0,0 +1,254 @@
1
+ import { z } from 'zod'
2
+ import { toolDefinition } from '@tanstack/ai'
3
+ import {
4
+ createEventAwareBindings,
5
+ toolsToBindings,
6
+ } from './bindings/tool-to-binding'
7
+ import { stripTypeScript } from './strip-typescript'
8
+ import type { ServerTool, ToolExecutionContext } from '@tanstack/ai'
9
+ import type {
10
+ CodeModeTool,
11
+ CodeModeToolConfig,
12
+ CodeModeToolResult,
13
+ IsolateContext,
14
+ } from './types'
15
+
16
+ /**
17
+ * Schema for the execute_typescript tool input
18
+ */
19
+ const executeTypescriptInputSchema = z.object({
20
+ typescriptCode: z
21
+ .string()
22
+ .describe(
23
+ 'TypeScript code to execute in the sandbox. ' +
24
+ 'Use external_* functions to call available APIs. ' +
25
+ 'Return a value to pass results back.',
26
+ ),
27
+ })
28
+
29
+ /**
30
+ * Schema for the execute_typescript tool output
31
+ */
32
+ const executeTypescriptOutputSchema = z.object({
33
+ success: z.boolean().describe('Whether execution completed without errors'),
34
+ result: z
35
+ .unknown()
36
+ .optional()
37
+ .describe('Return value from the executed code'),
38
+ logs: z
39
+ .array(z.string())
40
+ .optional()
41
+ .describe('Console output captured during execution'),
42
+ error: z
43
+ .object({
44
+ message: z.string(),
45
+ name: z.string().optional(),
46
+ line: z.number().optional(),
47
+ })
48
+ .optional()
49
+ .describe('Error details if execution failed'),
50
+ })
51
+
52
+ export type ExecuteTypescriptInput = z.infer<
53
+ typeof executeTypescriptInputSchema
54
+ >
55
+ export type ExecuteTypescriptOutput = z.infer<
56
+ typeof executeTypescriptOutputSchema
57
+ >
58
+
59
+ /**
60
+ * Create an execute_typescript tool that can be used alongside other agent tools.
61
+ *
62
+ * This tool allows an LLM to execute TypeScript code in a secure sandbox.
63
+ * Tools passed in the config become `external_*` functions available inside the sandbox.
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * import { createCodeMode } from '@tanstack/ai-code-mode'
68
+ * import { createNodeIsolateDriver } from '@tanstack/ai-isolate-node'
69
+ *
70
+ * const { tool, systemPrompt } = createCodeMode({
71
+ * driver: createNodeIsolateDriver(),
72
+ * tools: [weatherTool, dbTool], // Become external_fetchWeather, external_dbQuery
73
+ * timeout: 30000,
74
+ * })
75
+ *
76
+ * chat({
77
+ * systemPrompts: [myPrompt, systemPrompt],
78
+ * tools: [tool, searchTool, emailTool],
79
+ * messages,
80
+ * })
81
+ * ```
82
+ */
83
+ export function createCodeModeTool(
84
+ config: CodeModeToolConfig,
85
+ ): ServerTool<
86
+ typeof executeTypescriptInputSchema,
87
+ typeof executeTypescriptOutputSchema,
88
+ 'execute_typescript'
89
+ > {
90
+ const {
91
+ driver,
92
+ tools,
93
+ timeout = 30000,
94
+ memoryLimit = 128,
95
+ getSkillBindings,
96
+ } = config
97
+
98
+ // Validate tools
99
+ if (tools.length === 0) {
100
+ throw new Error('At least one tool must be provided to createCodeModeTool')
101
+ }
102
+
103
+ // Transform tools to bindings with external_ prefix (static bindings)
104
+ const staticBindings = toolsToBindings(tools, 'external_')
105
+
106
+ // Create the tool definition
107
+ const definition = toolDefinition({
108
+ name: 'execute_typescript' as const,
109
+ description: buildToolDescription(tools),
110
+ inputSchema: executeTypescriptInputSchema,
111
+ outputSchema: executeTypescriptOutputSchema,
112
+ })
113
+
114
+ // Return server tool with execute function that accepts context
115
+ return definition.server(
116
+ async (
117
+ input,
118
+ toolContext?: ToolExecutionContext,
119
+ ): Promise<CodeModeToolResult> => {
120
+ const { typescriptCode } = input
121
+
122
+ // Get emitCustomEvent from context or use no-op
123
+ const emitCustomEvent = toolContext?.emitCustomEvent || (() => {})
124
+
125
+ if (!typescriptCode || typeof typescriptCode !== 'string') {
126
+ return {
127
+ success: false,
128
+ error: {
129
+ message: 'typescriptCode must be a non-empty string',
130
+ name: 'ValidationError',
131
+ },
132
+ }
133
+ }
134
+
135
+ // Create a fresh sandbox context for this execution
136
+ let isolateContext: IsolateContext | null = null
137
+
138
+ // Emit execution started event immediately
139
+ emitCustomEvent('code_mode:execution_started', {
140
+ timestamp: Date.now(),
141
+ codeLength: typescriptCode.length,
142
+ })
143
+
144
+ try {
145
+ // Step 1: Strip TypeScript (also serves as syntax validation via esbuild)
146
+ let strippedCode: string
147
+ try {
148
+ strippedCode = await stripTypeScript(typescriptCode)
149
+ } catch (error) {
150
+ // Type/syntax error from esbuild
151
+ return {
152
+ success: false,
153
+ error: {
154
+ message: error instanceof Error ? error.message : String(error),
155
+ name: 'TypeScriptError',
156
+ },
157
+ }
158
+ }
159
+
160
+ // Step 2: Get dynamic skill bindings if available
161
+ const skillBindings = getSkillBindings ? await getSkillBindings() : {}
162
+
163
+ // Step 3: Merge static and dynamic bindings, then wrap with event awareness
164
+ const allBindings = { ...staticBindings, ...skillBindings }
165
+ const eventAwareBindings = createEventAwareBindings(
166
+ allBindings,
167
+ emitCustomEvent,
168
+ )
169
+
170
+ // Step 4: Create sandbox context with event-aware bindings
171
+ isolateContext = await driver.createContext({
172
+ bindings: eventAwareBindings,
173
+ timeout,
174
+ memoryLimit,
175
+ })
176
+
177
+ // Step 5: Execute the code in the sandbox
178
+ const executionResult = await isolateContext.execute(strippedCode)
179
+
180
+ // Emit console logs as custom events
181
+ if (executionResult.logs && executionResult.logs.length > 0) {
182
+ for (const log of executionResult.logs) {
183
+ // Parse log level from prefix (added by sandbox console implementation)
184
+ let level: 'log' | 'warn' | 'error' | 'info' = 'log'
185
+ let message = log
186
+
187
+ if (log.startsWith('ERROR: ')) {
188
+ level = 'error'
189
+ message = log.slice(7)
190
+ } else if (log.startsWith('WARN: ')) {
191
+ level = 'warn'
192
+ message = log.slice(6)
193
+ } else if (log.startsWith('INFO: ')) {
194
+ level = 'info'
195
+ message = log.slice(6)
196
+ }
197
+
198
+ emitCustomEvent('code_mode:console', {
199
+ level,
200
+ message,
201
+ timestamp: Date.now(),
202
+ })
203
+ }
204
+ }
205
+
206
+ if (executionResult.success) {
207
+ return {
208
+ success: true,
209
+ result: executionResult.value,
210
+ logs: executionResult.logs,
211
+ }
212
+ } else {
213
+ return {
214
+ success: false,
215
+ error: executionResult.error
216
+ ? {
217
+ message: executionResult.error.message,
218
+ name: executionResult.error.name,
219
+ }
220
+ : { message: 'Unknown execution error' },
221
+ logs: executionResult.logs,
222
+ }
223
+ }
224
+ } catch (error) {
225
+ return {
226
+ success: false,
227
+ error: {
228
+ message: error instanceof Error ? error.message : String(error),
229
+ name: error instanceof Error ? error.name : 'Error',
230
+ },
231
+ }
232
+ } finally {
233
+ // Always clean up the sandbox context
234
+ if (isolateContext) {
235
+ await isolateContext.dispose()
236
+ }
237
+ }
238
+ },
239
+ )
240
+ }
241
+
242
+ /**
243
+ * Build the tool description including available external functions
244
+ */
245
+ function buildToolDescription(tools: Array<CodeModeTool>): string {
246
+ const externalFunctions = tools.map((t) => `external_${t.name}`).join(', ')
247
+
248
+ return (
249
+ `Execute TypeScript code in a secure sandbox environment. ` +
250
+ `The code can use these external API functions: ${externalFunctions}. ` +
251
+ `All external_* calls are async and must be awaited. ` +
252
+ `Return a value to pass results back. Use console.log() for debugging.`
253
+ )
254
+ }
@@ -0,0 +1,35 @@
1
+ import { createCodeModeTool } from './create-code-mode-tool'
2
+ import { createCodeModeSystemPrompt } from './create-system-prompt'
3
+ import type { CodeModeToolConfig } from './types'
4
+
5
+ /**
6
+ * Create both the `execute_typescript` tool and its matching system prompt
7
+ * from a single config object.
8
+ *
9
+ * This is the recommended way to set up Code Mode — it ensures the tool and
10
+ * system prompt always stay in sync.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * import { createCodeMode } from '@tanstack/ai-code-mode'
15
+ * import { createNodeIsolateDriver } from '@tanstack/ai-isolate-node'
16
+ *
17
+ * const { tool, systemPrompt } = createCodeMode({
18
+ * driver: createNodeIsolateDriver(),
19
+ * tools: [weatherTool, dbTool],
20
+ * timeout: 30000,
21
+ * })
22
+ *
23
+ * chat({
24
+ * systemPrompts: [myPrompt, systemPrompt],
25
+ * tools: [tool, ...otherTools],
26
+ * messages,
27
+ * })
28
+ * ```
29
+ */
30
+ export function createCodeMode(config: CodeModeToolConfig) {
31
+ return {
32
+ tool: createCodeModeTool(config),
33
+ systemPrompt: createCodeModeSystemPrompt(config),
34
+ }
35
+ }
@@ -0,0 +1,95 @@
1
+ import { toolsToBindings } from './bindings/tool-to-binding'
2
+ import { generateTypeStubs } from './type-generator/json-schema-to-ts'
3
+ import type { CodeModeToolConfig } from './types'
4
+
5
+ /**
6
+ * Create a system prompt snippet that documents the execute_typescript tool
7
+ * and all available external_* functions.
8
+ *
9
+ * Add this to your system prompts array when using createCodeModeTool.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * import { createCodeMode } from '@tanstack/ai-code-mode'
14
+ * import { createNodeIsolateDriver } from '@tanstack/ai-isolate-node'
15
+ *
16
+ * const { tool, systemPrompt } = createCodeMode({
17
+ * driver: createNodeIsolateDriver(),
18
+ * tools: [weatherTool, dbTool],
19
+ * })
20
+ *
21
+ * chat({
22
+ * systemPrompts: ['You are a helpful assistant.', systemPrompt],
23
+ * tools: [tool, ...otherTools],
24
+ * })
25
+ * ```
26
+ */
27
+ export function createCodeModeSystemPrompt(config: CodeModeToolConfig): string {
28
+ const { tools } = config
29
+
30
+ // Transform tools to bindings with external_ prefix to generate correct type stubs
31
+ const bindings = toolsToBindings(tools, 'external_')
32
+
33
+ // Generate TypeScript type stubs for the external functions
34
+ const typeStubs = generateTypeStubs(bindings)
35
+
36
+ // Build function documentation
37
+ const functionDocs = Object.entries(bindings)
38
+ .map(([name, binding]) => {
39
+ const doc = `- \`${name}(input)\`: ${binding.description}`
40
+ return doc
41
+ })
42
+ .join('\n')
43
+
44
+ return `## Code Execution Tool
45
+
46
+ You have access to \`execute_typescript\` which runs TypeScript code in a sandboxed environment.
47
+
48
+ ### When to Use
49
+
50
+ Use \`execute_typescript\` when you need to:
51
+ - Process data with loops, conditionals, or complex logic
52
+ - Make multiple API calls in parallel (Promise.all)
53
+ - Transform, filter, or aggregate data
54
+ - Perform calculations or data analysis
55
+
56
+ For simple operations, prefer calling tools directly.
57
+
58
+ ### Available External APIs
59
+
60
+ Inside your TypeScript code, you can call these async functions:
61
+
62
+ ${functionDocs}
63
+
64
+ ### Type Definitions
65
+
66
+ \`\`\`typescript
67
+ ${typeStubs}
68
+ \`\`\`
69
+
70
+ ### Example
71
+
72
+ \`\`\`typescript
73
+ // Fetch weather for multiple cities in parallel
74
+ const cities = ["Tokyo", "Paris", "NYC"];
75
+ const results = await Promise.all(
76
+ cities.map(city => external_fetchWeather({ location: city }))
77
+ );
78
+
79
+ // Find the warmest city
80
+ const warmest = results.reduce((prev, curr) =>
81
+ curr.temperature > prev.temperature ? curr : prev
82
+ );
83
+
84
+ return { warmestCity: warmest.location, temperature: warmest.temperature };
85
+ \`\`\`
86
+
87
+ ### Important Notes
88
+
89
+ - All \`external_*\` calls are async - always use \`await\`
90
+ - Return a value to pass results back to you
91
+ - Use \`console.log()\` for debugging (logs are captured)
92
+ - The sandbox is isolated - no network access or file system
93
+ - Each execution is independent (no shared state between calls)
94
+ `
95
+ }
package/src/index.ts ADDED
@@ -0,0 +1,55 @@
1
+ // Code Mode Tool API
2
+ export { createCodeModeTool } from './create-code-mode-tool'
3
+ export type {
4
+ ExecuteTypescriptInput,
5
+ ExecuteTypescriptOutput,
6
+ } from './create-code-mode-tool'
7
+
8
+ export { createCodeModeSystemPrompt } from './create-system-prompt'
9
+ export { createCodeMode } from './create-code-mode'
10
+
11
+ export {
12
+ InMemoryAgentStore,
13
+ generateAgentName,
14
+ type AgentSession,
15
+ type AgentStore,
16
+ } from './agent-store'
17
+
18
+ // Bindings utilities (useful for custom implementations)
19
+ export {
20
+ toolToBinding,
21
+ toolsToBindings,
22
+ createEventAwareBindings,
23
+ } from './bindings/tool-to-binding'
24
+
25
+ // Type generator (useful for custom system prompts)
26
+ export {
27
+ generateTypeStubs,
28
+ jsonSchemaToTypeScript,
29
+ type TypeGeneratorOptions,
30
+ } from './type-generator/json-schema-to-ts'
31
+
32
+ // TypeScript stripping utility
33
+ export { stripTypeScript } from './strip-typescript'
34
+
35
+ // Code wrapper utility (used by isolate drivers)
36
+ export { wrapCode } from './code-wrapper'
37
+
38
+ // All types
39
+ export type {
40
+ // Tool-based API types
41
+ CodeModeToolConfig,
42
+ CodeModeToolResult,
43
+ // Isolate driver interfaces (used by driver packages)
44
+ IsolateDriver,
45
+ IsolateConfig,
46
+ IsolateContext,
47
+ ExecutionResult,
48
+ NormalizedError,
49
+ // Tool binding (used by driver packages)
50
+ ToolBinding,
51
+ // Tool input types
52
+ CodeModeTool,
53
+ // Re-exported from @tanstack/ai
54
+ ToolExecutionContext,
55
+ } from './types'