auto-coder 0.1.315__py3-none-any.whl → 0.1.317__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.

Files changed (42) hide show
  1. {auto_coder-0.1.315.dist-info → auto_coder-0.1.317.dist-info}/METADATA +1 -1
  2. {auto_coder-0.1.315.dist-info → auto_coder-0.1.317.dist-info}/RECORD +42 -21
  3. autocoder/auto_coder_runner.py +1 -2
  4. autocoder/commands/tools.py +30 -19
  5. autocoder/common/__init__.py +3 -0
  6. autocoder/common/auto_coder_lang.py +24 -0
  7. autocoder/common/code_auto_merge_editblock.py +2 -42
  8. autocoder/common/git_utils.py +2 -2
  9. autocoder/common/token_cost_caculate.py +103 -42
  10. autocoder/common/v2/__init__.py +0 -0
  11. autocoder/common/v2/code_auto_generate.py +199 -0
  12. autocoder/common/v2/code_auto_generate_diff.py +361 -0
  13. autocoder/common/v2/code_auto_generate_editblock.py +380 -0
  14. autocoder/common/v2/code_auto_generate_strict_diff.py +269 -0
  15. autocoder/common/v2/code_auto_merge.py +211 -0
  16. autocoder/common/v2/code_auto_merge_diff.py +354 -0
  17. autocoder/common/v2/code_auto_merge_editblock.py +523 -0
  18. autocoder/common/v2/code_auto_merge_strict_diff.py +259 -0
  19. autocoder/common/v2/code_diff_manager.py +266 -0
  20. autocoder/common/v2/code_editblock_manager.py +275 -0
  21. autocoder/common/v2/code_manager.py +238 -0
  22. autocoder/common/v2/code_strict_diff_manager.py +241 -0
  23. autocoder/dispacher/actions/action.py +16 -0
  24. autocoder/dispacher/actions/plugins/action_regex_project.py +6 -0
  25. autocoder/events/event_manager_singleton.py +2 -2
  26. autocoder/helper/__init__.py +0 -0
  27. autocoder/helper/project_creator.py +570 -0
  28. autocoder/linters/linter_factory.py +44 -25
  29. autocoder/linters/models.py +220 -0
  30. autocoder/linters/python_linter.py +1 -7
  31. autocoder/linters/reactjs_linter.py +580 -0
  32. autocoder/linters/shadow_linter.py +390 -0
  33. autocoder/linters/vue_linter.py +576 -0
  34. autocoder/memory/active_context_manager.py +0 -4
  35. autocoder/memory/active_package.py +12 -12
  36. autocoder/shadows/__init__.py +0 -0
  37. autocoder/shadows/shadow_manager.py +235 -0
  38. autocoder/version.py +1 -1
  39. {auto_coder-0.1.315.dist-info → auto_coder-0.1.317.dist-info}/LICENSE +0 -0
  40. {auto_coder-0.1.315.dist-info → auto_coder-0.1.317.dist-info}/WHEEL +0 -0
  41. {auto_coder-0.1.315.dist-info → auto_coder-0.1.317.dist-info}/entry_points.txt +0 -0
  42. {auto_coder-0.1.315.dist-info → auto_coder-0.1.317.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,275 @@
1
+ from typing import List, Dict, Tuple, Optional, Any
2
+ import os
3
+ import json
4
+ import time
5
+ from concurrent.futures import ThreadPoolExecutor
6
+
7
+ import byzerllm
8
+ from byzerllm.utils.client import code_utils
9
+
10
+ from autocoder.common.types import Mode, CodeGenerateResult, MergeCodeWithoutEffect
11
+ from autocoder.common import AutoCoderArgs, git_utils, SourceCodeList
12
+ from autocoder.common import sys_prompt
13
+ from autocoder.privacy.model_filter import ModelPathFilter
14
+ from autocoder.common.utils_code_auto_generate import chat_with_continue, stream_chat_with_continue, ChatWithContinueResult
15
+ from autocoder.utils.auto_coder_utils.chat_stream_out import stream_out
16
+ from autocoder.common.stream_out_type import CodeGenerateStreamOutType
17
+ from autocoder.common.auto_coder_lang import get_message_with_format
18
+ from autocoder.common.printer import Printer
19
+ from autocoder.rag.token_counter import count_tokens
20
+ from autocoder.utils import llms as llm_utils
21
+ from autocoder.memory.active_context_manager import ActiveContextManager
22
+ from autocoder.common.v2.code_auto_generate_editblock import CodeAutoGenerateEditBlock
23
+ from autocoder.common.v2.code_auto_merge_editblock import CodeAutoMergeEditBlock
24
+ from autocoder.shadows.shadow_manager import ShadowManager
25
+ from autocoder.linters.shadow_linter import ShadowLinter
26
+ from autocoder.linters.models import IssueSeverity
27
+ from loguru import logger
28
+ from autocoder.common.global_cancel import global_cancel
29
+ from autocoder.linters.models import ProjectLintResult
30
+ from autocoder.common.token_cost_caculate import TokenCostCalculator
31
+
32
+
33
+ class CodeEditBlockManager:
34
+ """
35
+ A class that combines code generation, linting, and merging with automatic error correction.
36
+ It generates code, lints it, and if there are errors, regenerates the code up to 5 times
37
+ before merging the final result.
38
+ """
39
+
40
+ def __init__(
41
+ self,
42
+ llm: byzerllm.ByzerLLM,
43
+ args: AutoCoderArgs,
44
+ action=None,
45
+ fence_0: str = "```",
46
+ fence_1: str = "```",
47
+ ) -> None:
48
+ self.llm = llm
49
+ self.args = args
50
+ self.action = action
51
+ self.fence_0 = fence_0
52
+ self.fence_1 = fence_1
53
+ self.generate_times_same_model = args.generate_times_same_model
54
+ self.max_correction_attempts = args.auto_fix_lint_max_attempts
55
+ self.printer = Printer()
56
+
57
+ # Initialize sub-components
58
+ self.code_generator = CodeAutoGenerateEditBlock(llm, args, action, fence_0, fence_1)
59
+ self.code_merger = CodeAutoMergeEditBlock(llm, args, fence_0, fence_1)
60
+
61
+ # Create shadow manager for linting
62
+ self.shadow_manager = ShadowManager(args.source_dir)
63
+ self.shadow_linter = ShadowLinter(self.shadow_manager, verbose=False)
64
+
65
+ @byzerllm.prompt()
66
+ def fix_linter_errors(self, query: str, lint_issues: str) -> str:
67
+ """
68
+ Linter 检测到的问题:
69
+ <lint_issues>
70
+ {{ lint_issues }}
71
+ </lint_issues>
72
+
73
+ 用户原始需求:
74
+ <user_query_wrapper>
75
+ {{ query }}
76
+ </user_query_wrapper>
77
+
78
+ 修复上述问题,请确保代码质量问题被解决,同时保持代码的原有功能。
79
+ 请严格遵守*SEARCH/REPLACE block*的格式。
80
+ """
81
+
82
+ def _create_shadow_files_from_edits(self, generation_result: CodeGenerateResult) -> Dict[str, str]:
83
+ """
84
+ 从编辑块内容中提取代码并创建临时影子文件用于检查。
85
+
86
+ 参数:
87
+ generation_result (CodeGenerateResult): 包含SEARCH/REPLACE块的内容
88
+
89
+ 返回:
90
+ Dict[str, str]: 映射 {影子文件路径: 内容}
91
+ """
92
+ result = self.code_merger.choose_best_choice(generation_result)
93
+ merge = self.code_merger._merge_code_without_effect(result.contents[0])
94
+ shadow_files = {}
95
+ for file_path, new_content in merge.success_blocks:
96
+ self.shadow_manager.update_file(file_path, new_content)
97
+ shadow_files[self.shadow_manager.to_shadow_path(file_path)] = new_content
98
+
99
+ return shadow_files
100
+
101
+ def _format_lint_issues(self, lint_results:ProjectLintResult,level:IssueSeverity) -> str:
102
+ """
103
+ 将linter结果格式化为字符串供模型使用
104
+
105
+ 参数:
106
+ lint_results: Linter结果对象
107
+ level: 过滤问题的级别
108
+
109
+ 返回:
110
+ str: 格式化的问题描述
111
+ """
112
+ formatted_issues = []
113
+
114
+ for file_path, result in lint_results.file_results.items():
115
+ file_has_issues = False
116
+ file_issues = []
117
+
118
+ for issue in result.issues:
119
+ if issue.severity.value != level.value:
120
+ continue
121
+
122
+ if not file_has_issues:
123
+ file_has_issues = True
124
+ file_issues.append(f"文件: {file_path}")
125
+
126
+ severity = "错误" if issue.severity == IssueSeverity.ERROR else "警告" if issue.severity == IssueSeverity.WARNING else "信息"
127
+ line_info = f"第{issue.position.line}行"
128
+ if issue.position.column:
129
+ line_info += f", 第{issue.position.column}列"
130
+
131
+ file_issues.append(
132
+ f" - [{severity}] {line_info}: {issue.message} (规则: {issue.code})"
133
+ )
134
+
135
+ if file_has_issues:
136
+ formatted_issues.extend(file_issues)
137
+ formatted_issues.append("") # 空行分隔不同文件
138
+
139
+ return "\n".join(formatted_issues)
140
+
141
+ def _count_errors(self, lint_results:ProjectLintResult) -> int:
142
+ """
143
+ 计算lint结果中的错误数量
144
+
145
+ 参数:
146
+ lint_results: Linter结果对象
147
+
148
+ 返回:
149
+ int: 错误数量
150
+ """
151
+ error_count = 0
152
+
153
+ for _, result in lint_results.file_results.items():
154
+ error_count += result.error_count
155
+
156
+ return error_count
157
+
158
+ def generate_and_fix(self, query: str, source_code_list: SourceCodeList) -> CodeGenerateResult:
159
+ """
160
+ 生成代码,运行linter,修复错误,最多尝试指定次数
161
+
162
+ 参数:
163
+ query (str): 用户查询
164
+ source_code_list (SourceCodeList): 源代码列表
165
+
166
+ 返回:
167
+ CodeGenerateResult: 生成的代码结果
168
+ """
169
+ # 初始代码生成
170
+ self.printer.print_in_terminal("generating_initial_code")
171
+ start_time = time.time()
172
+ generation_result = self.code_generator.single_round_run(query, source_code_list)
173
+
174
+ token_cost_calculator = TokenCostCalculator(args=self.args)
175
+ token_cost_calculator.track_token_usage_by_generate(
176
+ llm=self.llm,
177
+ generate=generation_result,
178
+ operation_name="code_generation_complete",
179
+ start_time=start_time,
180
+ end_time=time.time()
181
+ )
182
+
183
+ # 确保结果非空
184
+ if not generation_result.contents:
185
+ self.printer.print_in_terminal("generation_failed", style="red")
186
+ return generation_result
187
+
188
+
189
+ # 最多尝试修复5次
190
+ for attempt in range(self.max_correction_attempts):
191
+ global_cancel.check_and_raise()
192
+ # 代码生成结果更新到影子文件里去
193
+ shadow_files = self._create_shadow_files_from_edits(generation_result)
194
+
195
+ if not shadow_files:
196
+ self.printer.print_in_terminal("no_files_to_lint", style="yellow")
197
+ break
198
+
199
+ # 运行linter
200
+ lint_results = self.shadow_linter.lint_all_shadow_files()
201
+ error_count = self._count_errors(lint_results)
202
+ # print(f"error_count: {error_count}")
203
+ # print(f"lint_results: {json.dumps(lint_results.model_dump(), indent=4,ensure_ascii=False)}")
204
+
205
+ # 如果没有错误则完成
206
+ if error_count == 0:
207
+ self.printer.print_in_terminal("no_lint_errors_found", style="green")
208
+ break
209
+
210
+ # 格式化lint问题
211
+ formatted_issues = self._format_lint_issues(lint_results, IssueSeverity.ERROR)
212
+
213
+ # 打印当前错误
214
+ self.printer.print_in_terminal(
215
+ "lint_attempt_status",
216
+ style="yellow",
217
+ attempt=(attempt + 1),
218
+ max_correction_attempts=self.max_correction_attempts,
219
+ error_count=error_count,
220
+ formatted_issues=formatted_issues
221
+ )
222
+
223
+ if attempt == self.max_correction_attempts - 1:
224
+ self.printer.print_in_terminal("max_attempts_reached", style="yellow")
225
+ break
226
+
227
+
228
+
229
+ # 准备修复提示
230
+ fix_prompt = self.fix_linter_errors.prompt(
231
+ query=query,
232
+ lint_issues=formatted_issues
233
+ )
234
+
235
+ # for source in source_code_list.sources:
236
+ # print(f"file_path: {source.module_name}")
237
+ # print(f"fix_prompt: {fix_prompt}")
238
+
239
+ # 将 shadow_files 转化为 source_code_list
240
+ start_time = time.time()
241
+ source_code_list = self.code_merger.get_source_code_list_from_shadow_files(shadow_files)
242
+ generation_result = self.code_generator.single_round_run(fix_prompt, source_code_list)
243
+ token_cost_calculator.track_token_usage_by_generate(
244
+ llm=self.llm,
245
+ generate=generation_result,
246
+ operation_name="code_generation_complete",
247
+ start_time=start_time,
248
+ end_time=time.time()
249
+ )
250
+
251
+
252
+ # 清理临时影子文件
253
+ self.shadow_manager.clean_shadows()
254
+
255
+ # 返回最终结果
256
+ return generation_result
257
+
258
+ def run(self, query: str, source_code_list: SourceCodeList) -> CodeGenerateResult:
259
+ """
260
+ 执行完整的代码生成、修复、合并流程
261
+
262
+ 参数:
263
+ query (str): 用户查询
264
+ source_code_list (SourceCodeList): 源代码列表
265
+
266
+ 返回:
267
+ CodeGenerateResult: 生成和修复的代码结果
268
+ """
269
+ # 生成代码并自动修复lint错误
270
+ generation_result = self.generate_and_fix(query, source_code_list)
271
+ global_cancel.check_and_raise()
272
+ # 合并代码
273
+ self.code_merger.merge_code(generation_result)
274
+
275
+ return generation_result
@@ -0,0 +1,238 @@
1
+ from typing import List, Dict, Tuple, Optional, Any
2
+ import os
3
+ import json
4
+ import time
5
+ from concurrent.futures import ThreadPoolExecutor
6
+
7
+ import byzerllm
8
+ from byzerllm.utils.client import code_utils
9
+
10
+ from autocoder.common.types import Mode, CodeGenerateResult, MergeCodeWithoutEffect
11
+ from autocoder.common import AutoCoderArgs, git_utils, SourceCodeList
12
+ from autocoder.common import sys_prompt
13
+ from autocoder.privacy.model_filter import ModelPathFilter
14
+ from autocoder.common.utils_code_auto_generate import chat_with_continue, stream_chat_with_continue, ChatWithContinueResult
15
+ from autocoder.utils.auto_coder_utils.chat_stream_out import stream_out
16
+ from autocoder.common.stream_out_type import CodeGenerateStreamOutType
17
+ from autocoder.common.auto_coder_lang import get_message_with_format
18
+ from autocoder.common.printer import Printer
19
+ from autocoder.rag.token_counter import count_tokens
20
+ from autocoder.utils import llms as llm_utils
21
+ from autocoder.memory.active_context_manager import ActiveContextManager
22
+ from autocoder.shadows.shadow_manager import ShadowManager
23
+ from autocoder.linters.shadow_linter import ShadowLinter
24
+ from autocoder.linters.models import IssueSeverity
25
+ from loguru import logger
26
+ from autocoder.common.global_cancel import global_cancel
27
+ from autocoder.linters.models import ProjectLintResult
28
+ from autocoder.common.token_cost_caculate import TokenCostCalculator
29
+
30
+
31
+ class CodeManager:
32
+ """
33
+ Base class for code generation managers that combines code generation, linting, and merging with automatic error correction.
34
+ """
35
+
36
+ def __init__(
37
+ self,
38
+ llm: byzerllm.ByzerLLM,
39
+ args: AutoCoderArgs,
40
+ action=None,
41
+ ) -> None:
42
+ self.llm = llm
43
+ self.args = args
44
+ self.action = action
45
+ self.generate_times_same_model = args.generate_times_same_model
46
+ self.max_correction_attempts = args.auto_fix_lint_max_attempts
47
+ self.printer = Printer()
48
+
49
+ # Create shadow manager for linting
50
+ self.shadow_manager = ShadowManager(args.source_dir)
51
+ self.shadow_linter = ShadowLinter(self.shadow_manager, verbose=False)
52
+
53
+ @byzerllm.prompt()
54
+ def fix_linter_errors(self, query: str, lint_issues: str) -> str:
55
+ """
56
+ Linter 检测到的问题:
57
+ <lint_issues>
58
+ {{ lint_issues }}
59
+ </lint_issues>
60
+
61
+ 用户原始需求:
62
+ <user_query_wrapper>
63
+ {{ query }}
64
+ </user_query_wrapper>
65
+
66
+ 修复上述问题,请确保代码质量问题被解决,同时保持代码的原有功能。
67
+ """
68
+
69
+ def _format_lint_issues(self, lint_results:ProjectLintResult,level:IssueSeverity) -> str:
70
+ """
71
+ 将linter结果格式化为字符串供模型使用
72
+
73
+ 参数:
74
+ lint_results: Linter结果对象
75
+ level: 过滤问题的级别
76
+
77
+ 返回:
78
+ str: 格式化的问题描述
79
+ """
80
+ formatted_issues = []
81
+
82
+ for file_path, result in lint_results.file_results.items():
83
+ file_has_issues = False
84
+ file_issues = []
85
+
86
+ for issue in result.issues:
87
+ if issue.severity.value != level.value:
88
+ continue
89
+
90
+ if not file_has_issues:
91
+ file_has_issues = True
92
+ file_issues.append(f"文件: {file_path}")
93
+
94
+ severity = "错误" if issue.severity == IssueSeverity.ERROR else "警告" if issue.severity == IssueSeverity.WARNING else "信息"
95
+ line_info = f"第{issue.position.line}行"
96
+ if issue.position.column:
97
+ line_info += f", 第{issue.position.column}列"
98
+
99
+ file_issues.append(
100
+ f" - [{severity}] {line_info}: {issue.message} (规则: {issue.code})"
101
+ )
102
+
103
+ if file_has_issues:
104
+ formatted_issues.extend(file_issues)
105
+ formatted_issues.append("") # 空行分隔不同文件
106
+
107
+ return "\n".join(formatted_issues)
108
+
109
+ def _count_errors(self, lint_results:ProjectLintResult) -> int:
110
+ """
111
+ 计算lint结果中的错误数量
112
+
113
+ 参数:
114
+ lint_results: Linter结果对象
115
+
116
+ 返回:
117
+ int: 错误数量
118
+ """
119
+ error_count = 0
120
+
121
+ for _, result in lint_results.file_results.items():
122
+ error_count += result.error_count
123
+
124
+ return error_count
125
+
126
+ def generate_and_fix(self, query: str, source_code_list: SourceCodeList) -> CodeGenerateResult:
127
+ """
128
+ 生成代码,运行linter,修复错误,最多尝试指定次数
129
+
130
+ 参数:
131
+ query (str): 用户查询
132
+ source_code_list (SourceCodeList): 源代码列表
133
+
134
+ 返回:
135
+ CodeGenerateResult: 生成的代码结果
136
+ """
137
+ # 初始代码生成
138
+ self.printer.print_in_terminal("generating_initial_code")
139
+ start_time = time.time()
140
+ generation_result = self.code_generator.single_round_run(query, source_code_list)
141
+
142
+ token_cost_calculator = TokenCostCalculator(args=self.args)
143
+ token_cost_calculator.track_token_usage_by_generate(
144
+ llm=self.llm,
145
+ generate=generation_result,
146
+ operation_name="code_generation_complete",
147
+ start_time=start_time,
148
+ end_time=time.time()
149
+ )
150
+
151
+ # 确保结果非空
152
+ if not generation_result.contents:
153
+ self.printer.print_in_terminal("generation_failed", style="red")
154
+ return generation_result
155
+
156
+
157
+ # 最多尝试修复5次
158
+ for attempt in range(self.max_correction_attempts):
159
+ global_cancel.check_and_raise()
160
+ # 代码生成结果更新到影子文件里去
161
+ shadow_files = self._create_shadow_files_from_edits(generation_result)
162
+
163
+ if not shadow_files:
164
+ self.printer.print_in_terminal("no_files_to_lint", style="yellow")
165
+ break
166
+
167
+ # 运行linter
168
+ lint_results = self.shadow_linter.lint_all_shadow_files()
169
+ error_count = self._count_errors(lint_results)
170
+
171
+ # 如果没有错误则完成
172
+ if error_count == 0:
173
+ self.printer.print_in_terminal("no_lint_errors_found", style="green")
174
+ break
175
+
176
+ # 格式化lint问题
177
+ formatted_issues = self._format_lint_issues(lint_results, IssueSeverity.ERROR)
178
+
179
+ # 打印当前错误
180
+ self.printer.print_in_terminal(
181
+ "lint_attempt_status",
182
+ style="yellow",
183
+ attempt=(attempt + 1),
184
+ max_correction_attempts=self.max_correction_attempts,
185
+ error_count=error_count,
186
+ formatted_issues=formatted_issues
187
+ )
188
+
189
+ if attempt == self.max_correction_attempts - 1:
190
+ self.printer.print_in_terminal("max_attempts_reached", style="yellow")
191
+ break
192
+
193
+ # 准备修复提示
194
+ fix_prompt = self.fix_linter_errors.prompt(
195
+ query=query,
196
+ lint_issues=formatted_issues
197
+ )
198
+
199
+ for source in source_code_list.sources:
200
+ print(f"file_path: {source.module_name}")
201
+ print(f"fix_prompt: {fix_prompt}")
202
+
203
+ # 将 shadow_files 转化为 source_code_list
204
+ source_code_list = self.code_merger.get_source_code_list_from_shadow_files(shadow_files)
205
+ start_time = time.time()
206
+ generation_result = self.code_generator.single_round_run(fix_prompt, source_code_list)
207
+ token_cost_calculator.track_token_usage_by_generate(
208
+ llm=self.llm,
209
+ generate=generation_result,
210
+ operation_name="code_generation_complete",
211
+ start_time=start_time,
212
+ end_time=time.time()
213
+ )
214
+
215
+ # 清理临时影子文件
216
+ self.shadow_manager.clean_shadows()
217
+
218
+ # 返回最终结果
219
+ return generation_result
220
+
221
+ def run(self, query: str, source_code_list: SourceCodeList) -> CodeGenerateResult:
222
+ """
223
+ 执行完整的代码生成、修复、合并流程
224
+
225
+ 参数:
226
+ query (str): 用户查询
227
+ source_code_list (SourceCodeList): 源代码列表
228
+
229
+ 返回:
230
+ CodeGenerateResult: 生成和修复的代码结果
231
+ """
232
+ # 生成代码并自动修复lint错误
233
+ generation_result = self.generate_and_fix(query, source_code_list)
234
+ global_cancel.check_and_raise()
235
+ # 合并代码
236
+ self.code_merger.merge_code(generation_result)
237
+
238
+ return generation_result