auto-coder 0.1.316__py3-none-any.whl → 0.1.318__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.316.dist-info → auto_coder-0.1.318.dist-info}/METADATA +2 -2
- {auto_coder-0.1.316.dist-info → auto_coder-0.1.318.dist-info}/RECORD +41 -20
- autocoder/auto_coder_runner.py +1 -2
- autocoder/common/__init__.py +3 -0
- autocoder/common/auto_coder_lang.py +24 -0
- autocoder/common/code_auto_merge_editblock.py +2 -42
- autocoder/common/git_utils.py +2 -2
- autocoder/common/token_cost_caculate.py +103 -42
- autocoder/common/v2/__init__.py +0 -0
- autocoder/common/v2/code_auto_generate.py +199 -0
- autocoder/common/v2/code_auto_generate_diff.py +361 -0
- autocoder/common/v2/code_auto_generate_editblock.py +380 -0
- autocoder/common/v2/code_auto_generate_strict_diff.py +269 -0
- autocoder/common/v2/code_auto_merge.py +211 -0
- autocoder/common/v2/code_auto_merge_diff.py +354 -0
- autocoder/common/v2/code_auto_merge_editblock.py +523 -0
- autocoder/common/v2/code_auto_merge_strict_diff.py +259 -0
- autocoder/common/v2/code_diff_manager.py +266 -0
- autocoder/common/v2/code_editblock_manager.py +282 -0
- autocoder/common/v2/code_manager.py +238 -0
- autocoder/common/v2/code_strict_diff_manager.py +241 -0
- autocoder/dispacher/actions/action.py +16 -0
- autocoder/dispacher/actions/plugins/action_regex_project.py +6 -0
- autocoder/events/event_manager_singleton.py +2 -2
- autocoder/helper/__init__.py +0 -0
- autocoder/helper/project_creator.py +570 -0
- autocoder/linters/linter_factory.py +44 -25
- autocoder/linters/models.py +220 -0
- autocoder/linters/python_linter.py +1 -7
- autocoder/linters/reactjs_linter.py +580 -0
- autocoder/linters/shadow_linter.py +390 -0
- autocoder/linters/vue_linter.py +576 -0
- autocoder/memory/active_context_manager.py +0 -4
- autocoder/memory/active_package.py +12 -12
- autocoder/shadows/__init__.py +0 -0
- autocoder/shadows/shadow_manager.py +235 -0
- autocoder/version.py +1 -1
- {auto_coder-0.1.316.dist-info → auto_coder-0.1.318.dist-info}/LICENSE +0 -0
- {auto_coder-0.1.316.dist-info → auto_coder-0.1.318.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.316.dist-info → auto_coder-0.1.318.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.316.dist-info → auto_coder-0.1.318.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,282 @@
|
|
|
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,levels:List[IssueSeverity]=[IssueSeverity.ERROR]) -> 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 in levels:
|
|
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,levels:List[IssueSeverity]=[IssueSeverity.ERROR]) -> 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
|
+
if IssueSeverity.ERROR in levels:
|
|
155
|
+
error_count += result.error_count
|
|
156
|
+
if IssueSeverity.WARNING in levels:
|
|
157
|
+
error_count += result.warning_count
|
|
158
|
+
if IssueSeverity.INFO in levels:
|
|
159
|
+
error_count += result.info_count
|
|
160
|
+
if IssueSeverity.HINT in levels:
|
|
161
|
+
error_count += result.hint_count
|
|
162
|
+
|
|
163
|
+
return error_count
|
|
164
|
+
|
|
165
|
+
def generate_and_fix(self, query: str, source_code_list: SourceCodeList) -> CodeGenerateResult:
|
|
166
|
+
"""
|
|
167
|
+
生成代码,运行linter,修复错误,最多尝试指定次数
|
|
168
|
+
|
|
169
|
+
参数:
|
|
170
|
+
query (str): 用户查询
|
|
171
|
+
source_code_list (SourceCodeList): 源代码列表
|
|
172
|
+
|
|
173
|
+
返回:
|
|
174
|
+
CodeGenerateResult: 生成的代码结果
|
|
175
|
+
"""
|
|
176
|
+
# 初始代码生成
|
|
177
|
+
self.printer.print_in_terminal("generating_initial_code")
|
|
178
|
+
start_time = time.time()
|
|
179
|
+
generation_result = self.code_generator.single_round_run(query, source_code_list)
|
|
180
|
+
|
|
181
|
+
token_cost_calculator = TokenCostCalculator(args=self.args)
|
|
182
|
+
token_cost_calculator.track_token_usage_by_generate(
|
|
183
|
+
llm=self.llm,
|
|
184
|
+
generate=generation_result,
|
|
185
|
+
operation_name="code_generation_complete",
|
|
186
|
+
start_time=start_time,
|
|
187
|
+
end_time=time.time()
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
# 确保结果非空
|
|
191
|
+
if not generation_result.contents:
|
|
192
|
+
self.printer.print_in_terminal("generation_failed", style="red")
|
|
193
|
+
return generation_result
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
# 最多尝试修复5次
|
|
197
|
+
for attempt in range(self.max_correction_attempts):
|
|
198
|
+
global_cancel.check_and_raise()
|
|
199
|
+
# 代码生成结果更新到影子文件里去
|
|
200
|
+
shadow_files = self._create_shadow_files_from_edits(generation_result)
|
|
201
|
+
|
|
202
|
+
if not shadow_files:
|
|
203
|
+
self.printer.print_in_terminal("no_files_to_lint", style="yellow")
|
|
204
|
+
break
|
|
205
|
+
|
|
206
|
+
# 运行linter
|
|
207
|
+
lint_results = self.shadow_linter.lint_all_shadow_files()
|
|
208
|
+
error_count = self._count_errors(lint_results)
|
|
209
|
+
# print(f"error_count: {error_count}")
|
|
210
|
+
# print(f"lint_results: {json.dumps(lint_results.model_dump(), indent=4,ensure_ascii=False)}")
|
|
211
|
+
|
|
212
|
+
# 如果没有错误则完成
|
|
213
|
+
if error_count == 0:
|
|
214
|
+
self.printer.print_in_terminal("no_lint_errors_found", style="green")
|
|
215
|
+
break
|
|
216
|
+
|
|
217
|
+
# 格式化lint问题
|
|
218
|
+
formatted_issues = self._format_lint_issues(lint_results, [IssueSeverity.ERROR, IssueSeverity.WARNING])
|
|
219
|
+
|
|
220
|
+
# 打印当前错误
|
|
221
|
+
self.printer.print_in_terminal(
|
|
222
|
+
"lint_attempt_status",
|
|
223
|
+
style="yellow",
|
|
224
|
+
attempt=(attempt + 1),
|
|
225
|
+
max_correction_attempts=self.max_correction_attempts,
|
|
226
|
+
error_count=error_count,
|
|
227
|
+
formatted_issues=formatted_issues
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
if attempt == self.max_correction_attempts - 1:
|
|
231
|
+
self.printer.print_in_terminal("max_attempts_reached", style="yellow")
|
|
232
|
+
break
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
# 准备修复提示
|
|
237
|
+
fix_prompt = self.fix_linter_errors.prompt(
|
|
238
|
+
query=query,
|
|
239
|
+
lint_issues=formatted_issues
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
# for source in source_code_list.sources:
|
|
243
|
+
# print(f"file_path: {source.module_name}")
|
|
244
|
+
# print(f"fix_prompt: {fix_prompt}")
|
|
245
|
+
|
|
246
|
+
# 将 shadow_files 转化为 source_code_list
|
|
247
|
+
start_time = time.time()
|
|
248
|
+
source_code_list = self.code_merger.get_source_code_list_from_shadow_files(shadow_files)
|
|
249
|
+
generation_result = self.code_generator.single_round_run(fix_prompt, source_code_list)
|
|
250
|
+
token_cost_calculator.track_token_usage_by_generate(
|
|
251
|
+
llm=self.llm,
|
|
252
|
+
generate=generation_result,
|
|
253
|
+
operation_name="code_generation_complete",
|
|
254
|
+
start_time=start_time,
|
|
255
|
+
end_time=time.time()
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
# 清理临时影子文件
|
|
260
|
+
self.shadow_manager.clean_shadows()
|
|
261
|
+
|
|
262
|
+
# 返回最终结果
|
|
263
|
+
return generation_result
|
|
264
|
+
|
|
265
|
+
def run(self, query: str, source_code_list: SourceCodeList) -> CodeGenerateResult:
|
|
266
|
+
"""
|
|
267
|
+
执行完整的代码生成、修复、合并流程
|
|
268
|
+
|
|
269
|
+
参数:
|
|
270
|
+
query (str): 用户查询
|
|
271
|
+
source_code_list (SourceCodeList): 源代码列表
|
|
272
|
+
|
|
273
|
+
返回:
|
|
274
|
+
CodeGenerateResult: 生成和修复的代码结果
|
|
275
|
+
"""
|
|
276
|
+
# 生成代码并自动修复lint错误
|
|
277
|
+
generation_result = self.generate_and_fix(query, source_code_list)
|
|
278
|
+
global_cancel.check_and_raise()
|
|
279
|
+
# 合并代码
|
|
280
|
+
self.code_merger.merge_code(generation_result)
|
|
281
|
+
|
|
282
|
+
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
|