@ai-code-agents/environment-utils 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md ADDED
@@ -0,0 +1,7 @@
1
+ Copyright 2025 Felix Arntz
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # @ai-code-agents/environment-utils
2
+
3
+ Utilities for implementing AI Code agents execution environments.
4
+
5
+ This package provides the foundational interfaces, base classes, and utility functions used to build custom environments and tools for the [ai-code-agents](https://www.npmjs.com/package/ai-code-agents) SDK.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @ai-code-agents/environment-utils
11
+ ```
12
+
13
+ ## Core Concepts
14
+
15
+ ### Environment Interfaces
16
+
17
+ The package defines several key interfaces that all environments should implement:
18
+
19
+ - `FilesystemEnvironmentInterface`: Basic file operations (read, write, delete, move, copy).
20
+ - `CommandLineEnvironmentInterface`: Extends filesystem operations with command execution.
21
+ - `ShutdownableEnvironmentInterface`: For environments that require explicit cleanup (e.g., closing connections or stopping containers).
22
+
23
+ ### Base Classes
24
+
25
+ To simplify implementation, several abstract base classes are provided:
26
+
27
+ - `FilesystemEnvironmentBase`: Implements the `FilesystemEnvironmentInterface` logic, requiring only low-level file access methods to be implemented.
28
+ - `CommandLineEnvironmentBase`: Extends `FilesystemEnvironmentBase` with a base for command execution.
29
+ - `UnixEnvironmentBase`: A specialized base class for Unix-like environments that implements filesystem operations using standard Unix commands (`cat`, `rm`, `mv`, etc.) via `runCommand`.
30
+ - `ToolBase`: A base class for creating tools compatible with the Vercel AI SDK.
31
+ - `EnvironmentToolBase`: A specialized base class for tools that operate within a specific execution environment.
32
+
33
+ ### Utilities
34
+
35
+ - `escapeCommandArg(arg)`: Safely escapes a string for use as a command-line argument.
36
+ - `validateRelativePath(path)`: Ensures a path is relative and does not attempt to escape the project directory (preventing directory traversal).
37
+
38
+ ## Usage Example: Custom Environment
39
+
40
+ ```typescript
41
+ import {
42
+ UnixEnvironmentBase,
43
+ type RunCommandResult,
44
+ } from '@ai-code-agents/environment-utils';
45
+
46
+ class MyCustomEnvironment extends UnixEnvironmentBase<{ myConfig: string }> {
47
+ get name() {
48
+ return 'my-custom-env';
49
+ }
50
+
51
+ protected async executeCommand(
52
+ command: string,
53
+ ): Promise<[number, string, string]> {
54
+ // Implement your custom command execution logic here
55
+ // Returns [exitCode, stdout, stderr]
56
+ return [0, 'output', ''];
57
+ }
58
+ }
59
+ ```
60
+
61
+ ## Contributing
62
+
63
+ Contributions to the AI Code Agents SDK are welcome and highly appreciated. Please review the [contributing guidelines](https://github.com/felixarntz/ai-code-agents/blob/main/CONTRIBUTING.md) to learn more about how you can contribute.
package/dist/index.cjs ADDED
@@ -0,0 +1,529 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ CommandLineEnvironmentBase: () => CommandLineEnvironmentBase,
34
+ CopyFileResult: () => CopyFileResult,
35
+ DeleteFileResult: () => DeleteFileResult,
36
+ EnvironmentToolBase: () => EnvironmentToolBase,
37
+ FilesystemEnvironmentBase: () => FilesystemEnvironmentBase,
38
+ MoveFileResult: () => MoveFileResult,
39
+ ReadFileResult: () => ReadFileResult,
40
+ RunCommandResult: () => RunCommandResult,
41
+ ToolBase: () => ToolBase,
42
+ UnixEnvironmentBase: () => UnixEnvironmentBase,
43
+ WriteFileResult: () => WriteFileResult,
44
+ escapeCommandArg: () => escapeCommandArg,
45
+ isCommandLine: () => isCommandLine,
46
+ isShutdownable: () => isShutdownable,
47
+ validateRelativePath: () => validateRelativePath
48
+ });
49
+ module.exports = __toCommonJS(index_exports);
50
+
51
+ // src/types.ts
52
+ var z = __toESM(require("zod"), 1);
53
+ var ReadFileResult = z.object({
54
+ path: z.string().meta({
55
+ description: "The path to the file that was read."
56
+ }),
57
+ content: z.string().meta({
58
+ description: "The content of the file that was read."
59
+ })
60
+ });
61
+ var WriteFileResult = z.object({
62
+ path: z.string().meta({
63
+ description: "The path to the file that was written."
64
+ }),
65
+ message: z.string().meta({
66
+ description: "A message indicating the result of the write operation."
67
+ })
68
+ });
69
+ var DeleteFileResult = z.object({
70
+ path: z.string().meta({
71
+ description: "The path to the file that was deleted."
72
+ }),
73
+ message: z.string().meta({
74
+ description: "A message indicating the result of the delete operation."
75
+ })
76
+ });
77
+ var MoveFileResult = z.object({
78
+ sourcePath: z.string().meta({
79
+ description: "The original path of the file that was moved."
80
+ }),
81
+ destinationPath: z.string().meta({
82
+ description: "The new path of the file that was moved to."
83
+ }),
84
+ message: z.string().meta({
85
+ description: "A message indicating the result of the move operation."
86
+ })
87
+ });
88
+ var CopyFileResult = z.object({
89
+ sourcePath: z.string().meta({
90
+ description: "The original path of the file that was copied."
91
+ }),
92
+ destinationPath: z.string().meta({
93
+ description: "The new path of the file that was copied to."
94
+ }),
95
+ message: z.string().meta({
96
+ description: "A message indicating the result of the copy operation."
97
+ })
98
+ });
99
+ var RunCommandResult = z.object({
100
+ command: z.string().meta({
101
+ description: "The command that was executed."
102
+ }),
103
+ exitCode: z.number().meta({
104
+ description: "The exit code of the command."
105
+ }),
106
+ stdout: z.string().meta({
107
+ description: "The standard output of the command."
108
+ }),
109
+ stderr: z.string().meta({
110
+ description: "The standard error output of the command."
111
+ })
112
+ });
113
+ function isCommandLine(env) {
114
+ return "runCommand" in env && typeof env.runCommand === "function";
115
+ }
116
+ function isShutdownable(env) {
117
+ return "shutdown" in env && typeof env.shutdown === "function";
118
+ }
119
+
120
+ // src/util/validate-relative-path.ts
121
+ var path = __toESM(require("path"), 1);
122
+ function validateRelativePath(filePath) {
123
+ if (path.isAbsolute(filePath)) {
124
+ throw new Error("Absolute paths are not allowed.");
125
+ }
126
+ if (filePath.startsWith("~")) {
127
+ throw new Error('Paths starting with "~" are not allowed.');
128
+ }
129
+ if (filePath.includes("\0")) {
130
+ throw new Error("Paths must not contain null bytes.");
131
+ }
132
+ const normalizedPath = path.normalize(filePath);
133
+ if (normalizedPath.startsWith("..")) {
134
+ throw new Error("Path traversal is not allowed.");
135
+ }
136
+ }
137
+
138
+ // src/environments/filesystem-environment-base.ts
139
+ var FilesystemEnvironmentBase = class {
140
+ _envConfig;
141
+ /**
142
+ * Constructs a new environment instance.
143
+ *
144
+ * @param config - Environment configuration.
145
+ */
146
+ constructor(config) {
147
+ this._envConfig = config;
148
+ }
149
+ /**
150
+ * Reads the content of a file at the specified path.
151
+ *
152
+ * @param path - The path to the file to read, relative to the project directory.
153
+ * @returns A promise that resolves to a ReadFileResult.
154
+ */
155
+ async readFile(path2) {
156
+ validateRelativePath(path2);
157
+ if (!await this.fileExists(path2)) {
158
+ throw new Error(`File not found: ${path2}`);
159
+ }
160
+ const content = await this.readFileContent(path2);
161
+ return {
162
+ path: path2,
163
+ content
164
+ };
165
+ }
166
+ /**
167
+ * Writes content to a file at the specified path.
168
+ *
169
+ * If a file is already present at the path, it will be overwritten.
170
+ *
171
+ * @param path - The path to the file to write, relative to the project directory.
172
+ * @param content - The content to write to the file.
173
+ * @returns A promise that resolves to a WriteFileResult.
174
+ */
175
+ async writeFile(path2, content) {
176
+ validateRelativePath(path2);
177
+ await this.writeFileContent(path2, content);
178
+ return {
179
+ path: path2,
180
+ message: "File written successfully."
181
+ };
182
+ }
183
+ /**
184
+ * Deletes a file at the specified path.
185
+ *
186
+ * @param path - The path to the file to delete, relative to the project directory.
187
+ * @returns A promise that resolves to a DeleteFileResult.
188
+ */
189
+ async deleteFile(path2) {
190
+ validateRelativePath(path2);
191
+ if (!await this.fileExists(path2)) {
192
+ return {
193
+ path: path2,
194
+ message: "File was already deleted."
195
+ };
196
+ }
197
+ await this.deleteFileContent(path2);
198
+ return {
199
+ path: path2,
200
+ message: "File deleted successfully."
201
+ };
202
+ }
203
+ /**
204
+ * Moves a file from a source path to a destination path.
205
+ *
206
+ * If a file is already present at the destination path, it will be overwritten.
207
+ *
208
+ * @param sourcePath - The path to the file to move.
209
+ * @param destinationPath - The path to move the file to.
210
+ * @returns A promise that resolves to a MoveFileResult.
211
+ */
212
+ async moveFile(sourcePath, destinationPath) {
213
+ validateRelativePath(sourcePath);
214
+ validateRelativePath(destinationPath);
215
+ if (!await this.fileExists(sourcePath)) {
216
+ throw new Error(`File not found: ${sourcePath}`);
217
+ }
218
+ await this.moveFileContent(sourcePath, destinationPath);
219
+ return {
220
+ sourcePath,
221
+ destinationPath,
222
+ message: "File moved successfully."
223
+ };
224
+ }
225
+ /**
226
+ * Copies a file from a source path to a destination path.
227
+ *
228
+ * If a file is already present at the destination path, it will be overwritten.
229
+ *
230
+ * @param sourcePath - The path to the file to copy.
231
+ * @param destinationPath - The path to copy the file to.
232
+ * @returns A promise that resolves to a CopyFileResult.
233
+ */
234
+ async copyFile(sourcePath, destinationPath) {
235
+ validateRelativePath(sourcePath);
236
+ validateRelativePath(destinationPath);
237
+ if (!await this.fileExists(sourcePath)) {
238
+ throw new Error(`File not found: ${sourcePath}`);
239
+ }
240
+ await this.copyFileContent(sourcePath, destinationPath);
241
+ return {
242
+ sourcePath,
243
+ destinationPath,
244
+ message: "File copied successfully."
245
+ };
246
+ }
247
+ /**
248
+ * Moves the content of a file from a source path to a destination path, relative to the project directory.
249
+ *
250
+ * When this method is called, it is guaranteed that the source file exists.
251
+ * This method unconditionally moves the content, even if a file already exists at the destination path.
252
+ *
253
+ * @param relativeSourcePath - The path to the file to move, relative to the project directory.
254
+ * @param relativeDestinationPath - The path to move the file to, relative to the project directory.
255
+ */
256
+ async moveFileContent(relativeSourcePath, relativeDestinationPath) {
257
+ const content = await this.readFileContent(relativeSourcePath);
258
+ this.writeFileContent(relativeDestinationPath, content);
259
+ this.deleteFileContent(relativeSourcePath);
260
+ }
261
+ /**
262
+ * Copies the content of a file from a source path to a destination path, relative to the project directory.
263
+ *
264
+ * When this method is called, it is guaranteed that the source file exists.
265
+ * This method unconditionally copies the content, even if a file already exists at the destination path.
266
+ *
267
+ * @param relativeSourcePath - The path to the file to copy, relative to the project directory.
268
+ * @param relativeDestinationPath - The path to copy the file to, relative to the project directory.
269
+ */
270
+ async copyFileContent(relativeSourcePath, relativeDestinationPath) {
271
+ const content = await this.readFileContent(relativeSourcePath);
272
+ this.writeFileContent(relativeDestinationPath, content);
273
+ }
274
+ };
275
+
276
+ // src/environments/command-line-environment-base.ts
277
+ var CommandLineEnvironmentBase = class extends FilesystemEnvironmentBase {
278
+ /**
279
+ * Runs a CLI command in environment.
280
+ *
281
+ * @param command - The command to run.
282
+ * @returns A promise that resolves to a RunCommandResult.
283
+ */
284
+ async runCommand(command) {
285
+ const [exitCode, stdout, stderr] = await this.executeCommand(command);
286
+ return {
287
+ command,
288
+ exitCode,
289
+ stdout,
290
+ stderr
291
+ };
292
+ }
293
+ };
294
+
295
+ // src/util/escape-command-arg.ts
296
+ function escapeCommandArg(arg) {
297
+ if ("" === arg) {
298
+ return "''";
299
+ }
300
+ return `'${arg.replace(/'/g, "'\\''")}'`;
301
+ }
302
+
303
+ // src/environments/unix-environment-base.ts
304
+ var UnixEnvironmentBase = class extends CommandLineEnvironmentBase {
305
+ /**
306
+ * Checks whether a file exists at the specified path relative to the project directory.
307
+ *
308
+ * @param relativePath - The path to the file to check, relative to the project directory.
309
+ * @returns True if the file exists, false otherwise.
310
+ */
311
+ async fileExists(relativePath) {
312
+ const command = `if [ -e ${escapeCommandArg(relativePath)} ]; then echo "yes"; else echo "no"; fi`;
313
+ const { exitCode, stdout } = await this.runCommand(command);
314
+ return exitCode === 0 && stdout.trim() === "yes";
315
+ }
316
+ /**
317
+ * Gets the content of a file at the specified path, relative to the project directory.
318
+ *
319
+ * When this method is called, it is guaranteed that the file exists.
320
+ *
321
+ * @param relativePath - The path to the file to read, relative to the project directory.
322
+ * @returns The content of the file.
323
+ */
324
+ async readFileContent(relativePath) {
325
+ const command = `cat ${escapeCommandArg(relativePath)}`;
326
+ const { exitCode, stdout } = await this.runCommand(command);
327
+ return exitCode === 0 ? stdout : "";
328
+ }
329
+ /**
330
+ * Writes content to a file at the specified path, relative to the project directory.
331
+ *
332
+ * This method unconditionally writes the content, even if a file already exists at the path, or if the file is new.
333
+ *
334
+ * @param relativePath - The path to the file to write, relative to the project directory.
335
+ * @param content - The content to write to the file.
336
+ */
337
+ async writeFileContent(relativePath, content) {
338
+ const command = `sh -c "echo ${escapeCommandArg(
339
+ content
340
+ )} > ${escapeCommandArg(relativePath)}"`;
341
+ const { exitCode, stderr } = await this.runCommand(command);
342
+ if (exitCode !== 0) {
343
+ throw new Error(`Failed to write file: ${stderr || "Unknown error"}`);
344
+ }
345
+ }
346
+ /**
347
+ * Deletes a file at the specified path, relative to the project directory.
348
+ *
349
+ * When this method is called, it is guaranteed that the file exists.
350
+ *
351
+ * @param relativePath - The path to the file to delete, relative to the project directory.
352
+ */
353
+ async deleteFileContent(relativePath) {
354
+ const command = `rm ${escapeCommandArg(relativePath)}`;
355
+ const { exitCode, stderr } = await this.runCommand(command);
356
+ if (exitCode !== 0) {
357
+ throw new Error(`Failed to delete file: ${stderr || "Unknown error"}`);
358
+ }
359
+ }
360
+ /**
361
+ * Moves the content of a file from a source path to a destination path, relative to the project directory.
362
+ *
363
+ * When this method is called, it is guaranteed that the source file exists.
364
+ * This method unconditionally moves the content, even if a file already exists at the destination path.
365
+ *
366
+ * @param relativeSourcePath - The path to the file to move, relative to the project directory.
367
+ * @param relativeDestinationPath - The path to move the file to, relative to the project directory.
368
+ */
369
+ async moveFileContent(relativeSourcePath, relativeDestinationPath) {
370
+ const command = `mv ${escapeCommandArg(relativeSourcePath)} ${escapeCommandArg(
371
+ relativeDestinationPath
372
+ )}`;
373
+ const { exitCode, stderr } = await this.runCommand(command);
374
+ if (exitCode !== 0) {
375
+ throw new Error(`Failed to move file: ${stderr || "Unknown error"}`);
376
+ }
377
+ }
378
+ /**
379
+ * Copies the content of a file from a source path to a destination path, relative to the project directory.
380
+ *
381
+ * When this method is called, it is guaranteed that the source file exists.
382
+ * This method unconditionally copies the content, even if a file already exists at the destination path.
383
+ *
384
+ * @param relativeSourcePath - The path to the file to copy, relative to the project directory.
385
+ * @param relativeDestinationPath - The path to copy the file to, relative to the project directory.
386
+ */
387
+ async copyFileContent(relativeSourcePath, relativeDestinationPath) {
388
+ const command = `cp ${escapeCommandArg(relativeSourcePath)} ${escapeCommandArg(
389
+ relativeDestinationPath
390
+ )}`;
391
+ const result = await this.runCommand(command);
392
+ if (result.exitCode !== 0) {
393
+ throw new Error(
394
+ `Failed to copy file: ${result.stderr || "Unknown error"}`
395
+ );
396
+ }
397
+ }
398
+ };
399
+
400
+ // src/tools/tool-base.ts
401
+ var ToolBase = class {
402
+ _toolConfig;
403
+ _name;
404
+ _description;
405
+ _inputSchema;
406
+ _outputSchema;
407
+ _needsApproval;
408
+ /**
409
+ * Constructs a new tool instance.
410
+ *
411
+ * @param toolConfig - Optional tool config, can be used to override some defaults.
412
+ */
413
+ constructor(toolConfig) {
414
+ const {
415
+ name: defaultName,
416
+ description: defaultDescription,
417
+ inputSchema,
418
+ outputSchema,
419
+ needsApproval: defaultNeedsApproval
420
+ } = this.getMetadata();
421
+ this._name = toolConfig?.name || defaultName;
422
+ this._description = toolConfig?.description || defaultDescription;
423
+ this._inputSchema = inputSchema;
424
+ this._outputSchema = outputSchema;
425
+ this._needsApproval = toolConfig?.needsApproval !== void 0 ? toolConfig.needsApproval : defaultNeedsApproval;
426
+ }
427
+ /**
428
+ * Gets the tool name.
429
+ *
430
+ * @returns The tool name.
431
+ */
432
+ get name() {
433
+ return this._name;
434
+ }
435
+ /**
436
+ * Gets the tool description.
437
+ *
438
+ * @returns The tool description.
439
+ */
440
+ get description() {
441
+ return this._description;
442
+ }
443
+ /**
444
+ * Gets the input schema for the tool.
445
+ *
446
+ * @returns The input schema.
447
+ */
448
+ get inputSchema() {
449
+ return this._inputSchema;
450
+ }
451
+ /**
452
+ * Gets the input schema for the tool.
453
+ *
454
+ * @returns The input schema.
455
+ */
456
+ get outputSchema() {
457
+ return this._outputSchema;
458
+ }
459
+ /**
460
+ * Gets whether the tool needs approval before use.
461
+ *
462
+ * @returns True if the tool needs approval, false otherwise.
463
+ */
464
+ get needsApproval() {
465
+ return this._needsApproval;
466
+ }
467
+ /**
468
+ * Gets the input examples for the tool.
469
+ *
470
+ * This is used for AI SDK v6 compatibility, which supports input examples, but without output examples.
471
+ *
472
+ * @returns The tool input examples.
473
+ */
474
+ get inputExamples() {
475
+ return this.examples.map((example) => ({ input: example.input }));
476
+ }
477
+ };
478
+
479
+ // src/tools/environment-tool-base.ts
480
+ var EnvironmentToolBase = class extends ToolBase {
481
+ _environment;
482
+ /**
483
+ * Constructs a new `EnvironmentToolBase` instance.
484
+ *
485
+ * @param environment - The execution environment to apply the tool in.
486
+ * @param toolConfig - Optional tool config, can be used to override some defaults.
487
+ */
488
+ constructor(environment, toolConfig) {
489
+ super(toolConfig);
490
+ this._environment = environment;
491
+ }
492
+ /**
493
+ * Gets the current execution environment for the tool.
494
+ *
495
+ * @returns The current execution environment.
496
+ */
497
+ get environment() {
498
+ return this._environment;
499
+ }
500
+ /**
501
+ * Executes the tool with the given input.
502
+ *
503
+ * @param input - The input for the tool.
504
+ * @param _options - Options for the tool execution.
505
+ * @returns A promise that resolves to the tool execution result.
506
+ */
507
+ execute(input, _options) {
508
+ return this.executeForEnvironment(this._environment, input);
509
+ }
510
+ };
511
+ // Annotate the CommonJS export names for ESM import in node:
512
+ 0 && (module.exports = {
513
+ CommandLineEnvironmentBase,
514
+ CopyFileResult,
515
+ DeleteFileResult,
516
+ EnvironmentToolBase,
517
+ FilesystemEnvironmentBase,
518
+ MoveFileResult,
519
+ ReadFileResult,
520
+ RunCommandResult,
521
+ ToolBase,
522
+ UnixEnvironmentBase,
523
+ WriteFileResult,
524
+ escapeCommandArg,
525
+ isCommandLine,
526
+ isShutdownable,
527
+ validateRelativePath
528
+ });
529
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/util/validate-relative-path.ts","../src/environments/filesystem-environment-base.ts","../src/environments/command-line-environment-base.ts","../src/util/escape-command-arg.ts","../src/environments/unix-environment-base.ts","../src/tools/tool-base.ts","../src/tools/environment-tool-base.ts"],"sourcesContent":["export * from './types';\n\nexport * from './environments/filesystem-environment-base';\nexport * from './environments/command-line-environment-base';\nexport * from './environments/unix-environment-base';\n\nexport * from './tools/environment-tool-base';\nexport * from './tools/tool-base';\n\nexport * from './util/escape-command-arg';\nexport * from './util/validate-relative-path';\n","import type { FlexibleSchema } from '@ai-sdk/provider-utils';\nimport type { ToolExecutionOptions } from 'ai';\nimport * as z from 'zod';\n\nexport const ReadFileResult = z.object({\n path: z.string().meta({\n description: 'The path to the file that was read.',\n }),\n content: z.string().meta({\n description: 'The content of the file that was read.',\n }),\n});\n\nexport type ReadFileResult = z.infer<typeof ReadFileResult>;\n\nexport const WriteFileResult = z.object({\n path: z.string().meta({\n description: 'The path to the file that was written.',\n }),\n message: z.string().meta({\n description: 'A message indicating the result of the write operation.',\n }),\n});\n\nexport type WriteFileResult = z.infer<typeof WriteFileResult>;\n\nexport const DeleteFileResult = z.object({\n path: z.string().meta({\n description: 'The path to the file that was deleted.',\n }),\n message: z.string().meta({\n description: 'A message indicating the result of the delete operation.',\n }),\n});\n\nexport type DeleteFileResult = z.infer<typeof DeleteFileResult>;\n\nexport const MoveFileResult = z.object({\n sourcePath: z.string().meta({\n description: 'The original path of the file that was moved.',\n }),\n destinationPath: z.string().meta({\n description: 'The new path of the file that was moved to.',\n }),\n message: z.string().meta({\n description: 'A message indicating the result of the move operation.',\n }),\n});\n\nexport type MoveFileResult = z.infer<typeof MoveFileResult>;\n\nexport const CopyFileResult = z.object({\n sourcePath: z.string().meta({\n description: 'The original path of the file that was copied.',\n }),\n destinationPath: z.string().meta({\n description: 'The new path of the file that was copied to.',\n }),\n message: z.string().meta({\n description: 'A message indicating the result of the copy operation.',\n }),\n});\n\nexport type CopyFileResult = z.infer<typeof CopyFileResult>;\n\nexport const RunCommandResult = z.object({\n command: z.string().meta({\n description: 'The command that was executed.',\n }),\n exitCode: z.number().meta({\n description: 'The exit code of the command.',\n }),\n stdout: z.string().meta({\n description: 'The standard output of the command.',\n }),\n stderr: z.string().meta({\n description: 'The standard error output of the command.',\n }),\n});\n\nexport type RunCommandResult = z.infer<typeof RunCommandResult>;\n\nexport interface FilesystemEnvironmentInterface {\n get name(): string;\n readFile(path: string): Promise<ReadFileResult>;\n writeFile(path: string, content: string): Promise<WriteFileResult>;\n deleteFile(path: string): Promise<DeleteFileResult>;\n moveFile(\n sourcePath: string,\n destinationPath: string,\n ): Promise<MoveFileResult>;\n copyFile(\n sourcePath: string,\n destinationPath: string,\n ): Promise<CopyFileResult>;\n}\n\nexport interface CommandLineEnvironmentInterface extends FilesystemEnvironmentInterface {\n runCommand(command: string): Promise<RunCommandResult>;\n}\n\n/**\n * Interface for environments that support explicit shutdown/cleanup.\n *\n * Environments implementing this interface may hold resources (connections,\n * sandboxes, containers) that should be released when no longer needed.\n */\nexport interface ShutdownableEnvironmentInterface {\n /**\n * Shuts down the environment and releases any held resources.\n *\n * @returns A promise that resolves when shutdown is complete.\n */\n shutdown(): Promise<void>;\n}\n\nexport type Environment =\n | FilesystemEnvironmentInterface\n | CommandLineEnvironmentInterface;\n\n/**\n * Type guard to check if an environment supports command-line operations.\n *\n * @param env - The environment to check.\n * @returns True if the environment implements CommandLineEnvironmentInterface.\n */\nexport function isCommandLine(\n env: Environment,\n): env is CommandLineEnvironmentInterface {\n return 'runCommand' in env && typeof env.runCommand === 'function';\n}\n\n/**\n * Type guard to check if an environment supports shutdown.\n *\n * @param env - The environment to check.\n * @returns True if the environment implements ShutdownableEnvironmentInterface.\n */\nexport function isShutdownable(\n env: Environment,\n): env is Environment & ShutdownableEnvironmentInterface {\n return 'shutdown' in env && typeof env.shutdown === 'function';\n}\n\n// These types must be compatible with or subtypes of the LanguageModelV3ToolResultOutput type from '@ai-sdk/provider'.\ntype ModelTextResult = { type: 'text'; value: string };\ntype ModelTextPart = { type: 'text'; text: string };\ntype ModelMediaPart = { type: 'media'; data: string; mediaType: string };\nexport type ModelToolResultToFormat<ToolInputType, ToolOutputType> = {\n toolCallId: string;\n input: ToolInputType;\n output: ToolOutputType;\n};\nexport type ModelFormattedToolResult =\n | ModelTextResult\n | {\n type: 'content';\n value: Array<ModelTextPart | ModelMediaPart>;\n };\n\nexport type ToolExample<ToolInputType, ToolOutputType> = {\n input: ToolInputType;\n output: ToolOutputType | string;\n};\n\n// This interface must be compatible with the Tool interface from 'ai'.\nexport interface ToolInterface<ToolInputType, ToolOutputType> {\n get name(): string;\n get description(): string;\n get inputSchema(): FlexibleSchema<ToolInputType>;\n get outputSchema(): FlexibleSchema<ToolOutputType>;\n execute(\n input: ToolInputType,\n options: ToolExecutionOptions,\n ): Promise<ToolOutputType>;\n toModelOutput(\n options: ModelToolResultToFormat<ToolInputType, ToolOutputType>,\n ): ModelFormattedToolResult;\n get examples(): Array<ToolExample<ToolInputType, ToolOutputType>>;\n get inputExamples(): Array<{ input: ToolInputType }>;\n get needsApproval(): boolean;\n}\n\nexport interface EnvironmentToolInterface<\n ToolInputType,\n ToolOutputType,\n EnvironmentType,\n> extends ToolInterface<ToolInputType, ToolOutputType> {\n get environment(): EnvironmentType;\n}\n\n// Optional constructor parameter for tools.\nexport type ToolConfig = {\n name?: string;\n description?: string;\n needsApproval?: boolean;\n};\n","import * as path from 'node:path';\n\n/**\n * Validates that the given path is a relative path and does not contain path traversal.\n *\n * @param filePath - The file path to validate.\n */\nexport function validateRelativePath(filePath: string): void {\n if (path.isAbsolute(filePath)) {\n throw new Error('Absolute paths are not allowed.');\n }\n if (filePath.startsWith('~')) {\n throw new Error('Paths starting with \"~\" are not allowed.');\n }\n if (filePath.includes('\\0')) {\n throw new Error('Paths must not contain null bytes.');\n }\n\n const normalizedPath = path.normalize(filePath);\n if (normalizedPath.startsWith('..')) {\n throw new Error('Path traversal is not allowed.');\n }\n}\n","import { validateRelativePath } from '../util/validate-relative-path';\nimport type {\n FilesystemEnvironmentInterface,\n ReadFileResult,\n WriteFileResult,\n DeleteFileResult,\n MoveFileResult,\n CopyFileResult,\n} from '../types';\n\n/**\n * Base class for a filesystem-based execution environment.\n */\nexport abstract class FilesystemEnvironmentBase<\n EnvironmentConfig,\n> implements FilesystemEnvironmentInterface {\n protected _envConfig: EnvironmentConfig;\n\n /**\n * Constructs a new environment instance.\n *\n * @param config - Environment configuration.\n */\n constructor(config: EnvironmentConfig) {\n this._envConfig = config;\n }\n\n /**\n * Gets the environment name.\n *\n * @returns The environment name.\n */\n abstract get name(): string;\n\n /**\n * Reads the content of a file at the specified path.\n *\n * @param path - The path to the file to read, relative to the project directory.\n * @returns A promise that resolves to a ReadFileResult.\n */\n async readFile(path: string): Promise<ReadFileResult> {\n validateRelativePath(path);\n\n if (!(await this.fileExists(path))) {\n throw new Error(`File not found: ${path}`);\n }\n\n const content = await this.readFileContent(path);\n\n return {\n path,\n content,\n };\n }\n\n /**\n * Writes content to a file at the specified path.\n *\n * If a file is already present at the path, it will be overwritten.\n *\n * @param path - The path to the file to write, relative to the project directory.\n * @param content - The content to write to the file.\n * @returns A promise that resolves to a WriteFileResult.\n */\n async writeFile(path: string, content: string): Promise<WriteFileResult> {\n validateRelativePath(path);\n\n await this.writeFileContent(path, content);\n\n return {\n path,\n message: 'File written successfully.',\n };\n }\n\n /**\n * Deletes a file at the specified path.\n *\n * @param path - The path to the file to delete, relative to the project directory.\n * @returns A promise that resolves to a DeleteFileResult.\n */\n async deleteFile(path: string): Promise<DeleteFileResult> {\n validateRelativePath(path);\n\n if (!(await this.fileExists(path))) {\n return {\n path,\n message: 'File was already deleted.',\n };\n }\n\n await this.deleteFileContent(path);\n\n return {\n path,\n message: 'File deleted successfully.',\n };\n }\n\n /**\n * Moves a file from a source path to a destination path.\n *\n * If a file is already present at the destination path, it will be overwritten.\n *\n * @param sourcePath - The path to the file to move.\n * @param destinationPath - The path to move the file to.\n * @returns A promise that resolves to a MoveFileResult.\n */\n async moveFile(\n sourcePath: string,\n destinationPath: string,\n ): Promise<MoveFileResult> {\n validateRelativePath(sourcePath);\n validateRelativePath(destinationPath);\n\n if (!(await this.fileExists(sourcePath))) {\n throw new Error(`File not found: ${sourcePath}`);\n }\n\n await this.moveFileContent(sourcePath, destinationPath);\n\n return {\n sourcePath,\n destinationPath,\n message: 'File moved successfully.',\n };\n }\n\n /**\n * Copies a file from a source path to a destination path.\n *\n * If a file is already present at the destination path, it will be overwritten.\n *\n * @param sourcePath - The path to the file to copy.\n * @param destinationPath - The path to copy the file to.\n * @returns A promise that resolves to a CopyFileResult.\n */\n async copyFile(\n sourcePath: string,\n destinationPath: string,\n ): Promise<CopyFileResult> {\n validateRelativePath(sourcePath);\n validateRelativePath(destinationPath);\n\n if (!(await this.fileExists(sourcePath))) {\n throw new Error(`File not found: ${sourcePath}`);\n }\n\n await this.copyFileContent(sourcePath, destinationPath);\n\n return {\n sourcePath,\n destinationPath,\n message: 'File copied successfully.',\n };\n }\n\n /**\n * Checks whether a file exists at the specified path relative to the project directory.\n *\n * @param relativePath - The path to the file to check, relative to the project directory.\n * @returns True if the file exists, false otherwise.\n */\n protected abstract fileExists(relativePath: string): Promise<boolean>;\n\n /**\n * Gets the content of a file at the specified path, relative to the project directory.\n *\n * When this method is called, it is guaranteed that the file exists.\n *\n * @param relativePath - The path to the file to read, relative to the project directory.\n * @returns The content of the file.\n */\n protected abstract readFileContent(relativePath: string): Promise<string>;\n\n /**\n * Writes content to a file at the specified path, relative to the project directory.\n *\n * This method unconditionally writes the content, even if a file already exists at the path, or if the file is new.\n *\n * @param relativePath - The path to the file to write, relative to the project directory.\n * @param content - The content to write to the file.\n */\n protected abstract writeFileContent(\n relativePath: string,\n content: string,\n ): Promise<void>;\n\n /**\n * Deletes a file at the specified path, relative to the project directory.\n *\n * When this method is called, it is guaranteed that the file exists.\n *\n * @param relativePath - The path to the file to delete, relative to the project directory.\n */\n protected abstract deleteFileContent(relativePath: string): Promise<void>;\n\n /**\n * Moves the content of a file from a source path to a destination path, relative to the project directory.\n *\n * When this method is called, it is guaranteed that the source file exists.\n * This method unconditionally moves the content, even if a file already exists at the destination path.\n *\n * @param relativeSourcePath - The path to the file to move, relative to the project directory.\n * @param relativeDestinationPath - The path to move the file to, relative to the project directory.\n */\n protected async moveFileContent(\n relativeSourcePath: string,\n relativeDestinationPath: string,\n ): Promise<void> {\n const content = await this.readFileContent(relativeSourcePath);\n this.writeFileContent(relativeDestinationPath, content);\n this.deleteFileContent(relativeSourcePath);\n }\n\n /**\n * Copies the content of a file from a source path to a destination path, relative to the project directory.\n *\n * When this method is called, it is guaranteed that the source file exists.\n * This method unconditionally copies the content, even if a file already exists at the destination path.\n *\n * @param relativeSourcePath - The path to the file to copy, relative to the project directory.\n * @param relativeDestinationPath - The path to copy the file to, relative to the project directory.\n */\n protected async copyFileContent(\n relativeSourcePath: string,\n relativeDestinationPath: string,\n ): Promise<void> {\n const content = await this.readFileContent(relativeSourcePath);\n this.writeFileContent(relativeDestinationPath, content);\n }\n}\n","import type {\n CommandLineEnvironmentInterface,\n RunCommandResult,\n} from '../types';\nimport { FilesystemEnvironmentBase } from './filesystem-environment-base';\n\n/**\n * Base class for a command-line based execution environment.\n */\nexport abstract class CommandLineEnvironmentBase<EnvironmentConfig>\n extends FilesystemEnvironmentBase<EnvironmentConfig>\n implements CommandLineEnvironmentInterface\n{\n /**\n * Runs a CLI command in environment.\n *\n * @param command - The command to run.\n * @returns A promise that resolves to a RunCommandResult.\n */\n async runCommand(command: string): Promise<RunCommandResult> {\n const [exitCode, stdout, stderr] = await this.executeCommand(command);\n return {\n command,\n exitCode,\n stdout,\n stderr,\n };\n }\n\n /**\n * Executes a command in the environment and returns the exit code, stdout, and stderr.\n *\n * @param command - The command to execute.\n * @returns A promise that resolves to a tuple containing the exit code, stdout, and stderr.\n */\n protected abstract executeCommand(\n command: string,\n ): Promise<[number, string, string]>;\n}\n","/**\n * Escapes a string to be used as a single command-line argument in a POSIX-compliant shell.\n *\n * The string is wrapped in single quotes, and any existing single quotes are\n * safely escaped. This prevents the shell from interpreting special\n * characters or expanding variables.\n *\n * @param arg - The argument string to escape.\n * @returns The escaped and quoted argument string.\n */\nexport function escapeCommandArg(arg: string): string {\n if ('' === arg) {\n return \"''\";\n }\n // 1. Replace all single quotes with '\\''\n // 2. Wrap the entire string in single quotes.\n // e.g., \"it's a test\" -> \"'it'\\\\''s a test'\"\n return `'${arg.replace(/'/g, \"'\\\\''\")}'`;\n}\n","import { escapeCommandArg } from '../util/escape-command-arg';\nimport { CommandLineEnvironmentBase } from './command-line-environment-base';\n\n/**\n * Base class for a Unix-like command line execution environment.\n */\nexport abstract class UnixEnvironmentBase<\n EnvironmentConfig,\n> extends CommandLineEnvironmentBase<EnvironmentConfig> {\n /**\n * Checks whether a file exists at the specified path relative to the project directory.\n *\n * @param relativePath - The path to the file to check, relative to the project directory.\n * @returns True if the file exists, false otherwise.\n */\n protected async fileExists(relativePath: string): Promise<boolean> {\n const command = `if [ -e ${escapeCommandArg(relativePath)} ]; then echo \"yes\"; else echo \"no\"; fi`;\n const { exitCode, stdout } = await this.runCommand(command);\n return exitCode === 0 && stdout.trim() === 'yes';\n }\n\n /**\n * Gets the content of a file at the specified path, relative to the project directory.\n *\n * When this method is called, it is guaranteed that the file exists.\n *\n * @param relativePath - The path to the file to read, relative to the project directory.\n * @returns The content of the file.\n */\n protected async readFileContent(relativePath: string): Promise<string> {\n const command = `cat ${escapeCommandArg(relativePath)}`;\n const { exitCode, stdout } = await this.runCommand(command);\n return exitCode === 0 ? stdout : '';\n }\n\n /**\n * Writes content to a file at the specified path, relative to the project directory.\n *\n * This method unconditionally writes the content, even if a file already exists at the path, or if the file is new.\n *\n * @param relativePath - The path to the file to write, relative to the project directory.\n * @param content - The content to write to the file.\n */\n protected async writeFileContent(\n relativePath: string,\n content: string,\n ): Promise<void> {\n const command = `sh -c \"echo ${escapeCommandArg(\n content,\n )} > ${escapeCommandArg(relativePath)}\"`;\n const { exitCode, stderr } = await this.runCommand(command);\n if (exitCode !== 0) {\n throw new Error(`Failed to write file: ${stderr || 'Unknown error'}`);\n }\n }\n\n /**\n * Deletes a file at the specified path, relative to the project directory.\n *\n * When this method is called, it is guaranteed that the file exists.\n *\n * @param relativePath - The path to the file to delete, relative to the project directory.\n */\n protected async deleteFileContent(relativePath: string): Promise<void> {\n const command = `rm ${escapeCommandArg(relativePath)}`;\n const { exitCode, stderr } = await this.runCommand(command);\n if (exitCode !== 0) {\n throw new Error(`Failed to delete file: ${stderr || 'Unknown error'}`);\n }\n }\n\n /**\n * Moves the content of a file from a source path to a destination path, relative to the project directory.\n *\n * When this method is called, it is guaranteed that the source file exists.\n * This method unconditionally moves the content, even if a file already exists at the destination path.\n *\n * @param relativeSourcePath - The path to the file to move, relative to the project directory.\n * @param relativeDestinationPath - The path to move the file to, relative to the project directory.\n */\n protected override async moveFileContent(\n relativeSourcePath: string,\n relativeDestinationPath: string,\n ): Promise<void> {\n const command = `mv ${escapeCommandArg(relativeSourcePath)} ${escapeCommandArg(\n relativeDestinationPath,\n )}`;\n const { exitCode, stderr } = await this.runCommand(command);\n if (exitCode !== 0) {\n throw new Error(`Failed to move file: ${stderr || 'Unknown error'}`);\n }\n }\n\n /**\n * Copies the content of a file from a source path to a destination path, relative to the project directory.\n *\n * When this method is called, it is guaranteed that the source file exists.\n * This method unconditionally copies the content, even if a file already exists at the destination path.\n *\n * @param relativeSourcePath - The path to the file to copy, relative to the project directory.\n * @param relativeDestinationPath - The path to copy the file to, relative to the project directory.\n */\n protected override async copyFileContent(\n relativeSourcePath: string,\n relativeDestinationPath: string,\n ): Promise<void> {\n const command = `cp ${escapeCommandArg(relativeSourcePath)} ${escapeCommandArg(\n relativeDestinationPath,\n )}`;\n const result = await this.runCommand(command);\n if (result.exitCode !== 0) {\n throw new Error(\n `Failed to copy file: ${result.stderr || 'Unknown error'}`,\n );\n }\n }\n}\n","import type { ToolExecutionOptions } from 'ai';\nimport type {\n ToolInterface,\n ToolConfig as ToolBaseConfig,\n ToolExample,\n ModelToolResultToFormat,\n ModelFormattedToolResult,\n} from '../types';\n\ntype FlexibleInputSchema<T> = ToolInterface<T, unknown>['inputSchema'];\ntype FlexibleOutputSchema<T> = ToolInterface<unknown, T>['outputSchema'];\n\nexport type ToolMetadata<ToolInputType, ToolOutputType> = {\n name: string;\n description: string;\n inputSchema: FlexibleInputSchema<ToolInputType>;\n outputSchema: FlexibleOutputSchema<ToolOutputType>;\n needsApproval: boolean;\n};\n\n/**\n * Base class for a tool.\n */\nexport abstract class ToolBase<\n ToolConfig extends ToolBaseConfig,\n ToolInputType,\n ToolOutputType,\n> implements ToolInterface<ToolInputType, ToolOutputType> {\n readonly _toolConfig!: ToolConfig;\n protected readonly _name: string;\n protected readonly _description: string;\n protected readonly _inputSchema: FlexibleInputSchema<ToolInputType>;\n protected readonly _outputSchema: FlexibleOutputSchema<ToolOutputType>;\n protected readonly _needsApproval: boolean;\n\n /**\n * Constructs a new tool instance.\n *\n * @param toolConfig - Optional tool config, can be used to override some defaults.\n */\n constructor(toolConfig?: ToolConfig) {\n const {\n name: defaultName,\n description: defaultDescription,\n inputSchema,\n outputSchema,\n needsApproval: defaultNeedsApproval,\n } = this.getMetadata();\n\n this._name = toolConfig?.name || defaultName;\n this._description = toolConfig?.description || defaultDescription;\n this._inputSchema = inputSchema;\n this._outputSchema = outputSchema;\n this._needsApproval =\n toolConfig?.needsApproval !== undefined\n ? toolConfig.needsApproval\n : defaultNeedsApproval;\n }\n\n /**\n * Gets the tool name.\n *\n * @returns The tool name.\n */\n get name(): string {\n return this._name;\n }\n\n /**\n * Gets the tool description.\n *\n * @returns The tool description.\n */\n get description(): string {\n return this._description;\n }\n\n /**\n * Gets the input schema for the tool.\n *\n * @returns The input schema.\n */\n get inputSchema(): FlexibleInputSchema<ToolInputType> {\n return this._inputSchema;\n }\n\n /**\n * Gets the input schema for the tool.\n *\n * @returns The input schema.\n */\n get outputSchema(): FlexibleInputSchema<ToolOutputType> {\n return this._outputSchema;\n }\n\n /**\n * Gets whether the tool needs approval before use.\n *\n * @returns True if the tool needs approval, false otherwise.\n */\n get needsApproval(): boolean {\n return this._needsApproval;\n }\n\n /**\n * Gets the input examples for the tool.\n *\n * This is used for AI SDK v6 compatibility, which supports input examples, but without output examples.\n *\n * @returns The tool input examples.\n */\n get inputExamples(): Array<{ input: ToolInputType }> {\n return this.examples.map((example) => ({ input: example.input }));\n }\n\n /**\n * Gets the examples for the tool.\n *\n * @returns The tool examples.\n */\n abstract get examples(): Array<ToolExample<ToolInputType, ToolOutputType>>;\n\n /**\n * Executes the tool with the given input.\n *\n * @param input - The input for the tool.\n * @param options - Options for the tool execution.\n * @returns A promise that resolves to the tool execution result.\n */\n abstract execute(\n input: ToolInputType,\n options: ToolExecutionOptions,\n ): Promise<ToolOutputType>;\n\n /**\n * Converts the tool output to a format suitable for model consumption.\n *\n * @param options - The tool result, including the output from the tool execution.\n * @returns The formatted tool result.\n */\n abstract toModelOutput(\n options: ModelToolResultToFormat<ToolInputType, ToolOutputType>,\n ): ModelFormattedToolResult;\n\n /**\n * Returns the metadata for the tool.\n *\n * The name, description, and needsApproval properties are defaults which can be overridden in the constructor.\n *\n * @returns The tool metadata.\n */\n protected abstract getMetadata(): ToolMetadata<ToolInputType, ToolOutputType>;\n}\n","import type { ToolExecutionOptions } from 'ai';\nimport type {\n EnvironmentToolInterface,\n ToolConfig as ToolBaseConfig,\n} from '../types';\nimport { ToolBase, type ToolMetadata } from './tool-base';\n\nexport type EnvironmentToolMetadata<ToolInputType, ToolOutputType> =\n ToolMetadata<ToolInputType, ToolOutputType>;\n\n/**\n * Base class for an execution environment tool.\n */\nexport abstract class EnvironmentToolBase<\n ToolConfig extends ToolBaseConfig,\n ToolInputType,\n ToolOutputType,\n EnvironmentType,\n>\n extends ToolBase<ToolConfig, ToolInputType, ToolOutputType>\n implements\n EnvironmentToolInterface<ToolInputType, ToolOutputType, EnvironmentType>\n{\n protected readonly _environment: EnvironmentType;\n\n /**\n * Constructs a new `EnvironmentToolBase` instance.\n *\n * @param environment - The execution environment to apply the tool in.\n * @param toolConfig - Optional tool config, can be used to override some defaults.\n */\n constructor(environment: EnvironmentType, toolConfig?: ToolConfig) {\n super(toolConfig);\n\n this._environment = environment;\n }\n\n /**\n * Gets the current execution environment for the tool.\n *\n * @returns The current execution environment.\n */\n get environment(): EnvironmentType {\n return this._environment;\n }\n\n /**\n * Executes the tool with the given input.\n *\n * @param input - The input for the tool.\n * @param _options - Options for the tool execution.\n * @returns A promise that resolves to the tool execution result.\n */\n override execute(\n input: ToolInputType,\n _options: ToolExecutionOptions,\n ): Promise<ToolOutputType> {\n return this.executeForEnvironment(this._environment, input);\n }\n\n /**\n * Returns the metadata for the tool.\n *\n * The name, description, and needsApproval properties are defaults which can be overridden in the constructor.\n *\n * @returns The tool metadata.\n */\n protected abstract override getMetadata(): EnvironmentToolMetadata<\n ToolInputType,\n ToolOutputType\n >;\n\n /**\n * Executes the tool in the given execution environment with the given input.\n *\n * @param env - The execution environment to use.\n * @param input - The input for the tool.\n * @returns A promise that resolves to the tool execution result.\n */\n protected abstract executeForEnvironment(\n env: EnvironmentType,\n input: ToolInputType,\n ): Promise<ToolOutputType>;\n}\n"],"mappings":"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","names":["path"]}