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
@@ -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
- file_path, head, update = block
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
- self.printer.print_in_terminal("unmerged_blocks_warning", num_blocks=len(unmerged_blocks))
383
- self._print_unmerged_blocks(unmerged_blocks)
384
- return
385
-
386
- # lint check
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 pathlib import Path
5
- from typing import List, Dict, Tuple
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 AutoCoderArgs, git_utils
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.v2.code_auto_merge import CodeAutoMerge
11
- from autocoder.common import files as FileUtils
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
- class CodeAutoMergeStrictDiff(CodeAutoMerge):
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
+ '''
@@ -1,19 +1,19 @@
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
6
  from byzerllm.utils.client import code_utils
9
7
 
10
8
  from autocoder.common.types import Mode, CodeGenerateResult, MergeCodeWithoutEffect
11
- from autocoder.common import AutoCoderArgs, git_utils, SourceCodeList
9
+ from autocoder.common import AutoCoderArgs, git_utils, SourceCodeList, SourceCode
10
+ from autocoder.common.action_yml_file_manager import ActionYmlFileManager
12
11
  from autocoder.common import sys_prompt
12
+ from autocoder.compilers.shadow_compiler import ShadowCompiler
13
13
  from autocoder.privacy.model_filter import ModelPathFilter
14
14
  from autocoder.common.utils_code_auto_generate import chat_with_continue, stream_chat_with_continue, ChatWithContinueResult
15
15
  from autocoder.utils.auto_coder_utils.chat_stream_out import stream_out
16
- from autocoder.common.stream_out_type import CodeGenerateStreamOutType
16
+ from autocoder.common.stream_out_type import LintStreamOutType, CompileStreamOutType, UnmergedBlocksStreamOutType, CodeGenerateStreamOutType
17
17
  from autocoder.common.auto_coder_lang import get_message_with_format
18
18
  from autocoder.common.printer import Printer
19
19
  from autocoder.rag.token_counter import count_tokens
@@ -28,6 +28,9 @@ from loguru import logger
28
28
  from autocoder.common.global_cancel import global_cancel
29
29
  from autocoder.linters.models import ProjectLintResult
30
30
  from autocoder.common.token_cost_caculate import TokenCostCalculator
31
+ from autocoder.events.event_manager_singleton import get_event_manager
32
+ from autocoder.events.event_types import Event, EventType, EventMetadata
33
+ from autocoder.events import event_content as EventContentCreator
31
34
 
32
35
 
33
36
  class CodeDiffManager:
@@ -47,7 +50,8 @@ class CodeDiffManager:
47
50
  self.args = args
48
51
  self.action = action
49
52
  self.generate_times_same_model = args.generate_times_same_model
50
- self.max_correction_attempts = args.auto_fix_lint_max_attempts
53
+ self.auto_fix_lint_max_attempts = args.auto_fix_lint_max_attempts
54
+ self.auto_fix_compile_max_attempts = args.auto_fix_compile_max_attempts
51
55
  self.printer = Printer()
52
56
 
53
57
  # Initialize sub-components
@@ -55,8 +59,11 @@ class CodeDiffManager:
55
59
  self.code_merger = CodeAutoMergeDiff(llm, args)
56
60
 
57
61
  # Create shadow manager for linting
58
- self.shadow_manager = ShadowManager(args.source_dir, args.event_file)
62
+ self.shadow_manager = ShadowManager(
63
+ args.source_dir, args.event_file, args.ignore_clean_shadows)
59
64
  self.shadow_linter = ShadowLinter(self.shadow_manager, verbose=False)
65
+ self.shadow_compiler = ShadowCompiler(
66
+ self.shadow_manager, verbose=False)
60
67
 
61
68
  @byzerllm.prompt()
62
69
  def fix_linter_errors(self, query: str, lint_issues: str) -> str:
@@ -75,6 +82,66 @@ class CodeDiffManager:
75
82
  请使用 unified diff 格式输出修改。
76
83
  """
77
84
 
85
+ @byzerllm.prompt()
86
+ def fix_compile_errors(self, query: str, compile_errors: str) -> str:
87
+ """
88
+ 编译错误:
89
+ <compile_errors>
90
+ {{ compile_errors }}
91
+ </compile_errors>
92
+
93
+ 用户原始需求:
94
+ <user_query_wrapper>
95
+ {{ query }}
96
+ </user_query_wrapper>
97
+
98
+ 修复上述问题,请确保代码质量问题被解决,同时保持代码的原有功能。
99
+ 请使用 unified diff 格式输出修改。
100
+ """
101
+
102
+ @byzerllm.prompt()
103
+ def fix_missing_context(self, query: str, original_code: str, missing_files: str) -> str:
104
+ """
105
+ 下面是你根据格式要求输出的一份修改代码:
106
+ <original_code>
107
+ {{ original_code }}
108
+ </original_code>
109
+
110
+ 我发现你尝试修改以下文件,但这些文件没有在上下文中提供,所以你无法看到它们的内容:
111
+ <missing_files>
112
+ {{ missing_files }}
113
+ </missing_files>
114
+
115
+ 下面是用户原始的需求:
116
+ <user_query_wrapper>
117
+ {{ query }}
118
+ </user_query_wrapper>
119
+
120
+ 我已经将这些文件添加到上下文中,请重新生成代码,确保使用 unified diff 格式正确修改这些文件。
121
+ """
122
+
123
+ @byzerllm.prompt()
124
+ def fix_unmerged_blocks(self, query: str, original_code: str, unmerged_blocks: str) -> str:
125
+ """
126
+ 下面是你根据格式要求输出的一份修改代码:
127
+ <original_code>
128
+ {{ original_code }}
129
+ </original_code>
130
+
131
+ 但是我发现下面的代码块无法合并:
132
+ <unmerged_blocks>
133
+ {{ unmerged_blocks }}
134
+ </unmerged_blocks>
135
+
136
+ 下面是用户原始的需求:
137
+ <user_query_wrapper>
138
+ {{ query }}
139
+ </user_query_wrapper>
140
+
141
+ 请根据反馈,回顾之前的格式要求,重新生成一份修改代码,确保所有代码块都能够正确合并。
142
+ 请使用 unified diff 格式输出修改。
143
+ """
144
+
78
145
  def _create_shadow_files_from_edits(self, generation_result: CodeGenerateResult) -> Dict[str, str]:
79
146
  """
80
147
  从编辑块内容中提取代码并创建临时影子文件用于检查。