diff --git a/aider/coders/navigator_coder.py b/aider/coders/navigator_coder.py index 8f8dcb616..9893929ba 100644 --- a/aider/coders/navigator_coder.py +++ b/aider/coders/navigator_coder.py @@ -522,31 +522,31 @@ class NavigatorCoder(Coder): # Normalize tool name for case-insensitive matching norm_tool_name = tool_name.lower() - if norm_tool_name == 'glob': + if norm_tool_name == 'viewfilesatglob': pattern = params.get('pattern') if pattern is not None: - result_message = self._execute_glob(pattern) + result_message = self._execute_view_files_at_glob(pattern) else: - result_message = "Error: Missing 'pattern' parameter for Glob" - elif norm_tool_name == 'grep': + result_message = "Error: Missing 'pattern' parameter for ViewFilesAtGlob" + elif norm_tool_name == 'viewfilesmatching': pattern = params.get('pattern') file_pattern = params.get('file_pattern') # Optional if pattern is not None: - result_message = self._execute_grep(pattern, file_pattern) + result_message = self._execute_view_files_matching(pattern, file_pattern) else: - result_message = "Error: Missing 'pattern' parameter for Grep" + result_message = "Error: Missing 'pattern' parameter for ViewFilesMatching" elif norm_tool_name == 'ls': directory = params.get('directory') if directory is not None: result_message = self._execute_ls(directory) else: result_message = "Error: Missing 'directory' parameter for Ls" - elif norm_tool_name == 'add': + elif norm_tool_name == 'view': file_path = params.get('file_path') if file_path is not None: - result_message = self._execute_add(file_path) + result_message = self._execute_view(file_path) else: - result_message = "Error: Missing 'file_path' parameter for Add" + result_message = "Error: Missing 'file_path' parameter for View" elif norm_tool_name == 'remove': file_path = params.get('file_path') if file_path is not None: @@ -565,12 +565,12 @@ class NavigatorCoder(Coder): result_message = self._execute_make_readonly(file_path) else: result_message = "Error: Missing 'file_path' parameter for MakeReadonly" - elif norm_tool_name == 'find': + elif norm_tool_name == 'viewfileswithsymbol': symbol = params.get('symbol') if symbol is not None: - result_message = self._execute_find(symbol) + result_message = self._execute_view_files_with_symbol(symbol) else: - result_message = "Error: Missing 'symbol' parameter for Find" + result_message = "Error: Missing 'symbol' parameter for ViewFilesWithSymbol" elif norm_tool_name == 'command': command_string = params.get('command_string') if command_string is not None: @@ -916,10 +916,10 @@ Just reply with fixed versions of the {blocks} above that failed to match. return edited_files - def _execute_glob(self, pattern): + def _execute_view_files_at_glob(self, pattern): """ - Execute a glob pattern and add matching files to context. - + Execute a glob pattern and add matching files to context as read-only. + This tool helps the LLM find files by pattern matching, similar to how a developer would use glob patterns to find files. """ @@ -965,13 +965,13 @@ Just reply with fixed versions of the {blocks} above that failed to match. self.io.tool_output(f"⚠️ No files found matching '{pattern}'") return f"No files found matching '{pattern}'" except Exception as e: - self.io.tool_error(f"Error in glob: {str(e)}") + self.io.tool_error(f"Error in ViewFilesAtGlob: {str(e)}") return f"Error: {str(e)}" - - def _execute_grep(self, search_pattern, file_pattern=None): + + def _execute_view_files_matching(self, search_pattern, file_pattern=None): """ - Search for pattern in files and add matching files to context. - + Search for pattern in files and add matching files to context as read-only. + This tool lets the LLM search for content within files, mimicking how a developer would use grep to find relevant code. """ @@ -1034,9 +1034,9 @@ Just reply with fixed versions of the {blocks} above that failed to match. self.io.tool_output(f"⚠️ Pattern '{search_pattern}' not found in any files") return f"Pattern not found in any files" except Exception as e: - self.io.tool_error(f"Error in grep: {str(e)}") + self.io.tool_error(f"Error in ViewFilesMatching: {str(e)}") return f"Error: {str(e)}" - + def _execute_ls(self, dir_path): """ List files in directory and optionally add some to context. @@ -1083,27 +1083,28 @@ Just reply with fixed versions of the {blocks} above that failed to match. except Exception as e: self.io.tool_error(f"Error in ls: {str(e)}") return f"Error: {str(e)}" - - def _execute_add(self, file_path): + + def _execute_view(self, file_path): """ Explicitly add a file to context as read-only. - - This gives the LLM explicit control over what files to add, + + This gives the LLM explicit control over what files to view, rather than relying on indirect mentions. """ try: - return self._add_file_to_context(file_path, True) + # Use the helper, marking it as an explicit view request + return self._add_file_to_context(file_path, explicit=True) except Exception as e: - self.io.tool_error(f"Error adding file: {str(e)}") + self.io.tool_error(f"Error viewing file: {str(e)}") return f"Error: {str(e)}" - + def _add_file_to_context(self, file_path, explicit=False): """ Helper method to add a file to context as read-only. - + Parameters: - file_path: Path to the file to add - - explicit: Whether this was an explicit add command (vs. implicit through glob/grep) + - explicit: Whether this was an explicit view command (vs. implicit through ViewFilesAtGlob/ViewFilesMatching) """ # Check if file exists abs_path = self.abs_root_path(file_path) @@ -1144,22 +1145,22 @@ Just reply with fixed versions of the {blocks} above that failed to match. # Add to read-only files self.abs_read_only_fnames.add(abs_path) - + # Track in exploration set self.files_added_in_exploration.add(rel_path) - + # Inform user if explicit: - self.io.tool_output(f"📎 Added '{file_path}' to context as read-only") - return f"Added file to context as read-only" + self.io.tool_output(f"📎 Viewed '{file_path}' (added to context as read-only)") + return f"Viewed file (added to context as read-only)" else: - # For implicit adds (from glob/grep), just return success + # For implicit adds (from ViewFilesAtGlob/ViewFilesMatching), just return success return f"Added file to context as read-only" - + except Exception as e: - self.io.tool_error(f"Error adding file '{file_path}': {str(e)}") - return f"Error adding file: {str(e)}" - + self.io.tool_error(f"Error adding file '{file_path}' for viewing: {str(e)}") + return f"Error adding file for viewing: {str(e)}" + def _execute_make_editable(self, file_path): """ Convert a read-only file to an editable file. @@ -1266,17 +1267,17 @@ Just reply with fixed versions of the {blocks} above that failed to match. self.io.tool_error(f"Error removing file: {str(e)}") return f"Error: {str(e)}" - def _execute_find(self, symbol): + def _execute_view_files_with_symbol(self, symbol): """ Find files containing a specific symbol and add them to context as read-only. """ try: if not self.repo_map: - self.io.tool_output("⚠️ Repo map not available, cannot use Find tool.") + self.io.tool_output("⚠️ Repo map not available, cannot use ViewFilesWithSymbol tool.") return "Repo map not available" if not symbol: - return "Error: Missing 'symbol' parameter for Find" + return "Error: Missing 'symbol' parameter for ViewFilesWithSymbol" self.io.tool_output(f"🔎 Searching for symbol '{symbol}'...") found_files = set() @@ -1337,7 +1338,7 @@ Just reply with fixed versions of the {blocks} above that failed to match. return f"Symbol '{symbol}' not found in searchable files." except Exception as e: - self.io.tool_error(f"Error in find: {str(e)}") + self.io.tool_error(f"Error in ViewFilesWithSymbol: {str(e)}") return f"Error: {str(e)}" def _execute_command(self, command_string): @@ -1407,19 +1408,17 @@ Just reply with fixed versions of the {blocks} above that failed to match. # Get new files to add (not already in context) new_files = mentioned_files - current_files - # In navigator mode, we *only* add files via explicit tool commands. + # In navigator mode, we *only* add files via explicit tool commands (`View`, `ViewFilesAtGlob`, etc.). # Do nothing here for implicit mentions. pass - - - - + + def check_for_file_mentions(self, content): """ Override parent's method to use our own file processing logic. - + Override parent's method to disable implicit file mention handling in navigator mode. - Files should only be added via explicit tool commands (`Add`, `Glob`, `Grep`). + Files should only be added via explicit tool commands (`View`, `ViewFilesAtGlob`, `ViewFilesMatching`, `ViewFilesWithSymbol`). """ # Do nothing - disable implicit file adds in navigator mode. pass diff --git a/aider/coders/navigator_prompts.py b/aider/coders/navigator_prompts.py index 997dd49a4..9f2f8fd1d 100644 --- a/aider/coders/navigator_prompts.py +++ b/aider/coders/navigator_prompts.py @@ -31,23 +31,23 @@ Act as an expert software engineer with the ability to autonomously navigate and ## Available Tools ### File Discovery Tools -- **Glob**: `[tool_call(Glob, pattern="**/*.py")]` +- **ViewFilesAtGlob**: `[tool_call(ViewFilesAtGlob, pattern="**/*.py")]` Find files matching a glob pattern and add them to context as read-only. Supports patterns like "src/**/*.ts" or "*.json". -- **Grep**: `[tool_call(Grep, pattern="class User", file_pattern="*.py")]` +- **ViewFilesMatching**: `[tool_call(ViewFilesMatching, pattern="class User", file_pattern="*.py")]` Search for text in files and add matching files to context as read-only. Files with more matches are prioritized. `file_pattern` is optional. - **Ls**: `[tool_call(Ls, directory="src/components")]` List files in a directory. Useful for exploring the project structure. -- **Find**: `[tool_call(Find, symbol="my_function")]` +- **ViewFilesWithSymbol**: `[tool_call(ViewFilesWithSymbol, symbol="my_function")]` Find files containing a specific symbol (function, class, variable) and add them to context as read-only. Leverages the repo map for accurate symbol lookup. ### Context Management Tools -- **Add**: `[tool_call(Add, file_path="src/main.py")]` +- **View**: `[tool_call(View, file_path="src/main.py")]` Explicitly add a specific file to context as read-only. - **Remove**: `[tool_call(Remove, file_path="tests/old_test.py")]` @@ -104,8 +104,8 @@ When you include any tool call, the system will automatically continue to the ne ## Navigation Workflow ### Exploration Strategy -1. **Initial Discovery**: Use `Glob`, `Grep`, `Ls`, or `Find` to identify relevant files -2. **Focused Investigation**: Add promising files to context with `Add` +1. **Initial Discovery**: Use `ViewFilesAtGlob`, `ViewFilesMatching`, `Ls`, or `ViewFilesWithSymbol` to identify relevant files +2. **Focused Investigation**: Add promising files to context with `View` 3. **Context Management**: Remove irrelevant files with `Remove` to maintain focus 4. **Preparation for Editing**: Convert files to editable with `MakeEditable` when needed 5. **Continued Exploration**: Include any tool call to automatically continue to the next round @@ -114,16 +114,16 @@ When you include any tool call, the system will automatically continue to the ne ### Tool Usage Best Practices - Use the exact syntax `[tool_call(ToolName, param1=value1, param2="value2")]` for execution - Tool names are case-insensitive; parameters can be unquoted or quoted -- Verify files aren't already in context before adding them -- Use precise grep patterns with file_pattern to narrow search scope +- Verify files aren't already in context before adding them with `View` +- Use precise search patterns with `ViewFilesMatching` and `file_pattern` to narrow scope - Target specific patterns rather than overly broad searches -- Remember the `Find` tool is optimized for locating symbols across the codebase +- Remember the `ViewFilesWithSymbol` tool is optimized for locating symbols across the codebase ## Granular Editing Workflow **Note on Sequential Edits:** Tool calls within a single message execute sequentially. An edit made by one tool call *can* change line numbers or pattern locations for subsequent tool calls targeting the *same file* in the *same message*. Always check the result message and diff snippet after each edit. -1. **Discover and Add Files**: Use Glob, Grep, Find to locate relevant files. +1. **Discover and View Files**: Use `ViewFilesAtGlob`, `ViewFilesMatching`, `ViewFilesWithSymbol` to locate relevant files. Use `View` to add specific files. 2. **Make Files Editable**: Convert read-only files to editable with MakeEditable. 3. **Apply Edits (Default: Direct Edit)**: * For most edits where you are confident in the parameters (file path, patterns, line numbers), apply the change directly using the tool with `dry_run=False` (or omitting the parameter). @@ -255,19 +255,19 @@ Always reply to the user in {language}. role="assistant", content="""I'll help you understand the authentication system in this project. Let me explore the codebase first to find all relevant files. -[tool_call(Grep, pattern="login|auth|password|session", file_pattern="*.py")]""", +[tool_call(ViewFilesMatching, pattern="login|auth|password|session", file_pattern="*.py")]""", ), dict( role="user", - content="[Result (Grep): Found in 3 files: auth/models.py (12 matches), auth/views.py (8 matches), users/authentication.py (5 matches)]", + content="[Result (ViewFilesMatching): Found in 3 files: auth/models.py (12 matches), auth/views.py (8 matches), users/authentication.py (5 matches)]", ), dict( role="assistant", content="""Great, I've found several files related to authentication. Let me examine them to understand the login flow. -[tool_call(Add, file_path="auth/models.py")] -[tool_call(Add, file_path="auth/views.py")] -[tool_call(Add, file_path="users/authentication.py")]""", +[tool_call(View, file_path="auth/models.py")] +[tool_call(View, file_path="auth/views.py")] +[tool_call(View, file_path="users/authentication.py")]""", ), dict( role="user", @@ -306,11 +306,11 @@ Trust this message as the true contents of the files! files_no_full_files_with_repo_map = """ I have access to a map of the repository with summary information about files, but I don't have the complete content of any files yet. -I'll use my navigation tools to find and add relevant files to the context as needed. +I'll use my navigation tools (`ViewFilesAtGlob`, `ViewFilesMatching`, `ViewFilesWithSymbol`, `View`) to find and add relevant files to the context as needed. """ - files_no_full_files_with_repo_map_reply = """I understand. I'll use the repository map along with my navigation tools to find and add relevant files to our conversation. + files_no_full_files_with_repo_map_reply = """I understand. I'll use the repository map along with my navigation tools (`ViewFilesAtGlob`, `ViewFilesMatching`, `ViewFilesWithSymbol`, `View`) to find and add relevant files to our conversation. """ repo_content_prefix = """