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.
- aider/__init__.py +1 -1
- aider/_version.py +2 -2
- aider/args.py +63 -43
- aider/coders/agent_coder.py +331 -79
- aider/coders/agent_prompts.py +3 -15
- aider/coders/architect_coder.py +21 -5
- aider/coders/base_coder.py +661 -413
- aider/coders/base_prompts.py +6 -3
- aider/coders/chat_chunks.py +39 -17
- aider/commands.py +79 -15
- aider/diffs.py +10 -9
- aider/exceptions.py +1 -1
- aider/helpers/coroutines.py +8 -0
- aider/helpers/requests.py +45 -0
- aider/history.py +5 -0
- aider/io.py +179 -25
- aider/main.py +86 -35
- aider/models.py +16 -8
- aider/queries/tree-sitter-language-pack/c-tags.scm +3 -0
- aider/queries/tree-sitter-language-pack/clojure-tags.scm +5 -0
- aider/queries/tree-sitter-language-pack/commonlisp-tags.scm +5 -0
- aider/queries/tree-sitter-language-pack/cpp-tags.scm +3 -0
- aider/queries/tree-sitter-language-pack/csharp-tags.scm +6 -0
- aider/queries/tree-sitter-language-pack/dart-tags.scm +5 -0
- aider/queries/tree-sitter-language-pack/elixir-tags.scm +5 -0
- aider/queries/tree-sitter-language-pack/elm-tags.scm +3 -0
- aider/queries/tree-sitter-language-pack/go-tags.scm +7 -0
- aider/queries/tree-sitter-language-pack/java-tags.scm +6 -0
- aider/queries/tree-sitter-language-pack/javascript-tags.scm +8 -0
- aider/queries/tree-sitter-language-pack/lua-tags.scm +5 -0
- aider/queries/tree-sitter-language-pack/ocaml_interface-tags.scm +3 -0
- aider/queries/tree-sitter-language-pack/python-tags.scm +10 -0
- aider/queries/tree-sitter-language-pack/r-tags.scm +6 -0
- aider/queries/tree-sitter-language-pack/ruby-tags.scm +5 -0
- aider/queries/tree-sitter-language-pack/rust-tags.scm +3 -0
- aider/queries/tree-sitter-language-pack/solidity-tags.scm +1 -1
- aider/queries/tree-sitter-language-pack/swift-tags.scm +4 -1
- aider/queries/tree-sitter-languages/c-tags.scm +3 -0
- aider/queries/tree-sitter-languages/c_sharp-tags.scm +6 -0
- aider/queries/tree-sitter-languages/cpp-tags.scm +3 -0
- aider/queries/tree-sitter-languages/dart-tags.scm +2 -1
- aider/queries/tree-sitter-languages/elixir-tags.scm +5 -0
- aider/queries/tree-sitter-languages/elm-tags.scm +3 -0
- aider/queries/tree-sitter-languages/fortran-tags.scm +3 -0
- aider/queries/tree-sitter-languages/go-tags.scm +6 -0
- aider/queries/tree-sitter-languages/haskell-tags.scm +2 -0
- aider/queries/tree-sitter-languages/java-tags.scm +6 -0
- aider/queries/tree-sitter-languages/javascript-tags.scm +8 -0
- aider/queries/tree-sitter-languages/julia-tags.scm +2 -2
- aider/queries/tree-sitter-languages/kotlin-tags.scm +3 -0
- aider/queries/tree-sitter-languages/ocaml_interface-tags.scm +6 -0
- aider/queries/tree-sitter-languages/php-tags.scm +6 -0
- aider/queries/tree-sitter-languages/python-tags.scm +10 -0
- aider/queries/tree-sitter-languages/ruby-tags.scm +5 -0
- aider/queries/tree-sitter-languages/rust-tags.scm +3 -0
- aider/queries/tree-sitter-languages/scala-tags.scm +2 -3
- aider/queries/tree-sitter-languages/typescript-tags.scm +3 -0
- aider/queries/tree-sitter-languages/zig-tags.scm +20 -3
- aider/repomap.py +71 -11
- aider/resources/model-metadata.json +27335 -635
- aider/resources/model-settings.yml +190 -0
- aider/scrape.py +2 -0
- aider/tools/__init__.py +2 -0
- aider/tools/command.py +84 -94
- aider/tools/command_interactive.py +95 -110
- aider/tools/delete_block.py +131 -159
- aider/tools/delete_line.py +97 -132
- aider/tools/delete_lines.py +120 -160
- aider/tools/extract_lines.py +288 -312
- aider/tools/finished.py +30 -43
- aider/tools/git_branch.py +107 -109
- aider/tools/git_diff.py +44 -56
- aider/tools/git_log.py +39 -53
- aider/tools/git_remote.py +37 -51
- aider/tools/git_show.py +33 -47
- aider/tools/git_status.py +30 -44
- aider/tools/grep.py +214 -242
- aider/tools/indent_lines.py +175 -201
- aider/tools/insert_block.py +220 -253
- aider/tools/list_changes.py +65 -80
- aider/tools/ls.py +64 -80
- aider/tools/make_editable.py +57 -73
- aider/tools/make_readonly.py +50 -66
- aider/tools/remove.py +64 -80
- aider/tools/replace_all.py +96 -109
- aider/tools/replace_line.py +118 -156
- aider/tools/replace_lines.py +160 -197
- aider/tools/replace_text.py +159 -160
- aider/tools/show_numbered_context.py +115 -141
- aider/tools/thinking.py +52 -0
- aider/tools/undo_change.py +78 -91
- aider/tools/update_todo_list.py +130 -138
- aider/tools/utils/base_tool.py +64 -0
- aider/tools/utils/output.py +118 -0
- aider/tools/view.py +38 -54
- aider/tools/view_files_matching.py +131 -134
- aider/tools/view_files_with_symbol.py +108 -120
- aider/urls.py +1 -1
- aider/versioncheck.py +4 -3
- aider/website/docs/config/adv-model-settings.md +237 -0
- aider/website/docs/config/agent-mode.md +36 -3
- aider/website/docs/config/model-aliases.md +2 -1
- aider/website/docs/faq.md +6 -11
- aider/website/docs/languages.md +2 -2
- aider/website/docs/more/infinite-output.md +27 -0
- {aider_ce-0.88.20.dist-info → aider_ce-0.88.38.dist-info}/METADATA +112 -70
- {aider_ce-0.88.20.dist-info → aider_ce-0.88.38.dist-info}/RECORD +112 -107
- aider_ce-0.88.38.dist-info/entry_points.txt +6 -0
- aider_ce-0.88.20.dist-info/entry_points.txt +0 -2
- /aider/tools/{tool_utils.py → utils/helpers.py} +0 -0
- {aider_ce-0.88.20.dist-info → aider_ce-0.88.38.dist-info}/WHEEL +0 -0
- {aider_ce-0.88.20.dist-info → aider_ce-0.88.38.dist-info}/licenses/LICENSE.txt +0 -0
- {aider_ce-0.88.20.dist-info → aider_ce-0.88.38.dist-info}/top_level.txt +0 -0
aider/tools/thinking.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from aider.tools.utils.base_tool import BaseTool
|
|
4
|
+
from aider.tools.utils.output import color_markers, tool_footer, tool_header
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Tool(BaseTool):
|
|
8
|
+
NORM_NAME = "thinking"
|
|
9
|
+
SCHEMA = {
|
|
10
|
+
"type": "function",
|
|
11
|
+
"function": {
|
|
12
|
+
"name": "Thinking",
|
|
13
|
+
"description": (
|
|
14
|
+
"Use this tool to store useful facts for later "
|
|
15
|
+
"keep a scratch pad of your current efforts "
|
|
16
|
+
"and clarify your thoughts and intentions for your next steps."
|
|
17
|
+
),
|
|
18
|
+
"parameters": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"properties": {
|
|
21
|
+
"content": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"description": "Textual information to record in the context",
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
"required": ["content"],
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def execute(cls, coder, content):
|
|
33
|
+
"""
|
|
34
|
+
A place to allow the model to record freeform text as it
|
|
35
|
+
iterates over tools to ideally help it guide itself to a proper solution
|
|
36
|
+
"""
|
|
37
|
+
coder.io.tool_output("🧠 Thoughts recorded in context")
|
|
38
|
+
return content
|
|
39
|
+
|
|
40
|
+
@classmethod
|
|
41
|
+
def format_output(cls, coder, mcp_server, tool_response):
|
|
42
|
+
color_start, color_end = color_markers(coder)
|
|
43
|
+
params = json.loads(tool_response.function.arguments)
|
|
44
|
+
|
|
45
|
+
tool_header(coder=coder, mcp_server=mcp_server, tool_response=tool_response)
|
|
46
|
+
|
|
47
|
+
coder.io.tool_output("")
|
|
48
|
+
coder.io.tool_output(f"{color_start}Thoughts:{color_end}")
|
|
49
|
+
coder.io.tool_output(params["content"])
|
|
50
|
+
coder.io.tool_output("")
|
|
51
|
+
|
|
52
|
+
tool_footer(coder=coder, tool_response=tool_response)
|
aider/tools/undo_change.py
CHANGED
|
@@ -1,95 +1,82 @@
|
|
|
1
1
|
import traceback
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
3
|
+
from aider.tools.utils.base_tool import BaseTool
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Tool(BaseTool):
|
|
7
|
+
NORM_NAME = "undochange"
|
|
8
|
+
SCHEMA = {
|
|
9
|
+
"type": "function",
|
|
10
|
+
"function": {
|
|
11
|
+
"name": "UndoChange",
|
|
12
|
+
"description": "Undo a previously applied change.",
|
|
13
|
+
"parameters": {
|
|
14
|
+
"type": "object",
|
|
15
|
+
"properties": {
|
|
16
|
+
"change_id": {"type": "string"},
|
|
17
|
+
"file_path": {"type": "string"},
|
|
18
|
+
},
|
|
13
19
|
},
|
|
14
20
|
},
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
"
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
coder.io.tool_error(f"Error in UndoChange: {str(e)}\n{traceback.format_exc()}")
|
|
78
|
-
return f"Error: {str(e)}"
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
def process_response(coder, params):
|
|
82
|
-
"""
|
|
83
|
-
Process the UndoChange tool response.
|
|
84
|
-
|
|
85
|
-
Args:
|
|
86
|
-
coder: The Coder instance
|
|
87
|
-
params: Dictionary of parameters
|
|
88
|
-
|
|
89
|
-
Returns:
|
|
90
|
-
str: Result message
|
|
91
|
-
"""
|
|
92
|
-
change_id = params.get("change_id")
|
|
93
|
-
file_path = params.get("file_path")
|
|
94
|
-
|
|
95
|
-
return _execute_undo_change(coder, change_id, file_path)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
def execute(cls, coder, change_id=None, file_path=None):
|
|
25
|
+
"""
|
|
26
|
+
Undo a specific change by ID, or the last change to a file.
|
|
27
|
+
|
|
28
|
+
Parameters:
|
|
29
|
+
- coder: The Coder instance
|
|
30
|
+
- change_id: ID of the change to undo
|
|
31
|
+
- file_path: Path to file where the last change should be undone
|
|
32
|
+
|
|
33
|
+
Returns a result message.
|
|
34
|
+
"""
|
|
35
|
+
# Note: Undo does not have a dry_run parameter as it's inherently about reverting a previous action.
|
|
36
|
+
try:
|
|
37
|
+
# Validate parameters
|
|
38
|
+
if change_id is None and file_path is None:
|
|
39
|
+
coder.io.tool_error("Must specify either change_id or file_path for UndoChange")
|
|
40
|
+
return "Error: Must specify either change_id or file_path"
|
|
41
|
+
|
|
42
|
+
# If file_path is specified, get the most recent change for that file
|
|
43
|
+
if file_path:
|
|
44
|
+
abs_path = coder.abs_root_path(file_path)
|
|
45
|
+
rel_path = coder.get_rel_fname(abs_path)
|
|
46
|
+
|
|
47
|
+
change_id = coder.change_tracker.get_last_change(rel_path)
|
|
48
|
+
if not change_id:
|
|
49
|
+
coder.io.tool_error(f"No tracked changes found for file '{file_path}' to undo.")
|
|
50
|
+
return f"Error: No changes found for file '{file_path}'"
|
|
51
|
+
|
|
52
|
+
# Attempt to get undo information from the tracker
|
|
53
|
+
success, message, change_info = coder.change_tracker.undo_change(change_id)
|
|
54
|
+
|
|
55
|
+
if not success:
|
|
56
|
+
coder.io.tool_error(f"Failed to undo change '{change_id}': {message}")
|
|
57
|
+
return f"Error: {message}"
|
|
58
|
+
|
|
59
|
+
# Apply the undo by restoring the original content
|
|
60
|
+
if change_info:
|
|
61
|
+
file_path = change_info["file_path"]
|
|
62
|
+
abs_path = coder.abs_root_path(file_path)
|
|
63
|
+
# Write the original content back to the file
|
|
64
|
+
coder.io.write_text(abs_path, change_info["original"])
|
|
65
|
+
coder.aider_edited_files.add(
|
|
66
|
+
file_path
|
|
67
|
+
) # Track that the file was modified by the undo
|
|
68
|
+
|
|
69
|
+
change_type = change_info["type"]
|
|
70
|
+
coder.io.tool_output(f"✅ Undid {change_type} change '{change_id}' in {file_path}")
|
|
71
|
+
return f"Successfully undid {change_type} change '{change_id}'."
|
|
72
|
+
else:
|
|
73
|
+
# This case should ideally not be reached if tracker returns success
|
|
74
|
+
coder.io.tool_error(
|
|
75
|
+
f"Failed to undo change '{change_id}': Change info missing after successful"
|
|
76
|
+
" tracker update."
|
|
77
|
+
)
|
|
78
|
+
return f"Error: Failed to undo change '{change_id}' (missing change info)"
|
|
79
|
+
|
|
80
|
+
except Exception as e:
|
|
81
|
+
coder.io.tool_error(f"Error in UndoChange: {str(e)}\n{traceback.format_exc()}")
|
|
82
|
+
return f"Error: {str(e)}"
|
aider/tools/update_todo_list.py
CHANGED
|
@@ -1,156 +1,148 @@
|
|
|
1
|
-
from .
|
|
1
|
+
from aider.tools.utils.base_tool import BaseTool
|
|
2
|
+
from aider.tools.utils.helpers import (
|
|
2
3
|
ToolError,
|
|
3
4
|
format_tool_result,
|
|
4
5
|
generate_unified_diff_snippet,
|
|
5
6
|
handle_tool_error,
|
|
6
7
|
)
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
8
|
+
from aider.tools.utils.output import tool_body_unwrapped, tool_footer, tool_header
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Tool(BaseTool):
|
|
12
|
+
NORM_NAME = "updatetodolist"
|
|
13
|
+
SCHEMA = {
|
|
14
|
+
"type": "function",
|
|
15
|
+
"function": {
|
|
16
|
+
"name": "UpdateTodoList",
|
|
17
|
+
"description": "Update the todo list with new items or modify existing ones.",
|
|
18
|
+
"parameters": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"properties": {
|
|
21
|
+
"content": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"description": "The new content for the todo list.",
|
|
24
|
+
},
|
|
25
|
+
"append": {
|
|
26
|
+
"type": "boolean",
|
|
27
|
+
"description": (
|
|
28
|
+
"Whether to append to existing content instead of replacing it."
|
|
29
|
+
" Defaults to False."
|
|
30
|
+
),
|
|
31
|
+
},
|
|
32
|
+
"change_id": {
|
|
33
|
+
"type": "string",
|
|
34
|
+
"description": "Optional change ID for tracking.",
|
|
35
|
+
},
|
|
36
|
+
"dry_run": {
|
|
37
|
+
"type": "boolean",
|
|
38
|
+
"description": (
|
|
39
|
+
"Whether to perform a dry run without actually updating the file."
|
|
40
|
+
" Defaults to False."
|
|
41
|
+
),
|
|
42
|
+
},
|
|
37
43
|
},
|
|
44
|
+
"required": ["content"],
|
|
38
45
|
},
|
|
39
|
-
"required": ["content"],
|
|
40
46
|
},
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@classmethod
|
|
50
|
+
def execute(cls, coder, content, append=False, change_id=None, dry_run=False):
|
|
51
|
+
"""
|
|
52
|
+
Update the todo list file (.aider.todo.txt) with new content.
|
|
53
|
+
Can either replace the entire content or append to it.
|
|
54
|
+
"""
|
|
55
|
+
tool_name = "UpdateTodoList"
|
|
56
|
+
try:
|
|
57
|
+
# Define the todo file path
|
|
58
|
+
todo_file_path = ".aider.todo.txt"
|
|
59
|
+
abs_path = coder.abs_root_path(todo_file_path)
|
|
60
|
+
|
|
61
|
+
# Get existing content if appending
|
|
62
|
+
existing_content = ""
|
|
63
|
+
import os
|
|
64
|
+
|
|
65
|
+
if os.path.isfile(abs_path):
|
|
66
|
+
existing_content = coder.io.read_text(abs_path) or ""
|
|
67
|
+
|
|
68
|
+
# Prepare new content
|
|
69
|
+
if append:
|
|
70
|
+
if existing_content and not existing_content.endswith("\n"):
|
|
71
|
+
existing_content += "\n"
|
|
72
|
+
new_content = existing_content + content
|
|
73
|
+
else:
|
|
74
|
+
new_content = content
|
|
75
|
+
|
|
76
|
+
# Check if content exceeds 4096 characters and warn
|
|
77
|
+
if len(new_content) > 4096:
|
|
78
|
+
coder.io.tool_warning(
|
|
79
|
+
"⚠️ Todo list content exceeds 4096 characters. Consider summarizing the plan"
|
|
80
|
+
" before proceeding."
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# Check if content actually changed
|
|
84
|
+
if existing_content == new_content:
|
|
85
|
+
coder.io.tool_warning("No changes made: new content is identical to existing")
|
|
86
|
+
return "Warning: No changes made (content identical to existing)"
|
|
87
|
+
|
|
88
|
+
# Generate diff for feedback
|
|
89
|
+
diff_snippet = generate_unified_diff_snippet(
|
|
90
|
+
existing_content, new_content, todo_file_path
|
|
79
91
|
)
|
|
80
92
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
93
|
+
# Handle dry run
|
|
94
|
+
if dry_run:
|
|
95
|
+
action = "append to" if append else "replace"
|
|
96
|
+
dry_run_message = f"Dry run: Would {action} todo list in {todo_file_path}."
|
|
97
|
+
return format_tool_result(
|
|
98
|
+
coder,
|
|
99
|
+
tool_name,
|
|
100
|
+
"",
|
|
101
|
+
dry_run=True,
|
|
102
|
+
dry_run_message=dry_run_message,
|
|
103
|
+
diff_snippet=diff_snippet,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# Apply change
|
|
107
|
+
metadata = {
|
|
108
|
+
"append": append,
|
|
109
|
+
"existing_length": len(existing_content),
|
|
110
|
+
"new_length": len(new_content),
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
# Write the file directly since it's a special file
|
|
114
|
+
coder.io.write_text(abs_path, new_content)
|
|
115
|
+
|
|
116
|
+
# Track the change
|
|
117
|
+
final_change_id = coder.change_tracker.track_change(
|
|
118
|
+
file_path=todo_file_path,
|
|
119
|
+
change_type="updatetodolist",
|
|
120
|
+
original_content=existing_content,
|
|
121
|
+
new_content=new_content,
|
|
122
|
+
metadata=metadata,
|
|
123
|
+
change_id=change_id,
|
|
124
|
+
)
|
|
85
125
|
|
|
86
|
-
|
|
87
|
-
diff_snippet = generate_unified_diff_snippet(existing_content, new_content, todo_file_path)
|
|
126
|
+
coder.aider_edited_files.add(todo_file_path)
|
|
88
127
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
dry_run_message = f"Dry run: Would {action} todo list in {todo_file_path}."
|
|
128
|
+
# Format and return result
|
|
129
|
+
action = "appended to" if append else "updated"
|
|
130
|
+
success_message = f"Successfully {action} todo list in {todo_file_path}"
|
|
93
131
|
return format_tool_result(
|
|
94
132
|
coder,
|
|
95
133
|
tool_name,
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
dry_run_message=dry_run_message,
|
|
134
|
+
success_message,
|
|
135
|
+
change_id=final_change_id,
|
|
99
136
|
diff_snippet=diff_snippet,
|
|
100
137
|
)
|
|
101
138
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
coder
|
|
111
|
-
|
|
112
|
-
# Track the change
|
|
113
|
-
final_change_id = coder.change_tracker.track_change(
|
|
114
|
-
file_path=todo_file_path,
|
|
115
|
-
change_type="updatetodolist",
|
|
116
|
-
original_content=existing_content,
|
|
117
|
-
new_content=new_content,
|
|
118
|
-
metadata=metadata,
|
|
119
|
-
change_id=change_id,
|
|
120
|
-
)
|
|
121
|
-
|
|
122
|
-
coder.aider_edited_files.add(todo_file_path)
|
|
123
|
-
|
|
124
|
-
# Format and return result
|
|
125
|
-
action = "appended to" if append else "updated"
|
|
126
|
-
success_message = f"Successfully {action} todo list in {todo_file_path}"
|
|
127
|
-
return format_tool_result(
|
|
128
|
-
coder, tool_name, success_message, change_id=final_change_id, diff_snippet=diff_snippet
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
except ToolError as e:
|
|
132
|
-
return handle_tool_error(coder, tool_name, e, add_traceback=False)
|
|
133
|
-
except Exception as e:
|
|
134
|
-
return handle_tool_error(coder, tool_name, e)
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
def process_response(coder, params):
|
|
138
|
-
"""
|
|
139
|
-
Process the UpdateTodoList tool response.
|
|
140
|
-
|
|
141
|
-
Args:
|
|
142
|
-
coder: The Coder instance
|
|
143
|
-
params: Dictionary of parameters
|
|
144
|
-
|
|
145
|
-
Returns:
|
|
146
|
-
str: Result message
|
|
147
|
-
"""
|
|
148
|
-
content = params.get("content")
|
|
149
|
-
append = params.get("append", False)
|
|
150
|
-
change_id = params.get("change_id")
|
|
151
|
-
dry_run = params.get("dry_run", False)
|
|
152
|
-
|
|
153
|
-
if content is not None:
|
|
154
|
-
return _execute_update_todo_list(coder, content, append, change_id, dry_run)
|
|
155
|
-
else:
|
|
156
|
-
return "Error: Missing required 'content' parameter for UpdateTodoList"
|
|
139
|
+
except ToolError as e:
|
|
140
|
+
return handle_tool_error(coder, tool_name, e, add_traceback=False)
|
|
141
|
+
except Exception as e:
|
|
142
|
+
return handle_tool_error(coder, tool_name, e)
|
|
143
|
+
|
|
144
|
+
@classmethod
|
|
145
|
+
def format_output(cls, coder, mcp_server, tool_response):
|
|
146
|
+
tool_header(coder=coder, mcp_server=mcp_server, tool_response=tool_response)
|
|
147
|
+
tool_body_unwrapped(coder=coder, tool_response=tool_response)
|
|
148
|
+
tool_footer(coder=coder, tool_response=tool_response)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
from aider.tools.utils.helpers import handle_tool_error
|
|
4
|
+
from aider.tools.utils.output import print_tool_response
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BaseTool(ABC):
|
|
8
|
+
"""Abstract base class for all tools."""
|
|
9
|
+
|
|
10
|
+
# Class properties that must be defined by subclasses
|
|
11
|
+
# Note: NORM_NAME should be the lowercase version of the function name in the SCHEMA
|
|
12
|
+
NORM_NAME = None
|
|
13
|
+
SCHEMA = None
|
|
14
|
+
|
|
15
|
+
@classmethod
|
|
16
|
+
@abstractmethod
|
|
17
|
+
def execute(cls, coder, **params):
|
|
18
|
+
"""
|
|
19
|
+
Execute the tool with the given parameters.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
coder: The Coder instance
|
|
23
|
+
**params: Tool-specific parameters
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
str: Result message
|
|
27
|
+
"""
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def process_response(cls, coder, params):
|
|
32
|
+
"""
|
|
33
|
+
Process the tool response by creating an instance and calling execute.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
coder: The Coder instance
|
|
37
|
+
params: Dictionary of parameters
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
str: Result message
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
# Validate required parameters from SCHEMA
|
|
44
|
+
if cls.SCHEMA and "function" in cls.SCHEMA:
|
|
45
|
+
function_schema = cls.SCHEMA["function"]
|
|
46
|
+
|
|
47
|
+
if "parameters" in function_schema and "required" in function_schema["parameters"]:
|
|
48
|
+
required_params = function_schema["parameters"]["required"]
|
|
49
|
+
missing_params = [param for param in required_params if param not in params]
|
|
50
|
+
if missing_params:
|
|
51
|
+
tool_name = function_schema.get("name", "Unknown Tool")
|
|
52
|
+
error_msg = (
|
|
53
|
+
f"Missing required parameters for {tool_name}: {', '.join(missing_params)}"
|
|
54
|
+
)
|
|
55
|
+
return handle_tool_error(coder, tool_name, ValueError(error_msg))
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
return cls.execute(coder, **params)
|
|
59
|
+
except Exception as e:
|
|
60
|
+
return handle_tool_error(coder, cls.SCHEMA.get("function").get("name"), e)
|
|
61
|
+
|
|
62
|
+
@classmethod
|
|
63
|
+
def format_output(cls, coder, mcp_server, tool_response):
|
|
64
|
+
print_tool_response(coder=coder, mcp_server=mcp_server, tool_response=tool_response)
|