Skip to content

Commit 940c543

Browse files
committed
feat(read_file): enhance file description handling and add support for multiple files in messages
1 parent 03f9d4d commit 940c543

File tree

21 files changed

+78
-48
lines changed

21 files changed

+78
-48
lines changed

src/core/assistant-message/presentAssistantMessage.ts

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { telemetryService } from "../../services/telemetry/TelemetryService"
1111

1212
import { fetchInstructionsTool } from "../tools/fetchInstructionsTool"
1313
import { listFilesTool } from "../tools/listFilesTool"
14-
import { readFileTool } from "../tools/readFileTool"
14+
import { getReadFileToolDescription, readFileTool } from "../tools/readFileTool"
1515
import { writeToFileTool } from "../tools/writeToFileTool"
1616
import { applyDiffTool } from "../tools/applyDiffTool"
1717
import { insertContentTool } from "../tools/insertContentTool"
@@ -32,7 +32,6 @@ import { checkpointSave } from "../checkpoints"
3232
import { formatResponse } from "../prompts/responses"
3333
import { validateToolUse } from "../tools/validateToolUse"
3434
import { Task } from "../task/Task"
35-
import { parseXml } from "../../utils/xml"
3635

3736
/**
3837
* Processes and presents assistant message content to the user interface.
@@ -154,35 +153,8 @@ export async function presentAssistantMessage(cline: Task) {
154153
switch (block.name) {
155154
case "execute_command":
156155
return `[${block.name} for '${block.params.command}']`
157-
case "read_file": {
158-
// Handle both single path and multiple files via args
159-
if (block.params.args) {
160-
try {
161-
const parsed = parseXml(block.params.args) as any
162-
const files = Array.isArray(parsed.file) ? parsed.file : [parsed.file].filter(Boolean)
163-
const paths = files.map((f: any) => f?.path).filter(Boolean) as string[]
164-
165-
if (paths.length === 0) {
166-
return `[${block.name} with no valid paths]`
167-
} else if (paths.length === 1) {
168-
return `[${block.name} for '${paths[0]}']`
169-
} else if (paths.length <= 3) {
170-
const pathList = paths.map((p) => `'${p}'`).join(", ")
171-
return `[${block.name} for ${pathList}]`
172-
} else {
173-
return `[${block.name} for ${paths.length} files]`
174-
}
175-
} catch (error) {
176-
console.error("Failed to parse read_file args XML for description:", error)
177-
return `[${block.name} with unparseable args]`
178-
}
179-
} else if (block.params.path) {
180-
// Fallback for legacy single-path usage
181-
return `[${block.name} for '${block.params.path}']`
182-
} else {
183-
return `[${block.name} with missing path/args]`
184-
}
185-
}
156+
case "read_file":
157+
return getReadFileToolDescription(block.name, block.params)
186158
case "fetch_instructions":
187159
return `[${block.name} for '${block.params.task}']`
188160
case "write_to_file":

src/core/tools/readFileTool.ts

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,37 @@ import { extractTextFromFile, addLineNumbers } from "../../integrations/misc/ext
1515
import { parseSourceCodeDefinitionsForFile } from "../../services/tree-sitter"
1616
import { parseXml } from "../../utils/xml"
1717

18+
export function getReadFileToolDescription(blockName: string, blockParams: any): string {
19+
// Handle both single path and multiple files via args
20+
if (blockParams.args) {
21+
try {
22+
const parsed = parseXml(blockParams.args) as any
23+
const files = Array.isArray(parsed.file) ? parsed.file : [parsed.file].filter(Boolean)
24+
const paths = files.map((f: any) => f?.path).filter(Boolean) as string[]
25+
26+
if (paths.length === 0) {
27+
return `[${blockName} with no valid paths]`
28+
} else if (paths.length === 1) {
29+
// Modified part for single file
30+
return `[${blockName} for '${paths[0]}'. Reading multiple files at once is more efficient for the LLM. If other files are relevant to your current task, please read them simultaneously.]`
31+
} else if (paths.length <= 3) {
32+
const pathList = paths.map((p) => `'${p}'`).join(", ")
33+
return `[${blockName} for ${pathList}]`
34+
} else {
35+
return `[${blockName} for ${paths.length} files]`
36+
}
37+
} catch (error) {
38+
console.error("Failed to parse read_file args XML for description:", error)
39+
return `[${blockName} with unparseable args]`
40+
}
41+
} else if (blockParams.path) {
42+
// Fallback for legacy single-path usage
43+
// Modified part for single file (legacy)
44+
return `[${blockName} for '${blockParams.path}'. Reading multiple files at once is more efficient for the LLM. If other files are relevant to your current task, please read them simultaneously.]`
45+
} else {
46+
return `[${blockName} with missing path/args]`
47+
}
48+
}
1849
// Types
1950
interface LineRange {
2051
start: number
@@ -164,7 +195,8 @@ export async function readFileTool(
164195

165196
try {
166197
// First validate all files and get approvals
167-
for (const fileResult of fileResults) {
198+
for (let i = 0; i < fileResults.length; i++) {
199+
const fileResult = fileResults[i]
168200
const relPath = fileResult.path
169201
const fullPath = path.resolve(cline.cwd, relPath)
170202

@@ -216,6 +248,9 @@ export async function readFileTool(
216248
const isOutsideWorkspace = isPathOutsideWorkspace(fullPath)
217249
const { maxReadFileLine = 500 } = (await cline.providerRef.deref()?.getState()) ?? {}
218250

251+
const numOtherFiles = fileResults.length - 1 - i
252+
const additionalFileCount = numOtherFiles > 0 ? numOtherFiles : undefined
253+
219254
// Create line snippet for approval message
220255
let lineSnippet = ""
221256
if (fileResult.lineRanges && fileResult.lineRanges.length > 0) {
@@ -235,6 +270,7 @@ export async function readFileTool(
235270
isOutsideWorkspace,
236271
content: fullPath,
237272
reason: lineSnippet,
273+
additionalFileCount,
238274
} satisfies ClineSayTool)
239275

240276
const { response, text, images } = await cline.ask("tool", completeMessage, false)

src/shared/ExtensionMessage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ export interface ClineSayTool {
233233
mode?: string
234234
reason?: string
235235
isOutsideWorkspace?: boolean
236+
additionalFileCount?: number // Number of additional files in the same read_file request
236237
search?: string
237238
replace?: string
238239
useRegex?: boolean

webview-ui/src/components/chat/ChatRow.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,11 @@ export const ChatRowContent = ({
371371
{message.type === "ask"
372372
? tool.isOutsideWorkspace
373373
? t("chat:fileOperations.wantsToReadOutsideWorkspace")
374-
: t("chat:fileOperations.wantsToRead")
374+
: tool.additionalFileCount && tool.additionalFileCount > 0
375+
? t("chat:fileOperations.wantsToReadAndXMore", {
376+
count: tool.additionalFileCount,
377+
})
378+
: t("chat:fileOperations.wantsToRead")
375379
: t("chat:fileOperations.didRead")}
376380
</span>
377381
</div>

webview-ui/src/i18n/locales/ca/chat.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,8 @@
148148
"didSearchReplace": "Roo ha realitzat cerca i substitució en aquest fitxer:",
149149
"wantsToInsert": "Roo vol inserir contingut en aquest fitxer:",
150150
"wantsToInsertWithLineNumber": "Roo vol inserir contingut a la línia {{lineNumber}} d'aquest fitxer:",
151-
"wantsToInsertAtEnd": "Roo vol afegir contingut al final d'aquest fitxer:"
151+
"wantsToInsertAtEnd": "Roo vol afegir contingut al final d'aquest fitxer:",
152+
"wantsToReadAndXMore": "En Roo vol llegir aquest fitxer i {{count}} més:"
152153
},
153154
"directoryOperations": {
154155
"wantsToViewTopLevel": "Roo vol veure els fitxers de nivell superior en aquest directori:",

webview-ui/src/i18n/locales/de/chat.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@
139139
},
140140
"fileOperations": {
141141
"wantsToRead": "Roo möchte diese Datei lesen:",
142+
"wantsToReadAndXMore": "Roo möchte diese Datei und {{count}} weitere lesen:",
142143
"wantsToReadOutsideWorkspace": "Roo möchte diese Datei außerhalb des Arbeitsbereichs lesen:",
143144
"didRead": "Roo hat diese Datei gelesen:",
144145
"wantsToEdit": "Roo möchte diese Datei bearbeiten:",

webview-ui/src/i18n/locales/en/chat.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@
134134
},
135135
"fileOperations": {
136136
"wantsToRead": "Roo wants to read this file:",
137+
"wantsToReadAndXMore": "Roo wants to read this file and {{count}} more:",
137138
"wantsToReadOutsideWorkspace": "Roo wants to read this file outside of the workspace:",
138139
"didRead": "Roo read this file:",
139140
"wantsToEdit": "Roo wants to edit this file:",

webview-ui/src/i18n/locales/es/chat.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,8 @@
148148
"didSearchReplace": "Roo realizó búsqueda y reemplazo en este archivo:",
149149
"wantsToInsert": "Roo quiere insertar contenido en este archivo:",
150150
"wantsToInsertWithLineNumber": "Roo quiere insertar contenido en este archivo en la línea {{lineNumber}}:",
151-
"wantsToInsertAtEnd": "Roo quiere añadir contenido al final de este archivo:"
151+
"wantsToInsertAtEnd": "Roo quiere añadir contenido al final de este archivo:",
152+
"wantsToReadAndXMore": "Roo quiere leer este archivo y {{count}} más:"
152153
},
153154
"directoryOperations": {
154155
"wantsToViewTopLevel": "Roo quiere ver los archivos de nivel superior en este directorio:",

webview-ui/src/i18n/locales/fr/chat.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,8 @@
145145
"didSearchReplace": "Roo a effectué une recherche et remplacement sur ce fichier :",
146146
"wantsToInsert": "Roo veut insérer du contenu dans ce fichier :",
147147
"wantsToInsertWithLineNumber": "Roo veut insérer du contenu dans ce fichier à la ligne {{lineNumber}} :",
148-
"wantsToInsertAtEnd": "Roo veut ajouter du contenu à la fin de ce fichier :"
148+
"wantsToInsertAtEnd": "Roo veut ajouter du contenu à la fin de ce fichier :",
149+
"wantsToReadAndXMore": "Roo veut lire ce fichier et {{count}} de plus :"
149150
},
150151
"instructions": {
151152
"wantsToFetch": "Roo veut récupérer des instructions détaillées pour aider à la tâche actuelle"

webview-ui/src/i18n/locales/hi/chat.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,8 @@
148148
"didSearchReplace": "Roo ने इस फ़ाइल में खोज और प्रतिस्थापन किया:",
149149
"wantsToInsert": "Roo इस फ़ाइल में सामग्री डालना चाहता है:",
150150
"wantsToInsertWithLineNumber": "Roo इस फ़ाइल की {{lineNumber}} लाइन पर सामग्री डालना चाहता है:",
151-
"wantsToInsertAtEnd": "Roo इस फ़ाइल के अंत में सामग्री जोड़ना चाहता है:"
151+
"wantsToInsertAtEnd": "Roo इस फ़ाइल के अंत में सामग्री जोड़ना चाहता है:",
152+
"wantsToReadAndXMore": "रू इस फ़ाइल को और {{count}} अन्य को पढ़ना चाहता है:"
152153
},
153154
"directoryOperations": {
154155
"wantsToViewTopLevel": "Roo इस निर्देशिका में शीर्ष स्तर की फ़ाइलें देखना चाहता है:",

0 commit comments

Comments
 (0)