auto-coder 0.1.305__py3-none-any.whl → 0.1.307__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 (43) hide show
  1. {auto_coder-0.1.305.dist-info → auto_coder-0.1.307.dist-info}/METADATA +1 -1
  2. {auto_coder-0.1.305.dist-info → auto_coder-0.1.307.dist-info}/RECORD +43 -38
  3. autocoder/agent/auto_demand_organizer.py +13 -20
  4. autocoder/agent/auto_filegroup.py +10 -16
  5. autocoder/agent/auto_learn_from_commit.py +25 -33
  6. autocoder/agent/auto_review_commit.py +15 -64
  7. autocoder/auto_coder.py +6 -8
  8. autocoder/auto_coder_runner.py +153 -8
  9. autocoder/chat_auto_coder.py +9 -1
  10. autocoder/chat_auto_coder_lang.py +552 -278
  11. autocoder/commands/auto_command.py +31 -7
  12. autocoder/common/__init__.py +6 -0
  13. autocoder/common/action_yml_file_manager.py +75 -37
  14. autocoder/common/auto_coder_lang.py +737 -401
  15. autocoder/common/code_auto_generate.py +104 -16
  16. autocoder/common/code_auto_generate_diff.py +101 -10
  17. autocoder/common/code_auto_generate_editblock.py +103 -9
  18. autocoder/common/code_auto_generate_strict_diff.py +99 -9
  19. autocoder/common/code_auto_merge.py +8 -0
  20. autocoder/common/code_auto_merge_diff.py +8 -0
  21. autocoder/common/code_auto_merge_editblock.py +7 -0
  22. autocoder/common/code_auto_merge_strict_diff.py +5 -0
  23. autocoder/common/code_modification_ranker.py +9 -3
  24. autocoder/common/command_completer.py +12 -0
  25. autocoder/common/command_generator.py +5 -4
  26. autocoder/common/git_utils.py +86 -63
  27. autocoder/common/stream_out_type.py +8 -1
  28. autocoder/common/utils_code_auto_generate.py +29 -3
  29. autocoder/dispacher/__init__.py +18 -19
  30. autocoder/dispacher/actions/action.py +0 -132
  31. autocoder/index/filter/quick_filter.py +6 -3
  32. autocoder/memory/__init__.py +7 -0
  33. autocoder/memory/active_context_manager.py +649 -0
  34. autocoder/memory/active_package.py +469 -0
  35. autocoder/memory/async_processor.py +161 -0
  36. autocoder/memory/directory_mapper.py +67 -0
  37. autocoder/utils/auto_coder_utils/chat_stream_out.py +5 -0
  38. autocoder/utils/project_structure.py +35 -1
  39. autocoder/version.py +1 -1
  40. {auto_coder-0.1.305.dist-info → auto_coder-0.1.307.dist-info}/LICENSE +0 -0
  41. {auto_coder-0.1.305.dist-info → auto_coder-0.1.307.dist-info}/WHEEL +0 -0
  42. {auto_coder-0.1.305.dist-info → auto_coder-0.1.307.dist-info}/entry_points.txt +0 -0
  43. {auto_coder-0.1.305.dist-info → auto_coder-0.1.307.dist-info}/top_level.txt +0 -0
@@ -213,6 +213,8 @@ class CommandAutoTuner:
213
213
  @byzerllm.prompt()
214
214
  def _analyze(self, request: AutoCommandRequest) -> str:
215
215
  """
216
+ 你是 auto-coder.chat 软件,帮助用户完成编程方面的需求。我们的目标是根据用户输入和当前上下文,组合多个函数来完成用户的需求。
217
+
216
218
  ## 当前用户环境信息如下:
217
219
  <os_info>
218
220
  操作系统: {{ env_info.os_name }} {{ env_info.os_version }}
@@ -234,10 +236,11 @@ class CommandAutoTuner:
234
236
  {%- endif %}
235
237
  </os_info>
236
238
 
237
- 我们的目标是根据用户输入和当前上下文,组合多个函数来完成用户的需求。
238
-
239
+ 当前项目根目录:
240
+ {{ current_project }}
241
+
239
242
  {% if current_files %}
240
- ## 当前活跃区文件列表:
243
+ ## 当前用户手动添加关注的文件列表:
241
244
  <current_files>
242
245
  {% for file in current_files %}
243
246
  - {{ file }}
@@ -246,7 +249,7 @@ class CommandAutoTuner:
246
249
  {% endif %}
247
250
 
248
251
 
249
- ## 当前用户的配置选项如下:
252
+ ## 这是用户对你的配置
250
253
  <current_conf>
251
254
  {{ current_conf }}
252
255
  </current_conf>
@@ -260,6 +263,24 @@ class CommandAutoTuner:
260
263
  ## 函数组合说明:
261
264
  {{ command_combination_readme }}
262
265
 
266
+ ## active-context 项目追踪文档系统
267
+
268
+ 在 {{ current_project }}/.auto-coder/active-context 下,我们提供了对该项目每个文件目录的追踪。
269
+ 具体逻辑为:假设我们在当前项目有 ./src/package1/py1.py, 那么相应的在 .auto-coder/active-context 会有一个 ./src/package1 目录,
270
+ 该目录下可能会有一个 active-context.md 文件,该文件记录了该目录下所有文件相关信息,可以帮你更好的理解这个目录下的文档,你可以通过 read_files 函数来读取
271
+ 这个文件。注意,这个文件不一定存在。如果读取失败也是正常的。
272
+
273
+ ## 变更记录文档系统
274
+
275
+ 在 {{ current_project }}/actions 目录下,会有格式类似 000000001201_chat_action.yml 的文件,该文件记录了最近10次对话,
276
+ 你可以通过 read_files 函数来读取这些文件,从而更好的理解用户的需求。
277
+
278
+ 下面是一些字段的简单介绍
279
+ - query: 用户需求
280
+ - urls: 用户提供的上下文文件列表
281
+ - dynamic_urls: auto-coder.chat 自动感知的一些文件列表
282
+ - add_updated_urls: 这次需求发生变更的文件列表
283
+
263
284
  {% if conversation_history %}
264
285
  ## 历史对话:
265
286
  <conversation_history>
@@ -314,7 +335,8 @@ class CommandAutoTuner:
314
335
  "conversation_safe_zone_tokens": self.args.conversation_prune_safe_zone_tokens,
315
336
  "os_distribution": shells.get_os_distribution(),
316
337
  "current_user": shells.get_current_username(),
317
- "command_combination_readme": self._command_combination_readme.prompt()
338
+ "command_combination_readme": self._command_combination_readme.prompt(),
339
+ "current_project": os.path.abspath(self.args.source_dir)
318
340
  }
319
341
 
320
342
  @byzerllm.prompt()
@@ -337,8 +359,10 @@ class CommandAutoTuner:
337
359
  尽可通过了解项目后,多用 @文件和@@符号,这样 chat 函数可以更清晰的理解你关注的代码,文档和意图。
338
360
 
339
361
  ### 调用 coding 函数应该注意的事项
340
- 调用 coding 函数的时候,尽可能多的 @文件和@@符号,让需求更加清晰明了,建议多描述具体怎么完成对应的需求。
341
- 对于代码需求设计,尽可能使用 chat 函数。如果成功执行了 coding 函数, 最好再调用一次 chat("/review /commit"),方便总结这次代码变更。
362
+ 调用 coding 函数的之前,你需要尽可能先了解用户需求,了解项目状态,包括读取 active_context 文件来了解项目。
363
+ 然后清晰的描述自己的需求,完整的实现步骤,以及尽可能对@文件和@@符号需要参考以及修改的文件和符号。
364
+ 对于比较复杂的需求,你还可以使用 chat 函数来进行讨论,从而获取一些有用的信息。
365
+ 如果成功执行了 coding 函数, 最好再调用一次 chat("/review /commit"),方便总结这次代码变更。
342
366
  注意,review 完后,需要询问用户是否要做啥调整不,如果用户说不用,那么就停止。否则根据意图进行后续操作。
343
367
 
344
368
  ### 关于对话大小的问题
@@ -412,6 +412,12 @@ class AutoCoderArgs(pydantic.BaseModel):
412
412
 
413
413
  event_file: Optional[str] = None
414
414
 
415
+ enable_active_context: Optional[bool] = False
416
+
417
+ generate_max_rounds: Optional[int] = 5
418
+
419
+ revert_commit_id: Optional[str] = None
420
+
415
421
  class Config:
416
422
  protected_namespaces = ()
417
423
 
@@ -4,8 +4,10 @@ import hashlib
4
4
  import git
5
5
  from typing import List, Dict, Tuple, Optional, Union, Any
6
6
  from loguru import logger
7
+ from autocoder.common.git_utils import get_repo
7
8
  from autocoder.common.printer import Printer
8
9
  import byzerllm
10
+ from autocoder.common import git_utils
9
11
 
10
12
  class ActionYmlFileManager:
11
13
  """
@@ -44,7 +46,7 @@ class ActionYmlFileManager:
44
46
  except Exception as e:
45
47
  logger.error(f"Failed to create actions directory: {e}")
46
48
  return False
47
- return True
49
+ return True
48
50
 
49
51
  def get_action_files(self, filter_prefix: Optional[str] = None) -> List[str]:
50
52
  """
@@ -183,16 +185,21 @@ class ActionYmlFileManager:
183
185
  Returns:
184
186
  Dict: YAML 内容,如果加载失败返回空字典
185
187
  """
186
- yaml_path = os.path.join(self.actions_dir, file_name)
187
-
188
+ yaml_path = os.path.join(self.actions_dir, file_name)
188
189
  try:
189
190
  with open(yaml_path, 'r', encoding='utf-8') as f:
190
191
  content = yaml.safe_load(f) or {}
191
192
  return content
192
- except Exception as e:
193
+ except Exception as e:
193
194
  self.printer.print_in_terminal("yaml_load_error", style="red",
194
195
  yaml_file=yaml_path, error=str(e))
195
196
  return {}
197
+
198
+ def get_full_path_by_file_name(self, file_name: str) -> str:
199
+ """
200
+ 根据文件名获取完整路径
201
+ """
202
+ return os.path.join(self.actions_dir, file_name)
196
203
 
197
204
  def save_yaml_content(self, file_name: str, content: Dict) -> bool:
198
205
  """
@@ -232,6 +239,26 @@ class ActionYmlFileManager:
232
239
  yaml_content = self.load_yaml_content(file_name)
233
240
  yaml_content[field] = value
234
241
  return self.save_yaml_content(file_name, yaml_content)
242
+
243
+ def get_all_commit_id_from_file(self,file_name:str):
244
+ '''
245
+ 会包含 revert 信息
246
+ '''
247
+ repo = get_repo(self.source_dir)
248
+ if repo is None:
249
+ logger.error("Repository is not initialized.")
250
+ return []
251
+
252
+ commit_hashes = []
253
+ for commit in repo.iter_commits():
254
+ lines = commit.message.strip().split('\n')
255
+ last_line = lines[-1]
256
+ if file_name in last_line or (commit.message.startswith("<revert>") and file_name in commit.message):
257
+ commit_hash = commit.hexsha
258
+ commit_hashes.append(commit_hash)
259
+
260
+ return commit_hashes
261
+
235
262
 
236
263
  def get_commit_id_from_file(self, file_name: str) -> Optional[str]:
237
264
  """
@@ -243,16 +270,19 @@ class ActionYmlFileManager:
243
270
  Returns:
244
271
  Optional[str]: commit ID,如果计算失败返回 None
245
272
  """
246
- yaml_path = os.path.join(self.actions_dir, file_name)
247
-
248
- try:
249
- with open(yaml_path, 'r', encoding='utf-8') as f:
250
- yaml_content = f.read()
251
- file_md5 = hashlib.md5(yaml_content.encode("utf-8")).hexdigest()
252
- return f"auto_coder_{file_name}"
253
- except Exception as e:
254
- logger.error(f"Failed to calculate commit ID: {e}")
273
+ repo = get_repo(self.source_dir)
274
+ if repo is None:
275
+ logger.error("Repository is not initialized.")
255
276
  return None
277
+
278
+ commit_hash = None
279
+ # 这里遍历从最新的commit 开始遍历
280
+ for commit in repo.iter_commits():
281
+ last_line = commit.message.strip().split('\n')[-1]
282
+ if file_name in last_line and not commit.message.startswith("<revert>"):
283
+ commit_hash = commit.hexsha
284
+ break
285
+ return commit_hash
256
286
 
257
287
  def get_file_name_from_commit_id(self, commit_id: str) -> Optional[str]:
258
288
  """
@@ -298,7 +328,7 @@ class ActionYmlFileManager:
298
328
  return self.get_file_name_from_commit_id(last_line)
299
329
  except Exception as e:
300
330
  logger.error(f"Failed to extract file name from commit message: {e}")
301
- return None
331
+ return None
302
332
 
303
333
  def get_commit_changes(self, file_name: Optional[str] = None) -> List[Tuple[str, List[str], Dict[str, Tuple[str, str]]]]:
304
334
  """
@@ -327,31 +357,30 @@ class ActionYmlFileManager:
327
357
  changes = {}
328
358
  try:
329
359
  repo = git.Repo(self.source_dir)
330
- for commit in repo.iter_commits():
331
- if commit_id in commit.message:
332
- if commit.parents:
333
- parent = commit.parents[0]
334
- # 获取所有文件的前后内容
335
- for diff_item in parent.diff(commit):
336
- file_path = diff_item.a_path if diff_item.a_path else diff_item.b_path
337
-
338
- # 获取变更前内容
339
- before_content = None
340
- try:
341
- if diff_item.a_blob:
342
- before_content = repo.git.show(f"{parent.hexsha}:{file_path}")
343
- except git.exc.GitCommandError:
344
- pass # 文件可能是新增的
360
+ commit =repo.commit(commit_id)
361
+ if commit.parents:
362
+ parent = commit.parents[0]
363
+ # 获取所有文件的前后内容
364
+ for diff_item in parent.diff(commit):
365
+ file_path = diff_item.a_path if diff_item.a_path else diff_item.b_path
366
+
367
+ # 获取变更前内容
368
+ before_content = None
369
+ try:
370
+ if diff_item.a_blob:
371
+ before_content = repo.git.show(f"{parent.hexsha}:{file_path}")
372
+ except git.exc.GitCommandError:
373
+ pass # 文件可能是新增的
345
374
 
346
- # 获取变更后内容
347
- after_content = None
348
- try:
349
- if diff_item.b_blob:
350
- after_content = repo.git.show(f"{commit.hexsha}:{file_path}")
351
- except git.exc.GitCommandError:
352
- pass # 文件可能被删除
375
+ # 获取变更后内容
376
+ after_content = None
377
+ try:
378
+ if diff_item.b_blob:
379
+ after_content = repo.git.show(f"{commit.hexsha}:{file_path}")
380
+ except git.exc.GitCommandError:
381
+ pass # 文件可能被删除
353
382
 
354
- changes[file_path] = (before_content, after_content)
383
+ changes[file_path] = (before_content, after_content)
355
384
  break
356
385
  except git.exc.GitCommandError as e:
357
386
  self.printer.print_in_terminal("git_command_error", style="red", error=str(e))
@@ -360,6 +389,15 @@ class ActionYmlFileManager:
360
389
 
361
390
  return [(query, urls, changes)]
362
391
 
392
+ def revert_file(self, file_name: str) -> bool:
393
+ revert_result = git_utils.revert_changes(
394
+ self.source_dir, f"auto_coder_{file_name}"
395
+ )
396
+ if revert_result:
397
+ self.update_yaml_field(file_name, "revert_commit_id", revert_result.get("new_commit_hash"))
398
+ return True
399
+ return False
400
+
363
401
  def parse_history_tasks(self, limit: int = 5) -> List[Dict]:
364
402
  """
365
403
  解析历史任务信息