@semantictools/ai-toolbox 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -756,6 +756,81 @@ See the [examples](./examples) directory for complete working examples using the
756
756
  **Built-in Translator:**
757
757
  The `atfunc` translator is included as a built-in and can be used via the `TRANSLATOR_ATFUNC` constant or by name (`'atfunc'`). See the source at [src/translators/atfunc.mjs](./src/translators/atfunc.mjs).
758
758
 
759
+ ## Standard Toolboxes
760
+
761
+ The package includes ready-to-use standard toolboxes that you can import and register:
762
+
763
+ ### File Toolbox
764
+
765
+ A secure file operations toolbox that provides sandboxed access to a configured root folder.
766
+
767
+ **Features:**
768
+ - Operates within a configured root folder (prevents directory traversal)
769
+ - Two setup methods: `.filetb` file (beginners) or programmatic (production with custom settings)
770
+ - Support for basic file operations: read, write, delete, list, mkdir, rmdir
771
+
772
+ **Setup (Beginner - using .filetb file):**
773
+
774
+ ```javascript
775
+ import { register, setRootToolBox } from '@semantictools/ai-toolbox';
776
+ import { fileToolbox, initialize } from '@semantictools/ai-toolbox/src/toolboxes/file.mjs';
777
+
778
+ // 1. Create a .filetb config file with your root folder path
779
+ // echo "/path/to/your/folder" > .filetb
780
+
781
+ // 2. Initialize the file toolbox
782
+ await initialize(); // Reads .filetb from current directory
783
+
784
+ // 3. Register the toolbox
785
+ register(fileToolbox);
786
+ setRootToolBox('file');
787
+ ```
788
+
789
+ **Setup (custom - programmatic):**
790
+
791
+ ```javascript
792
+ import { register, setRootToolBox } from '@semantictools/ai-toolbox';
793
+ import { fileToolbox, setRootFolder } from '@semantictools/ai-toolbox/src/toolboxes/file.mjs';
794
+
795
+ // No .filetb file needed!
796
+ const dataDir = process.env.DATA_DIR || '/var/app/data';
797
+ await setRootFolder(dataDir);
798
+
799
+ register(fileToolbox);
800
+ setRootToolBox('file');
801
+ ```
802
+
803
+ **Available Functions:**
804
+
805
+ - `file.readfile(filepath)` - Read file contents
806
+ - `file.writefile(filepath, content)` - Write content to file
807
+ - `file.deletefile(filepath)` - Delete a file
808
+ - `file.listfiles(subdir?)` - List files and directories (optional subdirectory)
809
+ - `file.mkdir(dirpath)` - Create a directory
810
+ - `file.rmdir(dirpath)` - Remove an empty directory
811
+
812
+ **Example:**
813
+
814
+ ```javascript
815
+ // Read a file
816
+ const content = await call('readfile', {
817
+ filepath: { value: 'docs/readme.txt' }
818
+ });
819
+
820
+ // Write a file
821
+ await call('writefile', {
822
+ filepath: { value: 'output/results.txt' },
823
+ content: { value: 'Processing complete!' }
824
+ });
825
+
826
+ // List files
827
+ const files = await call('listfiles', {
828
+ subdir: { value: 'data' }
829
+ });
830
+ ```
831
+
832
+ See [examples/file-toolbox.mjs](./examples/file-toolbox.mjs) for a complete example.
833
+
759
834
  ## Use Cases
760
835
 
761
836
  - **AI Function Calling**: Provide tools for Claude, GPT, or other AI models
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@semantictools/ai-toolbox",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "A flexible tool manager for managing and executing AI function calling toolboxes",
5
5
  "main": "src/toolmanager.mjs",
6
6
  "type": "module",
@@ -32,6 +32,7 @@
32
32
  "files": [
33
33
  "src",
34
34
  "src/translators",
35
+ "src/toolboxes",
35
36
  "README.md",
36
37
  "LICENSE"
37
38
  ]
@@ -0,0 +1,128 @@
1
+ # Standard Toolboxes
2
+
3
+ This directory contains ready-to-use standard toolboxes that implement common functionality following the ai-toolbox interface standard.
4
+
5
+ ## Available Toolboxes
6
+
7
+ ### File Toolbox (`file.mjs`)
8
+
9
+ Provides secure file operations within a configured root folder.
10
+
11
+ **Domain:** `file`
12
+
13
+ **Configuration:**
14
+ - Reads root folder path from `.filetb` file
15
+ - Must call `initialize()` before registering the toolbox
16
+ - All file paths are relative to the configured root folder
17
+ - Security: Prevents directory traversal attacks
18
+
19
+ **Functions:**
20
+ - `readfile(filepath)` - Read file contents
21
+ - `writefile(filepath, content)` - Write content to file
22
+ - `deletefile(filepath)` - Delete a file
23
+ - `listfiles(subdir?)` - List files and directories
24
+ - `mkdir(dirpath)` - Create a directory
25
+ - `rmdir(dirpath)` - Remove an empty directory
26
+
27
+ **Usage Example:**
28
+
29
+ ```javascript
30
+ import { register, setRootToolBox, call } from '@semantictools/ai-toolbox';
31
+ import { fileToolbox, initialize } from '@semantictools/ai-toolbox/src/toolboxes/file.mjs';
32
+
33
+ // Initialize with .filetb config file
34
+ await initialize(); // Or: await initialize('/path/to/.filetb')
35
+
36
+ // Register the toolbox
37
+ register(fileToolbox);
38
+ setRootToolBox('file');
39
+
40
+ // Use the functions
41
+ const files = await call('listfiles');
42
+ const content = await call('readfile', { filepath: { value: 'data.txt' } });
43
+ ```
44
+
45
+ See [examples/file-toolbox.mjs](../../examples/file-toolbox.mjs) for a complete example.
46
+
47
+ ## Creating Your Own Standard Toolbox
48
+
49
+ To create a new standard toolbox:
50
+
51
+ 1. **Create a new file** in this directory (e.g., `mytoolbox.mjs`)
52
+
53
+ 2. **Define your functions** following the interface standard:
54
+
55
+ ```javascript
56
+ const functions = {
57
+ my_function: {
58
+ f: async (args) => {
59
+ // Implementation
60
+ return result;
61
+ },
62
+ interface: {
63
+ domain: 'mytoolbox',
64
+ name: 'my_function',
65
+ type: 'function',
66
+ description: 'What the function does',
67
+ params: {
68
+ param1: {
69
+ type: 'string',
70
+ isRequired: true,
71
+ description: 'Parameter description'
72
+ }
73
+ },
74
+ returns: 'string'
75
+ }
76
+ }
77
+ };
78
+ ```
79
+
80
+ 3. **Export the toolbox object**:
81
+
82
+ ```javascript
83
+ export const myToolbox = {
84
+ getName: () => 'mytoolbox',
85
+ getFunction: (fname) => functions[fname] || null,
86
+ functions: Object.keys(functions).reduce((acc, key) => {
87
+ acc[key] = true;
88
+ return acc;
89
+ }, {})
90
+ };
91
+ ```
92
+
93
+ 4. **Export any initialization functions** if needed:
94
+
95
+ ```javascript
96
+ export async function initialize(config) {
97
+ // Setup code
98
+ }
99
+ ```
100
+
101
+ 5. **Document your toolbox** in this README
102
+
103
+ ## Design Principles
104
+
105
+ Standard toolboxes should follow these principles:
106
+
107
+ 1. **Self-contained** - Include all necessary code in the toolbox file
108
+ 2. **Secure** - Validate inputs and prevent security vulnerabilities
109
+ 3. **Well-documented** - Clear descriptions for all functions and parameters
110
+ 4. **Error handling** - Provide clear error messages
111
+ 5. **Follow the standard** - Use the official interface format
112
+ 6. **Configuration** - Support external configuration when appropriate
113
+ 7. **Examples** - Provide working examples in the examples directory
114
+
115
+ ## Testing Your Toolbox
116
+
117
+ Create a test file in the examples directory that demonstrates all functions in your toolbox.
118
+
119
+ ## Contributing
120
+
121
+ When adding a new standard toolbox:
122
+
123
+ 1. Create the toolbox file in this directory
124
+ 2. Follow the interface standard
125
+ 3. Add comprehensive error handling
126
+ 4. Create an example file in `examples/`
127
+ 5. Document it in this README
128
+ 6. Update the main README to list the new toolbox
@@ -0,0 +1,287 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+
4
+ let rootFolder = null;
5
+ let configFile = '.filetb';
6
+
7
+ /**
8
+ * Set the root folder directly (for programmatic use)
9
+ * @param {string} folderPath - Absolute path to the root folder
10
+ * @returns {Promise<string>} The validated root folder path
11
+ */
12
+ async function setRootFolder(folderPath) {
13
+ if (!folderPath) {
14
+ throw new Error('Root folder path is required');
15
+ }
16
+
17
+ // Convert to absolute path if needed
18
+ const absolutePath = path.isAbsolute(folderPath) ? folderPath : path.resolve(folderPath);
19
+
20
+ // Verify the root folder exists
21
+ try {
22
+ const stats = await fs.stat(absolutePath);
23
+ if (!stats.isDirectory()) {
24
+ throw new Error(`Path ${absolutePath} is not a directory`);
25
+ }
26
+ } catch (error) {
27
+ throw new Error(`Root folder ${absolutePath} does not exist or is not accessible: ${error.message}`);
28
+ }
29
+
30
+ rootFolder = absolutePath;
31
+ return rootFolder;
32
+ }
33
+
34
+ /**
35
+ * Initialize the file toolbox by reading the root folder from config file
36
+ * Convenience method for beginners - enterprise users can use setRootFolder() directly
37
+ * @param {string} configPath - Optional path to config file (defaults to .filetb in cwd)
38
+ * @returns {Promise<string>} The configured root folder path
39
+ */
40
+ async function initialize(configPath = null) {
41
+ const configFilePath = configPath || path.join(process.cwd(), configFile);
42
+
43
+ try {
44
+ const config = await fs.readFile(configFilePath, 'utf-8');
45
+ const folderPath = config.trim();
46
+ return await setRootFolder(folderPath);
47
+ } catch (error) {
48
+ throw new Error(`Failed to read config file ${configFilePath}: ${error.message}`);
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Get the absolute path within the root folder
54
+ * @param {string} relativePath - Relative path within root folder
55
+ * @returns {string} Absolute path
56
+ */
57
+ function getAbsolutePath(relativePath) {
58
+ if (!rootFolder) {
59
+ throw new Error('File toolbox not initialized. Call initialize() first or ensure .filetb file exists.');
60
+ }
61
+
62
+ const fullPath = path.join(rootFolder, relativePath);
63
+
64
+ // Security check: ensure the path is within rootFolder
65
+ if (!fullPath.startsWith(rootFolder)) {
66
+ throw new Error(`Access denied: path ${relativePath} is outside root folder`);
67
+ }
68
+
69
+ return fullPath;
70
+ }
71
+
72
+ // ============================================================================
73
+ // File Operations
74
+ // ============================================================================
75
+
76
+ async function readFile(args) {
77
+ const filePath = getAbsolutePath(args.filepath.value);
78
+
79
+ try {
80
+ const content = await fs.readFile(filePath, 'utf-8');
81
+ return content;
82
+ } catch (error) {
83
+ throw new Error(`Failed to read file ${args.filepath.value}: ${error.message}`);
84
+ }
85
+ }
86
+
87
+ async function writeFile(args) {
88
+ const filePath = getAbsolutePath(args.filepath.value);
89
+ const content = args.content.value;
90
+
91
+ try {
92
+ // Ensure parent directory exists
93
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
94
+ await fs.writeFile(filePath, content, 'utf-8');
95
+ return `File ${args.filepath.value} written successfully`;
96
+ } catch (error) {
97
+ throw new Error(`Failed to write file ${args.filepath.value}: ${error.message}`);
98
+ }
99
+ }
100
+
101
+ async function deleteFile(args) {
102
+ const filePath = getAbsolutePath(args.filepath.value);
103
+
104
+ try {
105
+ await fs.unlink(filePath);
106
+ return `File ${args.filepath.value} deleted successfully`;
107
+ } catch (error) {
108
+ throw new Error(`Failed to delete file ${args.filepath.value}: ${error.message}`);
109
+ }
110
+ }
111
+
112
+ async function listFiles(args) {
113
+ const subdir = args.subdir ? args.subdir.value : '';
114
+ const dirPath = getAbsolutePath(subdir);
115
+
116
+ try {
117
+ const entries = await fs.readdir(dirPath, { withFileTypes: true });
118
+
119
+ const files = entries.map(entry => ({
120
+ name: entry.name,
121
+ type: entry.isDirectory() ? 'directory' : 'file',
122
+ path: path.join(subdir, entry.name)
123
+ }));
124
+
125
+ return files;
126
+ } catch (error) {
127
+ throw new Error(`Failed to list files in ${subdir || '/'}: ${error.message}`);
128
+ }
129
+ }
130
+
131
+ async function makeDirectory(args) {
132
+ const dirPath = getAbsolutePath(args.dirpath.value);
133
+
134
+ try {
135
+ await fs.mkdir(dirPath, { recursive: true });
136
+ return `Directory ${args.dirpath.value} created successfully`;
137
+ } catch (error) {
138
+ throw new Error(`Failed to create directory ${args.dirpath.value}: ${error.message}`);
139
+ }
140
+ }
141
+
142
+ async function removeDirectory(args) {
143
+ const dirPath = getAbsolutePath(args.dirpath.value);
144
+
145
+ try {
146
+ await fs.rmdir(dirPath);
147
+ return `Directory ${args.dirpath.value} removed successfully`;
148
+ } catch (error) {
149
+ throw new Error(`Failed to remove directory ${args.dirpath.value}: ${error.message}`);
150
+ }
151
+ }
152
+
153
+ // ============================================================================
154
+ // Function Definitions
155
+ // ============================================================================
156
+
157
+ const functions = {
158
+ readfile: {
159
+ f: readFile,
160
+ interface: {
161
+ domain: 'file',
162
+ name: 'readfile',
163
+ type: 'function',
164
+ description: 'Read contents of a file within the configured root folder',
165
+ params: {
166
+ filepath: {
167
+ type: 'string',
168
+ isRequired: true,
169
+ description: 'Relative path to the file from root folder'
170
+ }
171
+ },
172
+ returns: 'string'
173
+ }
174
+ },
175
+
176
+ writefile: {
177
+ f: writeFile,
178
+ interface: {
179
+ domain: 'file',
180
+ name: 'writefile',
181
+ type: 'function',
182
+ description: 'Write content to a file within the configured root folder',
183
+ params: {
184
+ filepath: {
185
+ type: 'string',
186
+ isRequired: true,
187
+ description: 'Relative path to the file from root folder'
188
+ },
189
+ content: {
190
+ type: 'string',
191
+ isRequired: true,
192
+ description: 'Content to write to the file'
193
+ }
194
+ },
195
+ returns: 'string'
196
+ }
197
+ },
198
+
199
+ deletefile: {
200
+ f: deleteFile,
201
+ interface: {
202
+ domain: 'file',
203
+ name: 'deletefile',
204
+ type: 'function',
205
+ description: 'Delete a file within the configured root folder',
206
+ params: {
207
+ filepath: {
208
+ type: 'string',
209
+ isRequired: true,
210
+ description: 'Relative path to the file from root folder'
211
+ }
212
+ },
213
+ returns: 'string'
214
+ }
215
+ },
216
+
217
+ listfiles: {
218
+ f: listFiles,
219
+ interface: {
220
+ domain: 'file',
221
+ name: 'listfiles',
222
+ type: 'function',
223
+ description: 'List files and directories within the configured root folder',
224
+ params: {
225
+ subdir: {
226
+ type: 'string',
227
+ isRequired: false,
228
+ description: 'Optional subdirectory path to list (defaults to root folder)'
229
+ }
230
+ },
231
+ returns: 'array'
232
+ }
233
+ },
234
+
235
+ mkdir: {
236
+ f: makeDirectory,
237
+ interface: {
238
+ domain: 'file',
239
+ name: 'mkdir',
240
+ type: 'function',
241
+ description: 'Create a directory within the configured root folder',
242
+ params: {
243
+ dirpath: {
244
+ type: 'string',
245
+ isRequired: true,
246
+ description: 'Relative path to the directory from root folder'
247
+ }
248
+ },
249
+ returns: 'string'
250
+ }
251
+ },
252
+
253
+ rmdir: {
254
+ f: removeDirectory,
255
+ interface: {
256
+ domain: 'file',
257
+ name: 'rmdir',
258
+ type: 'function',
259
+ description: 'Remove an empty directory within the configured root folder',
260
+ params: {
261
+ dirpath: {
262
+ type: 'string',
263
+ isRequired: true,
264
+ description: 'Relative path to the directory from root folder'
265
+ }
266
+ },
267
+ returns: 'string'
268
+ }
269
+ }
270
+ };
271
+
272
+ // ============================================================================
273
+ // Toolbox Interface
274
+ // ============================================================================
275
+
276
+ const fileToolbox = {
277
+ getName: () => 'file',
278
+ getFunction: (fname) => {
279
+ return functions[fname] || null;
280
+ },
281
+ functions: Object.keys(functions).reduce((acc, key) => {
282
+ acc[key] = true;
283
+ return acc;
284
+ }, {})
285
+ };
286
+
287
+ export { fileToolbox, initialize, setRootFolder, getAbsolutePath };