fix(search): honor directory filters without ripgrep

Signed-off-by: Rudy Celekli <47457359+rudycelekli@users.noreply.github.com>
This commit is contained in:
Rudy Celekli committed 2026-10-16 16:29:19 -04:00
1 parent d802eabaf6
commit cf10620cc2
2 files changed
+55

No files matched your search

+4
View File
@@ -523,6 +523,10 @@ class SearchFiles(BaseTool):
# ------------------------------------------------------------ grep backend
def _backend_grep(self, opts: "_SearchOptions") -> "_BackendResult":
# grep --include matches basenames, so a directory filter would silently
# return no matches. Reuse the path-aware fallback for these filters.
if "/" in opts.file_glob:
return self._backend_python(opts)
# -H forces filename even for a single-file target; -r recurses; -E = ERE
# (aligns alternation/quantifier syntax with rg). -n is added only in
# content mode — mixing it with -c/-l corrupts their output.
+51
View File
@@ -0,0 +1,51 @@
"""Exercise directory filters through the native grep-only tool entry point."""
import os
import shutil
import pytest
from agent.tools.search_files.search_files import SearchFiles
@pytest.fixture
def grep_tool(tmp_path, monkeypatch):
binary = shutil.which("grep")
if os.name == "nt" or not binary:
pytest.skip("native POSIX grep required")
source = tmp_path / "source"
source.mkdir()
for path in ["root.py", "src/direct.py", "src/nested/deep.py", "src/note.txt", "other/outside.py"]:
file = source / path
file.parent.mkdir(parents=True, exist_ok=True)
file.write_text("needle\nneedle again\n", encoding="utf-8")
bin_dir = tmp_path / "bin"
bin_dir.mkdir()
(bin_dir / "grep").symlink_to(binary)
monkeypatch.setenv("PATH", str(bin_dir))
tool = SearchFiles({"cwd": str(source)})
assert tool._pick_backend().__name__ == "_backend_grep"
return tool
@pytest.mark.parametrize("file_glob, expected", [
("src/*.py", ["src/direct.py"]),
("src/**/*.py", ["src/direct.py", "src/nested/deep.py"]),
("src/**/*.{py,txt}", ["src/direct.py", "src/nested/deep.py", "src/note.txt"]),
("missing/*.py", []),
("*.py", ["other/outside.py", "root.py", "src/direct.py", "src/nested/deep.py"]),
])
@pytest.mark.parametrize("mode", ["files", "content", "count"])
def test_grep_only_path_filter(grep_tool, file_glob, expected, mode):
result = grep_tool.execute({"pattern": "needle", "file_glob": file_glob, "output_mode": mode})
assert result.status == "success", result.result
data = result.result
if mode == "files":
actual = data["files"]
elif mode == "count":
actual = [row["file"] for row in data["counts"]]
assert all(row["count"] == 2 for row in data["counts"])
else:
actual = sorted({row["file"] for row in data["matches"]})
assert all(row["line"] in (1, 2) for row in data["matches"])
assert actual == expected