from unittest.mock import MagicMock import pytest from api.command_utils import extract_filepaths_from_command from api.detection import ( is_filepath_extraction_request, is_suggestion_mode_request, ) from api.models.anthropic import Message, MessagesRequest def _mk_req(messages, tools=None, system=None): req = MagicMock(spec=MessagesRequest) req.messages = messages req.tools = tools req.system = system return req def _mk_msg(role: str, content): msg = MagicMock(spec=Message) msg.role = role msg.content = content return msg class TestSuggestionMode: def test_detects_suggestion_mode_in_any_user_message(self): req = _mk_req( [ _mk_msg("assistant", "ignore"), _mk_msg("user", "Hello\n[SUGGESTION MODE: on]\nworld"), ] ) assert is_suggestion_mode_request(req) is True def test_suggestion_mode_ignores_non_user_messages(self): req = _mk_req([_mk_msg("assistant", "[SUGGESTION MODE: on]")]) assert is_suggestion_mode_request(req) is False class TestFilepathExtractionDetection: def test_rejects_when_tools_present(self): msg = _mk_msg( "user", "Command: cat foo.txt\nOutput: hi\n\nPlease extract .", ) req = _mk_req([msg], tools=[{"name": "search"}]) ok, cmd, out = is_filepath_extraction_request(req) assert (ok, cmd, out) == (False, "", "") def test_rejects_when_missing_output_marker(self): msg = _mk_msg( "user", "Command: cat foo.txt\n(no output marker)\n", ) req = _mk_req([msg], tools=None) ok, cmd, out = is_filepath_extraction_request(req) assert (ok, cmd, out) == (False, "", "") def test_rejects_when_not_asking_for_filepaths(self): msg = _mk_msg("user", "Command: cat foo.txt\nOutput: hi") req = _mk_req([msg], tools=None) ok, cmd, out = is_filepath_extraction_request(req) assert (ok, cmd, out) == (False, "", "") def test_detects_filepath_extraction_via_system_block(self): """Command: + Output: in user, no filepaths in user; system has extract instructions.""" msg = _mk_msg("user", "Command: ls\nOutput: avazu-ctr\nfree-claude-code") req = _mk_req( [msg], tools=None, system="Extract any file paths that this command reads or modifies.", ) ok, cmd, out = is_filepath_extraction_request(req) assert ok is True assert cmd == "ls" assert "avazu-ctr" in out assert "free-claude-code" in out def test_extracts_command_and_output_and_cleans_output(self): msg = _mk_msg( "user", "Command: cat foo.txt\n" "Output: line1\nline2\n\n" "Please extract .\n" "ignore me", ) req = _mk_req([msg], tools=None) ok, cmd, out = is_filepath_extraction_request(req) assert ok is True assert cmd == "cat foo.txt" assert out == "line1\nline2" class TestExtractFilepathsFromCommand: @pytest.mark.parametrize( "command,expected_paths", [ ("ls -la", []), ("dir .", []), ("cat foo.txt", ["foo.txt"]), ("cat -n foo.txt bar.md", ["foo.txt", "bar.md"]), ("type C:\\tmp\\a.txt", ["C:\\tmp\\a.txt"]), ("grep pattern file1.txt file2.txt", ["file1.txt", "file2.txt"]), ("grep -n pattern file.txt", ["file.txt"]), ("grep -e pattern file.txt", ["file.txt"]), ("unknowncmd arg1 arg2", []), ("", []), ], ids=[ "listing_ls", "listing_dir", "read_cat", "read_cat_flags", "read_type_windows_path", "grep_simple", "grep_with_flag", "grep_with_e", "unknown", "empty", ], ) def test_extracts_expected_paths(self, command, expected_paths): result = extract_filepaths_from_command(command, output="(ignored)") for p in expected_paths: assert p in result if not expected_paths: assert result.strip() == "\n"