diff --git a/libs/partners/anthropic/langchain_anthropic/middleware/file_search.py b/libs/partners/anthropic/langchain_anthropic/middleware/file_search.py index 775e251124..23b4299738 100644 --- a/libs/partners/anthropic/langchain_anthropic/middleware/file_search.py +++ b/libs/partners/anthropic/langchain_anthropic/middleware/file_search.py @@ -299,7 +299,11 @@ class StateFileSearchMiddleware(AgentMiddleware): results: dict[str, list[tuple[int, str]]] = {} for file_path, file_data in files.items(): - if not file_path.startswith(base_path): + if ( + base_path != "/" # noqa: PLR1714 + and file_path != base_path + and not file_path.startswith(base_path + "/") + ): continue # Check include filter diff --git a/libs/partners/anthropic/tests/unit_tests/middleware/test_file_search.py b/libs/partners/anthropic/tests/unit_tests/middleware/test_file_search.py index 1c1319961d..35e017f8ee 100644 --- a/libs/partners/anthropic/tests/unit_tests/middleware/test_file_search.py +++ b/libs/partners/anthropic/tests/unit_tests/middleware/test_file_search.py @@ -400,6 +400,38 @@ class TestFilesystemGrepSearch: assert "/src/main.py" in result assert "/tests/test.py" not in result + def test_grep_excludes_sibling_directory(self) -> None: + """Test grep scoped to a path excludes sibling directories sharing a prefix.""" + middleware = StateFileSearchMiddleware() + + state: AnthropicToolsState = { + "messages": [], + "text_editor_files": { + "/app/config.txt": { + "content": ["service=web"], + "created_at": "2025-01-01T00:00:00", + "modified_at": "2025-01-01T00:00:00", + }, + "/app-secret/creds.txt": { + "content": ["password=SIBLING-LEAK"], + "created_at": "2025-01-01T00:00:00", + "modified_at": "2025-01-01T00:00:00", + }, + }, + } + + result = middleware._handle_grep_search( + pattern="password|service", + path="/app", + include=None, + output_mode="files_with_matches", + state=state, + ) + + assert isinstance(result, str) + assert "/app/config.txt" in result + assert "/app-secret/creds.txt" not in result + def test_grep_no_matches(self) -> None: """Test grep with no matching content.""" middleware = StateFileSearchMiddleware()