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/dist/index.cjs CHANGED
@@ -30,12 +30,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
- CopyFileResult: () => CopyFileResult,
34
33
  CopyFileTool: () => CopyFileTool,
35
34
  CopyFileToolInput: () => CopyFileToolInput,
36
35
  CopyFileToolName: () => CopyFileToolName,
37
36
  CopyFileToolOutput: () => CopyFileToolOutput,
38
- DeleteFileResult: () => DeleteFileResult,
39
37
  DeleteFileTool: () => DeleteFileTool,
40
38
  DeleteFileToolInput: () => DeleteFileToolInput,
41
39
  DeleteFileToolName: () => DeleteFileToolName,
@@ -57,20 +55,22 @@ __export(index_exports, {
57
55
  GlobToolInput: () => GlobToolInput,
58
56
  GlobToolName: () => GlobToolName,
59
57
  GlobToolOutput: () => GlobToolOutput,
58
+ GrepTool: () => GrepTool,
59
+ GrepToolInput: () => GrepToolInput,
60
+ GrepToolName: () => GrepToolName,
61
+ GrepToolOutput: () => GrepToolOutput,
60
62
  ListDirectoryTool: () => ListDirectoryTool,
61
63
  ListDirectoryToolInput: () => ListDirectoryToolInput,
62
64
  ListDirectoryToolName: () => ListDirectoryToolName,
63
65
  ListDirectoryToolOutput: () => ListDirectoryToolOutput,
64
66
  MockFilesystemEnvironment: () => MockFilesystemEnvironment,
65
67
  MockFilesystemEnvironmentName: () => MockFilesystemEnvironmentName,
66
- MoveFileResult: () => MoveFileResult,
67
68
  MoveFileTool: () => MoveFileTool,
68
69
  MoveFileToolInput: () => MoveFileToolInput,
69
70
  MoveFileToolName: () => MoveFileToolName,
70
71
  MoveFileToolOutput: () => MoveFileToolOutput,
71
72
  NodeFilesystemEnvironment: () => NodeFilesystemEnvironment,
72
73
  NodeFilesystemEnvironmentName: () => NodeFilesystemEnvironmentName,
73
- ReadFileResult: () => ReadFileResult,
74
74
  ReadFileTool: () => ReadFileTool,
75
75
  ReadFileToolInput: () => ReadFileToolInput,
76
76
  ReadFileToolName: () => ReadFileToolName,
@@ -79,19 +79,23 @@ __export(index_exports, {
79
79
  ReadManyFilesToolInput: () => ReadManyFilesToolInput,
80
80
  ReadManyFilesToolName: () => ReadManyFilesToolName,
81
81
  ReadManyFilesToolOutput: () => ReadManyFilesToolOutput,
82
- RunCommandResult: () => RunCommandResult,
83
82
  RunCommandTool: () => RunCommandTool,
84
83
  RunCommandToolInput: () => RunCommandToolInput,
85
84
  RunCommandToolName: () => RunCommandToolName,
86
85
  RunCommandToolOutput: () => RunCommandToolOutput,
86
+ SubmitTool: () => SubmitTool,
87
+ SubmitToolInput: () => SubmitToolInput,
88
+ SubmitToolName: () => SubmitToolName,
89
+ SubmitToolOutput: () => SubmitToolOutput,
87
90
  UnsafeLocalEnvironment: () => UnsafeLocalEnvironment,
88
91
  UnsafeLocalEnvironmentName: () => UnsafeLocalEnvironmentName,
89
- WriteFileResult: () => WriteFileResult,
90
92
  WriteFileTool: () => WriteFileTool,
91
93
  WriteFileToolInput: () => WriteFileToolInput,
92
94
  WriteFileToolName: () => WriteFileToolName,
93
95
  WriteFileToolOutput: () => WriteFileToolOutput,
94
96
  createCodeAgent: () => createCodeAgent,
97
+ createCodeAgentSettings: () => createCodeAgentSettings,
98
+ createCodeAgentTools: () => createCodeAgentTools,
95
99
  createEnvironment: () => createEnvironment,
96
100
  createEnvironmentTool: () => createEnvironmentTool,
97
101
  createToolsForEnvironment: () => createToolsForEnvironment,
@@ -101,290 +105,17 @@ module.exports = __toCommonJS(index_exports);
101
105
 
102
106
  // src/environments/docker-environment.ts
103
107
  var import_node_child_process = require("child_process");
108
+ var import_environment_utils = require("@ai-code-agents/environment-utils");
104
109
 
105
- // src/util/escape-command-arg.ts
106
- function escapeCommandArg(arg) {
107
- if ("" === arg) {
108
- return "''";
109
- }
110
- return `'${arg.replace(/'/g, "'\\''")}'`;
111
- }
112
-
113
- // src/util/validate-relative-path.ts
114
- var path = __toESM(require("path"), 1);
115
- function validateRelativePath(filePath) {
116
- if (path.isAbsolute(filePath)) {
117
- throw new Error("Absolute paths are not allowed.");
118
- }
119
- if (filePath.startsWith("~")) {
120
- throw new Error('Paths starting with "~" are not allowed.');
121
- }
122
- if (filePath.includes("\0")) {
123
- throw new Error("Paths must not contain null bytes.");
124
- }
125
- const normalizedPath = path.normalize(filePath);
126
- if (normalizedPath.startsWith("..")) {
127
- throw new Error("Path traversal is not allowed.");
128
- }
110
+ // src/util/escape-command.ts
111
+ function escapeCommand(command) {
112
+ const escaped = command.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
113
+ return `"${escaped}"`;
129
114
  }
130
115
 
131
- // src/environments/filesystem-environment-base.ts
132
- var FilesystemEnvironmentBase = class {
133
- _envConfig;
134
- /**
135
- * Constructs a new environment instance.
136
- *
137
- * @param config - Environment configuration.
138
- */
139
- constructor(config) {
140
- this._envConfig = config;
141
- }
142
- /**
143
- * Reads the content of a file at the specified path.
144
- *
145
- * @param path - The path to the file to read, relative to the project directory.
146
- * @returns A promise that resolves to a ReadFileResult.
147
- */
148
- async readFile(path5) {
149
- validateRelativePath(path5);
150
- if (!await this.fileExists(path5)) {
151
- throw new Error(`File not found: ${path5}`);
152
- }
153
- const content = await this.readFileContent(path5);
154
- return {
155
- path: path5,
156
- content
157
- };
158
- }
159
- /**
160
- * Writes content to a file at the specified path.
161
- *
162
- * If a file is already present at the path, it will be overwritten.
163
- *
164
- * @param path - The path to the file to write, relative to the project directory.
165
- * @param content - The content to write to the file.
166
- * @returns A promise that resolves to a WriteFileResult.
167
- */
168
- async writeFile(path5, content) {
169
- validateRelativePath(path5);
170
- await this.writeFileContent(path5, content);
171
- return {
172
- path: path5,
173
- message: "File written successfully."
174
- };
175
- }
176
- /**
177
- * Deletes a file at the specified path.
178
- *
179
- * @param path - The path to the file to delete, relative to the project directory.
180
- * @returns A promise that resolves to a DeleteFileResult.
181
- */
182
- async deleteFile(path5) {
183
- validateRelativePath(path5);
184
- if (!await this.fileExists(path5)) {
185
- return {
186
- path: path5,
187
- message: "File was already deleted."
188
- };
189
- }
190
- await this.deleteFileContent(path5);
191
- return {
192
- path: path5,
193
- message: "File deleted successfully."
194
- };
195
- }
196
- /**
197
- * Moves a file from a source path to a destination path.
198
- *
199
- * If a file is already present at the destination path, it will be overwritten.
200
- *
201
- * @param sourcePath - The path to the file to move.
202
- * @param destinationPath - The path to move the file to.
203
- * @returns A promise that resolves to a MoveFileResult.
204
- */
205
- async moveFile(sourcePath, destinationPath) {
206
- validateRelativePath(sourcePath);
207
- validateRelativePath(destinationPath);
208
- if (!await this.fileExists(sourcePath)) {
209
- throw new Error(`File not found: ${sourcePath}`);
210
- }
211
- await this.moveFileContent(sourcePath, destinationPath);
212
- return {
213
- sourcePath,
214
- destinationPath,
215
- message: "File moved successfully."
216
- };
217
- }
218
- /**
219
- * Copies a file from a source path to a destination path.
220
- *
221
- * If a file is already present at the destination path, it will be overwritten.
222
- *
223
- * @param sourcePath - The path to the file to copy.
224
- * @param destinationPath - The path to copy the file to.
225
- * @returns A promise that resolves to a CopyFileResult.
226
- */
227
- async copyFile(sourcePath, destinationPath) {
228
- validateRelativePath(sourcePath);
229
- validateRelativePath(destinationPath);
230
- if (!await this.fileExists(sourcePath)) {
231
- throw new Error(`File not found: ${sourcePath}`);
232
- }
233
- await this.copyFileContent(sourcePath, destinationPath);
234
- return {
235
- sourcePath,
236
- destinationPath,
237
- message: "File copied successfully."
238
- };
239
- }
240
- /**
241
- * Moves the content of a file from a source path to a destination path, relative to the project directory.
242
- *
243
- * When this method is called, it is guaranteed that the source file exists.
244
- * This method unconditionally moves the content, even if a file already exists at the destination path.
245
- *
246
- * @param relativeSourcePath - The path to the file to move, relative to the project directory.
247
- * @param relativeDestinationPath - The path to move the file to, relative to the project directory.
248
- */
249
- async moveFileContent(relativeSourcePath, relativeDestinationPath) {
250
- const content = await this.readFileContent(relativeSourcePath);
251
- this.writeFileContent(relativeDestinationPath, content);
252
- this.deleteFileContent(relativeSourcePath);
253
- }
254
- /**
255
- * Copies the content of a file from a source path to a destination path, relative to the project directory.
256
- *
257
- * When this method is called, it is guaranteed that the source file exists.
258
- * This method unconditionally copies the content, even if a file already exists at the destination path.
259
- *
260
- * @param relativeSourcePath - The path to the file to copy, relative to the project directory.
261
- * @param relativeDestinationPath - The path to copy the file to, relative to the project directory.
262
- */
263
- async copyFileContent(relativeSourcePath, relativeDestinationPath) {
264
- const content = await this.readFileContent(relativeSourcePath);
265
- this.writeFileContent(relativeDestinationPath, content);
266
- }
267
- };
268
-
269
- // src/environments/command-line-environment-base.ts
270
- var CommandLineEnvironmentBase = class extends FilesystemEnvironmentBase {
271
- /**
272
- * Runs a CLI command in environment.
273
- *
274
- * @param command - The command to run.
275
- * @returns A promise that resolves to a RunCommandResult.
276
- */
277
- async runCommand(command) {
278
- const [exitCode, stdout, stderr] = await this.executeCommand(command);
279
- return {
280
- command,
281
- exitCode,
282
- stdout,
283
- stderr
284
- };
285
- }
286
- };
287
-
288
- // src/environments/unix-environment-base.ts
289
- var UnixEnvironmentBase = class extends CommandLineEnvironmentBase {
290
- /**
291
- * Checks whether a file exists at the specified path relative to the project directory.
292
- *
293
- * @param relativePath - The path to the file to check, relative to the project directory.
294
- * @returns True if the file exists, false otherwise.
295
- */
296
- async fileExists(relativePath) {
297
- const command = `if [ -e ${escapeCommandArg(relativePath)} ]; then echo "yes"; else echo "no"; fi`;
298
- const { exitCode, stdout } = await this.runCommand(command);
299
- return exitCode === 0 && stdout.trim() === "yes";
300
- }
301
- /**
302
- * Gets the content of a file at the specified path, relative to the project directory.
303
- *
304
- * When this method is called, it is guaranteed that the file exists.
305
- *
306
- * @param relativePath - The path to the file to read, relative to the project directory.
307
- * @returns The content of the file.
308
- */
309
- async readFileContent(relativePath) {
310
- const command = `cat ${escapeCommandArg(relativePath)}`;
311
- const { exitCode, stdout } = await this.runCommand(command);
312
- return exitCode === 0 ? stdout : "";
313
- }
314
- /**
315
- * Writes content to a file at the specified path, relative to the project directory.
316
- *
317
- * This method unconditionally writes the content, even if a file already exists at the path, or if the file is new.
318
- *
319
- * @param relativePath - The path to the file to write, relative to the project directory.
320
- * @param content - The content to write to the file.
321
- */
322
- async writeFileContent(relativePath, content) {
323
- const command = `sh -c "echo ${escapeCommandArg(
324
- content
325
- )} > ${escapeCommandArg(relativePath)}"`;
326
- const { exitCode, stderr } = await this.runCommand(command);
327
- if (exitCode !== 0) {
328
- throw new Error(`Failed to write file: ${stderr || "Unknown error"}`);
329
- }
330
- }
331
- /**
332
- * Deletes a file at the specified path, relative to the project directory.
333
- *
334
- * When this method is called, it is guaranteed that the file exists.
335
- *
336
- * @param relativePath - The path to the file to delete, relative to the project directory.
337
- */
338
- async deleteFileContent(relativePath) {
339
- const command = `rm ${escapeCommandArg(relativePath)}`;
340
- const { exitCode, stderr } = await this.runCommand(command);
341
- if (exitCode !== 0) {
342
- throw new Error(`Failed to delete file: ${stderr || "Unknown error"}`);
343
- }
344
- }
345
- /**
346
- * Moves the content of a file from a source path to a destination path, relative to the project directory.
347
- *
348
- * When this method is called, it is guaranteed that the source file exists.
349
- * This method unconditionally moves the content, even if a file already exists at the destination path.
350
- *
351
- * @param relativeSourcePath - The path to the file to move, relative to the project directory.
352
- * @param relativeDestinationPath - The path to move the file to, relative to the project directory.
353
- */
354
- async moveFileContent(relativeSourcePath, relativeDestinationPath) {
355
- const command = `mv ${escapeCommandArg(relativeSourcePath)} ${escapeCommandArg(
356
- relativeDestinationPath
357
- )}`;
358
- const { exitCode, stderr } = await this.runCommand(command);
359
- if (exitCode !== 0) {
360
- throw new Error(`Failed to move file: ${stderr || "Unknown error"}`);
361
- }
362
- }
363
- /**
364
- * Copies the content of a file from a source path to a destination path, relative to the project directory.
365
- *
366
- * When this method is called, it is guaranteed that the source file exists.
367
- * This method unconditionally copies the content, even if a file already exists at the destination path.
368
- *
369
- * @param relativeSourcePath - The path to the file to copy, relative to the project directory.
370
- * @param relativeDestinationPath - The path to copy the file to, relative to the project directory.
371
- */
372
- async copyFileContent(relativeSourcePath, relativeDestinationPath) {
373
- const command = `cp ${escapeCommandArg(relativeSourcePath)} ${escapeCommandArg(
374
- relativeDestinationPath
375
- )}`;
376
- const result = await this.runCommand(command);
377
- if (result.exitCode !== 0) {
378
- throw new Error(
379
- `Failed to copy file: ${result.stderr || "Unknown error"}`
380
- );
381
- }
382
- }
383
- };
384
-
385
116
  // src/environments/docker-environment.ts
386
117
  var DockerEnvironmentName = "docker";
387
- var DockerEnvironment = class extends UnixEnvironmentBase {
118
+ var DockerEnvironment = class extends import_environment_utils.UnixEnvironmentBase {
388
119
  _commandPrefix;
389
120
  /**
390
121
  * Constructs a new environment instance.
@@ -394,7 +125,7 @@ var DockerEnvironment = class extends UnixEnvironmentBase {
394
125
  constructor(config) {
395
126
  super(config);
396
127
  const { directoryPath } = this._envConfig;
397
- this._commandPrefix = directoryPath ? `cd ${escapeCommandArg(directoryPath)} && ` : "";
128
+ this._commandPrefix = directoryPath ? `cd ${(0, import_environment_utils.escapeCommandArg)(directoryPath)} && ` : "";
398
129
  }
399
130
  /**
400
131
  * Gets the environment name.
@@ -413,7 +144,7 @@ var DockerEnvironment = class extends UnixEnvironmentBase {
413
144
  async executeCommand(command) {
414
145
  return new Promise((resolve) => {
415
146
  (0, import_node_child_process.exec)(
416
- `docker exec ${this._envConfig.containerId} ${this._commandPrefix}${command}`,
147
+ `docker exec ${this._envConfig.containerId} sh -c ${escapeCommand(this._commandPrefix + command)}`,
417
148
  (error, stdout, stderr) => {
418
149
  const exitCode = error ? error.code ?? 1 : 0;
419
150
  resolve([exitCode, stdout, stderr]);
@@ -425,8 +156,9 @@ var DockerEnvironment = class extends UnixEnvironmentBase {
425
156
 
426
157
  // src/environments/mock-filesystem-environment.ts
427
158
  var import_node_path = __toESM(require("path"), 1);
159
+ var import_environment_utils2 = require("@ai-code-agents/environment-utils");
428
160
  var MockFilesystemEnvironmentName = "mock-filesystem";
429
- var MockFilesystemEnvironment = class extends FilesystemEnvironmentBase {
161
+ var MockFilesystemEnvironment = class extends import_environment_utils2.FilesystemEnvironmentBase {
430
162
  files;
431
163
  _preparePath;
432
164
  /**
@@ -437,7 +169,7 @@ var MockFilesystemEnvironment = class extends FilesystemEnvironmentBase {
437
169
  constructor(config = {}) {
438
170
  super(config);
439
171
  const { initialFiles, directoryPath } = this._envConfig;
440
- this.files = initialFiles ?? /* @__PURE__ */ new Map();
172
+ this.files = initialFiles ? new Map(Object.entries(initialFiles)) : /* @__PURE__ */ new Map();
441
173
  this._preparePath = directoryPath ? (filePath) => import_node_path.default.join(directoryPath, filePath) : (filePath) => filePath;
442
174
  }
443
175
  /**
@@ -492,8 +224,9 @@ var MockFilesystemEnvironment = class extends FilesystemEnvironmentBase {
492
224
  // src/environments/node-filesystem-environment.ts
493
225
  var import_promises = __toESM(require("fs/promises"), 1);
494
226
  var import_node_path2 = __toESM(require("path"), 1);
227
+ var import_environment_utils3 = require("@ai-code-agents/environment-utils");
495
228
  var NodeFilesystemEnvironmentName = "node-filesystem";
496
- var NodeFilesystemEnvironment = class extends FilesystemEnvironmentBase {
229
+ var NodeFilesystemEnvironment = class extends import_environment_utils3.FilesystemEnvironmentBase {
497
230
  /**
498
231
  * Constructs a new NodeFilesystemEnvironment instance.
499
232
  *
@@ -587,8 +320,9 @@ var NodeFilesystemEnvironment = class extends FilesystemEnvironmentBase {
587
320
 
588
321
  // src/environments/unsafe-local-environment.ts
589
322
  var import_node_child_process2 = require("child_process");
323
+ var import_environment_utils4 = require("@ai-code-agents/environment-utils");
590
324
  var UnsafeLocalEnvironmentName = "unsafe-local";
591
- var UnsafeLocalEnvironment = class extends UnixEnvironmentBase {
325
+ var UnsafeLocalEnvironment = class extends import_environment_utils4.UnixEnvironmentBase {
592
326
  _commandPrefix;
593
327
  /**
594
328
  * Constructs a new environment instance.
@@ -604,7 +338,7 @@ var UnsafeLocalEnvironment = class extends UnixEnvironmentBase {
604
338
  throw new Error('The directory path must be absolute (start with "/")');
605
339
  }
606
340
  super(config);
607
- this._commandPrefix = `cd ${escapeCommandArg(directoryPath)} && `;
341
+ this._commandPrefix = `cd ${(0, import_environment_utils4.escapeCommandArg)(directoryPath)} && `;
608
342
  }
609
343
  /**
610
344
  * Gets the environment name.
@@ -632,173 +366,7 @@ var UnsafeLocalEnvironment = class extends UnixEnvironmentBase {
632
366
 
633
367
  // src/tools/copy-file-tool.ts
634
368
  var import_zod = require("zod");
635
-
636
- // src/types.ts
637
- var z = __toESM(require("zod"), 1);
638
- var ReadFileResult = z.object({
639
- path: z.string().meta({
640
- description: "The path to the file that was read."
641
- }),
642
- content: z.string().meta({
643
- description: "The content of the file that was read."
644
- })
645
- });
646
- var WriteFileResult = z.object({
647
- path: z.string().meta({
648
- description: "The path to the file that was written."
649
- }),
650
- message: z.string().meta({
651
- description: "A message indicating the result of the write operation."
652
- })
653
- });
654
- var DeleteFileResult = z.object({
655
- path: z.string().meta({
656
- description: "The path to the file that was deleted."
657
- }),
658
- message: z.string().meta({
659
- description: "A message indicating the result of the delete operation."
660
- })
661
- });
662
- var MoveFileResult = z.object({
663
- sourcePath: z.string().meta({
664
- description: "The original path of the file that was moved."
665
- }),
666
- destinationPath: z.string().meta({
667
- description: "The new path of the file that was moved to."
668
- }),
669
- message: z.string().meta({
670
- description: "A message indicating the result of the move operation."
671
- })
672
- });
673
- var CopyFileResult = z.object({
674
- sourcePath: z.string().meta({
675
- description: "The original path of the file that was copied."
676
- }),
677
- destinationPath: z.string().meta({
678
- description: "The new path of the file that was copied to."
679
- }),
680
- message: z.string().meta({
681
- description: "A message indicating the result of the copy operation."
682
- })
683
- });
684
- var RunCommandResult = z.object({
685
- command: z.string().meta({
686
- description: "The command that was executed."
687
- }),
688
- exitCode: z.number().meta({
689
- description: "The exit code of the command."
690
- }),
691
- stdout: z.string().meta({
692
- description: "The standard output of the command."
693
- }),
694
- stderr: z.string().meta({
695
- description: "The standard error output of the command."
696
- })
697
- });
698
-
699
- // src/tools/tool-base.ts
700
- var ToolBase = class {
701
- _toolConfig;
702
- _name;
703
- _description;
704
- _inputSchema;
705
- _outputSchema;
706
- _needsApproval;
707
- /**
708
- * Constructs a new tool instance.
709
- *
710
- * @param toolConfig - Optional tool config, can be used to override some defaults.
711
- */
712
- constructor(toolConfig) {
713
- const {
714
- name: defaultName,
715
- description: defaultDescription,
716
- inputSchema,
717
- outputSchema,
718
- needsApproval: defaultNeedsApproval
719
- } = this.getMetadata();
720
- this._name = toolConfig?.name || defaultName;
721
- this._description = toolConfig?.description || defaultDescription;
722
- this._inputSchema = inputSchema;
723
- this._outputSchema = outputSchema;
724
- this._needsApproval = toolConfig?.needsApproval !== void 0 ? toolConfig.needsApproval : defaultNeedsApproval;
725
- }
726
- /**
727
- * Gets the tool name.
728
- *
729
- * @returns The tool name.
730
- */
731
- get name() {
732
- return this._name;
733
- }
734
- /**
735
- * Gets the tool description.
736
- *
737
- * @returns The tool description.
738
- */
739
- get description() {
740
- return this._description;
741
- }
742
- /**
743
- * Gets the input schema for the tool.
744
- *
745
- * @returns The input schema.
746
- */
747
- get inputSchema() {
748
- return this._inputSchema;
749
- }
750
- /**
751
- * Gets the input schema for the tool.
752
- *
753
- * @returns The input schema.
754
- */
755
- get outputSchema() {
756
- return this._outputSchema;
757
- }
758
- /**
759
- * Gets whether the tool needs approval before use.
760
- *
761
- * @returns True if the tool needs approval, false otherwise.
762
- */
763
- get needsApproval() {
764
- return this._needsApproval;
765
- }
766
- };
767
-
768
- // src/tools/environment-tool-base.ts
769
- var EnvironmentToolBase = class extends ToolBase {
770
- _environment;
771
- /**
772
- * Constructs a new `EnvironmentToolBase` instance.
773
- *
774
- * @param environment - The execution environment to apply the tool in.
775
- * @param toolConfig - Optional tool config, can be used to override some defaults.
776
- */
777
- constructor(environment, toolConfig) {
778
- super(toolConfig);
779
- this._environment = environment;
780
- }
781
- /**
782
- * Gets the current execution environment for the tool.
783
- *
784
- * @returns The current execution environment.
785
- */
786
- get environment() {
787
- return this._environment;
788
- }
789
- /**
790
- * Executes the tool with the given input.
791
- *
792
- * @param input - The input for the tool.
793
- * @param _options - Options from the tool call.
794
- * @returns A promise that resolves to the tool execution result.
795
- */
796
- execute(input, _options) {
797
- return this.executeForEnvironment(this._environment, input);
798
- }
799
- };
800
-
801
- // src/tools/copy-file-tool.ts
369
+ var import_environment_utils5 = require("@ai-code-agents/environment-utils");
802
370
  var CopyFileToolName = "copy_file";
803
371
  var CopyFileToolInput = import_zod.z.object({
804
372
  sourcePath: import_zod.z.string().meta({
@@ -808,8 +376,8 @@ var CopyFileToolInput = import_zod.z.object({
808
376
  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."
809
377
  })
810
378
  });
811
- var CopyFileToolOutput = CopyFileResult;
812
- var CopyFileTool = class extends EnvironmentToolBase {
379
+ var CopyFileToolOutput = import_environment_utils5.CopyFileResult;
380
+ var CopyFileTool = class extends import_environment_utils5.EnvironmentToolBase {
813
381
  /**
814
382
  * Returns the metadata for the tool.
815
383
  *
@@ -839,10 +407,11 @@ var CopyFileTool = class extends EnvironmentToolBase {
839
407
  /**
840
408
  * Converts the tool output to a format suitable for model consumption.
841
409
  *
842
- * @param output - The output from the tool execution.
410
+ * @param options - The tool result, including the output from the tool execution.
843
411
  * @returns The formatted tool result.
844
412
  */
845
- toModelOutput(output) {
413
+ toModelOutput(options) {
414
+ const { output } = options;
846
415
  return {
847
416
  type: "text",
848
417
  value: `File \`${output.sourcePath}\` copied successfully to \`${output.destinationPath}\`.`
@@ -868,14 +437,15 @@ var CopyFileTool = class extends EnvironmentToolBase {
868
437
 
869
438
  // src/tools/delete-file-tool.ts
870
439
  var import_zod2 = require("zod");
440
+ var import_environment_utils6 = require("@ai-code-agents/environment-utils");
871
441
  var DeleteFileToolName = "delete_file";
872
442
  var DeleteFileToolInput = import_zod2.z.object({
873
443
  path: import_zod2.z.string().meta({
874
444
  description: "The path to the file to delete, relative to the project directory."
875
445
  })
876
446
  });
877
- var DeleteFileToolOutput = DeleteFileResult;
878
- var DeleteFileTool = class extends EnvironmentToolBase {
447
+ var DeleteFileToolOutput = import_environment_utils6.DeleteFileResult;
448
+ var DeleteFileTool = class extends import_environment_utils6.EnvironmentToolBase {
879
449
  /**
880
450
  * Returns the metadata for the tool.
881
451
  *
@@ -905,10 +475,11 @@ var DeleteFileTool = class extends EnvironmentToolBase {
905
475
  /**
906
476
  * Converts the tool output to a format suitable for model consumption.
907
477
  *
908
- * @param output - The output from the tool execution.
478
+ * @param options - The tool result, including the output from the tool execution.
909
479
  * @returns The formatted tool result.
910
480
  */
911
- toModelOutput(output) {
481
+ toModelOutput(options) {
482
+ const { output } = options;
912
483
  return {
913
484
  type: "text",
914
485
  value: `File \`${output.path}\` deleted successfully.`
@@ -933,6 +504,7 @@ var DeleteFileTool = class extends EnvironmentToolBase {
933
504
 
934
505
  // src/tools/edit-file-tool.ts
935
506
  var import_zod3 = require("zod");
507
+ var import_environment_utils7 = require("@ai-code-agents/environment-utils");
936
508
  var EditFileToolName = "edit_file";
937
509
  var EditFileToolInput = import_zod3.z.object({
938
510
  path: import_zod3.z.string().meta({
@@ -965,10 +537,10 @@ var EditFileToolOutput = import_zod3.z.object({
965
537
  description: "A message indicating the result of the edit operation."
966
538
  })
967
539
  });
968
- function escapeRegExp(string2) {
969
- return string2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
540
+ function escapeRegExp(string) {
541
+ return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
970
542
  }
971
- var EditFileTool = class extends EnvironmentToolBase {
543
+ var EditFileTool = class extends import_environment_utils7.EnvironmentToolBase {
972
544
  /**
973
545
  * Returns the metadata for the tool.
974
546
  *
@@ -1023,10 +595,11 @@ var EditFileTool = class extends EnvironmentToolBase {
1023
595
  /**
1024
596
  * Converts the tool output to a format suitable for model consumption.
1025
597
  *
1026
- * @param output - The output from the tool execution.
598
+ * @param options - The tool result, including the output from the tool execution.
1027
599
  * @returns The formatted tool result.
1028
600
  */
1029
- toModelOutput(output) {
601
+ toModelOutput(options) {
602
+ const { output } = options;
1030
603
  return {
1031
604
  type: "text",
1032
605
  value: `Edited file \`${output.path}\` with ${output.replacements} replacement(s).`
@@ -1075,6 +648,7 @@ var EditFileTool = class extends EnvironmentToolBase {
1075
648
 
1076
649
  // src/tools/get-project-file-structure-tool.ts
1077
650
  var import_zod4 = require("zod");
651
+ var import_environment_utils9 = require("@ai-code-agents/environment-utils");
1078
652
 
1079
653
  // src/util/build-tree-from-files.ts
1080
654
  function renderTree(node, prefix = "") {
@@ -1111,6 +685,91 @@ function buildTreeFromFiles(files) {
1111
685
  return renderTree(tree).trim();
1112
686
  }
1113
687
 
688
+ // src/util/get-gitignored-paths.ts
689
+ var import_node_path3 = __toESM(require("path"), 1);
690
+ var import_environment_utils8 = require("@ai-code-agents/environment-utils");
691
+ async function getGitIgnoredPaths(env) {
692
+ const gitignorePath = await getClosestGitIgnorePath(env);
693
+ if (!gitignorePath) {
694
+ return [];
695
+ }
696
+ const { stdout: pwd } = await env.runCommand("pwd");
697
+ const currentDir = pwd.trim();
698
+ const gitignoreDir = import_node_path3.default.dirname(gitignorePath);
699
+ try {
700
+ const { stdout, exitCode } = await env.runCommand(
701
+ `cat ${(0, import_environment_utils8.escapeCommandArg)(gitignorePath)}`
702
+ );
703
+ if (exitCode !== 0) {
704
+ return [];
705
+ }
706
+ const rawRules = stdout.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
707
+ const relPath = import_node_path3.default.relative(gitignoreDir, currentDir);
708
+ if (relPath === "") {
709
+ return rawRules.map(
710
+ (rule) => rule.startsWith("/") ? rule.slice(1) : rule
711
+ );
712
+ }
713
+ const relPathSegments = relPath.split(import_node_path3.default.sep);
714
+ const sanitizedRules = [];
715
+ for (const rule of rawRules) {
716
+ const isAnchored = rule.startsWith("/") || rule.includes("/") && rule.indexOf("/") !== rule.length - 1;
717
+ if (!isAnchored || rule.startsWith("**/")) {
718
+ sanitizedRules.push(rule.startsWith("**/") ? rule.slice(3) : rule);
719
+ continue;
720
+ }
721
+ const normalizedRule = rule.startsWith("/") ? rule.slice(1) : rule;
722
+ const cleanRule = normalizedRule.endsWith("/") ? normalizedRule.slice(0, -1) : normalizedRule;
723
+ const ruleSegments = cleanRule.split("/");
724
+ let matches = true;
725
+ let i = 0;
726
+ for (; i < relPathSegments.length; i++) {
727
+ if (i >= ruleSegments.length) {
728
+ sanitizedRules.push(".");
729
+ matches = false;
730
+ break;
731
+ }
732
+ if (!matchSegment(ruleSegments[i], relPathSegments[i])) {
733
+ matches = false;
734
+ break;
735
+ }
736
+ }
737
+ if (matches) {
738
+ const remaining = ruleSegments.slice(i).join("/");
739
+ if (remaining) {
740
+ sanitizedRules.push(
741
+ normalizedRule.endsWith("/") && !remaining.endsWith("/") ? `${remaining}/` : remaining
742
+ );
743
+ } else {
744
+ sanitizedRules.push(".");
745
+ }
746
+ }
747
+ }
748
+ return [...new Set(sanitizedRules)];
749
+ } catch (_error) {
750
+ return [];
751
+ }
752
+ }
753
+ function matchSegment(pattern, segment) {
754
+ if (pattern === "*") {
755
+ return true;
756
+ }
757
+ if (pattern === segment) {
758
+ return true;
759
+ }
760
+ if (pattern.includes("*") || pattern.includes("?")) {
761
+ const regexStr = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
762
+ const regex = new RegExp(`^${regexStr}$`);
763
+ return regex.test(segment);
764
+ }
765
+ return false;
766
+ }
767
+ async function getClosestGitIgnorePath(env) {
768
+ const command = 'd=$PWD; while [ -n "$d" ] && [ ! -f "$d/.gitignore" ]; do d=${d%/*}; done; [ -f "$d/.gitignore" ] && echo "$d/.gitignore"';
769
+ const { stdout } = await env.runCommand(command);
770
+ return stdout.trim();
771
+ }
772
+
1114
773
  // src/tools/get-project-file-structure-tool.ts
1115
774
  var GetProjectFileStructureToolName = "get_project_file_structure";
1116
775
  var GetProjectFileStructureToolInput = import_zod4.z.object({
@@ -1129,7 +788,7 @@ var GetProjectFileStructureToolOutput = import_zod4.z.object({
1129
788
  description: "Whether files ignored by Git were excluded."
1130
789
  })
1131
790
  });
1132
- var GetProjectFileStructureTool = class extends EnvironmentToolBase {
791
+ var GetProjectFileStructureTool = class extends import_environment_utils9.EnvironmentToolBase {
1133
792
  /**
1134
793
  * Returns the metadata for the tool.
1135
794
  *
@@ -1155,21 +814,16 @@ var GetProjectFileStructureTool = class extends EnvironmentToolBase {
1155
814
  */
1156
815
  async executeForEnvironment(env, input) {
1157
816
  const { path: path5 = ".", excludeGitIgnored = true } = input;
1158
- const escapedPath = escapeCommandArg(path5);
817
+ const escapedPath = (0, import_environment_utils9.escapeCommandArg)(path5);
1159
818
  let command = `find ${escapedPath} -type f`;
1160
819
  if (excludeGitIgnored) {
1161
- let gitIgnoredPaths = [];
1162
- try {
1163
- const { content: gitignoreContent } = await env.readFile(".gitignore");
1164
- gitIgnoredPaths = gitignoreContent.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
1165
- } catch (_error) {
1166
- }
820
+ const gitIgnoredPaths = await getGitIgnoredPaths(env);
1167
821
  for (const gitIgnoredPath of gitIgnoredPaths) {
1168
822
  if (!gitIgnoredPath.endsWith("/")) {
1169
- const escapedPath2 = escapeCommandArg(`*/${gitIgnoredPath}/*`);
1170
- command += ` -not -name ${escapeCommandArg(gitIgnoredPath)} -not -path ${escapedPath2}`;
823
+ const escapedPath2 = (0, import_environment_utils9.escapeCommandArg)(`*/${gitIgnoredPath}/*`);
824
+ command += ` -not -name ${(0, import_environment_utils9.escapeCommandArg)(gitIgnoredPath)} -not -path ${escapedPath2}`;
1171
825
  } else {
1172
- const escapedPath2 = escapeCommandArg(`*/${gitIgnoredPath}*`);
826
+ const escapedPath2 = (0, import_environment_utils9.escapeCommandArg)(`*/${gitIgnoredPath}*`);
1173
827
  command += ` -not -path ${escapedPath2}`;
1174
828
  }
1175
829
  }
@@ -1191,10 +845,11 @@ var GetProjectFileStructureTool = class extends EnvironmentToolBase {
1191
845
  /**
1192
846
  * Converts the tool output to a format suitable for model consumption.
1193
847
  *
1194
- * @param output - The output from the tool execution.
848
+ * @param options - The tool result, including the output from the tool execution.
1195
849
  * @returns The formatted tool result.
1196
850
  */
1197
- toModelOutput(output) {
851
+ toModelOutput(options) {
852
+ const { output } = options;
1198
853
  const tree = buildTreeFromFiles(output.files);
1199
854
  if (!tree) {
1200
855
  return {
@@ -1233,6 +888,7 @@ var GetProjectFileStructureTool = class extends EnvironmentToolBase {
1233
888
 
1234
889
  // src/tools/glob-tool.ts
1235
890
  var import_zod5 = require("zod");
891
+ var import_environment_utils10 = require("@ai-code-agents/environment-utils");
1236
892
 
1237
893
  // src/util/glob-to-reg-exp.ts
1238
894
  function globToRegExp(glob) {
@@ -1305,7 +961,7 @@ var GlobToolOutput = import_zod5.z.object({
1305
961
  description: "The list of file paths that matched the glob search, relative to the project directory."
1306
962
  })
1307
963
  });
1308
- var GlobTool = class extends EnvironmentToolBase {
964
+ var GlobTool = class extends import_environment_utils10.EnvironmentToolBase {
1309
965
  /**
1310
966
  * Returns the metadata for the tool.
1311
967
  *
@@ -1337,24 +993,19 @@ var GlobTool = class extends EnvironmentToolBase {
1337
993
  );
1338
994
  }
1339
995
  if (searchPath) {
1340
- validateRelativePath(searchPath);
996
+ (0, import_environment_utils10.validateRelativePath)(searchPath);
1341
997
  }
1342
998
  const untrailingslashedSearchPath = searchPath === "" ? "." : searchPath.replace(/\/+$/, "");
1343
- const escapedSearchPath = escapeCommandArg(untrailingslashedSearchPath);
999
+ const escapedSearchPath = (0, import_environment_utils10.escapeCommandArg)(untrailingslashedSearchPath);
1344
1000
  let command = `find ${escapedSearchPath} -type f`;
1345
1001
  if (excludeGitIgnored) {
1346
- let gitIgnoredPaths = [];
1347
- try {
1348
- const { content: gitignoreContent } = await env.readFile(".gitignore");
1349
- gitIgnoredPaths = gitignoreContent.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
1350
- } catch (_error) {
1351
- }
1002
+ const gitIgnoredPaths = await getGitIgnoredPaths(env);
1352
1003
  for (const gitIgnoredPath of gitIgnoredPaths) {
1353
1004
  if (!gitIgnoredPath.endsWith("/")) {
1354
- const escapedPath = escapeCommandArg(`*/${gitIgnoredPath}/*`);
1355
- command += ` -not -name ${escapeCommandArg(gitIgnoredPath)} -not -path ${escapedPath}`;
1005
+ const escapedPath = (0, import_environment_utils10.escapeCommandArg)(`*/${gitIgnoredPath}/*`);
1006
+ command += ` -not -name ${(0, import_environment_utils10.escapeCommandArg)(gitIgnoredPath)} -not -path ${escapedPath}`;
1356
1007
  } else {
1357
- const escapedPath = escapeCommandArg(`*/${gitIgnoredPath}*`);
1008
+ const escapedPath = (0, import_environment_utils10.escapeCommandArg)(`*/${gitIgnoredPath}*`);
1358
1009
  command += ` -not -path ${escapedPath}`;
1359
1010
  }
1360
1011
  }
@@ -1390,10 +1041,11 @@ var GlobTool = class extends EnvironmentToolBase {
1390
1041
  /**
1391
1042
  * Converts the tool output to a format suitable for model consumption.
1392
1043
  *
1393
- * @param output - The output from the tool execution.
1044
+ * @param options - The tool result, including the output from the tool execution.
1394
1045
  * @returns The formatted tool result.
1395
1046
  */
1396
- toModelOutput(output) {
1047
+ toModelOutput(options) {
1048
+ const { output } = options;
1397
1049
  if (output.matchingPaths.length === 0) {
1398
1050
  return {
1399
1051
  type: "text",
@@ -1442,26 +1094,287 @@ ${bulletPoints}
1442
1094
  }
1443
1095
  };
1444
1096
 
1445
- // src/tools/list-directory-tool.ts
1097
+ // src/tools/grep-tool.ts
1446
1098
  var import_zod6 = require("zod");
1447
- var ListDirectoryToolName = "list_directory";
1448
- var ListDirectoryToolInput = import_zod6.z.object({
1099
+ var import_environment_utils11 = require("@ai-code-agents/environment-utils");
1100
+ var GrepToolName = "grep";
1101
+ var GrepToolInput = import_zod6.z.object({
1102
+ regexpPattern: import_zod6.z.string().meta({
1103
+ description: "The regular expression pattern to search for in file contents."
1104
+ }),
1105
+ searchPattern: import_zod6.z.string().optional().meta({
1106
+ description: 'The glob pattern to filter which files are searched (e.g. "**/*.ts"). If omitted, searches all files.'
1107
+ }),
1108
+ searchPath: import_zod6.z.string().optional().meta({
1109
+ description: "The path to search within, relative to the project directory. Defaults to the project directory."
1110
+ }),
1111
+ contextLines: import_zod6.z.number().int().nonnegative().optional().meta({
1112
+ description: "The number of context lines to include before and after each match."
1113
+ })
1114
+ });
1115
+ var GrepMatch = import_zod6.z.object({
1449
1116
  path: import_zod6.z.string().meta({
1117
+ description: "The path to the file containing the match, relative to the project directory."
1118
+ }),
1119
+ lineNumber: import_zod6.z.number().int().meta({
1120
+ description: "The line number of the match (1-based)."
1121
+ }),
1122
+ line: import_zod6.z.string().meta({
1123
+ description: "The content of the matching line."
1124
+ }),
1125
+ beforeContext: import_zod6.z.array(import_zod6.z.string()).optional().meta({
1126
+ description: "Lines of context before the match."
1127
+ }),
1128
+ afterContext: import_zod6.z.array(import_zod6.z.string()).optional().meta({
1129
+ description: "Lines of context after the match."
1130
+ })
1131
+ });
1132
+ var GrepToolOutput = import_zod6.z.object({
1133
+ regexpPattern: import_zod6.z.string().meta({
1134
+ description: "The regular expression pattern that was searched for."
1135
+ }),
1136
+ searchPattern: import_zod6.z.string().optional().meta({
1137
+ description: "The glob pattern used to filter files."
1138
+ }),
1139
+ searchPath: import_zod6.z.string().optional().meta({
1140
+ description: "The path that was searched within."
1141
+ }),
1142
+ contextLines: import_zod6.z.number().optional().meta({
1143
+ description: "The number of context lines included."
1144
+ }),
1145
+ matches: import_zod6.z.array(GrepMatch).meta({
1146
+ description: "The list of matches found."
1147
+ })
1148
+ });
1149
+ var GrepTool = class extends import_environment_utils11.EnvironmentToolBase {
1150
+ /**
1151
+ * Returns the metadata for the tool.
1152
+ *
1153
+ * The name, description, and needsApproval properties are defaults which can be overridden in the constructor.
1154
+ *
1155
+ * @returns The tool metadata.
1156
+ */
1157
+ getMetadata() {
1158
+ return {
1159
+ name: GrepToolName,
1160
+ description: "Searches for a regular expression pattern within the content of files in the project.",
1161
+ inputSchema: GrepToolInput,
1162
+ outputSchema: GrepToolOutput,
1163
+ needsApproval: false
1164
+ };
1165
+ }
1166
+ /**
1167
+ * Executes the tool in the given execution environment with the given input.
1168
+ *
1169
+ * @param env - The execution environment to use.
1170
+ * @param input - The input for the tool.
1171
+ * @returns A promise that resolves to the tool execution result.
1172
+ */
1173
+ async executeForEnvironment(env, input) {
1174
+ const {
1175
+ regexpPattern,
1176
+ searchPattern,
1177
+ searchPath = "",
1178
+ contextLines = 0
1179
+ } = input;
1180
+ if (searchPath) {
1181
+ (0, import_environment_utils11.validateRelativePath)(searchPath);
1182
+ }
1183
+ const globTool = new GlobTool(env);
1184
+ const globResult = await globTool.execute(
1185
+ {
1186
+ searchPattern: searchPattern || "**/*",
1187
+ searchPath
1188
+ },
1189
+ {}
1190
+ );
1191
+ const filesToSearch = globResult.matchingPaths;
1192
+ if (filesToSearch.length === 0) {
1193
+ return {
1194
+ regexpPattern,
1195
+ searchPattern,
1196
+ searchPath,
1197
+ contextLines,
1198
+ matches: []
1199
+ };
1200
+ }
1201
+ const BATCH_SIZE = 50;
1202
+ const matches = [];
1203
+ for (let i = 0; i < filesToSearch.length; i += BATCH_SIZE) {
1204
+ const batch = filesToSearch.slice(i, i + BATCH_SIZE);
1205
+ const escapedFilePaths = batch.map(import_environment_utils11.escapeCommandArg).join(" ");
1206
+ const command = `grep -n -H -I -E ${(0, import_environment_utils11.escapeCommandArg)(regexpPattern)} ${escapedFilePaths}`;
1207
+ const { stdout, exitCode } = await env.runCommand(command);
1208
+ if (exitCode > 1) {
1209
+ throw new Error(`Failed to execute grep command "${command}".`);
1210
+ }
1211
+ if (stdout) {
1212
+ const lines = stdout.split("\n");
1213
+ for (const line of lines) {
1214
+ if (!line.trim()) continue;
1215
+ const firstColonIndex = line.indexOf(":");
1216
+ if (firstColonIndex === -1) continue;
1217
+ const secondColonIndex = line.indexOf(":", firstColonIndex + 1);
1218
+ if (secondColonIndex === -1) continue;
1219
+ const filePath = line.substring(0, firstColonIndex);
1220
+ const lineNumberStr = line.substring(
1221
+ firstColonIndex + 1,
1222
+ secondColonIndex
1223
+ );
1224
+ const content = line.substring(secondColonIndex + 1);
1225
+ const lineNumber = parseInt(lineNumberStr, 10);
1226
+ if (isNaN(lineNumber)) continue;
1227
+ matches.push({
1228
+ path: filePath,
1229
+ lineNumber,
1230
+ line: content
1231
+ });
1232
+ }
1233
+ }
1234
+ }
1235
+ if (contextLines > 0 && matches.length > 0) {
1236
+ const matchesByFile = /* @__PURE__ */ new Map();
1237
+ for (const match of matches) {
1238
+ if (!matchesByFile.has(match.path)) {
1239
+ matchesByFile.set(match.path, []);
1240
+ }
1241
+ matchesByFile.get(match.path).push(match);
1242
+ }
1243
+ for (const [filePath, fileMatches] of matchesByFile) {
1244
+ try {
1245
+ const { content } = await env.readFile(filePath);
1246
+ const lines = content.split("\n");
1247
+ for (const match of fileMatches) {
1248
+ const lineIndex = match.lineNumber - 1;
1249
+ const start = Math.max(0, lineIndex - contextLines);
1250
+ const end = Math.min(lines.length, lineIndex + contextLines + 1);
1251
+ match.beforeContext = lines.slice(start, lineIndex);
1252
+ match.afterContext = lines.slice(lineIndex + 1, end);
1253
+ }
1254
+ } catch (_error) {
1255
+ }
1256
+ }
1257
+ }
1258
+ return {
1259
+ regexpPattern,
1260
+ searchPattern,
1261
+ searchPath,
1262
+ contextLines,
1263
+ matches
1264
+ };
1265
+ }
1266
+ /**
1267
+ * Converts the tool output to a format suitable for model consumption.
1268
+ *
1269
+ * @param options - The tool result, including the output from the tool execution.
1270
+ * @returns The formatted tool result.
1271
+ */
1272
+ toModelOutput(options) {
1273
+ const { output } = options;
1274
+ if (output.matches.length === 0) {
1275
+ return {
1276
+ type: "text",
1277
+ value: "No matches found."
1278
+ };
1279
+ }
1280
+ let result = `Found ${output.matches.length} matches:
1281
+ `;
1282
+ const matchesByFile = /* @__PURE__ */ new Map();
1283
+ for (const match of output.matches) {
1284
+ if (!matchesByFile.has(match.path)) {
1285
+ matchesByFile.set(match.path, []);
1286
+ }
1287
+ matchesByFile.get(match.path).push(match);
1288
+ }
1289
+ for (const [filePath, matches] of matchesByFile) {
1290
+ result += `
1291
+ File: ${filePath}
1292
+ `;
1293
+ for (const match of matches) {
1294
+ if (match.beforeContext && match.beforeContext.length > 0) {
1295
+ match.beforeContext.forEach((line, idx) => {
1296
+ result += ` ${match.lineNumber - match.beforeContext.length + idx}: ${line}
1297
+ `;
1298
+ });
1299
+ }
1300
+ result += `> ${match.lineNumber}: ${match.line}
1301
+ `;
1302
+ if (match.afterContext && match.afterContext.length > 0) {
1303
+ match.afterContext.forEach((line, idx) => {
1304
+ result += ` ${match.lineNumber + 1 + idx}: ${line}
1305
+ `;
1306
+ });
1307
+ }
1308
+ if (output.contextLines && output.contextLines > 0) {
1309
+ result += "---\n";
1310
+ }
1311
+ }
1312
+ }
1313
+ return {
1314
+ type: "text",
1315
+ value: result
1316
+ };
1317
+ }
1318
+ /**
1319
+ * Gets the examples for the tool.
1320
+ *
1321
+ * @returns The tool examples.
1322
+ */
1323
+ get examples() {
1324
+ return [
1325
+ {
1326
+ input: {
1327
+ regexpPattern: "interface.*Tool",
1328
+ searchPattern: "src/**/*.ts"
1329
+ },
1330
+ output: `Found 2 matches:
1331
+
1332
+ File: src/types.ts
1333
+ > 120: export interface ToolInterface<ToolInputType, ToolOutputType> {
1334
+ > 135: export interface EnvironmentToolInterface<
1335
+
1336
+ File: src/tools/tool-base.ts
1337
+ > 10: export abstract class ToolBase<
1338
+ `
1339
+ },
1340
+ {
1341
+ input: {
1342
+ regexpPattern: "TODO",
1343
+ contextLines: 1
1344
+ },
1345
+ output: `Found 1 matches:
1346
+
1347
+ File: src/index.ts
1348
+ 10: // Some code before
1349
+ > 11: // TODO: Implement feature X
1350
+ 12: // Some code after
1351
+ `
1352
+ }
1353
+ ];
1354
+ }
1355
+ };
1356
+
1357
+ // src/tools/list-directory-tool.ts
1358
+ var import_zod7 = require("zod");
1359
+ var import_environment_utils12 = require("@ai-code-agents/environment-utils");
1360
+ var ListDirectoryToolName = "list_directory";
1361
+ var ListDirectoryToolInput = import_zod7.z.object({
1362
+ path: import_zod7.z.string().meta({
1450
1363
  description: "The directory path to list, relative to the project directory."
1451
1364
  })
1452
1365
  });
1453
- var ListDirectoryToolOutput = import_zod6.z.object({
1454
- path: import_zod6.z.string().meta({
1366
+ var ListDirectoryToolOutput = import_zod7.z.object({
1367
+ path: import_zod7.z.string().meta({
1455
1368
  description: "The directory path that was listed."
1456
1369
  }),
1457
- files: import_zod6.z.array(import_zod6.z.string()).meta({
1370
+ files: import_zod7.z.array(import_zod7.z.string()).meta({
1458
1371
  description: "List of files in the directory."
1459
1372
  }),
1460
- directories: import_zod6.z.array(import_zod6.z.string()).meta({
1373
+ directories: import_zod7.z.array(import_zod7.z.string()).meta({
1461
1374
  description: "List of subdirectories in the directory."
1462
1375
  })
1463
1376
  });
1464
- var ListDirectoryTool = class extends EnvironmentToolBase {
1377
+ var ListDirectoryTool = class extends import_environment_utils12.EnvironmentToolBase {
1465
1378
  /**
1466
1379
  * Returns the metadata for the tool.
1467
1380
  *
@@ -1486,7 +1399,7 @@ var ListDirectoryTool = class extends EnvironmentToolBase {
1486
1399
  * @returns A promise that resolves to the tool execution result.
1487
1400
  */
1488
1401
  async executeForEnvironment(env, input) {
1489
- const escapedPath = escapeCommandArg(input.path);
1402
+ const escapedPath = (0, import_environment_utils12.escapeCommandArg)(input.path);
1490
1403
  const command = `ls -la ${escapedPath}`;
1491
1404
  const { stdout, stderr, exitCode } = await env.runCommand(command);
1492
1405
  if (exitCode !== 0) {
@@ -1519,10 +1432,11 @@ var ListDirectoryTool = class extends EnvironmentToolBase {
1519
1432
  /**
1520
1433
  * Converts the tool output to a format suitable for model consumption.
1521
1434
  *
1522
- * @param output - The output from the tool execution.
1435
+ * @param options - The tool result, including the output from the tool execution.
1523
1436
  * @returns The formatted tool result.
1524
1437
  */
1525
- toModelOutput(output) {
1438
+ toModelOutput(options) {
1439
+ const { output } = options;
1526
1440
  const formatEntries = (entries, type) => {
1527
1441
  if (entries.length === 0) {
1528
1442
  return `No ${type} found.`;
@@ -1568,18 +1482,19 @@ Directories:
1568
1482
  };
1569
1483
 
1570
1484
  // src/tools/move-file-tool.ts
1571
- var import_zod7 = require("zod");
1485
+ var import_zod8 = require("zod");
1486
+ var import_environment_utils13 = require("@ai-code-agents/environment-utils");
1572
1487
  var MoveFileToolName = "move_file";
1573
- var MoveFileToolInput = import_zod7.z.object({
1574
- sourcePath: import_zod7.z.string().meta({
1488
+ var MoveFileToolInput = import_zod8.z.object({
1489
+ sourcePath: import_zod8.z.string().meta({
1575
1490
  description: "The path to the file to move, relative to the project directory."
1576
1491
  }),
1577
- destinationPath: import_zod7.z.string().meta({
1492
+ destinationPath: import_zod8.z.string().meta({
1578
1493
  description: "The path to the destination where the file should be moved, relative to the project directory. If the file already exists, it will be overwritten."
1579
1494
  })
1580
1495
  });
1581
- var MoveFileToolOutput = MoveFileResult;
1582
- var MoveFileTool = class extends EnvironmentToolBase {
1496
+ var MoveFileToolOutput = import_environment_utils13.MoveFileResult;
1497
+ var MoveFileTool = class extends import_environment_utils13.EnvironmentToolBase {
1583
1498
  /**
1584
1499
  * Returns the metadata for the tool.
1585
1500
  *
@@ -1609,10 +1524,11 @@ var MoveFileTool = class extends EnvironmentToolBase {
1609
1524
  /**
1610
1525
  * Converts the tool output to a format suitable for model consumption.
1611
1526
  *
1612
- * @param output - The output from the tool execution.
1527
+ * @param options - The tool result, including the output from the tool execution.
1613
1528
  * @returns The formatted tool result.
1614
1529
  */
1615
- toModelOutput(output) {
1530
+ toModelOutput(options) {
1531
+ const { output } = options;
1616
1532
  return {
1617
1533
  type: "text",
1618
1534
  value: `File \`${output.sourcePath}\` moved successfully to \`${output.destinationPath}\`.`
@@ -1637,10 +1553,11 @@ var MoveFileTool = class extends EnvironmentToolBase {
1637
1553
  };
1638
1554
 
1639
1555
  // src/tools/read-file-tool.ts
1640
- var import_zod8 = require("zod");
1556
+ var import_zod9 = require("zod");
1557
+ var import_environment_utils14 = require("@ai-code-agents/environment-utils");
1641
1558
 
1642
1559
  // src/util/get-language-identifier-from-file-path.ts
1643
- var import_node_path3 = __toESM(require("path"), 1);
1560
+ var import_node_path4 = __toESM(require("path"), 1);
1644
1561
  var jsLanguage = {
1645
1562
  identifier: "javascript",
1646
1563
  name: "JavaScript",
@@ -1790,7 +1707,7 @@ var EXTENSION_TO_LANGUAGE = {
1790
1707
  }
1791
1708
  };
1792
1709
  function getLanguageFromFilePath(filePath) {
1793
- const extension = import_node_path3.default.extname(filePath).slice(1).toLowerCase() || "";
1710
+ const extension = import_node_path4.default.extname(filePath).slice(1).toLowerCase() || "";
1794
1711
  return EXTENSION_TO_LANGUAGE[extension];
1795
1712
  }
1796
1713
  function getLanguageIdentifierFromFilePath(filePath) {
@@ -1800,12 +1717,12 @@ function getLanguageIdentifierFromFilePath(filePath) {
1800
1717
 
1801
1718
  // src/tools/read-file-tool.ts
1802
1719
  var ReadFileToolName = "read_file";
1803
- var ReadFileToolInput = import_zod8.z.object({
1804
- path: import_zod8.z.string().meta({
1720
+ var ReadFileToolInput = import_zod9.z.object({
1721
+ path: import_zod9.z.string().meta({
1805
1722
  description: "The path to the file to read, relative to the project directory."
1806
1723
  })
1807
1724
  });
1808
- var ReadFileToolOutput = ReadFileResult;
1725
+ var ReadFileToolOutput = import_environment_utils14.ReadFileResult;
1809
1726
  var formatModelResponse = (output) => {
1810
1727
  const language = getLanguageIdentifierFromFilePath(output.path);
1811
1728
  return `File: \`${output.path}\`
@@ -1815,7 +1732,7 @@ ${output.content}
1815
1732
  \`\`\`
1816
1733
  `;
1817
1734
  };
1818
- var ReadFileTool = class extends EnvironmentToolBase {
1735
+ var ReadFileTool = class extends import_environment_utils14.EnvironmentToolBase {
1819
1736
  /**
1820
1737
  * Returns the metadata for the tool.
1821
1738
  *
@@ -1845,10 +1762,11 @@ var ReadFileTool = class extends EnvironmentToolBase {
1845
1762
  /**
1846
1763
  * Converts the tool output to a format suitable for model consumption.
1847
1764
  *
1848
- * @param output - The output from the tool execution.
1765
+ * @param options - The tool result, including the output from the tool execution.
1849
1766
  * @returns The formatted tool result.
1850
1767
  */
1851
- toModelOutput(output) {
1768
+ toModelOutput(options) {
1769
+ const { output } = options;
1852
1770
  return {
1853
1771
  type: "text",
1854
1772
  value: formatModelResponse(output)
@@ -1891,14 +1809,15 @@ export function Loader(props: LoaderProps) {
1891
1809
  };
1892
1810
 
1893
1811
  // src/tools/read-many-files-tool.ts
1894
- var import_zod9 = require("zod");
1812
+ var import_zod10 = require("zod");
1813
+ var import_environment_utils15 = require("@ai-code-agents/environment-utils");
1895
1814
  var ReadManyFilesToolName = "read_many_files";
1896
- var ReadManyFilesToolInput = import_zod9.z.object({
1897
- paths: import_zod9.z.array(import_zod9.z.string()).meta({
1815
+ var ReadManyFilesToolInput = import_zod10.z.object({
1816
+ paths: import_zod10.z.array(import_zod10.z.string()).meta({
1898
1817
  description: "The paths to the files to read, relative to the project directory."
1899
1818
  })
1900
1819
  });
1901
- var ReadManyFilesToolOutput = import_zod9.z.record(import_zod9.z.string(), ReadFileResult);
1820
+ var ReadManyFilesToolOutput = import_zod10.z.record(import_zod10.z.string(), import_environment_utils15.ReadFileResult);
1902
1821
  var formatModelResponse2 = (output) => {
1903
1822
  const language = getLanguageIdentifierFromFilePath(output.path);
1904
1823
  return `File: \`${output.path}\`
@@ -1908,7 +1827,7 @@ ${output.content}
1908
1827
  \`\`\`
1909
1828
  `;
1910
1829
  };
1911
- var ReadManyFilesTool = class extends EnvironmentToolBase {
1830
+ var ReadManyFilesTool = class extends import_environment_utils15.EnvironmentToolBase {
1912
1831
  /**
1913
1832
  * Returns the metadata for the tool.
1914
1833
  *
@@ -1944,10 +1863,11 @@ var ReadManyFilesTool = class extends EnvironmentToolBase {
1944
1863
  /**
1945
1864
  * Converts the tool output to a format suitable for model consumption.
1946
1865
  *
1947
- * @param output - The output from the tool execution.
1866
+ * @param options - The tool result, including the output from the tool execution.
1948
1867
  * @returns The formatted tool result.
1949
1868
  */
1950
- toModelOutput(output) {
1869
+ toModelOutput(options) {
1870
+ const { output } = options;
1951
1871
  const fileContentResponses = Object.values(output).map(
1952
1872
  (fileResult) => formatModelResponse2(fileResult)
1953
1873
  );
@@ -2003,12 +1923,13 @@ export function Loader(props: LoaderProps) {
2003
1923
  };
2004
1924
 
2005
1925
  // src/tools/run-command-tool.ts
2006
- var import_zod10 = require("zod");
1926
+ var import_zod11 = require("zod");
1927
+ var import_environment_utils16 = require("@ai-code-agents/environment-utils");
2007
1928
  var RunCommandToolName = "run_command";
2008
- var RunCommandToolInput = import_zod10.z.object({
2009
- command: import_zod10.z.string().meta({ description: "The CLI command to run, including all arguments." })
1929
+ var RunCommandToolInput = import_zod11.z.object({
1930
+ command: import_zod11.z.string().meta({ description: "The CLI command to run, including all arguments." })
2010
1931
  });
2011
- var RunCommandToolOutput = RunCommandResult;
1932
+ var RunCommandToolOutput = import_environment_utils16.RunCommandResult;
2012
1933
  function formatCommandResultToModelResponse(output) {
2013
1934
  const stdout = !output.stdout.trim() ? "(none)" : `
2014
1935
  \`\`\`
@@ -2024,7 +1945,7 @@ Output (stdout): ${stdout}
2024
1945
  Error Output (stderr): ${stderr}
2025
1946
  `;
2026
1947
  }
2027
- var RunCommandTool = class extends EnvironmentToolBase {
1948
+ var RunCommandTool = class extends import_environment_utils16.EnvironmentToolBase {
2028
1949
  /**
2029
1950
  * Returns the metadata for the tool.
2030
1951
  *
@@ -2054,10 +1975,11 @@ var RunCommandTool = class extends EnvironmentToolBase {
2054
1975
  /**
2055
1976
  * Converts the tool output to a format suitable for model consumption.
2056
1977
  *
2057
- * @param output - The output from the tool execution.
1978
+ * @param options - The tool result, including the output from the tool execution.
2058
1979
  * @returns The formatted tool result.
2059
1980
  */
2060
- toModelOutput(output) {
1981
+ toModelOutput(options) {
1982
+ const { output } = options;
2061
1983
  return {
2062
1984
  type: "text",
2063
1985
  value: formatCommandResultToModelResponse(output)
@@ -2128,18 +2050,19 @@ added 1 package, and changed 1 package in 2s
2128
2050
  };
2129
2051
 
2130
2052
  // src/tools/write-file-tool.ts
2131
- var import_zod11 = require("zod");
2053
+ var import_zod12 = require("zod");
2054
+ var import_environment_utils17 = require("@ai-code-agents/environment-utils");
2132
2055
  var WriteFileToolName = "write_file";
2133
- var WriteFileToolInput = import_zod11.z.object({
2134
- path: import_zod11.z.string().meta({
2056
+ var WriteFileToolInput = import_zod12.z.object({
2057
+ path: import_zod12.z.string().meta({
2135
2058
  description: "The path to the file to write, relative to the project directory."
2136
2059
  }),
2137
- content: import_zod11.z.string().meta({
2060
+ content: import_zod12.z.string().meta({
2138
2061
  description: "The content to write to the file. If the file already exists, the content will replace existing content."
2139
2062
  })
2140
2063
  });
2141
- var WriteFileToolOutput = WriteFileResult;
2142
- var WriteFileTool = class extends EnvironmentToolBase {
2064
+ var WriteFileToolOutput = import_environment_utils17.WriteFileResult;
2065
+ var WriteFileTool = class extends import_environment_utils17.EnvironmentToolBase {
2143
2066
  /**
2144
2067
  * Returns the metadata for the tool.
2145
2068
  *
@@ -2169,10 +2092,11 @@ var WriteFileTool = class extends EnvironmentToolBase {
2169
2092
  /**
2170
2093
  * Converts the tool output to a format suitable for model consumption.
2171
2094
  *
2172
- * @param output - The output from the tool execution.
2095
+ * @param options - The tool result, including the output from the tool execution.
2173
2096
  * @returns The formatted tool result.
2174
2097
  */
2175
- toModelOutput(output) {
2098
+ toModelOutput(options) {
2099
+ const { output } = options;
2176
2100
  return {
2177
2101
  type: "text",
2178
2102
  value: `File \`${output.path}\` written successfully.`
@@ -2200,15 +2124,13 @@ var WriteFileTool = class extends EnvironmentToolBase {
2200
2124
  }
2201
2125
  };
2202
2126
 
2203
- // src/agent-creators.ts
2204
- var import_ai = require("ai");
2205
-
2206
2127
  // src/tools/submit-tool.ts
2207
- var import_zod12 = require("zod");
2128
+ var import_zod13 = require("zod");
2129
+ var import_environment_utils18 = require("@ai-code-agents/environment-utils");
2208
2130
  var SubmitToolName = "submit";
2209
- var SubmitToolInput = import_zod12.z.object({});
2210
- var SubmitToolOutput = import_zod12.z.object({});
2211
- var SubmitTool = class extends ToolBase {
2131
+ var SubmitToolInput = import_zod13.z.object({});
2132
+ var SubmitToolOutput = import_zod13.z.object({});
2133
+ var SubmitTool = class extends import_environment_utils18.ToolBase {
2212
2134
  /**
2213
2135
  * Returns the metadata for the tool.
2214
2136
  *
@@ -2229,7 +2151,7 @@ var SubmitTool = class extends ToolBase {
2229
2151
  * Executes the tool with the given input.
2230
2152
  *
2231
2153
  * @param _ - The input for the tool. Unused.
2232
- * @param __ - Options from the tool call. Unused.
2154
+ * @param __ - Options for the tool execution. Unused.
2233
2155
  * @returns A promise that resolves to the tool execution result.
2234
2156
  */
2235
2157
  async execute(_, __) {
@@ -2238,7 +2160,7 @@ var SubmitTool = class extends ToolBase {
2238
2160
  /**
2239
2161
  * Converts the tool output to a format suitable for model consumption.
2240
2162
  *
2241
- * @param _ - The output from the tool execution. Unused.
2163
+ * @param _ - The tool result, including the output from the tool execution. Unused.
2242
2164
  * @returns The formatted tool result.
2243
2165
  */
2244
2166
  toModelOutput(_) {
@@ -2257,13 +2179,19 @@ var SubmitTool = class extends ToolBase {
2257
2179
  }
2258
2180
  };
2259
2181
 
2182
+ // src/agent-creators.ts
2183
+ var import_ai = require("ai");
2184
+
2260
2185
  // src/instructions.ts
2261
2186
  function getAdditionalInstructions(config) {
2262
2187
  const { maxSteps, allowSubmit, tools } = config;
2263
- const exampleSections = [];
2188
+ const exampleSections = [
2189
+ "# Tool Examples",
2190
+ "You have access to several tools to assist you in completing your task. Here are some examples of how to use them:"
2191
+ ];
2264
2192
  for (const [toolName, tool] of Object.entries(tools)) {
2265
2193
  if ("examples" in tool && Array.isArray(tool.examples) && tool.examples.length > 0) {
2266
- let toolSection = `### Tool: \`${toolName}\`
2194
+ let toolSection = `## Tool: \`${toolName}\`
2267
2195
 
2268
2196
  `;
2269
2197
  for (const example of tool.examples) {
@@ -2272,40 +2200,48 @@ function getAdditionalInstructions(config) {
2272
2200
  exampleSections.push(toolSection.trim());
2273
2201
  }
2274
2202
  }
2275
- const workflowGuidelines = [
2276
- /*
2277
- * If there are examples, the tool information is already mentioned in a separate Tool Examples section.
2278
- * Therefore the line below is only relevant if there are no examples.
2279
- */
2280
- ...!exampleSections.length ? [
2281
- "You have access to several tools to assist you in completing your task."
2282
- ] : [],
2283
- "You must issue tool calls to complete your task. Do not engage with the user directly.",
2284
- ...allowSubmit ? [
2285
- `Once you think you have completed your task, call the \`${SubmitToolName}\` tool to submit your results.`
2286
- ] : [],
2287
- `You have a maximum of ${maxSteps} steps to complete your task.`
2288
- ];
2289
- const importantWorkflowGuidelines = `## Important Workflow Guidelines
2290
-
2291
- ${workflowGuidelines.map((line) => `- ${line}`).join("\n")}
2292
-
2293
- 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.
2203
+ const constraintSections = ["# Behavioral Guidelines"];
2204
+ const constraintsByType = getCodeAgentConstraints({ maxSteps, allowSubmit });
2205
+ if (constraintsByType.must && constraintsByType.must.length > 0) {
2206
+ let constraintSection = "## You MUST:\n\n";
2207
+ for (const constraint of constraintsByType.must) {
2208
+ constraintSection += `- ${constraint}
2294
2209
  `;
2295
- if (exampleSections.length) {
2296
- return `## Tool Examples
2297
-
2298
- You have access to several tools to assist you in completing your task. Here are some examples of how to use them:
2299
-
2300
- ${exampleSections.join("\n\n")}
2301
-
2302
- ` + importantWorkflowGuidelines;
2210
+ }
2211
+ constraintSections.push(constraintSection.trim());
2212
+ }
2213
+ if (constraintsByType.must_not && constraintsByType.must_not.length > 0) {
2214
+ let constraintSection = "## You MUST NOT:\n\n";
2215
+ for (const constraint of constraintsByType.must_not) {
2216
+ constraintSection += `- ${constraint}
2217
+ `;
2218
+ }
2219
+ constraintSections.push(constraintSection.trim());
2220
+ }
2221
+ if (constraintsByType.should && constraintsByType.should.length > 0) {
2222
+ let constraintSection = "## You SHOULD:\n\n";
2223
+ for (const constraint of constraintsByType.should) {
2224
+ constraintSection += `- ${constraint}
2225
+ `;
2226
+ }
2227
+ constraintSections.push(constraintSection.trim());
2228
+ }
2229
+ if (constraintsByType.should_not && constraintsByType.should_not.length > 0) {
2230
+ let constraintSection = "## You SHOULD NOT:\n\n";
2231
+ for (const constraint of constraintsByType.should_not) {
2232
+ constraintSection += `- ${constraint}
2233
+ `;
2234
+ }
2235
+ constraintSections.push(constraintSection.trim());
2303
2236
  }
2304
- return importantWorkflowGuidelines;
2237
+ const finalReminder = getCodeAgentFinalReminder();
2238
+ return [...exampleSections, ...constraintSections, finalReminder].join(
2239
+ "\n\n"
2240
+ );
2305
2241
  }
2306
2242
  function formatExampleForInstructions(toolName, example) {
2307
- const input = typeof example.input === "undefined" ? "" : typeof example.input === "string" || typeof example.input === "number" ? example.input : JSON.stringify(example.input, null, 2);
2308
- const output = typeof example.output === "undefined" ? "" : typeof example.output === "string" || typeof example.output === "number" ? example.output : JSON.stringify(example.output, null, 2);
2243
+ const input = formatValueForExample(example.input);
2244
+ const output = formatValueForExample(example.output);
2309
2245
  if (output === "") {
2310
2246
  return `<example>
2311
2247
  <tool_call>
@@ -2322,8 +2258,40 @@ ${output}
2322
2258
  </tool_response>
2323
2259
  </example>`;
2324
2260
  }
2261
+ function formatValueForExample(value) {
2262
+ if (typeof value === "undefined") {
2263
+ return "";
2264
+ }
2265
+ if (typeof value === "string") {
2266
+ return `"${value}"`;
2267
+ }
2268
+ if (typeof value === "number") {
2269
+ return value.toString();
2270
+ }
2271
+ if (typeof value === "boolean") {
2272
+ return value ? "true" : "false";
2273
+ }
2274
+ return JSON.stringify(value, null, 2);
2275
+ }
2276
+ function getCodeAgentConstraints(config) {
2277
+ const { maxSteps, allowSubmit } = config;
2278
+ return {
2279
+ must: [
2280
+ "Always issue tool calls to complete your task",
2281
+ ...allowSubmit ? [
2282
+ `Call the \`${SubmitToolName}\` tool once you think you have completed your task, to submit your results`
2283
+ ] : [],
2284
+ `Complete your task within ${maxSteps} steps`
2285
+ ],
2286
+ must_not: ["Engage with the user directly"]
2287
+ };
2288
+ }
2289
+ function getCodeAgentFinalReminder() {
2290
+ 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.";
2291
+ }
2325
2292
 
2326
2293
  // src/tool-creators.ts
2294
+ var import_environment_utils19 = require("@ai-code-agents/environment-utils");
2327
2295
  var availableEnvironmentTools = {
2328
2296
  [ReadFileToolName]: ReadFileTool,
2329
2297
  [WriteFileToolName]: WriteFileTool,
@@ -2334,12 +2302,14 @@ var availableEnvironmentTools = {
2334
2302
  [ReadManyFilesToolName]: ReadManyFilesTool,
2335
2303
  [GetProjectFileStructureToolName]: GetProjectFileStructureTool,
2336
2304
  [GlobToolName]: GlobTool,
2305
+ [GrepToolName]: GrepTool,
2337
2306
  [ListDirectoryToolName]: ListDirectoryTool,
2338
2307
  [RunCommandToolName]: RunCommandTool
2339
2308
  };
2340
2309
  var cliOnlyTools = [
2341
2310
  GetProjectFileStructureToolName,
2342
2311
  GlobToolName,
2312
+ GrepToolName,
2343
2313
  ListDirectoryToolName,
2344
2314
  RunCommandToolName
2345
2315
  ];
@@ -2348,6 +2318,7 @@ var readonlyTools = [
2348
2318
  ReadManyFilesToolName,
2349
2319
  GetProjectFileStructureToolName,
2350
2320
  GlobToolName,
2321
+ GrepToolName,
2351
2322
  ListDirectoryToolName
2352
2323
  ];
2353
2324
  var dangerousTools = [
@@ -2375,7 +2346,7 @@ function createEnvironmentTool(toolName, environment, config) {
2375
2346
  }
2376
2347
  function createToolsForEnvironment(environment, toolsDefinition = "all") {
2377
2348
  const sanitizedToolsDefinition = sanitizeToolsDefinition(toolsDefinition);
2378
- const isCliEnvironment = "runCommand" in environment;
2349
+ const isCliEnvironment = (0, import_environment_utils19.isCommandLine)(environment);
2379
2350
  const tools = {};
2380
2351
  for (const toolDefinition of sanitizedToolsDefinition) {
2381
2352
  const actualToolName = toolDefinition.toolName;
@@ -2396,7 +2367,7 @@ function createToolsForEnvironment(environment, toolsDefinition = "all") {
2396
2367
  }
2397
2368
  tools[toolNameToUse] = createEnvironmentTool(
2398
2369
  actualToolName,
2399
- isCliEnvironment ? environment : environment,
2370
+ environment,
2400
2371
  toolConfig
2401
2372
  );
2402
2373
  }
@@ -2452,6 +2423,54 @@ function sanitizeToolsDefinition(toolsDefinition) {
2452
2423
  });
2453
2424
  }
2454
2425
 
2426
+ // src/util/truncate.ts
2427
+ function truncateString(str) {
2428
+ const lines = str.split("\n");
2429
+ while (lines.length > 0 && lines[lines.length - 1] === "") {
2430
+ lines.pop();
2431
+ }
2432
+ const isMultiline = lines.length > 1;
2433
+ if (isMultiline) {
2434
+ if (lines.length > 5) {
2435
+ const truncatedLines = lines.slice(0, 5).join("\n");
2436
+ const moreLines = lines.length - 5;
2437
+ const lineSuffix = moreLines === 1 ? "line" : "lines";
2438
+ return `${truncatedLines}
2439
+ ...(${moreLines} more ${lineSuffix})`;
2440
+ }
2441
+ return lines.join("\n");
2442
+ }
2443
+ const singleLine = lines[0] || "";
2444
+ if (singleLine.length > 300) {
2445
+ const moreChars = singleLine.length - 300;
2446
+ return `${singleLine.slice(0, 300)}...(${moreChars} more characters)`;
2447
+ }
2448
+ return singleLine;
2449
+ }
2450
+ function truncateObject(obj) {
2451
+ const result = {};
2452
+ for (const [key, value] of Object.entries(obj)) {
2453
+ if (typeof value === "string") {
2454
+ result[key] = truncateString(value);
2455
+ } else if (Array.isArray(value)) {
2456
+ result[key] = value.map((item) => {
2457
+ if (typeof item === "string") {
2458
+ return truncateString(item);
2459
+ }
2460
+ if (typeof item === "object" && item !== null) {
2461
+ return truncateObject(item);
2462
+ }
2463
+ return item;
2464
+ });
2465
+ } else if (typeof value === "object" && value !== null) {
2466
+ result[key] = truncateObject(value);
2467
+ } else {
2468
+ result[key] = value;
2469
+ }
2470
+ }
2471
+ return result;
2472
+ }
2473
+
2455
2474
  // src/util/get-step-log.ts
2456
2475
  function getStepLog(stepResult) {
2457
2476
  const { content } = stepResult;
@@ -2465,13 +2484,17 @@ function getStepLog(stepResult) {
2465
2484
  }
2466
2485
  logEntry += ": ";
2467
2486
  if (part.type === "tool-call" && "input" in part) {
2468
- logEntry += typeof part.input === "string" ? part.input : JSON.stringify(part.input);
2487
+ logEntry += typeof part.input === "string" ? truncateString(part.input) : part.input === null || part.input === void 0 ? String(part.input) : JSON.stringify(
2488
+ truncateObject(part.input)
2489
+ );
2469
2490
  } else if (part.type === "tool-result" && "output" in part) {
2470
- logEntry += typeof part.output === "string" ? part.output : JSON.stringify(part.output);
2491
+ logEntry += typeof part.output === "string" ? truncateString(part.output) : part.output === null || part.output === void 0 ? String(part.output) : JSON.stringify(
2492
+ truncateObject(part.output)
2493
+ );
2471
2494
  } else if (part.type === "tool-error" && "error" in part) {
2472
2495
  logEntry += typeof part.error === "object" && part.error !== null && "message" in part.error ? part.error.message : String(part.error);
2473
2496
  } else if (part.type === "text" && "text" in part) {
2474
- logEntry += part.text;
2497
+ logEntry += truncateString(part.text);
2475
2498
  }
2476
2499
  logEntry += "\n";
2477
2500
  });
@@ -2480,6 +2503,9 @@ function getStepLog(stepResult) {
2480
2503
 
2481
2504
  // src/agent-creators.ts
2482
2505
  function createCodeAgent(agentConfig) {
2506
+ return new import_ai.ToolLoopAgent(createCodeAgentSettings(agentConfig));
2507
+ }
2508
+ function createCodeAgentSettings(agentConfig) {
2483
2509
  const {
2484
2510
  maxSteps,
2485
2511
  allowSubmit,
@@ -2488,46 +2514,29 @@ function createCodeAgent(agentConfig) {
2488
2514
  tools: originalTools,
2489
2515
  stopWhen: originalStopWhen,
2490
2516
  prepareStep: originalPrepareStep,
2491
- system: originalSystemInstruction,
2517
+ instructions: originalSystemInstruction,
2492
2518
  ...remainingConfig
2493
2519
  } = agentConfig;
2494
2520
  let agentSettings;
2495
- let environmentTools;
2521
+ let tools;
2496
2522
  if ("environments" in remainingConfig) {
2497
2523
  const { environments, environmentToolsDefinition, ...agentSettingsInput } = remainingConfig;
2498
2524
  agentSettings = { ...agentSettingsInput };
2499
- environmentTools = {};
2500
- for (const [environmentName, environment] of Object.entries(environments)) {
2501
- if (!(environmentName in environmentToolsDefinition)) {
2502
- throw new Error(
2503
- `No tools definition provided for environment "${environmentName}". Please provide a tools definition for each environment.`
2504
- );
2505
- }
2506
- const environmentTools2 = createToolsForNamedEnvironment(
2507
- environmentName,
2508
- environment,
2509
- environmentToolsDefinition[environmentName]
2510
- );
2511
- for (const [toolName, tool] of Object.entries(environmentTools2)) {
2512
- if (toolName in environmentTools2) {
2513
- throw new Error(
2514
- `Tool name conflict: The tool name "${toolName}" from environment "${environmentName}" is already used by another environment's tools.`
2515
- );
2516
- }
2517
- environmentTools2[toolName] = tool;
2518
- }
2519
- }
2525
+ tools = createCodeAgentTools(
2526
+ { environments, environmentToolsDefinition },
2527
+ originalTools
2528
+ );
2520
2529
  } else if ("environment" in remainingConfig) {
2521
2530
  const { environment, environmentToolsDefinition, ...agentSettingsInput } = remainingConfig;
2522
2531
  agentSettings = { ...agentSettingsInput };
2523
- environmentTools = createToolsForEnvironment(
2524
- environment,
2525
- environmentToolsDefinition
2532
+ tools = createCodeAgentTools(
2533
+ { environment, environmentToolsDefinition },
2534
+ originalTools
2526
2535
  );
2527
2536
  } else {
2528
2537
  agentSettings = { ...remainingConfig };
2538
+ tools = originalTools || {};
2529
2539
  }
2530
- const tools = environmentTools && originalTools ? mergeTools(environmentTools, originalTools) : originalTools || environmentTools || {};
2531
2540
  if (allowSubmit) {
2532
2541
  if (SubmitToolName in tools) {
2533
2542
  throw new Error(
@@ -2555,16 +2564,54 @@ ${stepLog}`, stepCount - 1);
2555
2564
  } : originalPrepareStep;
2556
2565
  const stopWhenCondition = allowSubmit ? [(0, import_ai.stepCountIs)(maxSteps), (0, import_ai.hasToolCall)(SubmitToolName)] : (0, import_ai.stepCountIs)(maxSteps);
2557
2566
  const stopWhen = originalStopWhen ? mergeStopWhen(originalStopWhen, stopWhenCondition) : stopWhenCondition;
2558
- const system = !omitAdditionalInstructions ? mergeSystemInstructions(
2567
+ const instructions = !omitAdditionalInstructions ? mergeSystemInstructions(
2559
2568
  originalSystemInstruction,
2560
2569
  getAdditionalInstructions({ maxSteps, allowSubmit, tools })
2561
2570
  ) : originalSystemInstruction;
2562
- return new import_ai.Experimental_Agent({
2571
+ return {
2563
2572
  ...agentSettings,
2564
- system,
2573
+ instructions,
2565
2574
  prepareStep,
2566
2575
  stopWhen
2567
- });
2576
+ };
2577
+ }
2578
+ function createCodeAgentTools(agentToolsConfig, originalTools) {
2579
+ if ("environments" in agentToolsConfig) {
2580
+ const { environments, environmentToolsDefinition } = agentToolsConfig;
2581
+ const environmentTools = {};
2582
+ for (const [environmentName, environment] of Object.entries(environments)) {
2583
+ if (!(environmentName in environmentToolsDefinition)) {
2584
+ throw new Error(
2585
+ `No tools definition provided for environment "${environmentName}". Please provide a tools definition for each environment.`
2586
+ );
2587
+ }
2588
+ const envTools = createToolsForNamedEnvironment(
2589
+ environmentName,
2590
+ environment,
2591
+ environmentToolsDefinition[environmentName]
2592
+ );
2593
+ for (const [toolName, tool] of Object.entries(envTools)) {
2594
+ if (toolName in environmentTools) {
2595
+ throw new Error(
2596
+ `Tool name conflict: The tool name "${toolName}" from environment "${environmentName}" is already used by another environment's tools.`
2597
+ );
2598
+ }
2599
+ environmentTools[toolName] = tool;
2600
+ }
2601
+ }
2602
+ return originalTools ? mergeTools(environmentTools, originalTools) : environmentTools;
2603
+ }
2604
+ if ("environment" in agentToolsConfig) {
2605
+ const { environment, environmentToolsDefinition } = agentToolsConfig;
2606
+ const environmentTools = createToolsForEnvironment(
2607
+ environment,
2608
+ environmentToolsDefinition
2609
+ );
2610
+ return originalTools ? mergeTools(environmentTools, originalTools) : environmentTools;
2611
+ }
2612
+ throw new Error(
2613
+ 'No environments provided in agent tools configuration. Please provide either "environment" or "environments".'
2614
+ );
2568
2615
  }
2569
2616
  function mergeTools(baseTools, additionalTools) {
2570
2617
  const tools = { ...baseTools };
@@ -2590,9 +2637,26 @@ function mergeStopWhen(baseStopWhen, additionalStopWhen) {
2590
2637
  }
2591
2638
  return [baseStopWhen, additionalStopWhen];
2592
2639
  }
2593
- function mergeSystemInstructions(baseSystem, additionalInstructions) {
2594
- if (baseSystem) {
2595
- return `${baseSystem.trimEnd()}
2640
+ function mergeSystemInstructions(baseInstructions, additionalInstructions) {
2641
+ if (baseInstructions) {
2642
+ if (Array.isArray(baseInstructions)) {
2643
+ return [
2644
+ ...baseInstructions,
2645
+ {
2646
+ role: "system",
2647
+ content: additionalInstructions
2648
+ }
2649
+ ];
2650
+ }
2651
+ if (typeof baseInstructions === "object") {
2652
+ return {
2653
+ ...baseInstructions,
2654
+ content: `${baseInstructions.content.trimEnd()}
2655
+
2656
+ ${additionalInstructions}`
2657
+ };
2658
+ }
2659
+ return `${baseInstructions.trimEnd()}
2596
2660
 
2597
2661
  ${additionalInstructions}`;
2598
2662
  }
@@ -2618,12 +2682,10 @@ function createEnvironment(environmentName, config) {
2618
2682
  }
2619
2683
  // Annotate the CommonJS export names for ESM import in node:
2620
2684
  0 && (module.exports = {
2621
- CopyFileResult,
2622
2685
  CopyFileTool,
2623
2686
  CopyFileToolInput,
2624
2687
  CopyFileToolName,
2625
2688
  CopyFileToolOutput,
2626
- DeleteFileResult,
2627
2689
  DeleteFileTool,
2628
2690
  DeleteFileToolInput,
2629
2691
  DeleteFileToolName,
@@ -2645,20 +2707,22 @@ function createEnvironment(environmentName, config) {
2645
2707
  GlobToolInput,
2646
2708
  GlobToolName,
2647
2709
  GlobToolOutput,
2710
+ GrepTool,
2711
+ GrepToolInput,
2712
+ GrepToolName,
2713
+ GrepToolOutput,
2648
2714
  ListDirectoryTool,
2649
2715
  ListDirectoryToolInput,
2650
2716
  ListDirectoryToolName,
2651
2717
  ListDirectoryToolOutput,
2652
2718
  MockFilesystemEnvironment,
2653
2719
  MockFilesystemEnvironmentName,
2654
- MoveFileResult,
2655
2720
  MoveFileTool,
2656
2721
  MoveFileToolInput,
2657
2722
  MoveFileToolName,
2658
2723
  MoveFileToolOutput,
2659
2724
  NodeFilesystemEnvironment,
2660
2725
  NodeFilesystemEnvironmentName,
2661
- ReadFileResult,
2662
2726
  ReadFileTool,
2663
2727
  ReadFileToolInput,
2664
2728
  ReadFileToolName,
@@ -2667,19 +2731,23 @@ function createEnvironment(environmentName, config) {
2667
2731
  ReadManyFilesToolInput,
2668
2732
  ReadManyFilesToolName,
2669
2733
  ReadManyFilesToolOutput,
2670
- RunCommandResult,
2671
2734
  RunCommandTool,
2672
2735
  RunCommandToolInput,
2673
2736
  RunCommandToolName,
2674
2737
  RunCommandToolOutput,
2738
+ SubmitTool,
2739
+ SubmitToolInput,
2740
+ SubmitToolName,
2741
+ SubmitToolOutput,
2675
2742
  UnsafeLocalEnvironment,
2676
2743
  UnsafeLocalEnvironmentName,
2677
- WriteFileResult,
2678
2744
  WriteFileTool,
2679
2745
  WriteFileToolInput,
2680
2746
  WriteFileToolName,
2681
2747
  WriteFileToolOutput,
2682
2748
  createCodeAgent,
2749
+ createCodeAgentSettings,
2750
+ createCodeAgentTools,
2683
2751
  createEnvironment,
2684
2752
  createEnvironmentTool,
2685
2753
  createToolsForEnvironment,