auto-coder 0.1.364__py3-none-any.whl → 0.1.365__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 auto-coder might be problematic. Click here for more details.
- {auto_coder-0.1.364.dist-info → auto_coder-0.1.365.dist-info}/METADATA +1 -1
- {auto_coder-0.1.364.dist-info → auto_coder-0.1.365.dist-info}/RECORD +19 -18
- autocoder/auto_coder.py +46 -2
- autocoder/common/__init__.py +3 -0
- autocoder/common/file_checkpoint/conversation_checkpoint.py +182 -0
- autocoder/common/file_checkpoint/manager.py +208 -1
- autocoder/common/utils_code_auto_generate.py +2 -1
- autocoder/common/v2/agent/agentic_edit.py +291 -92
- autocoder/common/v2/agent/agentic_edit_tools/list_files_tool_resolver.py +83 -43
- autocoder/common/v2/agent/agentic_edit_tools/read_file_tool_resolver.py +115 -28
- autocoder/common/v2/agent/agentic_edit_tools/replace_in_file_tool_resolver.py +169 -61
- autocoder/common/v2/agent/agentic_edit_tools/search_files_tool_resolver.py +101 -56
- autocoder/common/v2/agent/agentic_edit_tools/write_to_file_tool_resolver.py +95 -76
- autocoder/common/v2/agent/agentic_edit_types.py +4 -0
- autocoder/version.py +1 -1
- {auto_coder-0.1.364.dist-info → auto_coder-0.1.365.dist-info}/LICENSE +0 -0
- {auto_coder-0.1.364.dist-info → auto_coder-0.1.365.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.364.dist-info → auto_coder-0.1.365.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.364.dist-info → auto_coder-0.1.365.dist-info}/top_level.txt +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import re
|
|
3
3
|
import glob
|
|
4
|
-
from typing import Dict, Any, Optional
|
|
4
|
+
from typing import Dict, Any, Optional, List, Union
|
|
5
5
|
from autocoder.common.v2.agent.agentic_edit_tools.base_tool_resolver import BaseToolResolver
|
|
6
6
|
from autocoder.common.v2.agent.agentic_edit_types import SearchFilesTool, ToolResult # Import ToolResult from types
|
|
7
7
|
from loguru import logger
|
|
@@ -20,14 +20,54 @@ class SearchFilesToolResolver(BaseToolResolver):
|
|
|
20
20
|
self.tool: SearchFilesTool = tool
|
|
21
21
|
self.shadow_manager = self.agent.shadow_manager if self.agent else None
|
|
22
22
|
|
|
23
|
-
def
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
def search_in_dir(self, base_dir: str, regex_pattern: str, file_pattern: str, source_dir: str, is_shadow: bool = False, compiled_regex: Optional[re.Pattern] = None) -> List[Dict[str, Any]]:
|
|
24
|
+
"""Helper function to search in a directory"""
|
|
25
|
+
search_results = []
|
|
26
|
+
search_glob_pattern = os.path.join(base_dir, "**", file_pattern)
|
|
27
|
+
|
|
28
|
+
logger.info(f"Searching for regex '{regex_pattern}' in files matching '{file_pattern}' under '{base_dir}' (shadow: {is_shadow}) with ignore rules applied.")
|
|
29
|
+
|
|
30
|
+
if compiled_regex is None:
|
|
31
|
+
compiled_regex = re.compile(regex_pattern)
|
|
32
|
+
|
|
33
|
+
for filepath in glob.glob(search_glob_pattern, recursive=True):
|
|
34
|
+
abs_path = os.path.abspath(filepath)
|
|
35
|
+
if should_ignore(abs_path):
|
|
36
|
+
continue
|
|
30
37
|
|
|
38
|
+
if os.path.isfile(filepath):
|
|
39
|
+
try:
|
|
40
|
+
with open(filepath, 'r', encoding='utf-8', errors='replace') as f:
|
|
41
|
+
lines = f.readlines()
|
|
42
|
+
for i, line in enumerate(lines):
|
|
43
|
+
if compiled_regex.search(line):
|
|
44
|
+
context_start = max(0, i - 2)
|
|
45
|
+
context_end = min(len(lines), i + 3)
|
|
46
|
+
context = "".join([f"{j+1}: {lines[j]}" for j in range(context_start, context_end)])
|
|
47
|
+
|
|
48
|
+
if is_shadow and self.shadow_manager:
|
|
49
|
+
try:
|
|
50
|
+
abs_project_path = self.shadow_manager.from_shadow_path(filepath)
|
|
51
|
+
relative_path = os.path.relpath(abs_project_path, source_dir)
|
|
52
|
+
except Exception:
|
|
53
|
+
relative_path = os.path.relpath(filepath, source_dir)
|
|
54
|
+
else:
|
|
55
|
+
relative_path = os.path.relpath(filepath, source_dir)
|
|
56
|
+
|
|
57
|
+
search_results.append({
|
|
58
|
+
"path": relative_path,
|
|
59
|
+
"line_number": i + 1,
|
|
60
|
+
"match_line": line.strip(),
|
|
61
|
+
"context": context.strip()
|
|
62
|
+
})
|
|
63
|
+
except Exception as e:
|
|
64
|
+
logger.warning(f"Could not read or process file {filepath}: {e}")
|
|
65
|
+
continue
|
|
66
|
+
|
|
67
|
+
return search_results
|
|
68
|
+
|
|
69
|
+
def search_files_with_shadow(self, search_path_str: str, regex_pattern: str, file_pattern: str, source_dir: str, absolute_source_dir: str, absolute_search_path: str) -> Union[ToolResult, List[Dict[str, Any]]]:
|
|
70
|
+
"""Search files using shadow manager for path translation"""
|
|
31
71
|
# Security check
|
|
32
72
|
if not absolute_search_path.startswith(absolute_source_dir):
|
|
33
73
|
return ToolResult(success=False, message=f"Error: Access denied. Attempted to search outside the project directory: {search_path_str}")
|
|
@@ -54,58 +94,15 @@ class SearchFilesToolResolver(BaseToolResolver):
|
|
|
54
94
|
try:
|
|
55
95
|
compiled_regex = re.compile(regex_pattern)
|
|
56
96
|
|
|
57
|
-
# Helper function to search in a directory
|
|
58
|
-
def search_in_dir(base_dir, is_shadow=False):
|
|
59
|
-
search_results = []
|
|
60
|
-
search_glob_pattern = os.path.join(base_dir, "**", file_pattern)
|
|
61
|
-
|
|
62
|
-
logger.info(f"Searching for regex '{regex_pattern}' in files matching '{file_pattern}' under '{base_dir}' (shadow: {is_shadow}) with ignore rules applied.")
|
|
63
|
-
|
|
64
|
-
for filepath in glob.glob(search_glob_pattern, recursive=True):
|
|
65
|
-
abs_path = os.path.abspath(filepath)
|
|
66
|
-
if should_ignore(abs_path):
|
|
67
|
-
continue
|
|
68
|
-
|
|
69
|
-
if os.path.isfile(filepath):
|
|
70
|
-
try:
|
|
71
|
-
with open(filepath, 'r', encoding='utf-8', errors='replace') as f:
|
|
72
|
-
lines = f.readlines()
|
|
73
|
-
for i, line in enumerate(lines):
|
|
74
|
-
if compiled_regex.search(line):
|
|
75
|
-
context_start = max(0, i - 2)
|
|
76
|
-
context_end = min(len(lines), i + 3)
|
|
77
|
-
context = "".join([f"{j+1}: {lines[j]}" for j in range(context_start, context_end)])
|
|
78
|
-
|
|
79
|
-
if is_shadow and self.shadow_manager:
|
|
80
|
-
try:
|
|
81
|
-
abs_project_path = self.shadow_manager.from_shadow_path(filepath)
|
|
82
|
-
relative_path = os.path.relpath(abs_project_path, source_dir)
|
|
83
|
-
except Exception:
|
|
84
|
-
relative_path = os.path.relpath(filepath, source_dir)
|
|
85
|
-
else:
|
|
86
|
-
relative_path = os.path.relpath(filepath, source_dir)
|
|
87
|
-
|
|
88
|
-
search_results.append({
|
|
89
|
-
"path": relative_path,
|
|
90
|
-
"line_number": i + 1,
|
|
91
|
-
"match_line": line.strip(),
|
|
92
|
-
"context": context.strip()
|
|
93
|
-
})
|
|
94
|
-
except Exception as e:
|
|
95
|
-
logger.warning(f"Could not read or process file {filepath}: {e}")
|
|
96
|
-
continue
|
|
97
|
-
|
|
98
|
-
return search_results
|
|
99
|
-
|
|
100
97
|
# Search in both directories and merge results
|
|
101
98
|
shadow_results = []
|
|
102
99
|
source_results = []
|
|
103
100
|
|
|
104
101
|
if shadow_exists:
|
|
105
|
-
shadow_results = search_in_dir(shadow_dir_path, is_shadow=True)
|
|
102
|
+
shadow_results = self.search_in_dir(shadow_dir_path, regex_pattern, file_pattern, source_dir, is_shadow=True, compiled_regex=compiled_regex)
|
|
106
103
|
|
|
107
104
|
if os.path.exists(absolute_search_path) and os.path.isdir(absolute_search_path):
|
|
108
|
-
source_results = search_in_dir(absolute_search_path, is_shadow=False)
|
|
105
|
+
source_results = self.search_in_dir(absolute_search_path, regex_pattern, file_pattern, source_dir, is_shadow=False, compiled_regex=compiled_regex)
|
|
109
106
|
|
|
110
107
|
# Merge results, prioritizing shadow results
|
|
111
108
|
# Create a dictionary for quick lookup
|
|
@@ -122,9 +119,34 @@ class SearchFilesToolResolver(BaseToolResolver):
|
|
|
122
119
|
# Convert back to list
|
|
123
120
|
merged_results = list(results_dict.values())
|
|
124
121
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
122
|
+
return merged_results
|
|
123
|
+
|
|
124
|
+
except re.error as e:
|
|
125
|
+
logger.error(f"Invalid regex pattern '{regex_pattern}': {e}")
|
|
126
|
+
return ToolResult(success=False, message=f"Invalid regex pattern: {e}")
|
|
127
|
+
except Exception as e:
|
|
128
|
+
logger.error(f"Error during file search: {str(e)}")
|
|
129
|
+
return ToolResult(success=False, message=f"An unexpected error occurred during search: {str(e)}")
|
|
130
|
+
|
|
131
|
+
def search_files_normal(self, search_path_str: str, regex_pattern: str, file_pattern: str, source_dir: str, absolute_source_dir: str, absolute_search_path: str) -> Union[ToolResult, List[Dict[str, Any]]]:
|
|
132
|
+
"""Search files directly without using shadow manager"""
|
|
133
|
+
# Security check
|
|
134
|
+
if not absolute_search_path.startswith(absolute_source_dir):
|
|
135
|
+
return ToolResult(success=False, message=f"Error: Access denied. Attempted to search outside the project directory: {search_path_str}")
|
|
136
|
+
|
|
137
|
+
# Validate that the directory exists
|
|
138
|
+
if not os.path.exists(absolute_search_path):
|
|
139
|
+
return ToolResult(success=False, message=f"Error: Search path not found: {search_path_str}")
|
|
140
|
+
if not os.path.isdir(absolute_search_path):
|
|
141
|
+
return ToolResult(success=False, message=f"Error: Search path is not a directory: {search_path_str}")
|
|
142
|
+
|
|
143
|
+
try:
|
|
144
|
+
compiled_regex = re.compile(regex_pattern)
|
|
145
|
+
|
|
146
|
+
# Search in the directory
|
|
147
|
+
search_results = self.search_in_dir(absolute_search_path, regex_pattern, file_pattern, source_dir, is_shadow=False, compiled_regex=compiled_regex)
|
|
148
|
+
|
|
149
|
+
return search_results
|
|
128
150
|
|
|
129
151
|
except re.error as e:
|
|
130
152
|
logger.error(f"Invalid regex pattern '{regex_pattern}': {e}")
|
|
@@ -132,3 +154,26 @@ class SearchFilesToolResolver(BaseToolResolver):
|
|
|
132
154
|
except Exception as e:
|
|
133
155
|
logger.error(f"Error during file search: {str(e)}")
|
|
134
156
|
return ToolResult(success=False, message=f"An unexpected error occurred during search: {str(e)}")
|
|
157
|
+
|
|
158
|
+
def resolve(self) -> ToolResult:
|
|
159
|
+
"""Resolve the search files tool by calling the appropriate implementation"""
|
|
160
|
+
search_path_str = self.tool.path
|
|
161
|
+
regex_pattern = self.tool.regex
|
|
162
|
+
file_pattern = self.tool.file_pattern or "*"
|
|
163
|
+
source_dir = self.args.source_dir or "."
|
|
164
|
+
absolute_source_dir = os.path.abspath(source_dir)
|
|
165
|
+
absolute_search_path = os.path.abspath(os.path.join(source_dir, search_path_str))
|
|
166
|
+
|
|
167
|
+
# Choose the appropriate implementation based on whether shadow_manager is available
|
|
168
|
+
if self.shadow_manager:
|
|
169
|
+
result = self.search_files_with_shadow(search_path_str, regex_pattern, file_pattern, source_dir, absolute_source_dir, absolute_search_path)
|
|
170
|
+
else:
|
|
171
|
+
result = self.search_files_normal(search_path_str, regex_pattern, file_pattern, source_dir, absolute_source_dir, absolute_search_path)
|
|
172
|
+
|
|
173
|
+
# Handle the case where the implementation returns a list instead of a ToolResult
|
|
174
|
+
if isinstance(result, list):
|
|
175
|
+
message = f"Search completed. Found {len(result)} matches."
|
|
176
|
+
logger.info(message)
|
|
177
|
+
return ToolResult(success=True, message=message, content=result)
|
|
178
|
+
else:
|
|
179
|
+
return result
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from typing import Dict, Any, Optional
|
|
3
|
-
from autocoder.common.v2.agent.agentic_edit_types import WriteToFileTool, ToolResult
|
|
3
|
+
from autocoder.common.v2.agent.agentic_edit_types import WriteToFileTool, ToolResult
|
|
4
4
|
from autocoder.common.v2.agent.agentic_edit_tools.base_tool_resolver import BaseToolResolver
|
|
5
5
|
from loguru import logger
|
|
6
6
|
from autocoder.common import AutoCoderArgs
|
|
@@ -44,82 +44,77 @@ class WriteToFileToolResolver(BaseToolResolver):
|
|
|
44
44
|
|
|
45
45
|
return "\n".join(formatted_issues)
|
|
46
46
|
|
|
47
|
-
def
|
|
48
|
-
|
|
49
|
-
content = self.tool.content
|
|
50
|
-
source_dir = self.args.source_dir or "."
|
|
51
|
-
abs_project_dir = os.path.abspath(source_dir)
|
|
52
|
-
abs_file_path = os.path.abspath(os.path.join(source_dir, file_path))
|
|
53
|
-
|
|
54
|
-
# Security check: ensure the path is within the source directory
|
|
55
|
-
if not abs_file_path.startswith(abs_project_dir):
|
|
56
|
-
return ToolResult(success=False, message=f"Error: Access denied. Attempted to write file outside the project directory: {file_path}")
|
|
57
|
-
|
|
47
|
+
def write_file_with_shadow(self, file_path: str, content: str, source_dir: str, abs_project_dir: str, abs_file_path: str) -> ToolResult:
|
|
48
|
+
"""Write file using shadow manager for path translation"""
|
|
58
49
|
try:
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
logger.info(f"[Shadow] Successfully wrote shadow file: {shadow_path}")
|
|
50
|
+
shadow_path = self.shadow_manager.to_shadow_path(abs_file_path)
|
|
51
|
+
# Ensure shadow directory exists
|
|
52
|
+
os.makedirs(os.path.dirname(shadow_path), exist_ok=True)
|
|
53
|
+
with open(shadow_path, 'w', encoding='utf-8') as f:
|
|
54
|
+
f.write(content)
|
|
55
|
+
logger.info(f"[Shadow] Successfully wrote shadow file: {shadow_path}")
|
|
66
56
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if lint_results and lint_results.issues:
|
|
89
|
-
has_lint_issues = True
|
|
90
|
-
# 格式化 lint 问题
|
|
91
|
-
formatted_issues = self._format_lint_issues(lint_results)
|
|
92
|
-
lint_message = f"\n\n代码质量检查发现 {len(lint_results.issues)} 个问题:\n{formatted_issues}"
|
|
93
|
-
else:
|
|
94
|
-
lint_message = "\n\n代码质量检查通过,未发现问题。"
|
|
95
|
-
except Exception as e:
|
|
96
|
-
logger.error(f"Lint 检查失败: {str(e)}")
|
|
97
|
-
lint_message = "\n\n尝试进行代码质量检查时出错。"
|
|
98
|
-
else:
|
|
99
|
-
logger.info("代码质量检查已禁用")
|
|
100
|
-
|
|
101
|
-
# 构建包含 lint 结果的返回消息
|
|
102
|
-
message = f"Successfully wrote to file (shadow): {file_path}"
|
|
103
|
-
|
|
104
|
-
# 将 lint 消息添加到结果中,如果启用了Lint
|
|
105
|
-
if enable_lint:
|
|
106
|
-
message += lint_message
|
|
107
|
-
|
|
108
|
-
# 附加 lint 结果到返回内容
|
|
109
|
-
result_content = {
|
|
110
|
-
"content": content,
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
# 只有在启用Lint时才添加Lint结果
|
|
114
|
-
if enable_lint:
|
|
115
|
-
result_content["lint_results"] = {
|
|
116
|
-
"has_issues": has_lint_issues,
|
|
117
|
-
"issues": formatted_issues if has_lint_issues else None
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return ToolResult(success=True, message=message, content=result_content)
|
|
57
|
+
# 回调AgenticEdit,记录变更
|
|
58
|
+
if self.agent:
|
|
59
|
+
rel_path = os.path.relpath(abs_file_path, abs_project_dir)
|
|
60
|
+
self.agent.record_file_change(rel_path, "added", diff=None, content=content)
|
|
61
|
+
|
|
62
|
+
# 新增:执行代码质量检查
|
|
63
|
+
lint_results = None
|
|
64
|
+
lint_message = ""
|
|
65
|
+
formatted_issues = ""
|
|
66
|
+
has_lint_issues = False
|
|
67
|
+
|
|
68
|
+
# 检查是否启用了Lint功能
|
|
69
|
+
enable_lint = self.args.enable_auto_fix_lint
|
|
70
|
+
|
|
71
|
+
if enable_lint:
|
|
72
|
+
try:
|
|
73
|
+
if self.shadow_linter and self.shadow_manager:
|
|
74
|
+
# 对新创建的文件进行 lint 检查
|
|
75
|
+
shadow_path = self.shadow_manager.to_shadow_path(abs_file_path)
|
|
76
|
+
lint_results = self.shadow_linter.lint_shadow_file(shadow_path)
|
|
121
77
|
|
|
122
|
-
|
|
78
|
+
if lint_results and lint_results.issues:
|
|
79
|
+
has_lint_issues = True
|
|
80
|
+
# 格式化 lint 问题
|
|
81
|
+
formatted_issues = self._format_lint_issues(lint_results)
|
|
82
|
+
lint_message = f"\n\n代码质量检查发现 {len(lint_results.issues)} 个问题:\n{formatted_issues}"
|
|
83
|
+
else:
|
|
84
|
+
lint_message = "\n\n代码质量检查通过,未发现问题。"
|
|
85
|
+
except Exception as e:
|
|
86
|
+
logger.error(f"Lint 检查失败: {str(e)}")
|
|
87
|
+
lint_message = "\n\n尝试进行代码质量检查时出错。"
|
|
88
|
+
else:
|
|
89
|
+
logger.info("代码质量检查已禁用")
|
|
90
|
+
|
|
91
|
+
# 构建包含 lint 结果的返回消息
|
|
92
|
+
message = f"Successfully wrote to file (shadow): {file_path}"
|
|
93
|
+
|
|
94
|
+
# 将 lint 消息添加到结果中,如果启用了Lint
|
|
95
|
+
if enable_lint:
|
|
96
|
+
message += lint_message
|
|
97
|
+
|
|
98
|
+
# 附加 lint 结果到返回内容
|
|
99
|
+
result_content = {
|
|
100
|
+
"content": content,
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
# 只有在启用Lint时才添加Lint结果
|
|
104
|
+
if enable_lint:
|
|
105
|
+
result_content["lint_results"] = {
|
|
106
|
+
"has_issues": has_lint_issues,
|
|
107
|
+
"issues": formatted_issues if has_lint_issues else None
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return ToolResult(success=True, message=message, content=result_content)
|
|
111
|
+
except Exception as e:
|
|
112
|
+
logger.error(f"Error writing to shadow file '{file_path}': {str(e)}")
|
|
113
|
+
return ToolResult(success=False, message=f"An error occurred while writing to the shadow file: {str(e)}")
|
|
114
|
+
|
|
115
|
+
def write_file_normal(self, file_path: str, content: str, source_dir: str, abs_project_dir: str, abs_file_path: str) -> ToolResult:
|
|
116
|
+
"""Write file directly without using shadow manager"""
|
|
117
|
+
try:
|
|
123
118
|
os.makedirs(os.path.dirname(abs_file_path), exist_ok=True)
|
|
124
119
|
|
|
125
120
|
if self.agent:
|
|
@@ -136,7 +131,13 @@ class WriteToFileToolResolver(BaseToolResolver):
|
|
|
136
131
|
)
|
|
137
132
|
}
|
|
138
133
|
change_group_id = self.args.event_file
|
|
139
|
-
|
|
134
|
+
|
|
135
|
+
self.agent.checkpoint_manager.apply_changes_with_conversation(
|
|
136
|
+
changes=changes,
|
|
137
|
+
conversations=self.agent.current_conversations,
|
|
138
|
+
change_group_id=change_group_id,
|
|
139
|
+
metadata={"event_file": self.args.event_file}
|
|
140
|
+
)
|
|
140
141
|
else:
|
|
141
142
|
with open(abs_file_path, 'w', encoding='utf-8') as f:
|
|
142
143
|
f.write(content)
|
|
@@ -205,4 +206,22 @@ class WriteToFileToolResolver(BaseToolResolver):
|
|
|
205
206
|
return ToolResult(success=True, message=message, content=result_content)
|
|
206
207
|
except Exception as e:
|
|
207
208
|
logger.error(f"Error writing to file '{file_path}': {str(e)}")
|
|
208
|
-
return ToolResult(success=False, message=f"An error occurred while writing to the file: {str(e)}")
|
|
209
|
+
return ToolResult(success=False, message=f"An error occurred while writing to the file: {str(e)}")
|
|
210
|
+
|
|
211
|
+
def resolve(self) -> ToolResult:
|
|
212
|
+
"""Resolve the write file tool by calling the appropriate implementation"""
|
|
213
|
+
file_path = self.tool.path
|
|
214
|
+
content = self.tool.content
|
|
215
|
+
source_dir = self.args.source_dir or "."
|
|
216
|
+
abs_project_dir = os.path.abspath(source_dir)
|
|
217
|
+
abs_file_path = os.path.abspath(os.path.join(source_dir, file_path))
|
|
218
|
+
|
|
219
|
+
# Security check: ensure the path is within the source directory
|
|
220
|
+
if not abs_file_path.startswith(abs_project_dir):
|
|
221
|
+
return ToolResult(success=False, message=f"Error: Access denied. Attempted to write file outside the project directory: {file_path}")
|
|
222
|
+
|
|
223
|
+
# Choose the appropriate implementation based on whether shadow_manager is available
|
|
224
|
+
if self.shadow_manager:
|
|
225
|
+
return self.write_file_with_shadow(file_path, content, source_dir, abs_project_dir, abs_file_path)
|
|
226
|
+
else:
|
|
227
|
+
return self.write_file_normal(file_path, content, source_dir, abs_project_dir, abs_file_path)
|
|
@@ -96,6 +96,10 @@ class ErrorEvent(BaseModel):
|
|
|
96
96
|
"""Represents an error during the process."""
|
|
97
97
|
message: str
|
|
98
98
|
|
|
99
|
+
class WindowLengthChangeEvent(BaseModel):
|
|
100
|
+
"""Represents the token usage in the conversation window."""
|
|
101
|
+
tokens_used: int
|
|
102
|
+
|
|
99
103
|
# Deprecated: Will be replaced by specific Event types
|
|
100
104
|
# class PlainTextOutput(BaseModel):
|
|
101
105
|
# text: str
|
autocoder/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.1.
|
|
1
|
+
__version__ = "0.1.365"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|