ai-code-agents 0.1.0-beta.1 → 0.2.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/README.md +27 -23
- package/dist/index.cjs +703 -635
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +289 -567
- package/dist/index.d.ts +289 -567
- package/dist/index.js +752 -639
- package/dist/index.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +27 -7
package/dist/index.js
CHANGED
|
@@ -1,286 +1,16 @@
|
|
|
1
1
|
// src/environments/docker-environment.ts
|
|
2
2
|
import { exec } from "child_process";
|
|
3
|
+
import {
|
|
4
|
+
UnixEnvironmentBase,
|
|
5
|
+
escapeCommandArg
|
|
6
|
+
} from "@ai-code-agents/environment-utils";
|
|
3
7
|
|
|
4
|
-
// src/util/escape-command
|
|
5
|
-
function
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
return `'${arg.replace(/'/g, "'\\''")}'`;
|
|
8
|
+
// src/util/escape-command.ts
|
|
9
|
+
function escapeCommand(command) {
|
|
10
|
+
const escaped = command.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
11
|
+
return `"${escaped}"`;
|
|
10
12
|
}
|
|
11
13
|
|
|
12
|
-
// src/util/validate-relative-path.ts
|
|
13
|
-
import * as path from "path";
|
|
14
|
-
function validateRelativePath(filePath) {
|
|
15
|
-
if (path.isAbsolute(filePath)) {
|
|
16
|
-
throw new Error("Absolute paths are not allowed.");
|
|
17
|
-
}
|
|
18
|
-
if (filePath.startsWith("~")) {
|
|
19
|
-
throw new Error('Paths starting with "~" are not allowed.');
|
|
20
|
-
}
|
|
21
|
-
if (filePath.includes("\0")) {
|
|
22
|
-
throw new Error("Paths must not contain null bytes.");
|
|
23
|
-
}
|
|
24
|
-
const normalizedPath = path.normalize(filePath);
|
|
25
|
-
if (normalizedPath.startsWith("..")) {
|
|
26
|
-
throw new Error("Path traversal is not allowed.");
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// src/environments/filesystem-environment-base.ts
|
|
31
|
-
var FilesystemEnvironmentBase = class {
|
|
32
|
-
_envConfig;
|
|
33
|
-
/**
|
|
34
|
-
* Constructs a new environment instance.
|
|
35
|
-
*
|
|
36
|
-
* @param config - Environment configuration.
|
|
37
|
-
*/
|
|
38
|
-
constructor(config) {
|
|
39
|
-
this._envConfig = config;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Reads the content of a file at the specified path.
|
|
43
|
-
*
|
|
44
|
-
* @param path - The path to the file to read, relative to the project directory.
|
|
45
|
-
* @returns A promise that resolves to a ReadFileResult.
|
|
46
|
-
*/
|
|
47
|
-
async readFile(path5) {
|
|
48
|
-
validateRelativePath(path5);
|
|
49
|
-
if (!await this.fileExists(path5)) {
|
|
50
|
-
throw new Error(`File not found: ${path5}`);
|
|
51
|
-
}
|
|
52
|
-
const content = await this.readFileContent(path5);
|
|
53
|
-
return {
|
|
54
|
-
path: path5,
|
|
55
|
-
content
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Writes content to a file at the specified path.
|
|
60
|
-
*
|
|
61
|
-
* If a file is already present at the path, it will be overwritten.
|
|
62
|
-
*
|
|
63
|
-
* @param path - The path to the file to write, relative to the project directory.
|
|
64
|
-
* @param content - The content to write to the file.
|
|
65
|
-
* @returns A promise that resolves to a WriteFileResult.
|
|
66
|
-
*/
|
|
67
|
-
async writeFile(path5, content) {
|
|
68
|
-
validateRelativePath(path5);
|
|
69
|
-
await this.writeFileContent(path5, content);
|
|
70
|
-
return {
|
|
71
|
-
path: path5,
|
|
72
|
-
message: "File written successfully."
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Deletes a file at the specified path.
|
|
77
|
-
*
|
|
78
|
-
* @param path - The path to the file to delete, relative to the project directory.
|
|
79
|
-
* @returns A promise that resolves to a DeleteFileResult.
|
|
80
|
-
*/
|
|
81
|
-
async deleteFile(path5) {
|
|
82
|
-
validateRelativePath(path5);
|
|
83
|
-
if (!await this.fileExists(path5)) {
|
|
84
|
-
return {
|
|
85
|
-
path: path5,
|
|
86
|
-
message: "File was already deleted."
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
await this.deleteFileContent(path5);
|
|
90
|
-
return {
|
|
91
|
-
path: path5,
|
|
92
|
-
message: "File deleted successfully."
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Moves a file from a source path to a destination path.
|
|
97
|
-
*
|
|
98
|
-
* If a file is already present at the destination path, it will be overwritten.
|
|
99
|
-
*
|
|
100
|
-
* @param sourcePath - The path to the file to move.
|
|
101
|
-
* @param destinationPath - The path to move the file to.
|
|
102
|
-
* @returns A promise that resolves to a MoveFileResult.
|
|
103
|
-
*/
|
|
104
|
-
async moveFile(sourcePath, destinationPath) {
|
|
105
|
-
validateRelativePath(sourcePath);
|
|
106
|
-
validateRelativePath(destinationPath);
|
|
107
|
-
if (!await this.fileExists(sourcePath)) {
|
|
108
|
-
throw new Error(`File not found: ${sourcePath}`);
|
|
109
|
-
}
|
|
110
|
-
await this.moveFileContent(sourcePath, destinationPath);
|
|
111
|
-
return {
|
|
112
|
-
sourcePath,
|
|
113
|
-
destinationPath,
|
|
114
|
-
message: "File moved successfully."
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Copies a file from a source path to a destination path.
|
|
119
|
-
*
|
|
120
|
-
* If a file is already present at the destination path, it will be overwritten.
|
|
121
|
-
*
|
|
122
|
-
* @param sourcePath - The path to the file to copy.
|
|
123
|
-
* @param destinationPath - The path to copy the file to.
|
|
124
|
-
* @returns A promise that resolves to a CopyFileResult.
|
|
125
|
-
*/
|
|
126
|
-
async copyFile(sourcePath, destinationPath) {
|
|
127
|
-
validateRelativePath(sourcePath);
|
|
128
|
-
validateRelativePath(destinationPath);
|
|
129
|
-
if (!await this.fileExists(sourcePath)) {
|
|
130
|
-
throw new Error(`File not found: ${sourcePath}`);
|
|
131
|
-
}
|
|
132
|
-
await this.copyFileContent(sourcePath, destinationPath);
|
|
133
|
-
return {
|
|
134
|
-
sourcePath,
|
|
135
|
-
destinationPath,
|
|
136
|
-
message: "File copied successfully."
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Moves the content of a file from a source path to a destination path, relative to the project directory.
|
|
141
|
-
*
|
|
142
|
-
* When this method is called, it is guaranteed that the source file exists.
|
|
143
|
-
* This method unconditionally moves the content, even if a file already exists at the destination path.
|
|
144
|
-
*
|
|
145
|
-
* @param relativeSourcePath - The path to the file to move, relative to the project directory.
|
|
146
|
-
* @param relativeDestinationPath - The path to move the file to, relative to the project directory.
|
|
147
|
-
*/
|
|
148
|
-
async moveFileContent(relativeSourcePath, relativeDestinationPath) {
|
|
149
|
-
const content = await this.readFileContent(relativeSourcePath);
|
|
150
|
-
this.writeFileContent(relativeDestinationPath, content);
|
|
151
|
-
this.deleteFileContent(relativeSourcePath);
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Copies the content of a file from a source path to a destination path, relative to the project directory.
|
|
155
|
-
*
|
|
156
|
-
* When this method is called, it is guaranteed that the source file exists.
|
|
157
|
-
* This method unconditionally copies the content, even if a file already exists at the destination path.
|
|
158
|
-
*
|
|
159
|
-
* @param relativeSourcePath - The path to the file to copy, relative to the project directory.
|
|
160
|
-
* @param relativeDestinationPath - The path to copy the file to, relative to the project directory.
|
|
161
|
-
*/
|
|
162
|
-
async copyFileContent(relativeSourcePath, relativeDestinationPath) {
|
|
163
|
-
const content = await this.readFileContent(relativeSourcePath);
|
|
164
|
-
this.writeFileContent(relativeDestinationPath, content);
|
|
165
|
-
}
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
// src/environments/command-line-environment-base.ts
|
|
169
|
-
var CommandLineEnvironmentBase = class extends FilesystemEnvironmentBase {
|
|
170
|
-
/**
|
|
171
|
-
* Runs a CLI command in environment.
|
|
172
|
-
*
|
|
173
|
-
* @param command - The command to run.
|
|
174
|
-
* @returns A promise that resolves to a RunCommandResult.
|
|
175
|
-
*/
|
|
176
|
-
async runCommand(command) {
|
|
177
|
-
const [exitCode, stdout, stderr] = await this.executeCommand(command);
|
|
178
|
-
return {
|
|
179
|
-
command,
|
|
180
|
-
exitCode,
|
|
181
|
-
stdout,
|
|
182
|
-
stderr
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
// src/environments/unix-environment-base.ts
|
|
188
|
-
var UnixEnvironmentBase = class extends CommandLineEnvironmentBase {
|
|
189
|
-
/**
|
|
190
|
-
* Checks whether a file exists at the specified path relative to the project directory.
|
|
191
|
-
*
|
|
192
|
-
* @param relativePath - The path to the file to check, relative to the project directory.
|
|
193
|
-
* @returns True if the file exists, false otherwise.
|
|
194
|
-
*/
|
|
195
|
-
async fileExists(relativePath) {
|
|
196
|
-
const command = `if [ -e ${escapeCommandArg(relativePath)} ]; then echo "yes"; else echo "no"; fi`;
|
|
197
|
-
const { exitCode, stdout } = await this.runCommand(command);
|
|
198
|
-
return exitCode === 0 && stdout.trim() === "yes";
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* Gets the content of a file at the specified path, relative to the project directory.
|
|
202
|
-
*
|
|
203
|
-
* When this method is called, it is guaranteed that the file exists.
|
|
204
|
-
*
|
|
205
|
-
* @param relativePath - The path to the file to read, relative to the project directory.
|
|
206
|
-
* @returns The content of the file.
|
|
207
|
-
*/
|
|
208
|
-
async readFileContent(relativePath) {
|
|
209
|
-
const command = `cat ${escapeCommandArg(relativePath)}`;
|
|
210
|
-
const { exitCode, stdout } = await this.runCommand(command);
|
|
211
|
-
return exitCode === 0 ? stdout : "";
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* Writes content to a file at the specified path, relative to the project directory.
|
|
215
|
-
*
|
|
216
|
-
* This method unconditionally writes the content, even if a file already exists at the path, or if the file is new.
|
|
217
|
-
*
|
|
218
|
-
* @param relativePath - The path to the file to write, relative to the project directory.
|
|
219
|
-
* @param content - The content to write to the file.
|
|
220
|
-
*/
|
|
221
|
-
async writeFileContent(relativePath, content) {
|
|
222
|
-
const command = `sh -c "echo ${escapeCommandArg(
|
|
223
|
-
content
|
|
224
|
-
)} > ${escapeCommandArg(relativePath)}"`;
|
|
225
|
-
const { exitCode, stderr } = await this.runCommand(command);
|
|
226
|
-
if (exitCode !== 0) {
|
|
227
|
-
throw new Error(`Failed to write file: ${stderr || "Unknown error"}`);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
/**
|
|
231
|
-
* Deletes a file at the specified path, relative to the project directory.
|
|
232
|
-
*
|
|
233
|
-
* When this method is called, it is guaranteed that the file exists.
|
|
234
|
-
*
|
|
235
|
-
* @param relativePath - The path to the file to delete, relative to the project directory.
|
|
236
|
-
*/
|
|
237
|
-
async deleteFileContent(relativePath) {
|
|
238
|
-
const command = `rm ${escapeCommandArg(relativePath)}`;
|
|
239
|
-
const { exitCode, stderr } = await this.runCommand(command);
|
|
240
|
-
if (exitCode !== 0) {
|
|
241
|
-
throw new Error(`Failed to delete file: ${stderr || "Unknown error"}`);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
/**
|
|
245
|
-
* Moves the content of a file from a source path to a destination path, relative to the project directory.
|
|
246
|
-
*
|
|
247
|
-
* When this method is called, it is guaranteed that the source file exists.
|
|
248
|
-
* This method unconditionally moves the content, even if a file already exists at the destination path.
|
|
249
|
-
*
|
|
250
|
-
* @param relativeSourcePath - The path to the file to move, relative to the project directory.
|
|
251
|
-
* @param relativeDestinationPath - The path to move the file to, relative to the project directory.
|
|
252
|
-
*/
|
|
253
|
-
async moveFileContent(relativeSourcePath, relativeDestinationPath) {
|
|
254
|
-
const command = `mv ${escapeCommandArg(relativeSourcePath)} ${escapeCommandArg(
|
|
255
|
-
relativeDestinationPath
|
|
256
|
-
)}`;
|
|
257
|
-
const { exitCode, stderr } = await this.runCommand(command);
|
|
258
|
-
if (exitCode !== 0) {
|
|
259
|
-
throw new Error(`Failed to move file: ${stderr || "Unknown error"}`);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
/**
|
|
263
|
-
* Copies the content of a file from a source path to a destination path, relative to the project directory.
|
|
264
|
-
*
|
|
265
|
-
* When this method is called, it is guaranteed that the source file exists.
|
|
266
|
-
* This method unconditionally copies the content, even if a file already exists at the destination path.
|
|
267
|
-
*
|
|
268
|
-
* @param relativeSourcePath - The path to the file to copy, relative to the project directory.
|
|
269
|
-
* @param relativeDestinationPath - The path to copy the file to, relative to the project directory.
|
|
270
|
-
*/
|
|
271
|
-
async copyFileContent(relativeSourcePath, relativeDestinationPath) {
|
|
272
|
-
const command = `cp ${escapeCommandArg(relativeSourcePath)} ${escapeCommandArg(
|
|
273
|
-
relativeDestinationPath
|
|
274
|
-
)}`;
|
|
275
|
-
const result = await this.runCommand(command);
|
|
276
|
-
if (result.exitCode !== 0) {
|
|
277
|
-
throw new Error(
|
|
278
|
-
`Failed to copy file: ${result.stderr || "Unknown error"}`
|
|
279
|
-
);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
};
|
|
283
|
-
|
|
284
14
|
// src/environments/docker-environment.ts
|
|
285
15
|
var DockerEnvironmentName = "docker";
|
|
286
16
|
var DockerEnvironment = class extends UnixEnvironmentBase {
|
|
@@ -312,7 +42,7 @@ var DockerEnvironment = class extends UnixEnvironmentBase {
|
|
|
312
42
|
async executeCommand(command) {
|
|
313
43
|
return new Promise((resolve) => {
|
|
314
44
|
exec(
|
|
315
|
-
`docker exec ${this._envConfig.containerId} ${this._commandPrefix
|
|
45
|
+
`docker exec ${this._envConfig.containerId} sh -c ${escapeCommand(this._commandPrefix + command)}`,
|
|
316
46
|
(error, stdout, stderr) => {
|
|
317
47
|
const exitCode = error ? error.code ?? 1 : 0;
|
|
318
48
|
resolve([exitCode, stdout, stderr]);
|
|
@@ -323,7 +53,8 @@ var DockerEnvironment = class extends UnixEnvironmentBase {
|
|
|
323
53
|
};
|
|
324
54
|
|
|
325
55
|
// src/environments/mock-filesystem-environment.ts
|
|
326
|
-
import
|
|
56
|
+
import path from "path";
|
|
57
|
+
import { FilesystemEnvironmentBase } from "@ai-code-agents/environment-utils";
|
|
327
58
|
var MockFilesystemEnvironmentName = "mock-filesystem";
|
|
328
59
|
var MockFilesystemEnvironment = class extends FilesystemEnvironmentBase {
|
|
329
60
|
files;
|
|
@@ -336,8 +67,8 @@ var MockFilesystemEnvironment = class extends FilesystemEnvironmentBase {
|
|
|
336
67
|
constructor(config = {}) {
|
|
337
68
|
super(config);
|
|
338
69
|
const { initialFiles, directoryPath } = this._envConfig;
|
|
339
|
-
this.files = initialFiles
|
|
340
|
-
this._preparePath = directoryPath ? (filePath) =>
|
|
70
|
+
this.files = initialFiles ? new Map(Object.entries(initialFiles)) : /* @__PURE__ */ new Map();
|
|
71
|
+
this._preparePath = directoryPath ? (filePath) => path.join(directoryPath, filePath) : (filePath) => filePath;
|
|
341
72
|
}
|
|
342
73
|
/**
|
|
343
74
|
* Gets the environment name.
|
|
@@ -390,9 +121,10 @@ var MockFilesystemEnvironment = class extends FilesystemEnvironmentBase {
|
|
|
390
121
|
|
|
391
122
|
// src/environments/node-filesystem-environment.ts
|
|
392
123
|
import fs from "fs/promises";
|
|
393
|
-
import
|
|
124
|
+
import path2 from "path";
|
|
125
|
+
import { FilesystemEnvironmentBase as FilesystemEnvironmentBase2 } from "@ai-code-agents/environment-utils";
|
|
394
126
|
var NodeFilesystemEnvironmentName = "node-filesystem";
|
|
395
|
-
var NodeFilesystemEnvironment = class extends
|
|
127
|
+
var NodeFilesystemEnvironment = class extends FilesystemEnvironmentBase2 {
|
|
396
128
|
/**
|
|
397
129
|
* Constructs a new NodeFilesystemEnvironment instance.
|
|
398
130
|
*
|
|
@@ -419,7 +151,7 @@ var NodeFilesystemEnvironment = class extends FilesystemEnvironmentBase {
|
|
|
419
151
|
* @returns True if the file exists, false otherwise.
|
|
420
152
|
*/
|
|
421
153
|
async fileExists(relativePath) {
|
|
422
|
-
const absolutePath =
|
|
154
|
+
const absolutePath = path2.join(this._envConfig.directoryPath, relativePath);
|
|
423
155
|
try {
|
|
424
156
|
await fs.stat(absolutePath);
|
|
425
157
|
return true;
|
|
@@ -436,7 +168,7 @@ var NodeFilesystemEnvironment = class extends FilesystemEnvironmentBase {
|
|
|
436
168
|
* @returns The content of the file.
|
|
437
169
|
*/
|
|
438
170
|
async readFileContent(relativePath) {
|
|
439
|
-
const absolutePath =
|
|
171
|
+
const absolutePath = path2.join(this._envConfig.directoryPath, relativePath);
|
|
440
172
|
return fs.readFile(absolutePath, "utf-8");
|
|
441
173
|
}
|
|
442
174
|
/**
|
|
@@ -448,7 +180,7 @@ var NodeFilesystemEnvironment = class extends FilesystemEnvironmentBase {
|
|
|
448
180
|
* @param content - The content to write to the file.
|
|
449
181
|
*/
|
|
450
182
|
async writeFileContent(relativePath, content) {
|
|
451
|
-
const absolutePath =
|
|
183
|
+
const absolutePath = path2.join(this._envConfig.directoryPath, relativePath);
|
|
452
184
|
await fs.writeFile(absolutePath, content, "utf-8");
|
|
453
185
|
}
|
|
454
186
|
/**
|
|
@@ -459,7 +191,7 @@ var NodeFilesystemEnvironment = class extends FilesystemEnvironmentBase {
|
|
|
459
191
|
* @param relativePath - The path to the file to delete, relative to the project directory.
|
|
460
192
|
*/
|
|
461
193
|
async deleteFileContent(relativePath) {
|
|
462
|
-
const absolutePath =
|
|
194
|
+
const absolutePath = path2.join(this._envConfig.directoryPath, relativePath);
|
|
463
195
|
await fs.rm(absolutePath);
|
|
464
196
|
}
|
|
465
197
|
/**
|
|
@@ -472,11 +204,11 @@ var NodeFilesystemEnvironment = class extends FilesystemEnvironmentBase {
|
|
|
472
204
|
* @param relativeDestinationPath - The path to move the file to, relative to the project directory.
|
|
473
205
|
*/
|
|
474
206
|
async moveFileContent(relativeSourcePath, relativeDestinationPath) {
|
|
475
|
-
const sourcePath =
|
|
207
|
+
const sourcePath = path2.join(
|
|
476
208
|
this._envConfig.directoryPath,
|
|
477
209
|
relativeSourcePath
|
|
478
210
|
);
|
|
479
|
-
const destinationPath =
|
|
211
|
+
const destinationPath = path2.join(
|
|
480
212
|
this._envConfig.directoryPath,
|
|
481
213
|
relativeDestinationPath
|
|
482
214
|
);
|
|
@@ -486,8 +218,12 @@ var NodeFilesystemEnvironment = class extends FilesystemEnvironmentBase {
|
|
|
486
218
|
|
|
487
219
|
// src/environments/unsafe-local-environment.ts
|
|
488
220
|
import { exec as exec2 } from "child_process";
|
|
221
|
+
import {
|
|
222
|
+
UnixEnvironmentBase as UnixEnvironmentBase2,
|
|
223
|
+
escapeCommandArg as escapeCommandArg2
|
|
224
|
+
} from "@ai-code-agents/environment-utils";
|
|
489
225
|
var UnsafeLocalEnvironmentName = "unsafe-local";
|
|
490
|
-
var UnsafeLocalEnvironment = class extends
|
|
226
|
+
var UnsafeLocalEnvironment = class extends UnixEnvironmentBase2 {
|
|
491
227
|
_commandPrefix;
|
|
492
228
|
/**
|
|
493
229
|
* Constructs a new environment instance.
|
|
@@ -503,7 +239,7 @@ var UnsafeLocalEnvironment = class extends UnixEnvironmentBase {
|
|
|
503
239
|
throw new Error('The directory path must be absolute (start with "/")');
|
|
504
240
|
}
|
|
505
241
|
super(config);
|
|
506
|
-
this._commandPrefix = `cd ${
|
|
242
|
+
this._commandPrefix = `cd ${escapeCommandArg2(directoryPath)} && `;
|
|
507
243
|
}
|
|
508
244
|
/**
|
|
509
245
|
* Gets the environment name.
|
|
@@ -530,180 +266,17 @@ var UnsafeLocalEnvironment = class extends UnixEnvironmentBase {
|
|
|
530
266
|
};
|
|
531
267
|
|
|
532
268
|
// src/tools/copy-file-tool.ts
|
|
533
|
-
import { z
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
path: z.string().meta({
|
|
539
|
-
description: "The path to the file that was read."
|
|
540
|
-
}),
|
|
541
|
-
content: z.string().meta({
|
|
542
|
-
description: "The content of the file that was read."
|
|
543
|
-
})
|
|
544
|
-
});
|
|
545
|
-
var WriteFileResult = z.object({
|
|
546
|
-
path: z.string().meta({
|
|
547
|
-
description: "The path to the file that was written."
|
|
548
|
-
}),
|
|
549
|
-
message: z.string().meta({
|
|
550
|
-
description: "A message indicating the result of the write operation."
|
|
551
|
-
})
|
|
552
|
-
});
|
|
553
|
-
var DeleteFileResult = z.object({
|
|
554
|
-
path: z.string().meta({
|
|
555
|
-
description: "The path to the file that was deleted."
|
|
556
|
-
}),
|
|
557
|
-
message: z.string().meta({
|
|
558
|
-
description: "A message indicating the result of the delete operation."
|
|
559
|
-
})
|
|
560
|
-
});
|
|
561
|
-
var MoveFileResult = z.object({
|
|
562
|
-
sourcePath: z.string().meta({
|
|
563
|
-
description: "The original path of the file that was moved."
|
|
564
|
-
}),
|
|
565
|
-
destinationPath: z.string().meta({
|
|
566
|
-
description: "The new path of the file that was moved to."
|
|
567
|
-
}),
|
|
568
|
-
message: z.string().meta({
|
|
569
|
-
description: "A message indicating the result of the move operation."
|
|
570
|
-
})
|
|
571
|
-
});
|
|
572
|
-
var CopyFileResult = z.object({
|
|
573
|
-
sourcePath: z.string().meta({
|
|
574
|
-
description: "The original path of the file that was copied."
|
|
575
|
-
}),
|
|
576
|
-
destinationPath: z.string().meta({
|
|
577
|
-
description: "The new path of the file that was copied to."
|
|
578
|
-
}),
|
|
579
|
-
message: z.string().meta({
|
|
580
|
-
description: "A message indicating the result of the copy operation."
|
|
581
|
-
})
|
|
582
|
-
});
|
|
583
|
-
var RunCommandResult = z.object({
|
|
584
|
-
command: z.string().meta({
|
|
585
|
-
description: "The command that was executed."
|
|
586
|
-
}),
|
|
587
|
-
exitCode: z.number().meta({
|
|
588
|
-
description: "The exit code of the command."
|
|
589
|
-
}),
|
|
590
|
-
stdout: z.string().meta({
|
|
591
|
-
description: "The standard output of the command."
|
|
592
|
-
}),
|
|
593
|
-
stderr: z.string().meta({
|
|
594
|
-
description: "The standard error output of the command."
|
|
595
|
-
})
|
|
596
|
-
});
|
|
597
|
-
|
|
598
|
-
// src/tools/tool-base.ts
|
|
599
|
-
var ToolBase = class {
|
|
600
|
-
_toolConfig;
|
|
601
|
-
_name;
|
|
602
|
-
_description;
|
|
603
|
-
_inputSchema;
|
|
604
|
-
_outputSchema;
|
|
605
|
-
_needsApproval;
|
|
606
|
-
/**
|
|
607
|
-
* Constructs a new tool instance.
|
|
608
|
-
*
|
|
609
|
-
* @param toolConfig - Optional tool config, can be used to override some defaults.
|
|
610
|
-
*/
|
|
611
|
-
constructor(toolConfig) {
|
|
612
|
-
const {
|
|
613
|
-
name: defaultName,
|
|
614
|
-
description: defaultDescription,
|
|
615
|
-
inputSchema,
|
|
616
|
-
outputSchema,
|
|
617
|
-
needsApproval: defaultNeedsApproval
|
|
618
|
-
} = this.getMetadata();
|
|
619
|
-
this._name = toolConfig?.name || defaultName;
|
|
620
|
-
this._description = toolConfig?.description || defaultDescription;
|
|
621
|
-
this._inputSchema = inputSchema;
|
|
622
|
-
this._outputSchema = outputSchema;
|
|
623
|
-
this._needsApproval = toolConfig?.needsApproval !== void 0 ? toolConfig.needsApproval : defaultNeedsApproval;
|
|
624
|
-
}
|
|
625
|
-
/**
|
|
626
|
-
* Gets the tool name.
|
|
627
|
-
*
|
|
628
|
-
* @returns The tool name.
|
|
629
|
-
*/
|
|
630
|
-
get name() {
|
|
631
|
-
return this._name;
|
|
632
|
-
}
|
|
633
|
-
/**
|
|
634
|
-
* Gets the tool description.
|
|
635
|
-
*
|
|
636
|
-
* @returns The tool description.
|
|
637
|
-
*/
|
|
638
|
-
get description() {
|
|
639
|
-
return this._description;
|
|
640
|
-
}
|
|
641
|
-
/**
|
|
642
|
-
* Gets the input schema for the tool.
|
|
643
|
-
*
|
|
644
|
-
* @returns The input schema.
|
|
645
|
-
*/
|
|
646
|
-
get inputSchema() {
|
|
647
|
-
return this._inputSchema;
|
|
648
|
-
}
|
|
649
|
-
/**
|
|
650
|
-
* Gets the input schema for the tool.
|
|
651
|
-
*
|
|
652
|
-
* @returns The input schema.
|
|
653
|
-
*/
|
|
654
|
-
get outputSchema() {
|
|
655
|
-
return this._outputSchema;
|
|
656
|
-
}
|
|
657
|
-
/**
|
|
658
|
-
* Gets whether the tool needs approval before use.
|
|
659
|
-
*
|
|
660
|
-
* @returns True if the tool needs approval, false otherwise.
|
|
661
|
-
*/
|
|
662
|
-
get needsApproval() {
|
|
663
|
-
return this._needsApproval;
|
|
664
|
-
}
|
|
665
|
-
};
|
|
666
|
-
|
|
667
|
-
// src/tools/environment-tool-base.ts
|
|
668
|
-
var EnvironmentToolBase = class extends ToolBase {
|
|
669
|
-
_environment;
|
|
670
|
-
/**
|
|
671
|
-
* Constructs a new `EnvironmentToolBase` instance.
|
|
672
|
-
*
|
|
673
|
-
* @param environment - The execution environment to apply the tool in.
|
|
674
|
-
* @param toolConfig - Optional tool config, can be used to override some defaults.
|
|
675
|
-
*/
|
|
676
|
-
constructor(environment, toolConfig) {
|
|
677
|
-
super(toolConfig);
|
|
678
|
-
this._environment = environment;
|
|
679
|
-
}
|
|
680
|
-
/**
|
|
681
|
-
* Gets the current execution environment for the tool.
|
|
682
|
-
*
|
|
683
|
-
* @returns The current execution environment.
|
|
684
|
-
*/
|
|
685
|
-
get environment() {
|
|
686
|
-
return this._environment;
|
|
687
|
-
}
|
|
688
|
-
/**
|
|
689
|
-
* Executes the tool with the given input.
|
|
690
|
-
*
|
|
691
|
-
* @param input - The input for the tool.
|
|
692
|
-
* @param _options - Options from the tool call.
|
|
693
|
-
* @returns A promise that resolves to the tool execution result.
|
|
694
|
-
*/
|
|
695
|
-
execute(input, _options) {
|
|
696
|
-
return this.executeForEnvironment(this._environment, input);
|
|
697
|
-
}
|
|
698
|
-
};
|
|
699
|
-
|
|
700
|
-
// src/tools/copy-file-tool.ts
|
|
269
|
+
import { z } from "zod";
|
|
270
|
+
import {
|
|
271
|
+
EnvironmentToolBase,
|
|
272
|
+
CopyFileResult
|
|
273
|
+
} from "@ai-code-agents/environment-utils";
|
|
701
274
|
var CopyFileToolName = "copy_file";
|
|
702
|
-
var CopyFileToolInput =
|
|
703
|
-
sourcePath:
|
|
275
|
+
var CopyFileToolInput = z.object({
|
|
276
|
+
sourcePath: z.string().meta({
|
|
704
277
|
description: "The path to the file to copy, relative to the project directory."
|
|
705
278
|
}),
|
|
706
|
-
destinationPath:
|
|
279
|
+
destinationPath: z.string().meta({
|
|
707
280
|
description: "The path to the destination where the file should be copied, relative to the project directory. If the file already exists, it will be overwritten."
|
|
708
281
|
})
|
|
709
282
|
});
|
|
@@ -738,10 +311,11 @@ var CopyFileTool = class extends EnvironmentToolBase {
|
|
|
738
311
|
/**
|
|
739
312
|
* Converts the tool output to a format suitable for model consumption.
|
|
740
313
|
*
|
|
741
|
-
* @param
|
|
314
|
+
* @param options - The tool result, including the output from the tool execution.
|
|
742
315
|
* @returns The formatted tool result.
|
|
743
316
|
*/
|
|
744
|
-
toModelOutput(
|
|
317
|
+
toModelOutput(options) {
|
|
318
|
+
const { output } = options;
|
|
745
319
|
return {
|
|
746
320
|
type: "text",
|
|
747
321
|
value: `File \`${output.sourcePath}\` copied successfully to \`${output.destinationPath}\`.`
|
|
@@ -766,15 +340,19 @@ var CopyFileTool = class extends EnvironmentToolBase {
|
|
|
766
340
|
};
|
|
767
341
|
|
|
768
342
|
// src/tools/delete-file-tool.ts
|
|
769
|
-
import { z as
|
|
343
|
+
import { z as z2 } from "zod";
|
|
344
|
+
import {
|
|
345
|
+
EnvironmentToolBase as EnvironmentToolBase2,
|
|
346
|
+
DeleteFileResult
|
|
347
|
+
} from "@ai-code-agents/environment-utils";
|
|
770
348
|
var DeleteFileToolName = "delete_file";
|
|
771
|
-
var DeleteFileToolInput =
|
|
772
|
-
path:
|
|
349
|
+
var DeleteFileToolInput = z2.object({
|
|
350
|
+
path: z2.string().meta({
|
|
773
351
|
description: "The path to the file to delete, relative to the project directory."
|
|
774
352
|
})
|
|
775
353
|
});
|
|
776
354
|
var DeleteFileToolOutput = DeleteFileResult;
|
|
777
|
-
var DeleteFileTool = class extends
|
|
355
|
+
var DeleteFileTool = class extends EnvironmentToolBase2 {
|
|
778
356
|
/**
|
|
779
357
|
* Returns the metadata for the tool.
|
|
780
358
|
*
|
|
@@ -804,10 +382,11 @@ var DeleteFileTool = class extends EnvironmentToolBase {
|
|
|
804
382
|
/**
|
|
805
383
|
* Converts the tool output to a format suitable for model consumption.
|
|
806
384
|
*
|
|
807
|
-
* @param
|
|
385
|
+
* @param options - The tool result, including the output from the tool execution.
|
|
808
386
|
* @returns The formatted tool result.
|
|
809
387
|
*/
|
|
810
|
-
toModelOutput(
|
|
388
|
+
toModelOutput(options) {
|
|
389
|
+
const { output } = options;
|
|
811
390
|
return {
|
|
812
391
|
type: "text",
|
|
813
392
|
value: `File \`${output.path}\` deleted successfully.`
|
|
@@ -831,43 +410,46 @@ var DeleteFileTool = class extends EnvironmentToolBase {
|
|
|
831
410
|
};
|
|
832
411
|
|
|
833
412
|
// src/tools/edit-file-tool.ts
|
|
834
|
-
import { z as
|
|
413
|
+
import { z as z3 } from "zod";
|
|
414
|
+
import {
|
|
415
|
+
EnvironmentToolBase as EnvironmentToolBase3
|
|
416
|
+
} from "@ai-code-agents/environment-utils";
|
|
835
417
|
var EditFileToolName = "edit_file";
|
|
836
|
-
var EditFileToolInput =
|
|
837
|
-
path:
|
|
418
|
+
var EditFileToolInput = z3.object({
|
|
419
|
+
path: z3.string().meta({
|
|
838
420
|
description: "The path to the file to edit, relative to the project directory."
|
|
839
421
|
}),
|
|
840
|
-
oldString:
|
|
422
|
+
oldString: z3.string().meta({
|
|
841
423
|
description: "The exact string to replace in the file."
|
|
842
424
|
}),
|
|
843
|
-
newString:
|
|
425
|
+
newString: z3.string().meta({
|
|
844
426
|
description: "The string to replace the old string with."
|
|
845
427
|
}),
|
|
846
|
-
replaceAll:
|
|
428
|
+
replaceAll: z3.boolean().optional().meta({
|
|
847
429
|
description: "Whether to replace all occurrences of the old string. Defaults to false."
|
|
848
430
|
})
|
|
849
431
|
});
|
|
850
|
-
var EditFileToolOutput =
|
|
851
|
-
path:
|
|
432
|
+
var EditFileToolOutput = z3.object({
|
|
433
|
+
path: z3.string().meta({
|
|
852
434
|
description: "The path to the file that was edited."
|
|
853
435
|
}),
|
|
854
|
-
oldString:
|
|
436
|
+
oldString: z3.string().meta({
|
|
855
437
|
description: "The old string that was replaced."
|
|
856
438
|
}),
|
|
857
|
-
newString:
|
|
439
|
+
newString: z3.string().meta({
|
|
858
440
|
description: "The new string that replaced the old string."
|
|
859
441
|
}),
|
|
860
|
-
replacements:
|
|
442
|
+
replacements: z3.number().meta({
|
|
861
443
|
description: "The number of replacements made."
|
|
862
444
|
}),
|
|
863
|
-
message:
|
|
445
|
+
message: z3.string().meta({
|
|
864
446
|
description: "A message indicating the result of the edit operation."
|
|
865
447
|
})
|
|
866
448
|
});
|
|
867
|
-
function escapeRegExp(
|
|
868
|
-
return
|
|
449
|
+
function escapeRegExp(string) {
|
|
450
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
869
451
|
}
|
|
870
|
-
var EditFileTool = class extends
|
|
452
|
+
var EditFileTool = class extends EnvironmentToolBase3 {
|
|
871
453
|
/**
|
|
872
454
|
* Returns the metadata for the tool.
|
|
873
455
|
*
|
|
@@ -922,10 +504,11 @@ var EditFileTool = class extends EnvironmentToolBase {
|
|
|
922
504
|
/**
|
|
923
505
|
* Converts the tool output to a format suitable for model consumption.
|
|
924
506
|
*
|
|
925
|
-
* @param
|
|
507
|
+
* @param options - The tool result, including the output from the tool execution.
|
|
926
508
|
* @returns The formatted tool result.
|
|
927
509
|
*/
|
|
928
|
-
toModelOutput(
|
|
510
|
+
toModelOutput(options) {
|
|
511
|
+
const { output } = options;
|
|
929
512
|
return {
|
|
930
513
|
type: "text",
|
|
931
514
|
value: `Edited file \`${output.path}\` with ${output.replacements} replacement(s).`
|
|
@@ -973,7 +556,11 @@ var EditFileTool = class extends EnvironmentToolBase {
|
|
|
973
556
|
};
|
|
974
557
|
|
|
975
558
|
// src/tools/get-project-file-structure-tool.ts
|
|
976
|
-
import { z as
|
|
559
|
+
import { z as z4 } from "zod";
|
|
560
|
+
import {
|
|
561
|
+
EnvironmentToolBase as EnvironmentToolBase4,
|
|
562
|
+
escapeCommandArg as escapeCommandArg4
|
|
563
|
+
} from "@ai-code-agents/environment-utils";
|
|
977
564
|
|
|
978
565
|
// src/util/build-tree-from-files.ts
|
|
979
566
|
function renderTree(node, prefix = "") {
|
|
@@ -1004,31 +591,118 @@ function buildTreeFromFiles(files) {
|
|
|
1004
591
|
if (!current[part]) {
|
|
1005
592
|
current[part] = {};
|
|
1006
593
|
}
|
|
1007
|
-
current = current[part];
|
|
594
|
+
current = current[part];
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
return renderTree(tree).trim();
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// src/util/get-gitignored-paths.ts
|
|
601
|
+
import path3 from "path";
|
|
602
|
+
import {
|
|
603
|
+
escapeCommandArg as escapeCommandArg3
|
|
604
|
+
} from "@ai-code-agents/environment-utils";
|
|
605
|
+
async function getGitIgnoredPaths(env) {
|
|
606
|
+
const gitignorePath = await getClosestGitIgnorePath(env);
|
|
607
|
+
if (!gitignorePath) {
|
|
608
|
+
return [];
|
|
609
|
+
}
|
|
610
|
+
const { stdout: pwd } = await env.runCommand("pwd");
|
|
611
|
+
const currentDir = pwd.trim();
|
|
612
|
+
const gitignoreDir = path3.dirname(gitignorePath);
|
|
613
|
+
try {
|
|
614
|
+
const { stdout, exitCode } = await env.runCommand(
|
|
615
|
+
`cat ${escapeCommandArg3(gitignorePath)}`
|
|
616
|
+
);
|
|
617
|
+
if (exitCode !== 0) {
|
|
618
|
+
return [];
|
|
619
|
+
}
|
|
620
|
+
const rawRules = stdout.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
|
|
621
|
+
const relPath = path3.relative(gitignoreDir, currentDir);
|
|
622
|
+
if (relPath === "") {
|
|
623
|
+
return rawRules.map(
|
|
624
|
+
(rule) => rule.startsWith("/") ? rule.slice(1) : rule
|
|
625
|
+
);
|
|
626
|
+
}
|
|
627
|
+
const relPathSegments = relPath.split(path3.sep);
|
|
628
|
+
const sanitizedRules = [];
|
|
629
|
+
for (const rule of rawRules) {
|
|
630
|
+
const isAnchored = rule.startsWith("/") || rule.includes("/") && rule.indexOf("/") !== rule.length - 1;
|
|
631
|
+
if (!isAnchored || rule.startsWith("**/")) {
|
|
632
|
+
sanitizedRules.push(rule.startsWith("**/") ? rule.slice(3) : rule);
|
|
633
|
+
continue;
|
|
634
|
+
}
|
|
635
|
+
const normalizedRule = rule.startsWith("/") ? rule.slice(1) : rule;
|
|
636
|
+
const cleanRule = normalizedRule.endsWith("/") ? normalizedRule.slice(0, -1) : normalizedRule;
|
|
637
|
+
const ruleSegments = cleanRule.split("/");
|
|
638
|
+
let matches = true;
|
|
639
|
+
let i = 0;
|
|
640
|
+
for (; i < relPathSegments.length; i++) {
|
|
641
|
+
if (i >= ruleSegments.length) {
|
|
642
|
+
sanitizedRules.push(".");
|
|
643
|
+
matches = false;
|
|
644
|
+
break;
|
|
645
|
+
}
|
|
646
|
+
if (!matchSegment(ruleSegments[i], relPathSegments[i])) {
|
|
647
|
+
matches = false;
|
|
648
|
+
break;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
if (matches) {
|
|
652
|
+
const remaining = ruleSegments.slice(i).join("/");
|
|
653
|
+
if (remaining) {
|
|
654
|
+
sanitizedRules.push(
|
|
655
|
+
normalizedRule.endsWith("/") && !remaining.endsWith("/") ? `${remaining}/` : remaining
|
|
656
|
+
);
|
|
657
|
+
} else {
|
|
658
|
+
sanitizedRules.push(".");
|
|
659
|
+
}
|
|
660
|
+
}
|
|
1008
661
|
}
|
|
662
|
+
return [...new Set(sanitizedRules)];
|
|
663
|
+
} catch (_error) {
|
|
664
|
+
return [];
|
|
1009
665
|
}
|
|
1010
|
-
|
|
666
|
+
}
|
|
667
|
+
function matchSegment(pattern, segment) {
|
|
668
|
+
if (pattern === "*") {
|
|
669
|
+
return true;
|
|
670
|
+
}
|
|
671
|
+
if (pattern === segment) {
|
|
672
|
+
return true;
|
|
673
|
+
}
|
|
674
|
+
if (pattern.includes("*") || pattern.includes("?")) {
|
|
675
|
+
const regexStr = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
676
|
+
const regex = new RegExp(`^${regexStr}$`);
|
|
677
|
+
return regex.test(segment);
|
|
678
|
+
}
|
|
679
|
+
return false;
|
|
680
|
+
}
|
|
681
|
+
async function getClosestGitIgnorePath(env) {
|
|
682
|
+
const command = 'd=$PWD; while [ -n "$d" ] && [ ! -f "$d/.gitignore" ]; do d=${d%/*}; done; [ -f "$d/.gitignore" ] && echo "$d/.gitignore"';
|
|
683
|
+
const { stdout } = await env.runCommand(command);
|
|
684
|
+
return stdout.trim();
|
|
1011
685
|
}
|
|
1012
686
|
|
|
1013
687
|
// src/tools/get-project-file-structure-tool.ts
|
|
1014
688
|
var GetProjectFileStructureToolName = "get_project_file_structure";
|
|
1015
|
-
var GetProjectFileStructureToolInput =
|
|
1016
|
-
path:
|
|
689
|
+
var GetProjectFileStructureToolInput = z4.object({
|
|
690
|
+
path: z4.string().optional().meta({
|
|
1017
691
|
description: 'Root path to list files from, relative to the project directory. Defaults to ".".'
|
|
1018
692
|
}),
|
|
1019
|
-
excludeGitIgnored:
|
|
693
|
+
excludeGitIgnored: z4.boolean().optional().meta({
|
|
1020
694
|
description: "Whether to exclude files ignored by Git. Defaults to true."
|
|
1021
695
|
})
|
|
1022
696
|
});
|
|
1023
|
-
var GetProjectFileStructureToolOutput =
|
|
1024
|
-
files:
|
|
697
|
+
var GetProjectFileStructureToolOutput = z4.object({
|
|
698
|
+
files: z4.array(z4.string()).meta({
|
|
1025
699
|
description: "List of all file paths found, relative to the root path."
|
|
1026
700
|
}),
|
|
1027
|
-
excludeGitIgnored:
|
|
701
|
+
excludeGitIgnored: z4.boolean().meta({
|
|
1028
702
|
description: "Whether files ignored by Git were excluded."
|
|
1029
703
|
})
|
|
1030
704
|
});
|
|
1031
|
-
var GetProjectFileStructureTool = class extends
|
|
705
|
+
var GetProjectFileStructureTool = class extends EnvironmentToolBase4 {
|
|
1032
706
|
/**
|
|
1033
707
|
* Returns the metadata for the tool.
|
|
1034
708
|
*
|
|
@@ -1054,21 +728,16 @@ var GetProjectFileStructureTool = class extends EnvironmentToolBase {
|
|
|
1054
728
|
*/
|
|
1055
729
|
async executeForEnvironment(env, input) {
|
|
1056
730
|
const { path: path5 = ".", excludeGitIgnored = true } = input;
|
|
1057
|
-
const escapedPath =
|
|
731
|
+
const escapedPath = escapeCommandArg4(path5);
|
|
1058
732
|
let command = `find ${escapedPath} -type f`;
|
|
1059
733
|
if (excludeGitIgnored) {
|
|
1060
|
-
|
|
1061
|
-
try {
|
|
1062
|
-
const { content: gitignoreContent } = await env.readFile(".gitignore");
|
|
1063
|
-
gitIgnoredPaths = gitignoreContent.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
|
|
1064
|
-
} catch (_error) {
|
|
1065
|
-
}
|
|
734
|
+
const gitIgnoredPaths = await getGitIgnoredPaths(env);
|
|
1066
735
|
for (const gitIgnoredPath of gitIgnoredPaths) {
|
|
1067
736
|
if (!gitIgnoredPath.endsWith("/")) {
|
|
1068
|
-
const escapedPath2 =
|
|
1069
|
-
command += ` -not -name ${
|
|
737
|
+
const escapedPath2 = escapeCommandArg4(`*/${gitIgnoredPath}/*`);
|
|
738
|
+
command += ` -not -name ${escapeCommandArg4(gitIgnoredPath)} -not -path ${escapedPath2}`;
|
|
1070
739
|
} else {
|
|
1071
|
-
const escapedPath2 =
|
|
740
|
+
const escapedPath2 = escapeCommandArg4(`*/${gitIgnoredPath}*`);
|
|
1072
741
|
command += ` -not -path ${escapedPath2}`;
|
|
1073
742
|
}
|
|
1074
743
|
}
|
|
@@ -1090,10 +759,11 @@ var GetProjectFileStructureTool = class extends EnvironmentToolBase {
|
|
|
1090
759
|
/**
|
|
1091
760
|
* Converts the tool output to a format suitable for model consumption.
|
|
1092
761
|
*
|
|
1093
|
-
* @param
|
|
762
|
+
* @param options - The tool result, including the output from the tool execution.
|
|
1094
763
|
* @returns The formatted tool result.
|
|
1095
764
|
*/
|
|
1096
|
-
toModelOutput(
|
|
765
|
+
toModelOutput(options) {
|
|
766
|
+
const { output } = options;
|
|
1097
767
|
const tree = buildTreeFromFiles(output.files);
|
|
1098
768
|
if (!tree) {
|
|
1099
769
|
return {
|
|
@@ -1131,7 +801,12 @@ var GetProjectFileStructureTool = class extends EnvironmentToolBase {
|
|
|
1131
801
|
};
|
|
1132
802
|
|
|
1133
803
|
// src/tools/glob-tool.ts
|
|
1134
|
-
import { z as
|
|
804
|
+
import { z as z5 } from "zod";
|
|
805
|
+
import {
|
|
806
|
+
EnvironmentToolBase as EnvironmentToolBase5,
|
|
807
|
+
escapeCommandArg as escapeCommandArg5,
|
|
808
|
+
validateRelativePath
|
|
809
|
+
} from "@ai-code-agents/environment-utils";
|
|
1135
810
|
|
|
1136
811
|
// src/util/glob-to-reg-exp.ts
|
|
1137
812
|
function globToRegExp(glob) {
|
|
@@ -1179,32 +854,32 @@ function globToRegExp(glob) {
|
|
|
1179
854
|
|
|
1180
855
|
// src/tools/glob-tool.ts
|
|
1181
856
|
var GlobToolName = "glob";
|
|
1182
|
-
var GlobToolInput =
|
|
1183
|
-
searchPattern:
|
|
857
|
+
var GlobToolInput = z5.object({
|
|
858
|
+
searchPattern: z5.string().meta({
|
|
1184
859
|
description: 'The glob pattern to search for, relative to the search path / project directory (e.g. "**/*.ts", "docs/*.md").'
|
|
1185
860
|
}),
|
|
1186
|
-
searchPath:
|
|
861
|
+
searchPath: z5.string().optional().meta({
|
|
1187
862
|
description: "The path to search within, relative to the project directory. Defaults to the project directory."
|
|
1188
863
|
}),
|
|
1189
|
-
excludeGitIgnored:
|
|
864
|
+
excludeGitIgnored: z5.boolean().optional().meta({
|
|
1190
865
|
description: "Whether to exclude files ignored by Git. Defaults to true."
|
|
1191
866
|
})
|
|
1192
867
|
});
|
|
1193
|
-
var GlobToolOutput =
|
|
1194
|
-
searchPattern:
|
|
868
|
+
var GlobToolOutput = z5.object({
|
|
869
|
+
searchPattern: z5.string().meta({
|
|
1195
870
|
description: "The glob pattern that was searched for."
|
|
1196
871
|
}),
|
|
1197
|
-
searchPath:
|
|
872
|
+
searchPath: z5.string().meta({
|
|
1198
873
|
description: "The path that was searched within."
|
|
1199
874
|
}),
|
|
1200
|
-
excludeGitIgnored:
|
|
875
|
+
excludeGitIgnored: z5.boolean().meta({
|
|
1201
876
|
description: "Whether files ignored by Git were excluded."
|
|
1202
877
|
}),
|
|
1203
|
-
matchingPaths:
|
|
878
|
+
matchingPaths: z5.array(z5.string()).meta({
|
|
1204
879
|
description: "The list of file paths that matched the glob search, relative to the project directory."
|
|
1205
880
|
})
|
|
1206
881
|
});
|
|
1207
|
-
var GlobTool = class extends
|
|
882
|
+
var GlobTool = class extends EnvironmentToolBase5 {
|
|
1208
883
|
/**
|
|
1209
884
|
* Returns the metadata for the tool.
|
|
1210
885
|
*
|
|
@@ -1239,21 +914,16 @@ var GlobTool = class extends EnvironmentToolBase {
|
|
|
1239
914
|
validateRelativePath(searchPath);
|
|
1240
915
|
}
|
|
1241
916
|
const untrailingslashedSearchPath = searchPath === "" ? "." : searchPath.replace(/\/+$/, "");
|
|
1242
|
-
const escapedSearchPath =
|
|
917
|
+
const escapedSearchPath = escapeCommandArg5(untrailingslashedSearchPath);
|
|
1243
918
|
let command = `find ${escapedSearchPath} -type f`;
|
|
1244
919
|
if (excludeGitIgnored) {
|
|
1245
|
-
|
|
1246
|
-
try {
|
|
1247
|
-
const { content: gitignoreContent } = await env.readFile(".gitignore");
|
|
1248
|
-
gitIgnoredPaths = gitignoreContent.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
|
|
1249
|
-
} catch (_error) {
|
|
1250
|
-
}
|
|
920
|
+
const gitIgnoredPaths = await getGitIgnoredPaths(env);
|
|
1251
921
|
for (const gitIgnoredPath of gitIgnoredPaths) {
|
|
1252
922
|
if (!gitIgnoredPath.endsWith("/")) {
|
|
1253
|
-
const escapedPath =
|
|
1254
|
-
command += ` -not -name ${
|
|
923
|
+
const escapedPath = escapeCommandArg5(`*/${gitIgnoredPath}/*`);
|
|
924
|
+
command += ` -not -name ${escapeCommandArg5(gitIgnoredPath)} -not -path ${escapedPath}`;
|
|
1255
925
|
} else {
|
|
1256
|
-
const escapedPath =
|
|
926
|
+
const escapedPath = escapeCommandArg5(`*/${gitIgnoredPath}*`);
|
|
1257
927
|
command += ` -not -path ${escapedPath}`;
|
|
1258
928
|
}
|
|
1259
929
|
}
|
|
@@ -1289,10 +959,11 @@ var GlobTool = class extends EnvironmentToolBase {
|
|
|
1289
959
|
/**
|
|
1290
960
|
* Converts the tool output to a format suitable for model consumption.
|
|
1291
961
|
*
|
|
1292
|
-
* @param
|
|
962
|
+
* @param options - The tool result, including the output from the tool execution.
|
|
1293
963
|
* @returns The formatted tool result.
|
|
1294
964
|
*/
|
|
1295
|
-
toModelOutput(
|
|
965
|
+
toModelOutput(options) {
|
|
966
|
+
const { output } = options;
|
|
1296
967
|
if (output.matchingPaths.length === 0) {
|
|
1297
968
|
return {
|
|
1298
969
|
type: "text",
|
|
@@ -1341,8 +1012,276 @@ ${bulletPoints}
|
|
|
1341
1012
|
}
|
|
1342
1013
|
};
|
|
1343
1014
|
|
|
1015
|
+
// src/tools/grep-tool.ts
|
|
1016
|
+
import { z as z6 } from "zod";
|
|
1017
|
+
import {
|
|
1018
|
+
EnvironmentToolBase as EnvironmentToolBase6,
|
|
1019
|
+
escapeCommandArg as escapeCommandArg6,
|
|
1020
|
+
validateRelativePath as validateRelativePath2
|
|
1021
|
+
} from "@ai-code-agents/environment-utils";
|
|
1022
|
+
var GrepToolName = "grep";
|
|
1023
|
+
var GrepToolInput = z6.object({
|
|
1024
|
+
regexpPattern: z6.string().meta({
|
|
1025
|
+
description: "The regular expression pattern to search for in file contents."
|
|
1026
|
+
}),
|
|
1027
|
+
searchPattern: z6.string().optional().meta({
|
|
1028
|
+
description: 'The glob pattern to filter which files are searched (e.g. "**/*.ts"). If omitted, searches all files.'
|
|
1029
|
+
}),
|
|
1030
|
+
searchPath: z6.string().optional().meta({
|
|
1031
|
+
description: "The path to search within, relative to the project directory. Defaults to the project directory."
|
|
1032
|
+
}),
|
|
1033
|
+
contextLines: z6.number().int().nonnegative().optional().meta({
|
|
1034
|
+
description: "The number of context lines to include before and after each match."
|
|
1035
|
+
})
|
|
1036
|
+
});
|
|
1037
|
+
var GrepMatch = z6.object({
|
|
1038
|
+
path: z6.string().meta({
|
|
1039
|
+
description: "The path to the file containing the match, relative to the project directory."
|
|
1040
|
+
}),
|
|
1041
|
+
lineNumber: z6.number().int().meta({
|
|
1042
|
+
description: "The line number of the match (1-based)."
|
|
1043
|
+
}),
|
|
1044
|
+
line: z6.string().meta({
|
|
1045
|
+
description: "The content of the matching line."
|
|
1046
|
+
}),
|
|
1047
|
+
beforeContext: z6.array(z6.string()).optional().meta({
|
|
1048
|
+
description: "Lines of context before the match."
|
|
1049
|
+
}),
|
|
1050
|
+
afterContext: z6.array(z6.string()).optional().meta({
|
|
1051
|
+
description: "Lines of context after the match."
|
|
1052
|
+
})
|
|
1053
|
+
});
|
|
1054
|
+
var GrepToolOutput = z6.object({
|
|
1055
|
+
regexpPattern: z6.string().meta({
|
|
1056
|
+
description: "The regular expression pattern that was searched for."
|
|
1057
|
+
}),
|
|
1058
|
+
searchPattern: z6.string().optional().meta({
|
|
1059
|
+
description: "The glob pattern used to filter files."
|
|
1060
|
+
}),
|
|
1061
|
+
searchPath: z6.string().optional().meta({
|
|
1062
|
+
description: "The path that was searched within."
|
|
1063
|
+
}),
|
|
1064
|
+
contextLines: z6.number().optional().meta({
|
|
1065
|
+
description: "The number of context lines included."
|
|
1066
|
+
}),
|
|
1067
|
+
matches: z6.array(GrepMatch).meta({
|
|
1068
|
+
description: "The list of matches found."
|
|
1069
|
+
})
|
|
1070
|
+
});
|
|
1071
|
+
var GrepTool = class extends EnvironmentToolBase6 {
|
|
1072
|
+
/**
|
|
1073
|
+
* Returns the metadata for the tool.
|
|
1074
|
+
*
|
|
1075
|
+
* The name, description, and needsApproval properties are defaults which can be overridden in the constructor.
|
|
1076
|
+
*
|
|
1077
|
+
* @returns The tool metadata.
|
|
1078
|
+
*/
|
|
1079
|
+
getMetadata() {
|
|
1080
|
+
return {
|
|
1081
|
+
name: GrepToolName,
|
|
1082
|
+
description: "Searches for a regular expression pattern within the content of files in the project.",
|
|
1083
|
+
inputSchema: GrepToolInput,
|
|
1084
|
+
outputSchema: GrepToolOutput,
|
|
1085
|
+
needsApproval: false
|
|
1086
|
+
};
|
|
1087
|
+
}
|
|
1088
|
+
/**
|
|
1089
|
+
* Executes the tool in the given execution environment with the given input.
|
|
1090
|
+
*
|
|
1091
|
+
* @param env - The execution environment to use.
|
|
1092
|
+
* @param input - The input for the tool.
|
|
1093
|
+
* @returns A promise that resolves to the tool execution result.
|
|
1094
|
+
*/
|
|
1095
|
+
async executeForEnvironment(env, input) {
|
|
1096
|
+
const {
|
|
1097
|
+
regexpPattern,
|
|
1098
|
+
searchPattern,
|
|
1099
|
+
searchPath = "",
|
|
1100
|
+
contextLines = 0
|
|
1101
|
+
} = input;
|
|
1102
|
+
if (searchPath) {
|
|
1103
|
+
validateRelativePath2(searchPath);
|
|
1104
|
+
}
|
|
1105
|
+
const globTool = new GlobTool(env);
|
|
1106
|
+
const globResult = await globTool.execute(
|
|
1107
|
+
{
|
|
1108
|
+
searchPattern: searchPattern || "**/*",
|
|
1109
|
+
searchPath
|
|
1110
|
+
},
|
|
1111
|
+
{}
|
|
1112
|
+
);
|
|
1113
|
+
const filesToSearch = globResult.matchingPaths;
|
|
1114
|
+
if (filesToSearch.length === 0) {
|
|
1115
|
+
return {
|
|
1116
|
+
regexpPattern,
|
|
1117
|
+
searchPattern,
|
|
1118
|
+
searchPath,
|
|
1119
|
+
contextLines,
|
|
1120
|
+
matches: []
|
|
1121
|
+
};
|
|
1122
|
+
}
|
|
1123
|
+
const BATCH_SIZE = 50;
|
|
1124
|
+
const matches = [];
|
|
1125
|
+
for (let i = 0; i < filesToSearch.length; i += BATCH_SIZE) {
|
|
1126
|
+
const batch = filesToSearch.slice(i, i + BATCH_SIZE);
|
|
1127
|
+
const escapedFilePaths = batch.map(escapeCommandArg6).join(" ");
|
|
1128
|
+
const command = `grep -n -H -I -E ${escapeCommandArg6(regexpPattern)} ${escapedFilePaths}`;
|
|
1129
|
+
const { stdout, exitCode } = await env.runCommand(command);
|
|
1130
|
+
if (exitCode > 1) {
|
|
1131
|
+
throw new Error(`Failed to execute grep command "${command}".`);
|
|
1132
|
+
}
|
|
1133
|
+
if (stdout) {
|
|
1134
|
+
const lines = stdout.split("\n");
|
|
1135
|
+
for (const line of lines) {
|
|
1136
|
+
if (!line.trim()) continue;
|
|
1137
|
+
const firstColonIndex = line.indexOf(":");
|
|
1138
|
+
if (firstColonIndex === -1) continue;
|
|
1139
|
+
const secondColonIndex = line.indexOf(":", firstColonIndex + 1);
|
|
1140
|
+
if (secondColonIndex === -1) continue;
|
|
1141
|
+
const filePath = line.substring(0, firstColonIndex);
|
|
1142
|
+
const lineNumberStr = line.substring(
|
|
1143
|
+
firstColonIndex + 1,
|
|
1144
|
+
secondColonIndex
|
|
1145
|
+
);
|
|
1146
|
+
const content = line.substring(secondColonIndex + 1);
|
|
1147
|
+
const lineNumber = parseInt(lineNumberStr, 10);
|
|
1148
|
+
if (isNaN(lineNumber)) continue;
|
|
1149
|
+
matches.push({
|
|
1150
|
+
path: filePath,
|
|
1151
|
+
lineNumber,
|
|
1152
|
+
line: content
|
|
1153
|
+
});
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
if (contextLines > 0 && matches.length > 0) {
|
|
1158
|
+
const matchesByFile = /* @__PURE__ */ new Map();
|
|
1159
|
+
for (const match of matches) {
|
|
1160
|
+
if (!matchesByFile.has(match.path)) {
|
|
1161
|
+
matchesByFile.set(match.path, []);
|
|
1162
|
+
}
|
|
1163
|
+
matchesByFile.get(match.path).push(match);
|
|
1164
|
+
}
|
|
1165
|
+
for (const [filePath, fileMatches] of matchesByFile) {
|
|
1166
|
+
try {
|
|
1167
|
+
const { content } = await env.readFile(filePath);
|
|
1168
|
+
const lines = content.split("\n");
|
|
1169
|
+
for (const match of fileMatches) {
|
|
1170
|
+
const lineIndex = match.lineNumber - 1;
|
|
1171
|
+
const start = Math.max(0, lineIndex - contextLines);
|
|
1172
|
+
const end = Math.min(lines.length, lineIndex + contextLines + 1);
|
|
1173
|
+
match.beforeContext = lines.slice(start, lineIndex);
|
|
1174
|
+
match.afterContext = lines.slice(lineIndex + 1, end);
|
|
1175
|
+
}
|
|
1176
|
+
} catch (_error) {
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
return {
|
|
1181
|
+
regexpPattern,
|
|
1182
|
+
searchPattern,
|
|
1183
|
+
searchPath,
|
|
1184
|
+
contextLines,
|
|
1185
|
+
matches
|
|
1186
|
+
};
|
|
1187
|
+
}
|
|
1188
|
+
/**
|
|
1189
|
+
* Converts the tool output to a format suitable for model consumption.
|
|
1190
|
+
*
|
|
1191
|
+
* @param options - The tool result, including the output from the tool execution.
|
|
1192
|
+
* @returns The formatted tool result.
|
|
1193
|
+
*/
|
|
1194
|
+
toModelOutput(options) {
|
|
1195
|
+
const { output } = options;
|
|
1196
|
+
if (output.matches.length === 0) {
|
|
1197
|
+
return {
|
|
1198
|
+
type: "text",
|
|
1199
|
+
value: "No matches found."
|
|
1200
|
+
};
|
|
1201
|
+
}
|
|
1202
|
+
let result = `Found ${output.matches.length} matches:
|
|
1203
|
+
`;
|
|
1204
|
+
const matchesByFile = /* @__PURE__ */ new Map();
|
|
1205
|
+
for (const match of output.matches) {
|
|
1206
|
+
if (!matchesByFile.has(match.path)) {
|
|
1207
|
+
matchesByFile.set(match.path, []);
|
|
1208
|
+
}
|
|
1209
|
+
matchesByFile.get(match.path).push(match);
|
|
1210
|
+
}
|
|
1211
|
+
for (const [filePath, matches] of matchesByFile) {
|
|
1212
|
+
result += `
|
|
1213
|
+
File: ${filePath}
|
|
1214
|
+
`;
|
|
1215
|
+
for (const match of matches) {
|
|
1216
|
+
if (match.beforeContext && match.beforeContext.length > 0) {
|
|
1217
|
+
match.beforeContext.forEach((line, idx) => {
|
|
1218
|
+
result += ` ${match.lineNumber - match.beforeContext.length + idx}: ${line}
|
|
1219
|
+
`;
|
|
1220
|
+
});
|
|
1221
|
+
}
|
|
1222
|
+
result += `> ${match.lineNumber}: ${match.line}
|
|
1223
|
+
`;
|
|
1224
|
+
if (match.afterContext && match.afterContext.length > 0) {
|
|
1225
|
+
match.afterContext.forEach((line, idx) => {
|
|
1226
|
+
result += ` ${match.lineNumber + 1 + idx}: ${line}
|
|
1227
|
+
`;
|
|
1228
|
+
});
|
|
1229
|
+
}
|
|
1230
|
+
if (output.contextLines && output.contextLines > 0) {
|
|
1231
|
+
result += "---\n";
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
return {
|
|
1236
|
+
type: "text",
|
|
1237
|
+
value: result
|
|
1238
|
+
};
|
|
1239
|
+
}
|
|
1240
|
+
/**
|
|
1241
|
+
* Gets the examples for the tool.
|
|
1242
|
+
*
|
|
1243
|
+
* @returns The tool examples.
|
|
1244
|
+
*/
|
|
1245
|
+
get examples() {
|
|
1246
|
+
return [
|
|
1247
|
+
{
|
|
1248
|
+
input: {
|
|
1249
|
+
regexpPattern: "interface.*Tool",
|
|
1250
|
+
searchPattern: "src/**/*.ts"
|
|
1251
|
+
},
|
|
1252
|
+
output: `Found 2 matches:
|
|
1253
|
+
|
|
1254
|
+
File: src/types.ts
|
|
1255
|
+
> 120: export interface ToolInterface<ToolInputType, ToolOutputType> {
|
|
1256
|
+
> 135: export interface EnvironmentToolInterface<
|
|
1257
|
+
|
|
1258
|
+
File: src/tools/tool-base.ts
|
|
1259
|
+
> 10: export abstract class ToolBase<
|
|
1260
|
+
`
|
|
1261
|
+
},
|
|
1262
|
+
{
|
|
1263
|
+
input: {
|
|
1264
|
+
regexpPattern: "TODO",
|
|
1265
|
+
contextLines: 1
|
|
1266
|
+
},
|
|
1267
|
+
output: `Found 1 matches:
|
|
1268
|
+
|
|
1269
|
+
File: src/index.ts
|
|
1270
|
+
10: // Some code before
|
|
1271
|
+
> 11: // TODO: Implement feature X
|
|
1272
|
+
12: // Some code after
|
|
1273
|
+
`
|
|
1274
|
+
}
|
|
1275
|
+
];
|
|
1276
|
+
}
|
|
1277
|
+
};
|
|
1278
|
+
|
|
1344
1279
|
// src/tools/list-directory-tool.ts
|
|
1345
1280
|
import { z as z7 } from "zod";
|
|
1281
|
+
import {
|
|
1282
|
+
EnvironmentToolBase as EnvironmentToolBase7,
|
|
1283
|
+
escapeCommandArg as escapeCommandArg7
|
|
1284
|
+
} from "@ai-code-agents/environment-utils";
|
|
1346
1285
|
var ListDirectoryToolName = "list_directory";
|
|
1347
1286
|
var ListDirectoryToolInput = z7.object({
|
|
1348
1287
|
path: z7.string().meta({
|
|
@@ -1360,7 +1299,7 @@ var ListDirectoryToolOutput = z7.object({
|
|
|
1360
1299
|
description: "List of subdirectories in the directory."
|
|
1361
1300
|
})
|
|
1362
1301
|
});
|
|
1363
|
-
var ListDirectoryTool = class extends
|
|
1302
|
+
var ListDirectoryTool = class extends EnvironmentToolBase7 {
|
|
1364
1303
|
/**
|
|
1365
1304
|
* Returns the metadata for the tool.
|
|
1366
1305
|
*
|
|
@@ -1385,7 +1324,7 @@ var ListDirectoryTool = class extends EnvironmentToolBase {
|
|
|
1385
1324
|
* @returns A promise that resolves to the tool execution result.
|
|
1386
1325
|
*/
|
|
1387
1326
|
async executeForEnvironment(env, input) {
|
|
1388
|
-
const escapedPath =
|
|
1327
|
+
const escapedPath = escapeCommandArg7(input.path);
|
|
1389
1328
|
const command = `ls -la ${escapedPath}`;
|
|
1390
1329
|
const { stdout, stderr, exitCode } = await env.runCommand(command);
|
|
1391
1330
|
if (exitCode !== 0) {
|
|
@@ -1418,10 +1357,11 @@ var ListDirectoryTool = class extends EnvironmentToolBase {
|
|
|
1418
1357
|
/**
|
|
1419
1358
|
* Converts the tool output to a format suitable for model consumption.
|
|
1420
1359
|
*
|
|
1421
|
-
* @param
|
|
1360
|
+
* @param options - The tool result, including the output from the tool execution.
|
|
1422
1361
|
* @returns The formatted tool result.
|
|
1423
1362
|
*/
|
|
1424
|
-
toModelOutput(
|
|
1363
|
+
toModelOutput(options) {
|
|
1364
|
+
const { output } = options;
|
|
1425
1365
|
const formatEntries = (entries, type) => {
|
|
1426
1366
|
if (entries.length === 0) {
|
|
1427
1367
|
return `No ${type} found.`;
|
|
@@ -1468,6 +1408,10 @@ Directories:
|
|
|
1468
1408
|
|
|
1469
1409
|
// src/tools/move-file-tool.ts
|
|
1470
1410
|
import { z as z8 } from "zod";
|
|
1411
|
+
import {
|
|
1412
|
+
EnvironmentToolBase as EnvironmentToolBase8,
|
|
1413
|
+
MoveFileResult
|
|
1414
|
+
} from "@ai-code-agents/environment-utils";
|
|
1471
1415
|
var MoveFileToolName = "move_file";
|
|
1472
1416
|
var MoveFileToolInput = z8.object({
|
|
1473
1417
|
sourcePath: z8.string().meta({
|
|
@@ -1478,7 +1422,7 @@ var MoveFileToolInput = z8.object({
|
|
|
1478
1422
|
})
|
|
1479
1423
|
});
|
|
1480
1424
|
var MoveFileToolOutput = MoveFileResult;
|
|
1481
|
-
var MoveFileTool = class extends
|
|
1425
|
+
var MoveFileTool = class extends EnvironmentToolBase8 {
|
|
1482
1426
|
/**
|
|
1483
1427
|
* Returns the metadata for the tool.
|
|
1484
1428
|
*
|
|
@@ -1508,10 +1452,11 @@ var MoveFileTool = class extends EnvironmentToolBase {
|
|
|
1508
1452
|
/**
|
|
1509
1453
|
* Converts the tool output to a format suitable for model consumption.
|
|
1510
1454
|
*
|
|
1511
|
-
* @param
|
|
1455
|
+
* @param options - The tool result, including the output from the tool execution.
|
|
1512
1456
|
* @returns The formatted tool result.
|
|
1513
1457
|
*/
|
|
1514
|
-
toModelOutput(
|
|
1458
|
+
toModelOutput(options) {
|
|
1459
|
+
const { output } = options;
|
|
1515
1460
|
return {
|
|
1516
1461
|
type: "text",
|
|
1517
1462
|
value: `File \`${output.sourcePath}\` moved successfully to \`${output.destinationPath}\`.`
|
|
@@ -1537,6 +1482,10 @@ var MoveFileTool = class extends EnvironmentToolBase {
|
|
|
1537
1482
|
|
|
1538
1483
|
// src/tools/read-file-tool.ts
|
|
1539
1484
|
import { z as z9 } from "zod";
|
|
1485
|
+
import {
|
|
1486
|
+
EnvironmentToolBase as EnvironmentToolBase9,
|
|
1487
|
+
ReadFileResult
|
|
1488
|
+
} from "@ai-code-agents/environment-utils";
|
|
1540
1489
|
|
|
1541
1490
|
// src/util/get-language-identifier-from-file-path.ts
|
|
1542
1491
|
import path4 from "path";
|
|
@@ -1714,7 +1663,7 @@ ${output.content}
|
|
|
1714
1663
|
\`\`\`
|
|
1715
1664
|
`;
|
|
1716
1665
|
};
|
|
1717
|
-
var ReadFileTool = class extends
|
|
1666
|
+
var ReadFileTool = class extends EnvironmentToolBase9 {
|
|
1718
1667
|
/**
|
|
1719
1668
|
* Returns the metadata for the tool.
|
|
1720
1669
|
*
|
|
@@ -1744,10 +1693,11 @@ var ReadFileTool = class extends EnvironmentToolBase {
|
|
|
1744
1693
|
/**
|
|
1745
1694
|
* Converts the tool output to a format suitable for model consumption.
|
|
1746
1695
|
*
|
|
1747
|
-
* @param
|
|
1696
|
+
* @param options - The tool result, including the output from the tool execution.
|
|
1748
1697
|
* @returns The formatted tool result.
|
|
1749
1698
|
*/
|
|
1750
|
-
toModelOutput(
|
|
1699
|
+
toModelOutput(options) {
|
|
1700
|
+
const { output } = options;
|
|
1751
1701
|
return {
|
|
1752
1702
|
type: "text",
|
|
1753
1703
|
value: formatModelResponse(output)
|
|
@@ -1791,13 +1741,17 @@ export function Loader(props: LoaderProps) {
|
|
|
1791
1741
|
|
|
1792
1742
|
// src/tools/read-many-files-tool.ts
|
|
1793
1743
|
import { z as z10 } from "zod";
|
|
1744
|
+
import {
|
|
1745
|
+
EnvironmentToolBase as EnvironmentToolBase10,
|
|
1746
|
+
ReadFileResult as ReadFileResult2
|
|
1747
|
+
} from "@ai-code-agents/environment-utils";
|
|
1794
1748
|
var ReadManyFilesToolName = "read_many_files";
|
|
1795
1749
|
var ReadManyFilesToolInput = z10.object({
|
|
1796
1750
|
paths: z10.array(z10.string()).meta({
|
|
1797
1751
|
description: "The paths to the files to read, relative to the project directory."
|
|
1798
1752
|
})
|
|
1799
1753
|
});
|
|
1800
|
-
var ReadManyFilesToolOutput = z10.record(z10.string(),
|
|
1754
|
+
var ReadManyFilesToolOutput = z10.record(z10.string(), ReadFileResult2);
|
|
1801
1755
|
var formatModelResponse2 = (output) => {
|
|
1802
1756
|
const language = getLanguageIdentifierFromFilePath(output.path);
|
|
1803
1757
|
return `File: \`${output.path}\`
|
|
@@ -1807,7 +1761,7 @@ ${output.content}
|
|
|
1807
1761
|
\`\`\`
|
|
1808
1762
|
`;
|
|
1809
1763
|
};
|
|
1810
|
-
var ReadManyFilesTool = class extends
|
|
1764
|
+
var ReadManyFilesTool = class extends EnvironmentToolBase10 {
|
|
1811
1765
|
/**
|
|
1812
1766
|
* Returns the metadata for the tool.
|
|
1813
1767
|
*
|
|
@@ -1843,10 +1797,11 @@ var ReadManyFilesTool = class extends EnvironmentToolBase {
|
|
|
1843
1797
|
/**
|
|
1844
1798
|
* Converts the tool output to a format suitable for model consumption.
|
|
1845
1799
|
*
|
|
1846
|
-
* @param
|
|
1800
|
+
* @param options - The tool result, including the output from the tool execution.
|
|
1847
1801
|
* @returns The formatted tool result.
|
|
1848
1802
|
*/
|
|
1849
|
-
toModelOutput(
|
|
1803
|
+
toModelOutput(options) {
|
|
1804
|
+
const { output } = options;
|
|
1850
1805
|
const fileContentResponses = Object.values(output).map(
|
|
1851
1806
|
(fileResult) => formatModelResponse2(fileResult)
|
|
1852
1807
|
);
|
|
@@ -1903,6 +1858,10 @@ export function Loader(props: LoaderProps) {
|
|
|
1903
1858
|
|
|
1904
1859
|
// src/tools/run-command-tool.ts
|
|
1905
1860
|
import { z as z11 } from "zod";
|
|
1861
|
+
import {
|
|
1862
|
+
EnvironmentToolBase as EnvironmentToolBase11,
|
|
1863
|
+
RunCommandResult
|
|
1864
|
+
} from "@ai-code-agents/environment-utils";
|
|
1906
1865
|
var RunCommandToolName = "run_command";
|
|
1907
1866
|
var RunCommandToolInput = z11.object({
|
|
1908
1867
|
command: z11.string().meta({ description: "The CLI command to run, including all arguments." })
|
|
@@ -1923,7 +1882,7 @@ Output (stdout): ${stdout}
|
|
|
1923
1882
|
Error Output (stderr): ${stderr}
|
|
1924
1883
|
`;
|
|
1925
1884
|
}
|
|
1926
|
-
var RunCommandTool = class extends
|
|
1885
|
+
var RunCommandTool = class extends EnvironmentToolBase11 {
|
|
1927
1886
|
/**
|
|
1928
1887
|
* Returns the metadata for the tool.
|
|
1929
1888
|
*
|
|
@@ -1953,10 +1912,11 @@ var RunCommandTool = class extends EnvironmentToolBase {
|
|
|
1953
1912
|
/**
|
|
1954
1913
|
* Converts the tool output to a format suitable for model consumption.
|
|
1955
1914
|
*
|
|
1956
|
-
* @param
|
|
1915
|
+
* @param options - The tool result, including the output from the tool execution.
|
|
1957
1916
|
* @returns The formatted tool result.
|
|
1958
1917
|
*/
|
|
1959
|
-
toModelOutput(
|
|
1918
|
+
toModelOutput(options) {
|
|
1919
|
+
const { output } = options;
|
|
1960
1920
|
return {
|
|
1961
1921
|
type: "text",
|
|
1962
1922
|
value: formatCommandResultToModelResponse(output)
|
|
@@ -2028,6 +1988,10 @@ added 1 package, and changed 1 package in 2s
|
|
|
2028
1988
|
|
|
2029
1989
|
// src/tools/write-file-tool.ts
|
|
2030
1990
|
import { z as z12 } from "zod";
|
|
1991
|
+
import {
|
|
1992
|
+
EnvironmentToolBase as EnvironmentToolBase12,
|
|
1993
|
+
WriteFileResult
|
|
1994
|
+
} from "@ai-code-agents/environment-utils";
|
|
2031
1995
|
var WriteFileToolName = "write_file";
|
|
2032
1996
|
var WriteFileToolInput = z12.object({
|
|
2033
1997
|
path: z12.string().meta({
|
|
@@ -2038,7 +2002,7 @@ var WriteFileToolInput = z12.object({
|
|
|
2038
2002
|
})
|
|
2039
2003
|
});
|
|
2040
2004
|
var WriteFileToolOutput = WriteFileResult;
|
|
2041
|
-
var WriteFileTool = class extends
|
|
2005
|
+
var WriteFileTool = class extends EnvironmentToolBase12 {
|
|
2042
2006
|
/**
|
|
2043
2007
|
* Returns the metadata for the tool.
|
|
2044
2008
|
*
|
|
@@ -2068,10 +2032,11 @@ var WriteFileTool = class extends EnvironmentToolBase {
|
|
|
2068
2032
|
/**
|
|
2069
2033
|
* Converts the tool output to a format suitable for model consumption.
|
|
2070
2034
|
*
|
|
2071
|
-
* @param
|
|
2035
|
+
* @param options - The tool result, including the output from the tool execution.
|
|
2072
2036
|
* @returns The formatted tool result.
|
|
2073
2037
|
*/
|
|
2074
|
-
toModelOutput(
|
|
2038
|
+
toModelOutput(options) {
|
|
2039
|
+
const { output } = options;
|
|
2075
2040
|
return {
|
|
2076
2041
|
type: "text",
|
|
2077
2042
|
value: `File \`${output.path}\` written successfully.`
|
|
@@ -2099,15 +2064,11 @@ var WriteFileTool = class extends EnvironmentToolBase {
|
|
|
2099
2064
|
}
|
|
2100
2065
|
};
|
|
2101
2066
|
|
|
2102
|
-
// src/agent-creators.ts
|
|
2103
|
-
import {
|
|
2104
|
-
Experimental_Agent as Agent,
|
|
2105
|
-
stepCountIs,
|
|
2106
|
-
hasToolCall
|
|
2107
|
-
} from "ai";
|
|
2108
|
-
|
|
2109
2067
|
// src/tools/submit-tool.ts
|
|
2110
2068
|
import { z as z13 } from "zod";
|
|
2069
|
+
import {
|
|
2070
|
+
ToolBase
|
|
2071
|
+
} from "@ai-code-agents/environment-utils";
|
|
2111
2072
|
var SubmitToolName = "submit";
|
|
2112
2073
|
var SubmitToolInput = z13.object({});
|
|
2113
2074
|
var SubmitToolOutput = z13.object({});
|
|
@@ -2132,7 +2093,7 @@ var SubmitTool = class extends ToolBase {
|
|
|
2132
2093
|
* Executes the tool with the given input.
|
|
2133
2094
|
*
|
|
2134
2095
|
* @param _ - The input for the tool. Unused.
|
|
2135
|
-
* @param __ - Options
|
|
2096
|
+
* @param __ - Options for the tool execution. Unused.
|
|
2136
2097
|
* @returns A promise that resolves to the tool execution result.
|
|
2137
2098
|
*/
|
|
2138
2099
|
async execute(_, __) {
|
|
@@ -2141,7 +2102,7 @@ var SubmitTool = class extends ToolBase {
|
|
|
2141
2102
|
/**
|
|
2142
2103
|
* Converts the tool output to a format suitable for model consumption.
|
|
2143
2104
|
*
|
|
2144
|
-
* @param _ - The output from the tool execution. Unused.
|
|
2105
|
+
* @param _ - The tool result, including the output from the tool execution. Unused.
|
|
2145
2106
|
* @returns The formatted tool result.
|
|
2146
2107
|
*/
|
|
2147
2108
|
toModelOutput(_) {
|
|
@@ -2160,13 +2121,23 @@ var SubmitTool = class extends ToolBase {
|
|
|
2160
2121
|
}
|
|
2161
2122
|
};
|
|
2162
2123
|
|
|
2124
|
+
// src/agent-creators.ts
|
|
2125
|
+
import {
|
|
2126
|
+
ToolLoopAgent,
|
|
2127
|
+
stepCountIs,
|
|
2128
|
+
hasToolCall
|
|
2129
|
+
} from "ai";
|
|
2130
|
+
|
|
2163
2131
|
// src/instructions.ts
|
|
2164
2132
|
function getAdditionalInstructions(config) {
|
|
2165
2133
|
const { maxSteps, allowSubmit, tools } = config;
|
|
2166
|
-
const exampleSections = [
|
|
2134
|
+
const exampleSections = [
|
|
2135
|
+
"# Tool Examples",
|
|
2136
|
+
"You have access to several tools to assist you in completing your task. Here are some examples of how to use them:"
|
|
2137
|
+
];
|
|
2167
2138
|
for (const [toolName, tool] of Object.entries(tools)) {
|
|
2168
2139
|
if ("examples" in tool && Array.isArray(tool.examples) && tool.examples.length > 0) {
|
|
2169
|
-
let toolSection =
|
|
2140
|
+
let toolSection = `## Tool: \`${toolName}\`
|
|
2170
2141
|
|
|
2171
2142
|
`;
|
|
2172
2143
|
for (const example of tool.examples) {
|
|
@@ -2175,40 +2146,48 @@ function getAdditionalInstructions(config) {
|
|
|
2175
2146
|
exampleSections.push(toolSection.trim());
|
|
2176
2147
|
}
|
|
2177
2148
|
}
|
|
2178
|
-
const
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
"You have access to several tools to assist you in completing your task."
|
|
2185
|
-
] : [],
|
|
2186
|
-
"You must issue tool calls to complete your task. Do not engage with the user directly.",
|
|
2187
|
-
...allowSubmit ? [
|
|
2188
|
-
`Once you think you have completed your task, call the \`${SubmitToolName}\` tool to submit your results.`
|
|
2189
|
-
] : [],
|
|
2190
|
-
`You have a maximum of ${maxSteps} steps to complete your task.`
|
|
2191
|
-
];
|
|
2192
|
-
const importantWorkflowGuidelines = `## Important Workflow Guidelines
|
|
2193
|
-
|
|
2194
|
-
${workflowGuidelines.map((line) => `- ${line}`).join("\n")}
|
|
2195
|
-
|
|
2196
|
-
Remember, you don't get to ask the user any clarifying questions, just use the tools available to complete your task. You're on your own now.
|
|
2149
|
+
const constraintSections = ["# Behavioral Guidelines"];
|
|
2150
|
+
const constraintsByType = getCodeAgentConstraints({ maxSteps, allowSubmit });
|
|
2151
|
+
if (constraintsByType.must && constraintsByType.must.length > 0) {
|
|
2152
|
+
let constraintSection = "## You MUST:\n\n";
|
|
2153
|
+
for (const constraint of constraintsByType.must) {
|
|
2154
|
+
constraintSection += `- ${constraint}
|
|
2197
2155
|
`;
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2156
|
+
}
|
|
2157
|
+
constraintSections.push(constraintSection.trim());
|
|
2158
|
+
}
|
|
2159
|
+
if (constraintsByType.must_not && constraintsByType.must_not.length > 0) {
|
|
2160
|
+
let constraintSection = "## You MUST NOT:\n\n";
|
|
2161
|
+
for (const constraint of constraintsByType.must_not) {
|
|
2162
|
+
constraintSection += `- ${constraint}
|
|
2163
|
+
`;
|
|
2164
|
+
}
|
|
2165
|
+
constraintSections.push(constraintSection.trim());
|
|
2166
|
+
}
|
|
2167
|
+
if (constraintsByType.should && constraintsByType.should.length > 0) {
|
|
2168
|
+
let constraintSection = "## You SHOULD:\n\n";
|
|
2169
|
+
for (const constraint of constraintsByType.should) {
|
|
2170
|
+
constraintSection += `- ${constraint}
|
|
2171
|
+
`;
|
|
2172
|
+
}
|
|
2173
|
+
constraintSections.push(constraintSection.trim());
|
|
2174
|
+
}
|
|
2175
|
+
if (constraintsByType.should_not && constraintsByType.should_not.length > 0) {
|
|
2176
|
+
let constraintSection = "## You SHOULD NOT:\n\n";
|
|
2177
|
+
for (const constraint of constraintsByType.should_not) {
|
|
2178
|
+
constraintSection += `- ${constraint}
|
|
2179
|
+
`;
|
|
2180
|
+
}
|
|
2181
|
+
constraintSections.push(constraintSection.trim());
|
|
2206
2182
|
}
|
|
2207
|
-
|
|
2183
|
+
const finalReminder = getCodeAgentFinalReminder();
|
|
2184
|
+
return [...exampleSections, ...constraintSections, finalReminder].join(
|
|
2185
|
+
"\n\n"
|
|
2186
|
+
);
|
|
2208
2187
|
}
|
|
2209
2188
|
function formatExampleForInstructions(toolName, example) {
|
|
2210
|
-
const input =
|
|
2211
|
-
const output =
|
|
2189
|
+
const input = formatValueForExample(example.input);
|
|
2190
|
+
const output = formatValueForExample(example.output);
|
|
2212
2191
|
if (output === "") {
|
|
2213
2192
|
return `<example>
|
|
2214
2193
|
<tool_call>
|
|
@@ -2225,8 +2204,42 @@ ${output}
|
|
|
2225
2204
|
</tool_response>
|
|
2226
2205
|
</example>`;
|
|
2227
2206
|
}
|
|
2207
|
+
function formatValueForExample(value) {
|
|
2208
|
+
if (typeof value === "undefined") {
|
|
2209
|
+
return "";
|
|
2210
|
+
}
|
|
2211
|
+
if (typeof value === "string") {
|
|
2212
|
+
return `"${value}"`;
|
|
2213
|
+
}
|
|
2214
|
+
if (typeof value === "number") {
|
|
2215
|
+
return value.toString();
|
|
2216
|
+
}
|
|
2217
|
+
if (typeof value === "boolean") {
|
|
2218
|
+
return value ? "true" : "false";
|
|
2219
|
+
}
|
|
2220
|
+
return JSON.stringify(value, null, 2);
|
|
2221
|
+
}
|
|
2222
|
+
function getCodeAgentConstraints(config) {
|
|
2223
|
+
const { maxSteps, allowSubmit } = config;
|
|
2224
|
+
return {
|
|
2225
|
+
must: [
|
|
2226
|
+
"Always issue tool calls to complete your task",
|
|
2227
|
+
...allowSubmit ? [
|
|
2228
|
+
`Call the \`${SubmitToolName}\` tool once you think you have completed your task, to submit your results`
|
|
2229
|
+
] : [],
|
|
2230
|
+
`Complete your task within ${maxSteps} steps`
|
|
2231
|
+
],
|
|
2232
|
+
must_not: ["Engage with the user directly"]
|
|
2233
|
+
};
|
|
2234
|
+
}
|
|
2235
|
+
function getCodeAgentFinalReminder() {
|
|
2236
|
+
return "Remember, you don't get to ask the user any clarifying questions, just use the tools available to complete your task. You're on your own now.";
|
|
2237
|
+
}
|
|
2228
2238
|
|
|
2229
2239
|
// src/tool-creators.ts
|
|
2240
|
+
import {
|
|
2241
|
+
isCommandLine
|
|
2242
|
+
} from "@ai-code-agents/environment-utils";
|
|
2230
2243
|
var availableEnvironmentTools = {
|
|
2231
2244
|
[ReadFileToolName]: ReadFileTool,
|
|
2232
2245
|
[WriteFileToolName]: WriteFileTool,
|
|
@@ -2237,12 +2250,14 @@ var availableEnvironmentTools = {
|
|
|
2237
2250
|
[ReadManyFilesToolName]: ReadManyFilesTool,
|
|
2238
2251
|
[GetProjectFileStructureToolName]: GetProjectFileStructureTool,
|
|
2239
2252
|
[GlobToolName]: GlobTool,
|
|
2253
|
+
[GrepToolName]: GrepTool,
|
|
2240
2254
|
[ListDirectoryToolName]: ListDirectoryTool,
|
|
2241
2255
|
[RunCommandToolName]: RunCommandTool
|
|
2242
2256
|
};
|
|
2243
2257
|
var cliOnlyTools = [
|
|
2244
2258
|
GetProjectFileStructureToolName,
|
|
2245
2259
|
GlobToolName,
|
|
2260
|
+
GrepToolName,
|
|
2246
2261
|
ListDirectoryToolName,
|
|
2247
2262
|
RunCommandToolName
|
|
2248
2263
|
];
|
|
@@ -2251,6 +2266,7 @@ var readonlyTools = [
|
|
|
2251
2266
|
ReadManyFilesToolName,
|
|
2252
2267
|
GetProjectFileStructureToolName,
|
|
2253
2268
|
GlobToolName,
|
|
2269
|
+
GrepToolName,
|
|
2254
2270
|
ListDirectoryToolName
|
|
2255
2271
|
];
|
|
2256
2272
|
var dangerousTools = [
|
|
@@ -2278,7 +2294,7 @@ function createEnvironmentTool(toolName, environment, config) {
|
|
|
2278
2294
|
}
|
|
2279
2295
|
function createToolsForEnvironment(environment, toolsDefinition = "all") {
|
|
2280
2296
|
const sanitizedToolsDefinition = sanitizeToolsDefinition(toolsDefinition);
|
|
2281
|
-
const isCliEnvironment =
|
|
2297
|
+
const isCliEnvironment = isCommandLine(environment);
|
|
2282
2298
|
const tools = {};
|
|
2283
2299
|
for (const toolDefinition of sanitizedToolsDefinition) {
|
|
2284
2300
|
const actualToolName = toolDefinition.toolName;
|
|
@@ -2299,7 +2315,7 @@ function createToolsForEnvironment(environment, toolsDefinition = "all") {
|
|
|
2299
2315
|
}
|
|
2300
2316
|
tools[toolNameToUse] = createEnvironmentTool(
|
|
2301
2317
|
actualToolName,
|
|
2302
|
-
|
|
2318
|
+
environment,
|
|
2303
2319
|
toolConfig
|
|
2304
2320
|
);
|
|
2305
2321
|
}
|
|
@@ -2355,6 +2371,54 @@ function sanitizeToolsDefinition(toolsDefinition) {
|
|
|
2355
2371
|
});
|
|
2356
2372
|
}
|
|
2357
2373
|
|
|
2374
|
+
// src/util/truncate.ts
|
|
2375
|
+
function truncateString(str) {
|
|
2376
|
+
const lines = str.split("\n");
|
|
2377
|
+
while (lines.length > 0 && lines[lines.length - 1] === "") {
|
|
2378
|
+
lines.pop();
|
|
2379
|
+
}
|
|
2380
|
+
const isMultiline = lines.length > 1;
|
|
2381
|
+
if (isMultiline) {
|
|
2382
|
+
if (lines.length > 5) {
|
|
2383
|
+
const truncatedLines = lines.slice(0, 5).join("\n");
|
|
2384
|
+
const moreLines = lines.length - 5;
|
|
2385
|
+
const lineSuffix = moreLines === 1 ? "line" : "lines";
|
|
2386
|
+
return `${truncatedLines}
|
|
2387
|
+
...(${moreLines} more ${lineSuffix})`;
|
|
2388
|
+
}
|
|
2389
|
+
return lines.join("\n");
|
|
2390
|
+
}
|
|
2391
|
+
const singleLine = lines[0] || "";
|
|
2392
|
+
if (singleLine.length > 300) {
|
|
2393
|
+
const moreChars = singleLine.length - 300;
|
|
2394
|
+
return `${singleLine.slice(0, 300)}...(${moreChars} more characters)`;
|
|
2395
|
+
}
|
|
2396
|
+
return singleLine;
|
|
2397
|
+
}
|
|
2398
|
+
function truncateObject(obj) {
|
|
2399
|
+
const result = {};
|
|
2400
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
2401
|
+
if (typeof value === "string") {
|
|
2402
|
+
result[key] = truncateString(value);
|
|
2403
|
+
} else if (Array.isArray(value)) {
|
|
2404
|
+
result[key] = value.map((item) => {
|
|
2405
|
+
if (typeof item === "string") {
|
|
2406
|
+
return truncateString(item);
|
|
2407
|
+
}
|
|
2408
|
+
if (typeof item === "object" && item !== null) {
|
|
2409
|
+
return truncateObject(item);
|
|
2410
|
+
}
|
|
2411
|
+
return item;
|
|
2412
|
+
});
|
|
2413
|
+
} else if (typeof value === "object" && value !== null) {
|
|
2414
|
+
result[key] = truncateObject(value);
|
|
2415
|
+
} else {
|
|
2416
|
+
result[key] = value;
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2419
|
+
return result;
|
|
2420
|
+
}
|
|
2421
|
+
|
|
2358
2422
|
// src/util/get-step-log.ts
|
|
2359
2423
|
function getStepLog(stepResult) {
|
|
2360
2424
|
const { content } = stepResult;
|
|
@@ -2368,13 +2432,17 @@ function getStepLog(stepResult) {
|
|
|
2368
2432
|
}
|
|
2369
2433
|
logEntry += ": ";
|
|
2370
2434
|
if (part.type === "tool-call" && "input" in part) {
|
|
2371
|
-
logEntry += typeof part.input === "string" ? part.input :
|
|
2435
|
+
logEntry += typeof part.input === "string" ? truncateString(part.input) : part.input === null || part.input === void 0 ? String(part.input) : JSON.stringify(
|
|
2436
|
+
truncateObject(part.input)
|
|
2437
|
+
);
|
|
2372
2438
|
} else if (part.type === "tool-result" && "output" in part) {
|
|
2373
|
-
logEntry += typeof part.output === "string" ? part.output :
|
|
2439
|
+
logEntry += typeof part.output === "string" ? truncateString(part.output) : part.output === null || part.output === void 0 ? String(part.output) : JSON.stringify(
|
|
2440
|
+
truncateObject(part.output)
|
|
2441
|
+
);
|
|
2374
2442
|
} else if (part.type === "tool-error" && "error" in part) {
|
|
2375
2443
|
logEntry += typeof part.error === "object" && part.error !== null && "message" in part.error ? part.error.message : String(part.error);
|
|
2376
2444
|
} else if (part.type === "text" && "text" in part) {
|
|
2377
|
-
logEntry += part.text;
|
|
2445
|
+
logEntry += truncateString(part.text);
|
|
2378
2446
|
}
|
|
2379
2447
|
logEntry += "\n";
|
|
2380
2448
|
});
|
|
@@ -2383,6 +2451,9 @@ function getStepLog(stepResult) {
|
|
|
2383
2451
|
|
|
2384
2452
|
// src/agent-creators.ts
|
|
2385
2453
|
function createCodeAgent(agentConfig) {
|
|
2454
|
+
return new ToolLoopAgent(createCodeAgentSettings(agentConfig));
|
|
2455
|
+
}
|
|
2456
|
+
function createCodeAgentSettings(agentConfig) {
|
|
2386
2457
|
const {
|
|
2387
2458
|
maxSteps,
|
|
2388
2459
|
allowSubmit,
|
|
@@ -2391,46 +2462,29 @@ function createCodeAgent(agentConfig) {
|
|
|
2391
2462
|
tools: originalTools,
|
|
2392
2463
|
stopWhen: originalStopWhen,
|
|
2393
2464
|
prepareStep: originalPrepareStep,
|
|
2394
|
-
|
|
2465
|
+
instructions: originalSystemInstruction,
|
|
2395
2466
|
...remainingConfig
|
|
2396
2467
|
} = agentConfig;
|
|
2397
2468
|
let agentSettings;
|
|
2398
|
-
let
|
|
2469
|
+
let tools;
|
|
2399
2470
|
if ("environments" in remainingConfig) {
|
|
2400
2471
|
const { environments, environmentToolsDefinition, ...agentSettingsInput } = remainingConfig;
|
|
2401
2472
|
agentSettings = { ...agentSettingsInput };
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
`No tools definition provided for environment "${environmentName}". Please provide a tools definition for each environment.`
|
|
2407
|
-
);
|
|
2408
|
-
}
|
|
2409
|
-
const environmentTools2 = createToolsForNamedEnvironment(
|
|
2410
|
-
environmentName,
|
|
2411
|
-
environment,
|
|
2412
|
-
environmentToolsDefinition[environmentName]
|
|
2413
|
-
);
|
|
2414
|
-
for (const [toolName, tool] of Object.entries(environmentTools2)) {
|
|
2415
|
-
if (toolName in environmentTools2) {
|
|
2416
|
-
throw new Error(
|
|
2417
|
-
`Tool name conflict: The tool name "${toolName}" from environment "${environmentName}" is already used by another environment's tools.`
|
|
2418
|
-
);
|
|
2419
|
-
}
|
|
2420
|
-
environmentTools2[toolName] = tool;
|
|
2421
|
-
}
|
|
2422
|
-
}
|
|
2473
|
+
tools = createCodeAgentTools(
|
|
2474
|
+
{ environments, environmentToolsDefinition },
|
|
2475
|
+
originalTools
|
|
2476
|
+
);
|
|
2423
2477
|
} else if ("environment" in remainingConfig) {
|
|
2424
2478
|
const { environment, environmentToolsDefinition, ...agentSettingsInput } = remainingConfig;
|
|
2425
2479
|
agentSettings = { ...agentSettingsInput };
|
|
2426
|
-
|
|
2427
|
-
environment,
|
|
2428
|
-
|
|
2480
|
+
tools = createCodeAgentTools(
|
|
2481
|
+
{ environment, environmentToolsDefinition },
|
|
2482
|
+
originalTools
|
|
2429
2483
|
);
|
|
2430
2484
|
} else {
|
|
2431
2485
|
agentSettings = { ...remainingConfig };
|
|
2486
|
+
tools = originalTools || {};
|
|
2432
2487
|
}
|
|
2433
|
-
const tools = environmentTools && originalTools ? mergeTools(environmentTools, originalTools) : originalTools || environmentTools || {};
|
|
2434
2488
|
if (allowSubmit) {
|
|
2435
2489
|
if (SubmitToolName in tools) {
|
|
2436
2490
|
throw new Error(
|
|
@@ -2458,16 +2512,54 @@ ${stepLog}`, stepCount - 1);
|
|
|
2458
2512
|
} : originalPrepareStep;
|
|
2459
2513
|
const stopWhenCondition = allowSubmit ? [stepCountIs(maxSteps), hasToolCall(SubmitToolName)] : stepCountIs(maxSteps);
|
|
2460
2514
|
const stopWhen = originalStopWhen ? mergeStopWhen(originalStopWhen, stopWhenCondition) : stopWhenCondition;
|
|
2461
|
-
const
|
|
2515
|
+
const instructions = !omitAdditionalInstructions ? mergeSystemInstructions(
|
|
2462
2516
|
originalSystemInstruction,
|
|
2463
2517
|
getAdditionalInstructions({ maxSteps, allowSubmit, tools })
|
|
2464
2518
|
) : originalSystemInstruction;
|
|
2465
|
-
return
|
|
2519
|
+
return {
|
|
2466
2520
|
...agentSettings,
|
|
2467
|
-
|
|
2521
|
+
instructions,
|
|
2468
2522
|
prepareStep,
|
|
2469
2523
|
stopWhen
|
|
2470
|
-
}
|
|
2524
|
+
};
|
|
2525
|
+
}
|
|
2526
|
+
function createCodeAgentTools(agentToolsConfig, originalTools) {
|
|
2527
|
+
if ("environments" in agentToolsConfig) {
|
|
2528
|
+
const { environments, environmentToolsDefinition } = agentToolsConfig;
|
|
2529
|
+
const environmentTools = {};
|
|
2530
|
+
for (const [environmentName, environment] of Object.entries(environments)) {
|
|
2531
|
+
if (!(environmentName in environmentToolsDefinition)) {
|
|
2532
|
+
throw new Error(
|
|
2533
|
+
`No tools definition provided for environment "${environmentName}". Please provide a tools definition for each environment.`
|
|
2534
|
+
);
|
|
2535
|
+
}
|
|
2536
|
+
const envTools = createToolsForNamedEnvironment(
|
|
2537
|
+
environmentName,
|
|
2538
|
+
environment,
|
|
2539
|
+
environmentToolsDefinition[environmentName]
|
|
2540
|
+
);
|
|
2541
|
+
for (const [toolName, tool] of Object.entries(envTools)) {
|
|
2542
|
+
if (toolName in environmentTools) {
|
|
2543
|
+
throw new Error(
|
|
2544
|
+
`Tool name conflict: The tool name "${toolName}" from environment "${environmentName}" is already used by another environment's tools.`
|
|
2545
|
+
);
|
|
2546
|
+
}
|
|
2547
|
+
environmentTools[toolName] = tool;
|
|
2548
|
+
}
|
|
2549
|
+
}
|
|
2550
|
+
return originalTools ? mergeTools(environmentTools, originalTools) : environmentTools;
|
|
2551
|
+
}
|
|
2552
|
+
if ("environment" in agentToolsConfig) {
|
|
2553
|
+
const { environment, environmentToolsDefinition } = agentToolsConfig;
|
|
2554
|
+
const environmentTools = createToolsForEnvironment(
|
|
2555
|
+
environment,
|
|
2556
|
+
environmentToolsDefinition
|
|
2557
|
+
);
|
|
2558
|
+
return originalTools ? mergeTools(environmentTools, originalTools) : environmentTools;
|
|
2559
|
+
}
|
|
2560
|
+
throw new Error(
|
|
2561
|
+
'No environments provided in agent tools configuration. Please provide either "environment" or "environments".'
|
|
2562
|
+
);
|
|
2471
2563
|
}
|
|
2472
2564
|
function mergeTools(baseTools, additionalTools) {
|
|
2473
2565
|
const tools = { ...baseTools };
|
|
@@ -2493,9 +2585,26 @@ function mergeStopWhen(baseStopWhen, additionalStopWhen) {
|
|
|
2493
2585
|
}
|
|
2494
2586
|
return [baseStopWhen, additionalStopWhen];
|
|
2495
2587
|
}
|
|
2496
|
-
function mergeSystemInstructions(
|
|
2497
|
-
if (
|
|
2498
|
-
|
|
2588
|
+
function mergeSystemInstructions(baseInstructions, additionalInstructions) {
|
|
2589
|
+
if (baseInstructions) {
|
|
2590
|
+
if (Array.isArray(baseInstructions)) {
|
|
2591
|
+
return [
|
|
2592
|
+
...baseInstructions,
|
|
2593
|
+
{
|
|
2594
|
+
role: "system",
|
|
2595
|
+
content: additionalInstructions
|
|
2596
|
+
}
|
|
2597
|
+
];
|
|
2598
|
+
}
|
|
2599
|
+
if (typeof baseInstructions === "object") {
|
|
2600
|
+
return {
|
|
2601
|
+
...baseInstructions,
|
|
2602
|
+
content: `${baseInstructions.content.trimEnd()}
|
|
2603
|
+
|
|
2604
|
+
${additionalInstructions}`
|
|
2605
|
+
};
|
|
2606
|
+
}
|
|
2607
|
+
return `${baseInstructions.trimEnd()}
|
|
2499
2608
|
|
|
2500
2609
|
${additionalInstructions}`;
|
|
2501
2610
|
}
|
|
@@ -2520,12 +2629,10 @@ function createEnvironment(environmentName, config) {
|
|
|
2520
2629
|
return new EnvironmentClass(config);
|
|
2521
2630
|
}
|
|
2522
2631
|
export {
|
|
2523
|
-
CopyFileResult,
|
|
2524
2632
|
CopyFileTool,
|
|
2525
2633
|
CopyFileToolInput,
|
|
2526
2634
|
CopyFileToolName,
|
|
2527
2635
|
CopyFileToolOutput,
|
|
2528
|
-
DeleteFileResult,
|
|
2529
2636
|
DeleteFileTool,
|
|
2530
2637
|
DeleteFileToolInput,
|
|
2531
2638
|
DeleteFileToolName,
|
|
@@ -2547,20 +2654,22 @@ export {
|
|
|
2547
2654
|
GlobToolInput,
|
|
2548
2655
|
GlobToolName,
|
|
2549
2656
|
GlobToolOutput,
|
|
2657
|
+
GrepTool,
|
|
2658
|
+
GrepToolInput,
|
|
2659
|
+
GrepToolName,
|
|
2660
|
+
GrepToolOutput,
|
|
2550
2661
|
ListDirectoryTool,
|
|
2551
2662
|
ListDirectoryToolInput,
|
|
2552
2663
|
ListDirectoryToolName,
|
|
2553
2664
|
ListDirectoryToolOutput,
|
|
2554
2665
|
MockFilesystemEnvironment,
|
|
2555
2666
|
MockFilesystemEnvironmentName,
|
|
2556
|
-
MoveFileResult,
|
|
2557
2667
|
MoveFileTool,
|
|
2558
2668
|
MoveFileToolInput,
|
|
2559
2669
|
MoveFileToolName,
|
|
2560
2670
|
MoveFileToolOutput,
|
|
2561
2671
|
NodeFilesystemEnvironment,
|
|
2562
2672
|
NodeFilesystemEnvironmentName,
|
|
2563
|
-
ReadFileResult,
|
|
2564
2673
|
ReadFileTool,
|
|
2565
2674
|
ReadFileToolInput,
|
|
2566
2675
|
ReadFileToolName,
|
|
@@ -2569,19 +2678,23 @@ export {
|
|
|
2569
2678
|
ReadManyFilesToolInput,
|
|
2570
2679
|
ReadManyFilesToolName,
|
|
2571
2680
|
ReadManyFilesToolOutput,
|
|
2572
|
-
RunCommandResult,
|
|
2573
2681
|
RunCommandTool,
|
|
2574
2682
|
RunCommandToolInput,
|
|
2575
2683
|
RunCommandToolName,
|
|
2576
2684
|
RunCommandToolOutput,
|
|
2685
|
+
SubmitTool,
|
|
2686
|
+
SubmitToolInput,
|
|
2687
|
+
SubmitToolName,
|
|
2688
|
+
SubmitToolOutput,
|
|
2577
2689
|
UnsafeLocalEnvironment,
|
|
2578
2690
|
UnsafeLocalEnvironmentName,
|
|
2579
|
-
WriteFileResult,
|
|
2580
2691
|
WriteFileTool,
|
|
2581
2692
|
WriteFileToolInput,
|
|
2582
2693
|
WriteFileToolName,
|
|
2583
2694
|
WriteFileToolOutput,
|
|
2584
2695
|
createCodeAgent,
|
|
2696
|
+
createCodeAgentSettings,
|
|
2697
|
+
createCodeAgentTools,
|
|
2585
2698
|
createEnvironment,
|
|
2586
2699
|
createEnvironmentTool,
|
|
2587
2700
|
createToolsForEnvironment,
|