ai-code-agents 0.1.0 → 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,7 +79,6 @@ __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,
@@ -90,12 +89,13 @@ __export(index_exports, {
90
89
  SubmitToolOutput: () => SubmitToolOutput,
91
90
  UnsafeLocalEnvironment: () => UnsafeLocalEnvironment,
92
91
  UnsafeLocalEnvironmentName: () => UnsafeLocalEnvironmentName,
93
- WriteFileResult: () => WriteFileResult,
94
92
  WriteFileTool: () => WriteFileTool,
95
93
  WriteFileToolInput: () => WriteFileToolInput,
96
94
  WriteFileToolName: () => WriteFileToolName,
97
95
  WriteFileToolOutput: () => WriteFileToolOutput,
98
96
  createCodeAgent: () => createCodeAgent,
97
+ createCodeAgentSettings: () => createCodeAgentSettings,
98
+ createCodeAgentTools: () => createCodeAgentTools,
99
99
  createEnvironment: () => createEnvironment,
100
100
  createEnvironmentTool: () => createEnvironmentTool,
101
101
  createToolsForEnvironment: () => createToolsForEnvironment,
@@ -105,14 +105,7 @@ module.exports = __toCommonJS(index_exports);
105
105
 
106
106
  // src/environments/docker-environment.ts
107
107
  var import_node_child_process = require("child_process");
108
-
109
- // src/util/escape-command-arg.ts
110
- function escapeCommandArg(arg) {
111
- if ("" === arg) {
112
- return "''";
113
- }
114
- return `'${arg.replace(/'/g, "'\\''")}'`;
115
- }
108
+ var import_environment_utils = require("@ai-code-agents/environment-utils");
116
109
 
117
110
  // src/util/escape-command.ts
118
111
  function escapeCommand(command) {
@@ -120,281 +113,9 @@ function escapeCommand(command) {
120
113
  return `"${escaped}"`;
121
114
  }
122
115
 
123
- // src/util/validate-relative-path.ts
124
- var path = __toESM(require("path"), 1);
125
- function validateRelativePath(filePath) {
126
- if (path.isAbsolute(filePath)) {
127
- throw new Error("Absolute paths are not allowed.");
128
- }
129
- if (filePath.startsWith("~")) {
130
- throw new Error('Paths starting with "~" are not allowed.');
131
- }
132
- if (filePath.includes("\0")) {
133
- throw new Error("Paths must not contain null bytes.");
134
- }
135
- const normalizedPath = path.normalize(filePath);
136
- if (normalizedPath.startsWith("..")) {
137
- throw new Error("Path traversal is not allowed.");
138
- }
139
- }
140
-
141
- // src/environments/filesystem-environment-base.ts
142
- var FilesystemEnvironmentBase = class {
143
- _envConfig;
144
- /**
145
- * Constructs a new environment instance.
146
- *
147
- * @param config - Environment configuration.
148
- */
149
- constructor(config) {
150
- this._envConfig = config;
151
- }
152
- /**
153
- * Reads the content of a file at the specified path.
154
- *
155
- * @param path - The path to the file to read, relative to the project directory.
156
- * @returns A promise that resolves to a ReadFileResult.
157
- */
158
- async readFile(path5) {
159
- validateRelativePath(path5);
160
- if (!await this.fileExists(path5)) {
161
- throw new Error(`File not found: ${path5}`);
162
- }
163
- const content = await this.readFileContent(path5);
164
- return {
165
- path: path5,
166
- content
167
- };
168
- }
169
- /**
170
- * Writes content to a file at the specified path.
171
- *
172
- * If a file is already present at the path, it will be overwritten.
173
- *
174
- * @param path - The path to the file to write, relative to the project directory.
175
- * @param content - The content to write to the file.
176
- * @returns A promise that resolves to a WriteFileResult.
177
- */
178
- async writeFile(path5, content) {
179
- validateRelativePath(path5);
180
- await this.writeFileContent(path5, content);
181
- return {
182
- path: path5,
183
- message: "File written successfully."
184
- };
185
- }
186
- /**
187
- * Deletes a file at the specified path.
188
- *
189
- * @param path - The path to the file to delete, relative to the project directory.
190
- * @returns A promise that resolves to a DeleteFileResult.
191
- */
192
- async deleteFile(path5) {
193
- validateRelativePath(path5);
194
- if (!await this.fileExists(path5)) {
195
- return {
196
- path: path5,
197
- message: "File was already deleted."
198
- };
199
- }
200
- await this.deleteFileContent(path5);
201
- return {
202
- path: path5,
203
- message: "File deleted successfully."
204
- };
205
- }
206
- /**
207
- * Moves a file from a source path to a destination path.
208
- *
209
- * If a file is already present at the destination path, it will be overwritten.
210
- *
211
- * @param sourcePath - The path to the file to move.
212
- * @param destinationPath - The path to move the file to.
213
- * @returns A promise that resolves to a MoveFileResult.
214
- */
215
- async moveFile(sourcePath, destinationPath) {
216
- validateRelativePath(sourcePath);
217
- validateRelativePath(destinationPath);
218
- if (!await this.fileExists(sourcePath)) {
219
- throw new Error(`File not found: ${sourcePath}`);
220
- }
221
- await this.moveFileContent(sourcePath, destinationPath);
222
- return {
223
- sourcePath,
224
- destinationPath,
225
- message: "File moved successfully."
226
- };
227
- }
228
- /**
229
- * Copies a file from a source path to a destination path.
230
- *
231
- * If a file is already present at the destination path, it will be overwritten.
232
- *
233
- * @param sourcePath - The path to the file to copy.
234
- * @param destinationPath - The path to copy the file to.
235
- * @returns A promise that resolves to a CopyFileResult.
236
- */
237
- async copyFile(sourcePath, destinationPath) {
238
- validateRelativePath(sourcePath);
239
- validateRelativePath(destinationPath);
240
- if (!await this.fileExists(sourcePath)) {
241
- throw new Error(`File not found: ${sourcePath}`);
242
- }
243
- await this.copyFileContent(sourcePath, destinationPath);
244
- return {
245
- sourcePath,
246
- destinationPath,
247
- message: "File copied successfully."
248
- };
249
- }
250
- /**
251
- * Moves the content of a file from a source path to a destination path, relative to the project directory.
252
- *
253
- * When this method is called, it is guaranteed that the source file exists.
254
- * This method unconditionally moves the content, even if a file already exists at the destination path.
255
- *
256
- * @param relativeSourcePath - The path to the file to move, relative to the project directory.
257
- * @param relativeDestinationPath - The path to move the file to, relative to the project directory.
258
- */
259
- async moveFileContent(relativeSourcePath, relativeDestinationPath) {
260
- const content = await this.readFileContent(relativeSourcePath);
261
- this.writeFileContent(relativeDestinationPath, content);
262
- this.deleteFileContent(relativeSourcePath);
263
- }
264
- /**
265
- * Copies the content of a file from a source path to a destination path, relative to the project directory.
266
- *
267
- * When this method is called, it is guaranteed that the source file exists.
268
- * This method unconditionally copies the content, even if a file already exists at the destination path.
269
- *
270
- * @param relativeSourcePath - The path to the file to copy, relative to the project directory.
271
- * @param relativeDestinationPath - The path to copy the file to, relative to the project directory.
272
- */
273
- async copyFileContent(relativeSourcePath, relativeDestinationPath) {
274
- const content = await this.readFileContent(relativeSourcePath);
275
- this.writeFileContent(relativeDestinationPath, content);
276
- }
277
- };
278
-
279
- // src/environments/command-line-environment-base.ts
280
- var CommandLineEnvironmentBase = class extends FilesystemEnvironmentBase {
281
- /**
282
- * Runs a CLI command in environment.
283
- *
284
- * @param command - The command to run.
285
- * @returns A promise that resolves to a RunCommandResult.
286
- */
287
- async runCommand(command) {
288
- const [exitCode, stdout, stderr] = await this.executeCommand(command);
289
- return {
290
- command,
291
- exitCode,
292
- stdout,
293
- stderr
294
- };
295
- }
296
- };
297
-
298
- // src/environments/unix-environment-base.ts
299
- var UnixEnvironmentBase = class extends CommandLineEnvironmentBase {
300
- /**
301
- * Checks whether a file exists at the specified path relative to the project directory.
302
- *
303
- * @param relativePath - The path to the file to check, relative to the project directory.
304
- * @returns True if the file exists, false otherwise.
305
- */
306
- async fileExists(relativePath) {
307
- const command = `if [ -e ${escapeCommandArg(relativePath)} ]; then echo "yes"; else echo "no"; fi`;
308
- const { exitCode, stdout } = await this.runCommand(command);
309
- return exitCode === 0 && stdout.trim() === "yes";
310
- }
311
- /**
312
- * Gets the content of a file at the specified path, relative to the project directory.
313
- *
314
- * When this method is called, it is guaranteed that the file exists.
315
- *
316
- * @param relativePath - The path to the file to read, relative to the project directory.
317
- * @returns The content of the file.
318
- */
319
- async readFileContent(relativePath) {
320
- const command = `cat ${escapeCommandArg(relativePath)}`;
321
- const { exitCode, stdout } = await this.runCommand(command);
322
- return exitCode === 0 ? stdout : "";
323
- }
324
- /**
325
- * Writes content to a file at the specified path, relative to the project directory.
326
- *
327
- * This method unconditionally writes the content, even if a file already exists at the path, or if the file is new.
328
- *
329
- * @param relativePath - The path to the file to write, relative to the project directory.
330
- * @param content - The content to write to the file.
331
- */
332
- async writeFileContent(relativePath, content) {
333
- const command = `sh -c "echo ${escapeCommandArg(
334
- content
335
- )} > ${escapeCommandArg(relativePath)}"`;
336
- const { exitCode, stderr } = await this.runCommand(command);
337
- if (exitCode !== 0) {
338
- throw new Error(`Failed to write file: ${stderr || "Unknown error"}`);
339
- }
340
- }
341
- /**
342
- * Deletes a file at the specified path, relative to the project directory.
343
- *
344
- * When this method is called, it is guaranteed that the file exists.
345
- *
346
- * @param relativePath - The path to the file to delete, relative to the project directory.
347
- */
348
- async deleteFileContent(relativePath) {
349
- const command = `rm ${escapeCommandArg(relativePath)}`;
350
- const { exitCode, stderr } = await this.runCommand(command);
351
- if (exitCode !== 0) {
352
- throw new Error(`Failed to delete file: ${stderr || "Unknown error"}`);
353
- }
354
- }
355
- /**
356
- * Moves the content of a file from a source path to a destination path, relative to the project directory.
357
- *
358
- * When this method is called, it is guaranteed that the source file exists.
359
- * This method unconditionally moves the content, even if a file already exists at the destination path.
360
- *
361
- * @param relativeSourcePath - The path to the file to move, relative to the project directory.
362
- * @param relativeDestinationPath - The path to move the file to, relative to the project directory.
363
- */
364
- async moveFileContent(relativeSourcePath, relativeDestinationPath) {
365
- const command = `mv ${escapeCommandArg(relativeSourcePath)} ${escapeCommandArg(
366
- relativeDestinationPath
367
- )}`;
368
- const { exitCode, stderr } = await this.runCommand(command);
369
- if (exitCode !== 0) {
370
- throw new Error(`Failed to move file: ${stderr || "Unknown error"}`);
371
- }
372
- }
373
- /**
374
- * Copies the content of a file from a source path to a destination path, relative to the project directory.
375
- *
376
- * When this method is called, it is guaranteed that the source file exists.
377
- * This method unconditionally copies the content, even if a file already exists at the destination path.
378
- *
379
- * @param relativeSourcePath - The path to the file to copy, relative to the project directory.
380
- * @param relativeDestinationPath - The path to copy the file to, relative to the project directory.
381
- */
382
- async copyFileContent(relativeSourcePath, relativeDestinationPath) {
383
- const command = `cp ${escapeCommandArg(relativeSourcePath)} ${escapeCommandArg(
384
- relativeDestinationPath
385
- )}`;
386
- const result = await this.runCommand(command);
387
- if (result.exitCode !== 0) {
388
- throw new Error(
389
- `Failed to copy file: ${result.stderr || "Unknown error"}`
390
- );
391
- }
392
- }
393
- };
394
-
395
116
  // src/environments/docker-environment.ts
396
117
  var DockerEnvironmentName = "docker";
397
- var DockerEnvironment = class extends UnixEnvironmentBase {
118
+ var DockerEnvironment = class extends import_environment_utils.UnixEnvironmentBase {
398
119
  _commandPrefix;
399
120
  /**
400
121
  * Constructs a new environment instance.
@@ -404,7 +125,7 @@ var DockerEnvironment = class extends UnixEnvironmentBase {
404
125
  constructor(config) {
405
126
  super(config);
406
127
  const { directoryPath } = this._envConfig;
407
- this._commandPrefix = directoryPath ? `cd ${escapeCommandArg(directoryPath)} && ` : "";
128
+ this._commandPrefix = directoryPath ? `cd ${(0, import_environment_utils.escapeCommandArg)(directoryPath)} && ` : "";
408
129
  }
409
130
  /**
410
131
  * Gets the environment name.
@@ -435,8 +156,9 @@ var DockerEnvironment = class extends UnixEnvironmentBase {
435
156
 
436
157
  // src/environments/mock-filesystem-environment.ts
437
158
  var import_node_path = __toESM(require("path"), 1);
159
+ var import_environment_utils2 = require("@ai-code-agents/environment-utils");
438
160
  var MockFilesystemEnvironmentName = "mock-filesystem";
439
- var MockFilesystemEnvironment = class extends FilesystemEnvironmentBase {
161
+ var MockFilesystemEnvironment = class extends import_environment_utils2.FilesystemEnvironmentBase {
440
162
  files;
441
163
  _preparePath;
442
164
  /**
@@ -447,7 +169,7 @@ var MockFilesystemEnvironment = class extends FilesystemEnvironmentBase {
447
169
  constructor(config = {}) {
448
170
  super(config);
449
171
  const { initialFiles, directoryPath } = this._envConfig;
450
- this.files = initialFiles ?? /* @__PURE__ */ new Map();
172
+ this.files = initialFiles ? new Map(Object.entries(initialFiles)) : /* @__PURE__ */ new Map();
451
173
  this._preparePath = directoryPath ? (filePath) => import_node_path.default.join(directoryPath, filePath) : (filePath) => filePath;
452
174
  }
453
175
  /**
@@ -502,8 +224,9 @@ var MockFilesystemEnvironment = class extends FilesystemEnvironmentBase {
502
224
  // src/environments/node-filesystem-environment.ts
503
225
  var import_promises = __toESM(require("fs/promises"), 1);
504
226
  var import_node_path2 = __toESM(require("path"), 1);
227
+ var import_environment_utils3 = require("@ai-code-agents/environment-utils");
505
228
  var NodeFilesystemEnvironmentName = "node-filesystem";
506
- var NodeFilesystemEnvironment = class extends FilesystemEnvironmentBase {
229
+ var NodeFilesystemEnvironment = class extends import_environment_utils3.FilesystemEnvironmentBase {
507
230
  /**
508
231
  * Constructs a new NodeFilesystemEnvironment instance.
509
232
  *
@@ -597,8 +320,9 @@ var NodeFilesystemEnvironment = class extends FilesystemEnvironmentBase {
597
320
 
598
321
  // src/environments/unsafe-local-environment.ts
599
322
  var import_node_child_process2 = require("child_process");
323
+ var import_environment_utils4 = require("@ai-code-agents/environment-utils");
600
324
  var UnsafeLocalEnvironmentName = "unsafe-local";
601
- var UnsafeLocalEnvironment = class extends UnixEnvironmentBase {
325
+ var UnsafeLocalEnvironment = class extends import_environment_utils4.UnixEnvironmentBase {
602
326
  _commandPrefix;
603
327
  /**
604
328
  * Constructs a new environment instance.
@@ -614,7 +338,7 @@ var UnsafeLocalEnvironment = class extends UnixEnvironmentBase {
614
338
  throw new Error('The directory path must be absolute (start with "/")');
615
339
  }
616
340
  super(config);
617
- this._commandPrefix = `cd ${escapeCommandArg(directoryPath)} && `;
341
+ this._commandPrefix = `cd ${(0, import_environment_utils4.escapeCommandArg)(directoryPath)} && `;
618
342
  }
619
343
  /**
620
344
  * Gets the environment name.
@@ -642,173 +366,7 @@ var UnsafeLocalEnvironment = class extends UnixEnvironmentBase {
642
366
 
643
367
  // src/tools/copy-file-tool.ts
644
368
  var import_zod = require("zod");
645
-
646
- // src/types.ts
647
- var z = __toESM(require("zod"), 1);
648
- var ReadFileResult = z.object({
649
- path: z.string().meta({
650
- description: "The path to the file that was read."
651
- }),
652
- content: z.string().meta({
653
- description: "The content of the file that was read."
654
- })
655
- });
656
- var WriteFileResult = z.object({
657
- path: z.string().meta({
658
- description: "The path to the file that was written."
659
- }),
660
- message: z.string().meta({
661
- description: "A message indicating the result of the write operation."
662
- })
663
- });
664
- var DeleteFileResult = z.object({
665
- path: z.string().meta({
666
- description: "The path to the file that was deleted."
667
- }),
668
- message: z.string().meta({
669
- description: "A message indicating the result of the delete operation."
670
- })
671
- });
672
- var MoveFileResult = z.object({
673
- sourcePath: z.string().meta({
674
- description: "The original path of the file that was moved."
675
- }),
676
- destinationPath: z.string().meta({
677
- description: "The new path of the file that was moved to."
678
- }),
679
- message: z.string().meta({
680
- description: "A message indicating the result of the move operation."
681
- })
682
- });
683
- var CopyFileResult = z.object({
684
- sourcePath: z.string().meta({
685
- description: "The original path of the file that was copied."
686
- }),
687
- destinationPath: z.string().meta({
688
- description: "The new path of the file that was copied to."
689
- }),
690
- message: z.string().meta({
691
- description: "A message indicating the result of the copy operation."
692
- })
693
- });
694
- var RunCommandResult = z.object({
695
- command: z.string().meta({
696
- description: "The command that was executed."
697
- }),
698
- exitCode: z.number().meta({
699
- description: "The exit code of the command."
700
- }),
701
- stdout: z.string().meta({
702
- description: "The standard output of the command."
703
- }),
704
- stderr: z.string().meta({
705
- description: "The standard error output of the command."
706
- })
707
- });
708
-
709
- // src/tools/tool-base.ts
710
- var ToolBase = class {
711
- _toolConfig;
712
- _name;
713
- _description;
714
- _inputSchema;
715
- _outputSchema;
716
- _needsApproval;
717
- /**
718
- * Constructs a new tool instance.
719
- *
720
- * @param toolConfig - Optional tool config, can be used to override some defaults.
721
- */
722
- constructor(toolConfig) {
723
- const {
724
- name: defaultName,
725
- description: defaultDescription,
726
- inputSchema,
727
- outputSchema,
728
- needsApproval: defaultNeedsApproval
729
- } = this.getMetadata();
730
- this._name = toolConfig?.name || defaultName;
731
- this._description = toolConfig?.description || defaultDescription;
732
- this._inputSchema = inputSchema;
733
- this._outputSchema = outputSchema;
734
- this._needsApproval = toolConfig?.needsApproval !== void 0 ? toolConfig.needsApproval : defaultNeedsApproval;
735
- }
736
- /**
737
- * Gets the tool name.
738
- *
739
- * @returns The tool name.
740
- */
741
- get name() {
742
- return this._name;
743
- }
744
- /**
745
- * Gets the tool description.
746
- *
747
- * @returns The tool description.
748
- */
749
- get description() {
750
- return this._description;
751
- }
752
- /**
753
- * Gets the input schema for the tool.
754
- *
755
- * @returns The input schema.
756
- */
757
- get inputSchema() {
758
- return this._inputSchema;
759
- }
760
- /**
761
- * Gets the input schema for the tool.
762
- *
763
- * @returns The input schema.
764
- */
765
- get outputSchema() {
766
- return this._outputSchema;
767
- }
768
- /**
769
- * Gets whether the tool needs approval before use.
770
- *
771
- * @returns True if the tool needs approval, false otherwise.
772
- */
773
- get needsApproval() {
774
- return this._needsApproval;
775
- }
776
- };
777
-
778
- // src/tools/environment-tool-base.ts
779
- var EnvironmentToolBase = class extends ToolBase {
780
- _environment;
781
- /**
782
- * Constructs a new `EnvironmentToolBase` instance.
783
- *
784
- * @param environment - The execution environment to apply the tool in.
785
- * @param toolConfig - Optional tool config, can be used to override some defaults.
786
- */
787
- constructor(environment, toolConfig) {
788
- super(toolConfig);
789
- this._environment = environment;
790
- }
791
- /**
792
- * Gets the current execution environment for the tool.
793
- *
794
- * @returns The current execution environment.
795
- */
796
- get environment() {
797
- return this._environment;
798
- }
799
- /**
800
- * Executes the tool with the given input.
801
- *
802
- * @param input - The input for the tool.
803
- * @param _options - Options from the tool call.
804
- * @returns A promise that resolves to the tool execution result.
805
- */
806
- execute(input, _options) {
807
- return this.executeForEnvironment(this._environment, input);
808
- }
809
- };
810
-
811
- // src/tools/copy-file-tool.ts
369
+ var import_environment_utils5 = require("@ai-code-agents/environment-utils");
812
370
  var CopyFileToolName = "copy_file";
813
371
  var CopyFileToolInput = import_zod.z.object({
814
372
  sourcePath: import_zod.z.string().meta({
@@ -818,8 +376,8 @@ var CopyFileToolInput = import_zod.z.object({
818
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."
819
377
  })
820
378
  });
821
- var CopyFileToolOutput = CopyFileResult;
822
- var CopyFileTool = class extends EnvironmentToolBase {
379
+ var CopyFileToolOutput = import_environment_utils5.CopyFileResult;
380
+ var CopyFileTool = class extends import_environment_utils5.EnvironmentToolBase {
823
381
  /**
824
382
  * Returns the metadata for the tool.
825
383
  *
@@ -849,10 +407,11 @@ var CopyFileTool = class extends EnvironmentToolBase {
849
407
  /**
850
408
  * Converts the tool output to a format suitable for model consumption.
851
409
  *
852
- * @param output - The output from the tool execution.
410
+ * @param options - The tool result, including the output from the tool execution.
853
411
  * @returns The formatted tool result.
854
412
  */
855
- toModelOutput(output) {
413
+ toModelOutput(options) {
414
+ const { output } = options;
856
415
  return {
857
416
  type: "text",
858
417
  value: `File \`${output.sourcePath}\` copied successfully to \`${output.destinationPath}\`.`
@@ -878,14 +437,15 @@ var CopyFileTool = class extends EnvironmentToolBase {
878
437
 
879
438
  // src/tools/delete-file-tool.ts
880
439
  var import_zod2 = require("zod");
440
+ var import_environment_utils6 = require("@ai-code-agents/environment-utils");
881
441
  var DeleteFileToolName = "delete_file";
882
442
  var DeleteFileToolInput = import_zod2.z.object({
883
443
  path: import_zod2.z.string().meta({
884
444
  description: "The path to the file to delete, relative to the project directory."
885
445
  })
886
446
  });
887
- var DeleteFileToolOutput = DeleteFileResult;
888
- var DeleteFileTool = class extends EnvironmentToolBase {
447
+ var DeleteFileToolOutput = import_environment_utils6.DeleteFileResult;
448
+ var DeleteFileTool = class extends import_environment_utils6.EnvironmentToolBase {
889
449
  /**
890
450
  * Returns the metadata for the tool.
891
451
  *
@@ -915,10 +475,11 @@ var DeleteFileTool = class extends EnvironmentToolBase {
915
475
  /**
916
476
  * Converts the tool output to a format suitable for model consumption.
917
477
  *
918
- * @param output - The output from the tool execution.
478
+ * @param options - The tool result, including the output from the tool execution.
919
479
  * @returns The formatted tool result.
920
480
  */
921
- toModelOutput(output) {
481
+ toModelOutput(options) {
482
+ const { output } = options;
922
483
  return {
923
484
  type: "text",
924
485
  value: `File \`${output.path}\` deleted successfully.`
@@ -943,6 +504,7 @@ var DeleteFileTool = class extends EnvironmentToolBase {
943
504
 
944
505
  // src/tools/edit-file-tool.ts
945
506
  var import_zod3 = require("zod");
507
+ var import_environment_utils7 = require("@ai-code-agents/environment-utils");
946
508
  var EditFileToolName = "edit_file";
947
509
  var EditFileToolInput = import_zod3.z.object({
948
510
  path: import_zod3.z.string().meta({
@@ -975,10 +537,10 @@ var EditFileToolOutput = import_zod3.z.object({
975
537
  description: "A message indicating the result of the edit operation."
976
538
  })
977
539
  });
978
- function escapeRegExp(string2) {
979
- return string2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
540
+ function escapeRegExp(string) {
541
+ return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
980
542
  }
981
- var EditFileTool = class extends EnvironmentToolBase {
543
+ var EditFileTool = class extends import_environment_utils7.EnvironmentToolBase {
982
544
  /**
983
545
  * Returns the metadata for the tool.
984
546
  *
@@ -1033,10 +595,11 @@ var EditFileTool = class extends EnvironmentToolBase {
1033
595
  /**
1034
596
  * Converts the tool output to a format suitable for model consumption.
1035
597
  *
1036
- * @param output - The output from the tool execution.
598
+ * @param options - The tool result, including the output from the tool execution.
1037
599
  * @returns The formatted tool result.
1038
600
  */
1039
- toModelOutput(output) {
601
+ toModelOutput(options) {
602
+ const { output } = options;
1040
603
  return {
1041
604
  type: "text",
1042
605
  value: `Edited file \`${output.path}\` with ${output.replacements} replacement(s).`
@@ -1085,6 +648,7 @@ var EditFileTool = class extends EnvironmentToolBase {
1085
648
 
1086
649
  // src/tools/get-project-file-structure-tool.ts
1087
650
  var import_zod4 = require("zod");
651
+ var import_environment_utils9 = require("@ai-code-agents/environment-utils");
1088
652
 
1089
653
  // src/util/build-tree-from-files.ts
1090
654
  function renderTree(node, prefix = "") {
@@ -1121,6 +685,91 @@ function buildTreeFromFiles(files) {
1121
685
  return renderTree(tree).trim();
1122
686
  }
1123
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
+
1124
773
  // src/tools/get-project-file-structure-tool.ts
1125
774
  var GetProjectFileStructureToolName = "get_project_file_structure";
1126
775
  var GetProjectFileStructureToolInput = import_zod4.z.object({
@@ -1139,7 +788,7 @@ var GetProjectFileStructureToolOutput = import_zod4.z.object({
1139
788
  description: "Whether files ignored by Git were excluded."
1140
789
  })
1141
790
  });
1142
- var GetProjectFileStructureTool = class extends EnvironmentToolBase {
791
+ var GetProjectFileStructureTool = class extends import_environment_utils9.EnvironmentToolBase {
1143
792
  /**
1144
793
  * Returns the metadata for the tool.
1145
794
  *
@@ -1165,21 +814,16 @@ var GetProjectFileStructureTool = class extends EnvironmentToolBase {
1165
814
  */
1166
815
  async executeForEnvironment(env, input) {
1167
816
  const { path: path5 = ".", excludeGitIgnored = true } = input;
1168
- const escapedPath = escapeCommandArg(path5);
817
+ const escapedPath = (0, import_environment_utils9.escapeCommandArg)(path5);
1169
818
  let command = `find ${escapedPath} -type f`;
1170
819
  if (excludeGitIgnored) {
1171
- let gitIgnoredPaths = [];
1172
- try {
1173
- const { content: gitignoreContent } = await env.readFile(".gitignore");
1174
- gitIgnoredPaths = gitignoreContent.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
1175
- } catch (_error) {
1176
- }
820
+ const gitIgnoredPaths = await getGitIgnoredPaths(env);
1177
821
  for (const gitIgnoredPath of gitIgnoredPaths) {
1178
822
  if (!gitIgnoredPath.endsWith("/")) {
1179
- const escapedPath2 = escapeCommandArg(`*/${gitIgnoredPath}/*`);
1180
- 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}`;
1181
825
  } else {
1182
- const escapedPath2 = escapeCommandArg(`*/${gitIgnoredPath}*`);
826
+ const escapedPath2 = (0, import_environment_utils9.escapeCommandArg)(`*/${gitIgnoredPath}*`);
1183
827
  command += ` -not -path ${escapedPath2}`;
1184
828
  }
1185
829
  }
@@ -1201,10 +845,11 @@ var GetProjectFileStructureTool = class extends EnvironmentToolBase {
1201
845
  /**
1202
846
  * Converts the tool output to a format suitable for model consumption.
1203
847
  *
1204
- * @param output - The output from the tool execution.
848
+ * @param options - The tool result, including the output from the tool execution.
1205
849
  * @returns The formatted tool result.
1206
850
  */
1207
- toModelOutput(output) {
851
+ toModelOutput(options) {
852
+ const { output } = options;
1208
853
  const tree = buildTreeFromFiles(output.files);
1209
854
  if (!tree) {
1210
855
  return {
@@ -1243,6 +888,7 @@ var GetProjectFileStructureTool = class extends EnvironmentToolBase {
1243
888
 
1244
889
  // src/tools/glob-tool.ts
1245
890
  var import_zod5 = require("zod");
891
+ var import_environment_utils10 = require("@ai-code-agents/environment-utils");
1246
892
 
1247
893
  // src/util/glob-to-reg-exp.ts
1248
894
  function globToRegExp(glob) {
@@ -1315,7 +961,7 @@ var GlobToolOutput = import_zod5.z.object({
1315
961
  description: "The list of file paths that matched the glob search, relative to the project directory."
1316
962
  })
1317
963
  });
1318
- var GlobTool = class extends EnvironmentToolBase {
964
+ var GlobTool = class extends import_environment_utils10.EnvironmentToolBase {
1319
965
  /**
1320
966
  * Returns the metadata for the tool.
1321
967
  *
@@ -1347,24 +993,19 @@ var GlobTool = class extends EnvironmentToolBase {
1347
993
  );
1348
994
  }
1349
995
  if (searchPath) {
1350
- validateRelativePath(searchPath);
996
+ (0, import_environment_utils10.validateRelativePath)(searchPath);
1351
997
  }
1352
998
  const untrailingslashedSearchPath = searchPath === "" ? "." : searchPath.replace(/\/+$/, "");
1353
- const escapedSearchPath = escapeCommandArg(untrailingslashedSearchPath);
999
+ const escapedSearchPath = (0, import_environment_utils10.escapeCommandArg)(untrailingslashedSearchPath);
1354
1000
  let command = `find ${escapedSearchPath} -type f`;
1355
1001
  if (excludeGitIgnored) {
1356
- let gitIgnoredPaths = [];
1357
- try {
1358
- const { content: gitignoreContent } = await env.readFile(".gitignore");
1359
- gitIgnoredPaths = gitignoreContent.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
1360
- } catch (_error) {
1361
- }
1002
+ const gitIgnoredPaths = await getGitIgnoredPaths(env);
1362
1003
  for (const gitIgnoredPath of gitIgnoredPaths) {
1363
1004
  if (!gitIgnoredPath.endsWith("/")) {
1364
- const escapedPath = escapeCommandArg(`*/${gitIgnoredPath}/*`);
1365
- 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}`;
1366
1007
  } else {
1367
- const escapedPath = escapeCommandArg(`*/${gitIgnoredPath}*`);
1008
+ const escapedPath = (0, import_environment_utils10.escapeCommandArg)(`*/${gitIgnoredPath}*`);
1368
1009
  command += ` -not -path ${escapedPath}`;
1369
1010
  }
1370
1011
  }
@@ -1400,10 +1041,11 @@ var GlobTool = class extends EnvironmentToolBase {
1400
1041
  /**
1401
1042
  * Converts the tool output to a format suitable for model consumption.
1402
1043
  *
1403
- * @param output - The output from the tool execution.
1044
+ * @param options - The tool result, including the output from the tool execution.
1404
1045
  * @returns The formatted tool result.
1405
1046
  */
1406
- toModelOutput(output) {
1047
+ toModelOutput(options) {
1048
+ const { output } = options;
1407
1049
  if (output.matchingPaths.length === 0) {
1408
1050
  return {
1409
1051
  type: "text",
@@ -1452,26 +1094,287 @@ ${bulletPoints}
1452
1094
  }
1453
1095
  };
1454
1096
 
1455
- // src/tools/list-directory-tool.ts
1097
+ // src/tools/grep-tool.ts
1456
1098
  var import_zod6 = require("zod");
1457
- var ListDirectoryToolName = "list_directory";
1458
- 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({
1459
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({
1460
1363
  description: "The directory path to list, relative to the project directory."
1461
1364
  })
1462
1365
  });
1463
- var ListDirectoryToolOutput = import_zod6.z.object({
1464
- path: import_zod6.z.string().meta({
1366
+ var ListDirectoryToolOutput = import_zod7.z.object({
1367
+ path: import_zod7.z.string().meta({
1465
1368
  description: "The directory path that was listed."
1466
1369
  }),
1467
- files: import_zod6.z.array(import_zod6.z.string()).meta({
1370
+ files: import_zod7.z.array(import_zod7.z.string()).meta({
1468
1371
  description: "List of files in the directory."
1469
1372
  }),
1470
- directories: import_zod6.z.array(import_zod6.z.string()).meta({
1373
+ directories: import_zod7.z.array(import_zod7.z.string()).meta({
1471
1374
  description: "List of subdirectories in the directory."
1472
1375
  })
1473
1376
  });
1474
- var ListDirectoryTool = class extends EnvironmentToolBase {
1377
+ var ListDirectoryTool = class extends import_environment_utils12.EnvironmentToolBase {
1475
1378
  /**
1476
1379
  * Returns the metadata for the tool.
1477
1380
  *
@@ -1496,7 +1399,7 @@ var ListDirectoryTool = class extends EnvironmentToolBase {
1496
1399
  * @returns A promise that resolves to the tool execution result.
1497
1400
  */
1498
1401
  async executeForEnvironment(env, input) {
1499
- const escapedPath = escapeCommandArg(input.path);
1402
+ const escapedPath = (0, import_environment_utils12.escapeCommandArg)(input.path);
1500
1403
  const command = `ls -la ${escapedPath}`;
1501
1404
  const { stdout, stderr, exitCode } = await env.runCommand(command);
1502
1405
  if (exitCode !== 0) {
@@ -1529,10 +1432,11 @@ var ListDirectoryTool = class extends EnvironmentToolBase {
1529
1432
  /**
1530
1433
  * Converts the tool output to a format suitable for model consumption.
1531
1434
  *
1532
- * @param output - The output from the tool execution.
1435
+ * @param options - The tool result, including the output from the tool execution.
1533
1436
  * @returns The formatted tool result.
1534
1437
  */
1535
- toModelOutput(output) {
1438
+ toModelOutput(options) {
1439
+ const { output } = options;
1536
1440
  const formatEntries = (entries, type) => {
1537
1441
  if (entries.length === 0) {
1538
1442
  return `No ${type} found.`;
@@ -1578,18 +1482,19 @@ Directories:
1578
1482
  };
1579
1483
 
1580
1484
  // src/tools/move-file-tool.ts
1581
- var import_zod7 = require("zod");
1485
+ var import_zod8 = require("zod");
1486
+ var import_environment_utils13 = require("@ai-code-agents/environment-utils");
1582
1487
  var MoveFileToolName = "move_file";
1583
- var MoveFileToolInput = import_zod7.z.object({
1584
- sourcePath: import_zod7.z.string().meta({
1488
+ var MoveFileToolInput = import_zod8.z.object({
1489
+ sourcePath: import_zod8.z.string().meta({
1585
1490
  description: "The path to the file to move, relative to the project directory."
1586
1491
  }),
1587
- destinationPath: import_zod7.z.string().meta({
1492
+ destinationPath: import_zod8.z.string().meta({
1588
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."
1589
1494
  })
1590
1495
  });
1591
- var MoveFileToolOutput = MoveFileResult;
1592
- var MoveFileTool = class extends EnvironmentToolBase {
1496
+ var MoveFileToolOutput = import_environment_utils13.MoveFileResult;
1497
+ var MoveFileTool = class extends import_environment_utils13.EnvironmentToolBase {
1593
1498
  /**
1594
1499
  * Returns the metadata for the tool.
1595
1500
  *
@@ -1619,10 +1524,11 @@ var MoveFileTool = class extends EnvironmentToolBase {
1619
1524
  /**
1620
1525
  * Converts the tool output to a format suitable for model consumption.
1621
1526
  *
1622
- * @param output - The output from the tool execution.
1527
+ * @param options - The tool result, including the output from the tool execution.
1623
1528
  * @returns The formatted tool result.
1624
1529
  */
1625
- toModelOutput(output) {
1530
+ toModelOutput(options) {
1531
+ const { output } = options;
1626
1532
  return {
1627
1533
  type: "text",
1628
1534
  value: `File \`${output.sourcePath}\` moved successfully to \`${output.destinationPath}\`.`
@@ -1647,10 +1553,11 @@ var MoveFileTool = class extends EnvironmentToolBase {
1647
1553
  };
1648
1554
 
1649
1555
  // src/tools/read-file-tool.ts
1650
- var import_zod8 = require("zod");
1556
+ var import_zod9 = require("zod");
1557
+ var import_environment_utils14 = require("@ai-code-agents/environment-utils");
1651
1558
 
1652
1559
  // src/util/get-language-identifier-from-file-path.ts
1653
- var import_node_path3 = __toESM(require("path"), 1);
1560
+ var import_node_path4 = __toESM(require("path"), 1);
1654
1561
  var jsLanguage = {
1655
1562
  identifier: "javascript",
1656
1563
  name: "JavaScript",
@@ -1800,7 +1707,7 @@ var EXTENSION_TO_LANGUAGE = {
1800
1707
  }
1801
1708
  };
1802
1709
  function getLanguageFromFilePath(filePath) {
1803
- const extension = import_node_path3.default.extname(filePath).slice(1).toLowerCase() || "";
1710
+ const extension = import_node_path4.default.extname(filePath).slice(1).toLowerCase() || "";
1804
1711
  return EXTENSION_TO_LANGUAGE[extension];
1805
1712
  }
1806
1713
  function getLanguageIdentifierFromFilePath(filePath) {
@@ -1810,12 +1717,12 @@ function getLanguageIdentifierFromFilePath(filePath) {
1810
1717
 
1811
1718
  // src/tools/read-file-tool.ts
1812
1719
  var ReadFileToolName = "read_file";
1813
- var ReadFileToolInput = import_zod8.z.object({
1814
- path: import_zod8.z.string().meta({
1720
+ var ReadFileToolInput = import_zod9.z.object({
1721
+ path: import_zod9.z.string().meta({
1815
1722
  description: "The path to the file to read, relative to the project directory."
1816
1723
  })
1817
1724
  });
1818
- var ReadFileToolOutput = ReadFileResult;
1725
+ var ReadFileToolOutput = import_environment_utils14.ReadFileResult;
1819
1726
  var formatModelResponse = (output) => {
1820
1727
  const language = getLanguageIdentifierFromFilePath(output.path);
1821
1728
  return `File: \`${output.path}\`
@@ -1825,7 +1732,7 @@ ${output.content}
1825
1732
  \`\`\`
1826
1733
  `;
1827
1734
  };
1828
- var ReadFileTool = class extends EnvironmentToolBase {
1735
+ var ReadFileTool = class extends import_environment_utils14.EnvironmentToolBase {
1829
1736
  /**
1830
1737
  * Returns the metadata for the tool.
1831
1738
  *
@@ -1855,10 +1762,11 @@ var ReadFileTool = class extends EnvironmentToolBase {
1855
1762
  /**
1856
1763
  * Converts the tool output to a format suitable for model consumption.
1857
1764
  *
1858
- * @param output - The output from the tool execution.
1765
+ * @param options - The tool result, including the output from the tool execution.
1859
1766
  * @returns The formatted tool result.
1860
1767
  */
1861
- toModelOutput(output) {
1768
+ toModelOutput(options) {
1769
+ const { output } = options;
1862
1770
  return {
1863
1771
  type: "text",
1864
1772
  value: formatModelResponse(output)
@@ -1901,14 +1809,15 @@ export function Loader(props: LoaderProps) {
1901
1809
  };
1902
1810
 
1903
1811
  // src/tools/read-many-files-tool.ts
1904
- var import_zod9 = require("zod");
1812
+ var import_zod10 = require("zod");
1813
+ var import_environment_utils15 = require("@ai-code-agents/environment-utils");
1905
1814
  var ReadManyFilesToolName = "read_many_files";
1906
- var ReadManyFilesToolInput = import_zod9.z.object({
1907
- 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({
1908
1817
  description: "The paths to the files to read, relative to the project directory."
1909
1818
  })
1910
1819
  });
1911
- 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);
1912
1821
  var formatModelResponse2 = (output) => {
1913
1822
  const language = getLanguageIdentifierFromFilePath(output.path);
1914
1823
  return `File: \`${output.path}\`
@@ -1918,7 +1827,7 @@ ${output.content}
1918
1827
  \`\`\`
1919
1828
  `;
1920
1829
  };
1921
- var ReadManyFilesTool = class extends EnvironmentToolBase {
1830
+ var ReadManyFilesTool = class extends import_environment_utils15.EnvironmentToolBase {
1922
1831
  /**
1923
1832
  * Returns the metadata for the tool.
1924
1833
  *
@@ -1954,10 +1863,11 @@ var ReadManyFilesTool = class extends EnvironmentToolBase {
1954
1863
  /**
1955
1864
  * Converts the tool output to a format suitable for model consumption.
1956
1865
  *
1957
- * @param output - The output from the tool execution.
1866
+ * @param options - The tool result, including the output from the tool execution.
1958
1867
  * @returns The formatted tool result.
1959
1868
  */
1960
- toModelOutput(output) {
1869
+ toModelOutput(options) {
1870
+ const { output } = options;
1961
1871
  const fileContentResponses = Object.values(output).map(
1962
1872
  (fileResult) => formatModelResponse2(fileResult)
1963
1873
  );
@@ -2013,12 +1923,13 @@ export function Loader(props: LoaderProps) {
2013
1923
  };
2014
1924
 
2015
1925
  // src/tools/run-command-tool.ts
2016
- var import_zod10 = require("zod");
1926
+ var import_zod11 = require("zod");
1927
+ var import_environment_utils16 = require("@ai-code-agents/environment-utils");
2017
1928
  var RunCommandToolName = "run_command";
2018
- var RunCommandToolInput = import_zod10.z.object({
2019
- 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." })
2020
1931
  });
2021
- var RunCommandToolOutput = RunCommandResult;
1932
+ var RunCommandToolOutput = import_environment_utils16.RunCommandResult;
2022
1933
  function formatCommandResultToModelResponse(output) {
2023
1934
  const stdout = !output.stdout.trim() ? "(none)" : `
2024
1935
  \`\`\`
@@ -2034,7 +1945,7 @@ Output (stdout): ${stdout}
2034
1945
  Error Output (stderr): ${stderr}
2035
1946
  `;
2036
1947
  }
2037
- var RunCommandTool = class extends EnvironmentToolBase {
1948
+ var RunCommandTool = class extends import_environment_utils16.EnvironmentToolBase {
2038
1949
  /**
2039
1950
  * Returns the metadata for the tool.
2040
1951
  *
@@ -2064,10 +1975,11 @@ var RunCommandTool = class extends EnvironmentToolBase {
2064
1975
  /**
2065
1976
  * Converts the tool output to a format suitable for model consumption.
2066
1977
  *
2067
- * @param output - The output from the tool execution.
1978
+ * @param options - The tool result, including the output from the tool execution.
2068
1979
  * @returns The formatted tool result.
2069
1980
  */
2070
- toModelOutput(output) {
1981
+ toModelOutput(options) {
1982
+ const { output } = options;
2071
1983
  return {
2072
1984
  type: "text",
2073
1985
  value: formatCommandResultToModelResponse(output)
@@ -2138,18 +2050,19 @@ added 1 package, and changed 1 package in 2s
2138
2050
  };
2139
2051
 
2140
2052
  // src/tools/write-file-tool.ts
2141
- var import_zod11 = require("zod");
2053
+ var import_zod12 = require("zod");
2054
+ var import_environment_utils17 = require("@ai-code-agents/environment-utils");
2142
2055
  var WriteFileToolName = "write_file";
2143
- var WriteFileToolInput = import_zod11.z.object({
2144
- path: import_zod11.z.string().meta({
2056
+ var WriteFileToolInput = import_zod12.z.object({
2057
+ path: import_zod12.z.string().meta({
2145
2058
  description: "The path to the file to write, relative to the project directory."
2146
2059
  }),
2147
- content: import_zod11.z.string().meta({
2060
+ content: import_zod12.z.string().meta({
2148
2061
  description: "The content to write to the file. If the file already exists, the content will replace existing content."
2149
2062
  })
2150
2063
  });
2151
- var WriteFileToolOutput = WriteFileResult;
2152
- var WriteFileTool = class extends EnvironmentToolBase {
2064
+ var WriteFileToolOutput = import_environment_utils17.WriteFileResult;
2065
+ var WriteFileTool = class extends import_environment_utils17.EnvironmentToolBase {
2153
2066
  /**
2154
2067
  * Returns the metadata for the tool.
2155
2068
  *
@@ -2179,10 +2092,11 @@ var WriteFileTool = class extends EnvironmentToolBase {
2179
2092
  /**
2180
2093
  * Converts the tool output to a format suitable for model consumption.
2181
2094
  *
2182
- * @param output - The output from the tool execution.
2095
+ * @param options - The tool result, including the output from the tool execution.
2183
2096
  * @returns The formatted tool result.
2184
2097
  */
2185
- toModelOutput(output) {
2098
+ toModelOutput(options) {
2099
+ const { output } = options;
2186
2100
  return {
2187
2101
  type: "text",
2188
2102
  value: `File \`${output.path}\` written successfully.`
@@ -2211,11 +2125,12 @@ var WriteFileTool = class extends EnvironmentToolBase {
2211
2125
  };
2212
2126
 
2213
2127
  // src/tools/submit-tool.ts
2214
- var import_zod12 = require("zod");
2128
+ var import_zod13 = require("zod");
2129
+ var import_environment_utils18 = require("@ai-code-agents/environment-utils");
2215
2130
  var SubmitToolName = "submit";
2216
- var SubmitToolInput = import_zod12.z.object({});
2217
- var SubmitToolOutput = import_zod12.z.object({});
2218
- 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 {
2219
2134
  /**
2220
2135
  * Returns the metadata for the tool.
2221
2136
  *
@@ -2236,7 +2151,7 @@ var SubmitTool = class extends ToolBase {
2236
2151
  * Executes the tool with the given input.
2237
2152
  *
2238
2153
  * @param _ - The input for the tool. Unused.
2239
- * @param __ - Options from the tool call. Unused.
2154
+ * @param __ - Options for the tool execution. Unused.
2240
2155
  * @returns A promise that resolves to the tool execution result.
2241
2156
  */
2242
2157
  async execute(_, __) {
@@ -2245,7 +2160,7 @@ var SubmitTool = class extends ToolBase {
2245
2160
  /**
2246
2161
  * Converts the tool output to a format suitable for model consumption.
2247
2162
  *
2248
- * @param _ - The output from the tool execution. Unused.
2163
+ * @param _ - The tool result, including the output from the tool execution. Unused.
2249
2164
  * @returns The formatted tool result.
2250
2165
  */
2251
2166
  toModelOutput(_) {
@@ -2270,10 +2185,13 @@ var import_ai = require("ai");
2270
2185
  // src/instructions.ts
2271
2186
  function getAdditionalInstructions(config) {
2272
2187
  const { maxSteps, allowSubmit, tools } = config;
2273
- 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
+ ];
2274
2192
  for (const [toolName, tool] of Object.entries(tools)) {
2275
2193
  if ("examples" in tool && Array.isArray(tool.examples) && tool.examples.length > 0) {
2276
- let toolSection = `### Tool: \`${toolName}\`
2194
+ let toolSection = `## Tool: \`${toolName}\`
2277
2195
 
2278
2196
  `;
2279
2197
  for (const example of tool.examples) {
@@ -2282,40 +2200,48 @@ function getAdditionalInstructions(config) {
2282
2200
  exampleSections.push(toolSection.trim());
2283
2201
  }
2284
2202
  }
2285
- const workflowGuidelines = [
2286
- /*
2287
- * If there are examples, the tool information is already mentioned in a separate Tool Examples section.
2288
- * Therefore the line below is only relevant if there are no examples.
2289
- */
2290
- ...!exampleSections.length ? [
2291
- "You have access to several tools to assist you in completing your task."
2292
- ] : [],
2293
- "You must issue tool calls to complete your task. Do not engage with the user directly.",
2294
- ...allowSubmit ? [
2295
- `Once you think you have completed your task, call the \`${SubmitToolName}\` tool to submit your results.`
2296
- ] : [],
2297
- `You have a maximum of ${maxSteps} steps to complete your task.`
2298
- ];
2299
- const importantWorkflowGuidelines = `## Important Workflow Guidelines
2300
-
2301
- ${workflowGuidelines.map((line) => `- ${line}`).join("\n")}
2302
-
2303
- 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}
2304
2209
  `;
2305
- if (exampleSections.length) {
2306
- return `## Tool Examples
2307
-
2308
- You have access to several tools to assist you in completing your task. Here are some examples of how to use them:
2309
-
2310
- ${exampleSections.join("\n\n")}
2311
-
2312
- ` + importantWorkflowGuidelines;
2210
+ }
2211
+ constraintSections.push(constraintSection.trim());
2313
2212
  }
2314
- return importantWorkflowGuidelines;
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());
2236
+ }
2237
+ const finalReminder = getCodeAgentFinalReminder();
2238
+ return [...exampleSections, ...constraintSections, finalReminder].join(
2239
+ "\n\n"
2240
+ );
2315
2241
  }
2316
2242
  function formatExampleForInstructions(toolName, example) {
2317
- const input = typeof example.input === "undefined" ? "" : typeof example.input === "string" || typeof example.input === "number" ? example.input : JSON.stringify(example.input, null, 2);
2318
- 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);
2319
2245
  if (output === "") {
2320
2246
  return `<example>
2321
2247
  <tool_call>
@@ -2332,8 +2258,40 @@ ${output}
2332
2258
  </tool_response>
2333
2259
  </example>`;
2334
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
+ }
2335
2292
 
2336
2293
  // src/tool-creators.ts
2294
+ var import_environment_utils19 = require("@ai-code-agents/environment-utils");
2337
2295
  var availableEnvironmentTools = {
2338
2296
  [ReadFileToolName]: ReadFileTool,
2339
2297
  [WriteFileToolName]: WriteFileTool,
@@ -2344,12 +2302,14 @@ var availableEnvironmentTools = {
2344
2302
  [ReadManyFilesToolName]: ReadManyFilesTool,
2345
2303
  [GetProjectFileStructureToolName]: GetProjectFileStructureTool,
2346
2304
  [GlobToolName]: GlobTool,
2305
+ [GrepToolName]: GrepTool,
2347
2306
  [ListDirectoryToolName]: ListDirectoryTool,
2348
2307
  [RunCommandToolName]: RunCommandTool
2349
2308
  };
2350
2309
  var cliOnlyTools = [
2351
2310
  GetProjectFileStructureToolName,
2352
2311
  GlobToolName,
2312
+ GrepToolName,
2353
2313
  ListDirectoryToolName,
2354
2314
  RunCommandToolName
2355
2315
  ];
@@ -2358,6 +2318,7 @@ var readonlyTools = [
2358
2318
  ReadManyFilesToolName,
2359
2319
  GetProjectFileStructureToolName,
2360
2320
  GlobToolName,
2321
+ GrepToolName,
2361
2322
  ListDirectoryToolName
2362
2323
  ];
2363
2324
  var dangerousTools = [
@@ -2385,7 +2346,7 @@ function createEnvironmentTool(toolName, environment, config) {
2385
2346
  }
2386
2347
  function createToolsForEnvironment(environment, toolsDefinition = "all") {
2387
2348
  const sanitizedToolsDefinition = sanitizeToolsDefinition(toolsDefinition);
2388
- const isCliEnvironment = "runCommand" in environment;
2349
+ const isCliEnvironment = (0, import_environment_utils19.isCommandLine)(environment);
2389
2350
  const tools = {};
2390
2351
  for (const toolDefinition of sanitizedToolsDefinition) {
2391
2352
  const actualToolName = toolDefinition.toolName;
@@ -2406,7 +2367,7 @@ function createToolsForEnvironment(environment, toolsDefinition = "all") {
2406
2367
  }
2407
2368
  tools[toolNameToUse] = createEnvironmentTool(
2408
2369
  actualToolName,
2409
- isCliEnvironment ? environment : environment,
2370
+ environment,
2410
2371
  toolConfig
2411
2372
  );
2412
2373
  }
@@ -2462,6 +2423,54 @@ function sanitizeToolsDefinition(toolsDefinition) {
2462
2423
  });
2463
2424
  }
2464
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
+
2465
2474
  // src/util/get-step-log.ts
2466
2475
  function getStepLog(stepResult) {
2467
2476
  const { content } = stepResult;
@@ -2475,13 +2484,17 @@ function getStepLog(stepResult) {
2475
2484
  }
2476
2485
  logEntry += ": ";
2477
2486
  if (part.type === "tool-call" && "input" in part) {
2478
- 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
+ );
2479
2490
  } else if (part.type === "tool-result" && "output" in part) {
2480
- 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
+ );
2481
2494
  } else if (part.type === "tool-error" && "error" in part) {
2482
2495
  logEntry += typeof part.error === "object" && part.error !== null && "message" in part.error ? part.error.message : String(part.error);
2483
2496
  } else if (part.type === "text" && "text" in part) {
2484
- logEntry += part.text;
2497
+ logEntry += truncateString(part.text);
2485
2498
  }
2486
2499
  logEntry += "\n";
2487
2500
  });
@@ -2490,6 +2503,9 @@ function getStepLog(stepResult) {
2490
2503
 
2491
2504
  // src/agent-creators.ts
2492
2505
  function createCodeAgent(agentConfig) {
2506
+ return new import_ai.ToolLoopAgent(createCodeAgentSettings(agentConfig));
2507
+ }
2508
+ function createCodeAgentSettings(agentConfig) {
2493
2509
  const {
2494
2510
  maxSteps,
2495
2511
  allowSubmit,
@@ -2498,46 +2514,29 @@ function createCodeAgent(agentConfig) {
2498
2514
  tools: originalTools,
2499
2515
  stopWhen: originalStopWhen,
2500
2516
  prepareStep: originalPrepareStep,
2501
- system: originalSystemInstruction,
2517
+ instructions: originalSystemInstruction,
2502
2518
  ...remainingConfig
2503
2519
  } = agentConfig;
2504
2520
  let agentSettings;
2505
- let environmentTools;
2521
+ let tools;
2506
2522
  if ("environments" in remainingConfig) {
2507
2523
  const { environments, environmentToolsDefinition, ...agentSettingsInput } = remainingConfig;
2508
2524
  agentSettings = { ...agentSettingsInput };
2509
- environmentTools = {};
2510
- for (const [environmentName, environment] of Object.entries(environments)) {
2511
- if (!(environmentName in environmentToolsDefinition)) {
2512
- throw new Error(
2513
- `No tools definition provided for environment "${environmentName}". Please provide a tools definition for each environment.`
2514
- );
2515
- }
2516
- const envTools = createToolsForNamedEnvironment(
2517
- environmentName,
2518
- environment,
2519
- environmentToolsDefinition[environmentName]
2520
- );
2521
- for (const [toolName, tool] of Object.entries(envTools)) {
2522
- if (toolName in environmentTools) {
2523
- throw new Error(
2524
- `Tool name conflict: The tool name "${toolName}" from environment "${environmentName}" is already used by another environment's tools.`
2525
- );
2526
- }
2527
- environmentTools[toolName] = tool;
2528
- }
2529
- }
2525
+ tools = createCodeAgentTools(
2526
+ { environments, environmentToolsDefinition },
2527
+ originalTools
2528
+ );
2530
2529
  } else if ("environment" in remainingConfig) {
2531
2530
  const { environment, environmentToolsDefinition, ...agentSettingsInput } = remainingConfig;
2532
2531
  agentSettings = { ...agentSettingsInput };
2533
- environmentTools = createToolsForEnvironment(
2534
- environment,
2535
- environmentToolsDefinition
2532
+ tools = createCodeAgentTools(
2533
+ { environment, environmentToolsDefinition },
2534
+ originalTools
2536
2535
  );
2537
2536
  } else {
2538
2537
  agentSettings = { ...remainingConfig };
2538
+ tools = originalTools || {};
2539
2539
  }
2540
- const tools = environmentTools && originalTools ? mergeTools(environmentTools, originalTools) : originalTools || environmentTools || {};
2541
2540
  if (allowSubmit) {
2542
2541
  if (SubmitToolName in tools) {
2543
2542
  throw new Error(
@@ -2565,16 +2564,54 @@ ${stepLog}`, stepCount - 1);
2565
2564
  } : originalPrepareStep;
2566
2565
  const stopWhenCondition = allowSubmit ? [(0, import_ai.stepCountIs)(maxSteps), (0, import_ai.hasToolCall)(SubmitToolName)] : (0, import_ai.stepCountIs)(maxSteps);
2567
2566
  const stopWhen = originalStopWhen ? mergeStopWhen(originalStopWhen, stopWhenCondition) : stopWhenCondition;
2568
- const system = !omitAdditionalInstructions ? mergeSystemInstructions(
2567
+ const instructions = !omitAdditionalInstructions ? mergeSystemInstructions(
2569
2568
  originalSystemInstruction,
2570
2569
  getAdditionalInstructions({ maxSteps, allowSubmit, tools })
2571
2570
  ) : originalSystemInstruction;
2572
- return new import_ai.Experimental_Agent({
2571
+ return {
2573
2572
  ...agentSettings,
2574
- system,
2573
+ instructions,
2575
2574
  prepareStep,
2576
2575
  stopWhen
2577
- });
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
+ );
2578
2615
  }
2579
2616
  function mergeTools(baseTools, additionalTools) {
2580
2617
  const tools = { ...baseTools };
@@ -2600,9 +2637,26 @@ function mergeStopWhen(baseStopWhen, additionalStopWhen) {
2600
2637
  }
2601
2638
  return [baseStopWhen, additionalStopWhen];
2602
2639
  }
2603
- function mergeSystemInstructions(baseSystem, additionalInstructions) {
2604
- if (baseSystem) {
2605
- 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()}
2606
2660
 
2607
2661
  ${additionalInstructions}`;
2608
2662
  }
@@ -2628,12 +2682,10 @@ function createEnvironment(environmentName, config) {
2628
2682
  }
2629
2683
  // Annotate the CommonJS export names for ESM import in node:
2630
2684
  0 && (module.exports = {
2631
- CopyFileResult,
2632
2685
  CopyFileTool,
2633
2686
  CopyFileToolInput,
2634
2687
  CopyFileToolName,
2635
2688
  CopyFileToolOutput,
2636
- DeleteFileResult,
2637
2689
  DeleteFileTool,
2638
2690
  DeleteFileToolInput,
2639
2691
  DeleteFileToolName,
@@ -2655,20 +2707,22 @@ function createEnvironment(environmentName, config) {
2655
2707
  GlobToolInput,
2656
2708
  GlobToolName,
2657
2709
  GlobToolOutput,
2710
+ GrepTool,
2711
+ GrepToolInput,
2712
+ GrepToolName,
2713
+ GrepToolOutput,
2658
2714
  ListDirectoryTool,
2659
2715
  ListDirectoryToolInput,
2660
2716
  ListDirectoryToolName,
2661
2717
  ListDirectoryToolOutput,
2662
2718
  MockFilesystemEnvironment,
2663
2719
  MockFilesystemEnvironmentName,
2664
- MoveFileResult,
2665
2720
  MoveFileTool,
2666
2721
  MoveFileToolInput,
2667
2722
  MoveFileToolName,
2668
2723
  MoveFileToolOutput,
2669
2724
  NodeFilesystemEnvironment,
2670
2725
  NodeFilesystemEnvironmentName,
2671
- ReadFileResult,
2672
2726
  ReadFileTool,
2673
2727
  ReadFileToolInput,
2674
2728
  ReadFileToolName,
@@ -2677,7 +2731,6 @@ function createEnvironment(environmentName, config) {
2677
2731
  ReadManyFilesToolInput,
2678
2732
  ReadManyFilesToolName,
2679
2733
  ReadManyFilesToolOutput,
2680
- RunCommandResult,
2681
2734
  RunCommandTool,
2682
2735
  RunCommandToolInput,
2683
2736
  RunCommandToolName,
@@ -2688,12 +2741,13 @@ function createEnvironment(environmentName, config) {
2688
2741
  SubmitToolOutput,
2689
2742
  UnsafeLocalEnvironment,
2690
2743
  UnsafeLocalEnvironmentName,
2691
- WriteFileResult,
2692
2744
  WriteFileTool,
2693
2745
  WriteFileToolInput,
2694
2746
  WriteFileToolName,
2695
2747
  WriteFileToolOutput,
2696
2748
  createCodeAgent,
2749
+ createCodeAgentSettings,
2750
+ createCodeAgentTools,
2697
2751
  createEnvironment,
2698
2752
  createEnvironmentTool,
2699
2753
  createToolsForEnvironment,