@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.
- package/LICENSE +21 -0
- package/README.md +208 -0
- package/dist/esm/code-mode-with-snippets.d.ts +65 -0
- package/dist/esm/code-mode-with-snippets.js +145 -0
- package/dist/esm/code-mode-with-snippets.js.map +1 -0
- package/dist/esm/create-snippet-management-tools.d.ts +40 -0
- package/dist/esm/create-snippet-management-tools.js +173 -0
- package/dist/esm/create-snippet-management-tools.js.map +1 -0
- package/dist/esm/create-snippets-system-prompt.d.ts +22 -0
- package/dist/esm/create-snippets-system-prompt.js +234 -0
- package/dist/esm/create-snippets-system-prompt.js.map +1 -0
- package/dist/esm/generate-snippet-types.d.ts +7 -0
- package/dist/esm/generate-snippet-types.js +79 -0
- package/dist/esm/generate-snippet-types.js.map +1 -0
- package/dist/esm/index.d.ts +14 -0
- package/dist/esm/index.js +10 -0
- package/dist/esm/select-relevant-snippets.d.ts +29 -0
- package/dist/esm/select-relevant-snippets.js +56 -0
- package/dist/esm/select-relevant-snippets.js.map +1 -0
- package/dist/esm/snippets-to-bindings.d.ts +34 -0
- package/dist/esm/snippets-to-bindings.js +74 -0
- package/dist/esm/snippets-to-bindings.js.map +1 -0
- package/dist/esm/snippets-to-tools.d.ts +74 -0
- package/dist/esm/snippets-to-tools.js +147 -0
- package/dist/esm/snippets-to-tools.js.map +1 -0
- package/dist/esm/storage/file-storage.d.ts +27 -0
- package/dist/esm/storage/file-storage.js +155 -0
- package/dist/esm/storage/file-storage.js.map +1 -0
- package/dist/esm/storage/index.d.ts +3 -0
- package/dist/esm/storage/index.js +3 -0
- package/dist/esm/storage/memory-storage.d.ts +17 -0
- package/dist/esm/storage/memory-storage.js +100 -0
- package/dist/esm/storage/memory-storage.js.map +1 -0
- package/dist/esm/trust-strategies.d.ts +50 -0
- package/dist/esm/trust-strategies.js +73 -0
- package/dist/esm/trust-strategies.js.map +1 -0
- package/dist/esm/types.d.ts +216 -0
- package/package.json +92 -0
- package/src/code-mode-with-snippets.ts +210 -0
- package/src/create-snippet-management-tools.ts +298 -0
- package/src/create-snippets-system-prompt.ts +289 -0
- package/src/generate-snippet-types.ts +162 -0
- package/src/index.ts +60 -0
- package/src/select-relevant-snippets.ts +136 -0
- package/src/snippets-to-bindings.ts +135 -0
- package/src/snippets-to-tools.ts +325 -0
- package/src/storage/file-storage.ts +275 -0
- package/src/storage/index.ts +6 -0
- package/src/storage/memory-storage.ts +172 -0
- package/src/trust-strategies.ts +142 -0
- 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
|