11import { tool } from "ai" ;
2- import { RuntimeError } from "@/runtime/Runtime" ;
32import type { FileEditInsertToolArgs , FileEditInsertToolResult } from "@/types/tools" ;
43import { EDIT_FAILED_NOTE_PREFIX , NOTE_READ_FILE_RETRY } from "@/types/tools" ;
54import type { ToolConfiguration , ToolFactory } from "@/utils/tools/tools" ;
65import { TOOL_DEFINITIONS } from "@/utils/tools/toolDefinitions" ;
76import { validateAndCorrectPath , validatePathInCwd } from "./fileCommon" ;
87import { executeFileEditOperation } from "./file_edit_operation" ;
9- import { fileExists } from "@/utils/runtime/fileExists" ;
10- import { writeFileString } from "@/utils/runtime/helpers" ;
118
129const READ_AND_RETRY_NOTE = `${ EDIT_FAILED_NOTE_PREFIX } ${ NOTE_READ_FILE_RETRY } ` ;
1310
@@ -26,7 +23,6 @@ interface InsertOperationFailure {
2623interface InsertContentOptions {
2724 before ?: string ;
2825 after ?: string ;
29- lineOffset ?: number ;
3026}
3127
3228interface GuardResolutionSuccess {
@@ -49,7 +45,7 @@ export const createFileEditInsertTool: ToolFactory = (config: ToolConfiguration)
4945 description : TOOL_DEFINITIONS . file_edit_insert . description ,
5046 inputSchema : TOOL_DEFINITIONS . file_edit_insert . schema ,
5147 execute : async (
52- { file_path, content, line_offset , create , before, after } : FileEditInsertToolArgs ,
48+ { file_path, content, before, after } : FileEditInsertToolArgs ,
5349 { abortSignal }
5450 ) : Promise < FileEditInsertToolResult > => {
5551 try {
@@ -64,39 +60,6 @@ export const createFileEditInsertTool: ToolFactory = (config: ToolConfiguration)
6460 } ;
6561 }
6662
67- if ( line_offset !== undefined && line_offset < 0 ) {
68- return {
69- success : false ,
70- error : `line_offset must be non-negative (got ${ line_offset } )` ,
71- note : `${ EDIT_FAILED_NOTE_PREFIX } The line_offset must be >= 0.` ,
72- } ;
73- }
74-
75- const resolvedPath = config . runtime . normalizePath ( file_path , config . cwd ) ;
76- const exists = await fileExists ( config . runtime , resolvedPath , abortSignal ) ;
77-
78- if ( ! exists ) {
79- if ( ! create ) {
80- return {
81- success : false ,
82- error : `File not found: ${ file_path } . Set create: true to create it.` ,
83- note : `${ EDIT_FAILED_NOTE_PREFIX } File does not exist. Set create: true to create it, or check the file path.` ,
84- } ;
85- }
86-
87- try {
88- await writeFileString ( config . runtime , resolvedPath , "" , abortSignal ) ;
89- } catch ( err ) {
90- if ( err instanceof RuntimeError ) {
91- return {
92- success : false ,
93- error : err . message ,
94- } ;
95- }
96- throw err ;
97- }
98- }
99-
10063 return executeFileEditOperation ( {
10164 config,
10265 filePath : file_path ,
@@ -105,7 +68,6 @@ export const createFileEditInsertTool: ToolFactory = (config: ToolConfiguration)
10568 insertContent ( originalContent , content , {
10669 before,
10770 after,
108- lineOffset : line_offset ,
10971 } ) ,
11072 } ) ;
11173 } catch ( error ) {
@@ -131,21 +93,17 @@ function insertContent(
13193 contentToInsert : string ,
13294 options : InsertContentOptions
13395) : InsertOperationSuccess | InsertOperationFailure {
134- const { before, after, lineOffset } = options ;
96+ const { before, after } = options ;
13597
13698 if ( before !== undefined && after !== undefined ) {
13799 return guardFailure ( "Provide only one of before or after (not both)." ) ;
138100 }
139101
140- if ( before !== undefined || after ! == undefined ) {
141- return insertWithGuards ( originalContent , contentToInsert , { before, after } ) ;
102+ if ( before === undefined && after = == undefined ) {
103+ return guardFailure ( "Provide either a before or after guard to anchor the insertion point." ) ;
142104 }
143105
144- if ( lineOffset === undefined ) {
145- return guardFailure ( "line_offset must be provided when before/after guards are omitted." ) ;
146- }
147-
148- return insertWithLineOffset ( originalContent , contentToInsert , lineOffset ) ;
106+ return insertWithGuards ( originalContent , contentToInsert , { before, after } ) ;
149107}
150108
151109function insertWithGuards (
@@ -212,76 +170,3 @@ function resolveGuardAnchor(
212170
213171 return guardFailure ( "Unable to determine insertion point from guards." ) ;
214172}
215-
216- function insertWithLineOffset (
217- originalContent : string ,
218- contentToInsert : string ,
219- lineOffset : number
220- ) : InsertOperationSuccess | InsertOperationFailure {
221- const lineCount = countLines ( originalContent ) ;
222- if ( lineOffset > lineCount ) {
223- return {
224- success : false ,
225- error : `line_offset ${ lineOffset } is beyond file length (${ lineCount } lines)` ,
226- note : `${ EDIT_FAILED_NOTE_PREFIX } The file has ${ lineCount } lines. ${ NOTE_READ_FILE_RETRY } ` ,
227- } ;
228- }
229-
230- const insertionIndex = getIndexForLineOffset ( originalContent , lineOffset ) ;
231- if ( insertionIndex === null ) {
232- return guardFailure ( `Unable to compute insertion point for line_offset ${ lineOffset } .` ) ;
233- }
234-
235- const newContent =
236- originalContent . slice ( 0 , insertionIndex ) +
237- contentToInsert +
238- originalContent . slice ( insertionIndex ) ;
239-
240- return {
241- success : true ,
242- newContent,
243- metadata : { } ,
244- } ;
245- }
246-
247- function getIndexForLineOffset ( content : string , lineOffset : number ) : number | null {
248- if ( lineOffset === 0 ) {
249- return 0 ;
250- }
251-
252- let linesAdvanced = 0 ;
253- let cursor = 0 ;
254-
255- while ( linesAdvanced < lineOffset ) {
256- const nextNewline = content . indexOf ( "\n" , cursor ) ;
257- if ( nextNewline === - 1 ) {
258- if ( linesAdvanced + 1 === lineOffset ) {
259- return content . length ;
260- }
261- return null ;
262- }
263-
264- linesAdvanced += 1 ;
265- cursor = nextNewline + 1 ;
266-
267- if ( linesAdvanced === lineOffset ) {
268- return cursor ;
269- }
270- }
271-
272- return null ;
273- }
274-
275- function countLines ( content : string ) : number {
276- if ( content . length === 0 ) {
277- return 1 ;
278- }
279-
280- let count = 1 ;
281- for ( const char of content ) {
282- if ( char === "\n" ) {
283- count += 1 ;
284- }
285- }
286- return count ;
287- }
0 commit comments