fix(core): bound default search results - #37154
Merged
Merged
Conversation
This was referenced Jul 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Give V2 filesystem
globandgrepsearches the same 100-result default bound as V1 when callers omitlimit.The audit found both model-facing search tools had the same unbounded fallback. Other built-in tools already have concrete capture limits:
readbounds lines and bytes,shellbounds captured output, andwebfetch/websearchbound response sizes.Before / After
Before: A model could call
globorgrepwithoutlimit. The tool translated that omission toNumber.MAX_SAFE_INTEGER, and the ripgrep adapter collected matching rows in memory. A broad search over a large worktree could therefore retain millions of paths or matches, exhaust process memory, and leave the tool call running indefinitely.After: Omitted limits resolve to 100 before either ripgrep or fff executes. Ripgrep's existing
take(limit + 1)boundary stops collection and terminates the scoped subprocess once the bounded result is known.How
packages/core/src/filesystem.tsdefines the sharedDEFAULT_SEARCH_LIMIT.packages/core/src/tool/glob.tsandpackages/core/src/tool/grep.tsapply and advertise that default for model calls.packages/core/src/filesystem/search.tsapplies the same default in both ripgrep and fff service implementations so non-tool consumers cannot recover the unbounded omission behavior.packages/core/test/tool-search.test.tsexecutes both real registered tools against 101 matches and verifies omitted limits settle with 100 structured results.Scope
This does not change explicit caller-supplied limits or the Location file indexer, whose catch-all scan deliberately uses separate indexing behavior. It does not modify V1, which already hard-codes a 100-result bound for both tools.
Testing
cd packages/core && bun run test test/tool-search.test.ts(3 passed)cd packages/core && bun run test(1,292 passed, 6 skipped)cd packages/core && bun run typecheckbun turbo typecheck --concurrency=3(32 packages passed)bun run prettier --check packages/core/src/filesystem.ts packages/core/src/filesystem/search.ts packages/core/src/tool/glob.ts packages/core/src/tool/grep.ts packages/core/test/tool-search.test.tsbun run lint(passes with existing repository warnings)bun run lint:effect-patternsremains blocked by seven pre-existing findings outside this diff