auto-coder 0.1.359__py3-none-any.whl → 0.1.361__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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: auto-coder
3
- Version: 0.1.359
3
+ Version: 0.1.361
4
4
  Summary: AutoCoder: AutoCoder
5
5
  Author: allwefantasy
6
6
  Classifier: Programming Language :: Python :: 3.10
@@ -1,5 +1,5 @@
1
1
  autocoder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- autocoder/auto_coder.py,sha256=cXORqFnZ_wNSVJXs7nrt0tLR_ystIIBj3TVrhTgNlyQ,66919
2
+ autocoder/auto_coder.py,sha256=PjMhyZCMm8HFG9BAvj6xwQ4DoMielPRvzOVS3oa1ZTk,67060
3
3
  autocoder/auto_coder_lang.py,sha256=Rtupq6N3_HT7JRhDKdgCBcwRaiAnyCOR_Gsp4jUomrI,3229
4
4
  autocoder/auto_coder_rag.py,sha256=ru5o86IaKylyVRlVORmnrdf3Q1To2eWi2KLdT9FMW0k,37580
5
5
  autocoder/auto_coder_rag_client_mcp.py,sha256=QRxUbjc6A8UmDMQ8lXgZkjgqtq3lgKYeatJbDY6rSo0,6270
@@ -14,7 +14,7 @@ autocoder/command_parser.py,sha256=fx1g9E6GaM273lGTcJqaFQ-hoksS_Ik2glBMnVltPCE,1
14
14
  autocoder/lang.py,sha256=PFtATuOhHRnfpqHQkXr6p4C893JvpsgwTMif3l-GEi0,14321
15
15
  autocoder/models.py,sha256=Gu50IATQtZtgEir1PpCfwgH6o4ygw6XqqbQRj3lx5dU,13798
16
16
  autocoder/run_context.py,sha256=IUfSO6_gp2Wt1blFWAmOpN0b0nDrTTk4LmtCYUBIoro,1643
17
- autocoder/version.py,sha256=kubSVhGu19jZ8JzGmXTOr05JRqWtxaCOHwlbz49NIwg,23
17
+ autocoder/version.py,sha256=-eHH-Zoj_ykjiLWosogiY77V86O55hXvZbTnLHM8u8A,23
18
18
  autocoder/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
19
  autocoder/agent/agentic_edit.py,sha256=XsfePZ-t6M-uBSdG1VLZXk1goqXk2HPeJ_A8IYyBuWQ,58896
20
20
  autocoder/agent/agentic_edit_types.py,sha256=oFcDd_cxJ2yH9Ed1uTpD3BipudgoIEWDMPb5pAkq4gI,3288
@@ -24,7 +24,7 @@ autocoder/agent/auto_filegroup.py,sha256=pBsAkBcpFTff-9L5OwI8xhf2xPKpl-aZwz-skF2
24
24
  autocoder/agent/auto_guess_query.py,sha256=rDSdhpPHcOGE5MuDXvIrhCXAPR4ARS1LqpyoLsx2Jhw,11374
25
25
  autocoder/agent/auto_learn.py,sha256=uNpfvE_EYGi79KUJEe7g-j5VanbmYOYYnxWf32DaWGE,22359
26
26
  autocoder/agent/auto_learn_from_commit.py,sha256=edD4GQJyO2qvVnTKyldeswWoNeKe1Aaua6ieJzlGlFI,10662
27
- autocoder/agent/auto_review_commit.py,sha256=gumITezGCztu70T7sSt5KBCFQREAchirApShnIvhC98,10913
27
+ autocoder/agent/auto_review_commit.py,sha256=1z9FOUDPZTWnrPmJ-TwUlXLOTDPmRcAlYqXbUj1pi08,11015
28
28
  autocoder/agent/auto_tool.py,sha256=DBzip-P_T6ZtT2eHexPcusmKYD0h7ufzp7TLwXAY10E,11554
29
29
  autocoder/agent/coder.py,sha256=x6bdJwDuETGg9ebQnYlUWCxCtQcDGg73LtI6McpWslQ,72034
30
30
  autocoder/agent/designer.py,sha256=EpRbzO58Xym3GrnppIT1Z8ZFAlnNfgzHbIzZ3PX-Yv8,27037
@@ -64,10 +64,10 @@ autocoder/common/buildin_tokenizer.py,sha256=L7d5t39ZFvUd6EoMPXUhYK1toD0FHlRH1jt
64
64
  autocoder/common/chunk_validation.py,sha256=BrR_ZWavW8IANuueEE7hS8NFAwEvm8TX34WnPx_1hs8,3030
65
65
  autocoder/common/cleaner.py,sha256=NU72i8C6o9m0vXExab7nao5bstBUsfJFcj11cXa9l4U,1089
66
66
  autocoder/common/code_auto_execute.py,sha256=4KXGmiGObr_B1d6tzV9dwS6MifCSc3Gm4j2d6ildBXQ,6867
67
- autocoder/common/code_auto_generate.py,sha256=0TuyfWdWeddBlgCzPC3JtJnYGBWa8idgSC6Oe3AXRz4,11634
68
- autocoder/common/code_auto_generate_diff.py,sha256=Pq7Q4ccjIMRkJ33krKejfRBw7DD6YMs5ap7q6x50awM,18528
69
- autocoder/common/code_auto_generate_editblock.py,sha256=wvKWBn_46u6j-ZoNAW6S2TZp3EvDPTnhhfEH95Z3TsM,21240
70
- autocoder/common/code_auto_generate_strict_diff.py,sha256=5q5VUwI-kngIHO76B125yGDfuPLmwxBA0gHKfTymjSk,17411
67
+ autocoder/common/code_auto_generate.py,sha256=6O7QiJe7514GCGuy4z-udzA2_h7TxEWHaJG7VyoCSSA,12151
68
+ autocoder/common/code_auto_generate_diff.py,sha256=WwMystn0cEFQMUKhIUa5EmNPzvnUMjKiPFpDb1nFb1A,19196
69
+ autocoder/common/code_auto_generate_editblock.py,sha256=JmnHqtt346hFFcLh-vb7_JYzb3PAsNCQZh2Owea9mVI,21906
70
+ autocoder/common/code_auto_generate_strict_diff.py,sha256=NSx1RYtNEQX2qFk1TfJlcTxiUB8Q4-PUxXk9TDV1-ak,18068
71
71
  autocoder/common/code_auto_merge.py,sha256=WaU-T-ZVn3QDaA_SrdkHciUPKDcTfVa-IbhHKBYEv5w,9961
72
72
  autocoder/common/code_auto_merge_diff.py,sha256=DcljWrtlejq2cb9Gj-jBjvUQzRbCE2uMNGg8SBOhEnk,19271
73
73
  autocoder/common/code_auto_merge_editblock.py,sha256=5PLH8Ey4GYsPNMGn36pSy_IgwgZ8-j1QF5FEv-THC-0,18397
@@ -121,8 +121,11 @@ autocoder/common/conversations/__init__.py,sha256=xGZeOFrDsgg2fkPK1zmvYBDhAyX66F
121
121
  autocoder/common/conversations/compatibility.py,sha256=WuBXB4-dw5X9LUMsB16VWbihvRZQ1tT99m6zuBwDfqE,9606
122
122
  autocoder/common/conversations/conversation_manager.py,sha256=ZhuhfSdOTncqgy3nHPoEU7Cg0dCsSl-VPcvLbUlL2Tk,18295
123
123
  autocoder/common/conversations/example.py,sha256=Pz_EhO6qneUFMfHZiDmGAClZ6b0V4T1sbC8tIMxX2RM,5437
124
+ autocoder/common/directory_cache/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
125
+ autocoder/common/directory_cache/cache.py,sha256=Jknygb_U6DkF04_SX04IwsOcQdd-2QQ4d6k9Ucc9OZ0,9358
126
+ autocoder/common/directory_cache/test_cache.py,sha256=0iQkHaZQPhZBwSS6dwK_je93QMLbYGY0BYrTSt45Cao,6610
124
127
  autocoder/common/file_monitor/__init__.py,sha256=9reL3IEnyLWU77WjPzeprM8-4lCetlSMZ94Nuxk5KNg,85
125
- autocoder/common/file_monitor/monitor.py,sha256=lnav8TkNHEK_XqQGWpHIrw6l0U5s99ZoB94NH1AEHa4,16623
128
+ autocoder/common/file_monitor/monitor.py,sha256=biS9TJyNKga2dE-CeYAi9xfXvA9aMeMl0tBf68G-SBE,16609
126
129
  autocoder/common/ignorefiles/__init__.py,sha256=P0hq7Avu1IeXBYEkPBZLsJhFzhzyktUWTqaRIXiAFLY,75
127
130
  autocoder/common/ignorefiles/ignore_file_utils.py,sha256=H1gUjjYLHZ_4GZel9bN5lEgpTlOyfPdIhyNRqd7no4c,3484
128
131
  autocoder/common/ignorefiles/test_ignore_file_utils.py,sha256=EydHG6E2iPsnbt-Jt8Go-WvRgFtBW6QkHUQ9nI4cF-w,3111
@@ -133,10 +136,10 @@ autocoder/common/rulefiles/__init__.py,sha256=babSbPdFaXk1NvdHtH2zrJLb_tWd7d2ELI
133
136
  autocoder/common/rulefiles/autocoderrules_utils.py,sha256=JsB0BkdyygbTOEBfaAB2WA4RFU6Q3VamaFncmbbiLRE,10011
134
137
  autocoder/common/v2/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
135
138
  autocoder/common/v2/code_agentic_editblock_manager.py,sha256=pAh918YMgmLenXmNKXlmDPgKyVJjOuk69901VEEQHm4,34980
136
- autocoder/common/v2/code_auto_generate.py,sha256=hdhTTb0r1A8_OSuUIkxSXrwf47pXnazphufMu1vpkhI,9327
137
- autocoder/common/v2/code_auto_generate_diff.py,sha256=NwoPSpUQxD8zXl-RIqoE7tJIJ2_qQdJvowvyCqjGeH0,15093
138
- autocoder/common/v2/code_auto_generate_editblock.py,sha256=VaBvhMg_ryEataxM_n0L08FN_LI1Wfjoq4ecXs9jZwQ,15059
139
- autocoder/common/v2/code_auto_generate_strict_diff.py,sha256=HYAeUQjxh_AKAArCuk3-j--7QUa0J8ewDOemuIHfenk,17434
139
+ autocoder/common/v2/code_auto_generate.py,sha256=PAySLU8ZnpdF8GelwSCiEbzv7sBbn-Vhakinf4i6udE,11646
140
+ autocoder/common/v2/code_auto_generate_diff.py,sha256=RWMJHxpQyD86ZOw0yYBFlKJLRsrrAWwRLJwu2rHfNXU,15213
141
+ autocoder/common/v2/code_auto_generate_editblock.py,sha256=qgTPox-0gLeNjzenzBM0B83Z-nzxYtT5BDCvllPLqps,15720
142
+ autocoder/common/v2/code_auto_generate_strict_diff.py,sha256=dbGyjBYWvjl_xT27Zxaq6Cgl7JuPZwYEGngPAyq3j9g,18066
140
143
  autocoder/common/v2/code_auto_merge.py,sha256=FZHrIZyFUkFmv4EbproXfIIUfGx_L3EPfvjldsYlplI,9345
141
144
  autocoder/common/v2/code_auto_merge_diff.py,sha256=DcljWrtlejq2cb9Gj-jBjvUQzRbCE2uMNGg8SBOhEnk,19271
142
145
  autocoder/common/v2/code_auto_merge_editblock.py,sha256=rVohrpjTzgvWEX09GNRAQ0fbjjNjcxeP1bqczhFT8F8,20741
@@ -146,7 +149,7 @@ autocoder/common/v2/code_editblock_manager.py,sha256=DMwJw-FAM6VyaBQV3p4xespHpgZ
146
149
  autocoder/common/v2/code_manager.py,sha256=C403bS-f6urixwitlKHcml-J03hci-UyNwHJOqBiY6Q,9182
147
150
  autocoder/common/v2/code_strict_diff_manager.py,sha256=Bys7tFAq4G03R1zUZuxrszBTvP4QB96jIw2y5BDLyRM,9424
148
151
  autocoder/common/v2/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
149
- autocoder/common/v2/agent/agentic_edit.py,sha256=BY31ZsniFydN7sncDNQUmAkMJFT-4mhTcnzsmuRMPTM,98524
152
+ autocoder/common/v2/agent/agentic_edit.py,sha256=qS-wwyzxsCVTZOCyFdX1bGeLKpbT_lkO2O2FOaU2_4s,98891
150
153
  autocoder/common/v2/agent/agentic_edit_conversation.py,sha256=pFgWPWHKhZ4J9EcFmIdiGsrSolTZuYcH1qkgKdD8nwk,7726
151
154
  autocoder/common/v2/agent/agentic_edit_types.py,sha256=VJMrictg6hJ3mC45VgQGRd43DyDUPDUvPV1Rf3z72NI,4776
152
155
  autocoder/common/v2/agent/agentic_tool_display.py,sha256=WKirt-2V346KLnbHgH3NVJiK3xvriD9oaCWj2IdvzLU,7309
@@ -307,9 +310,9 @@ autocoder/utils/types.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
307
310
  autocoder/utils/auto_coder_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
308
311
  autocoder/utils/auto_coder_utils/chat_stream_out.py,sha256=t902pKxQ5xM7zgIHiAOsTPLwxhE6VuvXAqPy751S7fg,14096
309
312
  autocoder/utils/chat_auto_coder_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
310
- auto_coder-0.1.359.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
311
- auto_coder-0.1.359.dist-info/METADATA,sha256=WP-yHh87MG8JU0Akq0ILfiyBqqG-hrbB_0wpXZkL2gA,2751
312
- auto_coder-0.1.359.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
313
- auto_coder-0.1.359.dist-info/entry_points.txt,sha256=0nzHtHH4pNcM7xq4EBA2toS28Qelrvcbrr59GqD_0Ak,350
314
- auto_coder-0.1.359.dist-info/top_level.txt,sha256=Jqc0_uJSw2GwoFQAa9iJxYns-2mWla-9ok_Y3Gcznjk,10
315
- auto_coder-0.1.359.dist-info/RECORD,,
313
+ auto_coder-0.1.361.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
314
+ auto_coder-0.1.361.dist-info/METADATA,sha256=HIhJ-9ho4w9uArb53Llorxzoeqn99ge5WW9HItR2t9U,2751
315
+ auto_coder-0.1.361.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
316
+ auto_coder-0.1.361.dist-info/entry_points.txt,sha256=0nzHtHH4pNcM7xq4EBA2toS28Qelrvcbrr59GqD_0Ak,350
317
+ auto_coder-0.1.361.dist-info/top_level.txt,sha256=Jqc0_uJSw2GwoFQAa9iJxYns-2mWla-9ok_Y3Gcznjk,10
318
+ auto_coder-0.1.361.dist-info/RECORD,,
@@ -47,7 +47,7 @@ class AutoReviewCommit:
47
47
  @byzerllm.prompt()
48
48
  def review(self, querie_with_urls_and_changes: List[Tuple[str, List[str], Dict[str, Tuple[str, str]]]], query: str) -> Generator[str,None,None]:
49
49
  """
50
- 如果前面我们对话提供了文档,请参考上面的文档对提交的代码变更进行审查,提供改进建议。
50
+ 如果前面我们对话提供了文档,请参考上面的文档对提交的代码变更进行审查,提供改进建议,你所有的输出都要以markdown语法输出。
51
51
 
52
52
  下面包含最新一次提交的信息:
53
53
  <commit>
@@ -96,7 +96,7 @@ class AutoReviewCommit:
96
96
  - 依赖关系:组件耦合是否合理
97
97
  - 复用性:是否有重复代码
98
98
 
99
- 评审结果包含以下内容(以美观易于阅读的Markdown格式输出):
99
+ 评审结果包含以下内容
100
100
  1. issues: 发现的具体问题列表
101
101
  3. severity: 问题的严重程度(low/medium/high),从高到底进行描述。
102
102
  4. suggestions: 对应的改进建议列表
@@ -115,7 +115,9 @@ class AutoReviewCommit:
115
115
  1. 评审意见应该具体且可操作,而不是泛泛而谈
116
116
  2. 对于每个问题都应该提供明确的改进建议
117
117
  3. 严重程度的判断要考虑问题对系统的潜在影响
118
- 4. 建议应该符合项目的技术栈和开发规范
118
+ 4. 建议应该符合项目的技术栈和开发规范
119
+
120
+ 注意,请以「纯 Markdown」输出,不要出现 <markdown>、</markdown> 之类标签。
119
121
  """
120
122
  return {}
121
123
 
autocoder/auto_coder.py CHANGED
@@ -52,7 +52,7 @@ from autocoder.common.mcp_server_types import (
52
52
  McpRequest, McpInstallRequest, McpRemoveRequest, McpListRequest,
53
53
  McpListRunningRequest, McpRefreshRequest
54
54
  )
55
-
55
+ from autocoder.run_context import get_run_context,RunMode
56
56
  console = Console()
57
57
 
58
58
 
@@ -438,7 +438,7 @@ def main(input_args: Optional[List[str]] = None):
438
438
  llm.setup_sub_client("index_filter_model", index_filter_model)
439
439
 
440
440
 
441
- if args.human_as_model:
441
+ if get_run_context().mode != RunMode.WEB and args.human_as_model:
442
442
 
443
443
  def intercept_callback(
444
444
  llm, model: str, input_value: List[Dict[str, Any]]
@@ -1157,7 +1157,7 @@ def main(input_args: Optional[List[str]] = None):
1157
1157
  loaded_conversations = pre_conversations + \
1158
1158
  chat_history["ask_conversation"]
1159
1159
 
1160
- if args.human_as_model:
1160
+ if get_run_context().mode != RunMode.WEB and args.human_as_model:
1161
1161
  console = Console()
1162
1162
 
1163
1163
  @byzerllm.prompt()
@@ -17,7 +17,7 @@ from autocoder.utils import llms as llm_utils
17
17
  from autocoder.common import SourceCodeList
18
18
  from autocoder.privacy.model_filter import ModelPathFilter
19
19
  from autocoder.memory.active_context_manager import ActiveContextManager
20
-
20
+ from autocoder.run_context import get_run_context,RunMode
21
21
 
22
22
  class CodeAutoGenerate:
23
23
  def __init__(
@@ -59,16 +59,19 @@ class CodeAutoGenerate:
59
59
  ) -> str:
60
60
  """
61
61
  {%- if structure %}
62
+ ====
62
63
  {{ structure }}
63
64
  {%- endif %}
64
65
 
65
66
  {%- if content %}
67
+ ====
66
68
  下面是一些文件路径以及每个文件对应的源码:
67
69
 
68
70
  {{ content }}
69
71
  {%- endif %}
70
72
 
71
73
  {%- if package_context %}
74
+ ====
72
75
  下面是上面文件的一些信息(包括最近的变更情况):
73
76
  <package_context>
74
77
  {{ package_context }}
@@ -76,9 +79,27 @@ class CodeAutoGenerate:
76
79
  {%- endif %}
77
80
 
78
81
  {%- if context %}
82
+ ====
79
83
  {{ context }}
80
84
  {%- endif %}
81
85
 
86
+ {%- if extra_docs %}
87
+ ====
88
+
89
+ RULES PROVIDED BY USER
90
+
91
+ The following rules are provided by the user, and you must follow them strictly.
92
+
93
+ {% for key, value in extra_docs.items() %}
94
+ <user_rule>
95
+ ##File: {{ key }}
96
+ {{ value }}
97
+ </user_rule>
98
+ {% endfor %}
99
+ {% endif %}
100
+
101
+ ====
102
+
82
103
  下面是用户的需求:
83
104
 
84
105
  {{ instruction }}
@@ -190,7 +211,7 @@ class CodeAutoGenerate:
190
211
  generate_mode="wholefile"
191
212
  )
192
213
 
193
- if not self.args.human_as_model:
214
+ if not self.args.human_as_model or get_run_context().mode == RunMode.WEB:
194
215
  with ThreadPoolExecutor(max_workers=len(self.llms) * self.generate_times_same_model) as executor:
195
216
  futures = []
196
217
  count = 0
@@ -16,6 +16,8 @@ from autocoder.rag.token_counter import count_tokens
16
16
  from autocoder.utils import llms as llm_utils
17
17
  from autocoder.common import SourceCodeList
18
18
  from autocoder.memory.active_context_manager import ActiveContextManager
19
+ from autocoder.common.rulefiles.autocoderrules_utils import get_rules
20
+ from autocoder.run_context import get_run_context,RunMode
19
21
 
20
22
  class CodeAutoGenerateDiff:
21
23
  def __init__(
@@ -135,10 +137,12 @@ class CodeAutoGenerateDiff:
135
137
  现在让我们开始一个新的任务:
136
138
 
137
139
  {%- if structure %}
140
+ ====
138
141
  {{ structure }}
139
142
  {%- endif %}
140
143
 
141
144
  {%- if content %}
145
+ ====
142
146
  下面是一些文件路径以及每个文件对应的源码:
143
147
  <files>
144
148
  {{ content }}
@@ -146,6 +150,7 @@ class CodeAutoGenerateDiff:
146
150
  {%- endif %}
147
151
 
148
152
  {%- if package_context %}
153
+ ====
149
154
  下面是上面文件的一些信息(包括最近的变更情况):
150
155
  <package_context>
151
156
  {{ package_context }}
@@ -153,11 +158,29 @@ class CodeAutoGenerateDiff:
153
158
  {%- endif %}
154
159
 
155
160
  {%- if context %}
161
+ ====
156
162
  <extra_context>
157
163
  {{ context }}
158
164
  </extra_context>
159
165
  {%- endif %}
160
166
 
167
+ {%- if extra_docs %}
168
+ ====
169
+
170
+ RULES PROVIDED BY USER
171
+
172
+ The following rules are provided by the user, and you must follow them strictly.
173
+
174
+ {% for key, value in extra_docs.items() %}
175
+ <user_rule>
176
+ ##File: {{ key }}
177
+ {{ value }}
178
+ </user_rule>
179
+ {% endfor %}
180
+ {% endif %}
181
+
182
+ ====
183
+
161
184
  下面是用户的需求:
162
185
 
163
186
  {{ instruction }}
@@ -169,13 +192,15 @@ class CodeAutoGenerateDiff:
169
192
  return {
170
193
  "structure": ""
171
194
  }
172
-
195
+
196
+ extra_docs = get_rules()
173
197
  return {
174
198
  "structure": (
175
199
  self.action.pp.get_tree_like_directory_structure()
176
200
  if self.action
177
201
  else ""
178
- )
202
+ ),
203
+ "extra_docs": extra_docs,
179
204
  }
180
205
 
181
206
  @byzerllm.prompt(llm=lambda self: self.llm)
@@ -380,7 +405,7 @@ class CodeAutoGenerateDiff:
380
405
  generate_mode="diff"
381
406
  )
382
407
 
383
- if not self.args.human_as_model:
408
+ if not self.args.human_as_model or get_run_context().mode == RunMode.WEB:
384
409
  with ThreadPoolExecutor(max_workers=len(self.llms) * self.generate_times_same_model) as executor:
385
410
  futures = []
386
411
  count = 0
@@ -20,8 +20,8 @@ from autocoder.rag.token_counter import count_tokens
20
20
  from autocoder.utils import llms as llm_utils
21
21
  from autocoder.common import SourceCodeList
22
22
  from autocoder.memory.active_context_manager import ActiveContextManager
23
-
24
-
23
+ from autocoder.common.rulefiles.autocoderrules_utils import get_rules
24
+ from autocoder.run_context import get_run_context,RunMode
25
25
 
26
26
  class CodeAutoGenerateEditBlock:
27
27
  def __init__(
@@ -188,10 +188,12 @@ class CodeAutoGenerateEditBlock:
188
188
  现在让我们开始一个新的任务:
189
189
 
190
190
  {%- if structure %}
191
+ ====
191
192
  {{ structure }}
192
193
  {%- endif %}
193
194
 
194
195
  {%- if content %}
196
+ ====
195
197
  下面是一些文件路径以及每个文件对应的源码:
196
198
  <files>
197
199
  {{ content }}
@@ -199,6 +201,7 @@ class CodeAutoGenerateEditBlock:
199
201
  {%- endif %}
200
202
 
201
203
  {%- if package_context %}
204
+ ====
202
205
  下面是上面文件的一些信息(包括最近的变更情况):
203
206
  <package_context>
204
207
  {{ package_context }}
@@ -206,11 +209,29 @@ class CodeAutoGenerateEditBlock:
206
209
  {%- endif %}
207
210
 
208
211
  {%- if context %}
212
+ ====
209
213
  <extra_context>
210
214
  {{ context }}
211
215
  </extra_context>
212
216
  {%- endif %}
213
217
 
218
+ {%- if extra_docs %}
219
+ ====
220
+
221
+ RULES PROVIDED BY USER
222
+
223
+ The following rules are provided by the user, and you must follow them strictly.
224
+
225
+ {% for key, value in extra_docs.items() %}
226
+ <user_rule>
227
+ ##File: {{ key }}
228
+ {{ value }}
229
+ </user_rule>
230
+ {% endfor %}
231
+ {% endif %}
232
+
233
+ ====
234
+
214
235
  下面是用户的需求:
215
236
 
216
237
  {{ instruction }}
@@ -224,6 +245,8 @@ class CodeAutoGenerateEditBlock:
224
245
  "fence_0": self.fence_0,
225
246
  "fence_1": self.fence_1,
226
247
  }
248
+
249
+ extra_docs = get_rules()
227
250
 
228
251
  return {
229
252
  "structure": (
@@ -233,6 +256,7 @@ class CodeAutoGenerateEditBlock:
233
256
  ),
234
257
  "fence_0": self.fence_0,
235
258
  "fence_1": self.fence_1,
259
+ "extra_docs": extra_docs,
236
260
  }
237
261
 
238
262
  @byzerllm.prompt()
@@ -493,7 +517,7 @@ class CodeAutoGenerateEditBlock:
493
517
  generate_mode="editblock"
494
518
  )
495
519
 
496
- if not self.args.human_as_model:
520
+ if not self.args.human_as_model or get_run_context().mode == RunMode.WEB:
497
521
  with ThreadPoolExecutor(max_workers=len(self.llms) * self.generate_times_same_model) as executor:
498
522
  futures = []
499
523
  count = 0
@@ -16,6 +16,9 @@ from autocoder.utils import llms as llm_utils
16
16
  from autocoder.common import SourceCodeList
17
17
  from autocoder.privacy.model_filter import ModelPathFilter
18
18
  from autocoder.memory.active_context_manager import ActiveContextManager
19
+ from autocoder.common.rulefiles.autocoderrules_utils import get_rules
20
+ from autocoder.run_context import get_run_context,RunMode
21
+
19
22
  class CodeAutoGenerateStrictDiff:
20
23
  def __init__(
21
24
  self, llm: byzerllm.ByzerLLM, args: AutoCoderArgs, action=None
@@ -118,10 +121,12 @@ class CodeAutoGenerateStrictDiff:
118
121
  现在让我们开始一个新的任务:
119
122
 
120
123
  {%- if structure %}
124
+ ====
121
125
  {{ structure }}
122
126
  {%- endif %}
123
127
 
124
128
  {%- if content %}
129
+ ====
125
130
  下面是一些文件路径以及每个文件对应的源码:
126
131
  <files>
127
132
  {{ content }}
@@ -129,6 +134,7 @@ class CodeAutoGenerateStrictDiff:
129
134
  {%- endif %}
130
135
 
131
136
  {%- if package_context %}
137
+ ====
132
138
  下面是上面文件的一些信息(包括最近的变更情况):
133
139
  <package_context>
134
140
  {{ package_context }}
@@ -141,6 +147,23 @@ class CodeAutoGenerateStrictDiff:
141
147
  </extra_context>
142
148
  {%- endif %}
143
149
 
150
+ {%- if extra_docs %}
151
+ ====
152
+
153
+ RULES PROVIDED BY USER
154
+
155
+ The following rules are provided by the user, and you must follow them strictly.
156
+
157
+ {% for key, value in extra_docs.items() %}
158
+ <user_rule>
159
+ ##File: {{ key }}
160
+ {{ value }}
161
+ </user_rule>
162
+ {% endfor %}
163
+ {% endif %}
164
+
165
+ ====
166
+
144
167
  下面是用户的需求:
145
168
 
146
169
  {{ instruction }}
@@ -152,13 +175,16 @@ class CodeAutoGenerateStrictDiff:
152
175
  return {
153
176
  "structure": "",
154
177
  }
178
+
179
+ extra_docs = get_rules()
155
180
 
156
181
  return {
157
182
  "structure": (
158
183
  self.action.pp.get_tree_like_directory_structure()
159
184
  if self.action
160
185
  else ""
161
- )
186
+ ),
187
+ "extra_docs": extra_docs,
162
188
  }
163
189
 
164
190
  @byzerllm.prompt(llm=lambda self: self.llm)
@@ -354,7 +380,7 @@ class CodeAutoGenerateStrictDiff:
354
380
  generate_mode="strict_diff"
355
381
  )
356
382
 
357
- if not self.args.human_as_model:
383
+ if not self.args.human_as_model or get_run_context().mode == RunMode.WEB:
358
384
  with ThreadPoolExecutor(max_workers=len(self.llms) * self.generate_times_same_model) as executor:
359
385
  futures = []
360
386
  count = 0
@@ -0,0 +1,192 @@
1
+ from __future__ import annotations
2
+ import os, fnmatch, asyncio
3
+ from watchfiles import Change
4
+ from autocoder.common.ignorefiles.ignore_file_utils import should_ignore
5
+ from autocoder.common.file_monitor.monitor import get_file_monitor
6
+ import logging
7
+ import functools
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+ class DirectoryCache:
12
+ _instance: "DirectoryCache|None" = None
13
+
14
+ def __init__(self, root: str):
15
+ self.root = os.path.abspath(root)
16
+ self.files_set: set[str] = set()
17
+ self.lock = asyncio.Lock()
18
+ self._main_loop = asyncio.get_event_loop() # 保存主事件循环引用
19
+ logger.info(f"Initializing DirectoryCache for root: {self.root}")
20
+
21
+ # ---------- 单例获取 ----------
22
+ @classmethod
23
+ def get_instance(cls, root: str | None = None) -> "DirectoryCache":
24
+ if cls._instance is None:
25
+ if root is None:
26
+ raise ValueError("root is required when initializing DirectoryCache for the first time")
27
+ logger.info("Creating new DirectoryCache instance.")
28
+ cls._instance = cls(root)
29
+ cls._instance._build() # 同步首扫
30
+ cls._instance._register_monitor()
31
+ elif root is not None and os.path.abspath(root) != cls._instance.root:
32
+ # 如果请求的 root 与已存在的实例 root 不同,可以选择抛出错误或重新初始化
33
+ logger.warning(f"Requested root {os.path.abspath(root)} differs from existing instance root {cls._instance.root}. Re-initializing cache.")
34
+ cls._instance = cls(root)
35
+ cls._instance._build()
36
+ cls._instance._register_monitor()
37
+
38
+ return cls._instance
39
+
40
+ # ---------- 构建 ----------
41
+ def _build(self) -> None:
42
+ logger.info(f"Building initial file cache for {self.root}...")
43
+ count = 0
44
+ for r, ds, fs in os.walk(self.root, followlinks=True):
45
+ # 过滤掉需要忽略的目录
46
+ ds[:] = [d for d in ds if not should_ignore(os.path.join(r, d))]
47
+ for f in fs:
48
+ fp = os.path.join(r, f)
49
+ abs_fp = os.path.abspath(fp)
50
+ if not should_ignore(abs_fp):
51
+ self.files_set.add(abs_fp)
52
+ count += 1
53
+ logger.info(f"Initial cache build complete. Found {count} files.")
54
+
55
+
56
+ # ---------- 监控回调 ----------
57
+ def _register_monitor(self) -> None:
58
+ try:
59
+ logger.info(f"Registering file monitor for {self.root}")
60
+ mon = get_file_monitor(self.root)
61
+ # 使用 functools.partial 包装异步回调
62
+ async_callback_wrapper = functools.partial(self._on_change_wrapper)
63
+ mon.register("**/*", async_callback_wrapper) # 监听所有文件变化
64
+ if not mon.is_running():
65
+ logger.info("Starting file monitor...")
66
+ mon.start()
67
+ logger.info("File monitor registered and running.")
68
+ except Exception as e:
69
+ logger.error(f"Failed to register or start file monitor: {e}", exc_info=True)
70
+
71
+ # Wrapper to run the async callback in the event loop
72
+ def _on_change_wrapper(self, change: Change, path: str):
73
+ try:
74
+ # 使用run_coroutine_threadsafe在主事件循环中运行协程
75
+ # 注意:主事件循环必须在其他地方运行,如主线程中
76
+ asyncio.run_coroutine_threadsafe(self._on_change(change, path), self._main_loop)
77
+ except Exception as e:
78
+ logger.error(f"Error executing _on_change_wrapper: {e}", exc_info=True)
79
+ # 如果run_coroutine_threadsafe失败,可以考虑一个同步的备用处理方法
80
+ try:
81
+ # 同步备份处理
82
+ ap = os.path.abspath(path)
83
+ if should_ignore(ap):
84
+ return
85
+
86
+ if change is Change.added:
87
+ self.files_set.add(ap)
88
+ elif change is Change.deleted:
89
+ self.files_set.discard(ap)
90
+ # Change.modified不需要更新集合
91
+ except Exception as backup_error:
92
+ logger.error(f"Backup handler also failed: {backup_error}", exc_info=True)
93
+
94
+
95
+ async def _on_change(self, change: Change, path: str) -> None:
96
+ ap = os.path.abspath(path)
97
+ # Check ignore status again, as gitignore might change
98
+ if should_ignore(ap):
99
+ # If a previously tracked file becomes ignored, remove it
100
+ async with self.lock:
101
+ if ap in self.files_set:
102
+ logger.debug(f"File became ignored, removing from cache: {ap}")
103
+ self.files_set.discard(ap)
104
+ return
105
+
106
+ async with self.lock:
107
+ if change is Change.added:
108
+ logger.debug(f"File added, adding to cache: {ap}")
109
+ self.files_set.add(ap)
110
+ elif change is Change.deleted:
111
+ logger.debug(f"File deleted, removing from cache: {ap}")
112
+ self.files_set.discard(ap)
113
+ elif change is Change.modified:
114
+ # Modification doesn't change existence, but we might want to log or handle metadata updates if needed
115
+ logger.debug(f"File modified: {ap} (ignored in cache set)")
116
+ pass # No change needed for the set itself
117
+
118
+ # ---------- 查询 ----------
119
+ async def query(self, patterns: list[str]) -> list[str]:
120
+ logger.debug(f"Querying cache with patterns: {patterns}")
121
+ async with self.lock:
122
+ # Make a copy to avoid issues if the set is modified during iteration (though lock prevents this here)
123
+ current_files = list(self.files_set)
124
+
125
+ if not patterns or patterns == [""] or patterns == ["*"]:
126
+ logger.debug(f"Returning all {len(current_files)} cached files.")
127
+ return current_files
128
+
129
+ out: set[str] = set()
130
+
131
+ for p in patterns:
132
+ pattern_abs = os.path.abspath(os.path.join(self.root, p)) if not os.path.isabs(p) else p
133
+ is_glob = "*" in p or "?" in p or "[" in p # More robust glob check
134
+
135
+ try:
136
+ if is_glob:
137
+ # fnmatch expects relative paths for matching within a root usually,
138
+ # but here we match against absolute paths in files_set.
139
+ # We need a pattern that works with absolute paths.
140
+ # If pattern 'p' is like '*.py', we need to match '/path/to/root/**/*.py'
141
+ # Let's adjust the pattern logic or filtering logic.
142
+
143
+ # Option 1: Match relative paths within the root
144
+ # Convert absolute paths in files_set to relative for matching
145
+ # relative_files = [os.path.relpath(f, self.root) for f in current_files]
146
+ # matched_relative = fnmatch.filter(relative_files, p)
147
+ # out.update(os.path.join(self.root, rel_f) for rel_f in matched_relative)
148
+
149
+ # Option 2: Match absolute paths directly (might need careful pattern construction)
150
+ # If p is relative, make it absolute based on root for matching
151
+ # Example: p = "src/*.py" -> effective_pattern = "/path/to/root/src/*.py"
152
+ # This requires fnmatch to handle absolute paths correctly or custom logic.
153
+
154
+ # Option 3: Simplified wildcard matching on absolute paths
155
+ # Treat '*' as a general wildcard anywhere in the path.
156
+ # fnmatch.filter might work if the pattern is constructed like `*pattern*`
157
+ # Let's stick to the user's original logic first, assuming it worked for their case
158
+ # The original `*{p}*` suggests substring matching with wildcards? Let's refine.
159
+
160
+ # Refined Glob Matching:
161
+ # If p contains wildcards, assume it's a glob pattern relative to root.
162
+ # Convert files_set paths to relative for matching.
163
+ for f_abs in current_files:
164
+ f_rel = os.path.relpath(f_abs, self.root)
165
+ if fnmatch.fnmatch(f_rel, p) or fnmatch.fnmatch(os.path.basename(f_abs), p):
166
+ out.add(f_abs)
167
+
168
+ else:
169
+ # Exact or substring matching for non-glob patterns
170
+ # Match against filename or full path segment
171
+ p_lower = p.lower()
172
+ for f_abs in current_files:
173
+ if p_lower in os.path.basename(f_abs).lower() or p_lower in f_abs.lower():
174
+ out.add(f_abs)
175
+
176
+ except Exception as e:
177
+ logger.error(f"Error during pattern matching for '{p}': {e}", exc_info=True)
178
+
179
+
180
+ result = sorted(list(out)) # Sort for consistent output
181
+ logger.debug(f"Query returned {len(result)} files.")
182
+ return result
183
+
184
+ # Helper function (optional, could be integrated into get_instance)
185
+ def initialize_cache(root_path: str):
186
+ """Initializes the DirectoryCache singleton."""
187
+ try:
188
+ DirectoryCache.get_instance(root_path)
189
+ logger.info("DirectoryCache initialized successfully.")
190
+ except Exception as e:
191
+ logger.error(f"Failed to initialize DirectoryCache: {e}", exc_info=True)
192
+