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
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
from .tool_utils import (
|
|
2
|
+
ToolError,
|
|
3
|
+
format_tool_result,
|
|
4
|
+
generate_unified_diff_snippet,
|
|
5
|
+
handle_tool_error,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
update_todo_list_schema = {
|
|
9
|
+
"type": "function",
|
|
10
|
+
"function": {
|
|
11
|
+
"name": "UpdateTodoList",
|
|
12
|
+
"description": "Update the todo list with new items or modify existing ones.",
|
|
13
|
+
"parameters": {
|
|
14
|
+
"type": "object",
|
|
15
|
+
"properties": {
|
|
16
|
+
"content": {
|
|
17
|
+
"type": "string",
|
|
18
|
+
"description": "The new content for the todo list.",
|
|
19
|
+
},
|
|
20
|
+
"append": {
|
|
21
|
+
"type": "boolean",
|
|
22
|
+
"description": (
|
|
23
|
+
"Whether to append to existing content instead of replacing it. Defaults to"
|
|
24
|
+
" False."
|
|
25
|
+
),
|
|
26
|
+
},
|
|
27
|
+
"change_id": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"description": "Optional change ID for tracking.",
|
|
30
|
+
},
|
|
31
|
+
"dry_run": {
|
|
32
|
+
"type": "boolean",
|
|
33
|
+
"description": (
|
|
34
|
+
"Whether to perform a dry run without actually updating the file. Defaults"
|
|
35
|
+
" to False."
|
|
36
|
+
),
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
"required": ["content"],
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _execute_update_todo_list(coder, content, append=False, change_id=None, dry_run=False):
|
|
46
|
+
"""
|
|
47
|
+
Update the todo list file (.aider.todo.txt) with new content.
|
|
48
|
+
Can either replace the entire content or append to it.
|
|
49
|
+
"""
|
|
50
|
+
tool_name = "UpdateTodoList"
|
|
51
|
+
try:
|
|
52
|
+
# Define the todo file path
|
|
53
|
+
todo_file_path = ".aider.todo.txt"
|
|
54
|
+
abs_path = coder.abs_root_path(todo_file_path)
|
|
55
|
+
|
|
56
|
+
# Get existing content if appending
|
|
57
|
+
existing_content = ""
|
|
58
|
+
import os
|
|
59
|
+
|
|
60
|
+
if os.path.isfile(abs_path):
|
|
61
|
+
existing_content = coder.io.read_text(abs_path) or ""
|
|
62
|
+
|
|
63
|
+
# Prepare new content
|
|
64
|
+
if append:
|
|
65
|
+
if existing_content and not existing_content.endswith("\n"):
|
|
66
|
+
existing_content += "\n"
|
|
67
|
+
new_content = existing_content + content
|
|
68
|
+
else:
|
|
69
|
+
new_content = content
|
|
70
|
+
|
|
71
|
+
# Check if content exceeds 4096 characters and warn
|
|
72
|
+
if len(new_content) > 4096:
|
|
73
|
+
coder.io.tool_warning(
|
|
74
|
+
"⚠️ Todo list content exceeds 4096 characters. Consider summarizing the plan before"
|
|
75
|
+
" proceeding."
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# Check if content actually changed
|
|
79
|
+
if existing_content == new_content:
|
|
80
|
+
coder.io.tool_warning("No changes made: new content is identical to existing")
|
|
81
|
+
return "Warning: No changes made (content identical to existing)"
|
|
82
|
+
|
|
83
|
+
# Generate diff for feedback
|
|
84
|
+
diff_snippet = generate_unified_diff_snippet(existing_content, new_content, todo_file_path)
|
|
85
|
+
|
|
86
|
+
# Handle dry run
|
|
87
|
+
if dry_run:
|
|
88
|
+
action = "append to" if append else "replace"
|
|
89
|
+
dry_run_message = f"Dry run: Would {action} todo list in {todo_file_path}."
|
|
90
|
+
return format_tool_result(
|
|
91
|
+
coder,
|
|
92
|
+
tool_name,
|
|
93
|
+
"",
|
|
94
|
+
dry_run=True,
|
|
95
|
+
dry_run_message=dry_run_message,
|
|
96
|
+
diff_snippet=diff_snippet,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
# Apply change
|
|
100
|
+
metadata = {
|
|
101
|
+
"append": append,
|
|
102
|
+
"existing_length": len(existing_content),
|
|
103
|
+
"new_length": len(new_content),
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
# Write the file directly since it's a special file
|
|
107
|
+
coder.io.write_text(abs_path, new_content)
|
|
108
|
+
|
|
109
|
+
# Track the change
|
|
110
|
+
final_change_id = coder.change_tracker.track_change(
|
|
111
|
+
file_path=todo_file_path,
|
|
112
|
+
change_type="updatetodolist",
|
|
113
|
+
original_content=existing_content,
|
|
114
|
+
new_content=new_content,
|
|
115
|
+
metadata=metadata,
|
|
116
|
+
change_id=change_id,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
coder.aider_edited_files.add(todo_file_path)
|
|
120
|
+
|
|
121
|
+
# Format and return result
|
|
122
|
+
action = "appended to" if append else "updated"
|
|
123
|
+
success_message = f"Successfully {action} todo list in {todo_file_path}"
|
|
124
|
+
return format_tool_result(
|
|
125
|
+
coder, tool_name, success_message, change_id=final_change_id, diff_snippet=diff_snippet
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
except ToolError as e:
|
|
129
|
+
return handle_tool_error(coder, tool_name, e, add_traceback=False)
|
|
130
|
+
except Exception as e:
|
|
131
|
+
return handle_tool_error(coder, tool_name, e)
|
aider/tools/view.py
CHANGED
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
view_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.",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
"required": ["file_path"],
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
1
24
|
def execute_view(coder, file_path):
|
|
2
25
|
"""
|
|
3
26
|
Explicitly add a file to context as read-only.
|
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
import fnmatch
|
|
2
2
|
import os
|
|
3
3
|
|
|
4
|
+
view_files_at_glob_schema = {
|
|
5
|
+
"type": "function",
|
|
6
|
+
"function": {
|
|
7
|
+
"name": "ViewFilesAtGlob",
|
|
8
|
+
"description": "View files matching a glob pattern.",
|
|
9
|
+
"parameters": {
|
|
10
|
+
"type": "object",
|
|
11
|
+
"properties": {
|
|
12
|
+
"pattern": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"description": "The glob pattern to match files.",
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
"required": ["pattern"],
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
}
|
|
21
|
+
|
|
4
22
|
|
|
5
23
|
def execute_view_files_at_glob(coder, pattern):
|
|
6
24
|
"""
|
|
7
|
-
Execute a glob pattern and
|
|
25
|
+
Execute a glob pattern and return matching files as text.
|
|
8
26
|
|
|
9
27
|
This tool helps the LLM find files by pattern matching, similar to
|
|
10
28
|
how a developer would use glob patterns to find files.
|
|
@@ -25,38 +43,25 @@ def execute_view_files_at_glob(coder, pattern):
|
|
|
25
43
|
if fnmatch.fnmatch(file, pattern):
|
|
26
44
|
matching_files.append(file)
|
|
27
45
|
|
|
28
|
-
#
|
|
29
|
-
if len(matching_files) > coder.max_files_per_glob:
|
|
30
|
-
coder.io.tool_output(
|
|
31
|
-
f"⚠️ Found {len(matching_files)} files matching '{pattern}', "
|
|
32
|
-
f"limiting to {coder.max_files_per_glob} most relevant files."
|
|
33
|
-
)
|
|
34
|
-
# Sort by modification time (most recent first)
|
|
35
|
-
matching_files.sort(
|
|
36
|
-
key=lambda f: os.path.getmtime(coder.abs_root_path(f)), reverse=True
|
|
37
|
-
)
|
|
38
|
-
matching_files = matching_files[: coder.max_files_per_glob]
|
|
39
|
-
|
|
40
|
-
# Add files to context
|
|
41
|
-
for file in matching_files:
|
|
42
|
-
# Use the coder's internal method to add files
|
|
43
|
-
coder._add_file_to_context(file)
|
|
44
|
-
|
|
45
|
-
# Return a user-friendly result
|
|
46
|
+
# Return formatted text instead of adding to context
|
|
46
47
|
if matching_files:
|
|
47
48
|
if len(matching_files) > 10:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
f"
|
|
49
|
+
result = (
|
|
50
|
+
f"Found {len(matching_files)} files matching '{pattern}':"
|
|
51
|
+
f" {', '.join(matching_files[:10])} and {len(matching_files) - 10} more"
|
|
51
52
|
)
|
|
53
|
+
coder.io.tool_output(f"📂 Found {len(matching_files)} files matching '{pattern}'")
|
|
52
54
|
else:
|
|
55
|
+
result = (
|
|
56
|
+
f"Found {len(matching_files)} files matching '{pattern}':"
|
|
57
|
+
f" {', '.join(matching_files)}"
|
|
58
|
+
)
|
|
53
59
|
coder.io.tool_output(
|
|
54
|
-
f"📂
|
|
60
|
+
f"📂 Found files matching '{pattern}':"
|
|
61
|
+
f" {', '.join(matching_files[:5])}{' and more' if len(matching_files) > 5 else ''}"
|
|
55
62
|
)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
f" {', '.join(matching_files[:5])}{' and more' if len(matching_files) > 5 else ''}"
|
|
59
|
-
)
|
|
63
|
+
|
|
64
|
+
return result
|
|
60
65
|
else:
|
|
61
66
|
coder.io.tool_output(f"⚠️ No files found matching '{pattern}'")
|
|
62
67
|
return f"No files found matching '{pattern}'"
|
|
@@ -1,18 +1,46 @@
|
|
|
1
1
|
import fnmatch
|
|
2
2
|
import re
|
|
3
3
|
|
|
4
|
+
view_files_matching_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
|
+
),
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
"required": ["pattern"],
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
}
|
|
4
31
|
|
|
5
|
-
|
|
32
|
+
|
|
33
|
+
def execute_view_files_matching(coder, pattern, file_pattern=None, regex=False):
|
|
6
34
|
"""
|
|
7
|
-
Search for pattern (literal string or regex) in files and
|
|
35
|
+
Search for pattern (literal string or regex) in files and return matching files as text.
|
|
8
36
|
|
|
9
37
|
Args:
|
|
10
38
|
coder: The Coder instance.
|
|
11
|
-
|
|
39
|
+
pattern (str): The pattern to search for.
|
|
12
40
|
Treated as a literal string by default.
|
|
13
41
|
file_pattern (str, optional): Glob pattern to filter which files are searched.
|
|
14
42
|
Defaults to None (search all files).
|
|
15
|
-
regex (bool, optional): If True, treat
|
|
43
|
+
regex (bool, optional): If True, treat pattern as a regular expression.
|
|
16
44
|
Defaults to False.
|
|
17
45
|
|
|
18
46
|
This tool lets the LLM search for content within files, mimicking
|
|
@@ -29,9 +57,7 @@ def execute_view_files_matching(coder, search_pattern, file_pattern=None, regex=
|
|
|
29
57
|
files_to_search.append(file)
|
|
30
58
|
|
|
31
59
|
if not files_to_search:
|
|
32
|
-
return
|
|
33
|
-
f"No files matching '{file_pattern}' to search for pattern '{search_pattern}'"
|
|
34
|
-
)
|
|
60
|
+
return f"No files matching '{file_pattern}' to search for pattern '{pattern}'"
|
|
35
61
|
else:
|
|
36
62
|
# Search all files if no pattern provided
|
|
37
63
|
files_to_search = coder.get_all_relative_files()
|
|
@@ -46,16 +72,16 @@ def execute_view_files_matching(coder, search_pattern, file_pattern=None, regex=
|
|
|
46
72
|
match_count = 0
|
|
47
73
|
if regex:
|
|
48
74
|
try:
|
|
49
|
-
matches_found = re.findall(
|
|
75
|
+
matches_found = re.findall(pattern, content)
|
|
50
76
|
match_count = len(matches_found)
|
|
51
77
|
except re.error as e:
|
|
52
78
|
# Handle invalid regex patterns gracefully
|
|
53
|
-
coder.io.tool_error(f"Invalid regex pattern '{
|
|
79
|
+
coder.io.tool_error(f"Invalid regex pattern '{pattern}': {e}")
|
|
54
80
|
# Skip this file for this search if regex is invalid
|
|
55
81
|
continue
|
|
56
82
|
else:
|
|
57
83
|
# Exact string matching
|
|
58
|
-
match_count = content.count(
|
|
84
|
+
match_count = content.count(pattern)
|
|
59
85
|
|
|
60
86
|
if match_count > 0:
|
|
61
87
|
matches[file] = match_count
|
|
@@ -63,40 +89,28 @@ def execute_view_files_matching(coder, search_pattern, file_pattern=None, regex=
|
|
|
63
89
|
# Skip files that can't be read (binary, etc.)
|
|
64
90
|
pass
|
|
65
91
|
|
|
66
|
-
#
|
|
67
|
-
if len(matches) > coder.max_files_per_glob:
|
|
68
|
-
coder.io.tool_output(
|
|
69
|
-
f"⚠️ Found '{search_pattern}' in {len(matches)} files, "
|
|
70
|
-
f"limiting to {coder.max_files_per_glob} files with most matches."
|
|
71
|
-
)
|
|
72
|
-
# Sort by number of matches (most matches first)
|
|
73
|
-
sorted_matches = sorted(matches.items(), key=lambda x: x[1], reverse=True)
|
|
74
|
-
matches = dict(sorted_matches[: coder.max_files_per_glob])
|
|
75
|
-
|
|
76
|
-
# Add matching files to context
|
|
77
|
-
for file in matches:
|
|
78
|
-
coder._add_file_to_context(file)
|
|
79
|
-
|
|
80
|
-
# Return a user-friendly result
|
|
92
|
+
# Return formatted text instead of adding to context
|
|
81
93
|
if matches:
|
|
82
94
|
# Sort by number of matches (most matches first)
|
|
83
95
|
sorted_matches = sorted(matches.items(), key=lambda x: x[1], reverse=True)
|
|
84
|
-
match_list = [f"{file} ({count} matches)" for file, count in sorted_matches
|
|
96
|
+
match_list = [f"{file} ({count} matches)" for file, count in sorted_matches]
|
|
85
97
|
|
|
86
|
-
if len(
|
|
87
|
-
|
|
88
|
-
f"
|
|
89
|
-
f" {
|
|
90
|
-
)
|
|
91
|
-
return (
|
|
92
|
-
f"Found in {len(matches)} files: {', '.join(match_list)} and"
|
|
93
|
-
f" {len(matches) - 5} more"
|
|
98
|
+
if len(matches) > 10:
|
|
99
|
+
result = (
|
|
100
|
+
f"Found '{pattern}' in {len(matches)} files: {', '.join(match_list[:10])} and"
|
|
101
|
+
f" {len(matches) - 10} more"
|
|
94
102
|
)
|
|
103
|
+
coder.io.tool_output(f"🔍 Found '{pattern}' in {len(matches)} files")
|
|
95
104
|
else:
|
|
96
|
-
|
|
97
|
-
|
|
105
|
+
result = f"Found '{pattern}' in {len(matches)} files: {', '.join(match_list)}"
|
|
106
|
+
coder.io.tool_output(
|
|
107
|
+
f"🔍 Found '{pattern}' in:"
|
|
108
|
+
f" {', '.join(match_list[:5])}{' and more' if len(matches) > 5 else ''}"
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
return result
|
|
98
112
|
else:
|
|
99
|
-
coder.io.tool_output(f"⚠️ Pattern '{
|
|
113
|
+
coder.io.tool_output(f"⚠️ Pattern '{pattern}' not found in any files")
|
|
100
114
|
return "Pattern not found in any files"
|
|
101
115
|
except Exception as e:
|
|
102
116
|
coder.io.tool_error(f"Error in ViewFilesMatching: {str(e)}")
|
|
@@ -1,9 +1,25 @@
|
|
|
1
|
-
|
|
1
|
+
view_files_with_symbol_schema = {
|
|
2
|
+
"type": "function",
|
|
3
|
+
"function": {
|
|
4
|
+
"name": "ViewFilesWithSymbol",
|
|
5
|
+
"description": "View files that contain a specific symbol (e.g., class, function).",
|
|
6
|
+
"parameters": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"symbol": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "The symbol to search for.",
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
"required": ["symbol"],
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
}
|
|
2
18
|
|
|
3
19
|
|
|
4
20
|
def _execute_view_files_with_symbol(coder, symbol):
|
|
5
21
|
"""
|
|
6
|
-
Find files containing a symbol using RepoMap and
|
|
22
|
+
Find files containing a symbol using RepoMap and return them as text.
|
|
7
23
|
Checks files already in context first.
|
|
8
24
|
"""
|
|
9
25
|
if not coder.repo_map:
|
|
@@ -13,7 +29,6 @@ def _execute_view_files_with_symbol(coder, symbol):
|
|
|
13
29
|
if not symbol:
|
|
14
30
|
return "Error: Missing 'symbol' parameter for ViewFilesWithSymbol"
|
|
15
31
|
|
|
16
|
-
# --- Start Modification ---
|
|
17
32
|
# 1. Check files already in context
|
|
18
33
|
files_in_context = list(coder.abs_fnames) + list(coder.abs_read_only_fnames)
|
|
19
34
|
found_in_context = []
|
|
@@ -34,20 +49,11 @@ def _execute_view_files_with_symbol(coder, symbol):
|
|
|
34
49
|
if found_in_context:
|
|
35
50
|
# Symbol found in already loaded files. Report this and stop.
|
|
36
51
|
file_list = ", ".join(sorted(list(set(found_in_context))))
|
|
37
|
-
coder.io.tool_output(
|
|
38
|
-
|
|
39
|
-
" performed."
|
|
40
|
-
)
|
|
41
|
-
return (
|
|
42
|
-
f"Symbol '{symbol}' found in already loaded file(s): {file_list}. No external search"
|
|
43
|
-
" performed."
|
|
44
|
-
)
|
|
45
|
-
# --- End Modification ---
|
|
52
|
+
coder.io.tool_output(f"Symbol '{symbol}' found in already loaded file(s): {file_list}")
|
|
53
|
+
return f"Symbol '{symbol}' found in already loaded file(s): {file_list}"
|
|
46
54
|
|
|
47
55
|
# 2. If not found in context, search the repository using RepoMap
|
|
48
|
-
coder.io.tool_output(
|
|
49
|
-
f"🔎 Searching for symbol '{symbol}' in repository (excluding current context)..."
|
|
50
|
-
)
|
|
56
|
+
coder.io.tool_output(f"🔎 Searching for symbol '{symbol}' in repository...")
|
|
51
57
|
try:
|
|
52
58
|
found_files = set()
|
|
53
59
|
current_context_files = coder.abs_fnames | coder.abs_read_only_fnames
|
|
@@ -71,50 +77,31 @@ def _execute_view_files_with_symbol(coder, symbol):
|
|
|
71
77
|
# Use absolute path directly if available, otherwise resolve from relative path
|
|
72
78
|
abs_fname = rel_fname_to_abs.get(tag.rel_fname) or coder.abs_root_path(tag.fname)
|
|
73
79
|
if abs_fname in files_to_search: # Ensure we only add files we intended to search
|
|
74
|
-
found_files.add(abs_fname)
|
|
80
|
+
found_files.add(coder.get_rel_fname(abs_fname))
|
|
75
81
|
|
|
76
|
-
#
|
|
77
|
-
if
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
)
|
|
86
|
-
found_files = set(sorted_found_files[: coder.max_files_per_glob])
|
|
87
|
-
|
|
88
|
-
# Add files to context (as read-only)
|
|
89
|
-
added_count = 0
|
|
90
|
-
added_files_rel = []
|
|
91
|
-
for abs_file_path in found_files:
|
|
92
|
-
rel_path = coder.get_rel_fname(abs_file_path)
|
|
93
|
-
# Double check it's not already added somehow
|
|
94
|
-
if (
|
|
95
|
-
abs_file_path not in coder.abs_fnames
|
|
96
|
-
and abs_file_path not in coder.abs_read_only_fnames
|
|
97
|
-
):
|
|
98
|
-
# Use explicit=True for clear output, even though it's an external search result
|
|
99
|
-
add_result = coder._add_file_to_context(rel_path, explicit=True)
|
|
100
|
-
if "Added" in add_result or "Viewed" in add_result: # Count successful adds/views
|
|
101
|
-
added_count += 1
|
|
102
|
-
added_files_rel.append(rel_path)
|
|
103
|
-
|
|
104
|
-
if added_count > 0:
|
|
105
|
-
if added_count > 5:
|
|
106
|
-
brief = ", ".join(added_files_rel[:5]) + f", and {added_count - 5} more"
|
|
107
|
-
coder.io.tool_output(f"🔎 Found '{symbol}' and added {added_count} files: {brief}")
|
|
82
|
+
# Return formatted text instead of adding to context
|
|
83
|
+
if found_files:
|
|
84
|
+
found_files_list = sorted(list(found_files))
|
|
85
|
+
if len(found_files) > 10:
|
|
86
|
+
result = (
|
|
87
|
+
f"Found symbol '{symbol}' in {len(found_files)} files:"
|
|
88
|
+
f" {', '.join(found_files_list[:10])} and {len(found_files) - 10} more"
|
|
89
|
+
)
|
|
90
|
+
coder.io.tool_output(f"🔎 Found '{symbol}' in {len(found_files)} files")
|
|
108
91
|
else:
|
|
92
|
+
result = (
|
|
93
|
+
f"Found symbol '{symbol}' in {len(found_files)} files:"
|
|
94
|
+
f" {', '.join(found_files_list)}"
|
|
95
|
+
)
|
|
109
96
|
coder.io.tool_output(
|
|
110
|
-
f"🔎 Found '{symbol}'
|
|
97
|
+
f"🔎 Found '{symbol}' in files:"
|
|
98
|
+
f" {', '.join(found_files_list[:5])}{' and more' if len(found_files) > 5 else ''}"
|
|
111
99
|
)
|
|
112
|
-
|
|
100
|
+
|
|
101
|
+
return result
|
|
113
102
|
else:
|
|
114
|
-
coder.io.tool_output(
|
|
115
|
-
|
|
116
|
-
)
|
|
117
|
-
return f"Symbol '{symbol}' not found in searchable files (outside current context)."
|
|
103
|
+
coder.io.tool_output(f"⚠️ Symbol '{symbol}' not found in searchable files")
|
|
104
|
+
return f"Symbol '{symbol}' not found in searchable files"
|
|
118
105
|
|
|
119
106
|
except Exception as e:
|
|
120
107
|
coder.io.tool_error(f"Error in ViewFilesWithSymbol: {str(e)}")
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from .tool_utils import ToolError, format_tool_result, handle_tool_error
|
|
2
|
+
|
|
3
|
+
view_todo_list_schema = {
|
|
4
|
+
"type": "function",
|
|
5
|
+
"function": {
|
|
6
|
+
"name": "ViewTodoList",
|
|
7
|
+
"description": "View the current todo list for tracking conversation steps and progress.",
|
|
8
|
+
"parameters": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"properties": {},
|
|
11
|
+
"required": [],
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _execute_view_todo_list(coder):
|
|
18
|
+
"""
|
|
19
|
+
View the current todo list from .aider.todo.txt file.
|
|
20
|
+
Returns the todo list content or creates an empty one if it doesn't exist.
|
|
21
|
+
"""
|
|
22
|
+
tool_name = "ViewTodoList"
|
|
23
|
+
try:
|
|
24
|
+
# Define the todo file path
|
|
25
|
+
todo_file_path = ".aider.todo.txt"
|
|
26
|
+
abs_path = coder.abs_root_path(todo_file_path)
|
|
27
|
+
|
|
28
|
+
# Check if file exists
|
|
29
|
+
import os
|
|
30
|
+
|
|
31
|
+
if os.path.isfile(abs_path):
|
|
32
|
+
# Read existing todo list
|
|
33
|
+
content = coder.io.read_text(abs_path)
|
|
34
|
+
if content is None:
|
|
35
|
+
raise ToolError(f"Could not read todo list file: {todo_file_path}")
|
|
36
|
+
|
|
37
|
+
# Check if content exceeds 4096 characters and warn
|
|
38
|
+
if len(content) > 4096:
|
|
39
|
+
coder.io.tool_warning(
|
|
40
|
+
"⚠️ Todo list content exceeds 4096 characters. Consider summarizing the plan"
|
|
41
|
+
" before proceeding."
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
if content.strip():
|
|
45
|
+
result_message = f"Current todo list:\n```\n{content}\n```"
|
|
46
|
+
else:
|
|
47
|
+
result_message = "Todo list is empty. Use UpdateTodoList to add items."
|
|
48
|
+
else:
|
|
49
|
+
# Create empty todo list
|
|
50
|
+
result_message = "Todo list is empty. Use UpdateTodoList to add items."
|
|
51
|
+
|
|
52
|
+
return format_tool_result(coder, tool_name, result_message)
|
|
53
|
+
|
|
54
|
+
except ToolError as e:
|
|
55
|
+
return handle_tool_error(coder, tool_name, e, add_traceback=False)
|
|
56
|
+
except Exception as e:
|
|
57
|
+
return handle_tool_error(coder, tool_name, e)
|