auto-coder 0.1.263__py3-none-any.whl → 0.1.265__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.263.dist-info → auto_coder-0.1.265.dist-info}/METADATA +1 -1
- {auto_coder-0.1.263.dist-info → auto_coder-0.1.265.dist-info}/RECORD +58 -55
- autocoder/agent/planner.py +4 -4
- autocoder/auto_coder.py +26 -21
- autocoder/auto_coder_server.py +7 -7
- autocoder/chat_auto_coder.py +203 -98
- autocoder/commands/auto_command.py +81 -4
- autocoder/commands/tools.py +48 -50
- autocoder/common/__init__.py +6 -1
- autocoder/common/auto_coder_lang.py +41 -3
- autocoder/common/code_auto_generate.py +3 -3
- autocoder/common/code_auto_generate_diff.py +12 -15
- autocoder/common/code_auto_generate_editblock.py +3 -3
- autocoder/common/code_auto_generate_strict_diff.py +3 -3
- autocoder/common/code_auto_merge.py +23 -3
- autocoder/common/code_auto_merge_diff.py +29 -4
- autocoder/common/code_auto_merge_editblock.py +25 -5
- autocoder/common/code_auto_merge_strict_diff.py +26 -6
- autocoder/common/code_modification_ranker.py +65 -3
- autocoder/common/command_completer.py +3 -0
- autocoder/common/command_generator.py +24 -8
- autocoder/common/command_templates.py +2 -2
- autocoder/common/conf_import_export.py +105 -0
- autocoder/common/conf_validator.py +7 -1
- autocoder/common/context_pruner.py +305 -0
- autocoder/common/files.py +41 -2
- autocoder/common/image_to_page.py +11 -11
- autocoder/common/index_import_export.py +38 -18
- autocoder/common/mcp_hub.py +3 -3
- autocoder/common/mcp_server.py +2 -2
- autocoder/common/shells.py +254 -13
- autocoder/common/stats_panel.py +126 -0
- autocoder/dispacher/actions/action.py +6 -18
- autocoder/dispacher/actions/copilot.py +2 -2
- autocoder/dispacher/actions/plugins/action_regex_project.py +1 -3
- autocoder/dispacher/actions/plugins/action_translate.py +1 -1
- autocoder/index/entry.py +8 -2
- autocoder/index/filter/normal_filter.py +13 -2
- autocoder/index/filter/quick_filter.py +127 -13
- autocoder/index/index.py +8 -7
- autocoder/models.py +2 -2
- autocoder/pyproject/__init__.py +5 -5
- autocoder/rag/cache/byzer_storage_cache.py +4 -4
- autocoder/rag/cache/file_monitor_cache.py +2 -2
- autocoder/rag/cache/simple_cache.py +4 -4
- autocoder/rag/long_context_rag.py +2 -2
- autocoder/regexproject/__init__.py +3 -2
- autocoder/suffixproject/__init__.py +3 -2
- autocoder/tsproject/__init__.py +3 -2
- autocoder/utils/conversation_store.py +1 -1
- autocoder/utils/operate_config_api.py +3 -3
- autocoder/utils/project_structure.py +258 -3
- autocoder/utils/thread_utils.py +6 -1
- autocoder/version.py +1 -1
- {auto_coder-0.1.263.dist-info → auto_coder-0.1.265.dist-info}/LICENSE +0 -0
- {auto_coder-0.1.263.dist-info → auto_coder-0.1.265.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.263.dist-info → auto_coder-0.1.265.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.263.dist-info → auto_coder-0.1.265.dist-info}/top_level.txt +0 -0
|
@@ -10,6 +10,7 @@ import hashlib
|
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
from autocoder.common.types import CodeGenerateResult, MergeCodeWithoutEffect
|
|
12
12
|
from autocoder.common.code_modification_ranker import CodeModificationRanker
|
|
13
|
+
from autocoder.common import files as FileUtils
|
|
13
14
|
|
|
14
15
|
class PathAndCode(pydantic.BaseModel):
|
|
15
16
|
path: str
|
|
@@ -138,15 +139,35 @@ class CodeAutoMergeStrictDiff:
|
|
|
138
139
|
def choose_best_choice(self, generate_result: CodeGenerateResult) -> CodeGenerateResult:
|
|
139
140
|
if len(generate_result.contents) == 1:
|
|
140
141
|
return generate_result
|
|
142
|
+
|
|
143
|
+
merge_results = []
|
|
144
|
+
for content,conversations in zip(generate_result.contents,generate_result.conversations):
|
|
145
|
+
merge_result = self._merge_code_without_effect(content)
|
|
146
|
+
merge_results.append(merge_result)
|
|
147
|
+
|
|
148
|
+
# If all merge results are None, return first one
|
|
149
|
+
if all(len(result.failed_blocks) != 0 for result in merge_results):
|
|
150
|
+
self.printer.print_in_terminal("all_merge_results_failed")
|
|
151
|
+
return CodeGenerateResult(contents=[generate_result.contents[0]], conversations=[generate_result.conversations[0]])
|
|
152
|
+
|
|
153
|
+
# If only one merge result is not None, return that one
|
|
154
|
+
not_none_indices = [i for i, result in enumerate(merge_results) if len(result.failed_blocks) == 0]
|
|
155
|
+
if len(not_none_indices) == 1:
|
|
156
|
+
idx = not_none_indices[0]
|
|
157
|
+
self.printer.print_in_terminal("only_one_merge_result_success")
|
|
158
|
+
return CodeGenerateResult(contents=[generate_result.contents[idx]], conversations=[generate_result.conversations[idx]])
|
|
141
159
|
|
|
160
|
+
# 最后,如果有多个,那么根据质量排序再返回
|
|
142
161
|
ranker = CodeModificationRanker(self.llm, self.args)
|
|
143
|
-
ranked_result = ranker.rank_modifications(generate_result)
|
|
144
|
-
|
|
162
|
+
ranked_result = ranker.rank_modifications(generate_result,merge_results)
|
|
163
|
+
|
|
164
|
+
## 得到的结果,再做一次合并,第一个通过的返回 , 返回做合并有点重复低效,未来修改。
|
|
145
165
|
for content,conversations in zip(ranked_result.contents,ranked_result.conversations):
|
|
146
166
|
merge_result = self._merge_code_without_effect(content)
|
|
147
167
|
if not merge_result.failed_blocks:
|
|
148
168
|
return CodeGenerateResult(contents=[content], conversations=[conversations])
|
|
149
|
-
|
|
169
|
+
|
|
170
|
+
# 最后保底,但实际不会出现
|
|
150
171
|
return CodeGenerateResult(contents=[ranked_result.contents[0]], conversations=[ranked_result.conversations[0]])
|
|
151
172
|
|
|
152
173
|
|
|
@@ -175,8 +196,7 @@ class CodeAutoMergeStrictDiff:
|
|
|
175
196
|
continue
|
|
176
197
|
|
|
177
198
|
if full_path not in file_content_mapping:
|
|
178
|
-
|
|
179
|
-
file_content_mapping[full_path] = f.read()
|
|
199
|
+
file_content_mapping[full_path] = FileUtils.read_file(full_path)
|
|
180
200
|
|
|
181
201
|
try:
|
|
182
202
|
import patch
|
|
@@ -204,7 +224,7 @@ class CodeAutoMergeStrictDiff:
|
|
|
204
224
|
def _merge_code(self, content: str, force_skip_git: bool = False):
|
|
205
225
|
total = 0
|
|
206
226
|
|
|
207
|
-
file_content =
|
|
227
|
+
file_content = FileUtils.read_file(self.args.file)
|
|
208
228
|
md5 = hashlib.md5(file_content.encode('utf-8')).hexdigest()
|
|
209
229
|
# get the file name
|
|
210
230
|
file_name = os.path.basename(self.args.file)
|
|
@@ -9,6 +9,8 @@ import traceback
|
|
|
9
9
|
from autocoder.common.utils_code_auto_generate import chat_with_continue
|
|
10
10
|
from byzerllm.utils.str2model import to_model
|
|
11
11
|
from autocoder.utils.llms import get_llm_names, get_model_info
|
|
12
|
+
from autocoder.common.types import CodeGenerateResult, MergeCodeWithoutEffect
|
|
13
|
+
import os
|
|
12
14
|
|
|
13
15
|
class RankResult(BaseModel):
|
|
14
16
|
rank_result: List[int]
|
|
@@ -51,12 +53,67 @@ class CodeModificationRanker:
|
|
|
51
53
|
}
|
|
52
54
|
```
|
|
53
55
|
|
|
54
|
-
注意:
|
|
56
|
+
注意:
|
|
55
57
|
1. id 为 edit_block 的 id,按质量从高到低排序,并且 id 必须是数字
|
|
56
58
|
2. 只输出前面要求的 Json 格式就好,不要输出其他内容,Json 需要使用 ```json ```包裹
|
|
57
59
|
'''
|
|
58
60
|
|
|
59
|
-
|
|
61
|
+
@byzerllm.prompt()
|
|
62
|
+
def _rank_modifications_with_merge_result(self, s: CodeGenerateResult,merge_results: List[MergeCodeWithoutEffect]) -> str:
|
|
63
|
+
'''
|
|
64
|
+
对一组代码修改进行质量评估并排序。
|
|
65
|
+
|
|
66
|
+
下面是修改需求:
|
|
67
|
+
|
|
68
|
+
<edit_requirement>
|
|
69
|
+
{{ s.conversations[0][-2]["content"] }}
|
|
70
|
+
</edit_requirement>
|
|
71
|
+
|
|
72
|
+
下面是相应的代码修改,如果Before 为空,那么表示是新增文件,如果After 为空,那么表示是删除文件,如果Before 和 After 都不为空,那么表示是修改文件:
|
|
73
|
+
{% for change in changes %}
|
|
74
|
+
<edit_file id="{{ loop.index0 }}">
|
|
75
|
+
{{change}}
|
|
76
|
+
</edit_file>
|
|
77
|
+
{% endfor %}
|
|
78
|
+
|
|
79
|
+
请输出如下格式的评估结果,只包含 JSON 数据:
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"rank_result": [id1, id2, id3]
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
注意:
|
|
88
|
+
1. 像python的缩进,前端诸如 reacjs,vue 的标签闭合匹配,这些很重要,需要在排序中作为重点考虑对象之一。
|
|
89
|
+
1. id 为 edit_file 的 id,按质量从高到低排序,并且 id 必须是数字
|
|
90
|
+
2. 只输出前面要求的 Json 格式就好,不要输出其他内容,Json 需要使用 ```json ```包裹
|
|
91
|
+
'''
|
|
92
|
+
changes = []
|
|
93
|
+
for merge_result in merge_results:
|
|
94
|
+
s = ""
|
|
95
|
+
for block in merge_result.success_blocks:
|
|
96
|
+
file_path,content = block
|
|
97
|
+
s += f"##File: {file_path}\n\n"
|
|
98
|
+
if not os.path.exists(file_path):
|
|
99
|
+
s += f"##Before: \n\n"
|
|
100
|
+
s += f"##File: {file_path}\n\n"
|
|
101
|
+
s += f"##After: \n\n"
|
|
102
|
+
s += content
|
|
103
|
+
else:
|
|
104
|
+
with open(file_path, "r",encoding="utf-8") as f:
|
|
105
|
+
original_content = f.read()
|
|
106
|
+
s += f"##Before: \n\n"
|
|
107
|
+
s += original_content
|
|
108
|
+
s += f"##File: {file_path}\n\n"
|
|
109
|
+
s += f"##After: \n\n"
|
|
110
|
+
s += content
|
|
111
|
+
changes.append(s)
|
|
112
|
+
return {
|
|
113
|
+
"changes": changes
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
def rank_modifications(self, generate_result: CodeGenerateResult, merge_result: List[MergeCodeWithoutEffect]) -> CodeGenerateResult:
|
|
60
117
|
import time
|
|
61
118
|
from collections import defaultdict
|
|
62
119
|
|
|
@@ -69,8 +126,13 @@ class CodeModificationRanker:
|
|
|
69
126
|
|
|
70
127
|
rank_times = self.args.rank_times_same_model
|
|
71
128
|
total_tasks = len(self.llms) * rank_times
|
|
129
|
+
if self.args.rank_strategy == "block":
|
|
130
|
+
query = self._rank_modifications.prompt(generate_result)
|
|
131
|
+
elif self.args.rank_strategy == "file":
|
|
132
|
+
query = self._rank_modifications_with_merge_result.prompt(generate_result, merge_result)
|
|
133
|
+
else:
|
|
134
|
+
raise Exception(f"Invalid rank strategy: {self.args.rank_strategy}")
|
|
72
135
|
|
|
73
|
-
query = self._rank_modifications.prompt(generate_result)
|
|
74
136
|
input_tokens_count = 0
|
|
75
137
|
generated_tokens_count = 0
|
|
76
138
|
try:
|
|
@@ -4,6 +4,7 @@ from autocoder.utils.auto_coder_utils.chat_stream_out import stream_out
|
|
|
4
4
|
from autocoder.common import detect_env
|
|
5
5
|
from autocoder.common import shells
|
|
6
6
|
from autocoder.common.printer import Printer
|
|
7
|
+
from typing import Dict,Union
|
|
7
8
|
|
|
8
9
|
@byzerllm.prompt()
|
|
9
10
|
def _generate_shell_script(user_input: str) -> str:
|
|
@@ -14,6 +15,11 @@ def _generate_shell_script(user_input: str) -> str:
|
|
|
14
15
|
Python版本: {{ env_info.python_version }}
|
|
15
16
|
终端类型: {{ env_info.shell_type }}
|
|
16
17
|
终端编码: {{ env_info.shell_encoding }}
|
|
18
|
+
|
|
19
|
+
{%- if shell_type %}
|
|
20
|
+
脚本类型:{{ shell_type }}
|
|
21
|
+
{%- endif %}
|
|
22
|
+
|
|
17
23
|
{%- if env_info.conda_env %}
|
|
18
24
|
Conda环境: {{ env_info.conda_env }}
|
|
19
25
|
{%- endif %}
|
|
@@ -21,29 +27,39 @@ def _generate_shell_script(user_input: str) -> str:
|
|
|
21
27
|
虚拟环境: {{ env_info.virtualenv }}
|
|
22
28
|
{%- endif %}
|
|
23
29
|
|
|
24
|
-
|
|
30
|
+
根据用户的输入以及当前的操作系统和终端类型以及脚本类型生成脚本,
|
|
31
|
+
注意只能生成一个shell脚本,不要生成多个。
|
|
25
32
|
|
|
26
33
|
用户输入: {{ user_input }}
|
|
27
34
|
|
|
28
|
-
|
|
35
|
+
请生成一个适当的脚本来执行用户的请求。确保脚本是安全的,并且可以在当前Shell环境中运行。
|
|
29
36
|
脚本应该包含必要的注释来解释每个步骤。
|
|
30
37
|
脚本内容请用如下方式返回:
|
|
31
38
|
|
|
32
|
-
```
|
|
33
|
-
# 你的
|
|
39
|
+
```script
|
|
40
|
+
# 你的 script 脚本内容
|
|
34
41
|
```
|
|
35
42
|
"""
|
|
36
|
-
env_info = detect_env()
|
|
43
|
+
env_info = detect_env()
|
|
44
|
+
shell_type = "bash"
|
|
45
|
+
if shells.is_running_in_cmd():
|
|
46
|
+
shell_type = "cmd"
|
|
47
|
+
elif shells.is_running_in_powershell():
|
|
48
|
+
shell_type = "powershell"
|
|
37
49
|
return {
|
|
38
50
|
"env_info": env_info,
|
|
39
|
-
"shell_type":
|
|
51
|
+
"shell_type": shell_type,
|
|
40
52
|
"shell_encoding": shells.get_terminal_encoding()
|
|
41
53
|
}
|
|
42
54
|
|
|
43
55
|
|
|
44
|
-
def generate_shell_script(user_input: str, llm: byzerllm.ByzerLLM) -> str:
|
|
56
|
+
def generate_shell_script(user_input: str, llm: Union[byzerllm.ByzerLLM,byzerllm.SimpleByzerLLM]) -> str:
|
|
45
57
|
# 获取 prompt 内容
|
|
46
58
|
prompt = _generate_shell_script.prompt(user_input=user_input)
|
|
59
|
+
if llm.get_sub_client("chat_model"):
|
|
60
|
+
shell_llm = llm.get_sub_client("chat_model")
|
|
61
|
+
else:
|
|
62
|
+
shell_llm = llm
|
|
47
63
|
|
|
48
64
|
# 构造对话上下文
|
|
49
65
|
conversations = [{"role": "user", "content": prompt}]
|
|
@@ -52,7 +68,7 @@ def generate_shell_script(user_input: str, llm: byzerllm.ByzerLLM) -> str:
|
|
|
52
68
|
printer = Printer()
|
|
53
69
|
title = printer.get_message_from_key("generating_shell_script")
|
|
54
70
|
result, _ = stream_out(
|
|
55
|
-
|
|
71
|
+
shell_llm.stream_chat_oai(conversations=conversations, delta_mode=True),
|
|
56
72
|
model_name=llm.default_model_name,
|
|
57
73
|
title=title
|
|
58
74
|
)
|
|
@@ -139,7 +139,7 @@ def create_actions(source_dir:str,params:Dict[str,str]):
|
|
|
139
139
|
"000_example": base_000_example.prompt(),
|
|
140
140
|
}
|
|
141
141
|
init_file_path = os.path.join(source_dir, "actions", "101_current_work.yml")
|
|
142
|
-
with open(init_file_path, "w") as f:
|
|
142
|
+
with open(init_file_path, "w", encoding="utf-8") as f:
|
|
143
143
|
f.write(init_command_template.prompt(source_dir=source_dir))
|
|
144
144
|
|
|
145
145
|
for k,v in mapping.items():
|
|
@@ -152,7 +152,7 @@ def create_actions(source_dir:str,params:Dict[str,str]):
|
|
|
152
152
|
if k == "000_example":
|
|
153
153
|
file_path = os.path.join(source_dir, "actions", f"{k}.yml")
|
|
154
154
|
|
|
155
|
-
with open(file_path, "w") as f:
|
|
155
|
+
with open(file_path, "w", encoding="utf-8") as f:
|
|
156
156
|
f.write(v)
|
|
157
157
|
|
|
158
158
|
@byzerllm.prompt()
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import json
|
|
3
|
+
import shutil
|
|
4
|
+
from loguru import logger
|
|
5
|
+
from autocoder.common.printer import Printer
|
|
6
|
+
from autocoder.common.result_manager import ResultManager
|
|
7
|
+
|
|
8
|
+
result_manager = ResultManager()
|
|
9
|
+
|
|
10
|
+
def export_conf(project_root: str, export_path: str) -> bool:
|
|
11
|
+
printer = Printer()
|
|
12
|
+
"""
|
|
13
|
+
Export conf from memory.json to a specified directory
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
project_root: Project root directory
|
|
17
|
+
export_path: Path to export the conf file
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
bool: True if successful, False otherwise
|
|
21
|
+
"""
|
|
22
|
+
project_root = os.path.abspath(project_root) or os.getcwd()
|
|
23
|
+
try:
|
|
24
|
+
memory_path = os.path.join(project_root, ".auto-coder", "plugins", "chat-auto-coder", "memory.json")
|
|
25
|
+
if not os.path.exists(memory_path):
|
|
26
|
+
printer.print_in_terminal("conf_not_found", path=memory_path)
|
|
27
|
+
return False
|
|
28
|
+
|
|
29
|
+
# Read and extract conf
|
|
30
|
+
with open(memory_path, "r",encoding="utf-8") as f:
|
|
31
|
+
memory_data = json.load(f)
|
|
32
|
+
|
|
33
|
+
conf_data = memory_data.get("conf", {})
|
|
34
|
+
|
|
35
|
+
# Write to export location
|
|
36
|
+
export_file = os.path.join(export_path, "conf.json")
|
|
37
|
+
os.makedirs(export_path, exist_ok=True)
|
|
38
|
+
with open(export_file, "w",encoding="utf-8") as f:
|
|
39
|
+
json.dump(conf_data, f, indent=2)
|
|
40
|
+
printer.print_in_terminal("conf_export_success", path=export_file)
|
|
41
|
+
result_manager.add_result(content=printer.get_message_from_key_with_format("conf_export_success", path=export_file), meta={"action": "conf_export", "input": {
|
|
42
|
+
"path": export_file
|
|
43
|
+
}})
|
|
44
|
+
return True
|
|
45
|
+
|
|
46
|
+
except Exception as e:
|
|
47
|
+
result_manager.add_result(content=printer.get_message_from_key_with_format("conf_export_error", error=str(e)), meta={"action": "conf_export", "input": {
|
|
48
|
+
"path": export_file
|
|
49
|
+
}})
|
|
50
|
+
printer.print_in_terminal("conf_export_error", error=str(e))
|
|
51
|
+
return False
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def import_conf(project_root: str, import_path: str) -> bool:
|
|
55
|
+
project_root = os.path.abspath(project_root) or os.getcwd()
|
|
56
|
+
printer = Printer()
|
|
57
|
+
"""
|
|
58
|
+
Import conf from a specified directory into memory.json
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
project_root: Project root directory
|
|
62
|
+
import_path: Path containing the conf file to import
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
bool: True if successful, False otherwise
|
|
66
|
+
"""
|
|
67
|
+
try:
|
|
68
|
+
import_file = os.path.join(import_path, "conf.json")
|
|
69
|
+
if not os.path.exists(import_file):
|
|
70
|
+
printer.print_in_terminal("conf_not_found", path=import_file)
|
|
71
|
+
return False
|
|
72
|
+
|
|
73
|
+
# Read conf file
|
|
74
|
+
with open(import_file, "r",encoding="utf-8") as f:
|
|
75
|
+
conf_data = json.load(f)
|
|
76
|
+
|
|
77
|
+
# Backup existing memory
|
|
78
|
+
memory_path = os.path.join(project_root, ".auto-coder", "plugins", "chat-auto-coder", "memory.json")
|
|
79
|
+
if os.path.exists(memory_path):
|
|
80
|
+
backup_path = memory_path + ".bak"
|
|
81
|
+
shutil.copy2(memory_path, backup_path)
|
|
82
|
+
printer.print_in_terminal("conf_backup_success", path=backup_path)
|
|
83
|
+
|
|
84
|
+
# Update conf in memory
|
|
85
|
+
with open(memory_path, "r",encoding="utf-8") as f:
|
|
86
|
+
memory_data = json.load(f)
|
|
87
|
+
|
|
88
|
+
memory_data["conf"] = conf_data
|
|
89
|
+
|
|
90
|
+
# Write updated memory
|
|
91
|
+
with open(memory_path, "w",encoding="utf-8") as f:
|
|
92
|
+
json.dump(memory_data, f, indent=2)
|
|
93
|
+
|
|
94
|
+
printer.print_in_terminal("conf_import_success", path=memory_path)
|
|
95
|
+
result_manager.add_result(content=printer.get_message_from_key_with_format("conf_import_success", path=memory_path), meta={"action": "conf_import", "input": {
|
|
96
|
+
"path": memory_path
|
|
97
|
+
}})
|
|
98
|
+
return True
|
|
99
|
+
|
|
100
|
+
except Exception as e:
|
|
101
|
+
result_manager.add_result(content=printer.get_message_from_key_with_format("conf_import_error", error=str(e)), meta={"action": "conf_import", "input": {
|
|
102
|
+
"path": memory_path
|
|
103
|
+
}})
|
|
104
|
+
printer.print_in_terminal("conf_import_error", error=str(e))
|
|
105
|
+
return False
|
|
@@ -132,11 +132,17 @@ class ConfigValidator:
|
|
|
132
132
|
"type": str,
|
|
133
133
|
"default": "v3_chat",
|
|
134
134
|
"description": "提交信息生成模型名称"
|
|
135
|
+
},
|
|
136
|
+
"rank_strategy": {
|
|
137
|
+
"type": str,
|
|
138
|
+
"allowed": ["block", "file"],
|
|
139
|
+
"default": "block",
|
|
140
|
+
"description": "排序策略(block/file)"
|
|
135
141
|
}
|
|
136
142
|
}
|
|
137
143
|
|
|
138
144
|
@classmethod
|
|
139
|
-
def validate(cls, key: str, value: Any, product_mode: str) -> Any:
|
|
145
|
+
def validate(cls, key: str, value: Any, product_mode: str) -> Any:
|
|
140
146
|
# 获取配置规范
|
|
141
147
|
spec = cls.CONFIG_SPEC.get(key)
|
|
142
148
|
if not spec:
|