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
@@ -1,217 +1,180 @@
1
- import os
2
-
3
- from .tool_utils import (
1
+ from aider.tools.utils.base_tool import BaseTool
2
+ from aider.tools.utils.helpers import (
4
3
  ToolError,
5
4
  apply_change,
6
5
  format_tool_result,
7
6
  generate_unified_diff_snippet,
8
7
  handle_tool_error,
8
+ validate_file_for_edit,
9
9
  )
10
-
11
- schema = {
12
- "type": "function",
13
- "function": {
14
- "name": "ReplaceLines",
15
- "description": "Replace a range of lines in a file.",
16
- "parameters": {
17
- "type": "object",
18
- "properties": {
19
- "file_path": {"type": "string"},
20
- "start_line": {"type": "integer"},
21
- "end_line": {"type": "integer"},
22
- "new_content": {"type": "string"},
23
- "change_id": {"type": "string"},
24
- "dry_run": {"type": "boolean", "default": False},
10
+ from aider.tools.utils.output import tool_body_unwrapped, tool_footer, tool_header
11
+
12
+
13
+ class Tool(BaseTool):
14
+ NORM_NAME = "replacelines"
15
+ SCHEMA = {
16
+ "type": "function",
17
+ "function": {
18
+ "name": "ReplaceLines",
19
+ "description": "Replace a range of lines in a file.",
20
+ "parameters": {
21
+ "type": "object",
22
+ "properties": {
23
+ "file_path": {"type": "string"},
24
+ "start_line": {"type": "integer"},
25
+ "end_line": {"type": "integer"},
26
+ "new_content": {"type": "string"},
27
+ "change_id": {"type": "string"},
28
+ "dry_run": {"type": "boolean", "default": False},
29
+ },
30
+ "required": ["file_path", "start_line", "end_line", "new_content"],
25
31
  },
26
- "required": ["file_path", "start_line", "end_line", "new_content"],
27
32
  },
28
- },
29
- }
30
-
31
- # Normalized tool name for lookup
32
- NORM_NAME = "replacelines"
33
-
34
-
35
- def _execute_replace_lines(
36
- coder, file_path, start_line, end_line, new_content, change_id=None, dry_run=False
37
- ):
38
- """
39
- Replace a range of lines identified by line numbers.
40
- Useful for fixing errors identified by error messages or linters.
41
-
42
- Parameters:
43
- - file_path: Path to the file to modify
44
- - start_line: The first line number to replace (1-based)
45
- - end_line: The last line number to replace (1-based)
46
- - new_content: New content for the lines (can be multi-line)
47
- - change_id: Optional ID for tracking the change
48
- - dry_run: If True, simulate the change without modifying the file
49
-
50
- Returns a result message.
51
- """
52
- tool_name = "ReplaceLines"
53
- try:
54
- # Get absolute file path
55
- abs_path = coder.abs_root_path(file_path)
56
- rel_path = coder.get_rel_fname(abs_path)
57
-
58
- # Check if file exists
59
- if not os.path.isfile(abs_path):
60
- raise ToolError(f"File '{file_path}' not found")
61
-
62
- # Check if file is in editable context
63
- if abs_path not in coder.abs_fnames:
64
- if abs_path in coder.abs_read_only_fnames:
65
- raise ToolError(f"File '{file_path}' is read-only. Use MakeEditable first.")
66
- else:
67
- raise ToolError(f"File '{file_path}' not in context")
68
-
69
- # Reread file content immediately before modification
70
- file_content = coder.io.read_text(abs_path)
71
- if file_content is None:
72
- raise ToolError(f"Could not read file '{file_path}'")
73
-
74
- # Convert line numbers to integers if needed
75
- try:
76
- start_line = int(start_line)
77
- except ValueError:
78
- raise ToolError(f"Invalid start_line value: '{start_line}'. Must be an integer.")
33
+ }
79
34
 
35
+ @classmethod
36
+ def execute(
37
+ cls, coder, file_path, start_line, end_line, new_content, change_id=None, dry_run=False
38
+ ):
39
+ """
40
+ Replace a range of lines identified by line numbers.
41
+ Useful for fixing errors identified by error messages or linters.
42
+
43
+ Parameters:
44
+ - file_path: Path to the file to modify
45
+ - start_line: The first line number to replace (1-based)
46
+ - end_line: The last line number to replace (1-based)
47
+ - new_content: New content for the lines (can be multi-line)
48
+ - change_id: Optional ID for tracking the change
49
+ - dry_run: If True, simulate the change without modifying the file
50
+
51
+ Returns a result message.
52
+ """
53
+ tool_name = "ReplaceLines"
80
54
  try:
81
- end_line = int(end_line)
82
- except ValueError:
83
- raise ToolError(f"Invalid end_line value: '{end_line}'. Must be an integer.")
84
-
85
- # Split into lines
86
- lines = file_content.splitlines()
87
-
88
- # Convert 1-based line numbers to 0-based indices
89
- start_idx = start_line - 1
90
- end_idx = end_line - 1
91
-
92
- # Validate line numbers
93
- if start_idx < 0 or start_idx >= len(lines):
94
- raise ToolError(
95
- f"Start line {start_line} is out of range for file '{file_path}' (has"
96
- f" {len(lines)} lines)."
55
+ # 1. Validate file and get content
56
+ abs_path, rel_path, original_content = validate_file_for_edit(coder, file_path)
57
+
58
+ # Convert line numbers to integers if needed
59
+ try:
60
+ start_line = int(start_line)
61
+ except ValueError:
62
+ raise ToolError(f"Invalid start_line value: '{start_line}'. Must be an integer.")
63
+
64
+ try:
65
+ end_line = int(end_line)
66
+ except ValueError:
67
+ raise ToolError(f"Invalid end_line value: '{end_line}'. Must be an integer.")
68
+
69
+ # Split into lines
70
+ lines = original_content.splitlines()
71
+
72
+ # Convert 1-based line numbers to 0-based indices
73
+ start_idx = start_line - 1
74
+ end_idx = end_line - 1
75
+
76
+ # Validate line numbers
77
+ if start_idx < 0 or start_idx >= len(lines):
78
+ raise ToolError(
79
+ f"Start line {start_line} is out of range for file '{file_path}' (has"
80
+ f" {len(lines)} lines)."
81
+ )
82
+
83
+ if end_idx < start_idx or end_idx >= len(lines):
84
+ raise ToolError(
85
+ f"End line {end_line} is out of range for file '{file_path}' (must be >= start"
86
+ f" line {start_line} and <= {len(lines)})."
87
+ )
88
+
89
+ # Store original content for change tracking
90
+ replaced_lines = lines[start_idx : end_idx + 1]
91
+
92
+ # Split the new content into lines
93
+ new_lines = new_content.splitlines()
94
+
95
+ # Perform the replacement
96
+ new_full_lines = lines[:start_idx] + new_lines + lines[end_idx + 1 :]
97
+ new_content_full = "\n".join(new_full_lines)
98
+
99
+ if original_content == new_content_full:
100
+ coder.io.tool_warning("No changes made: new content is identical to original")
101
+ return "Warning: No changes made (new content identical to original)"
102
+
103
+ # Generate diff snippet
104
+ diff_snippet = generate_unified_diff_snippet(
105
+ original_content, new_content_full, rel_path
97
106
  )
98
107
 
99
- if end_idx < start_idx or end_idx >= len(lines):
100
- raise ToolError(
101
- f"End line {end_line} is out of range for file '{file_path}' (must be >= start line"
102
- f" {start_line} and <= {len(lines)})."
108
+ # Create a readable diff for the lines replacement
109
+ diff = f"Lines {start_line}-{end_line}:\n"
110
+ # Add removed lines with - prefix
111
+ for line in replaced_lines:
112
+ diff += f"- {line}\n"
113
+ # Add separator
114
+ diff += "---\n"
115
+ # Add new lines with + prefix
116
+ for line in new_lines:
117
+ diff += f"+ {line}\n"
118
+
119
+ # Handle dry run
120
+ if dry_run:
121
+ dry_run_message = (
122
+ f"Dry run: Would replace lines {start_line}-{end_line} in {file_path}"
123
+ )
124
+ return format_tool_result(
125
+ coder,
126
+ tool_name,
127
+ "",
128
+ dry_run=True,
129
+ dry_run_message=dry_run_message,
130
+ diff_snippet=diff_snippet,
131
+ )
132
+
133
+ # --- Apply Change (Not dry run) ---
134
+ metadata = {
135
+ "start_line": start_line,
136
+ "end_line": end_line,
137
+ "replaced_lines": replaced_lines,
138
+ "new_lines": new_lines,
139
+ }
140
+
141
+ final_change_id = apply_change(
142
+ coder,
143
+ abs_path,
144
+ rel_path,
145
+ original_content,
146
+ new_content_full,
147
+ "replacelines",
148
+ metadata,
149
+ change_id,
103
150
  )
104
151
 
105
- # Store original content for change tracking
106
- original_content = file_content
107
- replaced_lines = lines[start_idx : end_idx + 1]
108
-
109
- # Split the new content into lines
110
- new_lines = new_content.splitlines()
111
-
112
- # Perform the replacement
113
- new_full_lines = lines[:start_idx] + new_lines + lines[end_idx + 1 :]
114
- new_content_full = "\n".join(new_full_lines)
115
-
116
- if original_content == new_content_full:
117
- coder.io.tool_warning("No changes made: new content is identical to original")
118
- return "Warning: No changes made (new content identical to original)"
119
-
120
- # Generate diff snippet
121
- diff_snippet = generate_unified_diff_snippet(original_content, new_content_full, rel_path)
122
-
123
- # Create a readable diff for the lines replacement
124
- diff = f"Lines {start_line}-{end_line}:\n"
125
- # Add removed lines with - prefix
126
- for line in replaced_lines:
127
- diff += f"- {line}\n"
128
- # Add separator
129
- diff += "---\n"
130
- # Add new lines with + prefix
131
- for line in new_lines:
132
- diff += f"+ {line}\n"
133
-
134
- # Handle dry run
135
- if dry_run:
136
- dry_run_message = f"Dry run: Would replace lines {start_line}-{end_line} in {file_path}"
152
+ coder.files_edited_by_tools.add(rel_path)
153
+ replaced_count = end_line - start_line + 1
154
+ new_count = len(new_lines)
155
+
156
+ # Format and return result
157
+ success_message = (
158
+ f"Replaced lines {start_line}-{end_line} ({replaced_count} lines) with {new_count}"
159
+ f" new lines in {file_path}"
160
+ )
137
161
  return format_tool_result(
138
162
  coder,
139
163
  tool_name,
140
- "",
141
- dry_run=True,
142
- dry_run_message=dry_run_message,
164
+ success_message,
165
+ change_id=final_change_id,
143
166
  diff_snippet=diff_snippet,
144
167
  )
145
168
 
146
- # --- Apply Change (Not dry run) ---
147
- metadata = {
148
- "start_line": start_line,
149
- "end_line": end_line,
150
- "replaced_lines": replaced_lines,
151
- "new_lines": new_lines,
152
- }
153
-
154
- final_change_id = apply_change(
155
- coder,
156
- abs_path,
157
- rel_path,
158
- original_content,
159
- new_content_full,
160
- "replacelines",
161
- metadata,
162
- change_id,
163
- )
164
-
165
- coder.files_edited_by_tools.add(rel_path)
166
- replaced_count = end_line - start_line + 1
167
- new_count = len(new_lines)
168
-
169
- # Format and return result
170
- success_message = (
171
- f"Replaced lines {start_line}-{end_line} ({replaced_count} lines) with {new_count} new"
172
- f" lines in {file_path}"
173
- )
174
- return format_tool_result(
175
- coder, tool_name, success_message, change_id=final_change_id, diff_snippet=diff_snippet
176
- )
177
-
178
- except ToolError as e:
179
- # Handle errors raised by utility functions (expected errors)
180
- return handle_tool_error(coder, tool_name, e, add_traceback=False)
181
- except Exception as e:
182
- # Handle unexpected errors
183
- return handle_tool_error(coder, tool_name, e)
184
-
185
-
186
- def process_response(coder, params):
187
- """
188
- Process the ReplaceLines tool response.
189
-
190
- Args:
191
- coder: The Coder instance
192
- params: Dictionary of parameters
193
-
194
- Returns:
195
- str: Result message
196
- """
197
- file_path = params.get("file_path")
198
- start_line = params.get("start_line")
199
- end_line = params.get("end_line")
200
- new_content = params.get("new_content")
201
- change_id = params.get("change_id")
202
- dry_run = params.get("dry_run", False)
203
-
204
- if (
205
- file_path is not None
206
- and start_line is not None
207
- and end_line is not None
208
- and new_content is not None
209
- ):
210
- return _execute_replace_lines(
211
- coder, file_path, start_line, end_line, new_content, change_id, dry_run
212
- )
213
- else:
214
- return (
215
- "Error: Missing required parameters for ReplaceLines (file_path,"
216
- " start_line, end_line, new_content)"
217
- )
169
+ except ToolError as e:
170
+ # Handle errors raised by utility functions (expected errors)
171
+ return handle_tool_error(coder, tool_name, e, add_traceback=False)
172
+ except Exception as e:
173
+ # Handle unexpected errors
174
+ return handle_tool_error(coder, tool_name, e)
175
+
176
+ @classmethod
177
+ def format_output(cls, coder, mcp_server, tool_response):
178
+ tool_header(coder=coder, mcp_server=mcp_server, tool_response=tool_response)
179
+ tool_body_unwrapped(coder=coder, tool_response=tool_response)
180
+ tool_footer(coder=coder, tool_response=tool_response)