auto-coder 0.1.316__py3-none-any.whl → 0.1.318__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.
- {auto_coder-0.1.316.dist-info → auto_coder-0.1.318.dist-info}/METADATA +2 -2
- {auto_coder-0.1.316.dist-info → auto_coder-0.1.318.dist-info}/RECORD +41 -20
- autocoder/auto_coder_runner.py +1 -2
- autocoder/common/__init__.py +3 -0
- autocoder/common/auto_coder_lang.py +24 -0
- autocoder/common/code_auto_merge_editblock.py +2 -42
- autocoder/common/git_utils.py +2 -2
- autocoder/common/token_cost_caculate.py +103 -42
- autocoder/common/v2/__init__.py +0 -0
- autocoder/common/v2/code_auto_generate.py +199 -0
- autocoder/common/v2/code_auto_generate_diff.py +361 -0
- autocoder/common/v2/code_auto_generate_editblock.py +380 -0
- autocoder/common/v2/code_auto_generate_strict_diff.py +269 -0
- autocoder/common/v2/code_auto_merge.py +211 -0
- autocoder/common/v2/code_auto_merge_diff.py +354 -0
- autocoder/common/v2/code_auto_merge_editblock.py +523 -0
- autocoder/common/v2/code_auto_merge_strict_diff.py +259 -0
- autocoder/common/v2/code_diff_manager.py +266 -0
- autocoder/common/v2/code_editblock_manager.py +282 -0
- autocoder/common/v2/code_manager.py +238 -0
- autocoder/common/v2/code_strict_diff_manager.py +241 -0
- autocoder/dispacher/actions/action.py +16 -0
- autocoder/dispacher/actions/plugins/action_regex_project.py +6 -0
- autocoder/events/event_manager_singleton.py +2 -2
- autocoder/helper/__init__.py +0 -0
- autocoder/helper/project_creator.py +570 -0
- autocoder/linters/linter_factory.py +44 -25
- autocoder/linters/models.py +220 -0
- autocoder/linters/python_linter.py +1 -7
- autocoder/linters/reactjs_linter.py +580 -0
- autocoder/linters/shadow_linter.py +390 -0
- autocoder/linters/vue_linter.py +576 -0
- autocoder/memory/active_context_manager.py +0 -4
- autocoder/memory/active_package.py +12 -12
- autocoder/shadows/__init__.py +0 -0
- autocoder/shadows/shadow_manager.py +235 -0
- autocoder/version.py +1 -1
- {auto_coder-0.1.316.dist-info → auto_coder-0.1.318.dist-info}/LICENSE +0 -0
- {auto_coder-0.1.316.dist-info → auto_coder-0.1.318.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.316.dist-info → auto_coder-0.1.318.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.316.dist-info → auto_coder-0.1.318.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
from typing import List, Dict, Tuple
|
|
2
|
+
from autocoder.common.types import Mode, CodeGenerateResult
|
|
3
|
+
from autocoder.common import AutoCoderArgs
|
|
4
|
+
import byzerllm
|
|
5
|
+
from autocoder.common import sys_prompt
|
|
6
|
+
from autocoder.privacy.model_filter import ModelPathFilter
|
|
7
|
+
import json
|
|
8
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
9
|
+
from autocoder.common.utils_code_auto_generate import chat_with_continue,stream_chat_with_continue,ChatWithContinueResult
|
|
10
|
+
from autocoder.utils.auto_coder_utils.chat_stream_out import stream_out
|
|
11
|
+
from autocoder.common.stream_out_type import CodeGenerateStreamOutType
|
|
12
|
+
from autocoder.common.auto_coder_lang import get_message_with_format
|
|
13
|
+
from autocoder.common.printer import Printer
|
|
14
|
+
from autocoder.rag.token_counter import count_tokens
|
|
15
|
+
from autocoder.utils import llms as llm_utils
|
|
16
|
+
from autocoder.common import SourceCodeList
|
|
17
|
+
from autocoder.memory.active_context_manager import ActiveContextManager
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class CodeAutoGenerateEditBlock:
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
llm: byzerllm.ByzerLLM,
|
|
25
|
+
args: AutoCoderArgs,
|
|
26
|
+
action=None,
|
|
27
|
+
fence_0: str = "```",
|
|
28
|
+
fence_1: str = "```",
|
|
29
|
+
) -> None:
|
|
30
|
+
self.llm = llm
|
|
31
|
+
self.args = args
|
|
32
|
+
self.action = action
|
|
33
|
+
self.fence_0 = fence_0
|
|
34
|
+
self.fence_1 = fence_1
|
|
35
|
+
self.generate_times_same_model = args.generate_times_same_model
|
|
36
|
+
if not self.llm:
|
|
37
|
+
raise ValueError(
|
|
38
|
+
"Please provide a valid model instance to use for code generation."
|
|
39
|
+
)
|
|
40
|
+
self.llms = self.llm.get_sub_client("code_model") or [self.llm]
|
|
41
|
+
if not isinstance(self.llms, list):
|
|
42
|
+
self.llms = [self.llms]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@byzerllm.prompt()
|
|
46
|
+
def single_round_instruction(self, instruction: str,
|
|
47
|
+
content: str,
|
|
48
|
+
context: str = "",
|
|
49
|
+
package_context: str = ""
|
|
50
|
+
) -> str:
|
|
51
|
+
"""
|
|
52
|
+
如果你需要生成代码,对于每个需要更改的文件,你需要按 *SEARCH/REPLACE block* 的格式进行生成。
|
|
53
|
+
|
|
54
|
+
# *SEARCH/REPLACE block* Rules:
|
|
55
|
+
|
|
56
|
+
Every *SEARCH/REPLACE block* must use this format:
|
|
57
|
+
1. The opening fence and code language, eg: {{ fence_0 }}python
|
|
58
|
+
2. The file path alone on a line, starting with "##File:" and verbatim. No bold asterisks, no quotes around it, no escaping of characters, etc.
|
|
59
|
+
3. The start of search block: <<<<<<< SEARCH
|
|
60
|
+
4. A contiguous chunk of lines to search for in the existing source code
|
|
61
|
+
5. The dividing line: =======
|
|
62
|
+
6. The lines to replace into the source code
|
|
63
|
+
7. The end of the replace block: >>>>>>> REPLACE
|
|
64
|
+
8. The closing fence: {{ fence_1 }}
|
|
65
|
+
|
|
66
|
+
Every *SEARCH* section must *EXACTLY MATCH* the existing source code, character for character, including all comments, docstrings, etc.
|
|
67
|
+
|
|
68
|
+
*SEARCH/REPLACE* blocks will replace *all* matching occurrences.
|
|
69
|
+
Include enough lines to make the SEARCH blocks unique.
|
|
70
|
+
|
|
71
|
+
Include *ALL* the code being searched and replaced!
|
|
72
|
+
|
|
73
|
+
To move code within a file, use 2 *SEARCH/REPLACE* blocks: 1 to delete it from its current location, 1 to insert it in the new location.
|
|
74
|
+
|
|
75
|
+
If you want to put code in a new file, use a *SEARCH/REPLACE block* with:
|
|
76
|
+
- A new file path, including dir name if needed
|
|
77
|
+
- An empty `SEARCH` section
|
|
78
|
+
- The new file's contents in the `REPLACE` section
|
|
79
|
+
|
|
80
|
+
ONLY EVER RETURN CODE IN A *SEARCH/REPLACE BLOCK*!
|
|
81
|
+
|
|
82
|
+
下面我们来看一个例子:
|
|
83
|
+
|
|
84
|
+
当前项目目录结构:
|
|
85
|
+
1. 项目根目录: /tmp/projects/mathweb
|
|
86
|
+
2. 项目子目录/文件列表(类似tree 命令输出)
|
|
87
|
+
flask/
|
|
88
|
+
app.py
|
|
89
|
+
templates/
|
|
90
|
+
index.html
|
|
91
|
+
static/
|
|
92
|
+
style.css
|
|
93
|
+
|
|
94
|
+
用户需求: Change get_factorial() to use math.factorial
|
|
95
|
+
|
|
96
|
+
回答: To make this change we need to modify `/tmp/projects/mathweb/flask/app.py` to:
|
|
97
|
+
|
|
98
|
+
1. Import the math package.
|
|
99
|
+
2. Remove the existing factorial() function.
|
|
100
|
+
3. Update get_factorial() to call math.factorial instead.
|
|
101
|
+
|
|
102
|
+
Here are the *SEARCH/REPLACE* blocks:
|
|
103
|
+
|
|
104
|
+
{{ fence_0 }}python
|
|
105
|
+
##File: /tmp/projects/mathweb/flask/app.py
|
|
106
|
+
<<<<<<< SEARCH
|
|
107
|
+
from flask import Flask
|
|
108
|
+
=======
|
|
109
|
+
import math
|
|
110
|
+
from flask import Flask
|
|
111
|
+
>>>>>>> REPLACE
|
|
112
|
+
{{ fence_1 }}
|
|
113
|
+
|
|
114
|
+
{{ fence_0 }}python
|
|
115
|
+
##File: /tmp/projects/mathweb/flask/app.py
|
|
116
|
+
<<<<<<< SEARCH
|
|
117
|
+
def factorial(n):
|
|
118
|
+
"compute factorial"
|
|
119
|
+
|
|
120
|
+
if n == 0:
|
|
121
|
+
return 1
|
|
122
|
+
else:
|
|
123
|
+
return n * factorial(n-1)
|
|
124
|
+
|
|
125
|
+
=======
|
|
126
|
+
>>>>>>> REPLACE
|
|
127
|
+
{{ fence_1 }}
|
|
128
|
+
|
|
129
|
+
{{ fence_0 }}python
|
|
130
|
+
##File: /tmp/projects/mathweb/flask/app.py
|
|
131
|
+
<<<<<<< SEARCH
|
|
132
|
+
return str(factorial(n))
|
|
133
|
+
=======
|
|
134
|
+
return str(math.factorial(n))
|
|
135
|
+
>>>>>>> REPLACE
|
|
136
|
+
{{ fence_1 }}
|
|
137
|
+
|
|
138
|
+
用户需求: Refactor hello() into its own file.
|
|
139
|
+
|
|
140
|
+
回答:To make this change we need to modify `main.py` and make a new file `hello.py`:
|
|
141
|
+
|
|
142
|
+
1. Make a new hello.py file with hello() in it.
|
|
143
|
+
2. Remove hello() from main.py and replace it with an import.
|
|
144
|
+
|
|
145
|
+
Here are the *SEARCH/REPLACE* blocks:
|
|
146
|
+
|
|
147
|
+
{{ fence_0 }}python
|
|
148
|
+
##File: /tmp/projects/mathweb/hello.py
|
|
149
|
+
<<<<<<< SEARCH
|
|
150
|
+
=======
|
|
151
|
+
def hello():
|
|
152
|
+
"print a greeting"
|
|
153
|
+
|
|
154
|
+
print("hello")
|
|
155
|
+
>>>>>>> REPLACE
|
|
156
|
+
{{ fence_1 }}
|
|
157
|
+
|
|
158
|
+
{{ fence_0 }}python
|
|
159
|
+
##File: /tmp/projects/mathweb/main.py
|
|
160
|
+
<<<<<<< SEARCH
|
|
161
|
+
def hello():
|
|
162
|
+
"print a greeting"
|
|
163
|
+
|
|
164
|
+
print("hello")
|
|
165
|
+
=======
|
|
166
|
+
from hello import hello
|
|
167
|
+
>>>>>>> REPLACE
|
|
168
|
+
{{ fence_1 }}
|
|
169
|
+
|
|
170
|
+
现在让我们开始一个新的任务:
|
|
171
|
+
|
|
172
|
+
{%- if structure %}
|
|
173
|
+
{{ structure }}
|
|
174
|
+
{%- endif %}
|
|
175
|
+
|
|
176
|
+
{%- if content %}
|
|
177
|
+
下面是一些文件路径以及每个文件对应的源码:
|
|
178
|
+
<files>
|
|
179
|
+
{{ content }}
|
|
180
|
+
</files>
|
|
181
|
+
{%- endif %}
|
|
182
|
+
|
|
183
|
+
{%- if package_context %}
|
|
184
|
+
下面是上面文件的一些信息(包括最近的变更情况):
|
|
185
|
+
<package_context>
|
|
186
|
+
{{ package_context }}
|
|
187
|
+
</package_context>
|
|
188
|
+
{%- endif %}
|
|
189
|
+
|
|
190
|
+
{%- if context %}
|
|
191
|
+
<extra_context>
|
|
192
|
+
{{ context }}
|
|
193
|
+
</extra_context>
|
|
194
|
+
{%- endif %}
|
|
195
|
+
|
|
196
|
+
下面是用户的需求:
|
|
197
|
+
|
|
198
|
+
{{ instruction }}
|
|
199
|
+
|
|
200
|
+
"""
|
|
201
|
+
if not self.args.include_project_structure:
|
|
202
|
+
return {
|
|
203
|
+
"structure": "",
|
|
204
|
+
"fence_0": self.fence_0,
|
|
205
|
+
"fence_1": self.fence_1,
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
"structure": (
|
|
210
|
+
self.action.pp.get_tree_like_directory_structure()
|
|
211
|
+
if self.action
|
|
212
|
+
else ""
|
|
213
|
+
),
|
|
214
|
+
"fence_0": self.fence_0,
|
|
215
|
+
"fence_1": self.fence_1,
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
def single_round_run(
|
|
219
|
+
self, query: str, source_code_list: SourceCodeList
|
|
220
|
+
) -> CodeGenerateResult:
|
|
221
|
+
|
|
222
|
+
# Apply model filter for code_llm
|
|
223
|
+
printer = Printer()
|
|
224
|
+
for llm in self.llms:
|
|
225
|
+
model_filter = ModelPathFilter.from_model_object(llm, self.args)
|
|
226
|
+
filtered_sources = []
|
|
227
|
+
for source in source_code_list.sources:
|
|
228
|
+
if model_filter.is_accessible(source.module_name):
|
|
229
|
+
filtered_sources.append(source)
|
|
230
|
+
else:
|
|
231
|
+
printer.print_in_terminal("index_file_filtered",
|
|
232
|
+
style="yellow",
|
|
233
|
+
file_path=source.module_name,
|
|
234
|
+
model_name=",".join(llm_utils.get_llm_names(llm)))
|
|
235
|
+
|
|
236
|
+
source_code_list = SourceCodeList(filtered_sources)
|
|
237
|
+
|
|
238
|
+
llm_config = {"human_as_model": self.args.human_as_model}
|
|
239
|
+
|
|
240
|
+
source_content = source_code_list.to_str()
|
|
241
|
+
|
|
242
|
+
active_context_manager = ActiveContextManager(self.llm, self.args.source_dir)
|
|
243
|
+
|
|
244
|
+
# 获取包上下文信息
|
|
245
|
+
package_context = ""
|
|
246
|
+
|
|
247
|
+
if self.args.enable_active_context:
|
|
248
|
+
# 获取活动上下文信息
|
|
249
|
+
result = active_context_manager.load_active_contexts_for_files(
|
|
250
|
+
[source.module_name for source in source_code_list.sources]
|
|
251
|
+
)
|
|
252
|
+
# 将活动上下文信息格式化为文本
|
|
253
|
+
if result.contexts:
|
|
254
|
+
package_context_parts = []
|
|
255
|
+
for dir_path, context in result.contexts.items():
|
|
256
|
+
package_context_parts.append(f"<package_info>{context.content}</package_info>")
|
|
257
|
+
|
|
258
|
+
package_context = "\n".join(package_context_parts)
|
|
259
|
+
|
|
260
|
+
init_prompt = self.single_round_instruction.prompt(
|
|
261
|
+
instruction=query, content=source_content, context=self.args.context,
|
|
262
|
+
package_context=package_context
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
with open(self.args.target_file, "w",encoding="utf-8") as file:
|
|
266
|
+
file.write(init_prompt)
|
|
267
|
+
|
|
268
|
+
conversations = []
|
|
269
|
+
|
|
270
|
+
if self.args.system_prompt and self.args.system_prompt.strip() == "claude":
|
|
271
|
+
conversations.append(
|
|
272
|
+
{"role": "system", "content": sys_prompt.claude_sys_prompt.prompt()})
|
|
273
|
+
elif self.args.system_prompt:
|
|
274
|
+
conversations.append(
|
|
275
|
+
{"role": "system", "content": self.args.system_prompt})
|
|
276
|
+
|
|
277
|
+
conversations.append({"role": "user", "content": init_prompt})
|
|
278
|
+
|
|
279
|
+
conversations_list = []
|
|
280
|
+
results = []
|
|
281
|
+
input_tokens_count = 0
|
|
282
|
+
generated_tokens_count = 0
|
|
283
|
+
|
|
284
|
+
input_tokens_cost = 0
|
|
285
|
+
generated_tokens_cost = 0
|
|
286
|
+
|
|
287
|
+
model_names = []
|
|
288
|
+
|
|
289
|
+
printer = Printer()
|
|
290
|
+
estimated_input_tokens = count_tokens(
|
|
291
|
+
json.dumps(conversations, ensure_ascii=False))
|
|
292
|
+
printer.print_in_terminal("estimated_input_tokens_in_generate",
|
|
293
|
+
style="yellow",
|
|
294
|
+
estimated_input_tokens_in_generate=estimated_input_tokens,
|
|
295
|
+
generate_mode="editblock"
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
if not self.args.human_as_model:
|
|
299
|
+
with ThreadPoolExecutor(max_workers=len(self.llms) * self.generate_times_same_model) as executor:
|
|
300
|
+
futures = []
|
|
301
|
+
for llm in self.llms:
|
|
302
|
+
|
|
303
|
+
model_names_list = llm_utils.get_llm_names(llm)
|
|
304
|
+
model_name = None
|
|
305
|
+
if model_names_list:
|
|
306
|
+
model_name = model_names_list[0]
|
|
307
|
+
|
|
308
|
+
for i in range(self.generate_times_same_model):
|
|
309
|
+
model_names.append(model_name)
|
|
310
|
+
if i==0:
|
|
311
|
+
def job():
|
|
312
|
+
stream_generator = stream_chat_with_continue(
|
|
313
|
+
llm=llm,
|
|
314
|
+
conversations=conversations,
|
|
315
|
+
llm_config=llm_config,
|
|
316
|
+
args=self.args
|
|
317
|
+
)
|
|
318
|
+
full_response, last_meta = stream_out(
|
|
319
|
+
stream_generator,
|
|
320
|
+
model_name=model_name,
|
|
321
|
+
title=get_message_with_format(
|
|
322
|
+
"code_generate_title", model_name=model_name),
|
|
323
|
+
args=self.args,
|
|
324
|
+
extra_meta={
|
|
325
|
+
"stream_out_type": CodeGenerateStreamOutType.CODE_GENERATE.value
|
|
326
|
+
})
|
|
327
|
+
return ChatWithContinueResult(
|
|
328
|
+
content=full_response,
|
|
329
|
+
input_tokens_count=last_meta.input_tokens_count,
|
|
330
|
+
generated_tokens_count=last_meta.generated_tokens_count
|
|
331
|
+
)
|
|
332
|
+
futures.append(executor.submit(job))
|
|
333
|
+
else:
|
|
334
|
+
futures.append(executor.submit(
|
|
335
|
+
chat_with_continue,
|
|
336
|
+
llm=llm,
|
|
337
|
+
conversations=conversations,
|
|
338
|
+
llm_config=llm_config,
|
|
339
|
+
args=self.args
|
|
340
|
+
))
|
|
341
|
+
|
|
342
|
+
temp_results = [future.result() for future in futures]
|
|
343
|
+
|
|
344
|
+
for result,model_name in zip(temp_results,model_names):
|
|
345
|
+
results.append(result.content)
|
|
346
|
+
input_tokens_count += result.input_tokens_count
|
|
347
|
+
generated_tokens_count += result.generated_tokens_count
|
|
348
|
+
model_info = llm_utils.get_model_info(model_name,self.args.product_mode)
|
|
349
|
+
input_cost = model_info.get("input_price", 0) if model_info else 0
|
|
350
|
+
output_cost = model_info.get("output_price", 0) if model_info else 0
|
|
351
|
+
input_tokens_cost += input_cost * result.input_tokens_count / 1000000
|
|
352
|
+
generated_tokens_cost += output_cost * result.generated_tokens_count / 1000000
|
|
353
|
+
|
|
354
|
+
for result in results:
|
|
355
|
+
conversations_list.append(
|
|
356
|
+
conversations + [{"role": "assistant", "content": result}])
|
|
357
|
+
else:
|
|
358
|
+
for _ in range(self.args.human_model_num):
|
|
359
|
+
single_result = chat_with_continue(
|
|
360
|
+
llm=self.llms[0],
|
|
361
|
+
conversations=conversations,
|
|
362
|
+
llm_config=llm_config,
|
|
363
|
+
args=self.args
|
|
364
|
+
)
|
|
365
|
+
results.append(single_result.content)
|
|
366
|
+
input_tokens_count += single_result.input_tokens_count
|
|
367
|
+
generated_tokens_count += single_result.generated_tokens_count
|
|
368
|
+
conversations_list.append(
|
|
369
|
+
conversations + [{"role": "assistant", "content": single_result.content}])
|
|
370
|
+
|
|
371
|
+
statistics = {
|
|
372
|
+
"input_tokens_count": input_tokens_count,
|
|
373
|
+
"generated_tokens_count": generated_tokens_count,
|
|
374
|
+
"input_tokens_cost": input_tokens_cost,
|
|
375
|
+
"generated_tokens_cost": generated_tokens_cost
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
return CodeGenerateResult(contents=results, conversations=conversations_list, metadata=statistics)
|
|
379
|
+
|
|
380
|
+
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
from typing import List, Dict, Tuple
|
|
2
|
+
from autocoder.common.types import Mode, CodeGenerateResult
|
|
3
|
+
from autocoder.common import AutoCoderArgs
|
|
4
|
+
import byzerllm
|
|
5
|
+
from autocoder.common import sys_prompt
|
|
6
|
+
from autocoder.common.v2.code_auto_generate import CodeAutoGenerate
|
|
7
|
+
from autocoder.common import SourceCodeList
|
|
8
|
+
|
|
9
|
+
class CodeAutoGenerateStrictDiff(CodeAutoGenerate):
|
|
10
|
+
"""
|
|
11
|
+
A class that handles code generation in strict diff format.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
@byzerllm.prompt(llm=lambda self: self.llm)
|
|
15
|
+
def single_round_instruction(
|
|
16
|
+
self, instruction: str, content: str, context: str = "", package_context: str = ""
|
|
17
|
+
) -> str:
|
|
18
|
+
"""
|
|
19
|
+
如果你需要生成代码,对于每个需要更改的文件,写出类似于 unified diff 的更改,就像`diff -U0`会产生的那样。
|
|
20
|
+
下面是一些生成diff的要求:
|
|
21
|
+
Make sure you include the first 2 lines with the file paths.
|
|
22
|
+
Don't include timestamps with the file paths.
|
|
23
|
+
|
|
24
|
+
Start each hunk of changes with a `@@ ... @@` line.
|
|
25
|
+
Must include line numbers like `diff -U0` does.
|
|
26
|
+
The user's patch tool need them.
|
|
27
|
+
|
|
28
|
+
The user's patch tool needs CORRECT patches that apply cleanly against the current contents of the file!
|
|
29
|
+
Think carefully and make sure you include and mark all lines that need to be removed or changed as `-` lines.
|
|
30
|
+
Make sure you mark all new or modified lines with `+`.
|
|
31
|
+
Don't leave out any lines or the diff patch won't apply correctly.
|
|
32
|
+
|
|
33
|
+
Indentation matters in the diffs!
|
|
34
|
+
|
|
35
|
+
To make a new file, show a diff from `--- /dev/null` to `+++ path/to/new/file.ext`.
|
|
36
|
+
The code part of the diff content should not contains any line number.
|
|
37
|
+
|
|
38
|
+
The path start with `---` or `+++` should be the absolute path of the file or relative path from the project root.
|
|
39
|
+
|
|
40
|
+
下面我们来看一个例子:
|
|
41
|
+
|
|
42
|
+
当前项目目录结构:
|
|
43
|
+
1. 项目根目录: /tmp/projects/mathweb
|
|
44
|
+
2. 项目子目录/文件列表(类似tree 命令输出)
|
|
45
|
+
flask/
|
|
46
|
+
app.py
|
|
47
|
+
templates/
|
|
48
|
+
index.html
|
|
49
|
+
static/
|
|
50
|
+
style.css
|
|
51
|
+
|
|
52
|
+
用户需求: 请将下面的代码中的is_prime()函数替换为sympy。
|
|
53
|
+
回答:
|
|
54
|
+
好的,我会先罗列出需要的修改步骤,然后再列出diff。
|
|
55
|
+
修改步骤:
|
|
56
|
+
1. 添加sympy的import 语句。
|
|
57
|
+
2. 删除is_prime()函数。
|
|
58
|
+
3. 将现有对is_prime()的调用替换为sympy.isprime()。
|
|
59
|
+
|
|
60
|
+
下面是这些变更的diff:
|
|
61
|
+
|
|
62
|
+
```diff
|
|
63
|
+
--- /tmp/projects/mathweb/flask/app.py
|
|
64
|
+
+++ /tmp/projects/mathweb/flask/app.py
|
|
65
|
+
@@ ... @@
|
|
66
|
+
-class MathWeb:
|
|
67
|
+
+import sympy
|
|
68
|
+
+
|
|
69
|
+
+class MathWeb:
|
|
70
|
+
@@ ... @@
|
|
71
|
+
-def is_prime(x):
|
|
72
|
+
- if x < 2:
|
|
73
|
+
- return False
|
|
74
|
+
- for i in range(2, int(math.sqrt(x)) + 1):
|
|
75
|
+
- if x % i == 0:
|
|
76
|
+
- return False
|
|
77
|
+
- return True
|
|
78
|
+
@@ ... @@
|
|
79
|
+
-@app.route('/prime/<int:n>')
|
|
80
|
+
-def nth_prime(n):
|
|
81
|
+
- count = 0
|
|
82
|
+
- num = 1
|
|
83
|
+
- while count < n:
|
|
84
|
+
- num += 1
|
|
85
|
+
- if is_prime(num):
|
|
86
|
+
- count += 1
|
|
87
|
+
- return str(num)
|
|
88
|
+
+@app.route('/prime/<int:n>')
|
|
89
|
+
+def nth_prime(n):
|
|
90
|
+
+ count = 0
|
|
91
|
+
+ num = 1
|
|
92
|
+
+ while count < n:
|
|
93
|
+
+ num += 1
|
|
94
|
+
+ if sympy.isprime(num):
|
|
95
|
+
+ count += 1
|
|
96
|
+
+ return str(num)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
现在让我们开始一个新的任务:
|
|
100
|
+
|
|
101
|
+
{%- if structure %}
|
|
102
|
+
{{ structure }}
|
|
103
|
+
{%- endif %}
|
|
104
|
+
|
|
105
|
+
{%- if content %}
|
|
106
|
+
下面是一些文件路径以及每个文件对应的源码:
|
|
107
|
+
<files>
|
|
108
|
+
{{ content }}
|
|
109
|
+
</files>
|
|
110
|
+
{%- endif %}
|
|
111
|
+
|
|
112
|
+
{%- if package_context %}
|
|
113
|
+
下面是上面文件的一些信息(包括最近的变更情况):
|
|
114
|
+
<package_context>
|
|
115
|
+
{{ package_context }}
|
|
116
|
+
</package_context>
|
|
117
|
+
{%- endif %}
|
|
118
|
+
|
|
119
|
+
{%- if context %}
|
|
120
|
+
<extra_context>
|
|
121
|
+
{{ context }}
|
|
122
|
+
</extra_context>
|
|
123
|
+
{%- endif %}
|
|
124
|
+
|
|
125
|
+
下面是用户的需求:
|
|
126
|
+
|
|
127
|
+
{{ instruction }}
|
|
128
|
+
"""
|
|
129
|
+
|
|
130
|
+
if not self.args.include_project_structure:
|
|
131
|
+
return {
|
|
132
|
+
"structure": "",
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
"structure": (
|
|
137
|
+
self.action.pp.get_tree_like_directory_structure()
|
|
138
|
+
if self.action
|
|
139
|
+
else ""
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
@byzerllm.prompt(llm=lambda self: self.llm)
|
|
144
|
+
def multi_round_instruction(
|
|
145
|
+
self, instruction: str, content: str, context: str = "", package_context: str = ""
|
|
146
|
+
) -> str:
|
|
147
|
+
"""
|
|
148
|
+
如果你需要生成代码,对于每个需要更改的文件,写出类似于 unified diff 的更改,就像`diff -U0`会产生的那样。
|
|
149
|
+
下面是一些生成diff的要求:
|
|
150
|
+
Make sure you include the first 2 lines with the file paths.
|
|
151
|
+
Don't include timestamps with the file paths.
|
|
152
|
+
|
|
153
|
+
Start each hunk of changes with a `@@ ... @@` line.
|
|
154
|
+
Must include line numbers like `diff -U0` does.
|
|
155
|
+
The user's patch tool need them.
|
|
156
|
+
|
|
157
|
+
The user's patch tool needs CORRECT patches that apply cleanly against the current contents of the file!
|
|
158
|
+
Think carefully and make sure you include and mark all lines that need to be removed or changed as `-` lines.
|
|
159
|
+
Make sure you mark all new or modified lines with `+`.
|
|
160
|
+
Don't leave out any lines or the diff patch won't apply correctly.
|
|
161
|
+
|
|
162
|
+
Indentation matters in the diffs!
|
|
163
|
+
|
|
164
|
+
To make a new file, show a diff from `--- /dev/null` to `+++ path/to/new/file.ext`.
|
|
165
|
+
|
|
166
|
+
下面我们来看一个例子:
|
|
167
|
+
|
|
168
|
+
当前项目目录结构:
|
|
169
|
+
1. 项目根目录: /tmp/projects/mathweb
|
|
170
|
+
2. 项目子目录/文件列表(类似tree 命令输出)
|
|
171
|
+
flask/
|
|
172
|
+
app.py
|
|
173
|
+
templates/
|
|
174
|
+
index.html
|
|
175
|
+
static/
|
|
176
|
+
style.css
|
|
177
|
+
|
|
178
|
+
用户需求: 请将下面的代码中的is_prime()函数替换为sympy。
|
|
179
|
+
回答:
|
|
180
|
+
好的,我会先罗列出需要的修改步骤,然后再列出diff。
|
|
181
|
+
修改步骤:
|
|
182
|
+
1. 添加sympy的import 语句。
|
|
183
|
+
2. 删除is_prime()函数。
|
|
184
|
+
3. 将现有对is_prime()的调用替换为sympy.isprime()。
|
|
185
|
+
|
|
186
|
+
下面是这些变更的diff:
|
|
187
|
+
|
|
188
|
+
```diff
|
|
189
|
+
--- /tmp/projects/mathweb/flask/app.py
|
|
190
|
+
+++ /tmp/projects/mathweb/flask/app.py
|
|
191
|
+
@@ ... @@
|
|
192
|
+
-class MathWeb:
|
|
193
|
+
+import sympy
|
|
194
|
+
+
|
|
195
|
+
+class MathWeb:
|
|
196
|
+
@@ ... @@
|
|
197
|
+
-def is_prime(x):
|
|
198
|
+
- if x < 2:
|
|
199
|
+
- return False
|
|
200
|
+
- for i in range(2, int(math.sqrt(x)) + 1):
|
|
201
|
+
- if x % i == 0:
|
|
202
|
+
- return False
|
|
203
|
+
- return True
|
|
204
|
+
@@ ... @@
|
|
205
|
+
-@app.route('/prime/<int:n>')
|
|
206
|
+
-def nth_prime(n):
|
|
207
|
+
- count = 0
|
|
208
|
+
- num = 1
|
|
209
|
+
- while count < n:
|
|
210
|
+
- num += 1
|
|
211
|
+
- if is_prime(num):
|
|
212
|
+
- count += 1
|
|
213
|
+
- return str(num)
|
|
214
|
+
+@app.route('/prime/<int:n>')
|
|
215
|
+
+def nth_prime(n):
|
|
216
|
+
+ count = 0
|
|
217
|
+
+ num = 1
|
|
218
|
+
+ while count < n:
|
|
219
|
+
+ num += 1
|
|
220
|
+
+ if sympy.isprime(num):
|
|
221
|
+
+ count += 1
|
|
222
|
+
+ return str(num)
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
现在让我们开始一个新的任务:
|
|
226
|
+
|
|
227
|
+
{%- if structure %}
|
|
228
|
+
{{ structure }}
|
|
229
|
+
{%- endif %}
|
|
230
|
+
|
|
231
|
+
{%- if content %}
|
|
232
|
+
下面是一些文件路径以及每个文件对应的源码:
|
|
233
|
+
<files>
|
|
234
|
+
{{ content }}
|
|
235
|
+
</files>
|
|
236
|
+
{%- endif %}
|
|
237
|
+
|
|
238
|
+
{%- if package_context %}
|
|
239
|
+
下面是上面文件的一些信息(包括最近的变更情况):
|
|
240
|
+
<package_context>
|
|
241
|
+
{{ package_context }}
|
|
242
|
+
</package_context>
|
|
243
|
+
{%- endif %}
|
|
244
|
+
|
|
245
|
+
{%- if context %}
|
|
246
|
+
<extra_context>
|
|
247
|
+
{{ context }}
|
|
248
|
+
</extra_context>
|
|
249
|
+
{%- endif %}
|
|
250
|
+
|
|
251
|
+
下面是用户的需求:
|
|
252
|
+
|
|
253
|
+
{{ instruction }}
|
|
254
|
+
|
|
255
|
+
每次生成一个文件的diff,然后询问我是否继续,当我回复继续,继续生成下一个文件的diff。当没有后续任务时,请回复 "__完成__" 或者 "__EOF__"。
|
|
256
|
+
"""
|
|
257
|
+
|
|
258
|
+
if not self.args.include_project_structure:
|
|
259
|
+
return {
|
|
260
|
+
"structure": "",
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return {
|
|
264
|
+
"structure": (
|
|
265
|
+
self.action.pp.get_tree_like_directory_structure()
|
|
266
|
+
if self.action
|
|
267
|
+
else ""
|
|
268
|
+
)
|
|
269
|
+
}
|