@tanstack/ai-code-mode-snippets 0.3.14

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 (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +208 -0
  3. package/dist/esm/code-mode-with-snippets.d.ts +65 -0
  4. package/dist/esm/code-mode-with-snippets.js +145 -0
  5. package/dist/esm/code-mode-with-snippets.js.map +1 -0
  6. package/dist/esm/create-snippet-management-tools.d.ts +40 -0
  7. package/dist/esm/create-snippet-management-tools.js +173 -0
  8. package/dist/esm/create-snippet-management-tools.js.map +1 -0
  9. package/dist/esm/create-snippets-system-prompt.d.ts +22 -0
  10. package/dist/esm/create-snippets-system-prompt.js +234 -0
  11. package/dist/esm/create-snippets-system-prompt.js.map +1 -0
  12. package/dist/esm/generate-snippet-types.d.ts +7 -0
  13. package/dist/esm/generate-snippet-types.js +79 -0
  14. package/dist/esm/generate-snippet-types.js.map +1 -0
  15. package/dist/esm/index.d.ts +14 -0
  16. package/dist/esm/index.js +10 -0
  17. package/dist/esm/select-relevant-snippets.d.ts +29 -0
  18. package/dist/esm/select-relevant-snippets.js +56 -0
  19. package/dist/esm/select-relevant-snippets.js.map +1 -0
  20. package/dist/esm/snippets-to-bindings.d.ts +34 -0
  21. package/dist/esm/snippets-to-bindings.js +74 -0
  22. package/dist/esm/snippets-to-bindings.js.map +1 -0
  23. package/dist/esm/snippets-to-tools.d.ts +74 -0
  24. package/dist/esm/snippets-to-tools.js +147 -0
  25. package/dist/esm/snippets-to-tools.js.map +1 -0
  26. package/dist/esm/storage/file-storage.d.ts +27 -0
  27. package/dist/esm/storage/file-storage.js +155 -0
  28. package/dist/esm/storage/file-storage.js.map +1 -0
  29. package/dist/esm/storage/index.d.ts +3 -0
  30. package/dist/esm/storage/index.js +3 -0
  31. package/dist/esm/storage/memory-storage.d.ts +17 -0
  32. package/dist/esm/storage/memory-storage.js +100 -0
  33. package/dist/esm/storage/memory-storage.js.map +1 -0
  34. package/dist/esm/trust-strategies.d.ts +50 -0
  35. package/dist/esm/trust-strategies.js +73 -0
  36. package/dist/esm/trust-strategies.js.map +1 -0
  37. package/dist/esm/types.d.ts +216 -0
  38. package/package.json +92 -0
  39. package/src/code-mode-with-snippets.ts +210 -0
  40. package/src/create-snippet-management-tools.ts +298 -0
  41. package/src/create-snippets-system-prompt.ts +289 -0
  42. package/src/generate-snippet-types.ts +162 -0
  43. package/src/index.ts +60 -0
  44. package/src/select-relevant-snippets.ts +136 -0
  45. package/src/snippets-to-bindings.ts +135 -0
  46. package/src/snippets-to-tools.ts +325 -0
  47. package/src/storage/file-storage.ts +275 -0
  48. package/src/storage/index.ts +6 -0
  49. package/src/storage/memory-storage.ts +172 -0
  50. package/src/trust-strategies.ts +142 -0
  51. package/src/types.ts +289 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Tanner Linsley
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,208 @@
1
+ # @tanstack/ai-code-mode-snippets
2
+
3
+ Persistent snippet library for TanStack AI Code Mode - LLM-created reusable code snippets.
4
+
5
+ ## Overview
6
+
7
+ The Snippets System extends Code Mode with persistent, LLM-creatable reusable code snippets. Snippets are TypeScript functions that the LLM can create, catalog, and invoke across sessions—enabling compounding capability over time.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ pnpm add @tanstack/ai-code-mode-snippets
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ```typescript
18
+ import {
19
+ codeModeWithSnippets,
20
+ createAlwaysTrustedStrategy,
21
+ } from '@tanstack/ai-code-mode-snippets'
22
+ // Node-only file storage lives behind the `/storage` subpath so the root
23
+ // export stays safe for Worker/browser bundlers.
24
+ import { createFileSnippetStorage } from '@tanstack/ai-code-mode-snippets/storage'
25
+ import { createNodeIsolateDriver } from '@tanstack/ai-isolate-node'
26
+
27
+ // Create snippet storage
28
+ const snippetStorage = createFileSnippetStorage({
29
+ directory: './.snippets',
30
+ trustStrategy: createAlwaysTrustedStrategy(),
31
+ })
32
+
33
+ // Create code mode config
34
+ const codeModeConfig = {
35
+ driver: createNodeIsolateDriver(),
36
+ tools: allTools, // Your external tools
37
+ timeout: 60000,
38
+ memoryLimit: 128,
39
+ }
40
+
41
+ // Build a dynamic registry and system prompt with snippets
42
+ const { toolsRegistry, systemPrompt, selectedSnippets } =
43
+ await codeModeWithSnippets({
44
+ config: codeModeConfig,
45
+ adapter: anthropic('claude-3-haiku'), // Cheap model for snippet selection
46
+ snippets: {
47
+ storage: snippetStorage,
48
+ maxSnippetsInContext: 5,
49
+ },
50
+ messages,
51
+ })
52
+
53
+ // Use in chat
54
+ const stream = chat({
55
+ adapter: anthropic('claude-sonnet-4-20250514'), // Main model
56
+ toolRegistry: toolsRegistry,
57
+ messages,
58
+ systemPrompts: [basePrompt, systemPrompt],
59
+ })
60
+ ```
61
+
62
+ ## Testing
63
+
64
+ This package includes a CLI for testing the snippets system. The tests verify the complete snippets lifecycle:
65
+
66
+ 1. **First run (Snippet Creation)**: LLM uses `execute_typescript` to solve a problem and registers a reusable snippet
67
+ 2. **Second run (Snippet Reuse)**: LLM calls the saved snippet directly without needing `execute_typescript`
68
+
69
+ ### Running the Simulated Test
70
+
71
+ The simulated test uses a mock adapter with predetermined responses for fully deterministic testing. No API key required.
72
+
73
+ ```bash
74
+ # From the package directory
75
+ cd packages/ai-code-mode-snippets
76
+
77
+ # Run the simulated test
78
+ pnpm test:cli:simulated
79
+ ```
80
+
81
+ ### Running the Live Test
82
+
83
+ The live test uses a real LLM (OpenAI or Anthropic) to verify the snippets flow with actual LLM responses.
84
+
85
+ #### Setup
86
+
87
+ 1. Copy the environment example file:
88
+
89
+ ```bash
90
+ cp test-cli/env.example test-cli/.env.local
91
+ ```
92
+
93
+ 2. Edit `test-cli/.env.local` and add your API key:
94
+ ```
95
+ OPENAI_API_KEY=sk-...
96
+ # or
97
+ ANTHROPIC_API_KEY=sk-ant-...
98
+ ```
99
+
100
+ #### Run the test
101
+
102
+ ```bash
103
+ # Run with OpenAI (default)
104
+ pnpm test:cli:live
105
+
106
+ # Run with Anthropic
107
+ pnpm test:cli:live --provider anthropic
108
+
109
+ # Run with a specific model
110
+ pnpm test:cli:live --model gpt-4o-mini
111
+
112
+ # Run with verbose output
113
+ pnpm test:cli:live -v
114
+ ```
115
+
116
+ ### CLI Commands
117
+
118
+ ```bash
119
+ # Show help
120
+ pnpm test:cli --help
121
+
122
+ # Run simulated test (deterministic, no API key)
123
+ pnpm test:cli simulated
124
+
125
+ # Run live test (requires API key)
126
+ pnpm test:cli live [options]
127
+
128
+ Options:
129
+ --provider <provider> LLM provider: openai or anthropic (default: openai)
130
+ --model <model> Model to use (default depends on provider)
131
+ -v, --verbose Enable verbose output
132
+ ```
133
+
134
+ ## API Reference
135
+
136
+ ### `codeModeWithSnippets(options)`
137
+
138
+ Creates Code Mode tools and system prompt with snippets integration.
139
+
140
+ **Options:**
141
+
142
+ - `config` - Code Mode tool configuration (driver, tools, timeout, memoryLimit)
143
+ - `adapter` - Text adapter for snippet selection (should be a cheap/fast model)
144
+ - `snippets.storage` - Snippet storage implementation
145
+ - `snippets.maxSnippetsInContext` - Maximum snippets to load into context (default: 5)
146
+ - `messages` - Current conversation messages
147
+ - `snippetsAsTools` - Whether to include snippets as direct tools (default: true)
148
+
149
+ **Returns:**
150
+
151
+ - `toolsRegistry` - Mutable `ToolRegistry` containing `execute_typescript`, snippet management tools, and selected snippet tools
152
+ - `systemPrompt` - System prompt documenting available snippets and external functions
153
+ - `selectedSnippets` - Snippets that were selected for this request
154
+
155
+ ### Storage
156
+
157
+ The worker/browser-safe in-memory storage (`createMemorySnippetStorage`) is
158
+ re-exported from the root entry. The Node-only file storage
159
+ (`createFileSnippetStorage`) imports `node:fs` / `node:path`, so it is only
160
+ available from the `/storage` subpath — keeping the root export safe to import
161
+ from Cloudflare Workers and browser bundlers:
162
+
163
+ ```typescript
164
+ // Worker/browser-safe — root export
165
+ import { createMemorySnippetStorage } from '@tanstack/ai-code-mode-snippets'
166
+
167
+ // Node-only — `/storage` subpath
168
+ import { createFileSnippetStorage } from '@tanstack/ai-code-mode-snippets/storage'
169
+ ```
170
+
171
+ #### `createFileSnippetStorage(options)`
172
+
173
+ Git-friendly file-based storage:
174
+
175
+ ```text
176
+ .snippets/
177
+ ├── compare_react_state_libraries/
178
+ │ ├── meta.json # Metadata, schemas, stats
179
+ │ └── code.ts # TypeScript implementation
180
+ └── fetch_github_stats/
181
+ ├── meta.json
182
+ └── code.ts
183
+ ```
184
+
185
+ #### `createMemorySnippetStorage(options)`
186
+
187
+ In-memory storage for testing.
188
+
189
+ ### Trust Strategies
190
+
191
+ Snippets track execution success and promote trust levels over time:
192
+
193
+ | Trust Level | Description |
194
+ | ------------- | --------------------------------- |
195
+ | `untrusted` | Newly created, not yet proven |
196
+ | `provisional` | 10+ executions with ≥90% success |
197
+ | `trusted` | 100+ executions with ≥95% success |
198
+
199
+ Available strategies:
200
+
201
+ - `createDefaultTrustStrategy()` - Earn trust through successful executions
202
+ - `createAlwaysTrustedStrategy()` - Trust immediately (dev/testing)
203
+ - `createRelaxedTrustStrategy()` - Faster promotion
204
+ - `createCustomTrustStrategy(options)` - Custom thresholds
205
+
206
+ ## License
207
+
208
+ MIT
@@ -0,0 +1,65 @@
1
+ import { CodeModeWithSnippetsOptions, CodeModeWithSnippetsResult, Snippet } from './types.js';
2
+ import { ToolBinding } from '@tanstack/ai-code-mode';
3
+ export type { CodeModeWithSnippetsOptions, CodeModeWithSnippetsResult };
4
+ /**
5
+ * Create Code Mode tools and system prompt with snippets integration.
6
+ *
7
+ * This function:
8
+ * 1. Loads the snippet index from storage
9
+ * 2. Uses a cheap/fast LLM to select relevant snippets based on conversation context
10
+ * 3. Creates the execute_typescript tool with dynamic snippet bindings
11
+ * 4. Creates snippet management tools (search, get, register)
12
+ * 5. Generates system prompts documenting available snippets
13
+ * 6. Returns a ToolRegistry that allows dynamic snippet additions mid-stream
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * // Node-only file storage lives behind the `/storage` subpath:
18
+ * import { createFileSnippetStorage } from '@tanstack/ai-code-mode-snippets/storage'
19
+ *
20
+ * const { toolsRegistry, systemPrompt, selectedSnippets } = await codeModeWithSnippets({
21
+ * config: {
22
+ * driver: createNodeIsolateDriver(),
23
+ * tools: allTools,
24
+ * timeout: 60000,
25
+ * },
26
+ * adapter: openaiText('gpt-4o-mini'), // Cheap model for selection
27
+ * snippets: {
28
+ * storage: createFileSnippetStorage('./.snippets'),
29
+ * maxSnippetsInContext: 5,
30
+ * },
31
+ * messages,
32
+ * });
33
+ *
34
+ * const stream = chat({
35
+ * adapter: openaiText('gpt-4o'), // Main model
36
+ * toolRegistry: toolsRegistry, // Dynamic tool registry
37
+ * messages,
38
+ * systemPrompts: [BASE_PROMPT, systemPrompt],
39
+ * });
40
+ * ```
41
+ */
42
+ export declare function codeModeWithSnippets({ config, adapter, snippets, messages, snippetsAsTools, }: CodeModeWithSnippetsOptions): Promise<CodeModeWithSnippetsResult>;
43
+ /**
44
+ * Create a Code Mode tool configuration extended with snippets.
45
+ * This is an alternative to codeModeWithSnippets that returns
46
+ * a config object instead of directly creating tools.
47
+ *
48
+ * Useful when you want more control over the tool creation process.
49
+ */
50
+ export declare function createCodeModeWithSnippetsConfig({ config, selectedSnippets, storage, }: {
51
+ config: CodeModeWithSnippetsOptions['config'];
52
+ selectedSnippets: Array<Snippet>;
53
+ storage: CodeModeWithSnippetsOptions['snippets']['storage'];
54
+ }): {
55
+ snippetTools: import('@tanstack/ai').ServerTool<import('@tanstack/ai').SchemaInput, import('@tanstack/ai').SchemaInput, string, unknown, false, undefined>[];
56
+ selectedSnippets: Snippet[];
57
+ driver: import('@tanstack/ai-code-mode').IsolateDriver;
58
+ tools: Array<import('@tanstack/ai-code-mode').CodeModeTool>;
59
+ timeout?: number;
60
+ memoryLimit?: number;
61
+ getSnippetBindings?: () => Promise<Record<string, ToolBinding>>;
62
+ onSecretParameter?: import('@tanstack/ai-code-mode').SecretParameterHandler;
63
+ lazyToolsConfig?: import('@tanstack/ai').LazyToolsConfig;
64
+ transpile?: (code: string) => string | Promise<string>;
65
+ };
@@ -0,0 +1,145 @@
1
+ import { selectRelevantSnippets } from "./select-relevant-snippets.js";
2
+ import { snippetsToTools } from "./snippets-to-tools.js";
3
+ import { createSnippetManagementTools } from "./create-snippet-management-tools.js";
4
+ import { createSnippetsSystemPrompt } from "./create-snippets-system-prompt.js";
5
+ import { createCodeModeSystemPrompt, createCodeModeTool, toolsToBindings } from "@tanstack/ai-code-mode";
6
+ import { createToolRegistry } from "@tanstack/ai";
7
+ //#region src/code-mode-with-snippets.ts
8
+ /**
9
+ * Create Code Mode tools and system prompt with snippets integration.
10
+ *
11
+ * This function:
12
+ * 1. Loads the snippet index from storage
13
+ * 2. Uses a cheap/fast LLM to select relevant snippets based on conversation context
14
+ * 3. Creates the execute_typescript tool with dynamic snippet bindings
15
+ * 4. Creates snippet management tools (search, get, register)
16
+ * 5. Generates system prompts documenting available snippets
17
+ * 6. Returns a ToolRegistry that allows dynamic snippet additions mid-stream
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * // Node-only file storage lives behind the `/storage` subpath:
22
+ * import { createFileSnippetStorage } from '@tanstack/ai-code-mode-snippets/storage'
23
+ *
24
+ * const { toolsRegistry, systemPrompt, selectedSnippets } = await codeModeWithSnippets({
25
+ * config: {
26
+ * driver: createNodeIsolateDriver(),
27
+ * tools: allTools,
28
+ * timeout: 60000,
29
+ * },
30
+ * adapter: openaiText('gpt-4o-mini'), // Cheap model for selection
31
+ * snippets: {
32
+ * storage: createFileSnippetStorage('./.snippets'),
33
+ * maxSnippetsInContext: 5,
34
+ * },
35
+ * messages,
36
+ * });
37
+ *
38
+ * const stream = chat({
39
+ * adapter: openaiText('gpt-4o'), // Main model
40
+ * toolRegistry: toolsRegistry, // Dynamic tool registry
41
+ * messages,
42
+ * systemPrompts: [BASE_PROMPT, systemPrompt],
43
+ * });
44
+ * ```
45
+ */
46
+ async function codeModeWithSnippets({ config, adapter, snippets, messages, snippetsAsTools = true }) {
47
+ const { storage, maxSnippetsInContext = 5 } = snippets;
48
+ const snippetIndex = await storage.loadIndex();
49
+ const selectedSnippets = await selectRelevantSnippets({
50
+ adapter,
51
+ messages,
52
+ snippetIndex,
53
+ maxSnippets: maxSnippetsInContext,
54
+ storage
55
+ });
56
+ const baseBindings = toolsToBindings(config.tools, "external_");
57
+ const codeModeTool = createCodeModeTool({
58
+ ...config,
59
+ getSnippetBindings: async () => {
60
+ const allSnippets = await storage.loadAll();
61
+ const snippetBindings = {};
62
+ for (const snippet of allSnippets) snippetBindings[`snippet_${snippet.name}`] = {
63
+ name: `snippet_${snippet.name}`,
64
+ description: snippet.description,
65
+ inputSchema: snippet.inputSchema,
66
+ outputSchema: snippet.outputSchema,
67
+ execute: async (input) => {
68
+ const wrappedCode = `const input = ${JSON.stringify(input)};\n${snippet.code}`;
69
+ const { stripTypeScript, createEventAwareBindings } = await import("@tanstack/ai-code-mode");
70
+ const strippedCode = await stripTypeScript(wrappedCode);
71
+ const context = await config.driver.createContext({
72
+ bindings: createEventAwareBindings(baseBindings, () => {}),
73
+ timeout: config.timeout,
74
+ ...config.memoryLimit !== void 0 && { memoryLimit: config.memoryLimit }
75
+ });
76
+ try {
77
+ const result = await context.execute(strippedCode);
78
+ if (!result.success) throw new Error(result.error?.message || "Snippet execution failed");
79
+ return result.value;
80
+ } finally {
81
+ await context.dispose();
82
+ }
83
+ }
84
+ };
85
+ return snippetBindings;
86
+ }
87
+ });
88
+ const registry = createToolRegistry();
89
+ registry.add(codeModeTool);
90
+ const snippetManagementTools = createSnippetManagementTools({
91
+ storage,
92
+ registry,
93
+ config,
94
+ baseBindings
95
+ });
96
+ for (const tool of snippetManagementTools) registry.add(tool);
97
+ if (snippetsAsTools && selectedSnippets.length > 0) {
98
+ const snippetToolsList = snippetsToTools({
99
+ snippets: selectedSnippets,
100
+ driver: config.driver,
101
+ tools: config.tools,
102
+ storage,
103
+ timeout: config.timeout,
104
+ memoryLimit: config.memoryLimit
105
+ });
106
+ for (const snippetTool of snippetToolsList) registry.add(snippetTool);
107
+ }
108
+ const basePrompt = createCodeModeSystemPrompt(config);
109
+ const snippetsPrompt = createSnippetsSystemPrompt({
110
+ selectedSnippets,
111
+ totalSnippetCount: snippetIndex.length,
112
+ snippetsAsTools
113
+ });
114
+ return {
115
+ toolsRegistry: registry,
116
+ systemPrompt: basePrompt + "\n\n" + snippetsPrompt,
117
+ selectedSnippets
118
+ };
119
+ }
120
+ /**
121
+ * Create a Code Mode tool configuration extended with snippets.
122
+ * This is an alternative to codeModeWithSnippets that returns
123
+ * a config object instead of directly creating tools.
124
+ *
125
+ * Useful when you want more control over the tool creation process.
126
+ */
127
+ function createCodeModeWithSnippetsConfig({ config, selectedSnippets, storage }) {
128
+ const snippetToolsList = snippetsToTools({
129
+ snippets: selectedSnippets,
130
+ driver: config.driver,
131
+ tools: config.tools,
132
+ storage,
133
+ timeout: config.timeout,
134
+ memoryLimit: config.memoryLimit
135
+ });
136
+ return {
137
+ ...config,
138
+ snippetTools: snippetToolsList,
139
+ selectedSnippets
140
+ };
141
+ }
142
+ //#endregion
143
+ export { codeModeWithSnippets, createCodeModeWithSnippetsConfig };
144
+
145
+ //# sourceMappingURL=code-mode-with-snippets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-mode-with-snippets.js","names":[],"sources":["../../src/code-mode-with-snippets.ts"],"sourcesContent":["import {\n createCodeModeSystemPrompt,\n createCodeModeTool,\n toolsToBindings,\n} from '@tanstack/ai-code-mode'\nimport { createToolRegistry } from '@tanstack/ai'\nimport { selectRelevantSnippets } from './select-relevant-snippets'\nimport { createSnippetManagementTools } from './create-snippet-management-tools'\nimport { createSnippetsSystemPrompt } from './create-snippets-system-prompt'\nimport { snippetsToTools } from './snippets-to-tools'\nimport type {\n CodeModeWithSnippetsOptions,\n CodeModeWithSnippetsResult,\n Snippet,\n} from './types'\nimport type { ToolBinding } from '@tanstack/ai-code-mode'\n\nexport type { CodeModeWithSnippetsOptions, CodeModeWithSnippetsResult }\n\n/**\n * Create Code Mode tools and system prompt with snippets integration.\n *\n * This function:\n * 1. Loads the snippet index from storage\n * 2. Uses a cheap/fast LLM to select relevant snippets based on conversation context\n * 3. Creates the execute_typescript tool with dynamic snippet bindings\n * 4. Creates snippet management tools (search, get, register)\n * 5. Generates system prompts documenting available snippets\n * 6. Returns a ToolRegistry that allows dynamic snippet additions mid-stream\n *\n * @example\n * ```typescript\n * // Node-only file storage lives behind the `/storage` subpath:\n * import { createFileSnippetStorage } from '@tanstack/ai-code-mode-snippets/storage'\n *\n * const { toolsRegistry, systemPrompt, selectedSnippets } = await codeModeWithSnippets({\n * config: {\n * driver: createNodeIsolateDriver(),\n * tools: allTools,\n * timeout: 60000,\n * },\n * adapter: openaiText('gpt-4o-mini'), // Cheap model for selection\n * snippets: {\n * storage: createFileSnippetStorage('./.snippets'),\n * maxSnippetsInContext: 5,\n * },\n * messages,\n * });\n *\n * const stream = chat({\n * adapter: openaiText('gpt-4o'), // Main model\n * toolRegistry: toolsRegistry, // Dynamic tool registry\n * messages,\n * systemPrompts: [BASE_PROMPT, systemPrompt],\n * });\n * ```\n */\nexport async function codeModeWithSnippets({\n config,\n adapter,\n snippets,\n messages,\n snippetsAsTools = true,\n}: CodeModeWithSnippetsOptions): Promise<CodeModeWithSnippetsResult> {\n const { storage, maxSnippetsInContext = 5 } = snippets\n\n // 1. Load the snippet index (lightweight metadata only)\n const snippetIndex = await storage.loadIndex()\n\n // 2. Use adapter to select relevant snippets based on transcript\n const selectedSnippets = await selectRelevantSnippets({\n adapter,\n messages,\n snippetIndex,\n maxSnippets: maxSnippetsInContext,\n storage,\n })\n\n // Pre-compute bindings from base tools (shared across snippet executions)\n const baseBindings = toolsToBindings(config.tools, 'external_')\n\n // 3. Create the execute_typescript tool with dynamic snippet bindings\n const codeModeTool = createCodeModeTool({\n ...config,\n // Dynamic snippet bindings - fetched at execution time\n getSnippetBindings: async () => {\n // Get all snippets from storage (includes newly registered ones)\n const allSnippets = await storage.loadAll()\n // Convert to bindings with snippet_ prefix\n const snippetBindings: Record<string, ToolBinding> = {}\n for (const snippet of allSnippets) {\n // Create a simple binding that executes the snippet code\n snippetBindings[`snippet_${snippet.name}`] = {\n name: `snippet_${snippet.name}`,\n description: snippet.description,\n inputSchema: snippet.inputSchema,\n outputSchema: snippet.outputSchema,\n execute: async (input: unknown) => {\n // This is a simplified execution - the full snippetToTool handles events\n const wrappedCode = `const input = ${JSON.stringify(input)};\\n${snippet.code}`\n const { stripTypeScript, createEventAwareBindings } =\n await import('@tanstack/ai-code-mode')\n const strippedCode = await stripTypeScript(wrappedCode)\n const context = await config.driver.createContext({\n bindings: createEventAwareBindings(baseBindings, () => {}),\n timeout: config.timeout,\n ...(config.memoryLimit !== undefined && {\n memoryLimit: config.memoryLimit,\n }),\n })\n try {\n const result = await context.execute(strippedCode)\n if (!result.success) {\n throw new Error(\n result.error?.message || 'Snippet execution failed',\n )\n }\n return result.value\n } finally {\n await context.dispose()\n }\n },\n }\n }\n return snippetBindings\n },\n })\n\n // 4. Create a mutable tool registry\n const registry = createToolRegistry()\n\n // 5. Add the execute_typescript tool to the registry\n registry.add(codeModeTool)\n\n // 6. Create snippet management tools (they need access to the registry)\n const snippetManagementTools = createSnippetManagementTools({\n storage,\n registry,\n config,\n baseBindings,\n })\n\n for (const tool of snippetManagementTools) {\n registry.add(tool)\n }\n\n // 7. Convert selected snippets to direct tools and add to registry (if enabled)\n if (snippetsAsTools && selectedSnippets.length > 0) {\n const snippetToolsList = snippetsToTools({\n snippets: selectedSnippets,\n driver: config.driver,\n tools: config.tools,\n storage,\n timeout: config.timeout,\n memoryLimit: config.memoryLimit,\n })\n\n for (const snippetTool of snippetToolsList) {\n registry.add(snippetTool)\n }\n }\n\n // 8. Generate combined system prompt\n const basePrompt = createCodeModeSystemPrompt(config)\n const snippetsPrompt = createSnippetsSystemPrompt({\n selectedSnippets,\n totalSnippetCount: snippetIndex.length,\n snippetsAsTools,\n })\n const systemPrompt = basePrompt + '\\n\\n' + snippetsPrompt\n\n return {\n toolsRegistry: registry,\n systemPrompt,\n selectedSnippets,\n }\n}\n\n/**\n * Create a Code Mode tool configuration extended with snippets.\n * This is an alternative to codeModeWithSnippets that returns\n * a config object instead of directly creating tools.\n *\n * Useful when you want more control over the tool creation process.\n */\nexport function createCodeModeWithSnippetsConfig({\n config,\n selectedSnippets,\n storage,\n}: {\n config: CodeModeWithSnippetsOptions['config']\n selectedSnippets: Array<Snippet>\n storage: CodeModeWithSnippetsOptions['snippets']['storage']\n}) {\n // Create snippet tools for direct calling\n const snippetToolsList = snippetsToTools({\n snippets: selectedSnippets,\n driver: config.driver,\n tools: config.tools,\n storage,\n timeout: config.timeout,\n memoryLimit: config.memoryLimit,\n })\n\n return {\n ...config,\n snippetTools: snippetToolsList,\n selectedSnippets,\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyDA,eAAsB,qBAAqB,EACzC,QACA,SACA,UACA,UACA,kBAAkB,QACiD;CACnE,MAAM,EAAE,SAAS,uBAAuB,MAAM;CAG9C,MAAM,eAAe,MAAM,QAAQ,UAAU;CAG7C,MAAM,mBAAmB,MAAM,uBAAuB;EACpD;EACA;EACA;EACA,aAAa;EACb;CACF,CAAC;CAGD,MAAM,eAAe,gBAAgB,OAAO,OAAO,WAAW;CAG9D,MAAM,eAAe,mBAAmB;EACtC,GAAG;EAEH,oBAAoB,YAAY;GAE9B,MAAM,cAAc,MAAM,QAAQ,QAAQ;GAE1C,MAAM,kBAA+C,CAAC;GACtD,KAAK,MAAM,WAAW,aAEpB,gBAAgB,WAAW,QAAQ,UAAU;IAC3C,MAAM,WAAW,QAAQ;IACzB,aAAa,QAAQ;IACrB,aAAa,QAAQ;IACrB,cAAc,QAAQ;IACtB,SAAS,OAAO,UAAmB;KAEjC,MAAM,cAAc,iBAAiB,KAAK,UAAU,KAAK,EAAE,KAAK,QAAQ;KACxE,MAAM,EAAE,iBAAiB,6BACvB,MAAM,OAAO;KACf,MAAM,eAAe,MAAM,gBAAgB,WAAW;KACtD,MAAM,UAAU,MAAM,OAAO,OAAO,cAAc;MAChD,UAAU,yBAAyB,oBAAoB,CAAC,CAAC;MACzD,SAAS,OAAO;MAChB,GAAI,OAAO,gBAAgB,KAAA,KAAa,EACtC,aAAa,OAAO,YACtB;KACF,CAAC;KACD,IAAI;MACF,MAAM,SAAS,MAAM,QAAQ,QAAQ,YAAY;MACjD,IAAI,CAAC,OAAO,SACV,MAAM,IAAI,MACR,OAAO,OAAO,WAAW,0BAC3B;MAEF,OAAO,OAAO;KAChB,UAAU;MACR,MAAM,QAAQ,QAAQ;KACxB;IACF;GACF;GAEF,OAAO;EACT;CACF,CAAC;CAGD,MAAM,WAAW,mBAAmB;CAGpC,SAAS,IAAI,YAAY;CAGzB,MAAM,yBAAyB,6BAA6B;EAC1D;EACA;EACA;EACA;CACF,CAAC;CAED,KAAK,MAAM,QAAQ,wBACjB,SAAS,IAAI,IAAI;CAInB,IAAI,mBAAmB,iBAAiB,SAAS,GAAG;EAClD,MAAM,mBAAmB,gBAAgB;GACvC,UAAU;GACV,QAAQ,OAAO;GACf,OAAO,OAAO;GACd;GACA,SAAS,OAAO;GAChB,aAAa,OAAO;EACtB,CAAC;EAED,KAAK,MAAM,eAAe,kBACxB,SAAS,IAAI,WAAW;CAE5B;CAGA,MAAM,aAAa,2BAA2B,MAAM;CACpD,MAAM,iBAAiB,2BAA2B;EAChD;EACA,mBAAmB,aAAa;EAChC;CACF,CAAC;CAGD,OAAO;EACL,eAAe;EACf,cAJmB,aAAa,SAAS;EAKzC;CACF;AACF;;;;;;;;AASA,SAAgB,iCAAiC,EAC/C,QACA,kBACA,WAKC;CAED,MAAM,mBAAmB,gBAAgB;EACvC,UAAU;EACV,QAAQ,OAAO;EACf,OAAO,OAAO;EACd;EACA,SAAS,OAAO;EAChB,aAAa,OAAO;CACtB,CAAC;CAED,OAAO;EACL,GAAG;EACH,cAAc;EACd;CACF;AACF"}
@@ -0,0 +1,40 @@
1
+ import { SchemaInput, ServerTool, ToolRegistry } from '@tanstack/ai';
2
+ import { CodeModeToolConfig, ToolBinding } from '@tanstack/ai-code-mode';
3
+ import { SnippetStorage } from './types.js';
4
+ import { TrustStrategy } from './trust-strategies.js';
5
+ interface CreateSnippetManagementToolsOptions {
6
+ /**
7
+ * Storage implementation for snippets
8
+ */
9
+ storage: SnippetStorage;
10
+ /**
11
+ * Trust strategy for determining initial trust level.
12
+ * If not provided, uses the storage's trustStrategy or falls back to default.
13
+ */
14
+ trustStrategy?: TrustStrategy;
15
+ /**
16
+ * Tool registry for adding newly registered snippets immediately.
17
+ * When provided, register_snippet will add the new snippet to this registry
18
+ * so it's available as a direct tool in the current chat session.
19
+ */
20
+ registry?: ToolRegistry;
21
+ /**
22
+ * Code mode config for creating snippet tools.
23
+ * Required when registry is provided.
24
+ */
25
+ config?: CodeModeToolConfig;
26
+ /**
27
+ * Pre-computed bindings for external_* functions.
28
+ * Required when registry is provided.
29
+ */
30
+ baseBindings?: Record<string, ToolBinding>;
31
+ }
32
+ /**
33
+ * Create tools for searching, retrieving, and registering snippets.
34
+ * These tools allow the LLM to interact with the snippet library at runtime.
35
+ *
36
+ * When registry, config, and baseBindings are provided, newly registered snippets
37
+ * will be immediately added to the registry and available as direct tools.
38
+ */
39
+ export declare function createSnippetManagementTools({ storage, trustStrategy, registry, config, baseBindings, }: CreateSnippetManagementToolsOptions): Array<ServerTool<SchemaInput, SchemaInput, string>>;
40
+ export {};
@@ -0,0 +1,173 @@
1
+ import { createDefaultTrustStrategy } from "./trust-strategies.js";
2
+ import { snippetToTool } from "./snippets-to-tools.js";
3
+ import { toolsToBindings } from "@tanstack/ai-code-mode";
4
+ import { toolDefinition } from "@tanstack/ai";
5
+ import { z } from "zod";
6
+ //#region src/create-snippet-management-tools.ts
7
+ /**
8
+ * Create tools for searching, retrieving, and registering snippets.
9
+ * These tools allow the LLM to interact with the snippet library at runtime.
10
+ *
11
+ * When registry, config, and baseBindings are provided, newly registered snippets
12
+ * will be immediately added to the registry and available as direct tools.
13
+ */
14
+ function createSnippetManagementTools({ storage, trustStrategy, registry, config, baseBindings }) {
15
+ const strategy = trustStrategy ?? storage.trustStrategy ?? createDefaultTrustStrategy();
16
+ const bindings = baseBindings ?? (config ? toolsToBindings(config.tools, "external_") : {});
17
+ return [
18
+ toolDefinition({
19
+ name: "search_snippets",
20
+ description: "Search the snippet library for reusable snippets. Use this to find snippets that can help accomplish a task. Returns matching snippets with their descriptions.",
21
+ inputSchema: z.object({
22
+ query: z.string().describe("Search query describing what you want to accomplish"),
23
+ limit: z.number().optional().default(5).describe("Maximum number of results (default: 5)")
24
+ }),
25
+ outputSchema: z.array(z.object({
26
+ name: z.string(),
27
+ description: z.string(),
28
+ usageHints: z.array(z.string()),
29
+ trustLevel: z.enum([
30
+ "untrusted",
31
+ "provisional",
32
+ "trusted"
33
+ ])
34
+ }))
35
+ }).server(async ({ query, limit }) => {
36
+ return (await storage.search(query, { limit: limit ?? 5 })).map((s) => ({
37
+ name: s.name,
38
+ description: s.description,
39
+ usageHints: s.usageHints,
40
+ trustLevel: s.trustLevel
41
+ }));
42
+ }),
43
+ toolDefinition({
44
+ name: "get_snippet",
45
+ description: "Get the full implementation details of a snippet, including its code. Use this after search_snippets to see how a snippet works before using it.",
46
+ inputSchema: z.object({ name: z.string().describe("The snippet name (without snippet_ prefix)") }),
47
+ outputSchema: z.object({
48
+ name: z.string().optional(),
49
+ description: z.string().optional(),
50
+ code: z.string().optional(),
51
+ inputSchema: z.string().optional().describe("JSON Schema as string"),
52
+ outputSchema: z.string().optional().describe("JSON Schema as string"),
53
+ usageHints: z.array(z.string()).optional(),
54
+ dependsOn: z.array(z.string()).optional(),
55
+ trustLevel: z.enum([
56
+ "untrusted",
57
+ "provisional",
58
+ "trusted"
59
+ ]).optional(),
60
+ stats: z.object({
61
+ executions: z.number(),
62
+ successRate: z.number()
63
+ }).optional(),
64
+ error: z.string().optional()
65
+ })
66
+ }).server(async ({ name }) => {
67
+ const snippet = await storage.get(name);
68
+ if (!snippet) return { error: `Snippet '${name}' not found` };
69
+ return {
70
+ name: snippet.name,
71
+ description: snippet.description,
72
+ code: snippet.code,
73
+ inputSchema: JSON.stringify(snippet.inputSchema),
74
+ outputSchema: JSON.stringify(snippet.outputSchema),
75
+ usageHints: snippet.usageHints,
76
+ dependsOn: snippet.dependsOn,
77
+ trustLevel: snippet.trustLevel,
78
+ stats: snippet.stats
79
+ };
80
+ }),
81
+ toolDefinition({
82
+ name: "register_snippet",
83
+ description: "Save working TypeScript code as a reusable snippet for future use. Only register code that has been tested and works correctly. The snippet becomes available as a callable tool immediately.",
84
+ inputSchema: z.object({
85
+ name: z.string().regex(/^[a-z][a-z0-9_]*$/, "Must be snake_case starting with a letter").describe("Unique snippet name in snake_case (e.g., fetch_github_stats)"),
86
+ description: z.string().describe("Clear description of what the snippet does"),
87
+ code: z.string().describe("The TypeScript code. Receives `input` variable, can call external_* and snippet_* functions, should return a value."),
88
+ inputSchema: z.string().describe("JSON Schema as a JSON string describing the input parameter, e.g. {\"type\":\"object\",\"properties\":{\"a\":{\"type\":\"number\"}},\"required\":[\"a\"]}"),
89
+ outputSchema: z.string().describe("JSON Schema as a JSON string describing the return value, e.g. {\"type\":\"object\",\"properties\":{\"result\":{\"type\":\"number\"}}}"),
90
+ usageHints: z.array(z.string()).describe("Hints about when to use this snippet, e.g. \"Use when user asks about...\""),
91
+ dependsOn: z.array(z.string()).optional().default([]).describe("Names of other snippets this snippet calls")
92
+ }),
93
+ outputSchema: z.object({
94
+ success: z.boolean().optional(),
95
+ snippetId: z.string().optional(),
96
+ name: z.string().optional(),
97
+ message: z.string().optional(),
98
+ error: z.string().optional()
99
+ })
100
+ }).server(async (rawSnippetDef, context) => {
101
+ let inputSchema;
102
+ let outputSchema;
103
+ try {
104
+ inputSchema = JSON.parse(rawSnippetDef.inputSchema);
105
+ } catch {
106
+ return { error: "inputSchema must be a valid JSON string" };
107
+ }
108
+ try {
109
+ outputSchema = JSON.parse(rawSnippetDef.outputSchema);
110
+ } catch {
111
+ return { error: "outputSchema must be a valid JSON string" };
112
+ }
113
+ const snippetDef = {
114
+ ...rawSnippetDef,
115
+ inputSchema,
116
+ outputSchema
117
+ };
118
+ try {
119
+ if (snippetDef.name.startsWith("external_")) return { error: "Snippet names cannot start with 'external_'" };
120
+ if (snippetDef.name.startsWith("snippet_")) return { error: "Snippet names should not include the 'snippet_' prefix - it will be added automatically" };
121
+ if (await storage.get(snippetDef.name)) return { error: `Snippet '${snippetDef.name}' already exists. Use a different name or update the existing snippet.` };
122
+ const id = crypto.randomUUID();
123
+ const initialTrustLevel = strategy.getInitialTrustLevel();
124
+ const snippet = await storage.save({
125
+ id,
126
+ name: snippetDef.name,
127
+ description: snippetDef.description,
128
+ code: snippetDef.code,
129
+ inputSchema: snippetDef.inputSchema,
130
+ outputSchema: snippetDef.outputSchema,
131
+ usageHints: snippetDef.usageHints,
132
+ dependsOn: snippetDef.dependsOn ?? [],
133
+ trustLevel: initialTrustLevel,
134
+ stats: {
135
+ executions: 0,
136
+ successRate: 0
137
+ }
138
+ });
139
+ if (registry && config) {
140
+ const snippetTool = snippetToTool({
141
+ snippet,
142
+ driver: config.driver,
143
+ bindings,
144
+ storage,
145
+ timeout: config.timeout,
146
+ memoryLimit: config.memoryLimit
147
+ });
148
+ registry.add(snippetTool);
149
+ console.log(`[register_snippet] Added snippet '${snippet.name}' to registry immediately`);
150
+ }
151
+ context?.emitCustomEvent("snippet:registered", {
152
+ id: snippet.id,
153
+ name: snippet.name,
154
+ description: snippet.description,
155
+ timestamp: Date.now()
156
+ });
157
+ return {
158
+ success: true,
159
+ snippetId: snippet.id,
160
+ name: snippet.name,
161
+ message: `Snippet '${snippet.name}' registered successfully and is now available as the '${snippet.name}' tool.`
162
+ };
163
+ } catch (error) {
164
+ console.error("[register_snippet] Error:", error);
165
+ return { error: `Failed to register snippet: ${error instanceof Error ? error.message : String(error)}` };
166
+ }
167
+ })
168
+ ];
169
+ }
170
+ //#endregion
171
+ export { createSnippetManagementTools };
172
+
173
+ //# sourceMappingURL=create-snippet-management-tools.js.map