aider-ce 0.87.13.dev3__py3-none-any.whl → 0.88.1__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.
Potentially problematic release.
This version of aider-ce might be problematic. Click here for more details.
- aider/__init__.py +1 -1
- aider/_version.py +2 -2
- aider/args.py +6 -0
- aider/coders/architect_coder.py +3 -3
- aider/coders/base_coder.py +511 -190
- aider/coders/context_coder.py +1 -1
- aider/coders/editblock_func_coder.py +2 -2
- aider/coders/navigator_coder.py +451 -649
- aider/coders/navigator_legacy_prompts.py +49 -284
- aider/coders/navigator_prompts.py +46 -473
- aider/coders/search_replace.py +0 -0
- aider/coders/wholefile_func_coder.py +2 -2
- aider/commands.py +56 -44
- aider/exceptions.py +1 -0
- aider/history.py +14 -12
- aider/io.py +354 -117
- aider/llm.py +12 -4
- aider/main.py +32 -29
- aider/mcp/__init__.py +65 -2
- aider/mcp/server.py +37 -11
- aider/models.py +45 -20
- aider/onboarding.py +5 -5
- aider/repo.py +7 -7
- aider/resources/model-metadata.json +8 -8
- aider/scrape.py +2 -2
- aider/sendchat.py +185 -15
- aider/tools/__init__.py +44 -23
- aider/tools/command.py +18 -0
- aider/tools/command_interactive.py +18 -0
- aider/tools/delete_block.py +23 -0
- aider/tools/delete_line.py +19 -1
- aider/tools/delete_lines.py +20 -1
- aider/tools/extract_lines.py +25 -2
- aider/tools/git.py +142 -0
- aider/tools/grep.py +47 -2
- aider/tools/indent_lines.py +25 -0
- aider/tools/insert_block.py +26 -0
- aider/tools/list_changes.py +15 -0
- aider/tools/ls.py +24 -1
- aider/tools/make_editable.py +18 -0
- aider/tools/make_readonly.py +19 -0
- aider/tools/remove.py +22 -0
- aider/tools/replace_all.py +21 -0
- aider/tools/replace_line.py +20 -1
- aider/tools/replace_lines.py +21 -1
- aider/tools/replace_text.py +22 -0
- aider/tools/show_numbered_context.py +18 -0
- aider/tools/undo_change.py +15 -0
- aider/tools/update_todo_list.py +131 -0
- aider/tools/view.py +23 -0
- aider/tools/view_files_at_glob.py +32 -27
- aider/tools/view_files_matching.py +51 -37
- aider/tools/view_files_with_symbol.py +41 -54
- aider/tools/view_todo_list.py +57 -0
- aider/waiting.py +20 -203
- {aider_ce-0.87.13.dev3.dist-info → aider_ce-0.88.1.dist-info}/METADATA +21 -5
- {aider_ce-0.87.13.dev3.dist-info → aider_ce-0.88.1.dist-info}/RECORD +60 -57
- {aider_ce-0.87.13.dev3.dist-info → aider_ce-0.88.1.dist-info}/WHEEL +0 -0
- {aider_ce-0.87.13.dev3.dist-info → aider_ce-0.88.1.dist-info}/entry_points.txt +0 -0
- {aider_ce-0.87.13.dev3.dist-info → aider_ce-0.88.1.dist-info}/licenses/LICENSE.txt +0 -0
- {aider_ce-0.87.13.dev3.dist-info → aider_ce-0.88.1.dist-info}/top_level.txt +0 -0
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
"litellm_provider": "fireworks_ai",
|
|
89
89
|
"input_cost_per_token": 0.000008,
|
|
90
90
|
"output_cost_per_token": 0.000008,
|
|
91
|
-
"mode": "chat"
|
|
91
|
+
"mode": "chat"
|
|
92
92
|
},
|
|
93
93
|
"fireworks_ai/accounts/fireworks/models/deepseek-v3-0324": {
|
|
94
94
|
"max_tokens": 160000,
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
"litellm_provider": "fireworks_ai",
|
|
98
98
|
"input_cost_per_token": 0.0000009,
|
|
99
99
|
"output_cost_per_token": 0.0000009,
|
|
100
|
-
"mode": "chat"
|
|
100
|
+
"mode": "chat"
|
|
101
101
|
},
|
|
102
102
|
"openrouter/openrouter/quasar-alpha": {
|
|
103
103
|
"max_input_tokens": 1000000,
|
|
@@ -552,7 +552,7 @@
|
|
|
552
552
|
"supported_output_modalities": [
|
|
553
553
|
"text"
|
|
554
554
|
],
|
|
555
|
-
"source": "https://ai.google.dev/gemini-api/docs/
|
|
555
|
+
"source": "https://ai.google.dev/gemini-api/docs/pricing#gemini-2.5-pro"
|
|
556
556
|
},
|
|
557
557
|
"gemini-2.5-pro-preview-06-05": {
|
|
558
558
|
"max_tokens": 65536,
|
|
@@ -592,7 +592,7 @@
|
|
|
592
592
|
"supported_output_modalities": [
|
|
593
593
|
"text"
|
|
594
594
|
],
|
|
595
|
-
"source": "https://ai.google.dev/gemini-api/docs/
|
|
595
|
+
"source": "https://ai.google.dev/gemini-api/docs/pricing#gemini-2.5-pro"
|
|
596
596
|
},
|
|
597
597
|
"gemini/gemini-2.5-pro-preview-05-06": {
|
|
598
598
|
"max_tokens": 65536,
|
|
@@ -628,7 +628,7 @@
|
|
|
628
628
|
"supported_output_modalities": [
|
|
629
629
|
"text"
|
|
630
630
|
],
|
|
631
|
-
"source": "https://ai.google.dev/gemini-api/docs/pricing#gemini-2.5-pro
|
|
631
|
+
"source": "https://ai.google.dev/gemini-api/docs/pricing#gemini-2.5-pro"
|
|
632
632
|
},
|
|
633
633
|
"gemini/gemini-2.5-pro-preview-06-05": {
|
|
634
634
|
"max_tokens": 65536,
|
|
@@ -664,7 +664,7 @@
|
|
|
664
664
|
"supported_output_modalities": [
|
|
665
665
|
"text"
|
|
666
666
|
],
|
|
667
|
-
"source": "https://ai.google.dev/gemini-api/docs/pricing#gemini-2.5-pro
|
|
667
|
+
"source": "https://ai.google.dev/gemini-api/docs/pricing#gemini-2.5-pro"
|
|
668
668
|
},
|
|
669
669
|
"gemini/gemini-2.5-pro": {
|
|
670
670
|
"max_tokens": 65536,
|
|
@@ -771,6 +771,6 @@
|
|
|
771
771
|
},
|
|
772
772
|
"together_ai/Qwen/Qwen3-235B-A22B-fp8-tput": {
|
|
773
773
|
"input_cost_per_token": 0.0000002,
|
|
774
|
-
"output_cost_per_token": 0.0000006
|
|
774
|
+
"output_cost_per_token": 0.0000006
|
|
775
775
|
}
|
|
776
|
-
}
|
|
776
|
+
}
|
aider/scrape.py
CHANGED
|
@@ -37,7 +37,7 @@ def has_playwright():
|
|
|
37
37
|
return has_pip and has_chromium
|
|
38
38
|
|
|
39
39
|
|
|
40
|
-
def install_playwright(io):
|
|
40
|
+
async def install_playwright(io):
|
|
41
41
|
has_pip, has_chromium = check_env()
|
|
42
42
|
if has_pip and has_chromium:
|
|
43
43
|
return True
|
|
@@ -59,7 +59,7 @@ See {urls.enable_playwright} for more info.
|
|
|
59
59
|
"""
|
|
60
60
|
|
|
61
61
|
io.tool_output(text)
|
|
62
|
-
if not io.confirm_ask("Install playwright?", default="y"):
|
|
62
|
+
if not await io.confirm_ask("Install playwright?", default="y"):
|
|
63
63
|
return
|
|
64
64
|
|
|
65
65
|
if not has_pip:
|
aider/sendchat.py
CHANGED
|
@@ -6,13 +6,52 @@ def sanity_check_messages(messages):
|
|
|
6
6
|
"""Check if messages alternate between user and assistant roles.
|
|
7
7
|
System messages can be interspersed anywhere.
|
|
8
8
|
Also verifies the last non-system message is from the user.
|
|
9
|
+
Validates tool message sequences.
|
|
9
10
|
Returns True if valid, False otherwise."""
|
|
10
11
|
last_role = None
|
|
11
12
|
last_non_system_role = None
|
|
13
|
+
i = 0
|
|
14
|
+
n = len(messages)
|
|
12
15
|
|
|
13
|
-
|
|
16
|
+
while i < n:
|
|
17
|
+
msg = messages[i]
|
|
14
18
|
role = msg.get("role")
|
|
19
|
+
|
|
20
|
+
# Handle tool sequences atomically
|
|
21
|
+
if role == "assistant" and "tool_calls" in msg and msg["tool_calls"]:
|
|
22
|
+
# Validate tool sequence
|
|
23
|
+
expected_ids = {call["id"] for call in msg["tool_calls"]}
|
|
24
|
+
i += 1
|
|
25
|
+
|
|
26
|
+
# Check for tool responses
|
|
27
|
+
while i < n and expected_ids:
|
|
28
|
+
next_msg = messages[i]
|
|
29
|
+
if next_msg.get("role") == "tool" and next_msg.get("tool_call_id") in expected_ids:
|
|
30
|
+
expected_ids.discard(next_msg.get("tool_call_id"))
|
|
31
|
+
i += 1
|
|
32
|
+
else:
|
|
33
|
+
break
|
|
34
|
+
|
|
35
|
+
# If we still have expected IDs, the tool sequence is incomplete
|
|
36
|
+
if expected_ids:
|
|
37
|
+
turns = format_messages(messages)
|
|
38
|
+
raise ValueError(
|
|
39
|
+
"Incomplete tool sequence - missing responses for tool calls:\n\n" + turns
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# Continue to next message after tool sequence
|
|
43
|
+
continue
|
|
44
|
+
|
|
45
|
+
elif role == "tool":
|
|
46
|
+
# Orphaned tool message without preceding assistant tool_calls
|
|
47
|
+
turns = format_messages(messages)
|
|
48
|
+
raise ValueError(
|
|
49
|
+
"Orphaned tool message without preceding assistant tool_calls:\n\n" + turns
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# Handle normal role alternation
|
|
15
53
|
if role == "system":
|
|
54
|
+
i += 1
|
|
16
55
|
continue
|
|
17
56
|
|
|
18
57
|
if last_role and role == last_role:
|
|
@@ -21,16 +60,84 @@ def sanity_check_messages(messages):
|
|
|
21
60
|
|
|
22
61
|
last_role = role
|
|
23
62
|
last_non_system_role = role
|
|
63
|
+
i += 1
|
|
24
64
|
|
|
25
65
|
# Ensure last non-system message is from user
|
|
26
66
|
return last_non_system_role == "user"
|
|
27
67
|
|
|
28
68
|
|
|
69
|
+
def clean_orphaned_tool_messages(messages):
|
|
70
|
+
"""Remove orphaned tool messages and incomplete tool sequences.
|
|
71
|
+
|
|
72
|
+
This function removes:
|
|
73
|
+
- Tool messages without a preceding assistant message containing tool_calls
|
|
74
|
+
- Assistant messages with tool_calls that don't have complete tool responses
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
messages: List of message dictionaries
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
Cleaned list of messages with orphaned tool sequences removed
|
|
81
|
+
"""
|
|
82
|
+
if not messages:
|
|
83
|
+
return messages
|
|
84
|
+
|
|
85
|
+
cleaned = []
|
|
86
|
+
i = 0
|
|
87
|
+
n = len(messages)
|
|
88
|
+
|
|
89
|
+
while i < n:
|
|
90
|
+
msg = messages[i]
|
|
91
|
+
role = msg.get("role")
|
|
92
|
+
|
|
93
|
+
# If it's an assistant message with tool_calls, check if we have complete responses
|
|
94
|
+
if role == "assistant" and "tool_calls" in msg and msg["tool_calls"]:
|
|
95
|
+
# Start of potential tool sequence
|
|
96
|
+
tool_sequence = [msg]
|
|
97
|
+
expected_ids = {call["id"] for call in msg["tool_calls"]}
|
|
98
|
+
j = i + 1
|
|
99
|
+
|
|
100
|
+
# Collect tool responses
|
|
101
|
+
while j < n and expected_ids:
|
|
102
|
+
next_msg = messages[j]
|
|
103
|
+
if next_msg.get("role") == "tool" and next_msg.get("tool_call_id") in expected_ids:
|
|
104
|
+
tool_sequence.append(next_msg)
|
|
105
|
+
expected_ids.discard(next_msg.get("tool_call_id"))
|
|
106
|
+
j += 1
|
|
107
|
+
else:
|
|
108
|
+
break
|
|
109
|
+
|
|
110
|
+
# If we have all tool responses, keep the sequence
|
|
111
|
+
if not expected_ids:
|
|
112
|
+
cleaned.extend(tool_sequence)
|
|
113
|
+
i = j
|
|
114
|
+
else:
|
|
115
|
+
# Incomplete sequence - skip the entire tool sequence
|
|
116
|
+
i = j
|
|
117
|
+
# Don't add anything to cleaned
|
|
118
|
+
continue
|
|
119
|
+
|
|
120
|
+
elif role == "tool":
|
|
121
|
+
# Orphaned tool message without preceding assistant tool_calls - skip it
|
|
122
|
+
i += 1
|
|
123
|
+
continue
|
|
124
|
+
else:
|
|
125
|
+
# Regular message - add it
|
|
126
|
+
cleaned.append(msg)
|
|
127
|
+
i += 1
|
|
128
|
+
|
|
129
|
+
return cleaned
|
|
130
|
+
|
|
131
|
+
|
|
29
132
|
def ensure_alternating_roles(messages):
|
|
30
133
|
"""Ensure messages alternate between 'assistant' and 'user' roles.
|
|
31
134
|
|
|
32
135
|
Inserts empty messages of the opposite role when consecutive messages
|
|
33
|
-
of the same role are found.
|
|
136
|
+
of the same 'user' or 'assistant' role are found. Messages with other
|
|
137
|
+
roles (e.g. 'system', 'tool') are ignored by the alternation logic.
|
|
138
|
+
|
|
139
|
+
Also handles tool call sequences properly - when an assistant message
|
|
140
|
+
contains tool_calls, processes the complete tool sequence atomically.
|
|
34
141
|
|
|
35
142
|
Args:
|
|
36
143
|
messages: List of message dictionaries with 'role' and 'content' keys.
|
|
@@ -41,21 +148,84 @@ def ensure_alternating_roles(messages):
|
|
|
41
148
|
if not messages:
|
|
42
149
|
return messages
|
|
43
150
|
|
|
44
|
-
|
|
151
|
+
# First clean orphaned tool messages
|
|
152
|
+
messages = clean_orphaned_tool_messages(messages)
|
|
153
|
+
|
|
154
|
+
result = []
|
|
155
|
+
i = 0
|
|
156
|
+
n = len(messages)
|
|
45
157
|
prev_role = None
|
|
46
158
|
|
|
47
|
-
|
|
48
|
-
|
|
159
|
+
while i < n:
|
|
160
|
+
msg = messages[i]
|
|
161
|
+
role = msg.get("role")
|
|
49
162
|
|
|
50
|
-
#
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
163
|
+
# Handle tool call sequences atomically
|
|
164
|
+
if role == "assistant" and "tool_calls" in msg and msg["tool_calls"]:
|
|
165
|
+
# Start of tool sequence - collect all related messages
|
|
166
|
+
tool_sequence = [msg]
|
|
167
|
+
expected_ids = {call["id"] for call in msg["tool_calls"]}
|
|
168
|
+
i += 1
|
|
169
|
+
|
|
170
|
+
# Collect tool responses
|
|
171
|
+
while i < n and expected_ids:
|
|
172
|
+
next_msg = messages[i]
|
|
173
|
+
if next_msg.get("role") == "tool" and next_msg.get("tool_call_id") in expected_ids:
|
|
174
|
+
tool_sequence.append(next_msg)
|
|
175
|
+
expected_ids.discard(next_msg.get("tool_call_id"))
|
|
176
|
+
i += 1
|
|
177
|
+
else:
|
|
178
|
+
break
|
|
179
|
+
|
|
180
|
+
# Add missing tool responses as empty
|
|
181
|
+
for tool_id in expected_ids:
|
|
182
|
+
tool_sequence.append({"role": "tool", "tool_call_id": tool_id, "content": ""})
|
|
183
|
+
|
|
184
|
+
# Add the complete tool sequence to result
|
|
185
|
+
for tool_msg in tool_sequence:
|
|
186
|
+
result.append(tool_msg)
|
|
187
|
+
|
|
188
|
+
# Update prev_role to assistant after processing tool sequence
|
|
189
|
+
prev_role = "assistant"
|
|
190
|
+
continue
|
|
191
|
+
|
|
192
|
+
# Handle normal message alternation
|
|
193
|
+
if role in ("user", "assistant"):
|
|
194
|
+
if role == prev_role:
|
|
195
|
+
# Insert empty message of opposite role
|
|
196
|
+
opposite_role = "user" if role == "assistant" else "assistant"
|
|
197
|
+
result.append({"role": opposite_role, "content": ""})
|
|
198
|
+
prev_role = opposite_role
|
|
199
|
+
|
|
200
|
+
result.append(msg)
|
|
201
|
+
prev_role = role
|
|
202
|
+
else:
|
|
203
|
+
# For non-user/assistant roles, just add them directly
|
|
204
|
+
result.append(msg)
|
|
205
|
+
|
|
206
|
+
i += 1
|
|
207
|
+
|
|
208
|
+
# Consolidate consecutive empty messages in a single pass
|
|
209
|
+
consolidated = []
|
|
210
|
+
for msg in result:
|
|
211
|
+
if not consolidated:
|
|
212
|
+
consolidated.append(msg)
|
|
213
|
+
continue
|
|
214
|
+
|
|
215
|
+
last_msg = consolidated[-1]
|
|
216
|
+
current_role = msg.get("role")
|
|
217
|
+
last_role = last_msg.get("role")
|
|
218
|
+
|
|
219
|
+
# Skip consecutive empty messages with the same role
|
|
220
|
+
if (
|
|
221
|
+
current_role in ("user", "assistant")
|
|
222
|
+
and last_role in ("user", "assistant")
|
|
223
|
+
and current_role == last_role
|
|
224
|
+
and msg.get("content") == ""
|
|
225
|
+
and last_msg.get("content") == ""
|
|
226
|
+
):
|
|
227
|
+
continue
|
|
57
228
|
|
|
58
|
-
|
|
59
|
-
prev_role = current_role
|
|
229
|
+
consolidated.append(msg)
|
|
60
230
|
|
|
61
|
-
return
|
|
231
|
+
return consolidated
|
aider/tools/__init__.py
CHANGED
|
@@ -1,26 +1,47 @@
|
|
|
1
1
|
# flake8: noqa: F401
|
|
2
2
|
# Import tool functions into the aider.tools namespace
|
|
3
3
|
|
|
4
|
-
from .command import _execute_command
|
|
5
|
-
from .command_interactive import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
from .
|
|
10
|
-
from .
|
|
11
|
-
from .
|
|
12
|
-
from .
|
|
13
|
-
from .
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
from .
|
|
24
|
-
from .
|
|
25
|
-
from .
|
|
26
|
-
from .
|
|
4
|
+
from .command import _execute_command, command_schema
|
|
5
|
+
from .command_interactive import (
|
|
6
|
+
_execute_command_interactive,
|
|
7
|
+
command_interactive_schema,
|
|
8
|
+
)
|
|
9
|
+
from .delete_block import _execute_delete_block, delete_block_schema
|
|
10
|
+
from .delete_line import _execute_delete_line, delete_line_schema
|
|
11
|
+
from .delete_lines import _execute_delete_lines, delete_lines_schema
|
|
12
|
+
from .extract_lines import _execute_extract_lines, extract_lines_schema
|
|
13
|
+
from .git import (
|
|
14
|
+
_execute_git_diff,
|
|
15
|
+
_execute_git_log,
|
|
16
|
+
_execute_git_show,
|
|
17
|
+
_execute_git_status,
|
|
18
|
+
git_diff_schema,
|
|
19
|
+
git_log_schema,
|
|
20
|
+
git_show_schema,
|
|
21
|
+
git_status_schema,
|
|
22
|
+
)
|
|
23
|
+
from .grep import _execute_grep, grep_schema
|
|
24
|
+
from .indent_lines import _execute_indent_lines, indent_lines_schema
|
|
25
|
+
from .insert_block import _execute_insert_block, insert_block_schema
|
|
26
|
+
from .list_changes import _execute_list_changes, list_changes_schema
|
|
27
|
+
from .ls import execute_ls, ls_schema
|
|
28
|
+
from .make_editable import _execute_make_editable, make_editable_schema
|
|
29
|
+
from .make_readonly import _execute_make_readonly, make_readonly_schema
|
|
30
|
+
from .remove import _execute_remove, remove_schema
|
|
31
|
+
from .replace_all import _execute_replace_all, replace_all_schema
|
|
32
|
+
from .replace_line import _execute_replace_line, replace_line_schema
|
|
33
|
+
from .replace_lines import _execute_replace_lines, replace_lines_schema
|
|
34
|
+
from .replace_text import _execute_replace_text, replace_text_schema
|
|
35
|
+
from .show_numbered_context import (
|
|
36
|
+
execute_show_numbered_context,
|
|
37
|
+
show_numbered_context_schema,
|
|
38
|
+
)
|
|
39
|
+
from .undo_change import _execute_undo_change, undo_change_schema
|
|
40
|
+
from .update_todo_list import _execute_update_todo_list, update_todo_list_schema
|
|
41
|
+
from .view import execute_view, view_schema
|
|
42
|
+
from .view_files_at_glob import execute_view_files_at_glob, view_files_at_glob_schema
|
|
43
|
+
from .view_files_matching import execute_view_files_matching, view_files_matching_schema
|
|
44
|
+
from .view_files_with_symbol import (
|
|
45
|
+
_execute_view_files_with_symbol,
|
|
46
|
+
view_files_with_symbol_schema,
|
|
47
|
+
)
|
aider/tools/command.py
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
# Import necessary functions
|
|
2
2
|
from aider.run_cmd import run_cmd_subprocess
|
|
3
3
|
|
|
4
|
+
command_schema = {
|
|
5
|
+
"type": "function",
|
|
6
|
+
"function": {
|
|
7
|
+
"name": "Command",
|
|
8
|
+
"description": "Execute a shell command.",
|
|
9
|
+
"parameters": {
|
|
10
|
+
"type": "object",
|
|
11
|
+
"properties": {
|
|
12
|
+
"command_string": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"description": "The shell command to execute.",
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
"required": ["command_string"],
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
}
|
|
21
|
+
|
|
4
22
|
|
|
5
23
|
def _execute_command(coder, command_string):
|
|
6
24
|
"""
|
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
# Import necessary functions
|
|
2
2
|
from aider.run_cmd import run_cmd
|
|
3
3
|
|
|
4
|
+
command_interactive_schema = {
|
|
5
|
+
"type": "function",
|
|
6
|
+
"function": {
|
|
7
|
+
"name": "CommandInteractive",
|
|
8
|
+
"description": "Execute a shell command interactively.",
|
|
9
|
+
"parameters": {
|
|
10
|
+
"type": "object",
|
|
11
|
+
"properties": {
|
|
12
|
+
"command_string": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"description": "The interactive shell command to execute.",
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
"required": ["command_string"],
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
}
|
|
21
|
+
|
|
4
22
|
|
|
5
23
|
def _execute_command_interactive(coder, command_string):
|
|
6
24
|
"""
|
aider/tools/delete_block.py
CHANGED
|
@@ -10,6 +10,28 @@ from .tool_utils import (
|
|
|
10
10
|
validate_file_for_edit,
|
|
11
11
|
)
|
|
12
12
|
|
|
13
|
+
delete_block_schema = {
|
|
14
|
+
"type": "function",
|
|
15
|
+
"function": {
|
|
16
|
+
"name": "DeleteBlock",
|
|
17
|
+
"description": "Delete a block of lines from a file.",
|
|
18
|
+
"parameters": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"properties": {
|
|
21
|
+
"file_path": {"type": "string"},
|
|
22
|
+
"start_pattern": {"type": "string"},
|
|
23
|
+
"end_pattern": {"type": "string"},
|
|
24
|
+
"line_count": {"type": "integer"},
|
|
25
|
+
"near_context": {"type": "string"},
|
|
26
|
+
"occurrence": {"type": "integer", "default": 1},
|
|
27
|
+
"change_id": {"type": "string"},
|
|
28
|
+
"dry_run": {"type": "boolean", "default": False},
|
|
29
|
+
},
|
|
30
|
+
"required": ["file_path", "start_pattern"],
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
|
|
13
35
|
|
|
14
36
|
def _execute_delete_block(
|
|
15
37
|
coder,
|
|
@@ -103,6 +125,7 @@ def _execute_delete_block(
|
|
|
103
125
|
change_id,
|
|
104
126
|
)
|
|
105
127
|
|
|
128
|
+
coder.files_edited_by_tools.add(rel_path)
|
|
106
129
|
# 8. Format and return result, adding line range to success message
|
|
107
130
|
success_message = (
|
|
108
131
|
f"Deleted {num_deleted} lines ({start_line + 1}-{end_line + 1}) (from"
|
aider/tools/delete_line.py
CHANGED
|
@@ -8,6 +8,24 @@ from .tool_utils import (
|
|
|
8
8
|
handle_tool_error,
|
|
9
9
|
)
|
|
10
10
|
|
|
11
|
+
delete_line_schema = {
|
|
12
|
+
"type": "function",
|
|
13
|
+
"function": {
|
|
14
|
+
"name": "DeleteLine",
|
|
15
|
+
"description": "Delete a single line from a file.",
|
|
16
|
+
"parameters": {
|
|
17
|
+
"type": "object",
|
|
18
|
+
"properties": {
|
|
19
|
+
"file_path": {"type": "string"},
|
|
20
|
+
"line_number": {"type": "integer"},
|
|
21
|
+
"change_id": {"type": "string"},
|
|
22
|
+
"dry_run": {"type": "boolean", "default": False},
|
|
23
|
+
},
|
|
24
|
+
"required": ["file_path", "line_number"],
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
|
|
11
29
|
|
|
12
30
|
def _execute_delete_line(coder, file_path, line_number, change_id=None, dry_run=False):
|
|
13
31
|
"""
|
|
@@ -96,7 +114,7 @@ def _execute_delete_line(coder, file_path, line_number, change_id=None, dry_run=
|
|
|
96
114
|
change_id,
|
|
97
115
|
)
|
|
98
116
|
|
|
99
|
-
coder.
|
|
117
|
+
coder.files_edited_by_tools.add(rel_path)
|
|
100
118
|
|
|
101
119
|
# Format and return result
|
|
102
120
|
success_message = f"Deleted line {line_num_int} in {file_path}"
|
aider/tools/delete_lines.py
CHANGED
|
@@ -8,6 +8,25 @@ from .tool_utils import (
|
|
|
8
8
|
handle_tool_error,
|
|
9
9
|
)
|
|
10
10
|
|
|
11
|
+
delete_lines_schema = {
|
|
12
|
+
"type": "function",
|
|
13
|
+
"function": {
|
|
14
|
+
"name": "DeleteLines",
|
|
15
|
+
"description": "Delete a range of lines from 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
|
+
"change_id": {"type": "string"},
|
|
23
|
+
"dry_run": {"type": "boolean", "default": False},
|
|
24
|
+
},
|
|
25
|
+
"required": ["file_path", "start_line", "end_line"],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
|
|
11
30
|
|
|
12
31
|
def _execute_delete_lines(coder, file_path, start_line, end_line, change_id=None, dry_run=False):
|
|
13
32
|
"""
|
|
@@ -119,7 +138,7 @@ def _execute_delete_lines(coder, file_path, start_line, end_line, change_id=None
|
|
|
119
138
|
change_id,
|
|
120
139
|
)
|
|
121
140
|
|
|
122
|
-
coder.
|
|
141
|
+
coder.files_edited_by_tools.add(rel_path)
|
|
123
142
|
num_deleted = end_idx - start_idx + 1
|
|
124
143
|
# Format and return result
|
|
125
144
|
success_message = (
|
aider/tools/extract_lines.py
CHANGED
|
@@ -3,6 +3,28 @@ import traceback
|
|
|
3
3
|
|
|
4
4
|
from .tool_utils import generate_unified_diff_snippet
|
|
5
5
|
|
|
6
|
+
extract_lines_schema = {
|
|
7
|
+
"type": "function",
|
|
8
|
+
"function": {
|
|
9
|
+
"name": "ExtractLines",
|
|
10
|
+
"description": "Extract lines from a source file and append them to a target file.",
|
|
11
|
+
"parameters": {
|
|
12
|
+
"type": "object",
|
|
13
|
+
"properties": {
|
|
14
|
+
"source_file_path": {"type": "string"},
|
|
15
|
+
"target_file_path": {"type": "string"},
|
|
16
|
+
"start_pattern": {"type": "string"},
|
|
17
|
+
"end_pattern": {"type": "string"},
|
|
18
|
+
"line_count": {"type": "integer"},
|
|
19
|
+
"near_context": {"type": "string"},
|
|
20
|
+
"occurrence": {"type": "integer", "default": 1},
|
|
21
|
+
"dry_run": {"type": "boolean", "default": False},
|
|
22
|
+
},
|
|
23
|
+
"required": ["source_file_path", "target_file_path", "start_pattern"],
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
}
|
|
27
|
+
|
|
6
28
|
|
|
7
29
|
def _execute_extract_lines(
|
|
8
30
|
coder,
|
|
@@ -248,8 +270,9 @@ def _execute_extract_lines(
|
|
|
248
270
|
coder.io.tool_error(f"Error tracking target change for ExtractLines: {track_e}")
|
|
249
271
|
|
|
250
272
|
# --- Update Context ---
|
|
251
|
-
coder.
|
|
252
|
-
coder.
|
|
273
|
+
coder.files_edited_by_tools.add(rel_source_path)
|
|
274
|
+
coder.files_edited_by_tools.add(rel_target_path)
|
|
275
|
+
|
|
253
276
|
if not target_exists:
|
|
254
277
|
# Add the newly created file to editable context
|
|
255
278
|
coder.abs_fnames.add(abs_target_path)
|