aider-ce 0.88.20__py3-none-any.whl → 0.88.38__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. aider/__init__.py +1 -1
  2. aider/_version.py +2 -2
  3. aider/args.py +63 -43
  4. aider/coders/agent_coder.py +331 -79
  5. aider/coders/agent_prompts.py +3 -15
  6. aider/coders/architect_coder.py +21 -5
  7. aider/coders/base_coder.py +661 -413
  8. aider/coders/base_prompts.py +6 -3
  9. aider/coders/chat_chunks.py +39 -17
  10. aider/commands.py +79 -15
  11. aider/diffs.py +10 -9
  12. aider/exceptions.py +1 -1
  13. aider/helpers/coroutines.py +8 -0
  14. aider/helpers/requests.py +45 -0
  15. aider/history.py +5 -0
  16. aider/io.py +179 -25
  17. aider/main.py +86 -35
  18. aider/models.py +16 -8
  19. aider/queries/tree-sitter-language-pack/c-tags.scm +3 -0
  20. aider/queries/tree-sitter-language-pack/clojure-tags.scm +5 -0
  21. aider/queries/tree-sitter-language-pack/commonlisp-tags.scm +5 -0
  22. aider/queries/tree-sitter-language-pack/cpp-tags.scm +3 -0
  23. aider/queries/tree-sitter-language-pack/csharp-tags.scm +6 -0
  24. aider/queries/tree-sitter-language-pack/dart-tags.scm +5 -0
  25. aider/queries/tree-sitter-language-pack/elixir-tags.scm +5 -0
  26. aider/queries/tree-sitter-language-pack/elm-tags.scm +3 -0
  27. aider/queries/tree-sitter-language-pack/go-tags.scm +7 -0
  28. aider/queries/tree-sitter-language-pack/java-tags.scm +6 -0
  29. aider/queries/tree-sitter-language-pack/javascript-tags.scm +8 -0
  30. aider/queries/tree-sitter-language-pack/lua-tags.scm +5 -0
  31. aider/queries/tree-sitter-language-pack/ocaml_interface-tags.scm +3 -0
  32. aider/queries/tree-sitter-language-pack/python-tags.scm +10 -0
  33. aider/queries/tree-sitter-language-pack/r-tags.scm +6 -0
  34. aider/queries/tree-sitter-language-pack/ruby-tags.scm +5 -0
  35. aider/queries/tree-sitter-language-pack/rust-tags.scm +3 -0
  36. aider/queries/tree-sitter-language-pack/solidity-tags.scm +1 -1
  37. aider/queries/tree-sitter-language-pack/swift-tags.scm +4 -1
  38. aider/queries/tree-sitter-languages/c-tags.scm +3 -0
  39. aider/queries/tree-sitter-languages/c_sharp-tags.scm +6 -0
  40. aider/queries/tree-sitter-languages/cpp-tags.scm +3 -0
  41. aider/queries/tree-sitter-languages/dart-tags.scm +2 -1
  42. aider/queries/tree-sitter-languages/elixir-tags.scm +5 -0
  43. aider/queries/tree-sitter-languages/elm-tags.scm +3 -0
  44. aider/queries/tree-sitter-languages/fortran-tags.scm +3 -0
  45. aider/queries/tree-sitter-languages/go-tags.scm +6 -0
  46. aider/queries/tree-sitter-languages/haskell-tags.scm +2 -0
  47. aider/queries/tree-sitter-languages/java-tags.scm +6 -0
  48. aider/queries/tree-sitter-languages/javascript-tags.scm +8 -0
  49. aider/queries/tree-sitter-languages/julia-tags.scm +2 -2
  50. aider/queries/tree-sitter-languages/kotlin-tags.scm +3 -0
  51. aider/queries/tree-sitter-languages/ocaml_interface-tags.scm +6 -0
  52. aider/queries/tree-sitter-languages/php-tags.scm +6 -0
  53. aider/queries/tree-sitter-languages/python-tags.scm +10 -0
  54. aider/queries/tree-sitter-languages/ruby-tags.scm +5 -0
  55. aider/queries/tree-sitter-languages/rust-tags.scm +3 -0
  56. aider/queries/tree-sitter-languages/scala-tags.scm +2 -3
  57. aider/queries/tree-sitter-languages/typescript-tags.scm +3 -0
  58. aider/queries/tree-sitter-languages/zig-tags.scm +20 -3
  59. aider/repomap.py +71 -11
  60. aider/resources/model-metadata.json +27335 -635
  61. aider/resources/model-settings.yml +190 -0
  62. aider/scrape.py +2 -0
  63. aider/tools/__init__.py +2 -0
  64. aider/tools/command.py +84 -94
  65. aider/tools/command_interactive.py +95 -110
  66. aider/tools/delete_block.py +131 -159
  67. aider/tools/delete_line.py +97 -132
  68. aider/tools/delete_lines.py +120 -160
  69. aider/tools/extract_lines.py +288 -312
  70. aider/tools/finished.py +30 -43
  71. aider/tools/git_branch.py +107 -109
  72. aider/tools/git_diff.py +44 -56
  73. aider/tools/git_log.py +39 -53
  74. aider/tools/git_remote.py +37 -51
  75. aider/tools/git_show.py +33 -47
  76. aider/tools/git_status.py +30 -44
  77. aider/tools/grep.py +214 -242
  78. aider/tools/indent_lines.py +175 -201
  79. aider/tools/insert_block.py +220 -253
  80. aider/tools/list_changes.py +65 -80
  81. aider/tools/ls.py +64 -80
  82. aider/tools/make_editable.py +57 -73
  83. aider/tools/make_readonly.py +50 -66
  84. aider/tools/remove.py +64 -80
  85. aider/tools/replace_all.py +96 -109
  86. aider/tools/replace_line.py +118 -156
  87. aider/tools/replace_lines.py +160 -197
  88. aider/tools/replace_text.py +159 -160
  89. aider/tools/show_numbered_context.py +115 -141
  90. aider/tools/thinking.py +52 -0
  91. aider/tools/undo_change.py +78 -91
  92. aider/tools/update_todo_list.py +130 -138
  93. aider/tools/utils/base_tool.py +64 -0
  94. aider/tools/utils/output.py +118 -0
  95. aider/tools/view.py +38 -54
  96. aider/tools/view_files_matching.py +131 -134
  97. aider/tools/view_files_with_symbol.py +108 -120
  98. aider/urls.py +1 -1
  99. aider/versioncheck.py +4 -3
  100. aider/website/docs/config/adv-model-settings.md +237 -0
  101. aider/website/docs/config/agent-mode.md +36 -3
  102. aider/website/docs/config/model-aliases.md +2 -1
  103. aider/website/docs/faq.md +6 -11
  104. aider/website/docs/languages.md +2 -2
  105. aider/website/docs/more/infinite-output.md +27 -0
  106. {aider_ce-0.88.20.dist-info → aider_ce-0.88.38.dist-info}/METADATA +112 -70
  107. {aider_ce-0.88.20.dist-info → aider_ce-0.88.38.dist-info}/RECORD +112 -107
  108. aider_ce-0.88.38.dist-info/entry_points.txt +6 -0
  109. aider_ce-0.88.20.dist-info/entry_points.txt +0 -2
  110. /aider/tools/{tool_utils.py → utils/helpers.py} +0 -0
  111. {aider_ce-0.88.20.dist-info → aider_ce-0.88.38.dist-info}/WHEEL +0 -0
  112. {aider_ce-0.88.20.dist-info → aider_ce-0.88.38.dist-info}/licenses/LICENSE.txt +0 -0
  113. {aider_ce-0.88.20.dist-info → aider_ce-0.88.38.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,118 @@
1
+ import json
2
+ import re
3
+
4
+
5
+ def print_tool_response(coder, mcp_server, tool_response):
6
+ """
7
+ Format the output for display.
8
+ Prints a Header to identify the tool, a body for the relevant information
9
+ for the user and a footer for verbose information
10
+
11
+ Args:
12
+ coder: An instance of base_coder
13
+ mcp_server: An mcp server instance
14
+ tool_response: a tool_response dictionary
15
+ """
16
+ tool_header(coder=coder, mcp_server=mcp_server, tool_response=tool_response)
17
+ tool_body(coder=coder, tool_response=tool_response)
18
+ tool_footer(coder=coder, tool_response=tool_response)
19
+
20
+
21
+ def tool_header(coder, mcp_server, tool_response):
22
+ """
23
+ Prints the header for the tool call output
24
+
25
+ Args:
26
+ coder: An instance of base_coder
27
+ mcp_server: An mcp server instance
28
+ tool_response: a tool_response dictionary
29
+ """
30
+ color_start, color_end = color_markers(coder)
31
+
32
+ coder.io.tool_output(
33
+ f"{color_start}Tool Call:{color_end} {mcp_server.name} • {tool_response.function.name}"
34
+ )
35
+
36
+
37
+ def tool_body(coder, tool_response):
38
+ """
39
+ Prints the output body of a tool call as the raw json returned from the model
40
+
41
+ Args:
42
+ coder: An instance of base_coder
43
+ tool_response: a tool_response dictionary
44
+ """
45
+ color_start, color_end = color_markers(coder)
46
+
47
+ # Parse and format arguments as headers with values
48
+ if tool_response.function.arguments:
49
+ # For non-replace tools, show raw arguments
50
+ raw_args = tool_response.function.arguments
51
+ coder.io.tool_output(f"{color_start}Arguments:{color_end} {raw_args}")
52
+
53
+
54
+ def tool_body_unwrapped(coder, tool_response):
55
+ """
56
+ Prints the output body of a tool call with the argument
57
+ and content sections separated
58
+
59
+ Args:
60
+ coder: An instance of base_coder
61
+ tool_response: a tool_response dictionary
62
+ """
63
+
64
+ color_start, color_end = color_markers(coder)
65
+
66
+ try:
67
+ args_dict = json.loads(tool_response.function.arguments)
68
+ first_key = True
69
+ for key, value in args_dict.items():
70
+ # Convert explicit \\n sequences to actual newlines using regex
71
+ # Only match \\n that is not preceded by any other backslashes
72
+ if isinstance(value, str):
73
+ value = re.sub(r"(?<!\\)\\n", "\n", value)
74
+ # Add extra newline before first key/header
75
+ if first_key:
76
+ coder.io.tool_output("\n")
77
+ first_key = False
78
+ coder.io.tool_output(f"{color_start}{key}:{color_end}")
79
+ # Split the value by newlines and output each line separately
80
+ if isinstance(value, str):
81
+ for line in value.split("\n"):
82
+ coder.io.tool_output(f"{line}")
83
+ else:
84
+ coder.io.tool_output(f"{str(value)}")
85
+ coder.io.tool_output("")
86
+ except json.JSONDecodeError:
87
+ # If JSON parsing fails, show raw arguments
88
+ raw_args = tool_response.function.arguments
89
+ coder.io.tool_output(f"{color_start}Arguments:{color_end} {raw_args}")
90
+
91
+
92
+ def tool_footer(coder, tool_response):
93
+ """
94
+ Prints the output footer of a tool call, generally a new line
95
+ But can include id's if ran in verbose mode
96
+
97
+ Args:
98
+ coder: An instance of base_coder
99
+ tool_response: a tool_response dictionary
100
+ """
101
+ if coder.verbose:
102
+ coder.io.tool_output(f"Tool ID: {tool_response.id}")
103
+ coder.io.tool_output(f"Tool type: {tool_response.type}")
104
+
105
+ coder.io.tool_output("\n")
106
+
107
+
108
+ def color_markers(coder):
109
+ """
110
+ Rich.console color markers
111
+
112
+ Args:
113
+ coder: An instance of base_coder
114
+ """
115
+ color_start = "[blue]" if coder.pretty else ""
116
+ color_end = "[/blue]" if coder.pretty else ""
117
+
118
+ return color_start, color_end
aider/tools/view.py CHANGED
@@ -1,57 +1,41 @@
1
- schema = {
2
- "type": "function",
3
- "function": {
4
- "name": "View",
5
- "description": (
6
- "View a specific file and add it to context."
7
- "Only use this when the file is not already in the context "
8
- "and when editing the file is necessary to accomplish the goal."
9
- ),
10
- "parameters": {
11
- "type": "object",
12
- "properties": {
13
- "file_path": {
14
- "type": "string",
15
- "description": "The path to the file to view.",
1
+ from aider.tools.utils.base_tool import BaseTool
2
+
3
+
4
+ class Tool(BaseTool):
5
+ NORM_NAME = "view"
6
+ SCHEMA = {
7
+ "type": "function",
8
+ "function": {
9
+ "name": "View",
10
+ "description": (
11
+ "View a specific file and add it to context."
12
+ "Only use this when the file is not already in the context "
13
+ "and when editing the file is necessary to accomplish the goal."
14
+ ),
15
+ "parameters": {
16
+ "type": "object",
17
+ "properties": {
18
+ "file_path": {
19
+ "type": "string",
20
+ "description": "The path to the file to view.",
21
+ },
16
22
  },
23
+ "required": ["file_path"],
17
24
  },
18
- "required": ["file_path"],
19
25
  },
20
- },
21
- }
22
-
23
- # Normalized tool name for lookup
24
- NORM_NAME = "view"
25
-
26
-
27
- def execute_view(coder, file_path):
28
- """
29
- Explicitly add a file to context as read-only.
30
-
31
- This gives the LLM explicit control over what files to view,
32
- rather than relying on indirect mentions.
33
- """
34
- try:
35
- # Use the coder's helper, marking it as an explicit view request
36
- return coder._add_file_to_context(file_path, explicit=True)
37
- except Exception as e:
38
- coder.io.tool_error(f"Error viewing file: {str(e)}")
39
- return f"Error: {str(e)}"
40
-
41
-
42
- def process_response(coder, params):
43
- """
44
- Process the View tool response.
45
-
46
- Args:
47
- coder: The Coder instance
48
- params: Dictionary of parameters
49
-
50
- Returns:
51
- str: Result message
52
- """
53
- file_path = params.get("file_path")
54
- if file_path is not None:
55
- return execute_view(coder, file_path)
56
- else:
57
- return "Error: Missing 'file_path' parameter for View"
26
+ }
27
+
28
+ @classmethod
29
+ def execute(cls, coder, file_path):
30
+ """
31
+ Explicitly add a file to context as read-only.
32
+
33
+ This gives the LLM explicit control over what files to view,
34
+ rather than relying on indirect mentions.
35
+ """
36
+ try:
37
+ # Use the coder's helper, marking it as an explicit view request
38
+ return coder._add_file_to_context(file_path, explicit=True)
39
+ except Exception as e:
40
+ coder.io.tool_error(f"Error viewing file: {str(e)}")
41
+ return f"Error: {str(e)}"
@@ -1,141 +1,138 @@
1
1
  import fnmatch
2
2
  import re
3
3
 
4
- schema = {
5
- "type": "function",
6
- "function": {
7
- "name": "ViewFilesMatching",
8
- "description": "View files containing a specific pattern.",
9
- "parameters": {
10
- "type": "object",
11
- "properties": {
12
- "pattern": {
13
- "type": "string",
14
- "description": "The pattern to search for in file contents.",
15
- },
16
- "file_pattern": {
17
- "type": "string",
18
- "description": "An optional glob pattern to filter which files are searched.",
19
- },
20
- "regex": {
21
- "type": "boolean",
22
- "description": (
23
- "Whether the pattern is a regular expression. Defaults to False."
24
- ),
4
+ from aider.tools.utils.base_tool import BaseTool
5
+
6
+
7
+ class Tool(BaseTool):
8
+ NORM_NAME = "viewfilesmatching"
9
+ SCHEMA = {
10
+ "type": "function",
11
+ "function": {
12
+ "name": "ViewFilesMatching",
13
+ "description": "View files containing a specific pattern.",
14
+ "parameters": {
15
+ "type": "object",
16
+ "properties": {
17
+ "pattern": {
18
+ "type": "string",
19
+ "description": "The pattern to search for in file contents.",
20
+ },
21
+ "file_pattern": {
22
+ "type": "string",
23
+ "description": (
24
+ "An optional glob pattern to filter which files are searched."
25
+ ),
26
+ },
27
+ "regex": {
28
+ "type": "boolean",
29
+ "description": (
30
+ "Whether the pattern is a regular expression. Defaults to False."
31
+ ),
32
+ },
25
33
  },
34
+ "required": ["pattern"],
26
35
  },
27
- "required": ["pattern"],
28
36
  },
29
- },
30
- }
31
-
32
- # Normalized tool name for lookup
33
- NORM_NAME = "viewfilesmatching"
34
-
35
-
36
- def execute_view_files_matching(coder, pattern, file_pattern=None, regex=False):
37
- """
38
- Search for pattern (literal string or regex) in files and return matching files as text.
39
-
40
- Args:
41
- coder: The Coder instance.
42
- pattern (str): The pattern to search for.
43
- Treated as a literal string by default.
44
- file_pattern (str, optional): Glob pattern to filter which files are searched.
45
- Defaults to None (search all files).
46
- regex (bool, optional): If True, treat pattern as a regular expression.
47
- Defaults to False.
48
-
49
- This tool lets the LLM search for content within files, mimicking
50
- how a developer would use grep or regex search to find relevant code.
51
- """
52
- try:
53
- # Get list of files to search
54
- if file_pattern:
55
- # Use glob pattern to filter files
56
- all_files = coder.get_all_relative_files()
57
- files_to_search = []
58
- for file in all_files:
59
- if fnmatch.fnmatch(file, file_pattern):
60
- files_to_search.append(file)
61
-
62
- if not files_to_search:
63
- return f"No files matching '{file_pattern}' to search for pattern '{pattern}'"
64
- else:
65
- # Search all files if no pattern provided
66
- files_to_search = coder.get_all_relative_files()
67
-
68
- # Search for pattern in files
69
- matches = {}
70
- for file in files_to_search:
71
- abs_path = coder.abs_root_path(file)
72
- try:
73
- with open(abs_path, "r", encoding="utf-8") as f:
74
- content = f.read()
75
- match_count = 0
76
- if regex:
77
- try:
78
- matches_found = re.findall(pattern, content)
79
- match_count = len(matches_found)
80
- except re.error as e:
81
- # Handle invalid regex patterns gracefully
82
- coder.io.tool_error(f"Invalid regex pattern '{pattern}': {e}")
83
- # Skip this file for this search if regex is invalid
84
- continue
85
- else:
86
- # Exact string matching
87
- match_count = content.count(pattern)
88
-
89
- if match_count > 0:
90
- matches[file] = match_count
91
- except Exception:
92
- # Skip files that can't be read (binary, etc.)
93
- pass
94
-
95
- # Return formatted text instead of adding to context
96
- if matches:
97
- # Sort by number of matches (most matches first)
98
- sorted_matches = sorted(matches.items(), key=lambda x: x[1], reverse=True)
99
- match_list = [f"{file} ({count} matches)" for file, count in sorted_matches]
100
-
101
- if len(matches) > 10:
102
- result = (
103
- f"Found '{pattern}' in {len(matches)} files: {', '.join(match_list[:10])} and"
104
- f" {len(matches) - 10} more"
105
- )
106
- coder.io.tool_output(f"🔍 Found '{pattern}' in {len(matches)} files")
37
+ }
38
+
39
+ @classmethod
40
+ def execute(cls, coder, pattern, file_pattern=None, regex=False):
41
+ """
42
+ Search for pattern (literal string or regex) in files and return matching files as text.
43
+
44
+ Args:
45
+ coder: The Coder instance.
46
+ pattern (str): The pattern to search for.
47
+ Treated as a literal string by default.
48
+ file_pattern (str, optional): Glob pattern to filter which files are searched.
49
+ Defaults to None (search all files).
50
+ regex (bool, optional): If True, treat pattern as a regular expression.
51
+ Defaults to False.
52
+
53
+ This tool lets the LLM search for content within files, mimicking
54
+ how a developer would use grep or regex search to find relevant code.
55
+ """
56
+ try:
57
+ # Get list of files to search
58
+ if file_pattern:
59
+ # Use glob pattern to filter files
60
+ all_files = coder.get_all_relative_files()
61
+ files_to_search = []
62
+ for file in all_files:
63
+ if fnmatch.fnmatch(file, file_pattern):
64
+ files_to_search.append(file)
65
+
66
+ if not files_to_search:
67
+ return f"No files matching '{file_pattern}' to search for pattern '{pattern}'"
68
+ else:
69
+ # Search all files if no pattern provided
70
+ files_to_search = coder.get_all_relative_files()
71
+
72
+ # Search for pattern in files
73
+ matches = {}
74
+ num_matches = 0
75
+ inspecific_search_flag = False
76
+
77
+ for file in files_to_search:
78
+ abs_path = coder.abs_root_path(file)
79
+
80
+ if num_matches >= 25:
81
+ inspecific_search_flag = True
82
+
83
+ try:
84
+ if coder.repo.ignored_file(abs_path):
85
+ continue
86
+
87
+ with open(abs_path, "r", encoding="utf-8") as f:
88
+ content = f.read()
89
+ match_count = 0
90
+ if regex:
91
+ try:
92
+ matches_found = re.findall(pattern, content)
93
+ match_count = len(matches_found)
94
+ except re.error as e:
95
+ # Handle invalid regex patterns gracefully
96
+ coder.io.tool_error(f"Invalid regex pattern '{pattern}': {e}")
97
+ # Skip this file for this search if regex is invalid
98
+ continue
99
+ else:
100
+ # Exact string matching
101
+ match_count = content.count(pattern)
102
+
103
+ if match_count > 0:
104
+ matches[file] = match_count
105
+ num_matches += 1
106
+ except Exception:
107
+ # Skip files that can't be read (binary, etc.)
108
+ pass
109
+
110
+ # Return formatted text instead of adding to context
111
+ if matches:
112
+ # Sort by number of matches (most matches first)
113
+ sorted_matches = sorted(matches.items(), key=lambda x: x[1], reverse=True)
114
+ match_list = [f"{file} ({count} matches)" for file, count in sorted_matches]
115
+
116
+ if len(matches) > 10:
117
+ result = (
118
+ f"Found '{pattern}' in {len(matches)} files:"
119
+ f" {', '.join(match_list[:10])} and {len(matches) - 10} more"
120
+ "\nTry more specific search terms going forward"
121
+ if inspecific_search_flag
122
+ else ""
123
+ )
124
+ coder.io.tool_output(f"🔍 Found '{pattern}' in {len(matches)} files")
125
+ else:
126
+ result = f"Found '{pattern}' in {len(matches)} files: {', '.join(match_list)}"
127
+ coder.io.tool_output(
128
+ f"🔍 Found '{pattern}' in:"
129
+ f" {', '.join(match_list[:5])}{' and more' if len(matches) > 5 else ''}"
130
+ )
131
+
132
+ return result
107
133
  else:
108
- result = f"Found '{pattern}' in {len(matches)} files: {', '.join(match_list)}"
109
- coder.io.tool_output(
110
- f"🔍 Found '{pattern}' in:"
111
- f" {', '.join(match_list[:5])}{' and more' if len(matches) > 5 else ''}"
112
- )
113
-
114
- return result
115
- else:
116
- coder.io.tool_output(f"⚠️ Pattern '{pattern}' not found in any files")
117
- return "Pattern not found in any files"
118
- except Exception as e:
119
- coder.io.tool_error(f"Error in ViewFilesMatching: {str(e)}")
120
- return f"Error: {str(e)}"
121
-
122
-
123
- def process_response(coder, params):
124
- """
125
- Process the ViewFilesMatching tool response.
126
-
127
- Args:
128
- coder: The Coder instance
129
- params: Dictionary of parameters
130
-
131
- Returns:
132
- str: Result message
133
- """
134
- pattern = params.get("pattern")
135
- file_pattern = params.get("file_pattern")
136
- regex = params.get("regex", False)
137
-
138
- if pattern is not None:
139
- return execute_view_files_matching(coder, pattern, file_pattern, regex)
140
- else:
141
- return "Error: Missing 'pattern' parameter for ViewFilesMatching"
134
+ coder.io.tool_output(f"⚠️ Pattern '{pattern}' not found in any files")
135
+ return "Pattern not found in any files"
136
+ except Exception as e:
137
+ coder.io.tool_error(f"Error in ViewFilesMatching: {str(e)}")
138
+ return f"Error: {str(e)}"