auto-coder 0.1.359__py3-none-any.whl → 0.1.360__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.360
4
4
  Summary: AutoCoder: AutoCoder
5
5
  Author: allwefantasy
6
6
  Classifier: Programming Language :: Python :: 3.10
@@ -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=AJWkVCVcNxcQiTT91kp7mLT7D-FHFLU1zfRiNjiCFIE,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=gZ2TUcmXQkNZS_bpQb7Qi9uoYcSFXUjtLvZtrhp0CzI,12053
68
+ autocoder/common/code_auto_generate_diff.py,sha256=WJEXW44USo1NA-EyH2lEbQBbt6FiXdJ_GQ8xXWjy_sc,19097
69
+ autocoder/common/code_auto_generate_editblock.py,sha256=MQwkDUZlC8FBPEfmIn0wYZyOgD3b2OXQfysUsltnNXk,21809
70
+ autocoder/common/code_auto_generate_strict_diff.py,sha256=oYRl43-mzXdPkM4SSsiari8xqfhJTm0Z3PLfa24e9as,17969
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=g6hbBCFfqZnBUvswv_eO9r8b7HwnpIVh9f1M9ICivYQ,11547
140
+ autocoder/common/v2/code_auto_generate_diff.py,sha256=QJQk_D3l5yk3kczRF9-HwQgOLQYDlDhkGH72UtI-4Ks,15114
141
+ autocoder/common/v2/code_auto_generate_editblock.py,sha256=JKeAul5S5xKWtB9Ma4XlJw9ImxnxXetfUSESME3StUk,15621
142
+ autocoder/common/v2/code_auto_generate_strict_diff.py,sha256=k0aW21Gb40b8Z4-i5aHFgMtfoqK0ilFwQtv9C823X34,17968
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
@@ -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.360.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
314
+ auto_coder-0.1.360.dist-info/METADATA,sha256=X4RcgNPLlNFVBEANGjlIbrqSgeJcWK0v8ACJWkPMGAY,2751
315
+ auto_coder-0.1.360.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
316
+ auto_coder-0.1.360.dist-info/entry_points.txt,sha256=0nzHtHH4pNcM7xq4EBA2toS28Qelrvcbrr59GqD_0Ak,350
317
+ auto_coder-0.1.360.dist-info/top_level.txt,sha256=Jqc0_uJSw2GwoFQAa9iJxYns-2mWla-9ok_Y3Gcznjk,10
318
+ auto_coder-0.1.360.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
 
@@ -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 }}
@@ -16,6 +16,7 @@ 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
19
20
 
20
21
  class CodeAutoGenerateDiff:
21
22
  def __init__(
@@ -135,10 +136,12 @@ class CodeAutoGenerateDiff:
135
136
  现在让我们开始一个新的任务:
136
137
 
137
138
  {%- if structure %}
139
+ ====
138
140
  {{ structure }}
139
141
  {%- endif %}
140
142
 
141
143
  {%- if content %}
144
+ ====
142
145
  下面是一些文件路径以及每个文件对应的源码:
143
146
  <files>
144
147
  {{ content }}
@@ -146,6 +149,7 @@ class CodeAutoGenerateDiff:
146
149
  {%- endif %}
147
150
 
148
151
  {%- if package_context %}
152
+ ====
149
153
  下面是上面文件的一些信息(包括最近的变更情况):
150
154
  <package_context>
151
155
  {{ package_context }}
@@ -153,11 +157,29 @@ class CodeAutoGenerateDiff:
153
157
  {%- endif %}
154
158
 
155
159
  {%- if context %}
160
+ ====
156
161
  <extra_context>
157
162
  {{ context }}
158
163
  </extra_context>
159
164
  {%- endif %}
160
165
 
166
+ {%- if extra_docs %}
167
+ ====
168
+
169
+ RULES PROVIDED BY USER
170
+
171
+ The following rules are provided by the user, and you must follow them strictly.
172
+
173
+ {% for key, value in extra_docs.items() %}
174
+ <user_rule>
175
+ ##File: {{ key }}
176
+ {{ value }}
177
+ </user_rule>
178
+ {% endfor %}
179
+ {% endif %}
180
+
181
+ ====
182
+
161
183
  下面是用户的需求:
162
184
 
163
185
  {{ instruction }}
@@ -169,13 +191,15 @@ class CodeAutoGenerateDiff:
169
191
  return {
170
192
  "structure": ""
171
193
  }
172
-
194
+
195
+ extra_docs = get_rules()
173
196
  return {
174
197
  "structure": (
175
198
  self.action.pp.get_tree_like_directory_structure()
176
199
  if self.action
177
200
  else ""
178
- )
201
+ ),
202
+ "extra_docs": extra_docs,
179
203
  }
180
204
 
181
205
  @byzerllm.prompt(llm=lambda self: self.llm)
@@ -20,6 +20,7 @@ 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
+ from autocoder.common.rulefiles.autocoderrules_utils import get_rules
23
24
 
24
25
 
25
26
 
@@ -188,10 +189,12 @@ class CodeAutoGenerateEditBlock:
188
189
  现在让我们开始一个新的任务:
189
190
 
190
191
  {%- if structure %}
192
+ ====
191
193
  {{ structure }}
192
194
  {%- endif %}
193
195
 
194
196
  {%- if content %}
197
+ ====
195
198
  下面是一些文件路径以及每个文件对应的源码:
196
199
  <files>
197
200
  {{ content }}
@@ -199,6 +202,7 @@ class CodeAutoGenerateEditBlock:
199
202
  {%- endif %}
200
203
 
201
204
  {%- if package_context %}
205
+ ====
202
206
  下面是上面文件的一些信息(包括最近的变更情况):
203
207
  <package_context>
204
208
  {{ package_context }}
@@ -206,11 +210,29 @@ class CodeAutoGenerateEditBlock:
206
210
  {%- endif %}
207
211
 
208
212
  {%- if context %}
213
+ ====
209
214
  <extra_context>
210
215
  {{ context }}
211
216
  </extra_context>
212
217
  {%- endif %}
213
218
 
219
+ {%- if extra_docs %}
220
+ ====
221
+
222
+ RULES PROVIDED BY USER
223
+
224
+ The following rules are provided by the user, and you must follow them strictly.
225
+
226
+ {% for key, value in extra_docs.items() %}
227
+ <user_rule>
228
+ ##File: {{ key }}
229
+ {{ value }}
230
+ </user_rule>
231
+ {% endfor %}
232
+ {% endif %}
233
+
234
+ ====
235
+
214
236
  下面是用户的需求:
215
237
 
216
238
  {{ instruction }}
@@ -224,6 +246,8 @@ class CodeAutoGenerateEditBlock:
224
246
  "fence_0": self.fence_0,
225
247
  "fence_1": self.fence_1,
226
248
  }
249
+
250
+ extra_docs = get_rules()
227
251
 
228
252
  return {
229
253
  "structure": (
@@ -233,6 +257,7 @@ class CodeAutoGenerateEditBlock:
233
257
  ),
234
258
  "fence_0": self.fence_0,
235
259
  "fence_1": self.fence_1,
260
+ "extra_docs": extra_docs,
236
261
  }
237
262
 
238
263
  @byzerllm.prompt()
@@ -16,6 +16,8 @@ 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
+
19
21
  class CodeAutoGenerateStrictDiff:
20
22
  def __init__(
21
23
  self, llm: byzerllm.ByzerLLM, args: AutoCoderArgs, action=None
@@ -118,10 +120,12 @@ class CodeAutoGenerateStrictDiff:
118
120
  现在让我们开始一个新的任务:
119
121
 
120
122
  {%- if structure %}
123
+ ====
121
124
  {{ structure }}
122
125
  {%- endif %}
123
126
 
124
127
  {%- if content %}
128
+ ====
125
129
  下面是一些文件路径以及每个文件对应的源码:
126
130
  <files>
127
131
  {{ content }}
@@ -129,6 +133,7 @@ class CodeAutoGenerateStrictDiff:
129
133
  {%- endif %}
130
134
 
131
135
  {%- if package_context %}
136
+ ====
132
137
  下面是上面文件的一些信息(包括最近的变更情况):
133
138
  <package_context>
134
139
  {{ package_context }}
@@ -141,6 +146,23 @@ class CodeAutoGenerateStrictDiff:
141
146
  </extra_context>
142
147
  {%- endif %}
143
148
 
149
+ {%- if extra_docs %}
150
+ ====
151
+
152
+ RULES PROVIDED BY USER
153
+
154
+ The following rules are provided by the user, and you must follow them strictly.
155
+
156
+ {% for key, value in extra_docs.items() %}
157
+ <user_rule>
158
+ ##File: {{ key }}
159
+ {{ value }}
160
+ </user_rule>
161
+ {% endfor %}
162
+ {% endif %}
163
+
164
+ ====
165
+
144
166
  下面是用户的需求:
145
167
 
146
168
  {{ instruction }}
@@ -152,13 +174,16 @@ class CodeAutoGenerateStrictDiff:
152
174
  return {
153
175
  "structure": "",
154
176
  }
177
+
178
+ extra_docs = get_rules()
155
179
 
156
180
  return {
157
181
  "structure": (
158
182
  self.action.pp.get_tree_like_directory_structure()
159
183
  if self.action
160
184
  else ""
161
- )
185
+ ),
186
+ "extra_docs": extra_docs,
162
187
  }
163
188
 
164
189
  @byzerllm.prompt(llm=lambda self: self.llm)
@@ -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
+
@@ -0,0 +1,190 @@
1
+ import pytest
2
+ import os
3
+ import tempfile
4
+ import shutil
5
+ import asyncio
6
+ from unittest.mock import patch, MagicMock
7
+
8
+ # 导入被测模块
9
+ from autocoder.common.directory_cache.cache import DirectoryCache
10
+
11
+ # 测试环境辅助函数
12
+ def create_test_environment(base_dir, structure):
13
+ """创建测试所需的文件/目录结构"""
14
+ for path, content in structure.items():
15
+ full_path = os.path.join(base_dir, path)
16
+ os.makedirs(os.path.dirname(full_path), exist_ok=True)
17
+ with open(full_path, 'w', encoding='utf-8') as f:
18
+ f.write(content)
19
+
20
+ # Pytest Fixture: 临时目录
21
+ @pytest.fixture(scope="function")
22
+ def temp_test_dir():
23
+ """提供一个临时的、测试后自动清理的目录"""
24
+ temp_dir = tempfile.mkdtemp()
25
+ print(f"创建测试临时目录: {temp_dir}")
26
+ yield temp_dir
27
+ print(f"清理测试临时目录: {temp_dir}")
28
+ shutil.rmtree(temp_dir)
29
+
30
+ # Pytest Fixture: 重置单例
31
+ @pytest.fixture(autouse=True)
32
+ def reset_singleton():
33
+ """每次测试前重置DirectoryCache单例"""
34
+ DirectoryCache._instance = None
35
+ yield
36
+ DirectoryCache._instance = None
37
+
38
+ # Pytest Fixture: 文件监视器模拟
39
+ @pytest.fixture
40
+ def mock_file_monitor():
41
+ """模拟文件监视器"""
42
+ mock_monitor = MagicMock()
43
+ mock_monitor.register = MagicMock()
44
+ mock_monitor.is_running = MagicMock(return_value=False)
45
+ mock_monitor.start = MagicMock()
46
+
47
+ with patch('autocoder.common.directory_cache.cache.get_file_monitor', return_value=mock_monitor):
48
+ yield mock_monitor
49
+
50
+ # --- 测试用例 ---
51
+
52
+ @pytest.mark.asyncio
53
+ async def test_initialization(temp_test_dir, mock_file_monitor):
54
+ """测试DirectoryCache的初始化和单例模式"""
55
+ # 创建测试文件结构
56
+ create_test_environment(temp_test_dir, {
57
+ "file1.txt": "测试内容1",
58
+ "subdir/file2.txt": "测试内容2",
59
+ ".gitignore": "*.ignored"
60
+ })
61
+ create_test_environment(temp_test_dir, {
62
+ "file3.ignored": "这个文件应该被忽略"
63
+ })
64
+
65
+ # 获取实例
66
+ cache = DirectoryCache.get_instance(temp_test_dir)
67
+
68
+ # 验证单例模式
69
+ assert DirectoryCache.get_instance() is cache
70
+ assert cache.root == os.path.abspath(temp_test_dir)
71
+
72
+ # 验证文件缓存构建
73
+ assert len(cache.files_set) == 3 # file1.txt, subdir/file2.txt, .gitignore
74
+ assert os.path.join(temp_test_dir, "file1.txt") in [os.path.normpath(f) for f in cache.files_set]
75
+ assert os.path.join(temp_test_dir, "subdir/file2.txt") in [os.path.normpath(f) for f in cache.files_set]
76
+
77
+ # 验证监视器注册
78
+ mock_file_monitor.register.assert_called_once()
79
+ mock_file_monitor.start.assert_called_once()
80
+
81
+ @pytest.mark.asyncio
82
+ async def test_query_all_files(temp_test_dir, mock_file_monitor):
83
+ """测试查询所有文件"""
84
+ # 创建测试文件结构
85
+ create_test_environment(temp_test_dir, {
86
+ "file1.py": "def test(): pass",
87
+ "file2.txt": "text content",
88
+ "subdir/file3.py": "class Test: pass"
89
+ })
90
+
91
+ # 获取实例并查询所有文件
92
+ cache = DirectoryCache.get_instance(temp_test_dir)
93
+ result = await cache.query(["*"])
94
+
95
+ # 验证结果
96
+ assert len(result) == 3
97
+ assert sorted([os.path.basename(f) for f in result]) == ["file1.py", "file2.txt", "file3.py"]
98
+
99
+ @pytest.mark.asyncio
100
+ async def test_query_with_pattern(temp_test_dir, mock_file_monitor):
101
+ """测试使用模式查询文件"""
102
+ # 创建测试文件结构
103
+ create_test_environment(temp_test_dir, {
104
+ "file1.py": "def test(): pass",
105
+ "file2.txt": "text content",
106
+ "subdir/file3.py": "class Test: pass",
107
+ "another.doc": "document"
108
+ })
109
+
110
+ # 获取实例
111
+ cache = DirectoryCache.get_instance(temp_test_dir)
112
+
113
+ # 测试不同的查询模式
114
+ py_files = await cache.query(["*.py"])
115
+ assert len(py_files) == 2
116
+ assert all(f.endswith('.py') for f in py_files)
117
+
118
+ txt_files = await cache.query(["*.txt"])
119
+ assert len(txt_files) == 1
120
+ assert txt_files[0].endswith('file2.txt')
121
+
122
+ # 测试多模式查询
123
+ mixed_files = await cache.query(["*.py", "*.txt"])
124
+ assert len(mixed_files) == 3
125
+ assert len([f for f in mixed_files if f.endswith('.py')]) == 2
126
+ assert len([f for f in mixed_files if f.endswith('.txt')]) == 1
127
+
128
+ @pytest.mark.asyncio
129
+ async def test_file_change_events(temp_test_dir, mock_file_monitor):
130
+ """测试文件变更事件处理"""
131
+ from watchfiles import Change
132
+
133
+ # 创建测试文件结构
134
+ create_test_environment(temp_test_dir, {
135
+ "file1.txt": "初始内容"
136
+ })
137
+
138
+ # 获取实例
139
+ cache = DirectoryCache.get_instance(temp_test_dir)
140
+
141
+ # 初始状态
142
+ file_path = os.path.join(temp_test_dir, "file1.txt")
143
+ abs_file_path = os.path.abspath(file_path)
144
+ assert abs_file_path in cache.files_set
145
+
146
+ # 测试删除事件
147
+ await cache._on_change(Change.deleted, abs_file_path)
148
+ assert abs_file_path not in cache.files_set
149
+
150
+ # 测试添加事件
151
+ await cache._on_change(Change.added, abs_file_path)
152
+ assert abs_file_path in cache.files_set
153
+
154
+ # 测试修改事件 (不应改变集合)
155
+ initial_set_size = len(cache.files_set)
156
+ await cache._on_change(Change.modified, abs_file_path)
157
+ assert len(cache.files_set) == initial_set_size
158
+ assert abs_file_path in cache.files_set
159
+
160
+ # 测试新文件
161
+ new_file_path = os.path.join(temp_test_dir, "newfile.txt")
162
+ abs_new_file_path = os.path.abspath(new_file_path)
163
+ await cache._on_change(Change.added, abs_new_file_path)
164
+ assert abs_new_file_path in cache.files_set
165
+
166
+ @pytest.mark.asyncio
167
+ async def test_reinitialization_with_different_root(temp_test_dir, mock_file_monitor):
168
+ """测试使用不同根目录重新初始化缓存"""
169
+ # 创建第一个测试目录
170
+ first_dir = os.path.join(temp_test_dir, "first")
171
+ os.makedirs(first_dir)
172
+ create_test_environment(first_dir, {"test.txt": "first directory"})
173
+
174
+ # 初始化缓存
175
+ cache1 = DirectoryCache.get_instance(first_dir)
176
+ assert cache1.root == os.path.abspath(first_dir)
177
+
178
+ # 创建第二个测试目录
179
+ second_dir = os.path.join(temp_test_dir, "second")
180
+ os.makedirs(second_dir)
181
+ create_test_environment(second_dir, {"other.txt": "second directory"})
182
+
183
+ # 使用新目录重新初始化
184
+ cache2 = DirectoryCache.get_instance(second_dir)
185
+ assert cache2.root == os.path.abspath(second_dir)
186
+
187
+ # 验证文件集合已更新
188
+ all_files = await cache2.query(["*"])
189
+ assert len(all_files) == 1
190
+ assert all_files[0].endswith('other.txt')
@@ -153,7 +153,7 @@ class FileMonitor:
153
153
  """
154
154
  # 将单个模式转换为pathspec格式
155
155
  # 使用GitWildMatchPattern,它支持.gitignore样式的通配符,功能最全面
156
- return pathspec.PathSpec.from_patterns([pattern], pathspec.patterns.GitWildMatchPattern)
156
+ return pathspec.PathSpec([pathspec.patterns.GitWildMatchPattern(pattern)])
157
157
 
158
158
  def register(self, path: Union[str, Path], callback: Callable[[Change, str], None]):
159
159
  """
@@ -16,6 +16,7 @@ from autocoder.utils import llms as llm_utils
16
16
  from autocoder.common import SourceCodeList
17
17
  from autocoder.memory.active_context_manager import ActiveContextManager
18
18
  from loguru import logger
19
+ from autocoder.common.rulefiles.autocoderrules_utils import get_rules
19
20
 
20
21
  class CodeAutoGenerate:
21
22
  def __init__(
@@ -36,6 +37,88 @@ class CodeAutoGenerate:
36
37
  if not isinstance(self.llms, list):
37
38
  self.llms = [self.llms]
38
39
 
40
+ @byzerllm.prompt(llm=lambda self: self.llm)
41
+ def single_round_instruction(
42
+ self, instruction: str, content: str, context: str = "", package_context: str = ""
43
+ ) -> str:
44
+ """
45
+ {%- if structure %}
46
+ ====
47
+ {{ structure }}
48
+ {%- endif %}
49
+
50
+ {%- if content %}
51
+ ====
52
+ 下面是一些文件路径以及每个文件对应的源码:
53
+
54
+ {{ content }}
55
+ {%- endif %}
56
+
57
+ {%- if package_context %}
58
+ ====
59
+ 下面是上面文件的一些信息(包括最近的变更情况):
60
+ <package_context>
61
+ {{ package_context }}
62
+ </package_context>
63
+ {%- endif %}
64
+
65
+ {%- if context %}
66
+ ====
67
+ {{ context }}
68
+ {%- endif %}
69
+
70
+ {%- if extra_docs %}
71
+ ====
72
+
73
+ RULES PROVIDED BY USER
74
+
75
+ The following rules are provided by the user, and you must follow them strictly.
76
+
77
+ {% for key, value in extra_docs.items() %}
78
+ <user_rule>
79
+ ##File: {{ key }}
80
+ {{ value }}
81
+ </user_rule>
82
+ {% endfor %}
83
+ {% endif %}
84
+
85
+ 下面是用户的需求:
86
+
87
+ {{ instruction }}
88
+
89
+ 如果你需要生成代码,你生成的代码要符合这个格式:
90
+
91
+ ```{lang}
92
+ ##File: {FILE_PATH}
93
+ {CODE}
94
+ ```
95
+
96
+ ```{lang}
97
+ ##File: {FILE_PATH}
98
+ {CODE}
99
+ ```
100
+
101
+ 其中,{lang}是代码的语言,{CODE}是代码的内容, {FILE_PATH} 是文件的路径(请尽量使用绝对路径),他们都在代码块中,请严格按上面的格式进行内容生成。
102
+
103
+ 请确保每份代码的完整性,而不要只生成修改部分。
104
+ """
105
+
106
+ if not self.args.include_project_structure:
107
+ return {
108
+ "structure": "",
109
+ }
110
+
111
+ extra_docs = get_rules()
112
+
113
+ return {
114
+ "structure": (
115
+ self.action.pp.get_tree_like_directory_structure()
116
+ if self.action
117
+ else ""
118
+ ),
119
+ "extra_docs": extra_docs,
120
+ }
121
+
39
122
  def single_round_run(
40
123
  self, query: str, source_code_list: SourceCodeList
41
124
  ) -> CodeGenerateResult:
@@ -155,22 +155,23 @@ class CodeAutoGenerateDiff:
155
155
  ```
156
156
 
157
157
  现在让我们开始一个新的任务:
158
-
159
- ====
158
+
160
159
  {%- if structure %}
160
+ ====
161
161
  {{ structure }}
162
162
  {%- endif %}
163
163
 
164
- ====
164
+
165
165
  {%- if content %}
166
+ ====
166
167
  下面是一些文件路径以及每个文件对应的源码:
167
168
  <files>
168
169
  {{ content }}
169
170
  </files>
170
171
  {%- endif %}
171
-
172
- ====
172
+
173
173
  {%- if package_context %}
174
+ ====
174
175
  下面是上面文件的一些信息(包括最近的变更情况):
175
176
  <package_context>
176
177
  {{ package_context }}
@@ -15,6 +15,7 @@ from autocoder.rag.token_counter import count_tokens
15
15
  from autocoder.utils import llms as llm_utils
16
16
  from autocoder.common import SourceCodeList
17
17
  from autocoder.memory.active_context_manager import ActiveContextManager
18
+ from autocoder.common.rulefiles.autocoderrules_utils import get_rules
18
19
  from loguru import logger
19
20
 
20
21
 
@@ -175,13 +176,15 @@ class CodeAutoGenerateEditBlock:
175
176
  {%- endif %}
176
177
 
177
178
  {%- if content %}
179
+ ====
178
180
  下面是一些文件路径以及每个文件对应的源码:
179
181
  <files>
180
182
  {{ content }}
181
183
  </files>
182
184
  {%- endif %}
183
-
185
+
184
186
  {%- if package_context %}
187
+ ====
185
188
  下面是上面文件的一些信息(包括最近的变更情况):
186
189
  <package_context>
187
190
  {{ package_context }}
@@ -194,6 +197,22 @@ class CodeAutoGenerateEditBlock:
194
197
  </extra_context>
195
198
  {%- endif %}
196
199
 
200
+ {%- if extra_docs %}
201
+ ====
202
+
203
+ RULES PROVIDED BY USER
204
+
205
+ The following rules are provided by the user, and you must follow them strictly.
206
+
207
+ {% for key, value in extra_docs.items() %}
208
+ <user_rule>
209
+ ##File: {{ key }}
210
+ {{ value }}
211
+ </user_rule>
212
+ {% endfor %}
213
+ {% endif %}
214
+
215
+ ====
197
216
  下面是用户的需求:
198
217
 
199
218
  {{ instruction }}
@@ -204,7 +223,9 @@ class CodeAutoGenerateEditBlock:
204
223
  "structure": "",
205
224
  "fence_0": self.fence_0,
206
225
  "fence_1": self.fence_1,
207
- }
226
+ }
227
+
228
+ extra_docs = get_rules()
208
229
 
209
230
  return {
210
231
  "structure": (
@@ -214,6 +235,7 @@ class CodeAutoGenerateEditBlock:
214
235
  ),
215
236
  "fence_0": self.fence_0,
216
237
  "fence_1": self.fence_1,
238
+ "extra_docs": extra_docs,
217
239
  }
218
240
 
219
241
  def single_round_run(
@@ -16,6 +16,7 @@ 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
19
20
  class CodeAutoGenerateStrictDiff:
20
21
  def __init__(
21
22
  self, llm: byzerllm.ByzerLLM, args: AutoCoderArgs, action=None
@@ -118,10 +119,12 @@ class CodeAutoGenerateStrictDiff:
118
119
  现在让我们开始一个新的任务:
119
120
 
120
121
  {%- if structure %}
122
+ ====
121
123
  {{ structure }}
122
124
  {%- endif %}
123
125
 
124
126
  {%- if content %}
127
+ ====
125
128
  下面是一些文件路径以及每个文件对应的源码:
126
129
  <files>
127
130
  {{ content }}
@@ -129,6 +132,7 @@ class CodeAutoGenerateStrictDiff:
129
132
  {%- endif %}
130
133
 
131
134
  {%- if package_context %}
135
+ ====
132
136
  下面是上面文件的一些信息(包括最近的变更情况):
133
137
  <package_context>
134
138
  {{ package_context }}
@@ -136,14 +140,29 @@ class CodeAutoGenerateStrictDiff:
136
140
  {%- endif %}
137
141
 
138
142
  {%- if context %}
143
+ ====
139
144
  <extra_context>
140
145
  {{ context }}
141
146
  </extra_context>
142
147
  {%- endif %}
143
148
 
144
- 下面是用户的需求:
149
+ {%- if extra_docs %}
150
+ ====
145
151
 
146
- {{ instruction }}
152
+ RULES PROVIDED BY USER
153
+
154
+ The following rules are provided by the user, and you must follow them strictly.
155
+
156
+ {% for key, value in extra_docs.items() %}
157
+ <user_rule>
158
+ ##File: {{ key }}
159
+ {{ value }}
160
+ </user_rule>
161
+ {% endfor %}
162
+ {% endif %}
163
+
164
+ ====
165
+ 下面是用户的需求:
147
166
 
148
167
  每次生成一个文件的diff,然后询问我是否继续,当我回复继续,继续生成下一个文件的diff。当没有后续任务时,请回复 "__完成__" 或者 "__EOF__"。
149
168
  """
@@ -152,13 +171,16 @@ class CodeAutoGenerateStrictDiff:
152
171
  return {
153
172
  "structure": "",
154
173
  }
174
+
175
+ extra_docs = get_rules()
155
176
 
156
177
  return {
157
178
  "structure": (
158
179
  self.action.pp.get_tree_like_directory_structure()
159
180
  if self.action
160
181
  else ""
161
- )
182
+ ),
183
+ "extra_docs": extra_docs,
162
184
  }
163
185
 
164
186
  @byzerllm.prompt(llm=lambda self: self.llm)
autocoder/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.359"
1
+ __version__ = "0.1.360"