From f7b0192b07e83f9d7fd80519334e4e06f50fdc88 Mon Sep 17 00:00:00 2001 From: Dustin Washington Date: Sat, 22 Nov 2025 09:21:05 -0500 Subject: [PATCH 1/8] Bump Version --- aider/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aider/__init__.py b/aider/__init__.py index ebf15deb00b..2c48bccaf57 100644 --- a/aider/__init__.py +++ b/aider/__init__.py @@ -1,6 +1,6 @@ from packaging import version -__version__ = "0.88.26.dev" +__version__ = "0.88.27.dev" safe_version = __version__ try: From 4774137b4e0ad78c4c50951214498cec7dff8f52 Mon Sep 17 00:00:00 2001 From: Dustin Washington Date: Sat, 22 Nov 2025 12:18:35 -0500 Subject: [PATCH 2/8] Cache system prompts with LiteLLM automatic injection when available --- README.md | 1 + aider/models.py | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/README.md b/README.md index 5055872a2bb..8209c762611 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ analytics: false auto-commits: true auto-save: true auto-load: true +cache-prompts: true check-update: true debug: false enable-context-compaction: true diff --git a/aider/models.py b/aider/models.py index de6ccd0946e..652061551b9 100644 --- a/aider/models.py +++ b/aider/models.py @@ -977,6 +977,14 @@ async def send_completion( dump(kwargs) kwargs["messages"] = messages + # Cache System Prompts When Possible + kwargs["cache_control_injection_points"] = [ + { + "location": "message", + "role": "system", + } + ] + # Are we using github copilot? if "GITHUB_COPILOT_TOKEN" in os.environ or self.name.startswith("github_copilot/"): if "extra_headers" not in kwargs: From dc5135676a5a782659e6c8f0dce0d5b6950e823b Mon Sep 17 00:00:00 2001 From: Dustin Washington Date: Sat, 22 Nov 2025 12:49:10 -0500 Subject: [PATCH 3/8] #180: Don't print git erros to screen outside of verbose mode for non-repos --- aider/coders/base_coder.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/aider/coders/base_coder.py b/aider/coders/base_coder.py index 5617b86831c..0b5b0a1cf2a 100755 --- a/aider/coders/base_coder.py +++ b/aider/coders/base_coder.py @@ -892,7 +892,8 @@ def get_repo_map(self, force_refresh=False): ) except ANY_GIT_ERROR as err: # Handle git errors gracefully - use a fallback hash - self.io.tool_warning(f"Git error while checking staged files for repo map: {err}") + if self.verbose: + self.io.tool_warning(f"Git error while checking staged files for repo map: {err}") staged_files_hash = hash(str(time.time())) # Use timestamp as fallback read_only_count = len(set(self.abs_read_only_fnames)) + len( @@ -3382,7 +3383,8 @@ def get_all_relative_files(self): return self.data_cache["relative_files"] except ANY_GIT_ERROR as err: # Handle git errors gracefully - fall back to getting tracked files - self.io.tool_warning(f"Git error while checking staged files: {err}") + if self.verbose: + self.io.tool_warning(f"Git error while checking staged files: {err}") # Continue to get tracked files normally if self.repo: From 1330e0f24e6539733911da18d34288b88a4d74d8 Mon Sep 17 00:00:00 2001 From: Dustin Washington Date: Sat, 22 Nov 2025 15:51:18 -0500 Subject: [PATCH 4/8] Run save session in a background thread way less frequently (once every 15 seconds) --- aider/coders/agent_coder.py | 2 +- aider/coders/base_coder.py | 29 +++++++++++++++++++---------- aider/main.py | 3 +++ 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/aider/coders/agent_coder.py b/aider/coders/agent_coder.py index 596c6c28f6e..c613d045184 100644 --- a/aider/coders/agent_coder.py +++ b/aider/coders/agent_coder.py @@ -946,7 +946,7 @@ async def process_tool_calls(self, tool_call_response): Track tool usage before calling the base implementation. """ self.agent_finished = False - self.auto_save_session() + await self.auto_save_session() if self.partial_response_tool_calls: for tool_call in self.partial_response_tool_calls: diff --git a/aider/coders/base_coder.py b/aider/coders/base_coder.py index 0b5b0a1cf2a..64282ad9c84 100755 --- a/aider/coders/base_coder.py +++ b/aider/coders/base_coder.py @@ -1146,7 +1146,7 @@ async def _run_linear(self, with_message=None, preproc=True): self.io.tool_output("Finished.") self.io.ring_bell() user_message = None - self.auto_save_session() + await self.auto_save_session() except KeyboardInterrupt: if self.io.input_task: @@ -1222,7 +1222,7 @@ async def _run_parallel(self, with_message=None, preproc=True): # Ensure IO tasks are properly cancelled await self.io.cancel_task_streams() - self.auto_save_session() + await self.auto_save_session() except EOFError: return finally: @@ -1249,7 +1249,7 @@ async def input_task(self, preproc): if not self.io.acknowledge_confirmation(): if user_message: self.user_message = user_message - self.auto_save_session() + await self.auto_save_session() else: self.user_message = "" await self.io.cancel_task_streams() @@ -1326,7 +1326,7 @@ async def output_task(self, preproc): # Stop spinner when processing task completes self.io.stop_spinner() - self.auto_save_session() + await self.auto_save_session() await asyncio.sleep(0.01) # Small yield to prevent tight loop except KeyboardInterrupt: @@ -2008,7 +2008,7 @@ async def check_tokens(self, messages): " the context limit is exceeded." ) - if not await self.io.confirm_ask("Try to proceed anyway?"): + if not await self.io.confirm_ask("Try to proceed anyway?", explicit_yes_required=True): return False return True @@ -3693,7 +3693,7 @@ def apply_edits(self, edits): def apply_edits_dry_run(self, edits): return edits - def auto_save_session(self): + async def auto_save_session(self): """Automatically save the current session as 'auto-save'.""" if not getattr(self.args, "auto_save", False): return @@ -3702,13 +3702,22 @@ def auto_save_session(self): if not hasattr(self, "_last_autosave_time"): self._last_autosave_time = 0 - # Throttle autosave to run at most once per second + if not hasattr(self, "_autosave_future"): + self._autosave_future = None + + if self._autosave_future and self._autosave_future.done(): + return + + # Throttle autosave to run at most once every 15 seconds current_time = time.time() - if current_time - self._last_autosave_time >= 1.0: + if current_time - self._last_autosave_time >= 15.0: try: - session_manager = SessionManager(self, self.io) - session_manager.save_session("auto-save", False) self._last_autosave_time = current_time + session_manager = SessionManager(self, self.io) + loop = asyncio.get_running_loop() + self._autosave_future = loop.run_in_executor( + None, session_manager.save_session, "auto-save", False + ) except Exception: # Don't show errors for auto-save to avoid interrupting the user experience pass diff --git a/aider/main.py b/aider/main.py index 18cdc6162a4..eb6ca8f80c4 100644 --- a/aider/main.py +++ b/aider/main.py @@ -1420,6 +1420,9 @@ def load_slow_imports(swallow=True): async def graceful_exit(coder=None, exit_code=0): if coder: + if hasattr(coder, "_autosave_future"): + await coder._autosave_future + for server in coder.mcp_servers: try: await server.exit_stack.aclose() From 818e121aa01758d195cbb8fc349809df76a7823f Mon Sep 17 00:00:00 2001 From: Dustin Washington Date: Sat, 22 Nov 2025 16:15:52 -0500 Subject: [PATCH 5/8] #181: Close on blank prompt to mimic ctrl+d for shells --- aider/io.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/aider/io.py b/aider/io.py index 1183a946f68..47cc6caff5e 100644 --- a/aider/io.py +++ b/aider/io.py @@ -697,9 +697,13 @@ def reject_outstanding_confirmations(self): # This method is now a no-op since we removed the confirmation_future logic pass + def get_coder(self): + coder = self.coder() if self.coder else None + return coder + async def recreate_input(self, future=None): if not coroutines.is_active(self.input_task): - coder = self.coder() if self.coder else None + coder = self.get_coder() if coder: self.input_task = asyncio.create_task(coder.get_input()) @@ -889,7 +893,13 @@ def get_continuation(width, line_number, is_soft_wrap): return cmd except EOFError: - raise + coder = self.get_coder() + + if coder: + await coder.commands.cmd_exit(None) + else: + raise SystemExit + except KeyboardInterrupt: self.console.print() return "" From 534c922487bde29cd8fc30326f0e105ae3a1e4b6 Mon Sep 17 00:00:00 2001 From: Dustin Washington Date: Sat, 22 Nov 2025 18:00:11 -0500 Subject: [PATCH 6/8] #182: Fix parsing of help text so --help works again, consolidate/reorder some of these sets of options --- aider/args.py | 97 ++++++++++++++++++++++++++------------------------- 1 file changed, 50 insertions(+), 47 deletions(-) diff --git a/aider/args.py b/aider/args.py index f75556d3090..ce2f3138566 100644 --- a/aider/args.py +++ b/aider/args.py @@ -234,6 +234,52 @@ def get_parser(default_config_files, git_root): ), ) + ######### + group = parser.add_argument_group("Agent settings") + group.add_argument( + "--agent-config", + metavar="AGENT_CONFIG_JSON", + help="Specify Agent Mode configuration as a JSON string", + default=None, + ) + group.add_argument( + "--auto-save", + action=argparse.BooleanOptionalAction, + default=False, + help="Enable/disable automatic saving of sessions as 'auto-save' (default: False)", + ) + group.add_argument( + "--auto-load", + action=argparse.BooleanOptionalAction, + default=False, + help="Enable/disable automatic loading of 'auto-save' session on startup (default: False)", + ) + group.add_argument( + "--mcp-servers", + metavar="MCP_CONFIG_JSON", + help="Specify MCP server configurations as a JSON string", + default=None, + ) + group.add_argument( + "--mcp-servers-file", + metavar="MCP_CONFIG_FILE", + help="Specify a file path with MCP server configurations", + default=None, + ) + group.add_argument( + "--mcp-transport", + metavar="MCP_TRANSPORT", + help="Specify the transport for MCP servers (default: stdio)", + default="stdio", + choices=["stdio", "http", "sse"], + ) + group.add_argument( + "--preserve-todo-list", + action="store_true", + help="Preserve the existing .aider.todo.txt file on startup (default: False)", + default=False, + ) + ########## group = parser.add_argument_group("Context Compaction") group.add_argument( @@ -248,7 +294,7 @@ def get_parser(default_config_files, git_root): default=None, help=( "The maximum number of tokens in the conversation before context compaction is" - " triggered. (default: 80% of model's context window)" + " triggered. (default: 80%% of model's context window)" ), ) group.add_argument( @@ -789,22 +835,10 @@ def get_parser(default_config_files, git_root): ###### group = parser.add_argument_group("Other settings") group.add_argument( - "--preserve-todo-list", + "--yes-always", action="store_true", - help="Preserve the existing .aider.todo.txt file on startup (default: False)", - default=False, - ) - group.add_argument( - "--auto-save", - action=argparse.BooleanOptionalAction, - default=False, - help="Enable/disable automatic saving of sessions as 'auto-save' (default: False)", - ) - group.add_argument( - "--auto-load", - action=argparse.BooleanOptionalAction, - default=False, - help="Enable/disable automatic loading of 'auto-save' session on startup (default: False)", + help="Always say yes to every confirmation", + default=None, ) group.add_argument( "--disable-playwright", @@ -842,12 +876,6 @@ def get_parser(default_config_files, git_root): default=None, help="Specify the language to use in the commit message (default: None, user language)", ) - group.add_argument( - "--yes-always", - action="store_true", - help="Always say yes to every confirmation", - default=None, - ) group.add_argument( "-v", "--verbose", @@ -871,25 +899,6 @@ def get_parser(default_config_files, git_root): default="platform", help="Line endings to use when writing files (default: platform)", ) - group.add_argument( - "--mcp-servers", - metavar="MCP_CONFIG_JSON", - help="Specify MCP server configurations as a JSON string", - default=None, - ) - group.add_argument( - "--mcp-servers-file", - metavar="MCP_CONFIG_FILE", - help="Specify a file path with MCP server configurations", - default=None, - ) - group.add_argument( - "--mcp-transport", - metavar="MCP_TRANSPORT", - help="Specify the transport for MCP servers (default: stdio)", - default="stdio", - choices=["stdio", "http"], - ) group.add_argument( "-c", "--config", @@ -900,12 +909,6 @@ def get_parser(default_config_files, git_root): " or home directory)" ), ).complete = shtab.FILE - group.add_argument( - "--agent-config", - metavar="AGENT_CONFIG_JSON", - help="Specify Agent Mode configuration as a JSON string", - default=None, - ) # This is a duplicate of the argument in the preparser and is a no-op by this time of # argument parsing, but it's here so that the help is displayed as expected. group.add_argument( From 7a4a304b7643458a8f64a7a99160ae87ebc7d6e8 Mon Sep 17 00:00:00 2001 From: Dustin Washington Date: Sat, 22 Nov 2025 21:33:18 -0500 Subject: [PATCH 7/8] Add enhanced repo map that can approximate file import dependencies for symbol de-duplication and a sparser, and likely quicker to calculate page ranking of identifiers throughout a codebase --- README.md | 4 +- aider/args.py | 6 ++ aider/coders/base_coder.py | 1 + .../tree-sitter-language-pack/c-tags.scm | 3 + .../clojure-tags.scm | 5 ++ .../commonlisp-tags.scm | 5 ++ .../tree-sitter-language-pack/cpp-tags.scm | 3 + .../tree-sitter-language-pack/csharp-tags.scm | 6 ++ .../tree-sitter-language-pack/dart-tags.scm | 5 ++ .../tree-sitter-language-pack/elixir-tags.scm | 5 ++ .../tree-sitter-language-pack/elm-tags.scm | 3 + .../tree-sitter-language-pack/go-tags.scm | 7 ++ .../tree-sitter-language-pack/java-tags.scm | 6 ++ .../javascript-tags.scm | 8 +++ .../tree-sitter-language-pack/lua-tags.scm | 5 ++ .../ocaml_interface-tags.scm | 3 + .../tree-sitter-language-pack/python-tags.scm | 10 +++ .../tree-sitter-language-pack/r-tags.scm | 6 ++ .../tree-sitter-language-pack/ruby-tags.scm | 5 ++ .../tree-sitter-language-pack/rust-tags.scm | 3 + .../solidity-tags.scm | 2 +- .../tree-sitter-language-pack/swift-tags.scm | 5 +- .../queries/tree-sitter-languages/c-tags.scm | 3 + .../tree-sitter-languages/c_sharp-tags.scm | 6 ++ .../tree-sitter-languages/cpp-tags.scm | 3 + .../tree-sitter-languages/dart-tags.scm | 3 +- .../tree-sitter-languages/elixir-tags.scm | 5 ++ .../tree-sitter-languages/elm-tags.scm | 3 + .../tree-sitter-languages/fortran-tags.scm | 3 + .../queries/tree-sitter-languages/go-tags.scm | 6 ++ .../tree-sitter-languages/haskell-tags.scm | 2 + .../tree-sitter-languages/java-tags.scm | 6 ++ .../tree-sitter-languages/javascript-tags.scm | 8 +++ .../tree-sitter-languages/julia-tags.scm | 4 +- .../tree-sitter-languages/kotlin-tags.scm | 3 + .../ocaml_interface-tags.scm | 6 ++ .../tree-sitter-languages/php-tags.scm | 6 ++ .../tree-sitter-languages/python-tags.scm | 10 +++ .../tree-sitter-languages/ruby-tags.scm | 5 ++ .../tree-sitter-languages/rust-tags.scm | 3 + .../tree-sitter-languages/scala-tags.scm | 5 +- .../tree-sitter-languages/typescript-tags.scm | 3 + .../tree-sitter-languages/zig-tags.scm | 23 ++++++- aider/repomap.py | 65 ++++++++++++++++--- 44 files changed, 264 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 8209c762611..05c8fbca1db 100644 --- a/README.md +++ b/README.md @@ -87,8 +87,8 @@ The current priorities are to improve core capabilities and user experience of t 2. **Repo Map Accuracy** - [Discussion](https://github.com/dwash96/aider-ce/issues/45) * [x] [Bias page ranking toward active/editable files in repo map parsing](https://github.com/Aider-AI/aider/issues/2405) - * [ ] [Include import information in repo map for richer context](https://github.com/Aider-AI/aider/issues/2688) - * [ ] [Handle non-unique symbols that break down in large codebases](https://github.com/Aider-AI/aider/issues/2341) + * [x] [Include import information in repo map for richer context](https://github.com/Aider-AI/aider/issues/2688) + * [x] [Handle non-unique symbols that break down in large codebases](https://github.com/Aider-AI/aider/issues/2341) 3. **Context Discovery** - [Discussion](https://github.com/dwash96/aider-ce/issues/46) * [ ] Develop AST-based search capabilities diff --git a/aider/args.py b/aider/args.py index ce2f3138566..b81251021ad 100644 --- a/aider/args.py +++ b/aider/args.py @@ -279,6 +279,12 @@ def get_parser(default_config_files, git_root): help="Preserve the existing .aider.todo.txt file on startup (default: False)", default=False, ) + group.add_argument( + "--use-enhanced-map", + action="store_true", + help="Use enhanced Repo Map that takes into account imports (default: False)", + default=False, + ) ########## group = parser.add_argument_group("Context Compaction") diff --git a/aider/coders/base_coder.py b/aider/coders/base_coder.py index 64282ad9c84..de5486204d3 100755 --- a/aider/coders/base_coder.py +++ b/aider/coders/base_coder.py @@ -590,6 +590,7 @@ def __init__( max_code_line_length=map_max_line_length, repo_root=self.root, use_memory_cache=repomap_in_memory, + use_enhanced_map=self.args.use_enhanced_map, ) self.summarizer = summarizer or ChatSummary( diff --git a/aider/queries/tree-sitter-language-pack/c-tags.scm b/aider/queries/tree-sitter-language-pack/c-tags.scm index 1035aa2247b..fd7dd994bf2 100644 --- a/aider/queries/tree-sitter-language-pack/c-tags.scm +++ b/aider/queries/tree-sitter-language-pack/c-tags.scm @@ -7,3 +7,6 @@ (type_definition declarator: (type_identifier) @name.definition.type) @definition.type (enum_specifier name: (type_identifier) @name.definition.type) @definition.type + +(preproc_include + path: (_) @name.reference.import) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-language-pack/clojure-tags.scm b/aider/queries/tree-sitter-language-pack/clojure-tags.scm index 4b2bfa1724f..3fe169e0ad6 100644 --- a/aider/queries/tree-sitter-language-pack/clojure-tags.scm +++ b/aider/queries/tree-sitter-language-pack/clojure-tags.scm @@ -5,3 +5,8 @@ (#match? @ignore "^def.*")) (sym_lit name: (sym_name) @name.reference.call) + +(list_lit + . (sym_lit name: (sym_name) @import_call) + . (sym_lit name: (sym_name) @name.reference.import) + (#match? @import_call "^(require|use)$")) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-language-pack/commonlisp-tags.scm b/aider/queries/tree-sitter-language-pack/commonlisp-tags.scm index a47dfeedaa9..1a17e409955 100644 --- a/aider/queries/tree-sitter-language-pack/commonlisp-tags.scm +++ b/aider/queries/tree-sitter-language-pack/commonlisp-tags.scm @@ -78,6 +78,11 @@ ;; first element (list_lit . [(sym_lit) (package_lit)] @name.reference.call) @reference.call +(list_lit + . (sym_lit) @import_call + . (sym_lit) @name.reference.import + (#match? @import_call "^(require|load)$")) @reference.import + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; classes diff --git a/aider/queries/tree-sitter-language-pack/cpp-tags.scm b/aider/queries/tree-sitter-language-pack/cpp-tags.scm index 00cc966376c..a8d10958749 100644 --- a/aider/queries/tree-sitter-language-pack/cpp-tags.scm +++ b/aider/queries/tree-sitter-language-pack/cpp-tags.scm @@ -13,3 +13,6 @@ (enum_specifier name: (type_identifier) @name.definition.type) @definition.type (class_specifier name: (type_identifier) @name.definition.class) @definition.class + +(preproc_include + path: (_) @name.reference.import) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-language-pack/csharp-tags.scm b/aider/queries/tree-sitter-language-pack/csharp-tags.scm index 36ef49a2918..95659b8e8f8 100644 --- a/aider/queries/tree-sitter-language-pack/csharp-tags.scm +++ b/aider/queries/tree-sitter-language-pack/csharp-tags.scm @@ -24,3 +24,9 @@ (namespace_declaration name: (identifier) @name.definition.module) @definition.module (namespace_declaration name: (identifier) @name.definition.module) @module + +(using_directive + (qualified_name) @name.reference.import) @reference.import + +(using_directive + (identifier) @name.reference.import) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-language-pack/dart-tags.scm b/aider/queries/tree-sitter-language-pack/dart-tags.scm index a11fafcb166..59315b1591a 100644 --- a/aider/queries/tree-sitter-language-pack/dart-tags.scm +++ b/aider/queries/tree-sitter-language-pack/dart-tags.scm @@ -90,3 +90,8 @@ (arguments (argument)*))?)?) @reference.call +(import_or_export + (library_import + (import_specification + (configurable_uri + (uri (string_literal) @name.reference.import))))) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-language-pack/elixir-tags.scm b/aider/queries/tree-sitter-language-pack/elixir-tags.scm index e0a351e3278..1fd2d2ad1d8 100644 --- a/aider/queries/tree-sitter-language-pack/elixir-tags.scm +++ b/aider/queries/tree-sitter-language-pack/elixir-tags.scm @@ -52,3 +52,8 @@ ; * modules (alias) @name.reference.module @reference.module + +(call + target: (identifier) @import_call + (arguments (alias) @name.reference.import) + (#any-of? @import_call "alias" "import" "require" "use")) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-language-pack/elm-tags.scm b/aider/queries/tree-sitter-language-pack/elm-tags.scm index c2e04276320..1402438c474 100644 --- a/aider/queries/tree-sitter-language-pack/elm-tags.scm +++ b/aider/queries/tree-sitter-language-pack/elm-tags.scm @@ -17,3 +17,6 @@ (module_declaration (upper_case_qid (upper_case_identifier)) @name.definition.module ) @definition.module + +(import_clause + (upper_case_qid) @name.reference.import) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-language-pack/go-tags.scm b/aider/queries/tree-sitter-language-pack/go-tags.scm index 16ecc4de8d9..dcccbc2e2b3 100644 --- a/aider/queries/tree-sitter-language-pack/go-tags.scm +++ b/aider/queries/tree-sitter-language-pack/go-tags.scm @@ -40,3 +40,10 @@ (var_declaration (var_spec name: (identifier) @name.definition.variable)) (const_declaration (const_spec name: (identifier) @name.definition.constant)) + +(import_spec + path: [ + (interpreted_string_literal) + (raw_string_literal) + ] @name.reference.import) @reference.import + diff --git a/aider/queries/tree-sitter-language-pack/java-tags.scm b/aider/queries/tree-sitter-language-pack/java-tags.scm index ae4481e9e79..619977f27ae 100644 --- a/aider/queries/tree-sitter-language-pack/java-tags.scm +++ b/aider/queries/tree-sitter-language-pack/java-tags.scm @@ -18,3 +18,9 @@ type: (type_identifier) @name.reference.class) @reference.class (superclass (type_identifier) @name.reference.class) @reference.class + +(import_declaration + (scoped_identifier) @name.reference.import) @reference.import + +(import_declaration + (identifier) @name.reference.import) @reference.import diff --git a/aider/queries/tree-sitter-language-pack/javascript-tags.scm b/aider/queries/tree-sitter-language-pack/javascript-tags.scm index c143e3efd71..e41c062f5c5 100644 --- a/aider/queries/tree-sitter-language-pack/javascript-tags.scm +++ b/aider/queries/tree-sitter-language-pack/javascript-tags.scm @@ -86,3 +86,11 @@ (new_expression constructor: (_) @name.reference.class) @reference.class + +(import_statement + source: (string (string_fragment) @name.reference.import)) @reference.import + +(call_expression + function: (identifier) @import_func + arguments: (arguments (string (string_fragment) @name.reference.import)) + (#eq? @import_func "require")) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-language-pack/lua-tags.scm b/aider/queries/tree-sitter-language-pack/lua-tags.scm index 0910cf153dc..e36cd15596a 100644 --- a/aider/queries/tree-sitter-language-pack/lua-tags.scm +++ b/aider/queries/tree-sitter-language-pack/lua-tags.scm @@ -32,3 +32,8 @@ (method_index_expression method: (identifier) @name.reference.method) ]) @reference.call + +(function_call + name: (identifier) @import_func + arguments: (arguments (string (string_content) @name.reference.import)) + (#eq? @import_func "require")) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-language-pack/ocaml_interface-tags.scm b/aider/queries/tree-sitter-language-pack/ocaml_interface-tags.scm index d7a8f8b9776..1ac3f3a0ce5 100644 --- a/aider/queries/tree-sitter-language-pack/ocaml_interface-tags.scm +++ b/aider/queries/tree-sitter-language-pack/ocaml_interface-tags.scm @@ -96,3 +96,6 @@ ) @definition.function (#strip! @doc "^\\(\\*+\\s*|\\s*\\*+\\)$") ) + +(open_module + (module_path) @name.reference.import) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-language-pack/python-tags.scm b/aider/queries/tree-sitter-language-pack/python-tags.scm index dab8b941dea..d6a5bcc7412 100644 --- a/aider/queries/tree-sitter-language-pack/python-tags.scm +++ b/aider/queries/tree-sitter-language-pack/python-tags.scm @@ -12,3 +12,13 @@ (attribute attribute: (identifier) @name.reference.call) ]) @reference.call + +(import_statement + name: (dotted_name) @name.reference.import) @reference.import + +(import_statement + name: (aliased_import + name: (dotted_name) @name.reference.import)) @reference.import + +(import_from_statement + module_name: (dotted_name) @name.reference.import) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-language-pack/r-tags.scm b/aider/queries/tree-sitter-language-pack/r-tags.scm index 5ffc7233293..581115d9f43 100644 --- a/aider/queries/tree-sitter-language-pack/r-tags.scm +++ b/aider/queries/tree-sitter-language-pack/r-tags.scm @@ -19,3 +19,9 @@ rhs: (identifier) @name.reference.call ) ) @reference.call + +(call + function: (identifier) @import_call + arguments: (arguments (identifier) @name.reference.import) + (#match? @import_call "^(library|require)$") +) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-language-pack/ruby-tags.scm b/aider/queries/tree-sitter-language-pack/ruby-tags.scm index 79e71d2d646..9b87eb87914 100644 --- a/aider/queries/tree-sitter-language-pack/ruby-tags.scm +++ b/aider/queries/tree-sitter-language-pack/ruby-tags.scm @@ -62,3 +62,8 @@ (#is-not? local) (#not-match? @name.reference.call "^(lambda|load|require|require_relative|__FILE__|__LINE__)$") ) + +(call + method: (identifier) @import_method + arguments: (argument_list (string (string_content) @name.reference.import)) + (#match? @import_method "^(require|require_relative|load)$")) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-language-pack/rust-tags.scm b/aider/queries/tree-sitter-language-pack/rust-tags.scm index 0888cc0d843..23d355dc1d1 100644 --- a/aider/queries/tree-sitter-language-pack/rust-tags.scm +++ b/aider/queries/tree-sitter-language-pack/rust-tags.scm @@ -58,3 +58,6 @@ (impl_item type: (type_identifier) @name.reference.implementation !trait) @reference.implementation + +(use_declaration + argument: (_) @name.reference.import) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-language-pack/solidity-tags.scm b/aider/queries/tree-sitter-language-pack/solidity-tags.scm index d56bc19a06f..29b86b5b6ba 100644 --- a/aider/queries/tree-sitter-language-pack/solidity-tags.scm +++ b/aider/queries/tree-sitter-language-pack/solidity-tags.scm @@ -40,4 +40,4 @@ ;; Imports ( note that unknown is not standardised ) (import_directive - import_name: (_) @name.reference.module ) @reference.unknown + import_name: (_) @name.reference.import ) @reference.import diff --git a/aider/queries/tree-sitter-language-pack/swift-tags.scm b/aider/queries/tree-sitter-language-pack/swift-tags.scm index 9b81cf7bd66..4fdc32a058c 100644 --- a/aider/queries/tree-sitter-language-pack/swift-tags.scm +++ b/aider/queries/tree-sitter-language-pack/swift-tags.scm @@ -48,4 +48,7 @@ ) @definition.property (function_declaration - name: (simple_identifier) @name.definition.function) @definition.function + name: (simple_identifier) @name.definition.function) @definition.function + +(import_declaration + "import" @name.reference.import) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-languages/c-tags.scm b/aider/queries/tree-sitter-languages/c-tags.scm index 1035aa2247b..fd7dd994bf2 100644 --- a/aider/queries/tree-sitter-languages/c-tags.scm +++ b/aider/queries/tree-sitter-languages/c-tags.scm @@ -7,3 +7,6 @@ (type_definition declarator: (type_identifier) @name.definition.type) @definition.type (enum_specifier name: (type_identifier) @name.definition.type) @definition.type + +(preproc_include + path: (_) @name.reference.import) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-languages/c_sharp-tags.scm b/aider/queries/tree-sitter-languages/c_sharp-tags.scm index 58e9199a46d..ebc9158dcf6 100644 --- a/aider/queries/tree-sitter-languages/c_sharp-tags.scm +++ b/aider/queries/tree-sitter-languages/c_sharp-tags.scm @@ -44,3 +44,9 @@ (namespace_declaration name: (identifier) @name.definition.module ) @definition.module + +(using_directive + (qualified_name) @name.reference.import) @reference.import + +(using_directive + (identifier) @name.reference.import) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-languages/cpp-tags.scm b/aider/queries/tree-sitter-languages/cpp-tags.scm index 7a7ad0b99d4..7aff26860b5 100644 --- a/aider/queries/tree-sitter-languages/cpp-tags.scm +++ b/aider/queries/tree-sitter-languages/cpp-tags.scm @@ -13,3 +13,6 @@ (enum_specifier name: (type_identifier) @name.definition.type) @definition.type (class_specifier name: (type_identifier) @name.definition.class) @definition.class + +(preproc_include + path: (_) @name.reference.import) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-languages/dart-tags.scm b/aider/queries/tree-sitter-languages/dart-tags.scm index 1aacad0deaf..3bd240a74b9 100644 --- a/aider/queries/tree-sitter-languages/dart-tags.scm +++ b/aider/queries/tree-sitter-languages/dart-tags.scm @@ -88,4 +88,5 @@ (arguments (argument)*))?)?) @reference.call - +(import_or_export + (string_literal) @name.reference.import) @reference.import diff --git a/aider/queries/tree-sitter-languages/elixir-tags.scm b/aider/queries/tree-sitter-languages/elixir-tags.scm index 9eb39d95d85..7963c6d916c 100644 --- a/aider/queries/tree-sitter-languages/elixir-tags.scm +++ b/aider/queries/tree-sitter-languages/elixir-tags.scm @@ -52,3 +52,8 @@ ; * modules (alias) @name.reference.module @reference.module + +(call + target: (identifier) @import_call + (arguments (alias) @name.reference.import) + (#match? @import_call "^(alias|import|require|use)$")) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-languages/elm-tags.scm b/aider/queries/tree-sitter-languages/elm-tags.scm index 8b1589e9a87..b2306572e2a 100644 --- a/aider/queries/tree-sitter-languages/elm-tags.scm +++ b/aider/queries/tree-sitter-languages/elm-tags.scm @@ -17,3 +17,6 @@ (module_declaration (upper_case_qid (upper_case_identifier)) @name.definition.module ) @definition.module + +(import_clause + (upper_case_qid) @name.reference.import) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-languages/fortran-tags.scm b/aider/queries/tree-sitter-languages/fortran-tags.scm index c0bb260e881..9358e5b2c0b 100644 --- a/aider/queries/tree-sitter-languages/fortran-tags.scm +++ b/aider/queries/tree-sitter-languages/fortran-tags.scm @@ -12,4 +12,7 @@ (module_procedure_statement name: (name) @name.definition.function) @definition.function + +(use_statement + (name) @name.reference.import) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-languages/go-tags.scm b/aider/queries/tree-sitter-languages/go-tags.scm index a32d03aa700..06d8af45e5b 100644 --- a/aider/queries/tree-sitter-languages/go-tags.scm +++ b/aider/queries/tree-sitter-languages/go-tags.scm @@ -28,3 +28,9 @@ name: (type_identifier) @name.definition.type) @definition.type (type_identifier) @name.reference.type @reference.type + +(import_spec + path: [ + (interpreted_string_literal) + (raw_string_literal) + ] @name.reference.import) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-languages/haskell-tags.scm b/aider/queries/tree-sitter-languages/haskell-tags.scm index f5c073750a6..5365d6b6b70 100644 --- a/aider/queries/tree-sitter-languages/haskell-tags.scm +++ b/aider/queries/tree-sitter-languages/haskell-tags.scm @@ -1,3 +1,5 @@ (function (variable) @name.definition.function) (bind (variable) @name.definition.function) (signature (variable) @name.definition.type) + +(import) @name.reference.import @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-languages/java-tags.scm b/aider/queries/tree-sitter-languages/java-tags.scm index 3b7290d461c..cc30dacb067 100644 --- a/aider/queries/tree-sitter-languages/java-tags.scm +++ b/aider/queries/tree-sitter-languages/java-tags.scm @@ -18,3 +18,9 @@ type: (type_identifier) @name.reference.class) @reference.class (superclass (type_identifier) @name.reference.class) @reference.class + +(import_declaration + (scoped_identifier) @name.reference.import) @reference.import + +(import_declaration + (identifier) @name.reference.import) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-languages/javascript-tags.scm b/aider/queries/tree-sitter-languages/javascript-tags.scm index 3bc55c5c58c..f8d2457123e 100644 --- a/aider/queries/tree-sitter-languages/javascript-tags.scm +++ b/aider/queries/tree-sitter-languages/javascript-tags.scm @@ -86,3 +86,11 @@ (new_expression constructor: (_) @name.reference.class) @reference.class + +(import_statement + source: (string (string_fragment) @name.reference.import)) @reference.import + +(call_expression + function: (identifier) @import_func + arguments: (arguments (string (string_fragment) @name.reference.import)) + (#eq? @import_func "require")) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-languages/julia-tags.scm b/aider/queries/tree-sitter-languages/julia-tags.scm index b7d33d93b6c..1d0502e67df 100644 --- a/aider/queries/tree-sitter-languages/julia-tags.scm +++ b/aider/queries/tree-sitter-languages/julia-tags.scm @@ -54,7 +54,7 @@ (identifier) @name.reference.export) @reference.export (using_statement - (identifier) @name.reference.module) @reference.module + (identifier) @name.reference.import) @reference.import (import_statement - (identifier) @name.reference.module) @reference.module + (identifier) @name.reference.import) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-languages/kotlin-tags.scm b/aider/queries/tree-sitter-languages/kotlin-tags.scm index 9770a4c0eb1..0668f717e2f 100644 --- a/aider/queries/tree-sitter-languages/kotlin-tags.scm +++ b/aider/queries/tree-sitter-languages/kotlin-tags.scm @@ -25,3 +25,6 @@ (constructor_invocation (user_type) @name.reference.type) ]) @reference.type + +(import_header + (identifier) @name.reference.import) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-languages/ocaml_interface-tags.scm b/aider/queries/tree-sitter-languages/ocaml_interface-tags.scm index d7a8f8b9776..059745e5fb6 100644 --- a/aider/queries/tree-sitter-languages/ocaml_interface-tags.scm +++ b/aider/queries/tree-sitter-languages/ocaml_interface-tags.scm @@ -96,3 +96,9 @@ ) @definition.function (#strip! @doc "^\\(\\*+\\s*|\\s*\\*+\\)$") ) + +(open_statement + (module_path) @name.reference.import) @reference.import + +(include_statement + (module_path) @name.reference.import) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-languages/php-tags.scm b/aider/queries/tree-sitter-languages/php-tags.scm index 61c86fcbe5c..4a88451cd85 100644 --- a/aider/queries/tree-sitter-languages/php-tags.scm +++ b/aider/queries/tree-sitter-languages/php-tags.scm @@ -24,3 +24,9 @@ (member_call_expression name: (name) @name.reference.call) @reference.call + +(namespace_use_declaration + (namespace_use_clause (qualified_name) @name.reference.import)) @reference.import + +(require_expression (string) @name.reference.import) @reference.import +(include_expression (string) @name.reference.import) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-languages/python-tags.scm b/aider/queries/tree-sitter-languages/python-tags.scm index 3be5bed9fef..cf25ad0e41b 100644 --- a/aider/queries/tree-sitter-languages/python-tags.scm +++ b/aider/queries/tree-sitter-languages/python-tags.scm @@ -10,3 +10,13 @@ (attribute attribute: (identifier) @name.reference.call) ]) @reference.call + +(import_statement + name: (dotted_name) @name.reference.import) @reference.import + +(import_statement + name: (aliased_import + name: (dotted_name) @name.reference.import)) @reference.import + +(import_from_statement + module_name: (dotted_name) @name.reference.import) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-languages/ruby-tags.scm b/aider/queries/tree-sitter-languages/ruby-tags.scm index 79e71d2d646..9b87eb87914 100644 --- a/aider/queries/tree-sitter-languages/ruby-tags.scm +++ b/aider/queries/tree-sitter-languages/ruby-tags.scm @@ -62,3 +62,8 @@ (#is-not? local) (#not-match? @name.reference.call "^(lambda|load|require|require_relative|__FILE__|__LINE__)$") ) + +(call + method: (identifier) @import_method + arguments: (argument_list (string (string_content) @name.reference.import)) + (#match? @import_method "^(require|require_relative|load)$")) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-languages/rust-tags.scm b/aider/queries/tree-sitter-languages/rust-tags.scm index dadfa7acb6f..9f25c743508 100644 --- a/aider/queries/tree-sitter-languages/rust-tags.scm +++ b/aider/queries/tree-sitter-languages/rust-tags.scm @@ -58,3 +58,6 @@ (impl_item type: (type_identifier) @name.reference.implementation !trait) @reference.implementation + +(use_declaration + argument: (_) @name.reference.import) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-languages/scala-tags.scm b/aider/queries/tree-sitter-languages/scala-tags.scm index 4bf3953ffc8..d3f858004cc 100644 --- a/aider/queries/tree-sitter-languages/scala-tags.scm +++ b/aider/queries/tree-sitter-languages/scala-tags.scm @@ -60,6 +60,5 @@ (extends_clause (type_identifier) @name.reference.class) @reference.class -(extends_clause - (generic_type - (type_identifier) @name.reference.class)) @reference.class +(import_declaration + (identifier) @name.reference.import) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-languages/typescript-tags.scm b/aider/queries/tree-sitter-languages/typescript-tags.scm index 8a73dccc241..e33fc8f57d9 100644 --- a/aider/queries/tree-sitter-languages/typescript-tags.scm +++ b/aider/queries/tree-sitter-languages/typescript-tags.scm @@ -39,3 +39,6 @@ (enum_declaration name: (identifier) @name.definition.enum) @definition.enum + +(import_statement + source: (string (string_fragment) @name.reference.import)) @reference.import \ No newline at end of file diff --git a/aider/queries/tree-sitter-languages/zig-tags.scm b/aider/queries/tree-sitter-languages/zig-tags.scm index c02028ea8a1..dba232eb0fc 100644 --- a/aider/queries/tree-sitter-languages/zig-tags.scm +++ b/aider/queries/tree-sitter-languages/zig-tags.scm @@ -1,3 +1,20 @@ -(FnProto) @name.definition.function -(VarDecl "const" @name.definition.constant) -(VarDecl "var" @name.definition.variable) +(FnProto + (IDENTIFIER) @name.definition.function) @definition.function + +(VarDecl + "const" + (IDENTIFIER) @name.definition.constant) @definition.constant + +(VarDecl + "var" + (IDENTIFIER) @name.definition.variable) @definition.variable + +( + (SuffixExpr + (BUILTINIDENTIFIER) @func + (FnCallArguments + (ErrorUnionExpr + (SuffixExpr + (STRINGLITERALSINGLE) @name.reference.import)))) @reference.import + (#eq? @func "@import") +) \ No newline at end of file diff --git a/aider/repomap.py b/aider/repomap.py index 020f51c1029..81733916f0a 100644 --- a/aider/repomap.py +++ b/aider/repomap.py @@ -1,5 +1,6 @@ import math import os +import re import shutil import sqlite3 import sys @@ -75,9 +76,9 @@ def __new__( SQLITE_ERRORS = (sqlite3.OperationalError, sqlite3.DatabaseError, OSError) -CACHE_VERSION = 5 +CACHE_VERSION = 6 if USING_TSL_PACK: - CACHE_VERSION = 7 + CACHE_VERSION = 8 UPDATING_REPO_MAP_MESSAGE = "Updating repo map" @@ -156,10 +157,12 @@ def __init__( max_code_line_length=100, repo_root=None, use_memory_cache=False, + use_enhanced_map=False, ): self.io = io self.verbose = verbose self.refresh = refresh + self.use_enhanced_map = use_enhanced_map self.map_cache_dir = map_cache_dir # Prefer an explicit repo root (eg per-test repo), fallback to CWD @@ -465,6 +468,33 @@ def shared_path_components(self, path1_str, path2_str): distance = len(p1) + len(p2) - (2 * common_count) return distance + def check_import_match(self, definer, imports): + definer_path = Path(definer) + definer_parts = list(definer_path.parts) + if not definer_parts: + return False + + # Remove extension from last part + definer_parts[-1] = os.path.splitext(definer_parts[-1])[0] + + for imp in imports: + imp_parts = [p for p in re.split(r"[.\\/]", imp) if p] + if len(imp_parts) > len(definer_parts): + continue + + # Check for sub-sequence match + # Check for sub-sequence match + for i in range(len(definer_parts) - len(imp_parts) + 1): + if definer_parts[i : i + len(imp_parts)] == imp_parts: + # Allow if it's a suffix match (standard aliasing) + if i + len(imp_parts) == len(definer_parts): + return True + + # Allow partial/middle match if enough specificity (>= 2 parts) + if len(imp_parts) >= 2: + return True + return False + def get_tags_raw(self, fname, rel_fname): lang = filename_to_lang(fname) if not lang: @@ -474,7 +504,8 @@ def get_tags_raw(self, fname, rel_fname): language = get_language(lang) parser = get_parser(lang) except Exception as err: - print(f"Skipping file {fname}: {err}") + if self.verbose: + print(f"Skipping file {fname}: {err}") return query_scm = get_scm_fname(lang) @@ -572,6 +603,8 @@ def get_ranked_tags( defines = defaultdict(set) references = defaultdict(list) definitions = defaultdict(set) + file_imports = defaultdict(set) + import_ast_mode = False personalization = dict() @@ -660,10 +693,11 @@ def get_ranked_tags( elif tag.kind == "ref": references[tag.name].append(rel_fname) - ## - # dump(defines) - # dump(references) - # dump(personalization) + if tag.specific_kind == "import": + file_imports[rel_fname].add(tag.name) + + if self.use_enhanced_map and len(file_imports) > 0: + import_ast_mode = True if not references: references = dict((k, list(v)) for k, v in defines.items()) @@ -723,7 +757,19 @@ def get_ranked_tags( ext_mul = round(math.log2(unique_file_refs * total_refs**2 + 1)) for referencer, num_refs in Counter(references[ident]).items(): - for definer in definers: + relevant_definers = [] if import_ast_mode else definers + + if import_ast_mode: + if referencer in file_imports: + matches = [ + d + for d in definers + if self.check_import_match(d, file_imports[referencer]) + ] + if matches: + relevant_definers = matches + + for definer in relevant_definers: # dump(referencer, definer, num_refs, mul) # Only add edge if file extensions match @@ -743,7 +789,7 @@ def get_ranked_tags( # num_refs = math.sqrt(num_refs) path_distance = self.shared_path_components(referencer, definer) weight = num_refs * use_mul * 2 ** (-1 * path_distance) - G.add_edge(referencer, definer, weight=weight, ident=ident) + G.add_edge(referencer, definer, weight=weight, key=ident, ident=ident) if not references: pass @@ -781,7 +827,6 @@ def get_ranked_tags( ranked_definitions.items(), reverse=True, key=lambda x: (x[1], x[0]) ) - # dump(ranked_definitions) # with open('defs.txt', 'w') as out_file: # import pprint # printer = pprint.PrettyPrinter(indent=2, stream=out_file) From 90caacc82e3e6f7cbc7d81faf14c1671c4ac491f Mon Sep 17 00:00:00 2001 From: Dustin Washington Date: Sat, 22 Nov 2025 21:44:21 -0500 Subject: [PATCH 8/8] Fix use_enhanced_map assignment so help tests pass --- aider/coders/base_coder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aider/coders/base_coder.py b/aider/coders/base_coder.py index de5486204d3..f9564a61b5b 100755 --- a/aider/coders/base_coder.py +++ b/aider/coders/base_coder.py @@ -590,7 +590,7 @@ def __init__( max_code_line_length=map_max_line_length, repo_root=self.root, use_memory_cache=repomap_in_memory, - use_enhanced_map=self.args.use_enhanced_map, + use_enhanced_map=False if not self.args or self.args.use_enhanced_map else True, ) self.summarizer = summarizer or ChatSummary(