Skip to content

Commit 3fb0360

Browse files
authored
fixing ripgrep overload - tool should not return more than 0.25mb max… (RooCodeInc#3967)
* fixing ripgrep overload - tool should not return more than 0.25mb max, but it can easily return more than 9mb in some cases * changeset
1 parent 084c0a7 commit 3fb0360

File tree

2 files changed

+97
-8
lines changed

2 files changed

+97
-8
lines changed

.changeset/healthy-ties-kneel.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"claude-dev": patch
3+
---
4+
5+
Fixed search tool overloading conversation with massive outputs by setting a maximum overall byte limit for search tool responses

src/services/ripgrep/index.ts

Lines changed: 92 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,9 @@ export async function regexSearchFiles(
181181
return formatResults(filteredResults, cwd)
182182
}
183183

184+
const MAX_RIPGREP_MB = 0.25
185+
const MAX_BYTE_SIZE = MAX_RIPGREP_MB * 1024 * 1024 // 0./25MB in bytes
186+
184187
function formatResults(results: SearchResult[], cwd: string): string {
185188
const groupedResults: { [key: string]: SearchResult[] } = {}
186189

@@ -200,21 +203,102 @@ function formatResults(results: SearchResult[], cwd: string): string {
200203
groupedResults[relativeFilePath].push(result)
201204
})
202205

206+
// Track byte size
207+
let byteSize = Buffer.byteLength(output, "utf8")
208+
let wasLimitReached = false
209+
203210
for (const [filePath, fileResults] of Object.entries(groupedResults)) {
204-
output += `${filePath.toPosix()}\n│----\n`
211+
// Check if adding this file's path would exceed the byte limit
212+
const filePathString = `${filePath.toPosix()}\n│----\n`
213+
const filePathBytes = Buffer.byteLength(filePathString, "utf8")
214+
215+
if (byteSize + filePathBytes >= MAX_BYTE_SIZE) {
216+
wasLimitReached = true
217+
break
218+
}
205219

206-
fileResults.forEach((result, index) => {
220+
output += filePathString
221+
byteSize += filePathBytes
222+
223+
for (let resultIndex = 0; resultIndex < fileResults.length; resultIndex++) {
224+
const result = fileResults[resultIndex]
207225
const allLines = [...result.beforeContext, result.match, ...result.afterContext]
208-
allLines.forEach((line) => {
209-
output += `│${line?.trimEnd() ?? ""}\n`
226+
227+
// Calculate bytes in all lines for this result
228+
let resultBytes = 0
229+
const resultLines: string[] = []
230+
231+
for (const line of allLines) {
232+
const trimmedLine = line?.trimEnd() ?? ""
233+
const lineString = `│${trimmedLine}\n`
234+
const lineBytes = Buffer.byteLength(lineString, "utf8")
235+
236+
// Check if adding this line would exceed the byte limit
237+
if (byteSize + resultBytes + lineBytes >= MAX_BYTE_SIZE) {
238+
wasLimitReached = true
239+
break
240+
}
241+
242+
resultLines.push(lineString)
243+
resultBytes += lineBytes
244+
}
245+
246+
// If we hit the limit in the middle of processing lines, break out of the result loop
247+
if (wasLimitReached) {
248+
break
249+
}
250+
251+
// Add all lines for this result to the output
252+
resultLines.forEach((line) => {
253+
output += line
210254
})
255+
byteSize += resultBytes
256+
257+
// Add separator between results if needed
258+
if (resultIndex < fileResults.length - 1) {
259+
const separatorString = "│----\n"
260+
const separatorBytes = Buffer.byteLength(separatorString, "utf8")
211261

212-
if (index < fileResults.length - 1) {
213-
output += "│----\n"
262+
if (byteSize + separatorBytes >= MAX_BYTE_SIZE) {
263+
wasLimitReached = true
264+
break
265+
}
266+
267+
output += separatorString
268+
byteSize += separatorBytes
214269
}
215-
})
216270

217-
output += "│----\n\n"
271+
// Check if we've hit the byte limit
272+
if (byteSize >= MAX_BYTE_SIZE) {
273+
wasLimitReached = true
274+
break
275+
}
276+
}
277+
278+
// If we hit the limit, break out of the file loop
279+
if (wasLimitReached) {
280+
break
281+
}
282+
283+
const closingString = "│----\n\n"
284+
const closingBytes = Buffer.byteLength(closingString, "utf8")
285+
286+
if (byteSize + closingBytes >= MAX_BYTE_SIZE) {
287+
wasLimitReached = true
288+
break
289+
}
290+
291+
output += closingString
292+
byteSize += closingBytes
293+
}
294+
295+
// Add a message if we hit the byte limit
296+
if (wasLimitReached) {
297+
const truncationMessage = `\n[Results truncated due to exceeding the ${MAX_RIPGREP_MB}MB size limit. Please use a more specific search pattern.]`
298+
// Only add the message if it fits within the limit
299+
if (byteSize + Buffer.byteLength(truncationMessage, "utf8") < MAX_BYTE_SIZE) {
300+
output += truncationMessage
301+
}
218302
}
219303

220304
return output.trim()

0 commit comments

Comments
 (0)