auto-coder 0.1.330__py3-none-any.whl → 0.1.331__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.330.dist-info → auto_coder-0.1.331.dist-info}/METADATA +1 -1
- {auto_coder-0.1.330.dist-info → auto_coder-0.1.331.dist-info}/RECORD +40 -40
- autocoder/agent/project_reader.py +1 -14
- autocoder/auto_coder.py +1 -24
- autocoder/command_args.py +1 -6
- autocoder/commands/tools.py +0 -13
- autocoder/common/__init__.py +6 -3
- autocoder/common/auto_coder_lang.py +12 -0
- autocoder/common/code_auto_generate.py +6 -160
- autocoder/common/code_auto_generate_diff.py +5 -111
- autocoder/common/code_auto_generate_editblock.py +5 -95
- autocoder/common/code_auto_generate_strict_diff.py +6 -112
- autocoder/common/code_auto_merge_editblock.py +1 -45
- autocoder/common/command_templates.py +2 -9
- autocoder/common/stream_out_type.py +3 -0
- autocoder/common/types.py +2 -1
- autocoder/common/v2/code_auto_generate.py +6 -4
- autocoder/common/v2/code_auto_generate_diff.py +4 -3
- autocoder/common/v2/code_auto_generate_editblock.py +9 -4
- autocoder/common/v2/code_auto_generate_strict_diff.py +182 -14
- autocoder/common/v2/code_auto_merge_diff.py +560 -306
- autocoder/common/v2/code_auto_merge_editblock.py +11 -44
- autocoder/common/v2/code_auto_merge_strict_diff.py +76 -7
- autocoder/common/v2/code_editblock_manager.py +141 -6
- autocoder/dispacher/actions/action.py +15 -28
- autocoder/dispacher/actions/plugins/action_regex_project.py +5 -9
- autocoder/helper/project_creator.py +0 -1
- autocoder/index/entry.py +0 -43
- autocoder/index/filter/normal_filter.py +0 -16
- autocoder/lang.py +2 -4
- autocoder/pyproject/__init__.py +2 -19
- autocoder/rag/cache/simple_cache.py +31 -6
- autocoder/regexproject/__init__.py +4 -22
- autocoder/suffixproject/__init__.py +6 -24
- autocoder/tsproject/__init__.py +5 -22
- autocoder/version.py +1 -1
- {auto_coder-0.1.330.dist-info → auto_coder-0.1.331.dist-info}/LICENSE +0 -0
- {auto_coder-0.1.330.dist-info → auto_coder-0.1.331.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.330.dist-info → auto_coder-0.1.331.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.330.dist-info → auto_coder-0.1.331.dist-info}/top_level.txt +0 -0
|
@@ -269,10 +269,12 @@ class CodeAutoMergeEditBlock:
|
|
|
269
269
|
codes = self.get_edits(content)
|
|
270
270
|
file_content_mapping = {}
|
|
271
271
|
failed_blocks = []
|
|
272
|
+
merged_blocks = []
|
|
272
273
|
|
|
273
274
|
for block in codes:
|
|
274
275
|
file_path, head, update = block
|
|
275
276
|
if not os.path.exists(file_path):
|
|
277
|
+
merged_blocks.append((file_path, "", update))
|
|
276
278
|
file_content_mapping[file_path] = update
|
|
277
279
|
else:
|
|
278
280
|
if file_path not in file_content_mapping:
|
|
@@ -286,7 +288,7 @@ class CodeAutoMergeEditBlock:
|
|
|
286
288
|
else existing_content + "\n" + update
|
|
287
289
|
)
|
|
288
290
|
|
|
289
|
-
# If exact match fails, try similarity match
|
|
291
|
+
# If exact match fails, try similarity match
|
|
290
292
|
if new_content == existing_content and head:
|
|
291
293
|
similarity, best_window = TextSimilarity(
|
|
292
294
|
head, existing_content
|
|
@@ -297,6 +299,7 @@ class CodeAutoMergeEditBlock:
|
|
|
297
299
|
)
|
|
298
300
|
|
|
299
301
|
if new_content != existing_content:
|
|
302
|
+
merged_blocks.append((file_path, head, update))
|
|
300
303
|
file_content_mapping[file_path] = new_content
|
|
301
304
|
else:
|
|
302
305
|
failed_blocks.append((file_path, head, update))
|
|
@@ -304,7 +307,8 @@ class CodeAutoMergeEditBlock:
|
|
|
304
307
|
return MergeCodeWithoutEffect(
|
|
305
308
|
success_blocks=[(path, content)
|
|
306
309
|
for path, content in file_content_mapping.items()],
|
|
307
|
-
failed_blocks=failed_blocks
|
|
310
|
+
failed_blocks=failed_blocks,
|
|
311
|
+
merged_blocks=merged_blocks
|
|
308
312
|
)
|
|
309
313
|
|
|
310
314
|
|
|
@@ -363,35 +367,12 @@ class CodeAutoMergeEditBlock:
|
|
|
363
367
|
else:
|
|
364
368
|
unmerged_blocks.append(
|
|
365
369
|
(file_path, head, update, similarity))
|
|
366
|
-
|
|
367
|
-
if unmerged_blocks:
|
|
368
|
-
if self.args.request_id and not self.args.skip_events:
|
|
369
|
-
# collect unmerged blocks
|
|
370
|
-
event_data = []
|
|
371
|
-
for file_path, head, update, similarity in unmerged_blocks:
|
|
372
|
-
event_data.append(
|
|
373
|
-
{
|
|
374
|
-
"file_path": file_path,
|
|
375
|
-
"head": head,
|
|
376
|
-
"update": update,
|
|
377
|
-
"similarity": similarity,
|
|
378
|
-
}
|
|
379
|
-
)
|
|
380
|
-
return
|
|
381
370
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
for file_path, new_content in file_content_mapping.items():
|
|
388
|
-
if file_path.endswith(".py"):
|
|
389
|
-
pylint_passed, error_message = self.run_pylint(new_content)
|
|
390
|
-
if not pylint_passed:
|
|
391
|
-
self.printer.print_in_terminal("pylint_file_check_failed",
|
|
392
|
-
file_path=file_path,
|
|
393
|
-
error_message=error_message)
|
|
394
|
-
|
|
371
|
+
if unmerged_blocks:
|
|
372
|
+
self.printer.print_in_terminal("unmerged_blocks_warning", num_blocks=len(unmerged_blocks))
|
|
373
|
+
self._print_unmerged_blocks(unmerged_blocks)
|
|
374
|
+
return
|
|
375
|
+
|
|
395
376
|
if changes_made and not force_skip_git and not self.args.skip_commit:
|
|
396
377
|
try:
|
|
397
378
|
git_utils.commit_changes(
|
|
@@ -410,20 +391,6 @@ class CodeAutoMergeEditBlock:
|
|
|
410
391
|
with open(file_path, "w") as f:
|
|
411
392
|
f.write(new_content)
|
|
412
393
|
|
|
413
|
-
if self.args.request_id and not self.args.skip_events:
|
|
414
|
-
# collect modified files
|
|
415
|
-
event_data = []
|
|
416
|
-
for code in merged_blocks:
|
|
417
|
-
file_path, head, update, similarity = code
|
|
418
|
-
event_data.append(
|
|
419
|
-
{
|
|
420
|
-
"file_path": file_path,
|
|
421
|
-
"head": head,
|
|
422
|
-
"update": update,
|
|
423
|
-
"similarity": similarity,
|
|
424
|
-
}
|
|
425
|
-
)
|
|
426
|
-
|
|
427
394
|
|
|
428
395
|
if changes_made:
|
|
429
396
|
if not force_skip_git and not self.args.skip_commit:
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import difflib
|
|
3
3
|
import diff_match_patch as dmp_module
|
|
4
|
-
from
|
|
5
|
-
from typing import List,
|
|
4
|
+
from autocoder.common import AutoCoderArgs, git_utils
|
|
5
|
+
from typing import List,Tuple
|
|
6
6
|
import pydantic
|
|
7
7
|
import byzerllm
|
|
8
|
-
from autocoder.common import
|
|
8
|
+
from autocoder.common.action_yml_file_manager import ActionYmlFileManager
|
|
9
|
+
from autocoder.common.printer import Printer
|
|
10
|
+
import hashlib
|
|
11
|
+
from pathlib import Path
|
|
9
12
|
from autocoder.common.types import CodeGenerateResult, MergeCodeWithoutEffect
|
|
10
|
-
from autocoder.common.
|
|
11
|
-
from autocoder.common import files as
|
|
13
|
+
from autocoder.common.code_modification_ranker import CodeModificationRanker
|
|
14
|
+
from autocoder.common import files as FileUtils
|
|
15
|
+
from autocoder.memory.active_context_manager import ActiveContextManager
|
|
12
16
|
|
|
13
17
|
class PathAndCode(pydantic.BaseModel):
|
|
14
18
|
path: str
|
|
@@ -49,6 +53,7 @@ def apply_hunk(content, hunk):
|
|
|
49
53
|
|
|
50
54
|
return "\n".join(content_out)
|
|
51
55
|
|
|
56
|
+
|
|
52
57
|
def hunk_to_before_after(hunk, lines=False):
|
|
53
58
|
before = []
|
|
54
59
|
after = []
|
|
@@ -77,7 +82,14 @@ def hunk_to_before_after(hunk, lines=False):
|
|
|
77
82
|
|
|
78
83
|
return before, after
|
|
79
84
|
|
|
80
|
-
|
|
85
|
+
|
|
86
|
+
class CodeAutoMergeStrictDiff:
|
|
87
|
+
def __init__(self, llm: byzerllm.ByzerLLM, args: AutoCoderArgs):
|
|
88
|
+
self.llm = llm
|
|
89
|
+
self.args = args
|
|
90
|
+
self.printer = Printer()
|
|
91
|
+
|
|
92
|
+
|
|
81
93
|
def parse_diff_block(self,text: str) -> List[PathAndCode]:
|
|
82
94
|
lines = text.split('\n')
|
|
83
95
|
lines_len = len(lines)
|
|
@@ -121,6 +133,46 @@ class CodeAutoMergeStrictDiff(CodeAutoMerge):
|
|
|
121
133
|
|
|
122
134
|
return path_and_code_list
|
|
123
135
|
|
|
136
|
+
def merge_code(self, generate_result: CodeGenerateResult, force_skip_git: bool = False):
|
|
137
|
+
result = self.choose_best_choice(generate_result)
|
|
138
|
+
self._merge_code(result.contents[0], force_skip_git)
|
|
139
|
+
return result
|
|
140
|
+
|
|
141
|
+
def choose_best_choice(self, generate_result: CodeGenerateResult) -> CodeGenerateResult:
|
|
142
|
+
if len(generate_result.contents) == 1:
|
|
143
|
+
return generate_result
|
|
144
|
+
|
|
145
|
+
merge_results = []
|
|
146
|
+
for content,conversations in zip(generate_result.contents,generate_result.conversations):
|
|
147
|
+
merge_result = self._merge_code_without_effect(content)
|
|
148
|
+
merge_results.append(merge_result)
|
|
149
|
+
|
|
150
|
+
# If all merge results are None, return first one
|
|
151
|
+
if all(len(result.failed_blocks) != 0 for result in merge_results):
|
|
152
|
+
self.printer.print_in_terminal("all_merge_results_failed")
|
|
153
|
+
return CodeGenerateResult(contents=[generate_result.contents[0]], conversations=[generate_result.conversations[0]])
|
|
154
|
+
|
|
155
|
+
# If only one merge result is not None, return that one
|
|
156
|
+
not_none_indices = [i for i, result in enumerate(merge_results) if len(result.failed_blocks) == 0]
|
|
157
|
+
if len(not_none_indices) == 1:
|
|
158
|
+
idx = not_none_indices[0]
|
|
159
|
+
self.printer.print_in_terminal("only_one_merge_result_success")
|
|
160
|
+
return CodeGenerateResult(contents=[generate_result.contents[idx]], conversations=[generate_result.conversations[idx]])
|
|
161
|
+
|
|
162
|
+
# 最后,如果有多个,那么根据质量排序再返回
|
|
163
|
+
ranker = CodeModificationRanker(self.llm, self.args)
|
|
164
|
+
ranked_result = ranker.rank_modifications(generate_result,merge_results)
|
|
165
|
+
|
|
166
|
+
## 得到的结果,再做一次合并,第一个通过的返回 , 返回做合并有点重复低效,未来修改。
|
|
167
|
+
for content,conversations in zip(ranked_result.contents,ranked_result.conversations):
|
|
168
|
+
merge_result = self._merge_code_without_effect(content)
|
|
169
|
+
if not merge_result.failed_blocks:
|
|
170
|
+
return CodeGenerateResult(contents=[content], conversations=[conversations])
|
|
171
|
+
|
|
172
|
+
# 最后保底,但实际不会出现
|
|
173
|
+
return CodeGenerateResult(contents=[ranked_result.contents[0]], conversations=[ranked_result.conversations[0]])
|
|
174
|
+
|
|
175
|
+
|
|
124
176
|
def abs_root_path(self, path):
|
|
125
177
|
if path.startswith(self.args.source_dir):
|
|
126
178
|
return safe_abs_path(Path(path))
|
|
@@ -207,6 +259,7 @@ class CodeAutoMergeStrictDiff(CodeAutoMerge):
|
|
|
207
259
|
|
|
208
260
|
file_content = FileUtils.read_file(self.args.file)
|
|
209
261
|
md5 = hashlib.md5(file_content.encode('utf-8')).hexdigest()
|
|
262
|
+
# get the file name
|
|
210
263
|
file_name = os.path.basename(self.args.file)
|
|
211
264
|
|
|
212
265
|
if not force_skip_git and not self.args.skip_commit:
|
|
@@ -256,4 +309,20 @@ class CodeAutoMergeStrictDiff(CodeAutoMerge):
|
|
|
256
309
|
git_utils.print_commit_info(commit_result=commit_result)
|
|
257
310
|
else:
|
|
258
311
|
# Print diff blocks for review
|
|
259
|
-
self.print_diff_blocks(diff_blocks)
|
|
312
|
+
self.print_diff_blocks(diff_blocks)
|
|
313
|
+
|
|
314
|
+
@byzerllm.prompt(render="jinja2")
|
|
315
|
+
def git_require_msg(self, source_dir: str, error: str) -> str:
|
|
316
|
+
'''
|
|
317
|
+
auto_merge only works for git repositories.
|
|
318
|
+
|
|
319
|
+
Try to use git init in the source directory.
|
|
320
|
+
|
|
321
|
+
```shell
|
|
322
|
+
cd {{ source_dir }}
|
|
323
|
+
git init .
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
Then try to run auto-coder again.
|
|
327
|
+
Error: {{ error }}
|
|
328
|
+
'''
|
|
@@ -14,7 +14,7 @@ from autocoder.compilers.shadow_compiler import ShadowCompiler
|
|
|
14
14
|
from autocoder.privacy.model_filter import ModelPathFilter
|
|
15
15
|
from autocoder.common.utils_code_auto_generate import chat_with_continue, stream_chat_with_continue, ChatWithContinueResult
|
|
16
16
|
from autocoder.utils.auto_coder_utils.chat_stream_out import stream_out
|
|
17
|
-
from autocoder.common.stream_out_type import LintStreamOutType, CompileStreamOutType
|
|
17
|
+
from autocoder.common.stream_out_type import LintStreamOutType, CompileStreamOutType, UnmergedBlocksStreamOutType
|
|
18
18
|
from autocoder.common.auto_coder_lang import get_message_with_format
|
|
19
19
|
from autocoder.common.printer import Printer
|
|
20
20
|
from autocoder.rag.token_counter import count_tokens
|
|
@@ -103,6 +103,27 @@ class CodeEditBlockManager:
|
|
|
103
103
|
修复上述问题,请确保代码质量问题被解决,同时保持代码的原有功能。
|
|
104
104
|
请严格遵守*SEARCH/REPLACE block*的格式。
|
|
105
105
|
"""
|
|
106
|
+
@byzerllm.prompt()
|
|
107
|
+
def fix_unmerged_blocks(self, query: str, original_code: str, unmerged_blocks: str) -> str:
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
下面是你根据格式要求输出的一份修改代码:
|
|
111
|
+
<original_code>
|
|
112
|
+
{{ original_code }}
|
|
113
|
+
</original_code>
|
|
114
|
+
|
|
115
|
+
但是我发现下面的代码块无法合并:
|
|
116
|
+
<unmerged_blocks>
|
|
117
|
+
{{ unmerged_blocks }}
|
|
118
|
+
</unmerged_blocks>
|
|
119
|
+
|
|
120
|
+
下面是用户原始的需求:
|
|
121
|
+
<user_query_wrapper>
|
|
122
|
+
{{ query }}
|
|
123
|
+
</user_query_wrapper>
|
|
124
|
+
|
|
125
|
+
请根据反馈,回顾之前的格式要求,重新生成一份修改代码,确保所有代码块都能够正确合并。
|
|
126
|
+
"""
|
|
106
127
|
|
|
107
128
|
def _create_shadow_files_from_edits(self, generation_result: CodeGenerateResult) -> Dict[str, str]:
|
|
108
129
|
"""
|
|
@@ -219,6 +240,119 @@ class CodeEditBlockManager:
|
|
|
219
240
|
self.printer.print_in_terminal("generation_failed", style="red")
|
|
220
241
|
return generation_result
|
|
221
242
|
|
|
243
|
+
result = self.code_merger.choose_best_choice(generation_result)
|
|
244
|
+
merge = self.code_merger._merge_code_without_effect(result.contents[0])
|
|
245
|
+
|
|
246
|
+
if self.args.enable_auto_fix_merge and merge.failed_blocks:
|
|
247
|
+
def _format_blocks(merge: MergeCodeWithoutEffect) -> Tuple[str, str]:
|
|
248
|
+
unmerged_formatted_text = ""
|
|
249
|
+
for file_path, head, update in merge.failed_blocks:
|
|
250
|
+
unmerged_formatted_text += "```lang"
|
|
251
|
+
unmerged_formatted_text += f"##File: {file_path}\n"
|
|
252
|
+
unmerged_formatted_text += "<<<<<<< SEARCH\n"
|
|
253
|
+
unmerged_formatted_text += head
|
|
254
|
+
unmerged_formatted_text += "=======\n"
|
|
255
|
+
unmerged_formatted_text += update
|
|
256
|
+
unmerged_formatted_text += ">>>>>>> REPLACE\n"
|
|
257
|
+
unmerged_formatted_text += "```"
|
|
258
|
+
unmerged_formatted_text += "\n"
|
|
259
|
+
|
|
260
|
+
merged_formatted_text = ""
|
|
261
|
+
for file_path, head, update in merge.merged_blocks:
|
|
262
|
+
merged_formatted_text += "```lang"
|
|
263
|
+
merged_formatted_text += f"##File: {file_path}\n"
|
|
264
|
+
merged_formatted_text += head
|
|
265
|
+
merged_formatted_text += "=======\n"
|
|
266
|
+
merged_formatted_text += update
|
|
267
|
+
merged_formatted_text += "```"
|
|
268
|
+
merged_formatted_text += "\n"
|
|
269
|
+
|
|
270
|
+
get_event_manager(self.args.event_file).write_result(EventContentCreator.create_result(
|
|
271
|
+
content=EventContentCreator.ResultContent(content=f"Unmerged blocks:\\n {unmerged_formatted_text}",
|
|
272
|
+
metadata={
|
|
273
|
+
"merged_blocks": merge.success_blocks,
|
|
274
|
+
"failed_blocks": merge.failed_blocks
|
|
275
|
+
}
|
|
276
|
+
).to_dict(),
|
|
277
|
+
metadata={
|
|
278
|
+
"stream_out_type": UnmergedBlocksStreamOutType.UNMERGED_BLOCKS.value,
|
|
279
|
+
"action_file": self.args.file
|
|
280
|
+
}
|
|
281
|
+
))
|
|
282
|
+
return (unmerged_formatted_text, merged_formatted_text)
|
|
283
|
+
|
|
284
|
+
for attempt in range(self.args.auto_fix_merge_max_attempts):
|
|
285
|
+
global_cancel.check_and_raise()
|
|
286
|
+
unmerged_formatted_text, merged_formatted_text = _format_blocks(
|
|
287
|
+
merge)
|
|
288
|
+
fix_prompt = self.fix_unmerged_blocks.prompt(
|
|
289
|
+
query=query,
|
|
290
|
+
original_code=result.contents[0],
|
|
291
|
+
unmerged_blocks=unmerged_formatted_text
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
logger.info(f"fix_prompt: {fix_prompt}")
|
|
295
|
+
|
|
296
|
+
# 打印当前修复尝试状态
|
|
297
|
+
self.printer.print_in_terminal(
|
|
298
|
+
"unmerged_blocks_attempt_status",
|
|
299
|
+
style="yellow",
|
|
300
|
+
attempt=(attempt + 1),
|
|
301
|
+
max_correction_attempts=self.args.auto_fix_merge_max_attempts
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
get_event_manager(self.args.event_file).write_result(EventContentCreator.create_result(
|
|
305
|
+
content=EventContentCreator.ResultContent(content=f"Unmerged blocks attempt {attempt + 1}/{self.args.auto_fix_merge_max_attempts}: {unmerged_formatted_text}",
|
|
306
|
+
metadata={}
|
|
307
|
+
).to_dict(),
|
|
308
|
+
metadata={
|
|
309
|
+
"stream_out_type": UnmergedBlocksStreamOutType.UNMERGED_BLOCKS.value,
|
|
310
|
+
"action_file": self.args.file
|
|
311
|
+
}
|
|
312
|
+
))
|
|
313
|
+
|
|
314
|
+
# 使用修复提示重新生成代码
|
|
315
|
+
start_time = time.time()
|
|
316
|
+
generation_result = self.code_generator.single_round_run(
|
|
317
|
+
fix_prompt, source_code_list)
|
|
318
|
+
|
|
319
|
+
# 计算这次修复未合并块花费的token情况
|
|
320
|
+
token_cost_calculator = TokenCostCalculator(args=self.args)
|
|
321
|
+
token_cost_calculator.track_token_usage_by_generate(
|
|
322
|
+
llm=self.llm,
|
|
323
|
+
generate=generation_result,
|
|
324
|
+
operation_name="code_generation_complete",
|
|
325
|
+
start_time=start_time,
|
|
326
|
+
end_time=time.time()
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
# 检查修复后的代码是否仍有未合并块
|
|
330
|
+
result = self.code_merger.choose_best_choice(generation_result)
|
|
331
|
+
merge = self.code_merger._merge_code_without_effect(
|
|
332
|
+
result.contents[0])
|
|
333
|
+
|
|
334
|
+
# 如果没有失败的块,则修复成功,退出循环
|
|
335
|
+
if not merge.failed_blocks:
|
|
336
|
+
self.printer.print_in_terminal(
|
|
337
|
+
"unmerged_blocks_fixed", style="green")
|
|
338
|
+
break
|
|
339
|
+
|
|
340
|
+
# 如果是最后一次尝试仍未成功,打印警告
|
|
341
|
+
if attempt == self.args.auto_fix_merge_max_attempts - 1:
|
|
342
|
+
self.printer.print_in_terminal(
|
|
343
|
+
"max_unmerged_blocks_attempts_reached", style="yellow")
|
|
344
|
+
get_event_manager(self.args.event_file).write_result(EventContentCreator.create_result(
|
|
345
|
+
content=EventContentCreator.ResultContent(content=self.printer.get_message_from_key("max_unmerged_blocks_attempts_reached"),
|
|
346
|
+
metadata={}
|
|
347
|
+
).to_dict(),
|
|
348
|
+
metadata={
|
|
349
|
+
"stream_out_type": UnmergedBlocksStreamOutType.UNMERGED_BLOCKS.value,
|
|
350
|
+
"action_file": self.args.file
|
|
351
|
+
}
|
|
352
|
+
))
|
|
353
|
+
raise Exception(self.printer.get_message_from_key(
|
|
354
|
+
"max_unmerged_blocks_attempts_reached"))
|
|
355
|
+
|
|
222
356
|
# 最多尝试修复5次
|
|
223
357
|
for attempt in range(self.auto_fix_lint_max_attempts):
|
|
224
358
|
global_cancel.check_and_raise()
|
|
@@ -298,23 +432,24 @@ class CodeEditBlockManager:
|
|
|
298
432
|
start_time=start_time,
|
|
299
433
|
end_time=time.time()
|
|
300
434
|
)
|
|
301
|
-
|
|
435
|
+
|
|
302
436
|
# 如果开启了自动修复compile问题,则进行compile修复
|
|
303
437
|
if self.args.enable_auto_fix_compile:
|
|
304
438
|
for attempt in range(self.auto_fix_compile_max_attempts):
|
|
305
439
|
global_cancel.check_and_raise()
|
|
306
440
|
# 先更新增量影子系统的文件
|
|
307
|
-
shadow_files = self._create_shadow_files_from_edits(
|
|
441
|
+
shadow_files = self._create_shadow_files_from_edits(
|
|
442
|
+
generation_result)
|
|
308
443
|
|
|
309
444
|
# 在影子系统生成完整的项目,然后编译
|
|
310
445
|
compile_result = self.shadow_compiler.compile_all_shadow_files()
|
|
311
|
-
|
|
446
|
+
|
|
312
447
|
# 如果编译成功,则退出,继续往后走
|
|
313
448
|
if compile_result.success or compile_result.total_errors == 0:
|
|
314
449
|
self.printer.print_in_terminal(
|
|
315
450
|
"compile_success", style="green")
|
|
316
451
|
break
|
|
317
|
-
|
|
452
|
+
|
|
318
453
|
# 如果有错误,则把compile结果记录到事件系统
|
|
319
454
|
get_event_manager(self.args.event_file).write_result(EventContentCreator.create_result(
|
|
320
455
|
content=EventContentCreator.ResultContent(content=f"Compile attempt {attempt + 1}/{self.auto_fix_compile_max_attempts}: Found {compile_result.total_errors} errors:\n {compile_result.to_str()}",
|
|
@@ -357,7 +492,7 @@ class CodeEditBlockManager:
|
|
|
357
492
|
operation_name="code_generation_complete",
|
|
358
493
|
start_time=start_time,
|
|
359
494
|
end_time=time.time()
|
|
360
|
-
)
|
|
495
|
+
)
|
|
361
496
|
|
|
362
497
|
# 清理临时影子文件
|
|
363
498
|
self.shadow_manager.clean_shadows()
|
|
@@ -115,7 +115,7 @@ class ActionTSProject(BaseAction):
|
|
|
115
115
|
|
|
116
116
|
global_cancel.check_and_raise()
|
|
117
117
|
|
|
118
|
-
if args.enable_auto_fix_lint and args.execute and args.auto_merge=="editblock":
|
|
118
|
+
if (args.enable_auto_fix_merge or args.enable_auto_fix_lint) and args.execute and args.auto_merge=="editblock":
|
|
119
119
|
code_merge_manager = CodeEditBlockManager(llm=self.llm, args=self.args,action=self)
|
|
120
120
|
code_merge_manager.run(query=args.query, source_code_list=source_code_list)
|
|
121
121
|
return
|
|
@@ -138,15 +138,10 @@ class ActionTSProject(BaseAction):
|
|
|
138
138
|
else:
|
|
139
139
|
generate = CodeAutoGenerate(
|
|
140
140
|
llm=self.llm, args=self.args, action=self)
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
)
|
|
146
|
-
else:
|
|
147
|
-
generate_result = generate.single_round_run(
|
|
148
|
-
query=args.query, source_code_list=source_code_list
|
|
149
|
-
)
|
|
141
|
+
|
|
142
|
+
generate_result = generate.single_round_run(
|
|
143
|
+
query=args.query, source_code_list=source_code_list
|
|
144
|
+
)
|
|
150
145
|
elapsed_time = time.time() - start_time
|
|
151
146
|
speed = generate_result.metadata.get(
|
|
152
147
|
'generated_tokens_count', 0) / elapsed_time if elapsed_time > 0 else 0
|
|
@@ -274,7 +269,7 @@ class ActionPyProject(BaseAction):
|
|
|
274
269
|
|
|
275
270
|
global_cancel.check_and_raise()
|
|
276
271
|
|
|
277
|
-
if args.enable_auto_fix_lint and args.execute and args.auto_merge=="editblock":
|
|
272
|
+
if (args.enable_auto_fix_merge or args.enable_auto_fix_lint) and args.execute and args.auto_merge=="editblock":
|
|
278
273
|
code_merge_manager = CodeEditBlockManager(llm=self.llm, args=self.args,action=self)
|
|
279
274
|
code_merge_manager.run(query=args.query, source_code_list=source_code_list)
|
|
280
275
|
return
|
|
@@ -297,15 +292,11 @@ class ActionPyProject(BaseAction):
|
|
|
297
292
|
else:
|
|
298
293
|
generate = CodeAutoGenerate(
|
|
299
294
|
llm=self.llm, args=self.args, action=self)
|
|
295
|
+
|
|
296
|
+
generate_result = generate.single_round_run(
|
|
297
|
+
query=args.query, source_code_list=source_code_list
|
|
298
|
+
)
|
|
300
299
|
|
|
301
|
-
if self.args.enable_multi_round_generate:
|
|
302
|
-
generate_result = generate.multi_round_run(
|
|
303
|
-
query=args.query, source_code_list=source_code_list
|
|
304
|
-
)
|
|
305
|
-
else:
|
|
306
|
-
generate_result = generate.single_round_run(
|
|
307
|
-
query=args.query, source_code_list=source_code_list
|
|
308
|
-
)
|
|
309
300
|
elapsed_time = time.time() - start_time
|
|
310
301
|
speed = generate_result.metadata.get(
|
|
311
302
|
'generated_tokens_count', 0) / elapsed_time if elapsed_time > 0 else 0
|
|
@@ -426,7 +417,7 @@ class ActionSuffixProject(BaseAction):
|
|
|
426
417
|
|
|
427
418
|
global_cancel.check_and_raise()
|
|
428
419
|
|
|
429
|
-
if args.enable_auto_fix_lint and args.execute and args.auto_merge=="editblock":
|
|
420
|
+
if (args.enable_auto_fix_merge or args.enable_auto_fix_lint) and args.execute and args.auto_merge=="editblock":
|
|
430
421
|
code_merge_manager = CodeEditBlockManager(llm=self.llm, args=self.args,action=self)
|
|
431
422
|
code_merge_manager.run(query=args.query, source_code_list=source_code_list)
|
|
432
423
|
return
|
|
@@ -449,14 +440,10 @@ class ActionSuffixProject(BaseAction):
|
|
|
449
440
|
else:
|
|
450
441
|
generate = CodeAutoGenerate(
|
|
451
442
|
llm=self.llm, args=self.args, action=self)
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
else:
|
|
457
|
-
generate_result = generate.single_round_run(
|
|
458
|
-
query=args.query, source_code_list=source_code_list
|
|
459
|
-
)
|
|
443
|
+
|
|
444
|
+
generate_result = generate.single_round_run(
|
|
445
|
+
query=args.query, source_code_list=source_code_list
|
|
446
|
+
)
|
|
460
447
|
|
|
461
448
|
elapsed_time = time.time() - start_time
|
|
462
449
|
speed = generate_result.metadata.get(
|
|
@@ -69,7 +69,7 @@ class ActionRegexProject:
|
|
|
69
69
|
|
|
70
70
|
global_cancel.check_and_raise()
|
|
71
71
|
|
|
72
|
-
if args.enable_auto_fix_lint and args.execute and args.auto_merge=="editblock":
|
|
72
|
+
if (args.enable_auto_fix_merge or args.enable_auto_fix_lint) and args.execute and args.auto_merge=="editblock":
|
|
73
73
|
code_merge_manager = CodeEditBlockManager(llm=self.llm, args=self.args,action=self)
|
|
74
74
|
code_merge_manager.run(query=args.query, source_code_list=source_code_list)
|
|
75
75
|
return
|
|
@@ -91,14 +91,10 @@ class ActionRegexProject:
|
|
|
91
91
|
)
|
|
92
92
|
else:
|
|
93
93
|
generate = CodeAutoGenerate(llm=self.llm, args=self.args, action=self)
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
else:
|
|
99
|
-
generate_result = generate.single_round_run(
|
|
100
|
-
query=args.query, source_code_list=source_code_list
|
|
101
|
-
)
|
|
94
|
+
|
|
95
|
+
generate_result = generate.single_round_run(
|
|
96
|
+
query=args.query, source_code_list=source_code_list
|
|
97
|
+
)
|
|
102
98
|
|
|
103
99
|
elapsed_time = time.time() - start_time
|
|
104
100
|
speed = generate_result.metadata.get('generated_tokens_count', 0) / elapsed_time if elapsed_time > 0 else 0
|
autocoder/index/entry.py
CHANGED
|
@@ -86,15 +86,6 @@ def build_index_and_filter_files(
|
|
|
86
86
|
|
|
87
87
|
if not args.skip_build_index and llm:
|
|
88
88
|
# Phase 2: Build index
|
|
89
|
-
if args.request_id and not args.skip_events:
|
|
90
|
-
queue_communicate.send_event(
|
|
91
|
-
request_id=args.request_id,
|
|
92
|
-
event=CommunicateEvent(
|
|
93
|
-
event_type=CommunicateEventType.CODE_INDEX_BUILD_START.value,
|
|
94
|
-
data=json.dumps({"total_files": len(sources)})
|
|
95
|
-
)
|
|
96
|
-
)
|
|
97
|
-
|
|
98
89
|
printer.print_in_terminal("phase2_building_index")
|
|
99
90
|
phase_start = time.monotonic()
|
|
100
91
|
index_manager = IndexManager(llm=llm, sources=sources, args=args)
|
|
@@ -103,17 +94,6 @@ def build_index_and_filter_files(
|
|
|
103
94
|
phase_end = time.monotonic()
|
|
104
95
|
stats["timings"]["build_index"] = phase_end - phase_start
|
|
105
96
|
|
|
106
|
-
if args.request_id and not args.skip_events:
|
|
107
|
-
queue_communicate.send_event(
|
|
108
|
-
request_id=args.request_id,
|
|
109
|
-
event=CommunicateEvent(
|
|
110
|
-
event_type=CommunicateEventType.CODE_INDEX_BUILD_END.value,
|
|
111
|
-
data=json.dumps({
|
|
112
|
-
"indexed_files": stats["indexed_files"],
|
|
113
|
-
"build_index_time": stats["timings"]["build_index"],
|
|
114
|
-
})
|
|
115
|
-
)
|
|
116
|
-
)
|
|
117
97
|
|
|
118
98
|
if not args.skip_filter_index and args.index_filter_model:
|
|
119
99
|
model_name = getattr(
|
|
@@ -313,17 +293,6 @@ def build_index_and_filter_files(
|
|
|
313
293
|
temp_sources, [{"role": "user", "content": args.query}], args.context_prune_strategy)
|
|
314
294
|
source_code_list.sources = pruned_files
|
|
315
295
|
|
|
316
|
-
if args.request_id and not args.skip_events:
|
|
317
|
-
queue_communicate.send_event(
|
|
318
|
-
request_id=args.request_id,
|
|
319
|
-
event=CommunicateEvent(
|
|
320
|
-
event_type=CommunicateEventType.CODE_INDEX_FILTER_FILE_SELECTED.value,
|
|
321
|
-
data=json.dumps([
|
|
322
|
-
(file.module_name, "") for file in source_code_list.sources
|
|
323
|
-
])
|
|
324
|
-
)
|
|
325
|
-
)
|
|
326
|
-
|
|
327
296
|
stats["final_files"] = len(source_code_list.sources)
|
|
328
297
|
phase_end = time.monotonic()
|
|
329
298
|
stats["timings"]["prepare_output"] = phase_end - phase_start
|
|
@@ -374,18 +343,6 @@ def build_index_and_filter_files(
|
|
|
374
343
|
# }
|
|
375
344
|
# )
|
|
376
345
|
|
|
377
|
-
if args.request_id and not args.skip_events:
|
|
378
|
-
queue_communicate.send_event(
|
|
379
|
-
request_id=args.request_id,
|
|
380
|
-
event=CommunicateEvent(
|
|
381
|
-
event_type=CommunicateEventType.CODE_INDEX_FILTER_END.value,
|
|
382
|
-
data=json.dumps({
|
|
383
|
-
"filtered_files": stats["final_files"],
|
|
384
|
-
"filter_time": total_filter_time
|
|
385
|
-
})
|
|
386
|
-
)
|
|
387
|
-
)
|
|
388
|
-
|
|
389
346
|
get_event_manager(args.event_file).write_result(
|
|
390
347
|
EventContentCreator.create_result(
|
|
391
348
|
content=EventContentCreator.ResultContextUsedContent(
|
|
@@ -44,14 +44,6 @@ class NormalFilter():
|
|
|
44
44
|
|
|
45
45
|
final_files: Dict[str, TargetFile] = {}
|
|
46
46
|
if not self.args.skip_filter_index:
|
|
47
|
-
if self.args.request_id and not self.args.skip_events:
|
|
48
|
-
queue_communicate.send_event(
|
|
49
|
-
request_id=self.args.request_id,
|
|
50
|
-
event=CommunicateEvent(
|
|
51
|
-
event_type=CommunicateEventType.CODE_INDEX_FILTER_START.value,
|
|
52
|
-
data=json.dumps({})
|
|
53
|
-
)
|
|
54
|
-
)
|
|
55
47
|
# Phase 3: Level 1 filtering - Query-based
|
|
56
48
|
logger.info(
|
|
57
49
|
"Phase 3: Performing Level 1 filtering (query-based)...")
|
|
@@ -71,14 +63,6 @@ class NormalFilter():
|
|
|
71
63
|
if target_files is not None and self.args.index_filter_level >= 2:
|
|
72
64
|
logger.info(
|
|
73
65
|
"Phase 4: Performing Level 2 filtering (related files)...")
|
|
74
|
-
if self.args.request_id and not self.args.skip_events:
|
|
75
|
-
queue_communicate.send_event(
|
|
76
|
-
request_id=self.args.request_id,
|
|
77
|
-
event=CommunicateEvent(
|
|
78
|
-
event_type=CommunicateEventType.CODE_INDEX_FILTER_START.value,
|
|
79
|
-
data=json.dumps({})
|
|
80
|
-
)
|
|
81
|
-
)
|
|
82
66
|
phase_start = time.monotonic()
|
|
83
67
|
related_files = self.index_manager.get_related_files(
|
|
84
68
|
[file.file_path for file in target_files.file_list]
|
autocoder/lang.py
CHANGED
|
@@ -48,8 +48,7 @@ lang_desc = {
|
|
|
48
48
|
"urls_use_model":"Whether to use model to processing content in urls. Default is False",
|
|
49
49
|
"ray_address": "The address of the Ray cluster to connect to. Default is 'auto'",
|
|
50
50
|
"enable_rag_search":"Whether to enable retrieval augmented generation using search. Default is False",
|
|
51
|
-
"enable_rag_context":"Whether to enable retrieval augmented generation using context. Default is False",
|
|
52
|
-
"enable_multi_round_generate":"Whether to enable multi-round conversation for generation. Default is False",
|
|
51
|
+
"enable_rag_context":"Whether to enable retrieval augmented generation using context. Default is False",
|
|
53
52
|
"index_model_max_length":"The maximum length of the generated code by the index model. Default is 0, which means using the value of model_max_length",
|
|
54
53
|
"index_model_max_input_length":"The maximum length of the input to the index model. Default is 0, which means using the value of model_max_input_length",
|
|
55
54
|
"index_model_anti_quota_limit":"Time to wait in seconds after each API request for the index model. Default is 0, which means using the value of anti_quota_limit",
|
|
@@ -132,8 +131,7 @@ lang_desc = {
|
|
|
132
131
|
"urls_use_model":"是否使用模型处理urls中的内容。默认为False",
|
|
133
132
|
"ray_address": "要连接的Ray集群的地址。默认为'auto'",
|
|
134
133
|
"enable_rag_search":"是否开启使用搜索的检索增强生成。默认为False",
|
|
135
|
-
"enable_rag_context":"是否开启使用上下文的检索增强生成。默认为False",
|
|
136
|
-
"enable_multi_round_generate":"是否开启多轮对话生成。默认为False",
|
|
134
|
+
"enable_rag_context":"是否开启使用上下文的检索增强生成。默认为False",
|
|
137
135
|
"index_model_max_length":"索引模型生成代码的最大长度。默认为0,表示使用model_max_length的值",
|
|
138
136
|
"index_model_max_input_length":"索引模型的最大输入长度。默认为0,表示使用model_max_input_length的值",
|
|
139
137
|
"index_model_anti_quota_limit": "每次索引模型API请求后等待的秒数。默认为0,表示使用anti_quota_limit的值",
|