From c64d8133472dabea41491595bb5fb436ae18c859 Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Fri, 24 Jul 2026 10:17:37 -0500 Subject: [PATCH] fix(core): report truncated glob results (#38631) --- packages/core/src/tool/glob.ts | 28 +++++++++++++++++--------- packages/core/test/tool-search.test.ts | 7 +++++-- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/packages/core/src/tool/glob.ts b/packages/core/src/tool/glob.ts index 50ef6853942..3da274fcf10 100644 --- a/packages/core/src/tool/glob.ts +++ b/packages/core/src/tool/glob.ts @@ -25,11 +25,16 @@ export const Input = Schema.Struct({ }) 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. */ -export const toModelOutput = (output: ModelOutput) => { - const lines = output.length === 0 ? ["No files found"] : output.map((item) => item.path) +export const toModelContent = (entries: EncodedOutput, truncated = false) => { + 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") } @@ -74,11 +79,12 @@ export const Plugin = { 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({ cwd, pattern: input.pattern, - limit: input.limit ?? FileSystem.DEFAULT_SEARCH_LIMIT, + limit: limit + 1, }) .pipe( Effect.map((result) => @@ -90,13 +96,15 @@ export const Plugin = { ), ), ) + return { entries: entries.slice(0, limit), truncated: entries.length > limit } }).pipe( - Effect.map((output) => ({ - output, - content: toModelOutput( - output.map((entry) => ({ ...entry, path: path.resolve(location.directory, entry.path) })), + Effect.map((result) => ({ + output: result.entries, + content: toModelContent( + 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) => error instanceof ToolFailure diff --git a/packages/core/test/tool-search.test.ts b/packages/core/test/tool-search.test.ts index 9958b0dfb4b..7f924a94dd1 100644 --- a/packages/core/test/tool-search.test.ts +++ b/packages/core/test/tool-search.test.ts @@ -86,13 +86,16 @@ describe("search tools", () => { const glob = yield* executeTool(registry, call("glob", { pattern: "*" })) 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(glob.content).toHaveLength(1) expect(grep.content).toHaveLength(1) const globText = glob.content?.[0]?.type === "text" ? glob.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`) }), )