Skip to content

Commit 667838e

Browse files
committed
Update sdk code_search impl to limit results per file and globally
1 parent aad6b70 commit 667838e

File tree

1 file changed

+98
-15
lines changed

1 file changed

+98
-15
lines changed

sdk/src/tools/code-search.ts

Lines changed: 98 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,17 @@ export function codeSearch({
1111
pattern,
1212
flags,
1313
cwd,
14-
maxResults = 30,
14+
maxResults = 15,
15+
globalMaxResults = 250,
16+
maxOutputStringLength = 20_000,
1517
}: {
1618
projectPath: string
1719
pattern: string
1820
flags?: string
1921
cwd?: string
2022
maxResults?: number
23+
globalMaxResults?: number
24+
maxOutputStringLength?: number
2125
}): Promise<CodebuffToolOutput<'code_search'>> {
2226
return new Promise((resolve) => {
2327
let stdout = ''
@@ -59,27 +63,106 @@ export function codeSearch({
5963
})
6064

6165
childProcess.on('close', (code) => {
62-
// Limit results to maxResults
63-
const lines = stdout.split('\n')
64-
const limitedLines = lines.slice(0, maxResults)
65-
const limitedStdout = limitedLines.join('\n')
66-
const formattedStdout = formatCodeSearchOutput(limitedStdout)
66+
const lines = stdout.split('\n').filter((line) => line.trim())
67+
68+
// Group results by file
69+
const fileGroups = new Map<string, string[]>()
70+
let currentFile: string | null = null
71+
72+
for (const line of lines) {
73+
// Ripgrep output format: filename:line_number:content or filename:content
74+
const colonIndex = line.indexOf(':')
75+
if (colonIndex === -1) {
76+
// This shouldn't happen with standard ripgrep output
77+
if (currentFile) {
78+
fileGroups.get(currentFile)!.push(line)
79+
}
80+
continue
81+
}
82+
83+
const filename = line.substring(0, colonIndex)
84+
85+
// Check if this is a new file
86+
if (filename && !filename.includes('\t') && !filename.startsWith(' ')) {
87+
currentFile = filename
88+
if (!fileGroups.has(currentFile)) {
89+
fileGroups.set(currentFile, [])
90+
}
91+
fileGroups.get(currentFile)!.push(line)
92+
} else if (currentFile) {
93+
// Continuation of previous result
94+
fileGroups.get(currentFile)!.push(line)
95+
}
96+
}
97+
98+
// Limit results per file and globally
99+
const limitedLines: string[] = []
100+
let totalOriginalCount = 0
101+
let totalLimitedCount = 0
102+
const truncatedFiles: string[] = []
103+
let globalLimitReached = false
104+
const skippedFiles: string[] = []
105+
106+
for (const [filename, fileLines] of fileGroups) {
107+
totalOriginalCount += fileLines.length
108+
109+
// Check if we've hit the global limit
110+
if (totalLimitedCount >= globalMaxResults) {
111+
globalLimitReached = true
112+
skippedFiles.push(filename)
113+
continue
114+
}
115+
116+
// Calculate how many results we can take from this file
117+
const remainingGlobalSpace = globalMaxResults - totalLimitedCount
118+
const resultsToTake = Math.min(
119+
maxResults,
120+
fileLines.length,
121+
remainingGlobalSpace,
122+
)
123+
const limited = fileLines.slice(0, resultsToTake)
124+
totalLimitedCount += limited.length
125+
limitedLines.push(...limited)
126+
127+
if (fileLines.length > resultsToTake) {
128+
truncatedFiles.push(
129+
`${filename}: ${fileLines.length} results (showing ${resultsToTake})`,
130+
)
131+
}
132+
}
133+
134+
let limitedStdout = limitedLines.join('\n')
67135

68136
// Add truncation message if results were limited
69-
const finalStdout =
70-
lines.length > maxResults
71-
? formattedStdout +
72-
`\n\n[Results limited to ${maxResults} of ${lines.length} total matches]`
73-
: formattedStdout
137+
const truncationMessages: string[] = []
138+
139+
if (truncatedFiles.length > 0) {
140+
truncationMessages.push(
141+
`Results limited to ${maxResults} per file. Truncated files:\n${truncatedFiles.join('\n')}`,
142+
)
143+
}
144+
145+
if (globalLimitReached) {
146+
truncationMessages.push(
147+
`Global limit of ${globalMaxResults} results reached. ${skippedFiles.length} file(s) skipped:\n${skippedFiles.join('\n')}`,
148+
)
149+
}
150+
151+
if (truncationMessages.length > 0) {
152+
limitedStdout += `\n\n[${truncationMessages.join('\n\n')}]`
153+
}
154+
155+
const formattedStdout = formatCodeSearchOutput(limitedStdout)
156+
const finalStdout = formattedStdout
74157

75158
// Truncate output to prevent memory issues
76-
const maxLength = 10000
77159
const truncatedStdout =
78-
finalStdout.length > maxLength
79-
? finalStdout.substring(0, maxLength) + '\n\n[Output truncated]'
160+
finalStdout.length > maxOutputStringLength
161+
? finalStdout.substring(0, maxOutputStringLength) +
162+
'\n\n[Output truncated]'
80163
: finalStdout
81164

82-
const maxErrorLength = 1000
165+
const maxErrorLength = maxOutputStringLength / 5
83166
const truncatedStderr =
84167
stderr.length > maxErrorLength
85168
? stderr.substring(0, maxErrorLength) + '\n\n[Error output truncated]'

0 commit comments

Comments
 (0)