@@ -48,15 +48,21 @@ export async function readFileTool(
4848 _removeClosingTag : RemoveClosingTag ,
4949) {
5050 const argsXmlTag : string | undefined = block . params . args
51+ const legacyPath : string | undefined = block . params . path
52+ const legacyStartLineStr : string | undefined = block . params . start_line
53+ const legacyEndLineStr : string | undefined = block . params . end_line
5154
5255 // Handle partial message first
5356 if ( block . partial ) {
5457 let filePath = ""
58+ // Prioritize args for partial, then legacy path
5559 if ( argsXmlTag ) {
5660 const match = argsXmlTag . match ( / < f i l e > .* ?< p a t h > ( [ ^ < ] + ) < \/ p a t h > / s)
57- if ( match ) {
58- filePath = match [ 1 ]
59- }
61+ if ( match ) filePath = match [ 1 ]
62+ }
63+ if ( ! filePath && legacyPath ) {
64+ // If args didn't yield a path, try legacy
65+ filePath = legacyPath
6066 }
6167
6268 const fullPath = filePath ? path . resolve ( cline . cwd , filePath ) : ""
@@ -73,52 +79,70 @@ export async function readFileTool(
7379 return
7480 }
7581
76- if ( ! argsXmlTag ) {
77- cline . consecutiveMistakeCount ++
78- cline . recordToolError ( "read_file" )
79- const errorMsg = await cline . sayAndCreateMissingParamError ( "read_file" , "args" )
80- pushToolResult ( `<files><error>${ errorMsg } </error></files>` )
81- return
82- }
83-
84- // Parse file entries from XML
8582 const fileEntries : FileEntry [ ] = [ ]
86- try {
87- const parsed = parseXml ( argsXmlTag ) as any
88- const files = Array . isArray ( parsed . file ) ? parsed . file : [ parsed . file ] . filter ( Boolean )
8983
90- for ( const file of files ) {
91- if ( ! file . path ) continue
84+ if ( argsXmlTag ) {
85+ // Parse file entries from XML (new multi-file format)
86+ try {
87+ const parsed = parseXml ( argsXmlTag ) as any
88+ const files = Array . isArray ( parsed . file ) ? parsed . file : [ parsed . file ] . filter ( Boolean )
9289
93- const fileEntry : FileEntry = {
94- path : file . path ,
95- lineRanges : [ ] ,
96- }
90+ for ( const file of files ) {
91+ if ( ! file . path ) continue // Skip if no path in a file entry
92+
93+ const fileEntry : FileEntry = {
94+ path : file . path ,
95+ lineRanges : [ ] ,
96+ }
9797
98- // Handle line ranges
99- if ( file . line_range ) {
100- const ranges = Array . isArray ( file . line_range ) ? file . line_range : [ file . line_range ]
101- for ( const range of ranges ) {
102- const match = range . match ( / ( \d + ) - ( \d + ) / )
103- if ( match ) {
104- const [ , start , end ] = match . map ( Number )
105- if ( ! isNaN ( start ) && ! isNaN ( end ) ) {
106- fileEntry . lineRanges ?. push ( { start , end } )
98+ if ( file . line_range ) {
99+ const ranges = Array . isArray ( file . line_range ) ? file . line_range : [ file . line_range ]
100+ for ( const range of ranges ) {
101+ const match = String ( range ) . match ( / ( \d + ) - ( \d + ) / ) // Ensure range is treated as string
102+ if ( match ) {
103+ const [ , start , end ] = match . map ( Number )
104+ if ( ! isNaN ( start ) && ! isNaN ( end ) ) {
105+ fileEntry . lineRanges ?. push ( { start, end } )
106+ }
107107 }
108108 }
109109 }
110+ fileEntries . push ( fileEntry )
110111 }
112+ } catch ( error ) {
113+ const errorMessage = `Failed to parse read_file XML args: ${ error instanceof Error ? error . message : String ( error ) } `
114+ await handleError ( "parsing read_file args" , new Error ( errorMessage ) )
115+ pushToolResult ( `<files><error>${ errorMessage } </error></files>` )
116+ return
117+ }
118+ } else if ( legacyPath ) {
119+ // Handle legacy single file path as a fallback
120+ console . warn ( "[readFileTool] Received legacy 'path' parameter. Consider updating to use 'args' structure." )
111121
112- fileEntries . push ( fileEntry )
122+ const fileEntry : FileEntry = {
123+ path : legacyPath ,
124+ lineRanges : [ ] ,
113125 }
114- } catch ( error ) {
115- throw new Error ( `Failed to parse read_file XML: ${ error instanceof Error ? error . message : String ( error ) } ` )
126+
127+ if ( legacyStartLineStr && legacyEndLineStr ) {
128+ const start = parseInt ( legacyStartLineStr , 10 )
129+ const end = parseInt ( legacyEndLineStr , 10 )
130+ if ( ! isNaN ( start ) && ! isNaN ( end ) && start > 0 && end > 0 ) {
131+ fileEntry . lineRanges ?. push ( { start, end } )
132+ } else {
133+ console . warn (
134+ `[readFileTool] Invalid legacy line range for ${ legacyPath } : start='${ legacyStartLineStr } ', end='${ legacyEndLineStr } '` ,
135+ )
136+ }
137+ }
138+ fileEntries . push ( fileEntry )
116139 }
117140
141+ // If, after trying both new and legacy, no valid file entries are found.
118142 if ( fileEntries . length === 0 ) {
119143 cline . consecutiveMistakeCount ++
120144 cline . recordToolError ( "read_file" )
121- const errorMsg = await cline . sayAndCreateMissingParamError ( "read_file" , "args" )
145+ const errorMsg = await cline . sayAndCreateMissingParamError ( "read_file" , "args (containing valid file paths) " )
122146 pushToolResult ( `<files><error>${ errorMsg } </error></files>` )
123147 return
124148 }
0 commit comments