auto-coder 0.1.330__py3-none-any.whl → 0.1.332__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 (47) hide show
  1. {auto_coder-0.1.330.dist-info → auto_coder-0.1.332.dist-info}/METADATA +1 -1
  2. {auto_coder-0.1.330.dist-info → auto_coder-0.1.332.dist-info}/RECORD +47 -45
  3. autocoder/agent/agentic_filter.py +928 -0
  4. autocoder/agent/project_reader.py +1 -14
  5. autocoder/auto_coder.py +6 -47
  6. autocoder/auto_coder_runner.py +2 -0
  7. autocoder/command_args.py +1 -6
  8. autocoder/commands/auto_command.py +1 -1
  9. autocoder/commands/tools.py +68 -16
  10. autocoder/common/__init__.py +8 -3
  11. autocoder/common/auto_coder_lang.py +21 -1
  12. autocoder/common/code_auto_generate.py +6 -160
  13. autocoder/common/code_auto_generate_diff.py +5 -111
  14. autocoder/common/code_auto_generate_editblock.py +5 -95
  15. autocoder/common/code_auto_generate_strict_diff.py +6 -112
  16. autocoder/common/code_auto_merge_editblock.py +1 -45
  17. autocoder/common/code_modification_ranker.py +6 -2
  18. autocoder/common/command_templates.py +2 -9
  19. autocoder/common/conf_utils.py +36 -0
  20. autocoder/common/stream_out_type.py +7 -2
  21. autocoder/common/types.py +3 -2
  22. autocoder/common/v2/code_auto_generate.py +6 -4
  23. autocoder/common/v2/code_auto_generate_diff.py +4 -3
  24. autocoder/common/v2/code_auto_generate_editblock.py +9 -4
  25. autocoder/common/v2/code_auto_generate_strict_diff.py +182 -14
  26. autocoder/common/v2/code_auto_merge_diff.py +560 -306
  27. autocoder/common/v2/code_auto_merge_editblock.py +12 -45
  28. autocoder/common/v2/code_auto_merge_strict_diff.py +76 -7
  29. autocoder/common/v2/code_diff_manager.py +73 -6
  30. autocoder/common/v2/code_editblock_manager.py +534 -82
  31. autocoder/dispacher/actions/action.py +15 -28
  32. autocoder/dispacher/actions/plugins/action_regex_project.py +5 -9
  33. autocoder/helper/project_creator.py +0 -1
  34. autocoder/index/entry.py +35 -53
  35. autocoder/index/filter/normal_filter.py +0 -16
  36. autocoder/lang.py +2 -4
  37. autocoder/linters/shadow_linter.py +4 -0
  38. autocoder/pyproject/__init__.py +2 -19
  39. autocoder/rag/cache/simple_cache.py +31 -6
  40. autocoder/regexproject/__init__.py +4 -22
  41. autocoder/suffixproject/__init__.py +6 -24
  42. autocoder/tsproject/__init__.py +5 -22
  43. autocoder/version.py +1 -1
  44. {auto_coder-0.1.330.dist-info → auto_coder-0.1.332.dist-info}/LICENSE +0 -0
  45. {auto_coder-0.1.330.dist-info → auto_coder-0.1.332.dist-info}/WHEEL +0 -0
  46. {auto_coder-0.1.330.dist-info → auto_coder-0.1.332.dist-info}/entry_points.txt +0 -0
  47. {auto_coder-0.1.330.dist-info → auto_coder-0.1.332.dist-info}/top_level.txt +0 -0
@@ -1,20 +1,18 @@
1
1
  from typing import List, Dict, Tuple, Optional, Any
2
2
  import os
3
- import json
4
3
  import time
5
- from concurrent.futures import ThreadPoolExecutor
6
4
 
7
5
  import byzerllm
8
- from byzerllm.utils.client import code_utils
9
6
 
10
7
  from autocoder.common.types import Mode, CodeGenerateResult, MergeCodeWithoutEffect
11
- from autocoder.common import AutoCoderArgs, git_utils, SourceCodeList
8
+ from autocoder.common import AutoCoderArgs, SourceCodeList,SourceCode
9
+ from autocoder.common.action_yml_file_manager import ActionYmlFileManager
12
10
  from autocoder.common import sys_prompt
13
11
  from autocoder.compilers.shadow_compiler import ShadowCompiler
14
12
  from autocoder.privacy.model_filter import ModelPathFilter
15
13
  from autocoder.common.utils_code_auto_generate import chat_with_continue, stream_chat_with_continue, ChatWithContinueResult
16
14
  from autocoder.utils.auto_coder_utils.chat_stream_out import stream_out
17
- from autocoder.common.stream_out_type import LintStreamOutType, CompileStreamOutType
15
+ from autocoder.common.stream_out_type import LintStreamOutType, CompileStreamOutType, UnmergedBlocksStreamOutType
18
16
  from autocoder.common.auto_coder_lang import get_message_with_format
19
17
  from autocoder.common.printer import Printer
20
18
  from autocoder.rag.token_counter import count_tokens
@@ -87,7 +85,7 @@ class CodeEditBlockManager:
87
85
  修复上述问题,请确保代码质量问题被解决,同时保持代码的原有功能。
88
86
  请严格遵守*SEARCH/REPLACE block*的格式。
89
87
  """
90
-
88
+ @byzerllm.prompt()
91
89
  def fix_compile_errors(self, query: str, compile_errors: str) -> str:
92
90
  """
93
91
  编译错误:
@@ -104,6 +102,50 @@ class CodeEditBlockManager:
104
102
  请严格遵守*SEARCH/REPLACE block*的格式。
105
103
  """
106
104
 
105
+ @byzerllm.prompt()
106
+ def fix_missing_context(self, query: str, original_code: str, missing_files: str) -> str:
107
+ """
108
+ 下面是你根据格式要求输出的一份修改代码:
109
+ <original_code>
110
+ {{ original_code }}
111
+ </original_code>
112
+
113
+ 我发现你尝试修改以下文件,但这些文件没有在上下文中提供,所以你无法看到它们的内容:
114
+ <missing_files>
115
+ {{ missing_files }}
116
+ </missing_files>
117
+
118
+ 下面是用户原始的需求:
119
+ <user_query_wrapper>
120
+ {{ query }}
121
+ </user_query_wrapper>
122
+
123
+ 我已经将这些文件添加到上下文中,请重新生成代码,确保使用SEARCH/REPLACE格式正确修改这些文件。
124
+ 对于每个文件,请确保SEARCH部分包含文件中的实际内容,而不是空的SEARCH块。
125
+ """
126
+
127
+ @byzerllm.prompt()
128
+ def fix_unmerged_blocks(self, query: str, original_code: str, unmerged_blocks: str) -> str:
129
+ """
130
+
131
+ 下面是你根据格式要求输出的一份修改代码:
132
+ <original_code>
133
+ {{ original_code }}
134
+ </original_code>
135
+
136
+ 但是我发现下面的代码块无法合并:
137
+ <unmerged_blocks>
138
+ {{ unmerged_blocks }}
139
+ </unmerged_blocks>
140
+
141
+ 下面是用户原始的需求:
142
+ <user_query_wrapper>
143
+ {{ query }}
144
+ </user_query_wrapper>
145
+
146
+ 请根据反馈,回顾之前的格式要求,重新生成一份修改代码,确保所有代码块都能够正确合并。
147
+ """
148
+
107
149
  def _create_shadow_files_from_edits(self, generation_result: CodeGenerateResult) -> Dict[str, str]:
108
150
  """
109
151
  从编辑块内容中提取代码并创建临时影子文件用于检查。
@@ -188,24 +230,96 @@ class CodeEditBlockManager:
188
230
 
189
231
  return error_count
190
232
 
191
- def generate_and_fix(self, query: str, source_code_list: SourceCodeList) -> CodeGenerateResult:
233
+ def _fix_missing_context(self, query: str, generation_result: CodeGenerateResult, source_code_list: SourceCodeList) -> CodeGenerateResult:
192
234
  """
193
- 生成代码,运行linter/compile,修复错误,最多尝试指定次数
235
+ 检查是否有空的SEARCH块但目标文件存在,如果有,将文件添加到动态上下文并重新生成代码
194
236
 
195
237
  参数:
196
238
  query (str): 用户查询
239
+ generation_result (CodeGenerateResult): 生成的代码结果
197
240
  source_code_list (SourceCodeList): 源代码列表
198
241
 
199
242
  返回:
200
- CodeGenerateResult: 生成的代码结果
243
+ CodeGenerateResult: 修复后的代码结果
201
244
  """
202
- # 初始代码生成
203
- self.printer.print_in_terminal("generating_initial_code")
245
+ token_cost_calculator = TokenCostCalculator(args=self.args)
246
+
247
+ # 获取编辑块
248
+ codes = self.code_merger.get_edits(generation_result.contents[0])
249
+
250
+ # 检查是否有空的SEARCH块但目标文件存在
251
+ missing_files = []
252
+ for file_path, head, update in codes:
253
+ # 如果SEARCH块为空,检查文件是否存在但不在上下文中
254
+ if not head and os.path.exists(file_path):
255
+ # 检查文件是否已经在上下文中
256
+ in_context = False
257
+ if hasattr(self.args, 'urls') and self.args.urls:
258
+ in_context = file_path in self.args.urls
259
+ if hasattr(self.args, 'dynamic_urls') and self.args.dynamic_urls and not in_context:
260
+ in_context = file_path in self.args.dynamic_urls
261
+
262
+ # 如果文件存在但不在上下文中,添加到缺失文件列表
263
+ if not in_context:
264
+ missing_files.append(file_path)
265
+ # 将文件添加到动态上下文中
266
+ if not hasattr(self.args, 'dynamic_urls'):
267
+ self.args.dynamic_urls = []
268
+ if file_path not in self.args.dynamic_urls:
269
+ self.args.dynamic_urls.append(file_path)
270
+
271
+ # 如果没有缺失文件,直接返回原结果
272
+ if not missing_files:
273
+ return generation_result
274
+
275
+ # 格式化缺失文件列表
276
+ missing_files_text = "\n".join(missing_files)
277
+
278
+ # 打印当前修复状态
279
+ self.printer.print_in_terminal(
280
+ "missing_context_attempt_status",
281
+ style="yellow",
282
+ missing_files=missing_files_text
283
+ )
284
+
285
+ # 更新源代码列表,包含新添加的文件
286
+ updated_source_code_list = SourceCodeList([])
287
+ for source in source_code_list.sources:
288
+ updated_source_code_list.sources.append(source)
289
+
290
+ # 添加缺失的文件到源代码列表
291
+ for file_path in missing_files:
292
+ if os.path.exists(file_path):
293
+ with open(file_path, 'r') as f:
294
+ file_content = f.read()
295
+ source = SourceCode(module_name=file_path, source_code=file_content)
296
+ updated_source_code_list.sources.append(source)
297
+
298
+ # 更新action yml文件
299
+ if missing_files and hasattr(self.args, 'dynamic_urls') and self.args.dynamic_urls:
300
+ action_yml_file_manager = ActionYmlFileManager(self.args.source_dir)
301
+ action_file_name = os.path.basename(self.args.file)
302
+ update_yaml_success = action_yml_file_manager.update_yaml_field(
303
+ action_file_name, "dynamic_urls", self.args.dynamic_urls)
304
+ if not update_yaml_success:
305
+ self.printer.print_in_terminal(
306
+ "yaml_save_error", style="red", yaml_file=action_file_name)
307
+
308
+ # 准备修复提示
309
+ fix_prompt = self.fix_missing_context.prompt(
310
+ query=query,
311
+ original_code=generation_result.contents[0],
312
+ missing_files=missing_files_text
313
+ )
314
+
315
+ logger.info(f"fix_missing_context_prompt: {fix_prompt}")
316
+
317
+ # 使用修复提示重新生成代码
204
318
  start_time = time.time()
205
319
  generation_result = self.code_generator.single_round_run(
206
- query, source_code_list)
207
-
208
- token_cost_calculator = TokenCostCalculator(args=self.args)
320
+ fix_prompt, updated_source_code_list)
321
+
322
+ # 计算这次修复缺失上下文花费的token情况
209
323
  token_cost_calculator.track_token_usage_by_generate(
210
324
  llm=self.llm,
211
325
  generate=generation_result,
@@ -213,13 +327,288 @@ class CodeEditBlockManager:
213
327
  start_time=start_time,
214
328
  end_time=time.time()
215
329
  )
330
+
331
+ # 选择最佳结果
332
+ generation_result = self.code_merger.choose_best_choice(generation_result)
333
+ ## 因为已经排完结果,就不要触发后面的排序了,所以只要保留第一个即可。
334
+ generation_result = CodeGenerateResult(contents=[generation_result.contents[0]],conversations=[generation_result.conversations[0]],metadata=generation_result.metadata)
335
+
336
+ return generation_result
216
337
 
217
- # 确保结果非空
218
- if not generation_result.contents:
219
- self.printer.print_in_terminal("generation_failed", style="red")
338
+ def _fix_unmerged_blocks(self, query: str, generation_result: CodeGenerateResult, source_code_list: SourceCodeList) -> CodeGenerateResult:
339
+ """
340
+ 修复未合并的代码块,最多尝试指定次数
341
+
342
+ 参数:
343
+ query (str): 用户查询
344
+ generation_result (CodeGenerateResult): 生成的代码结果
345
+ source_code_list (SourceCodeList): 源代码列表
346
+
347
+ 返回:
348
+ CodeGenerateResult: 修复后的代码结果
349
+ """
350
+ token_cost_calculator = TokenCostCalculator(args=self.args)
351
+ merge = self.code_merger._merge_code_without_effect(generation_result.contents[0])
352
+
353
+ if not self.args.enable_auto_fix_merge or not merge.failed_blocks:
220
354
  return generation_result
221
355
 
222
- # 最多尝试修复5次
356
+ def _format_blocks(merge: MergeCodeWithoutEffect) -> Tuple[str, str]:
357
+ unmerged_formatted_text = ""
358
+ for file_path, head, update in merge.failed_blocks:
359
+ unmerged_formatted_text += "```lang\n"
360
+ unmerged_formatted_text += f"##File: {file_path}\n"
361
+ unmerged_formatted_text += "<<<<<<< SEARCH\n"
362
+ unmerged_formatted_text += head
363
+ unmerged_formatted_text += "=======\n"
364
+ unmerged_formatted_text += update
365
+ unmerged_formatted_text += ">>>>>>> REPLACE\n"
366
+ unmerged_formatted_text += "```"
367
+ unmerged_formatted_text += "\n"
368
+
369
+ merged_formatted_text = ""
370
+ if merge.merged_blocks:
371
+ for file_path, head, update in merge.merged_blocks:
372
+ merged_formatted_text += "```lang\n"
373
+ merged_formatted_text += f"##File: {file_path}\n"
374
+ merged_formatted_text += head
375
+ merged_formatted_text += "=======\n"
376
+ merged_formatted_text += update
377
+ merged_formatted_text += "```"
378
+ merged_formatted_text += "\n"
379
+
380
+ get_event_manager(self.args.event_file).write_result(EventContentCreator.create_result(
381
+ content=EventContentCreator.ResultContent(content=f"Unmerged blocks:\n\n {unmerged_formatted_text}",
382
+ metadata={
383
+ "merged_blocks": merge.success_blocks,
384
+ "failed_blocks": merge.failed_blocks
385
+ }
386
+ ).to_dict(),
387
+ metadata={
388
+ "stream_out_type": UnmergedBlocksStreamOutType.UNMERGED_BLOCKS.value,
389
+ "action_file": self.args.file
390
+ }
391
+ ))
392
+ return (unmerged_formatted_text, merged_formatted_text)
393
+
394
+ for attempt in range(self.args.auto_fix_merge_max_attempts):
395
+ global_cancel.check_and_raise()
396
+ unmerged_formatted_text, merged_formatted_text = _format_blocks(merge)
397
+ fix_prompt = self.fix_unmerged_blocks.prompt(
398
+ query=query,
399
+ original_code=generation_result.contents[0],
400
+ unmerged_blocks=unmerged_formatted_text
401
+ )
402
+
403
+ logger.info(f"fix_prompt: {fix_prompt}")
404
+
405
+ # 打印当前修复尝试状态
406
+ self.printer.print_in_terminal(
407
+ "unmerged_blocks_attempt_status",
408
+ style="yellow",
409
+ attempt=(attempt + 1),
410
+ max_correction_attempts=self.args.auto_fix_merge_max_attempts
411
+ )
412
+
413
+ get_event_manager(self.args.event_file).write_result(EventContentCreator.create_result(
414
+ content=EventContentCreator.ResultContent(content=f"Unmerged blocks attempt {attempt + 1}/{self.args.auto_fix_merge_max_attempts}: {unmerged_formatted_text}",
415
+ metadata={}
416
+ ).to_dict(),
417
+ metadata={
418
+ "stream_out_type": UnmergedBlocksStreamOutType.UNMERGED_BLOCKS.value,
419
+ "action_file": self.args.file
420
+ }
421
+ ))
422
+
423
+ # 使用修复提示重新生成代码
424
+ start_time = time.time()
425
+ generation_result = self.code_generator.single_round_run(
426
+ fix_prompt, source_code_list)
427
+
428
+ # 计算这次修复未合并块花费的token情况
429
+ token_cost_calculator.track_token_usage_by_generate(
430
+ llm=self.llm,
431
+ generate=generation_result,
432
+ operation_name="code_generation_complete",
433
+ start_time=start_time,
434
+ end_time=time.time()
435
+ )
436
+
437
+ # 检查修复后的代码是否仍有未合并块
438
+ generation_result = self.code_merger.choose_best_choice(generation_result)
439
+ ## 因为已经排完结果,就不要触发后面的排序了,所以只要保留第一个即可。
440
+ generation_result = CodeGenerateResult(contents=[generation_result.contents[0]],conversations=[generation_result.conversations[0]],metadata=generation_result.metadata)
441
+ merge = self.code_merger._merge_code_without_effect(
442
+ generation_result.contents[0])
443
+
444
+ # 如果没有失败的块,则修复成功,退出循环
445
+ if not merge.failed_blocks:
446
+ self.printer.print_in_terminal(
447
+ "unmerged_blocks_fixed", style="green")
448
+ break
449
+
450
+ # 如果是最后一次尝试仍未成功,打印警告
451
+ if attempt == self.args.auto_fix_merge_max_attempts - 1:
452
+ self.printer.print_in_terminal(
453
+ "max_unmerged_blocks_attempts_reached", style="yellow")
454
+ get_event_manager(self.args.event_file).write_result(EventContentCreator.create_result(
455
+ content=EventContentCreator.ResultContent(content=self.printer.get_message_from_key("max_unmerged_blocks_attempts_reached"),
456
+ metadata={}
457
+ ).to_dict(),
458
+ metadata={
459
+ "stream_out_type": UnmergedBlocksStreamOutType.UNMERGED_BLOCKS.value,
460
+ "action_file": self.args.file
461
+ }
462
+ ))
463
+ raise Exception(self.printer.get_message_from_key(
464
+ "max_unmerged_blocks_attempts_reached"))
465
+
466
+ return generation_result
467
+
468
+ def _fix_unmerged_blocks(self, query: str, generation_result: CodeGenerateResult, source_code_list: SourceCodeList) -> CodeGenerateResult:
469
+ """
470
+ 修复未合并的代码块,最多尝试指定次数
471
+
472
+ 参数:
473
+ query (str): 用户查询
474
+ generation_result (CodeGenerateResult): 生成的代码结果
475
+ source_code_list (SourceCodeList): 源代码列表
476
+
477
+ 返回:
478
+ CodeGenerateResult: 修复后的代码结果
479
+ """
480
+ token_cost_calculator = TokenCostCalculator(args=self.args)
481
+ merge = self.code_merger._merge_code_without_effect(generation_result.contents[0])
482
+
483
+ if not self.args.enable_auto_fix_merge or not merge.failed_blocks:
484
+ return generation_result
485
+
486
+ def _format_blocks(merge: MergeCodeWithoutEffect) -> Tuple[str, str]:
487
+ unmerged_formatted_text = ""
488
+ for file_path, head, update in merge.failed_blocks:
489
+ unmerged_formatted_text += "```lang"
490
+ unmerged_formatted_text += f"##File: {file_path}\n"
491
+ unmerged_formatted_text += "<<<<<<< SEARCH\n"
492
+ unmerged_formatted_text += head
493
+ unmerged_formatted_text += "=======\n"
494
+ unmerged_formatted_text += update
495
+ unmerged_formatted_text += ">>>>>>> REPLACE\n"
496
+ unmerged_formatted_text += "```"
497
+ unmerged_formatted_text += "\n"
498
+
499
+ merged_formatted_text = ""
500
+ if merge.merged_blocks:
501
+ for file_path, head, update in merge.merged_blocks:
502
+ merged_formatted_text += "```lang"
503
+ merged_formatted_text += f"##File: {file_path}\n"
504
+ merged_formatted_text += head
505
+ merged_formatted_text += "=======\n"
506
+ merged_formatted_text += update
507
+ merged_formatted_text += "```"
508
+ merged_formatted_text += "\n"
509
+
510
+ get_event_manager(self.args.event_file).write_result(EventContentCreator.create_result(
511
+ content=EventContentCreator.ResultContent(content=f"Unmerged blocks:\\n {unmerged_formatted_text}",
512
+ metadata={
513
+ "merged_blocks": merge.success_blocks,
514
+ "failed_blocks": merge.failed_blocks
515
+ }
516
+ ).to_dict(),
517
+ metadata={
518
+ "stream_out_type": UnmergedBlocksStreamOutType.UNMERGED_BLOCKS.value,
519
+ "action_file": self.args.file
520
+ }
521
+ ))
522
+ return (unmerged_formatted_text, merged_formatted_text)
523
+
524
+ for attempt in range(self.args.auto_fix_merge_max_attempts):
525
+ global_cancel.check_and_raise()
526
+ unmerged_formatted_text, merged_formatted_text = _format_blocks(merge)
527
+ fix_prompt = self.fix_unmerged_blocks.prompt(
528
+ query=query,
529
+ original_code=generation_result.contents[0],
530
+ unmerged_blocks=unmerged_formatted_text
531
+ )
532
+
533
+ logger.info(f"fix_prompt: {fix_prompt}")
534
+
535
+ # 打印当前修复尝试状态
536
+ self.printer.print_in_terminal(
537
+ "unmerged_blocks_attempt_status",
538
+ style="yellow",
539
+ attempt=(attempt + 1),
540
+ max_correction_attempts=self.args.auto_fix_merge_max_attempts
541
+ )
542
+
543
+ get_event_manager(self.args.event_file).write_result(EventContentCreator.create_result(
544
+ content=EventContentCreator.ResultContent(content=f"Unmerged blocks attempt {attempt + 1}/{self.args.auto_fix_merge_max_attempts}: {unmerged_formatted_text}",
545
+ metadata={}
546
+ ).to_dict(),
547
+ metadata={
548
+ "stream_out_type": UnmergedBlocksStreamOutType.UNMERGED_BLOCKS.value,
549
+ "action_file": self.args.file
550
+ }
551
+ ))
552
+
553
+ # 使用修复提示重新生成代码
554
+ start_time = time.time()
555
+ generation_result = self.code_generator.single_round_run(
556
+ fix_prompt, source_code_list)
557
+
558
+ # 计算这次修复未合并块花费的token情况
559
+ token_cost_calculator.track_token_usage_by_generate(
560
+ llm=self.llm,
561
+ generate=generation_result,
562
+ operation_name="code_generation_complete",
563
+ start_time=start_time,
564
+ end_time=time.time()
565
+ )
566
+
567
+ # 检查修复后的代码是否仍有未合并块
568
+ generation_result = self.code_merger.choose_best_choice(generation_result)
569
+ ## 因为已经排完结果,就不要触发后面的排序了,所以只要保留第一个即可。
570
+ generation_result = CodeGenerateResult(contents=[generation_result.contents[0]],conversations=[generation_result.conversations[0]],metadata=generation_result.metadata)
571
+ merge = self.code_merger._merge_code_without_effect(
572
+ generation_result.contents[0])
573
+
574
+ # 如果没有失败的块,则修复成功,退出循环
575
+ if not merge.failed_blocks:
576
+ self.printer.print_in_terminal(
577
+ "unmerged_blocks_fixed", style="green")
578
+ break
579
+
580
+ # 如果是最后一次尝试仍未成功,打印警告
581
+ if attempt == self.args.auto_fix_merge_max_attempts - 1:
582
+ self.printer.print_in_terminal(
583
+ "max_unmerged_blocks_attempts_reached", style="yellow")
584
+ get_event_manager(self.args.event_file).write_result(EventContentCreator.create_result(
585
+ content=EventContentCreator.ResultContent(content=self.printer.get_message_from_key("max_unmerged_blocks_attempts_reached"),
586
+ metadata={}
587
+ ).to_dict(),
588
+ metadata={
589
+ "stream_out_type": UnmergedBlocksStreamOutType.UNMERGED_BLOCKS.value,
590
+ "action_file": self.args.file
591
+ }
592
+ ))
593
+ raise Exception(self.printer.get_message_from_key(
594
+ "max_unmerged_blocks_attempts_reached"))
595
+
596
+ return generation_result
597
+
598
+ def _fix_lint_errors(self, query: str, generation_result: CodeGenerateResult, source_code_list: SourceCodeList) -> CodeGenerateResult:
599
+ """
600
+ 自动修复lint错误,最多尝试指定次数
601
+
602
+ 参数:
603
+ query (str): 用户查询
604
+ generation_result (CodeGenerateResult): 生成的代码结果
605
+ source_code_list (SourceCodeList): 源代码列表
606
+
607
+ 返回:
608
+ CodeGenerateResult: 修复后的代码结果
609
+ """
610
+ token_cost_calculator = TokenCostCalculator(args=self.args)
611
+
223
612
  for attempt in range(self.auto_fix_lint_max_attempts):
224
613
  global_cancel.check_and_raise()
225
614
  # 代码生成结果更新到影子文件里去
@@ -234,8 +623,6 @@ class CodeEditBlockManager:
234
623
  # 运行linter
235
624
  lint_results = self.shadow_linter.lint_all_shadow_files()
236
625
  error_count = self._count_errors(lint_results)
237
- # print(f"error_count: {error_count}")
238
- # print(f"lint_results: {json.dumps(lint_results.model_dump(), indent=4,ensure_ascii=False)}")
239
626
 
240
627
  # 如果没有错误则完成
241
628
  if error_count == 0:
@@ -279,10 +666,6 @@ class CodeEditBlockManager:
279
666
  lint_issues=formatted_issues
280
667
  )
281
668
 
282
- # for source in source_code_list.sources:
283
- # print(f"file_path: {source.module_name}")
284
- # print(f"fix_prompt: {fix_prompt}")
285
-
286
669
  # 将 shadow_files 转化为 source_code_list
287
670
  start_time = time.time()
288
671
  source_code_list = self.code_merger.get_source_code_list_from_shadow_files(
@@ -290,7 +673,7 @@ class CodeEditBlockManager:
290
673
  generation_result = self.code_generator.single_round_run(
291
674
  fix_prompt, source_code_list)
292
675
 
293
- # 计算这次修复lint 问题花费的token情况
676
+ # 计算这次修复lint问题花费的token情况
294
677
  token_cost_calculator.track_token_usage_by_generate(
295
678
  llm=self.llm,
296
679
  generate=generation_result,
@@ -298,66 +681,135 @@ class CodeEditBlockManager:
298
681
  start_time=start_time,
299
682
  end_time=time.time()
300
683
  )
684
+
685
+ return generation_result
686
+
687
+ def _fix_compile_errors(self, query: str, generation_result: CodeGenerateResult, source_code_list: SourceCodeList) -> CodeGenerateResult:
688
+ """
689
+ 自动修复编译错误,最多尝试指定次数
690
+
691
+ 参数:
692
+ query (str): 用户查询
693
+ generation_result (CodeGenerateResult): 生成的代码结果
694
+ source_code_list (SourceCodeList): 源代码列表
695
+
696
+ 返回:
697
+ CodeGenerateResult: 修复后的代码结果
698
+ """
699
+ if not self.args.enable_auto_fix_compile:
700
+ return generation_result
701
+
702
+ token_cost_calculator = TokenCostCalculator(args=self.args)
301
703
 
302
- # 如果开启了自动修复compile问题,则进行compile修复
303
- if self.args.enable_auto_fix_compile:
304
- for attempt in range(self.auto_fix_compile_max_attempts):
305
- global_cancel.check_and_raise()
306
- # 先更新增量影子系统的文件
307
- shadow_files = self._create_shadow_files_from_edits(generation_result)
308
-
309
- # 在影子系统生成完整的项目,然后编译
310
- compile_result = self.shadow_compiler.compile_all_shadow_files()
311
-
312
- # 如果编译成功,则退出,继续往后走
313
- if compile_result.success or compile_result.total_errors == 0:
314
- self.printer.print_in_terminal(
315
- "compile_success", style="green")
316
- break
317
-
318
- # 如果有错误,则把compile结果记录到事件系统
319
- get_event_manager(self.args.event_file).write_result(EventContentCreator.create_result(
320
- 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()}",
321
- metadata={}
322
- ).to_dict(),
323
- metadata={
324
- "stream_out_type": CompileStreamOutType.COMPILE.value,
325
- "action_file": self.args.file
326
- }
327
- ))
704
+ for attempt in range(self.auto_fix_compile_max_attempts):
705
+ global_cancel.check_and_raise()
706
+ # 先更新增量影子系统的文件
707
+ shadow_files = self._create_shadow_files_from_edits(
708
+ generation_result)
709
+
710
+ # 在影子系统生成完整的项目,然后编译
711
+ compile_result = self.shadow_compiler.compile_all_shadow_files()
328
712
 
329
- if attempt == self.auto_fix_compile_max_attempts - 1:
330
- self.printer.print_in_terminal(
331
- "max_compile_attempts_reached", style="yellow")
332
- break
333
-
334
- # 打印当前compile错误
335
- self.printer.print_in_terminal("compile_attempt_status",
336
- style="yellow",
337
- attempt=(attempt + 1), max_correction_attempts=self.auto_fix_compile_max_attempts,
338
- error_count=compile_result.total_errors,
339
- formatted_issues=compile_result.to_str())
340
-
341
- fix_compile_prompt = self.fix_compile_errors.prompt(
342
- query=query,
343
- compile_errors=compile_result.to_str()
344
- )
713
+ # 如果编译成功,则退出,继续往后走
714
+ if compile_result.success or compile_result.total_errors == 0:
715
+ self.printer.print_in_terminal(
716
+ "compile_success", style="green")
717
+ break
718
+
719
+ # 如果有错误,则把compile结果记录到事件系统
720
+ get_event_manager(self.args.event_file).write_result(EventContentCreator.create_result(
721
+ 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()}",
722
+ metadata={}
723
+ ).to_dict(),
724
+ metadata={
725
+ "stream_out_type": CompileStreamOutType.COMPILE.value,
726
+ "action_file": self.args.file
727
+ }
728
+ ))
729
+
730
+ if attempt == self.auto_fix_compile_max_attempts - 1:
731
+ self.printer.print_in_terminal(
732
+ "max_compile_attempts_reached", style="yellow")
733
+ break
734
+
735
+ # 打印当前compile错误
736
+ self.printer.print_in_terminal("compile_attempt_status",
737
+ style="yellow",
738
+ attempt=(attempt + 1), max_correction_attempts=self.auto_fix_compile_max_attempts,
739
+ error_count=compile_result.total_errors,
740
+ formatted_issues=compile_result.to_str())
741
+
742
+ fix_compile_prompt = self.fix_compile_errors.prompt(
743
+ query=query,
744
+ compile_errors=compile_result.to_str()
745
+ )
746
+
747
+ # 将 shadow_files 转化为 source_code_list
748
+ start_time = time.time()
749
+ source_code_list = self.code_merger.get_source_code_list_from_shadow_files(
750
+ shadow_files)
751
+ generation_result = self.code_generator.single_round_run(
752
+ fix_compile_prompt, source_code_list)
753
+
754
+ # 计算这次修复compile问题花费的token情况
755
+ token_cost_calculator.track_token_usage_by_generate(
756
+ llm=self.llm,
757
+ generate=generation_result,
758
+ operation_name="code_generation_complete",
759
+ start_time=start_time,
760
+ end_time=time.time()
761
+ )
762
+
763
+ return generation_result
764
+
765
+ def generate_and_fix(self, query: str, source_code_list: SourceCodeList) -> CodeGenerateResult:
766
+ """
767
+ 生成代码,运行linter/compile,修复错误,最多尝试指定次数
768
+
769
+ 参数:
770
+ query (str): 用户查询
771
+ source_code_list (SourceCodeList): 源代码列表
772
+
773
+ 返回:
774
+ CodeGenerateResult: 生成的代码结果
775
+ """
776
+ # 初始代码生成
777
+ self.printer.print_in_terminal("generating_initial_code")
778
+ start_time = time.time()
779
+ generation_result = self.code_generator.single_round_run(
780
+ query, source_code_list)
345
781
 
346
- # shadow_files 转化为 source_code_list
347
- start_time = time.time()
348
- source_code_list = self.code_merger.get_source_code_list_from_shadow_files(
349
- shadow_files)
350
- generation_result = self.code_generator.single_round_run(
351
- fix_compile_prompt, source_code_list)
352
-
353
- # 计算这次修复compile 问题花费的token情况
354
- token_cost_calculator.track_token_usage_by_generate(
355
- llm=self.llm,
356
- generate=generation_result,
357
- operation_name="code_generation_complete",
358
- start_time=start_time,
359
- end_time=time.time()
360
- )
782
+ token_cost_calculator = TokenCostCalculator(args=self.args)
783
+ token_cost_calculator.track_token_usage_by_generate(
784
+ llm=self.llm,
785
+ generate=generation_result,
786
+ operation_name="code_generation_complete",
787
+ start_time=start_time,
788
+ end_time=time.time()
789
+ )
790
+
791
+ # 确保结果非空
792
+ if not generation_result.contents:
793
+ self.printer.print_in_terminal("generation_failed", style="red")
794
+ return generation_result
795
+
796
+ ## 可能第一次触发排序
797
+ generation_result = self.code_merger.choose_best_choice(generation_result)
798
+
799
+ ## 因为已经排完结果,就不要触发后面的排序了,所以只要保留第一个即可。
800
+ generation_result = CodeGenerateResult(contents=[generation_result.contents[0]],conversations=[generation_result.conversations[0]],metadata=generation_result.metadata)
801
+
802
+ # 修复缺少上下文的文件
803
+ generation_result = self._fix_missing_context(query, generation_result, source_code_list)
804
+
805
+ # 修复未合并的代码块
806
+ generation_result = self._fix_unmerged_blocks(query, generation_result, source_code_list)
807
+
808
+ # 修复lint错误
809
+ generation_result = self._fix_lint_errors(query, generation_result, source_code_list)
810
+
811
+ # 修复编译错误
812
+ generation_result = self._fix_compile_errors(query, generation_result, source_code_list)
361
813
 
362
814
  # 清理临时影子文件
363
815
  self.shadow_manager.clean_shadows()