auto-coder 0.1.355__py3-none-any.whl → 0.1.356__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.355.dist-info → auto_coder-0.1.356.dist-info}/METADATA +1 -1
- {auto_coder-0.1.355.dist-info → auto_coder-0.1.356.dist-info}/RECORD +19 -17
- autocoder/agent/auto_learn.py +631 -0
- autocoder/auto_coder_runner.py +9 -10
- autocoder/chat/rules_command.py +458 -0
- autocoder/chat_auto_coder.py +5 -0
- autocoder/chat_auto_coder_lang.py +130 -0
- autocoder/common/auto_coder_lang.py +9 -1
- autocoder/common/command_completer_v2.py +39 -0
- autocoder/common/rulefiles/autocoderrules_utils.py +83 -0
- autocoder/common/v2/agent/agentic_edit.py +1 -1
- autocoder/rag/loaders/image_loader.py +25 -13
- autocoder/rag/long_context_rag.py +2 -2
- autocoder/utils/model_provider_selector.py +14 -2
- autocoder/version.py +1 -1
- {auto_coder-0.1.355.dist-info → auto_coder-0.1.356.dist-info}/LICENSE +0 -0
- {auto_coder-0.1.355.dist-info → auto_coder-0.1.356.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.355.dist-info → auto_coder-0.1.356.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.355.dist-info → auto_coder-0.1.356.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import io
|
|
3
|
+
import fnmatch
|
|
4
|
+
import json
|
|
5
|
+
import pathspec
|
|
6
|
+
from typing import Dict, Any, List, Callable, Optional
|
|
7
|
+
from rich.console import Console
|
|
8
|
+
from rich.panel import Panel
|
|
9
|
+
from rich.table import Table
|
|
10
|
+
from rich.text import Text
|
|
11
|
+
from rich.markdown import Markdown
|
|
12
|
+
from autocoder.auto_coder_runner import get_memory, save_memory
|
|
13
|
+
from autocoder.common.rulefiles.autocoderrules_utils import AutocoderRulesManager
|
|
14
|
+
from autocoder.agent.auto_learn import AutoLearn
|
|
15
|
+
from autocoder.common import SourceCode, SourceCodeList
|
|
16
|
+
from autocoder.auto_coder_runner import get_final_config, get_single_llm
|
|
17
|
+
from autocoder.chat_auto_coder_lang import get_message, get_message_with_format
|
|
18
|
+
from autocoder.rag.token_counter import count_tokens
|
|
19
|
+
from autocoder.common.printer import Printer
|
|
20
|
+
from autocoder.command_parser import CommandParser
|
|
21
|
+
from loguru import logger
|
|
22
|
+
|
|
23
|
+
printer = Printer()
|
|
24
|
+
|
|
25
|
+
# Helper function to print the rules files table (internal implementation)
|
|
26
|
+
def _print_rules_table(rules: Dict[str, str], pattern: str = "*"):
|
|
27
|
+
"""Display rules files in a Rich table format."""
|
|
28
|
+
console = Console() # Capture output
|
|
29
|
+
|
|
30
|
+
# Create a styled table with rounded borders
|
|
31
|
+
title_text = get_message_with_format("rules_file_list_title", pattern=pattern)
|
|
32
|
+
printer.print_str_in_terminal(title_text)
|
|
33
|
+
table = Table(
|
|
34
|
+
show_header=True,
|
|
35
|
+
header_style="bold magenta",
|
|
36
|
+
title=title_text,
|
|
37
|
+
title_style="bold blue",
|
|
38
|
+
border_style="blue",
|
|
39
|
+
show_lines=True
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# Add columns with explicit width and alignment
|
|
43
|
+
column_title = get_message("rules_file_path")
|
|
44
|
+
printer.print_str_in_terminal(column_title)
|
|
45
|
+
table.add_column(column_title, style="cyan", justify="left", width=80, no_wrap=False)
|
|
46
|
+
table.add_column("Token数", style="green", justify="right", width=15, no_wrap=False)
|
|
47
|
+
|
|
48
|
+
# Sort keys for consistent display
|
|
49
|
+
for file_path in sorted(rules.keys()):
|
|
50
|
+
if not fnmatch.fnmatch(os.path.basename(file_path), pattern):
|
|
51
|
+
continue
|
|
52
|
+
|
|
53
|
+
content = rules[file_path]
|
|
54
|
+
token_count = count_tokens(content)
|
|
55
|
+
|
|
56
|
+
# Format display values
|
|
57
|
+
formatted_path = Text(file_path, style="cyan")
|
|
58
|
+
formatted_token_count = Text(str(token_count), style="bright_cyan")
|
|
59
|
+
|
|
60
|
+
table.add_row(formatted_path, formatted_token_count)
|
|
61
|
+
|
|
62
|
+
# Add padding and print with a panel
|
|
63
|
+
console.print(Panel(
|
|
64
|
+
table,
|
|
65
|
+
padding=(1, 2),
|
|
66
|
+
subtitle=f"[italic]{get_message('rules_help_subtitle')}[/italic]",
|
|
67
|
+
border_style="blue"
|
|
68
|
+
))
|
|
69
|
+
|
|
70
|
+
# --- Command Handlers ---
|
|
71
|
+
|
|
72
|
+
def _handle_list_rules(memory: Dict[str, Any], args: List[str]) -> str:
|
|
73
|
+
"""Handles listing rules files, supports wildcard filtering."""
|
|
74
|
+
from autocoder.common.rulefiles.autocoderrules_utils import get_rules
|
|
75
|
+
|
|
76
|
+
# 获取项目根目录(当前工作目录)
|
|
77
|
+
project_root = os.getcwd()
|
|
78
|
+
|
|
79
|
+
# 获取所有规则文件
|
|
80
|
+
rules = get_rules(project_root)
|
|
81
|
+
|
|
82
|
+
if not rules:
|
|
83
|
+
message = get_message("rules_no_files_found")
|
|
84
|
+
printer.print_str_in_terminal(message)
|
|
85
|
+
return message
|
|
86
|
+
|
|
87
|
+
# 如果提供了参数,使用它作为过滤模式
|
|
88
|
+
pattern = args[0] if args else "*"
|
|
89
|
+
|
|
90
|
+
# 使用通配符匹配规则文件
|
|
91
|
+
if pattern != "*":
|
|
92
|
+
# 使用 pathspec 处理通配符路径
|
|
93
|
+
try:
|
|
94
|
+
# 创建 pathspec 对象,支持 .gitignore 风格的路径匹配
|
|
95
|
+
spec = pathspec.PathSpec.from_lines(
|
|
96
|
+
pathspec.patterns.GitWildMatchPattern, [pattern]
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
# 获取相对于项目根目录的路径
|
|
100
|
+
rel_paths = {}
|
|
101
|
+
for file_path in rules.keys():
|
|
102
|
+
# 计算相对路径用于匹配
|
|
103
|
+
if os.path.isabs(file_path):
|
|
104
|
+
rel_path = os.path.relpath(file_path, project_root)
|
|
105
|
+
else:
|
|
106
|
+
rel_path = file_path
|
|
107
|
+
rel_paths[file_path] = rel_path
|
|
108
|
+
|
|
109
|
+
# 使用 pathspec 匹配文件
|
|
110
|
+
filtered_rules = {}
|
|
111
|
+
for file_path, rel_path in rel_paths.items():
|
|
112
|
+
if spec.match_file(rel_path):
|
|
113
|
+
filtered_rules[file_path] = rules[file_path]
|
|
114
|
+
|
|
115
|
+
if not filtered_rules:
|
|
116
|
+
message = get_message_with_format("rules_no_matching_files", pattern=pattern)
|
|
117
|
+
printer.print_str_in_terminal(message)
|
|
118
|
+
return message
|
|
119
|
+
return _print_rules_table(filtered_rules, pattern)
|
|
120
|
+
except Exception as e:
|
|
121
|
+
message = f"Error matching pattern '{pattern}': {str(e)}"
|
|
122
|
+
printer.print_str_in_terminal(message)
|
|
123
|
+
return message
|
|
124
|
+
else:
|
|
125
|
+
return _print_rules_table(rules)
|
|
126
|
+
|
|
127
|
+
def _handle_remove_rules(memory: Dict[str, Any], args: List[str]) -> str:
|
|
128
|
+
"""Handles removing rules files based on glob pattern."""
|
|
129
|
+
if not args:
|
|
130
|
+
message = get_message("rules_remove_param_required")
|
|
131
|
+
printer.print_str_in_terminal(message)
|
|
132
|
+
return message
|
|
133
|
+
|
|
134
|
+
pattern = args[0]
|
|
135
|
+
|
|
136
|
+
# 获取规则管理器
|
|
137
|
+
rules_manager = AutocoderRulesManager()
|
|
138
|
+
rules = rules_manager.get_rules()
|
|
139
|
+
|
|
140
|
+
if not rules:
|
|
141
|
+
message = get_message("rules_no_files_found")
|
|
142
|
+
printer.print_str_in_terminal(message)
|
|
143
|
+
return message
|
|
144
|
+
|
|
145
|
+
# 获取项目根目录
|
|
146
|
+
project_root = os.getcwd()
|
|
147
|
+
|
|
148
|
+
# 使用 pathspec 匹配要删除的文件
|
|
149
|
+
files_to_remove = []
|
|
150
|
+
try:
|
|
151
|
+
# 创建 pathspec 对象,支持 .gitignore 风格的路径匹配
|
|
152
|
+
spec = pathspec.PathSpec.from_lines(
|
|
153
|
+
pathspec.patterns.GitWildMatchPattern, [pattern]
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
# 获取相对于项目根目录的路径
|
|
157
|
+
for file_path in rules.keys():
|
|
158
|
+
# 计算相对路径用于匹配
|
|
159
|
+
if os.path.isabs(file_path):
|
|
160
|
+
rel_path = os.path.relpath(file_path, project_root)
|
|
161
|
+
else:
|
|
162
|
+
rel_path = file_path
|
|
163
|
+
|
|
164
|
+
if spec.match_file(rel_path):
|
|
165
|
+
files_to_remove.append(file_path)
|
|
166
|
+
except Exception as e:
|
|
167
|
+
message = f"Error matching pattern '{pattern}': {str(e)}"
|
|
168
|
+
printer.print_str_in_terminal(message)
|
|
169
|
+
return message
|
|
170
|
+
|
|
171
|
+
if not files_to_remove:
|
|
172
|
+
message = get_message_with_format("rules_no_files_to_remove", pattern=pattern)
|
|
173
|
+
printer.print_str_in_terminal(message)
|
|
174
|
+
return message
|
|
175
|
+
|
|
176
|
+
# 删除匹配的文件
|
|
177
|
+
removed_count = 0
|
|
178
|
+
for file_path in files_to_remove:
|
|
179
|
+
try:
|
|
180
|
+
os.remove(file_path)
|
|
181
|
+
removed_count += 1
|
|
182
|
+
except Exception as e:
|
|
183
|
+
message = get_message_with_format("rules_delete_error", file_path=file_path, error=str(e))
|
|
184
|
+
printer.print_str_in_terminal(message)
|
|
185
|
+
return message
|
|
186
|
+
|
|
187
|
+
# 重新加载规则
|
|
188
|
+
rules_manager._load_rules()
|
|
189
|
+
|
|
190
|
+
message = get_message_with_format("rules_delete_success", count=removed_count)
|
|
191
|
+
printer.print_str_in_terminal(message)
|
|
192
|
+
return message
|
|
193
|
+
|
|
194
|
+
def _handle_analyze_commit_rules(memory: Dict[str, Any], args: List[str],commit_id: str, coding_func=None) -> str:
|
|
195
|
+
"""Handles analyzing current files with rules."""
|
|
196
|
+
query = " ".join(args) if args else ""
|
|
197
|
+
|
|
198
|
+
args = get_final_config()
|
|
199
|
+
llm = get_single_llm(args.model, product_mode=args.product_mode)
|
|
200
|
+
auto_learn = AutoLearn(llm=llm, args=args)
|
|
201
|
+
changes, _ = auto_learn.get_commit_changes(commit_id)
|
|
202
|
+
|
|
203
|
+
try:
|
|
204
|
+
result = auto_learn.analyze_commit.prompt(
|
|
205
|
+
querie_with_urls_and_changes=changes,
|
|
206
|
+
new_query=query
|
|
207
|
+
)
|
|
208
|
+
# 如果传入了 coding_func,则执行
|
|
209
|
+
if coding_func is not None:
|
|
210
|
+
coding_func(query=result)
|
|
211
|
+
return result
|
|
212
|
+
except Exception as e:
|
|
213
|
+
logger.exception(e)
|
|
214
|
+
import traceback
|
|
215
|
+
traceback.print_exc()
|
|
216
|
+
message = get_message_with_format("rules_analysis_error", error=str(e))
|
|
217
|
+
printer.print_str_in_terminal(message)
|
|
218
|
+
return message
|
|
219
|
+
|
|
220
|
+
def _handle_analyze_rules(memory: Dict[str, Any], args: List[str], coding_func=None) -> str:
|
|
221
|
+
"""Handles analyzing current files with rules."""
|
|
222
|
+
query = " ".join(args) if args else ""
|
|
223
|
+
|
|
224
|
+
args = get_final_config()
|
|
225
|
+
llm = get_single_llm(args.model, product_mode=args.product_mode)
|
|
226
|
+
auto_learn = AutoLearn(llm=llm, args=args)
|
|
227
|
+
|
|
228
|
+
files = memory.get("current_files", {}).get("files", [])
|
|
229
|
+
if not files:
|
|
230
|
+
message = get_message("rules_no_active_files")
|
|
231
|
+
printer.print_str_in_terminal(message)
|
|
232
|
+
return message
|
|
233
|
+
|
|
234
|
+
sources = SourceCodeList([])
|
|
235
|
+
for file in files:
|
|
236
|
+
try:
|
|
237
|
+
with open(file, "r", encoding="utf-8") as f:
|
|
238
|
+
source_code = f.read()
|
|
239
|
+
sources.sources.append(SourceCode(module_name=file, source_code=source_code))
|
|
240
|
+
except Exception as e:
|
|
241
|
+
message = get_message_with_format("rules_file_read_error", file_path=file, error=str(e))
|
|
242
|
+
printer.print_str_in_terminal(message)
|
|
243
|
+
continue
|
|
244
|
+
|
|
245
|
+
try:
|
|
246
|
+
result = auto_learn.analyze_modules.prompt(sources=sources, query=query)
|
|
247
|
+
# 如果传入了 coding_func,则执行
|
|
248
|
+
if coding_func is not None:
|
|
249
|
+
coding_func(query=result)
|
|
250
|
+
return result
|
|
251
|
+
except Exception as e:
|
|
252
|
+
message = get_message_with_format("rules_analysis_error", error=str(e))
|
|
253
|
+
printer.print_str_in_terminal(message)
|
|
254
|
+
return message
|
|
255
|
+
|
|
256
|
+
def _handle_get_rules(memory: Dict[str, Any], args: List[str]) -> str:
|
|
257
|
+
"""Handles displaying the content of rules files based on glob pattern."""
|
|
258
|
+
if not args:
|
|
259
|
+
message = get_message("rules_get_param_required")
|
|
260
|
+
printer.print_str_in_terminal(message)
|
|
261
|
+
return message
|
|
262
|
+
|
|
263
|
+
pattern = args[0]
|
|
264
|
+
|
|
265
|
+
# 获取规则管理器
|
|
266
|
+
from autocoder.common.rulefiles.autocoderrules_utils import get_rules
|
|
267
|
+
project_root = os.getcwd()
|
|
268
|
+
rules = get_rules(project_root)
|
|
269
|
+
|
|
270
|
+
if not rules:
|
|
271
|
+
message = get_message("rules_no_files_found")
|
|
272
|
+
printer.print_str_in_terminal(message)
|
|
273
|
+
return message
|
|
274
|
+
|
|
275
|
+
# 使用 pathspec 匹配文件
|
|
276
|
+
matched_files = []
|
|
277
|
+
try:
|
|
278
|
+
# 创建 pathspec 对象,支持 .gitignore 风格的路径匹配
|
|
279
|
+
spec = pathspec.PathSpec.from_lines(
|
|
280
|
+
pathspec.patterns.GitWildMatchPattern, [pattern]
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
# 获取相对于项目根目录的路径
|
|
284
|
+
for file_path in rules.keys():
|
|
285
|
+
# 计算相对路径用于匹配
|
|
286
|
+
if os.path.isabs(file_path):
|
|
287
|
+
rel_path = os.path.relpath(file_path, project_root)
|
|
288
|
+
else:
|
|
289
|
+
rel_path = file_path
|
|
290
|
+
|
|
291
|
+
if spec.match_file(rel_path):
|
|
292
|
+
matched_files.append(file_path)
|
|
293
|
+
except Exception as e:
|
|
294
|
+
message = f"Error matching pattern '{pattern}': {str(e)}"
|
|
295
|
+
printer.print_str_in_terminal(message)
|
|
296
|
+
return message
|
|
297
|
+
|
|
298
|
+
if not matched_files:
|
|
299
|
+
message = get_message_with_format("rules_get_no_matching_files", pattern=pattern)
|
|
300
|
+
printer.print_str_in_terminal(message)
|
|
301
|
+
return message
|
|
302
|
+
|
|
303
|
+
# 创建一个真实的控制台,而不是捕获输出
|
|
304
|
+
console = Console()
|
|
305
|
+
|
|
306
|
+
# 打印每个匹配文件的内容
|
|
307
|
+
for file_path in sorted(matched_files):
|
|
308
|
+
try:
|
|
309
|
+
# 获取文件内容
|
|
310
|
+
content = rules[file_path]
|
|
311
|
+
|
|
312
|
+
# 打印文件标题
|
|
313
|
+
console.print("\n")
|
|
314
|
+
console.print(Panel(
|
|
315
|
+
get_message_with_format("rules_get_file_title", file_path=file_path),
|
|
316
|
+
style="bold blue"
|
|
317
|
+
))
|
|
318
|
+
|
|
319
|
+
# 以Markdown格式打印内容
|
|
320
|
+
md = Markdown(content)
|
|
321
|
+
console.print(md)
|
|
322
|
+
|
|
323
|
+
except Exception as e:
|
|
324
|
+
printer.print_str_in_terminal(get_message_with_format("rules_get_read_error", file_path=file_path, error=str(e)))
|
|
325
|
+
logger.exception(e)
|
|
326
|
+
|
|
327
|
+
# 由于控制台直接打印,返回空字符串
|
|
328
|
+
return ""
|
|
329
|
+
|
|
330
|
+
def _handle_help(memory: Dict[str, Any], args: List[str]) -> str:
|
|
331
|
+
"""Provides help text for the /rules command."""
|
|
332
|
+
help_text = get_message("rules_help_text")
|
|
333
|
+
if not help_text:
|
|
334
|
+
# 如果没有翻译好的帮助文本,提供默认的中文帮助文本
|
|
335
|
+
help_text = """
|
|
336
|
+
/rules 命令帮助:
|
|
337
|
+
/rules /list [通配符] - 列出规则文件,可选通配符过滤
|
|
338
|
+
/rules /get [通配符] - 查看规则文件内容,可选通配符过滤
|
|
339
|
+
/rules /remove [通配符] - 删除规则文件,使用通配符匹配
|
|
340
|
+
/rules /analyze [查询] - 分析当前文件,可选提供查询内容
|
|
341
|
+
/rules /commit <提交ID> /query <查询> - 分析特定提交,必须提供提交ID和查询内容
|
|
342
|
+
/rules /help - 显示此帮助信息
|
|
343
|
+
|
|
344
|
+
默认情况下,直接使用 /rules [查询] 相当于 /rules /analyze [查询]
|
|
345
|
+
"""
|
|
346
|
+
|
|
347
|
+
printer.print_str_in_terminal(help_text)
|
|
348
|
+
return help_text
|
|
349
|
+
|
|
350
|
+
def _handle_commit_rules(memory: Dict[str, Any], args: List[str], coding_func=None) -> str:
|
|
351
|
+
"""处理 commit 命令,要求格式为 /commit <commit_id> /query <查询内容>"""
|
|
352
|
+
if not args:
|
|
353
|
+
message = get_message("rules_commit_param_required")
|
|
354
|
+
printer.print_str_in_terminal(message)
|
|
355
|
+
return message
|
|
356
|
+
|
|
357
|
+
# 构建要解析的完整命令字符串
|
|
358
|
+
command_str = " ".join(args)
|
|
359
|
+
|
|
360
|
+
# 使用 CommandParser 解析命令
|
|
361
|
+
parser = CommandParser()
|
|
362
|
+
|
|
363
|
+
## 传递过来的命令行是没有 /commit 子命令的,需要补充上
|
|
364
|
+
commands = parser.parse(f"/commit {command_str}")
|
|
365
|
+
|
|
366
|
+
# 验证必须包含 commit 和 query 命令
|
|
367
|
+
if not commands.get('commit') or not commands.get('query'):
|
|
368
|
+
message = get_message("rules_commit_format_error")
|
|
369
|
+
printer.print_str_in_terminal(message)
|
|
370
|
+
return message
|
|
371
|
+
|
|
372
|
+
# 获取 commit_id 和查询内容
|
|
373
|
+
commit_args = commands.get('commit', {}).get('args', [])
|
|
374
|
+
if not commit_args:
|
|
375
|
+
message = get_message("rules_commit_id_required")
|
|
376
|
+
printer.print_str_in_terminal(message)
|
|
377
|
+
return message
|
|
378
|
+
|
|
379
|
+
commit_id = commit_args[0]
|
|
380
|
+
|
|
381
|
+
# 获取查询内容
|
|
382
|
+
query_args = commands.get('query', {}).get('args', [])
|
|
383
|
+
if not query_args:
|
|
384
|
+
message = get_message("rules_query_required")
|
|
385
|
+
printer.print_str_in_terminal(message)
|
|
386
|
+
return message
|
|
387
|
+
|
|
388
|
+
query = " ".join(query_args)
|
|
389
|
+
|
|
390
|
+
# 实现实际的 commit 分析逻辑...
|
|
391
|
+
try:
|
|
392
|
+
_handle_analyze_commit_rules(memory, [query], commit_id=commit_id, coding_func=coding_func)
|
|
393
|
+
message = get_message_with_format("rules_commit_success", commit_id=commit_id, query=query)
|
|
394
|
+
printer.print_str_in_terminal(message)
|
|
395
|
+
return message
|
|
396
|
+
except Exception as e:
|
|
397
|
+
message = get_message_with_format("rules_commit_error", commit_id=commit_id, error=str(e))
|
|
398
|
+
printer.print_str_in_terminal(message)
|
|
399
|
+
return message
|
|
400
|
+
|
|
401
|
+
# Command dispatch table
|
|
402
|
+
COMMAND_HANDLERS: Dict[str, Callable[[Dict[str, Any], List[str]], str]] = {
|
|
403
|
+
"list": _handle_list_rules,
|
|
404
|
+
"remove": _handle_remove_rules,
|
|
405
|
+
"get": _handle_get_rules,
|
|
406
|
+
"analyze": _handle_analyze_rules, # 默认行为
|
|
407
|
+
"help": _handle_help,
|
|
408
|
+
"commit": _handle_commit_rules, # 添加新的命令处理函数
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
def handle_rules_command(command_args: str, memory: Dict[str, Any], coding_func=None) -> str:
|
|
412
|
+
"""
|
|
413
|
+
Handles the /rules command and its subcommands.
|
|
414
|
+
|
|
415
|
+
Args:
|
|
416
|
+
command_args: The arguments string following the /rules command.
|
|
417
|
+
Example: "analyze code quality", "/list", "/remove *.md"
|
|
418
|
+
memory: The current session memory dictionary.
|
|
419
|
+
|
|
420
|
+
Returns:
|
|
421
|
+
A string response to be displayed to the user.
|
|
422
|
+
"""
|
|
423
|
+
rules_str = command_args.strip()
|
|
424
|
+
# 处理空命令
|
|
425
|
+
if not rules_str:
|
|
426
|
+
return _handle_help(memory, [])
|
|
427
|
+
|
|
428
|
+
# 处理子命令
|
|
429
|
+
if rules_str.startswith("/"):
|
|
430
|
+
# 解析子命令
|
|
431
|
+
parts = rules_str[1:].strip().split(maxsplit=1)
|
|
432
|
+
subcommand = parts[0].lower() if parts else ""
|
|
433
|
+
args = parts[1].split() if len(parts) > 1 else []
|
|
434
|
+
|
|
435
|
+
handler = COMMAND_HANDLERS.get(subcommand)
|
|
436
|
+
if handler:
|
|
437
|
+
try:
|
|
438
|
+
# 仅 analyze 需要 coding_func
|
|
439
|
+
if subcommand == "analyze":
|
|
440
|
+
return handler(memory, args, coding_func=coding_func)
|
|
441
|
+
elif subcommand == "commit":
|
|
442
|
+
return handler(memory, args, coding_func=coding_func)
|
|
443
|
+
else:
|
|
444
|
+
return handler(memory, args)
|
|
445
|
+
except Exception as e:
|
|
446
|
+
message = get_message_with_format("rules_command_error", subcommand=subcommand, error=str(e))
|
|
447
|
+
printer.print_str_in_terminal(message)
|
|
448
|
+
return message
|
|
449
|
+
else:
|
|
450
|
+
message = get_message_with_format("rules_unknown_command", subcommand=subcommand)
|
|
451
|
+
printer.print_str_in_terminal(message)
|
|
452
|
+
return message
|
|
453
|
+
elif rules_str.lower() == "help":
|
|
454
|
+
# 处理无斜杠的 help 命令
|
|
455
|
+
return _handle_help(memory, [])
|
|
456
|
+
else:
|
|
457
|
+
# 将整个字符串作为查询参数传递给 analyze
|
|
458
|
+
return _handle_analyze_rules(memory, [rules_str], coding_func=coding_func)
|
autocoder/chat_auto_coder.py
CHANGED
|
@@ -53,6 +53,7 @@ from autocoder.auto_coder_runner import (
|
|
|
53
53
|
summon,
|
|
54
54
|
get_memory,
|
|
55
55
|
active_context,
|
|
56
|
+
rules
|
|
56
57
|
)
|
|
57
58
|
# Ensure the correct import is present
|
|
58
59
|
from autocoder.chat.conf_command import handle_conf_command
|
|
@@ -628,6 +629,10 @@ def main():
|
|
|
628
629
|
args = user_input[len("/lib") :].strip().split()
|
|
629
630
|
lib_command(args)
|
|
630
631
|
|
|
632
|
+
elif user_input.startswith("/rules"):
|
|
633
|
+
query = user_input[len("/rules") :].strip()
|
|
634
|
+
rules(query)
|
|
635
|
+
|
|
631
636
|
elif user_input.startswith("/mcp"):
|
|
632
637
|
query = user_input[len("/mcp") :].strip()
|
|
633
638
|
if not query:
|
|
@@ -593,6 +593,136 @@ Available subcommands:
|
|
|
593
593
|
"marketplace_add_error": {
|
|
594
594
|
"en": "Error adding marketplace item: {{name}} - {{error}}",
|
|
595
595
|
"zh": "添加市场项目时出错:{{name}} - {{error}}"
|
|
596
|
+
},
|
|
597
|
+
"rules_desc": {
|
|
598
|
+
"en": "Analyze current files with rules and create code learning notes",
|
|
599
|
+
"zh": "使用规则分析当前文件并创建代码学习笔记"
|
|
600
|
+
},
|
|
601
|
+
"rules_file_list_title": {
|
|
602
|
+
"en": "Rules Files List (Pattern: {{pattern}})",
|
|
603
|
+
"zh": "规则文件列表 (匹配: {{pattern}})"
|
|
604
|
+
},
|
|
605
|
+
"rules_file_path": {
|
|
606
|
+
"en": "File Path",
|
|
607
|
+
"zh": "文件路径"
|
|
608
|
+
},
|
|
609
|
+
"rules_content_length": {
|
|
610
|
+
"en": "Content Length",
|
|
611
|
+
"zh": "内容长度"
|
|
612
|
+
},
|
|
613
|
+
"rules_help_subtitle": {
|
|
614
|
+
"en": "Use '/rules help' for more information",
|
|
615
|
+
"zh": "使用 '/rules help' 获取更多帮助"
|
|
616
|
+
},
|
|
617
|
+
"rules_no_files_found": {
|
|
618
|
+
"en": "No rules files found. Use '/rules /help' to learn how to add rules.",
|
|
619
|
+
"zh": "未找到任何规则文件。请使用 '/rules /help' 了解如何添加规则。"
|
|
620
|
+
},
|
|
621
|
+
"rules_no_matching_files": {
|
|
622
|
+
"en": "No rules files found matching pattern '{{pattern}}'.",
|
|
623
|
+
"zh": "没有找到匹配模式 '{{pattern}}' 的规则文件。"
|
|
624
|
+
},
|
|
625
|
+
"rules_remove_param_required": {
|
|
626
|
+
"en": "Error: 'remove' command requires a parameter (file pattern). Usage: /rules /remove <pattern>",
|
|
627
|
+
"zh": "错误: 'remove' 命令需要一个参数(文件匹配模式)。用法: /rules /remove <匹配模式>"
|
|
628
|
+
},
|
|
629
|
+
"rules_no_files_to_remove": {
|
|
630
|
+
"en": "No rules files found matching pattern '{{pattern}}'.",
|
|
631
|
+
"zh": "没有找到匹配模式 '{{pattern}}' 的规则文件。"
|
|
632
|
+
},
|
|
633
|
+
"rules_delete_error": {
|
|
634
|
+
"en": "Error deleting file '{{file_path}}': {{error}}",
|
|
635
|
+
"zh": "删除文件 '{{file_path}}' 时出错: {{error}}"
|
|
636
|
+
},
|
|
637
|
+
"rules_delete_success": {
|
|
638
|
+
"en": "Successfully deleted {{count}} rules files.",
|
|
639
|
+
"zh": "成功删除了 {{count}} 个规则文件。"
|
|
640
|
+
},
|
|
641
|
+
"rules_no_active_files": {
|
|
642
|
+
"en": "Error: No files selected for analysis. Please use 'add_files' command to add files first.",
|
|
643
|
+
"zh": "错误: 没有选择任何文件进行分析。请先使用 'add_files' 命令添加文件。"
|
|
644
|
+
},
|
|
645
|
+
"rules_file_read_error": {
|
|
646
|
+
"en": "Error reading file '{{file_path}}': {{error}}",
|
|
647
|
+
"zh": "读取文件 '{{file_path}}' 时出错: {{error}}"
|
|
648
|
+
},
|
|
649
|
+
"rules_analysis_error": {
|
|
650
|
+
"en": "Error analyzing code: {{error}}",
|
|
651
|
+
"zh": "分析代码时出错: {{error}}"
|
|
652
|
+
},
|
|
653
|
+
"rules_help_text": {
|
|
654
|
+
"en": """
|
|
655
|
+
/rules command usage:
|
|
656
|
+
/rules [query] - Analyze current added files, optionally provide specific query content.
|
|
657
|
+
/rules /list [pattern] - List all rules files. Optionally provide wildcard pattern (e.g. *.md).
|
|
658
|
+
/rules /remove <pattern> - Delete rules files matching the specified pattern.
|
|
659
|
+
/rules /get <pattern> - Display the content of rules files matching the specified pattern.
|
|
660
|
+
/rules /help or /rules help - Show this help message.
|
|
661
|
+
|
|
662
|
+
Rules file usage:
|
|
663
|
+
Rules files are stored in the project's .autocoderrules/ directory, in Markdown format.
|
|
664
|
+
The system automatically monitors changes to this directory and updates rules.
|
|
665
|
+
""",
|
|
666
|
+
"zh": """
|
|
667
|
+
/rules 命令用法:
|
|
668
|
+
/rules [查询内容] - 分析当前已添加的文件,可选提供具体查询内容。
|
|
669
|
+
/rules /list [匹配模式] - 列出所有规则文件。可选提供通配符匹配模式 (例如: *.md).
|
|
670
|
+
/rules /remove <匹配模式> - 删除匹配指定模式的规则文件。
|
|
671
|
+
/rules /get <匹配模式> - 显示匹配指定模式的规则文件内容。
|
|
672
|
+
/rules /help 或 /rules help - 显示此帮助信息。
|
|
673
|
+
|
|
674
|
+
规则文件用法:
|
|
675
|
+
规则文件存储在项目的 .autocoderrules/ 目录下,为 Markdown 格式。
|
|
676
|
+
系统会自动监控该目录的变化并更新规则。
|
|
677
|
+
"""
|
|
678
|
+
},
|
|
679
|
+
"rules_unknown_command": {
|
|
680
|
+
"en": "Unknown subcommand '/rules {{subcommand}}'. Use '/rules /help' for help.",
|
|
681
|
+
"zh": "未知的子命令 '/rules {{subcommand}}'。请使用 '/rules /help' 获取帮助。"
|
|
682
|
+
},
|
|
683
|
+
"rules_command_error": {
|
|
684
|
+
"en": "Error executing '/rules {{subcommand}}': {{error}}",
|
|
685
|
+
"zh": "执行 '/rules {{subcommand}}' 时发生错误: {{error}}"
|
|
686
|
+
},
|
|
687
|
+
"rules_get_param_required": {
|
|
688
|
+
"en": "Error: 'get' command requires a parameter (file pattern). Usage: /rules /get <pattern>",
|
|
689
|
+
"zh": "错误: 'get' 命令需要一个参数(文件匹配模式)。用法: /rules /get <匹配模式>"
|
|
690
|
+
},
|
|
691
|
+
"rules_get_no_matching_files": {
|
|
692
|
+
"en": "No rules files found matching pattern '{{pattern}}'.",
|
|
693
|
+
"zh": "没有找到匹配模式 '{{pattern}}' 的规则文件。"
|
|
694
|
+
},
|
|
695
|
+
"rules_get_file_title": {
|
|
696
|
+
"en": "Rule File: {{file_path}}",
|
|
697
|
+
"zh": "规则文件: {{file_path}}"
|
|
698
|
+
},
|
|
699
|
+
"rules_get_read_error": {
|
|
700
|
+
"en": "Error reading file '{{file_path}}': {{error}}",
|
|
701
|
+
"zh": "读取文件 '{{file_path}}' 时出错: {{error}}"
|
|
702
|
+
},
|
|
703
|
+
"rules_commit_param_required": {
|
|
704
|
+
"en": "Error: 'commit' command requires parameters. Usage: /rules /commit <commit_id> /query <query>",
|
|
705
|
+
"zh": "错误: 'commit' 命令需要参数。用法: /rules /commit <commit_id> /query <查询内容>"
|
|
706
|
+
},
|
|
707
|
+
"rules_commit_format_error": {
|
|
708
|
+
"en": "Error: Command format must be '/rules /commit <commit_id> /query <query>'",
|
|
709
|
+
"zh": "错误:命令格式必须为 '/rules /commit <commit_id> /query <你的需求>'"
|
|
710
|
+
},
|
|
711
|
+
"rules_commit_id_required": {
|
|
712
|
+
"en": "Error: Commit ID must be provided",
|
|
713
|
+
"zh": "错误:必须提供 commit ID"
|
|
714
|
+
},
|
|
715
|
+
"rules_query_required": {
|
|
716
|
+
"en": "Error: Query content must be provided",
|
|
717
|
+
"zh": "错误:必须提供查询内容"
|
|
718
|
+
},
|
|
719
|
+
"rules_commit_success": {
|
|
720
|
+
"en": "Successfully analyzed commit {{commit_id}}, query: {{query}}",
|
|
721
|
+
"zh": "成功分析 commit {{commit_id}},查询:{{query}}"
|
|
722
|
+
},
|
|
723
|
+
"rules_commit_error": {
|
|
724
|
+
"en": "Error analyzing commit {{commit_id}}: {{error}}",
|
|
725
|
+
"zh": "分析 commit {{commit_id}} 时出错:{{error}}"
|
|
596
726
|
}
|
|
597
727
|
}
|
|
598
728
|
|
|
@@ -106,6 +106,10 @@ MESSAGES = {
|
|
|
106
106
|
"en": "DeepSeek Official",
|
|
107
107
|
"zh": "DeepSeek官方"
|
|
108
108
|
},
|
|
109
|
+
"model_provider_openrouter": {
|
|
110
|
+
"en": "OpenRouter",
|
|
111
|
+
"zh": "OpenRouter"
|
|
112
|
+
},
|
|
109
113
|
"model_provider_api_key_title": {
|
|
110
114
|
"en": "API Key",
|
|
111
115
|
"zh": "API密钥"
|
|
@@ -114,6 +118,10 @@ MESSAGES = {
|
|
|
114
118
|
"en": "Please enter your Volcano Engine API key:",
|
|
115
119
|
"zh": "请输入您的火山方舟API密钥:"
|
|
116
120
|
},
|
|
121
|
+
"model_provider_openrouter_api_key_text": {
|
|
122
|
+
"en": "Please enter your OpenRouter API key:",
|
|
123
|
+
"zh": "请输入您的OpenRouter API密钥:"
|
|
124
|
+
},
|
|
117
125
|
"model_provider_volcano_r1_text": {
|
|
118
126
|
"en": "Please enter your Volcano Engine R1 endpoint (format: ep-20250204215011-vzbsg):",
|
|
119
127
|
"zh": "请输入您的火山方舟 R1 推理点(格式如: ep-20250204215011-vzbsg):"
|
|
@@ -129,7 +137,7 @@ MESSAGES = {
|
|
|
129
137
|
"model_provider_deepseek_api_key_text": {
|
|
130
138
|
"en": "Please enter your DeepSeek API key:",
|
|
131
139
|
"zh": "请输入您的DeepSeek API密钥:"
|
|
132
|
-
},
|
|
140
|
+
},
|
|
133
141
|
"model_provider_selected": {
|
|
134
142
|
"en": "Provider configuration completed successfully! You can use /models command to view, add and modify all models later.",
|
|
135
143
|
"zh": "供应商配置已成功完成!后续你可以使用 /models 命令,查看,新增和修改所有模型"
|