auto-coder 0.1.263__py3-none-any.whl → 0.1.265__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.263.dist-info → auto_coder-0.1.265.dist-info}/METADATA +1 -1
- {auto_coder-0.1.263.dist-info → auto_coder-0.1.265.dist-info}/RECORD +58 -55
- autocoder/agent/planner.py +4 -4
- autocoder/auto_coder.py +26 -21
- autocoder/auto_coder_server.py +7 -7
- autocoder/chat_auto_coder.py +203 -98
- autocoder/commands/auto_command.py +81 -4
- autocoder/commands/tools.py +48 -50
- autocoder/common/__init__.py +6 -1
- autocoder/common/auto_coder_lang.py +41 -3
- autocoder/common/code_auto_generate.py +3 -3
- autocoder/common/code_auto_generate_diff.py +12 -15
- autocoder/common/code_auto_generate_editblock.py +3 -3
- autocoder/common/code_auto_generate_strict_diff.py +3 -3
- autocoder/common/code_auto_merge.py +23 -3
- autocoder/common/code_auto_merge_diff.py +29 -4
- autocoder/common/code_auto_merge_editblock.py +25 -5
- autocoder/common/code_auto_merge_strict_diff.py +26 -6
- autocoder/common/code_modification_ranker.py +65 -3
- autocoder/common/command_completer.py +3 -0
- autocoder/common/command_generator.py +24 -8
- autocoder/common/command_templates.py +2 -2
- autocoder/common/conf_import_export.py +105 -0
- autocoder/common/conf_validator.py +7 -1
- autocoder/common/context_pruner.py +305 -0
- autocoder/common/files.py +41 -2
- autocoder/common/image_to_page.py +11 -11
- autocoder/common/index_import_export.py +38 -18
- autocoder/common/mcp_hub.py +3 -3
- autocoder/common/mcp_server.py +2 -2
- autocoder/common/shells.py +254 -13
- autocoder/common/stats_panel.py +126 -0
- autocoder/dispacher/actions/action.py +6 -18
- autocoder/dispacher/actions/copilot.py +2 -2
- autocoder/dispacher/actions/plugins/action_regex_project.py +1 -3
- autocoder/dispacher/actions/plugins/action_translate.py +1 -1
- autocoder/index/entry.py +8 -2
- autocoder/index/filter/normal_filter.py +13 -2
- autocoder/index/filter/quick_filter.py +127 -13
- autocoder/index/index.py +8 -7
- autocoder/models.py +2 -2
- autocoder/pyproject/__init__.py +5 -5
- autocoder/rag/cache/byzer_storage_cache.py +4 -4
- autocoder/rag/cache/file_monitor_cache.py +2 -2
- autocoder/rag/cache/simple_cache.py +4 -4
- autocoder/rag/long_context_rag.py +2 -2
- autocoder/regexproject/__init__.py +3 -2
- autocoder/suffixproject/__init__.py +3 -2
- autocoder/tsproject/__init__.py +3 -2
- autocoder/utils/conversation_store.py +1 -1
- autocoder/utils/operate_config_api.py +3 -3
- autocoder/utils/project_structure.py +258 -3
- autocoder/utils/thread_utils.py +6 -1
- autocoder/version.py +1 -1
- {auto_coder-0.1.263.dist-info → auto_coder-0.1.265.dist-info}/LICENSE +0 -0
- {auto_coder-0.1.263.dist-info → auto_coder-0.1.265.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.263.dist-info → auto_coder-0.1.265.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.263.dist-info → auto_coder-0.1.265.dist-info}/top_level.txt +0 -0
|
@@ -138,6 +138,11 @@ class CommandConfig(BaseModel):
|
|
|
138
138
|
lib: SkipValidation[Callable]
|
|
139
139
|
execute_shell_command: SkipValidation[Callable]
|
|
140
140
|
generate_shell_command: SkipValidation[Callable]
|
|
141
|
+
conf_export: SkipValidation[Callable]
|
|
142
|
+
conf_import: SkipValidation[Callable]
|
|
143
|
+
index_export: SkipValidation[Callable]
|
|
144
|
+
index_import: SkipValidation[Callable]
|
|
145
|
+
exclude_files: SkipValidation[Callable]
|
|
141
146
|
|
|
142
147
|
|
|
143
148
|
|
|
@@ -298,6 +303,7 @@ class CommandAutoTuner:
|
|
|
298
303
|
try:
|
|
299
304
|
response = to_model(content, AutoCommandResponse)
|
|
300
305
|
if response.suggestions:
|
|
306
|
+
print(response)
|
|
301
307
|
command = response.suggestions[0].command
|
|
302
308
|
parameters = response.suggestions[0].parameters
|
|
303
309
|
if parameters:
|
|
@@ -306,9 +312,9 @@ class CommandAutoTuner:
|
|
|
306
312
|
params_str = ""
|
|
307
313
|
return f"{command}({params_str})"
|
|
308
314
|
else:
|
|
309
|
-
return printer.get_message_from_key("satisfied_prompt"
|
|
310
|
-
except Exception as e:
|
|
311
|
-
logger.error(f"Error extracting command response: {e}")
|
|
315
|
+
return printer.get_message_from_key("satisfied_prompt")
|
|
316
|
+
except Exception as e:
|
|
317
|
+
logger.error(f"Error extracting command response: {str(e)}")
|
|
312
318
|
return content
|
|
313
319
|
|
|
314
320
|
model_name = ",".join(llms_utils.get_llm_names(self.llm))
|
|
@@ -1111,7 +1117,72 @@ class CommandAutoTuner:
|
|
|
1111
1117
|
</usage>
|
|
1112
1118
|
</command>
|
|
1113
1119
|
|
|
1114
|
-
|
|
1120
|
+
<command>
|
|
1121
|
+
<name>conf_export</name>
|
|
1122
|
+
<description>配置管理命令,用于管理和控制配置。</description>
|
|
1123
|
+
<usage>
|
|
1124
|
+
该命令导出当前软件的配置,并保存到指定路径。
|
|
1125
|
+
|
|
1126
|
+
使用例子:
|
|
1127
|
+
conf_export(path="导出路径,通常是.json文件")
|
|
1128
|
+
|
|
1129
|
+
</usage>
|
|
1130
|
+
</command>
|
|
1131
|
+
|
|
1132
|
+
<command>
|
|
1133
|
+
<name>conf_import</name>
|
|
1134
|
+
<description>配置管理命令,用于管理和控制配置。</description>
|
|
1135
|
+
<usage>
|
|
1136
|
+
该命令导入指定路径的配置文件到当前软件。
|
|
1137
|
+
|
|
1138
|
+
使用例子:
|
|
1139
|
+
conf_import(path="导入路径,通常是.json文件")
|
|
1140
|
+
|
|
1141
|
+
</usage>
|
|
1142
|
+
</command>
|
|
1143
|
+
|
|
1144
|
+
<command>
|
|
1145
|
+
<name>index_export</name>
|
|
1146
|
+
<description>索引管理命令,用于管理和控制索引。</description>
|
|
1147
|
+
<usage>
|
|
1148
|
+
该命令导出当前软件的索引,并保存到指定路径。
|
|
1149
|
+
|
|
1150
|
+
使用例子:
|
|
1151
|
+
index_export(path="导出路径,通常是.json文件")
|
|
1152
|
+
|
|
1153
|
+
</usage>
|
|
1154
|
+
</command>
|
|
1155
|
+
|
|
1156
|
+
<command>
|
|
1157
|
+
<name>index_import</name>
|
|
1158
|
+
<description>索引管理命令,用于管理和控制索引。</description>
|
|
1159
|
+
<usage>
|
|
1160
|
+
该命令导入指定路径的索引文件到当前软件。
|
|
1161
|
+
|
|
1162
|
+
使用例子:
|
|
1163
|
+
index_import(path="导入路径,通常最后是.json文件")
|
|
1164
|
+
|
|
1165
|
+
</usage>
|
|
1166
|
+
</command>
|
|
1167
|
+
|
|
1168
|
+
<command>
|
|
1169
|
+
<name>exclude_files</name>
|
|
1170
|
+
<description>排除指定文件。</description>
|
|
1171
|
+
<usage>
|
|
1172
|
+
该命令接受一个参数 file_patterns, 为要排除的文件模式字符串列表。
|
|
1173
|
+
|
|
1174
|
+
使用例子,比如你想要排除 package-lock.json 文件,你可以这样调用:
|
|
1175
|
+
|
|
1176
|
+
exclude_files(file_patterns=["regex://.*/package-lock\.json"])
|
|
1177
|
+
|
|
1178
|
+
注意:
|
|
1179
|
+
- 文件模式字符串必须以 regex:// 开头
|
|
1180
|
+
- regex:// 后面部分是标准的正则表达式
|
|
1181
|
+
</usage>
|
|
1182
|
+
</command>
|
|
1183
|
+
</commands>
|
|
1184
|
+
|
|
1185
|
+
|
|
1115
1186
|
'''
|
|
1116
1187
|
|
|
1117
1188
|
def execute_auto_command(self, command: str, parameters: Dict[str, Any]) -> None:
|
|
@@ -1135,6 +1206,11 @@ class CommandAutoTuner:
|
|
|
1135
1206
|
"models": self.command_config.models,
|
|
1136
1207
|
"execute_shell_command": self.command_config.execute_shell_command,
|
|
1137
1208
|
"generate_shell_command": self.command_config.generate_shell_command,
|
|
1209
|
+
"conf_export": self.command_config.conf_export,
|
|
1210
|
+
"conf_import": self.command_config.conf_import,
|
|
1211
|
+
"index_export": self.command_config.index_export,
|
|
1212
|
+
"index_import": self.command_config.index_import,
|
|
1213
|
+
"exclude_files": self.command_config.exclude_files,
|
|
1138
1214
|
|
|
1139
1215
|
"run_python": self.tools.run_python_code,
|
|
1140
1216
|
"get_related_files_by_symbols": self.tools.get_related_files_by_symbols,
|
|
@@ -1146,6 +1222,7 @@ class CommandAutoTuner:
|
|
|
1146
1222
|
"get_project_related_files": self.tools.get_project_related_files,
|
|
1147
1223
|
"ask_user":self.tools.ask_user,
|
|
1148
1224
|
"read_file_with_keyword_ranges": self.tools.read_file_with_keyword_ranges,
|
|
1225
|
+
|
|
1149
1226
|
|
|
1150
1227
|
|
|
1151
1228
|
}
|
autocoder/commands/tools.py
CHANGED
|
@@ -27,6 +27,7 @@ from autocoder.utils.queue_communicate import (
|
|
|
27
27
|
)
|
|
28
28
|
import sys
|
|
29
29
|
import io
|
|
30
|
+
from autocoder.common import files as files_utils
|
|
30
31
|
|
|
31
32
|
@byzerllm.prompt()
|
|
32
33
|
def detect_rm_command(command: str) -> Bool:
|
|
@@ -286,34 +287,33 @@ class AutoCommandTools:
|
|
|
286
287
|
|
|
287
288
|
result = []
|
|
288
289
|
try:
|
|
289
|
-
|
|
290
|
-
|
|
290
|
+
|
|
291
|
+
lines = files_utils.read_lines(absolute_path)
|
|
292
|
+
# Find all lines containing the keyword
|
|
293
|
+
keyword_lines = []
|
|
294
|
+
for i, line in enumerate(lines):
|
|
295
|
+
if keyword.lower() in line.lower():
|
|
296
|
+
keyword_lines.append(i)
|
|
297
|
+
|
|
298
|
+
# Process each keyword line and its surrounding range
|
|
299
|
+
processed_ranges = set()
|
|
300
|
+
for line_num in keyword_lines:
|
|
301
|
+
# Calculate range boundaries
|
|
302
|
+
start = max(0, line_num - before_size)
|
|
303
|
+
end = min(len(lines), line_num + after_size + 1)
|
|
291
304
|
|
|
292
|
-
#
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
keyword_lines.append(i)
|
|
305
|
+
# Check if this range overlaps with any previously processed range
|
|
306
|
+
range_key = (start, end)
|
|
307
|
+
if range_key in processed_ranges:
|
|
308
|
+
continue
|
|
297
309
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
# Check if this range overlaps with any previously processed range
|
|
306
|
-
range_key = (start, end)
|
|
307
|
-
if range_key in processed_ranges:
|
|
308
|
-
continue
|
|
309
|
-
|
|
310
|
-
processed_ranges.add(range_key)
|
|
311
|
-
|
|
312
|
-
# Format the content block
|
|
313
|
-
content = f"##File: {absolute_path}\n"
|
|
314
|
-
content += f"##Line: {start+1}-{end}\n\n"
|
|
315
|
-
content += "".join(lines[start:end])
|
|
316
|
-
result.append(content)
|
|
310
|
+
processed_ranges.add(range_key)
|
|
311
|
+
|
|
312
|
+
# Format the content block
|
|
313
|
+
content = f"##File: {absolute_path}\n"
|
|
314
|
+
content += f"##Line: {start+1}-{end}\n\n"
|
|
315
|
+
content += "".join(lines[start:end])
|
|
316
|
+
result.append(content)
|
|
317
317
|
|
|
318
318
|
except Exception as e:
|
|
319
319
|
v = f"Error reading file {absolute_path}: {str(e)}"
|
|
@@ -403,23 +403,22 @@ class AutoCommandTools:
|
|
|
403
403
|
if path in os.path.join(root, file):
|
|
404
404
|
absolute_path = os.path.join(root, file)
|
|
405
405
|
break
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
source_code = f"##File: {absolute_path}\n\n{content}"
|
|
406
|
+
|
|
407
|
+
if path in file_line_ranges:
|
|
408
|
+
# Read specific line ranges
|
|
409
|
+
lines = files_utils.read_lines(absolute_path)
|
|
410
|
+
filtered_lines = []
|
|
411
|
+
for start, end in file_line_ranges[path]:
|
|
412
|
+
# Adjust for 0-based indexing
|
|
413
|
+
start = max(0, start - 1)
|
|
414
|
+
end = min(len(lines), end)
|
|
415
|
+
content = "".join(lines[start:end])
|
|
416
|
+
filtered_lines.extend(f"##File: {absolute_path}\n##Line: {start}-{end}\n\n{content}")
|
|
417
|
+
source_code = "".join(filtered_lines)
|
|
418
|
+
else:
|
|
419
|
+
# Read entire file if no range specified
|
|
420
|
+
content = files_utils.read_file(absolute_path)
|
|
421
|
+
source_code = f"##File: {absolute_path}\n\n{content}"
|
|
423
422
|
|
|
424
423
|
sc = SourceCode(module_name=absolute_path, source_code=source_code)
|
|
425
424
|
source_code_str += f"{sc.source_code}\n\n"
|
|
@@ -510,13 +509,12 @@ class AutoCommandTools:
|
|
|
510
509
|
for file in files:
|
|
511
510
|
file_path = os.path.join(root, file)
|
|
512
511
|
try:
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
break
|
|
512
|
+
content = files_utils.read_file(file_path)
|
|
513
|
+
if keyword.lower() in content.lower():
|
|
514
|
+
matched_files.append(file_path)
|
|
515
|
+
# Limit to first 10 matches
|
|
516
|
+
if len(matched_files) >= 10:
|
|
517
|
+
break
|
|
520
518
|
except Exception:
|
|
521
519
|
# Skip files that can't be read
|
|
522
520
|
pass
|
autocoder/common/__init__.py
CHANGED
|
@@ -6,7 +6,6 @@ import os
|
|
|
6
6
|
import time
|
|
7
7
|
from typing import List, Dict, Any, Optional, Union
|
|
8
8
|
|
|
9
|
-
|
|
10
9
|
class SourceCode(pydantic.BaseModel):
|
|
11
10
|
module_name: str
|
|
12
11
|
source_code: str
|
|
@@ -359,6 +358,9 @@ class AutoCoderArgs(pydantic.BaseModel):
|
|
|
359
358
|
data_cells_max_num: Optional[int] = 2000
|
|
360
359
|
generate_times_same_model: Optional[int] = 1
|
|
361
360
|
rank_times_same_model: Optional[int] = 1
|
|
361
|
+
|
|
362
|
+
# block:给定每个文件修改的代码块 file: 给定每个文件修改前后内容
|
|
363
|
+
rank_strategy: Optional[str] = "file"
|
|
362
364
|
|
|
363
365
|
action: List[str] = []
|
|
364
366
|
enable_global_memory: Optional[bool] = True
|
|
@@ -374,6 +376,9 @@ class AutoCoderArgs(pydantic.BaseModel):
|
|
|
374
376
|
conversation_prune_group_size: Optional[int] = 4
|
|
375
377
|
conversation_prune_strategy: Optional[str] = "summarize"
|
|
376
378
|
|
|
379
|
+
context_prune_strategy: Optional[str] = "score"
|
|
380
|
+
context_prune: Optional[bool] = True
|
|
381
|
+
|
|
377
382
|
auto_command_max_iterations: Optional[int] = 10
|
|
378
383
|
|
|
379
384
|
skip_commit: Optional[bool] = False
|
|
@@ -3,6 +3,7 @@ from byzerllm.utils import format_str_jinja2
|
|
|
3
3
|
|
|
4
4
|
MESSAGES = {
|
|
5
5
|
"en": {
|
|
6
|
+
"invalid_file_pattern": "Invalid file pattern: {{file_pattern}}. e.g. regex://.*/package-lock\\.json",
|
|
6
7
|
"config_validation_error": "Config validation error: {{error}}",
|
|
7
8
|
"invalid_boolean_value": "Value '{{value}}' is not a valid boolean(true/false)",
|
|
8
9
|
"invalid_integer_value": "Value '{{value}}' is not a valid integer",
|
|
@@ -137,9 +138,42 @@ MESSAGES = {
|
|
|
137
138
|
"invalid_enum_value": "Value '{{value}}' is not in allowed values ({{allowed}})",
|
|
138
139
|
"no_changes_made": "⚠️ no changes made, the reason may be that the text block generated by the coding function has a problem, so it cannot be merged into the project",
|
|
139
140
|
"conversation_pruning_start": "⚠️ Conversation pruning started, total tokens: {{total_tokens}}, safe zone: {{safe_zone}}",
|
|
140
|
-
"invalid_file_number": "⚠️ Invalid file number {{file_number}}, total files: {{total_files}}"
|
|
141
|
-
|
|
141
|
+
"invalid_file_number": "⚠️ Invalid file number {{file_number}}, total files: {{total_files}}",
|
|
142
|
+
"all_merge_results_failed": "⚠️ All merge attempts failed, returning first candidate",
|
|
143
|
+
"only_one_merge_result_success": "✅ Only one merge result succeeded, returning that candidate",
|
|
144
|
+
"conf_import_success": "Successfully imported configuration: {{path}}",
|
|
145
|
+
"conf_export_success": "Successfully exported configuration: {{path}}",
|
|
146
|
+
"conf_import_error": "Error importing configuration: {{error}}",
|
|
147
|
+
"conf_export_error": "Error exporting configuration: {{error}}",
|
|
148
|
+
"conf_import_invalid_format": "Invalid import configuration format, expected 'key:value'",
|
|
149
|
+
"conf_export_invalid_format": "Invalid export configuration format, expected 'key:value'",
|
|
150
|
+
"conf_import_file_not_found": "Import configuration file not found: {{file_path}}",
|
|
151
|
+
"conf_export_file_not_found": "Export configuration file not found: {{file_path}}",
|
|
152
|
+
"conf_import_file_empty": "Import configuration file is empty: {{file_path}}",
|
|
153
|
+
"conf_export_file_empty": "Export configuration file is empty: {{file_path}}",
|
|
154
|
+
"generated_shell_script": "Generated Shell Script",
|
|
155
|
+
"confirm_execute_shell_script": "Do you want to execute this shell script?",
|
|
156
|
+
"shell_script_not_executed": "Shell script was not executed",
|
|
157
|
+
"conf_not_found": "Configuration file not found: {{path}}",
|
|
158
|
+
"index_export_success": "Index exported successfully: {{path}}",
|
|
159
|
+
"index_import_success": "Index imported successfully: {{path}}",
|
|
160
|
+
},
|
|
142
161
|
"zh": {
|
|
162
|
+
"invalid_file_pattern": "无效的文件模式: {{file_pattern}}. 例如: regex://.*/package-lock\\.json",
|
|
163
|
+
"conf_not_found": "未找到配置文件: {{path}}",
|
|
164
|
+
"conf_import_success": "成功导入配置: {{path}}",
|
|
165
|
+
"conf_export_success": "成功导出配置: {{path}}",
|
|
166
|
+
"conf_import_error": "导入配置出错: {{error}}",
|
|
167
|
+
"conf_export_error": "导出配置出错: {{error}}",
|
|
168
|
+
"conf_import_invalid_format": "导入配置格式无效, 应为 'key:value' 格式",
|
|
169
|
+
"conf_export_invalid_format": "导出配置格式无效, 应为 'key:value' 格式",
|
|
170
|
+
"conf_import_file_not_found": "未找到导入配置文件: {{file_path}}",
|
|
171
|
+
"conf_export_file_not_found": "未找到导出配置文件: {{file_path}}",
|
|
172
|
+
"conf_import_file_empty": "导入配置文件为空: {{file_path}}",
|
|
173
|
+
"conf_export_file_empty": "导出配置文件为空: {{file_path}}",
|
|
174
|
+
"generated_shell_script": "生成的 Shell 脚本",
|
|
175
|
+
"confirm_execute_shell_script": "您要执行此 shell 脚本吗?",
|
|
176
|
+
"shell_script_not_executed": "Shell 脚本未执行",
|
|
143
177
|
"config_validation_error": "配置验证错误: {{error}}",
|
|
144
178
|
"invalid_boolean_value": "值 '{{value}}' 不是有效的布尔值(true/false)",
|
|
145
179
|
"invalid_integer_value": "值 '{{value}}' 不是有效的整数",
|
|
@@ -272,7 +306,11 @@ MESSAGES = {
|
|
|
272
306
|
"auto_command_analyzed": "被选择指令",
|
|
273
307
|
"invalid_enum_value": "值 '{{value}}' 不在允许的值列表中 ({{allowed}})",
|
|
274
308
|
"conversation_pruning_start": "⚠️ 对话长度 {{total_tokens}} tokens 超过安全阈值 {{safe_zone}},开始修剪对话。",
|
|
275
|
-
"invalid_file_number": "⚠️ 无效的文件编号 {{file_number}},总文件数为 {{total_files}}"
|
|
309
|
+
"invalid_file_number": "⚠️ 无效的文件编号 {{file_number}},总文件数为 {{total_files}}",
|
|
310
|
+
"all_merge_results_failed": "⚠️ 所有合并尝试都失败,返回第一个候选",
|
|
311
|
+
"only_one_merge_result_success": "✅ 只有一个合并结果成功,返回该候选",
|
|
312
|
+
"index_export_success": "索引导出成功: {{path}}",
|
|
313
|
+
"index_import_success": "索引导入成功: {{path}}",
|
|
276
314
|
}}
|
|
277
315
|
|
|
278
316
|
|
|
@@ -197,7 +197,7 @@ class CodeAutoGenerate:
|
|
|
197
197
|
instruction=query, content=source_content
|
|
198
198
|
)
|
|
199
199
|
|
|
200
|
-
with open(self.args.target_file, "w") as file:
|
|
200
|
+
with open(self.args.target_file, "w",encoding="utf-8") as file:
|
|
201
201
|
file.write(init_prompt)
|
|
202
202
|
|
|
203
203
|
conversations = []
|
|
@@ -298,7 +298,7 @@ class CodeAutoGenerate:
|
|
|
298
298
|
|
|
299
299
|
conversations = [{"role": "user", "content": init_prompt}]
|
|
300
300
|
|
|
301
|
-
with open(self.args.target_file, "w") as file:
|
|
301
|
+
with open(self.args.target_file, "w",encoding="utf-8") as file:
|
|
302
302
|
file.write(init_prompt)
|
|
303
303
|
|
|
304
304
|
t = self.llm.chat_oai(conversations=conversations, llm_config=llm_config)
|
|
@@ -320,7 +320,7 @@ class CodeAutoGenerate:
|
|
|
320
320
|
|
|
321
321
|
conversations.append({"role": "user", "content": "继续"})
|
|
322
322
|
|
|
323
|
-
with open(self.args.target_file, "w") as file:
|
|
323
|
+
with open(self.args.target_file, "w",encoding="utf-8") as file:
|
|
324
324
|
file.write("继续")
|
|
325
325
|
|
|
326
326
|
t = self.llm.chat_oai(conversations=conversations, llm_config=llm_config)
|
|
@@ -315,10 +315,7 @@ class CodeAutoGenerateDiff:
|
|
|
315
315
|
elif self.args.template == "auto_implement":
|
|
316
316
|
init_prompt = self.auto_implement_function.prompt(
|
|
317
317
|
instruction=query, content=source_content
|
|
318
|
-
)
|
|
319
|
-
|
|
320
|
-
with open(self.args.target_file, "w") as file:
|
|
321
|
-
file.write(init_prompt)
|
|
318
|
+
)
|
|
322
319
|
|
|
323
320
|
conversations = []
|
|
324
321
|
|
|
@@ -359,16 +356,16 @@ class CodeAutoGenerateDiff:
|
|
|
359
356
|
with ThreadPoolExecutor(max_workers=len(self.llms) * self.generate_times_same_model) as executor:
|
|
360
357
|
futures = []
|
|
361
358
|
for llm in self.llms:
|
|
359
|
+
|
|
360
|
+
model_names_list = llm_utils.get_llm_names(llm)
|
|
361
|
+
model_name = None
|
|
362
|
+
if model_names_list:
|
|
363
|
+
model_name = model_names_list[0]
|
|
364
|
+
|
|
362
365
|
for _ in range(self.generate_times_same_model):
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
model_name = model_names_list[0]
|
|
367
|
-
|
|
368
|
-
for _ in range(self.generate_times_same_model):
|
|
369
|
-
model_names.append(model_name)
|
|
370
|
-
futures.append(executor.submit(
|
|
371
|
-
chat_with_continue, llm=llm, conversations=conversations, llm_config=llm_config))
|
|
366
|
+
model_names.append(model_name)
|
|
367
|
+
futures.append(executor.submit(
|
|
368
|
+
chat_with_continue, llm=llm, conversations=conversations, llm_config=llm_config))
|
|
372
369
|
|
|
373
370
|
temp_results = [future.result() for future in futures]
|
|
374
371
|
for result in temp_results:
|
|
@@ -447,7 +444,7 @@ class CodeAutoGenerateDiff:
|
|
|
447
444
|
# conversations.append({"role": "system", "content": sys_prompt.prompt()})
|
|
448
445
|
conversations.append({"role": "user", "content": init_prompt})
|
|
449
446
|
|
|
450
|
-
with open(self.args.target_file, "w") as file:
|
|
447
|
+
with open(self.args.target_file, "w",encoding="utf-8") as file:
|
|
451
448
|
file.write(init_prompt)
|
|
452
449
|
|
|
453
450
|
code_llm = self.llms[0]
|
|
@@ -467,7 +464,7 @@ class CodeAutoGenerateDiff:
|
|
|
467
464
|
|
|
468
465
|
conversations.append({"role": "user", "content": "继续"})
|
|
469
466
|
|
|
470
|
-
with open(self.args.target_file, "w") as file:
|
|
467
|
+
with open(self.args.target_file, "w",encoding="utf-8") as file:
|
|
471
468
|
file.write("继续")
|
|
472
469
|
|
|
473
470
|
t = code_llm.chat_oai(
|
|
@@ -418,7 +418,7 @@ class CodeAutoGenerateEditBlock:
|
|
|
418
418
|
instruction=query, content=source_content
|
|
419
419
|
)
|
|
420
420
|
|
|
421
|
-
with open(self.args.target_file, "w") as file:
|
|
421
|
+
with open(self.args.target_file, "w",encoding="utf-8") as file:
|
|
422
422
|
file.write(init_prompt)
|
|
423
423
|
|
|
424
424
|
conversations = []
|
|
@@ -538,7 +538,7 @@ class CodeAutoGenerateEditBlock:
|
|
|
538
538
|
# conversations.append({"role": "system", "content": sys_prompt.prompt()})
|
|
539
539
|
conversations.append({"role": "user", "content": init_prompt})
|
|
540
540
|
|
|
541
|
-
with open(self.args.target_file, "w") as file:
|
|
541
|
+
with open(self.args.target_file, "w",encoding="utf-8") as file:
|
|
542
542
|
file.write(init_prompt)
|
|
543
543
|
|
|
544
544
|
code_llm = self.llms[0]
|
|
@@ -558,7 +558,7 @@ class CodeAutoGenerateEditBlock:
|
|
|
558
558
|
|
|
559
559
|
conversations.append({"role": "user", "content": "继续"})
|
|
560
560
|
|
|
561
|
-
with open(self.args.target_file, "w") as file:
|
|
561
|
+
with open(self.args.target_file, "w",encoding="utf-8") as file:
|
|
562
562
|
file.write("继续")
|
|
563
563
|
|
|
564
564
|
t = code_llm.chat_oai(
|
|
@@ -287,7 +287,7 @@ class CodeAutoGenerateStrictDiff:
|
|
|
287
287
|
instruction=query, content=source_content
|
|
288
288
|
)
|
|
289
289
|
|
|
290
|
-
with open(self.args.target_file, "w") as file:
|
|
290
|
+
with open(self.args.target_file, "w",encoding="utf-8") as file:
|
|
291
291
|
file.write(init_prompt)
|
|
292
292
|
|
|
293
293
|
conversations = []
|
|
@@ -417,7 +417,7 @@ class CodeAutoGenerateStrictDiff:
|
|
|
417
417
|
# conversations.append({"role": "system", "content": sys_prompt.prompt()})
|
|
418
418
|
conversations.append({"role": "user", "content": init_prompt})
|
|
419
419
|
|
|
420
|
-
with open(self.args.target_file, "w") as file:
|
|
420
|
+
with open(self.args.target_file, "w",encoding="utf-8") as file:
|
|
421
421
|
file.write(init_prompt)
|
|
422
422
|
|
|
423
423
|
code_llm = self.llms[0]
|
|
@@ -437,7 +437,7 @@ class CodeAutoGenerateStrictDiff:
|
|
|
437
437
|
|
|
438
438
|
conversations.append({"role": "user", "content": "继续"})
|
|
439
439
|
|
|
440
|
-
with open(self.args.target_file, "w") as file:
|
|
440
|
+
with open(self.args.target_file, "w",encoding="utf-8") as file:
|
|
441
441
|
file.write("继续")
|
|
442
442
|
|
|
443
443
|
t = code_llm.chat_oai(
|
|
@@ -73,15 +73,35 @@ class CodeAutoMerge:
|
|
|
73
73
|
def choose_best_choice(self, generate_result: CodeGenerateResult) -> CodeGenerateResult:
|
|
74
74
|
if len(generate_result.contents) == 1:
|
|
75
75
|
return generate_result
|
|
76
|
+
|
|
77
|
+
merge_results = []
|
|
78
|
+
for content,conversations in zip(generate_result.contents,generate_result.conversations):
|
|
79
|
+
merge_result = self._merge_code_without_effect(content)
|
|
80
|
+
merge_results.append(merge_result)
|
|
76
81
|
|
|
82
|
+
# If all merge results are None, return first one
|
|
83
|
+
if all(len(result.failed_blocks) != 0 for result in merge_results):
|
|
84
|
+
self.printer.print_in_terminal("all_merge_results_failed")
|
|
85
|
+
return CodeGenerateResult(contents=[generate_result.contents[0]], conversations=[generate_result.conversations[0]])
|
|
86
|
+
|
|
87
|
+
# If only one merge result is not None, return that one
|
|
88
|
+
not_none_indices = [i for i, result in enumerate(merge_results) if len(result.failed_blocks) == 0]
|
|
89
|
+
if len(not_none_indices) == 1:
|
|
90
|
+
idx = not_none_indices[0]
|
|
91
|
+
self.printer.print_in_terminal("only_one_merge_result_success")
|
|
92
|
+
return CodeGenerateResult(contents=[generate_result.contents[idx]], conversations=[generate_result.conversations[idx]])
|
|
93
|
+
|
|
94
|
+
# 最后,如果有多个,那么根据质量排序再返回
|
|
77
95
|
ranker = CodeModificationRanker(self.llm, self.args)
|
|
78
|
-
ranked_result = ranker.rank_modifications(generate_result)
|
|
79
|
-
|
|
96
|
+
ranked_result = ranker.rank_modifications(generate_result,merge_results)
|
|
97
|
+
|
|
98
|
+
## 得到的结果,再做一次合并,第一个通过的返回 , 返回做合并有点重复低效,未来修改。
|
|
80
99
|
for content,conversations in zip(ranked_result.contents,ranked_result.conversations):
|
|
81
100
|
merge_result = self._merge_code_without_effect(content)
|
|
82
101
|
if not merge_result.failed_blocks:
|
|
83
102
|
return CodeGenerateResult(contents=[content], conversations=[conversations])
|
|
84
|
-
|
|
103
|
+
|
|
104
|
+
# 最后保底,但实际不会出现
|
|
85
105
|
return CodeGenerateResult(contents=[ranked_result.contents[0]], conversations=[ranked_result.conversations[0]])
|
|
86
106
|
|
|
87
107
|
|
|
@@ -387,15 +387,35 @@ class CodeAutoMergeDiff:
|
|
|
387
387
|
def choose_best_choice(self, generate_result: CodeGenerateResult) -> CodeGenerateResult:
|
|
388
388
|
if len(generate_result.contents) == 1:
|
|
389
389
|
return generate_result
|
|
390
|
+
|
|
391
|
+
merge_results = []
|
|
392
|
+
for content,conversations in zip(generate_result.contents,generate_result.conversations):
|
|
393
|
+
merge_result = self._merge_code_without_effect(content)
|
|
394
|
+
merge_results.append(merge_result)
|
|
390
395
|
|
|
396
|
+
# If all merge results are None, return first one
|
|
397
|
+
if all(len(result.failed_blocks) != 0 for result in merge_results):
|
|
398
|
+
self.printer.print_in_terminal("all_merge_results_failed")
|
|
399
|
+
return CodeGenerateResult(contents=[generate_result.contents[0]], conversations=[generate_result.conversations[0]])
|
|
400
|
+
|
|
401
|
+
# If only one merge result is not None, return that one
|
|
402
|
+
not_none_indices = [i for i, result in enumerate(merge_results) if len(result.failed_blocks) == 0]
|
|
403
|
+
if len(not_none_indices) == 1:
|
|
404
|
+
idx = not_none_indices[0]
|
|
405
|
+
self.printer.print_in_terminal("only_one_merge_result_success")
|
|
406
|
+
return CodeGenerateResult(contents=[generate_result.contents[idx]], conversations=[generate_result.conversations[idx]])
|
|
407
|
+
|
|
408
|
+
# 最后,如果有多个,那么根据质量排序再返回
|
|
391
409
|
ranker = CodeModificationRanker(self.llm, self.args)
|
|
392
|
-
ranked_result = ranker.rank_modifications(generate_result)
|
|
393
|
-
|
|
410
|
+
ranked_result = ranker.rank_modifications(generate_result,merge_results)
|
|
411
|
+
|
|
412
|
+
## 得到的结果,再做一次合并,第一个通过的返回 , 返回做合并有点重复低效,未来修改。
|
|
394
413
|
for content,conversations in zip(ranked_result.contents,ranked_result.conversations):
|
|
395
414
|
merge_result = self._merge_code_without_effect(content)
|
|
396
415
|
if not merge_result.failed_blocks:
|
|
397
416
|
return CodeGenerateResult(contents=[content], conversations=[conversations])
|
|
398
|
-
|
|
417
|
+
|
|
418
|
+
# 最后保底,但实际不会出现
|
|
399
419
|
return CodeGenerateResult(contents=[ranked_result.contents[0]], conversations=[ranked_result.conversations[0]])
|
|
400
420
|
|
|
401
421
|
@byzerllm.prompt(render="jinja2")
|
|
@@ -440,6 +460,11 @@ class CodeAutoMergeDiff:
|
|
|
440
460
|
errors = []
|
|
441
461
|
for path, hunk in uniq:
|
|
442
462
|
full_path = self.abs_root_path(path)
|
|
463
|
+
|
|
464
|
+
if not os.path.exists(full_path):
|
|
465
|
+
with open(full_path, "w") as f:
|
|
466
|
+
f.write("")
|
|
467
|
+
|
|
443
468
|
content = FileUtils.read_file(full_path)
|
|
444
469
|
|
|
445
470
|
original, _ = hunk_to_before_after(hunk)
|
|
@@ -506,7 +531,7 @@ class CodeAutoMergeDiff:
|
|
|
506
531
|
def _merge_code(self, content: str,force_skip_git:bool=False):
|
|
507
532
|
total = 0
|
|
508
533
|
|
|
509
|
-
file_content =
|
|
534
|
+
file_content = FileUtils.read_file(self.args.file)
|
|
510
535
|
md5 = hashlib.md5(file_content.encode('utf-8')).hexdigest()
|
|
511
536
|
# get the file name
|
|
512
537
|
file_name = os.path.basename(self.args.file)
|
|
@@ -164,15 +164,35 @@ class CodeAutoMergeEditBlock:
|
|
|
164
164
|
def choose_best_choice(self, generate_result: CodeGenerateResult) -> CodeGenerateResult:
|
|
165
165
|
if len(generate_result.contents) == 1:
|
|
166
166
|
return generate_result
|
|
167
|
-
|
|
167
|
+
|
|
168
|
+
merge_results = []
|
|
169
|
+
for content,conversations in zip(generate_result.contents,generate_result.conversations):
|
|
170
|
+
merge_result = self._merge_code_without_effect(content)
|
|
171
|
+
merge_results.append(merge_result)
|
|
172
|
+
|
|
173
|
+
# If all merge results are None, return first one
|
|
174
|
+
if all(len(result.failed_blocks) != 0 for result in merge_results):
|
|
175
|
+
self.printer.print_in_terminal("all_merge_results_failed")
|
|
176
|
+
return CodeGenerateResult(contents=[generate_result.contents[0]], conversations=[generate_result.conversations[0]])
|
|
177
|
+
|
|
178
|
+
# If only one merge result is not None, return that one
|
|
179
|
+
not_none_indices = [i for i, result in enumerate(merge_results) if len(result.failed_blocks) == 0]
|
|
180
|
+
if len(not_none_indices) == 1:
|
|
181
|
+
idx = not_none_indices[0]
|
|
182
|
+
self.printer.print_in_terminal("only_one_merge_result_success")
|
|
183
|
+
return CodeGenerateResult(contents=[generate_result.contents[idx]], conversations=[generate_result.conversations[idx]])
|
|
184
|
+
|
|
185
|
+
# 最后,如果有多个,那么根据质量排序再返回
|
|
168
186
|
ranker = CodeModificationRanker(self.llm, self.args)
|
|
169
|
-
ranked_result = ranker.rank_modifications(generate_result)
|
|
170
|
-
|
|
187
|
+
ranked_result = ranker.rank_modifications(generate_result,merge_results)
|
|
188
|
+
|
|
189
|
+
## 得到的结果,再做一次合并,第一个通过的返回 , 返回做合并有点重复低效,未来修改。
|
|
171
190
|
for content,conversations in zip(ranked_result.contents,ranked_result.conversations):
|
|
172
191
|
merge_result = self._merge_code_without_effect(content)
|
|
173
192
|
if not merge_result.failed_blocks:
|
|
174
193
|
return CodeGenerateResult(contents=[content], conversations=[conversations])
|
|
175
|
-
|
|
194
|
+
|
|
195
|
+
# 最后保底,但实际不会出现
|
|
176
196
|
return CodeGenerateResult(contents=[ranked_result.contents[0]], conversations=[ranked_result.conversations[0]])
|
|
177
197
|
|
|
178
198
|
@byzerllm.prompt()
|
|
@@ -269,7 +289,7 @@ class CodeAutoMergeEditBlock:
|
|
|
269
289
|
)
|
|
270
290
|
|
|
271
291
|
def _merge_code(self, content: str, force_skip_git: bool = False):
|
|
272
|
-
file_content =
|
|
292
|
+
file_content = FileUtils.read_file(self.args.file)
|
|
273
293
|
md5 = hashlib.md5(file_content.encode("utf-8")).hexdigest()
|
|
274
294
|
file_name = os.path.basename(self.args.file)
|
|
275
295
|
|