Skip to content

Commit 62e5b22

Browse files
committed
read subtree: accept path with trailing '/'
1 parent 68d3240 commit 62e5b22

File tree

2 files changed

+82
-1
lines changed

2 files changed

+82
-1
lines changed

packages/agent-runtime/src/tools/handlers/__tests__/read-subtree.test.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,84 @@ describe('handleReadSubtree', () => {
211211
expect(dirEntry!.printedTree).toContain('myClass')
212212
})
213213

214+
it('resolves directory paths with trailing slashes', async () => {
215+
const fileContext = buildMockFileContext()
216+
const logger = createLogger()
217+
218+
const toolCall: CodebuffToolCall<'read_subtree'> = {
219+
toolName: 'read_subtree',
220+
toolCallId: 'tc-trailing-slash',
221+
input: { paths: ['src/'], maxTokens: 50000 },
222+
}
223+
224+
const { output } = await handleReadSubtree({
225+
previousToolCallFinished: Promise.resolve(),
226+
toolCall,
227+
fileContext,
228+
logger,
229+
})
230+
231+
expect(output[0].type).toBe('json')
232+
const value = output[0].value as ReadSubtreeResultEntry[]
233+
const dirEntry = value.find(
234+
(v) => v.type === 'directory' && v.path === 'src',
235+
)
236+
expect(dirEntry).toBeTruthy()
237+
expect(dirEntry!.printedTree).toContain('index.ts')
238+
})
239+
240+
it('resolves nested directory paths with trailing slashes', async () => {
241+
const fileContext = buildMockFileContext()
242+
const logger = createLogger()
243+
244+
fileContext.fileTree = [
245+
{
246+
name: 'packages',
247+
type: 'directory',
248+
filePath: 'packages',
249+
children: [
250+
{
251+
name: 'backend',
252+
type: 'directory',
253+
filePath: 'packages/backend',
254+
children: [
255+
{
256+
name: 'index.ts',
257+
type: 'file',
258+
filePath: 'packages/backend/index.ts',
259+
lastReadTime: 0,
260+
},
261+
],
262+
},
263+
],
264+
},
265+
]
266+
fileContext.fileTokenScores = {
267+
'packages/backend/index.ts': { myFunction: 5.0 },
268+
}
269+
270+
const toolCall: CodebuffToolCall<'read_subtree'> = {
271+
toolName: 'read_subtree',
272+
toolCallId: 'tc-nested-trailing-slash',
273+
input: { paths: ['packages/backend/'], maxTokens: 50000 },
274+
}
275+
276+
const { output } = await handleReadSubtree({
277+
previousToolCallFinished: Promise.resolve(),
278+
toolCall,
279+
fileContext,
280+
logger,
281+
})
282+
283+
expect(output[0].type).toBe('json')
284+
const value = output[0].value as ReadSubtreeResultEntry[]
285+
const dirEntry = value.find(
286+
(v) => v.type === 'directory' && v.path === 'packages/backend',
287+
)
288+
expect(dirEntry).toBeTruthy()
289+
expect(dirEntry!.printedTree).toContain('myFunction')
290+
})
291+
214292
it('honors maxTokens by reducing token count under a tiny budget', async () => {
215293
const fileContext = buildMockFileContext()
216294
const logger = createLogger()

packages/agent-runtime/src/tools/handlers/tool/read-subtree.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,10 @@ export const handleReadSubtree = (async (params: {
112112
| { path: string; errorMessage: string }
113113
> = []
114114

115-
for (const p of requested) {
115+
for (const rawPath of requested) {
116+
// Strip trailing slashes so paths like 'src/' resolve to 'src'
117+
const p = rawPath.replace(/\/+$/, '')
118+
116119
if (p === '.' || p === '/' || p === '') {
117120
outputs.push(buildDirectoryResult(fileContext.fileTree, p))
118121
continue

0 commit comments

Comments
 (0)