fix(core): report truncated glob results (#38631)
This commit is contained in:
parent
6e4a972bb9
commit
c64d813347
2 changed files with 23 additions and 12 deletions
|
|
@ -25,11 +25,16 @@ export const Input = Schema.Struct({
|
||||||
})
|
})
|
||||||
|
|
||||||
export const Output = Schema.Array(FileSystem.Entry)
|
export const Output = Schema.Array(FileSystem.Entry)
|
||||||
type ModelOutput = typeof Output.Encoded
|
type EncodedOutput = typeof Output.Encoded
|
||||||
|
|
||||||
/** Format raw search results into the concise line-oriented output models expect. */
|
/** Format raw search results into the concise line-oriented output models expect. */
|
||||||
export const toModelOutput = (output: ModelOutput) => {
|
export const toModelContent = (entries: EncodedOutput, truncated = false) => {
|
||||||
const lines = output.length === 0 ? ["No files found"] : output.map((item) => item.path)
|
const lines = entries.length === 0 ? ["No files found"] : entries.map((item) => item.path)
|
||||||
|
if (truncated)
|
||||||
|
lines.push(
|
||||||
|
"",
|
||||||
|
`(Results are truncated: showing first ${entries.length} results. Consider using a more specific path or pattern.)`,
|
||||||
|
)
|
||||||
return lines.join("\n")
|
return lines.join("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -74,11 +79,12 @@ export const Plugin = {
|
||||||
Effect.fail(new ToolFailure({ message: `Search path does not exist: ${input.path ?? "."}` })),
|
Effect.fail(new ToolFailure({ message: `Search path does not exist: ${input.path ?? "."}` })),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
return yield* ripgrep
|
const limit = input.limit ?? FileSystem.DEFAULT_SEARCH_LIMIT
|
||||||
|
const entries = yield* ripgrep
|
||||||
.glob({
|
.glob({
|
||||||
cwd,
|
cwd,
|
||||||
pattern: input.pattern,
|
pattern: input.pattern,
|
||||||
limit: input.limit ?? FileSystem.DEFAULT_SEARCH_LIMIT,
|
limit: limit + 1,
|
||||||
})
|
})
|
||||||
.pipe(
|
.pipe(
|
||||||
Effect.map((result) =>
|
Effect.map((result) =>
|
||||||
|
|
@ -90,13 +96,15 @@ export const Plugin = {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
return { entries: entries.slice(0, limit), truncated: entries.length > limit }
|
||||||
}).pipe(
|
}).pipe(
|
||||||
Effect.map((output) => ({
|
Effect.map((result) => ({
|
||||||
output,
|
output: result.entries,
|
||||||
content: toModelOutput(
|
content: toModelContent(
|
||||||
output.map((entry) => ({ ...entry, path: path.resolve(location.directory, entry.path) })),
|
result.entries.map((entry) => ({ ...entry, path: path.resolve(location.directory, entry.path) })),
|
||||||
|
result.truncated,
|
||||||
),
|
),
|
||||||
metadata: { count: output.length },
|
metadata: { count: result.entries.length, truncated: result.truncated },
|
||||||
})),
|
})),
|
||||||
Effect.mapError((error) =>
|
Effect.mapError((error) =>
|
||||||
error instanceof ToolFailure
|
error instanceof ToolFailure
|
||||||
|
|
|
||||||
|
|
@ -86,13 +86,16 @@ describe("search tools", () => {
|
||||||
const glob = yield* executeTool(registry, call("glob", { pattern: "*" }))
|
const glob = yield* executeTool(registry, call("glob", { pattern: "*" }))
|
||||||
const grep = yield* executeTool(registry, call("grep", { pattern: "needle" }))
|
const grep = yield* executeTool(registry, call("grep", { pattern: "needle" }))
|
||||||
|
|
||||||
expect(glob.metadata).toEqual({ count: FileSystem.DEFAULT_SEARCH_LIMIT })
|
expect(glob.metadata).toEqual({ count: FileSystem.DEFAULT_SEARCH_LIMIT, truncated: true })
|
||||||
expect(grep.metadata).toEqual({ matches: FileSystem.DEFAULT_SEARCH_LIMIT })
|
expect(grep.metadata).toEqual({ matches: FileSystem.DEFAULT_SEARCH_LIMIT })
|
||||||
expect(glob.content).toHaveLength(1)
|
expect(glob.content).toHaveLength(1)
|
||||||
expect(grep.content).toHaveLength(1)
|
expect(grep.content).toHaveLength(1)
|
||||||
const globText = glob.content?.[0]?.type === "text" ? glob.content[0].text : ""
|
const globText = glob.content?.[0]?.type === "text" ? glob.content[0].text : ""
|
||||||
const grepText = grep.content?.[0]?.type === "text" ? grep.content[0].text : ""
|
const grepText = grep.content?.[0]?.type === "text" ? grep.content[0].text : ""
|
||||||
expect(globText.split("\n")).toHaveLength(FileSystem.DEFAULT_SEARCH_LIMIT)
|
expect(globText.split("\n")).toHaveLength(FileSystem.DEFAULT_SEARCH_LIMIT + 2)
|
||||||
|
expect(globText).toEndWith(
|
||||||
|
`(Results are truncated: showing first ${FileSystem.DEFAULT_SEARCH_LIMIT} results. Consider using a more specific path or pattern.)`,
|
||||||
|
)
|
||||||
expect(grepText).toStartWith(`Found ${FileSystem.DEFAULT_SEARCH_LIMIT} matches\n`)
|
expect(grepText).toStartWith(`Found ${FileSystem.DEFAULT_SEARCH_LIMIT} matches\n`)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue