auto-coder 0.1.399__py3-none-any.whl → 0.1.400__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 (38) hide show
  1. {auto_coder-0.1.399.dist-info → auto_coder-0.1.400.dist-info}/METADATA +1 -1
  2. {auto_coder-0.1.399.dist-info → auto_coder-0.1.400.dist-info}/RECORD +38 -19
  3. autocoder/auto_coder_runner.py +2 -1
  4. autocoder/common/ac_style_command_parser/parser.py +27 -12
  5. autocoder/common/auto_coder_lang.py +78 -0
  6. autocoder/common/command_completer_v2.py +1 -1
  7. autocoder/common/pull_requests/__init__.py +256 -0
  8. autocoder/common/pull_requests/base_provider.py +191 -0
  9. autocoder/common/pull_requests/config.py +66 -0
  10. autocoder/common/pull_requests/example.py +1 -0
  11. autocoder/common/pull_requests/exceptions.py +46 -0
  12. autocoder/common/pull_requests/manager.py +201 -0
  13. autocoder/common/pull_requests/models.py +164 -0
  14. autocoder/common/pull_requests/providers/__init__.py +23 -0
  15. autocoder/common/pull_requests/providers/gitcode_provider.py +19 -0
  16. autocoder/common/pull_requests/providers/gitee_provider.py +20 -0
  17. autocoder/common/pull_requests/providers/github_provider.py +214 -0
  18. autocoder/common/pull_requests/providers/gitlab_provider.py +29 -0
  19. autocoder/common/pull_requests/test_module.py +1 -0
  20. autocoder/common/pull_requests/utils.py +344 -0
  21. autocoder/common/tokens/__init__.py +62 -0
  22. autocoder/common/tokens/counter.py +211 -0
  23. autocoder/common/tokens/file_detector.py +105 -0
  24. autocoder/common/tokens/filters.py +111 -0
  25. autocoder/common/tokens/models.py +28 -0
  26. autocoder/common/v2/agent/agentic_edit.py +182 -68
  27. autocoder/common/v2/agent/agentic_edit_types.py +1 -0
  28. autocoder/sdk/cli/handlers.py +2 -1
  29. autocoder/sdk/cli/main.py +4 -2
  30. autocoder/sdk/cli/options.py +4 -3
  31. autocoder/sdk/core/auto_coder_core.py +14 -1
  32. autocoder/sdk/core/bridge.py +3 -0
  33. autocoder/sdk/models/options.py +8 -6
  34. autocoder/version.py +1 -1
  35. {auto_coder-0.1.399.dist-info → auto_coder-0.1.400.dist-info}/WHEEL +0 -0
  36. {auto_coder-0.1.399.dist-info → auto_coder-0.1.400.dist-info}/entry_points.txt +0 -0
  37. {auto_coder-0.1.399.dist-info → auto_coder-0.1.400.dist-info}/licenses/LICENSE +0 -0
  38. {auto_coder-0.1.399.dist-info → auto_coder-0.1.400.dist-info}/top_level.txt +0 -0
@@ -111,6 +111,8 @@ from autocoder.common.conversations.get_conversation_manager import (
111
111
  reset_conversation_manager
112
112
  )
113
113
  from autocoder.common.conversations import ConversationManagerConfig
114
+ from autocoder.common.pull_requests import create_pull_request, detect_platform_from_repo
115
+ from autocoder.common.auto_coder_lang import get_message, get_message_with_format
114
116
 
115
117
 
116
118
  # --- Tool Display Customization is now handled by agentic_tool_display.py ---
@@ -1050,7 +1052,7 @@ class AgenticEdit:
1050
1052
  {% endfor %}
1051
1053
  </user_rule_or_document_files>
1052
1054
 
1053
- Make sure you always start your task by using the read_file tool to get the relevant RULE files listed in index.md based on the user's specific requirements.
1055
+ You should decide based on the user's requirements whether to use the read_file tool to get the relevant files listed in index.md.
1054
1056
  {% endif %}
1055
1057
 
1056
1058
 
@@ -1920,76 +1922,186 @@ class AgenticEdit:
1920
1922
  def apply_changes(self):
1921
1923
  """
1922
1924
  Apply all tracked file changes to the original project directory.
1925
+ """
1926
+ if not self.args.skip_commit:
1927
+ try:
1928
+ file_name = os.path.basename(self.args.file)
1929
+ commit_result = git_utils.commit_changes(
1930
+ self.args.source_dir,
1931
+ f"{self.args.query}\nauto_coder_{file_name}",
1932
+ )
1933
+
1934
+ get_event_manager(self.args.event_file).write_result(
1935
+ EventContentCreator.create_result(
1936
+ content={
1937
+ "have_commit":commit_result.success,
1938
+ "commit_hash":commit_result.commit_hash,
1939
+ "diff_file_num":len(commit_result.changed_files),
1940
+ "event_file":self.args.event_file
1941
+ }), metadata=EventMetadata(
1942
+ action_file=self.args.file,
1943
+ is_streaming=False,
1944
+ path="/agent/edit/apply_changes",
1945
+ stream_out_type="/agent/edit").to_dict())
1946
+
1947
+ action_yml_file_manager = ActionYmlFileManager(
1948
+ self.args.source_dir)
1949
+ action_file_name = os.path.basename(self.args.file)
1950
+ add_updated_urls = []
1951
+ commit_result.changed_files
1952
+ for file in commit_result.changed_files:
1953
+ add_updated_urls.append(
1954
+ os.path.join(self.args.source_dir, file))
1955
+
1956
+ self.args.add_updated_urls = add_updated_urls
1957
+ update_yaml_success = action_yml_file_manager.update_yaml_field(
1958
+ action_file_name, "add_updated_urls", add_updated_urls)
1959
+ if not update_yaml_success:
1960
+ self.printer.print_in_terminal(
1961
+ "yaml_save_error", style="red", yaml_file=action_file_name)
1962
+
1963
+ if self.args.enable_active_context:
1964
+ active_context_manager = ActiveContextManager(
1965
+ self.llm, self.args.source_dir)
1966
+ task_id = active_context_manager.process_changes(
1967
+ self.args)
1968
+ self.printer.print_in_terminal("active_context_background_task",
1969
+ style="blue",
1970
+ task_id=task_id)
1971
+ git_utils.print_commit_info(commit_result=commit_result)
1972
+
1973
+ # 检查是否需要创建 Pull Request
1974
+ if self.conversation_config and self.conversation_config.pull_request:
1975
+ self._create_pull_request(commit_result)
1976
+
1977
+ except Exception as e:
1978
+ self.printer.print_str_in_terminal(
1979
+ str(e),
1980
+ style="red"
1981
+ )
1982
+
1983
+ def _create_pull_request(self, commit_result):
1984
+ """
1985
+ 创建 Pull Request(如果配置启用)
1986
+
1987
+ Args:
1988
+ commit_result: Git commit 结果对象
1923
1989
  """
1924
- diff_file_num = 0
1925
- if self.shadow_manager:
1926
- for (file_path, change) in self.get_all_file_changes().items():
1927
- # Ensure the directory exists before writing the file
1928
- dir_path = os.path.dirname(file_path)
1929
- if dir_path: # Ensure dir_path is not empty (for files in root)
1930
- os.makedirs(dir_path, exist_ok=True)
1931
-
1932
- with open(file_path, 'w', encoding='utf-8') as f:
1933
- f.write(change.content)
1934
- diff_file_num = len(self.get_all_file_changes())
1935
- else:
1936
- changes = self.checkpoint_manager.get_changes_by_group(self.args.event_file)
1937
- diff_file_num = len(changes)
1990
+ try:
1991
+ # 获取当前分支名
1992
+ current_branch = git_utils.get_current_branch(self.args.source_dir)
1993
+ if not current_branch:
1994
+ logger.warning(get_message("/agent/edit/pull_request/branch_name_failed"))
1995
+ return
1938
1996
 
1939
- if diff_file_num > 0:
1940
- if not self.args.skip_commit:
1941
- try:
1942
- file_name = os.path.basename(self.args.file)
1943
- commit_result = git_utils.commit_changes(
1944
- self.args.source_dir,
1945
- f"{self.args.query}\nauto_coder_{file_name}",
1946
- )
1947
-
1948
- get_event_manager(self.args.event_file).write_result(
1949
- EventContentCreator.create_result(
1950
- content={
1951
- "have_commit":commit_result.success,
1952
- "commit_hash":commit_result.commit_hash,
1953
- "diff_file_num":diff_file_num,
1954
- "event_file":self.args.event_file
1955
- }), metadata=EventMetadata(
1956
- action_file=self.args.file,
1957
- is_streaming=False,
1958
- path="/agent/edit/apply_changes",
1959
- stream_out_type="/agent/edit").to_dict())
1960
-
1961
- action_yml_file_manager = ActionYmlFileManager(
1962
- self.args.source_dir)
1963
- action_file_name = os.path.basename(self.args.file)
1964
- add_updated_urls = []
1965
- commit_result.changed_files
1966
- for file in commit_result.changed_files:
1967
- add_updated_urls.append(
1968
- os.path.join(self.args.source_dir, file))
1969
-
1970
- self.args.add_updated_urls = add_updated_urls
1971
- update_yaml_success = action_yml_file_manager.update_yaml_field(
1972
- action_file_name, "add_updated_urls", add_updated_urls)
1973
- if not update_yaml_success:
1974
- self.printer.print_in_terminal(
1975
- "yaml_save_error", style="red", yaml_file=action_file_name)
1976
-
1977
- if self.args.enable_active_context:
1978
- active_context_manager = ActiveContextManager(
1979
- self.llm, self.args.source_dir)
1980
- task_id = active_context_manager.process_changes(
1981
- self.args)
1982
- self.printer.print_in_terminal("active_context_background_task",
1983
- style="blue",
1984
- task_id=task_id)
1985
- git_utils.print_commit_info(commit_result=commit_result)
1986
- except Exception as e:
1987
- self.printer.print_str_in_terminal(
1988
- self.git_require_msg(
1989
- source_dir=self.args.source_dir, error=str(e)),
1990
- style="red"
1991
- )
1997
+ # 准备 PR 标题和描述
1998
+ query = self.args.query or get_message("/agent/edit/pull_request/default_query")
1999
+ pr_title = get_message_with_format("/agent/edit/pull_request/title", query=query[0:40])
2000
+
2001
+ # 构建 PR 描述
2002
+ file_list = ""
2003
+ if commit_result.changed_files:
2004
+ for file_path in commit_result.changed_files:
2005
+ file_list += f"- `{file_path}`\n"
1992
2006
 
2007
+ pr_description = get_message_with_format(
2008
+ "/agent/edit/pull_request/description",
2009
+ query=query,
2010
+ file_count=len(commit_result.changed_files or []),
2011
+ commit_hash=commit_result.commit_hash,
2012
+ file_list=file_list.strip(),
2013
+ source_branch=current_branch,
2014
+ target_branch="main",
2015
+ timestamp=time.strftime('%Y-%m-%d %H:%M:%S')
2016
+ )
2017
+
2018
+ # 创建 Pull Request
2019
+ logger.info(get_message_with_format("/agent/edit/pull_request/creating", title=pr_title))
2020
+
2021
+ result = create_pull_request(
2022
+ repo_path=self.args.source_dir,
2023
+ title=pr_title,
2024
+ description=pr_description,
2025
+ )
2026
+
2027
+ if result.success:
2028
+ logger.info(get_message("/agent/edit/pull_request/success"))
2029
+ logger.info(f"PR URL: {result.pr_url}")
2030
+ logger.info(f"PR 编号: {result.pr_number}")
2031
+
2032
+ # 打印成功信息到终端
2033
+ self.printer.print_str_in_terminal(
2034
+ get_message("/agent/edit/pull_request/success"),
2035
+ style="green"
2036
+ )
2037
+ self.printer.print_str_in_terminal(f"PR URL: {result.pr_url}")
2038
+ self.printer.print_str_in_terminal(f"PR 编号: {result.pr_number}")
2039
+
2040
+ # 写入事件日志
2041
+ get_event_manager(self.args.event_file).write_result(
2042
+ EventContentCreator.create_result(
2043
+ content={
2044
+ "success": True,
2045
+ "pr_url": result.pr_url,
2046
+ "pr_number": result.pr_number,
2047
+ "source_branch": current_branch,
2048
+ "target_branch": "main",
2049
+ "platform": result.platform.value if result.platform else "unknown"
2050
+ }),
2051
+ metadata=EventMetadata(
2052
+ action_file=self.args.file,
2053
+ is_streaming=False,
2054
+ path="/agent/edit/pull_request_created",
2055
+ stream_out_type="/agent/edit"
2056
+ ).to_dict()
2057
+ )
2058
+
2059
+ else:
2060
+ error_msg = get_message_with_format("/agent/edit/pull_request/failed", error=result.error_message)
2061
+ logger.error(error_msg)
2062
+
2063
+ # 打印错误信息到终端
2064
+ self.printer.print_str_in_terminal(error_msg, style="red")
2065
+
2066
+ # 写入错误事件日志
2067
+ get_event_manager(self.args.event_file).write_error(
2068
+ EventContentCreator.create_error(
2069
+ error_code="PR_CREATION_FAILED",
2070
+ error_message=result.error_message,
2071
+ details={
2072
+ "source_branch": current_branch,
2073
+ "target_branch": "main"
2074
+ }
2075
+ ).to_dict(),
2076
+ metadata=EventMetadata(
2077
+ action_file=self.args.file,
2078
+ is_streaming=False,
2079
+ path="/agent/edit/pull_request_error",
2080
+ stream_out_type="/agent/edit"
2081
+ ).to_dict()
2082
+ )
2083
+
2084
+ except Exception as e:
2085
+ error_msg = get_message_with_format("/agent/edit/pull_request/exception", error=str(e))
2086
+ logger.exception(error_msg)
2087
+
2088
+ # 打印异常信息到终端
2089
+ self.printer.print_str_in_terminal(error_msg, style="red")
2090
+
2091
+ # 写入异常事件日志
2092
+ get_event_manager(self.args.event_file).write_error(
2093
+ EventContentCreator.create_error(
2094
+ error_code="PR_CREATION_EXCEPTION",
2095
+ error_message=get_message_with_format("/agent/edit/pull_request/exception", error=str(e)),
2096
+ details={"exception_type": type(e).__name__}
2097
+ ).to_dict(),
2098
+ metadata=EventMetadata(
2099
+ action_file=self.args.file,
2100
+ is_streaming=False,
2101
+ path="/agent/edit/pull_request_exception",
2102
+ stream_out_type="/agent/edit"
2103
+ ).to_dict()
2104
+ )
1993
2105
 
1994
2106
  def run_in_terminal(self, request: AgenticEditRequest):
1995
2107
  """
@@ -2239,6 +2351,8 @@ class AgenticEdit:
2239
2351
  try:
2240
2352
  event_stream = self.analyze(request)
2241
2353
  for agent_event in event_stream:
2354
+ if isinstance(agent_event, CompletionEvent):
2355
+ self.apply_changes()
2242
2356
  yield agent_event
2243
2357
 
2244
2358
  except Exception as e:
@@ -187,3 +187,4 @@ class AgenticEditConversationConfig(BaseModel):
187
187
  conversation_id: Optional[str] = None
188
188
  action: Optional[str] = None
189
189
  query: Optional[str] = None
190
+ pull_request: bool = False
@@ -49,7 +49,8 @@ class CommandHandler:
49
49
  stream=self.options.output_format.startswith("stream"),
50
50
  session_id=self.options.resume_session,
51
51
  continue_session=self.options.continue_session,
52
- model=self.options.model
52
+ model=self.options.model,
53
+ pr=self.options.pr
53
54
  )
54
55
 
55
56
  def _get_prompt(self) -> str:
autocoder/sdk/cli/main.py CHANGED
@@ -115,12 +115,13 @@ class AutoCoderCLI:
115
115
 
116
116
  # 高级选项
117
117
  advanced = parser.add_argument_group("高级选项")
118
- advanced.add_argument("--max-turns", type=int, default=3, help="最大对话轮数 (默认: 3)")
118
+ advanced.add_argument("--max-turns", type=int, default= -1, help="最大对话轮数 (默认: -1 不限制)")
119
119
  advanced.add_argument("--system-prompt", help="系统提示")
120
120
  advanced.add_argument("--allowed-tools", nargs="+", help="允许使用的工具列表")
121
121
  advanced.add_argument("--permission-mode", choices=["manual", "acceptEdits"],
122
122
  default="manual", help="权限模式 (默认: manual)")
123
123
  advanced.add_argument("--model", required=True, help="指定使用的模型名称 (如: gpt-4, gpt-3.5-turbo, claude-3-sonnet 等)")
124
+ advanced.add_argument("--pr", action="store_true", help="创建 Pull Request")
124
125
 
125
126
  # 启用自动补全
126
127
  if ARGCOMPLETE_AVAILABLE:
@@ -143,7 +144,8 @@ class AutoCoderCLI:
143
144
  system_prompt=parsed_args.system_prompt,
144
145
  allowed_tools=parsed_args.allowed_tools or [],
145
146
  permission_mode=parsed_args.permission_mode,
146
- model=parsed_args.model
147
+ model=parsed_args.model,
148
+ pr=parsed_args.pr
147
149
  )
148
150
 
149
151
  return options
@@ -32,6 +32,7 @@ class CLIOptions:
32
32
  allowed_tools: list = field(default_factory=list) # 允许使用的工具列表
33
33
  permission_mode: str = "manual" # 权限模式,可选值: manual, acceptEdits
34
34
  model: Optional[str] = None # 模型名称,如 gpt-4, gpt-3.5-turbo 等
35
+ pr: bool = False # 是否创建 PR
35
36
 
36
37
  def validate(self) -> None:
37
38
  """验证选项的有效性。"""
@@ -49,9 +50,9 @@ class CLIOptions:
49
50
  if self.permission_mode not in valid_permission_modes:
50
51
  raise ValueError(f"无效的权限模式: {self.permission_mode},有效值为: {', '.join(valid_permission_modes)}")
51
52
 
52
- # 验证最大对话轮数
53
- if self.max_turns <= 0:
54
- raise ValueError("max_turns必须为正数")
53
+ # 验证最大对话轮数(-1表示不限制)
54
+ if self.max_turns <= 0 and self.max_turns != -1:
55
+ raise ValueError("max_turns必须为正数或-1(表示不限制)")
55
56
 
56
57
  # 验证会话选项的互斥性
57
58
  if self.continue_session and self.resume_session:
@@ -656,6 +656,7 @@ class AutoCoderCore:
656
656
  self,
657
657
  prompt: str,
658
658
  pre_commit: bool = False,
659
+ pr: Optional[bool] = None,
659
660
  extra_args: Optional[Dict[str, Any]] = None,
660
661
  show_terminal: bool = True
661
662
  ) -> CodeModificationResult:
@@ -665,6 +666,7 @@ class AutoCoderCore:
665
666
  Args:
666
667
  prompt: 修改提示
667
668
  pre_commit: 是否预提交
669
+ pr: 是否创建 PR,如果为None则使用配置中的值
668
670
  extra_args: 额外参数
669
671
  show_terminal: 是否显示到终端
670
672
 
@@ -677,7 +679,8 @@ class AutoCoderCore:
677
679
 
678
680
  event_stream = self._sync_run_auto_command(
679
681
  prompt,
680
- pre_commit=pre_commit,
682
+ pre_commit=pre_commit,
683
+ pr=pr,
681
684
  extra_args=extra_args
682
685
  )
683
686
 
@@ -746,6 +749,7 @@ class AutoCoderCore:
746
749
  self,
747
750
  prompt: str,
748
751
  pre_commit: bool = False,
752
+ pr: Optional[bool] = None,
749
753
  extra_args: Optional[Dict[str, Any]] = None,
750
754
  show_terminal: bool = True
751
755
  ) -> AsyncIterator[StreamEvent]:
@@ -755,6 +759,7 @@ class AutoCoderCore:
755
759
  Args:
756
760
  prompt: 修改提示
757
761
  pre_commit: 是否预提交
762
+ pr: 是否创建 PR,如果为None则使用配置中的值
758
763
  extra_args: 额外参数
759
764
  show_terminal: 是否显示到终端
760
765
 
@@ -773,6 +778,7 @@ class AutoCoderCore:
773
778
  self._sync_run_auto_command,
774
779
  prompt,
775
780
  pre_commit,
781
+ pr,
776
782
  extra_args
777
783
  )
778
784
 
@@ -808,6 +814,7 @@ class AutoCoderCore:
808
814
  self,
809
815
  prompt: str,
810
816
  pre_commit: bool = False,
817
+ pr: Optional[bool] = None,
811
818
  extra_args: Optional[Dict[str, Any]] = None
812
819
  ) -> Iterator[StreamEvent]:
813
820
  """
@@ -816,14 +823,20 @@ class AutoCoderCore:
816
823
  Args:
817
824
  prompt: 查询提示
818
825
  pre_commit: 是否预提交
826
+ pr: 是否创建 PR,如果为None则使用配置中的值
819
827
  extra_args: 额外参数
820
828
 
821
829
  Returns:
822
830
  Iterator[StreamEvent]: 事件流
823
831
  """
832
+ # 如果没有明确指定pr参数,使用配置中的值
833
+ if pr is None:
834
+ pr = self.options.pr
835
+
824
836
  return self.bridge.call_run_auto_command(
825
837
  query=prompt,
826
838
  pre_commit=pre_commit,
839
+ pr=pr,
827
840
  extra_args=extra_args or {},
828
841
  stream=True
829
842
  )
@@ -65,6 +65,7 @@ class AutoCoderBridge:
65
65
  self,
66
66
  query: str,
67
67
  pre_commit: bool = False,
68
+ pr: bool = False,
68
69
  extra_args: Optional[Dict[str, Any]] = None,
69
70
  stream: bool = True
70
71
  ) -> Iterator[StreamEvent]:
@@ -74,6 +75,7 @@ class AutoCoderBridge:
74
75
  Args:
75
76
  query: 查询内容
76
77
  pre_commit: 是否预提交
78
+ pr: 是否预提交
77
79
  extra_args: 额外参数
78
80
  stream: 是否流式返回
79
81
 
@@ -103,6 +105,7 @@ class AutoCoderBridge:
103
105
  events = run_auto_command(
104
106
  query=query,
105
107
  pre_commit=pre_commit,
108
+ pr=pr,
106
109
  extra_args=extra_args
107
110
  )
108
111
 
@@ -52,6 +52,7 @@ class AutoCodeOptions:
52
52
  timeout: int = 30
53
53
  verbose: bool = False
54
54
  include_project_structure: bool = True
55
+ pr: bool = False # 是否创建 PR
55
56
 
56
57
  def __post_init__(self):
57
58
  """初始化后验证"""
@@ -61,12 +62,12 @@ class AutoCodeOptions:
61
62
  def validate(self) -> None:
62
63
  """验证配置选项"""
63
64
 
64
- # 验证max_turns
65
- if self.max_turns <= 0:
66
- raise ValidationError("max_turns", "must be positive integer")
65
+ # 验证max_turns(-1表示不限制)
66
+ if self.max_turns <= 0 and self.max_turns != -1:
67
+ raise ValidationError("max_turns", "must be positive integer or -1 (unlimited)")
67
68
 
68
- if self.max_turns > 100:
69
- raise ValidationError("max_turns", "cannot exceed 100")
69
+ if self.max_turns > 100 and self.max_turns != -1:
70
+ raise ValidationError("max_turns", "cannot exceed 100 (unless -1 for unlimited)")
70
71
 
71
72
  # 验证output_format
72
73
  if self.output_format not in OUTPUT_FORMATS:
@@ -140,7 +141,8 @@ class AutoCodeOptions:
140
141
  "temperature": self.temperature,
141
142
  "timeout": self.timeout,
142
143
  "verbose": self.verbose,
143
- "include_project_structure": self.include_project_structure
144
+ "include_project_structure": self.include_project_structure,
145
+ "pr": self.pr
144
146
  }
145
147
 
146
148
  @classmethod
autocoder/version.py CHANGED
@@ -1,2 +1,2 @@
1
- __version__ = "0.1.399"
1
+ __version__ = "0.1.400"
2
2