auto-coder 0.1.354__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.

Files changed (40) hide show
  1. {auto_coder-0.1.354.dist-info → auto_coder-0.1.356.dist-info}/METADATA +1 -1
  2. {auto_coder-0.1.354.dist-info → auto_coder-0.1.356.dist-info}/RECORD +40 -35
  3. autocoder/agent/agentic_filter.py +1 -1
  4. autocoder/agent/auto_learn.py +631 -0
  5. autocoder/auto_coder.py +8 -0
  6. autocoder/auto_coder_runner.py +59 -87
  7. autocoder/chat/conf_command.py +270 -0
  8. autocoder/chat/models_command.py +485 -0
  9. autocoder/chat/rules_command.py +458 -0
  10. autocoder/chat_auto_coder.py +34 -24
  11. autocoder/chat_auto_coder_lang.py +156 -2
  12. autocoder/commands/auto_command.py +1 -1
  13. autocoder/commands/auto_web.py +1 -1
  14. autocoder/common/__init__.py +2 -0
  15. autocoder/common/auto_coder_lang.py +9 -1
  16. autocoder/common/command_completer.py +58 -12
  17. autocoder/common/command_completer_v2.py +615 -0
  18. autocoder/common/global_cancel.py +53 -16
  19. autocoder/common/rulefiles/autocoderrules_utils.py +83 -0
  20. autocoder/common/v2/agent/agentic_edit.py +4 -4
  21. autocoder/common/v2/code_agentic_editblock_manager.py +9 -9
  22. autocoder/common/v2/code_diff_manager.py +2 -2
  23. autocoder/common/v2/code_editblock_manager.py +11 -10
  24. autocoder/common/v2/code_strict_diff_manager.py +3 -2
  25. autocoder/dispacher/actions/action.py +6 -6
  26. autocoder/dispacher/actions/plugins/action_regex_project.py +2 -2
  27. autocoder/events/event_manager_singleton.py +1 -1
  28. autocoder/index/index.py +2 -2
  29. autocoder/rag/cache/local_byzer_storage_cache.py +1 -1
  30. autocoder/rag/cache/local_duckdb_storage_cache.py +8 -0
  31. autocoder/rag/loaders/image_loader.py +25 -13
  32. autocoder/rag/long_context_rag.py +2 -2
  33. autocoder/utils/auto_coder_utils/chat_stream_out.py +3 -4
  34. autocoder/utils/model_provider_selector.py +14 -2
  35. autocoder/utils/thread_utils.py +9 -27
  36. autocoder/version.py +1 -1
  37. {auto_coder-0.1.354.dist-info → auto_coder-0.1.356.dist-info}/LICENSE +0 -0
  38. {auto_coder-0.1.354.dist-info → auto_coder-0.1.356.dist-info}/WHEEL +0 -0
  39. {auto_coder-0.1.354.dist-info → auto_coder-0.1.356.dist-info}/entry_points.txt +0 -0
  40. {auto_coder-0.1.354.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)
@@ -7,7 +7,7 @@ import argparse
7
7
  import os
8
8
  from prompt_toolkit import PromptSession
9
9
  from prompt_toolkit.key_binding import KeyBindings
10
- from prompt_toolkit.history import InMemoryHistory
10
+ from prompt_toolkit.history import FileHistory
11
11
  from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
12
12
  from prompt_toolkit.styles import Style
13
13
  from autocoder.version import __version__
@@ -16,13 +16,15 @@ from prompt_toolkit.formatted_text import FormattedText
16
16
  from prompt_toolkit.completion import Completer, Completion
17
17
  from autocoder.plugins import PluginManager
18
18
  from autocoder.events.event_manager_singleton import gengerate_event_file_path
19
+ from autocoder.common.global_cancel import global_cancel
20
+ from autocoder.chat.models_command import handle_models_command
19
21
  from autocoder.auto_coder_runner import (
20
22
  auto_command,
21
23
  load_memory,
22
24
  save_memory,
23
- configure,
24
- manage_models,
25
- print_conf,
25
+ configure, # Keep configure if it's used elsewhere or by handle_conf_command internally (though we adapted handle_conf_command not to)
26
+ # manage_models, # Removed
27
+ # print_conf, # Removed
26
28
  exclude_dirs,
27
29
  exclude_files,
28
30
  ask,
@@ -51,7 +53,10 @@ from autocoder.auto_coder_runner import (
51
53
  summon,
52
54
  get_memory,
53
55
  active_context,
56
+ rules
54
57
  )
58
+ # Ensure the correct import is present
59
+ from autocoder.chat.conf_command import handle_conf_command
55
60
 
56
61
  # Create a global plugin manager
57
62
  plugin_manager = PluginManager()
@@ -377,8 +382,13 @@ def main():
377
382
  # 创建一个继承Completer的增强补全器
378
383
  enhanced_completer = EnhancedCompleter(completer, plugin_manager)
379
384
 
385
+ # Define the path for the history file
386
+ history_file_path = os.path.join(os.getcwd(), ".auto-coder", "auto-coder.chat", "history", "command_history.txt")
387
+ # Ensure the directory exists
388
+ os.makedirs(os.path.dirname(history_file_path), exist_ok=True)
389
+
380
390
  session = PromptSession(
381
- history=InMemoryHistory(),
391
+ history=FileHistory(history_file_path), # Use FileHistory
382
392
  auto_suggest=AutoSuggestFromHistory(),
383
393
  enable_history_search=False,
384
394
  completer=enhanced_completer,
@@ -482,6 +492,7 @@ def main():
482
492
  ):
483
493
  event_file, file_id = gengerate_event_file_path()
484
494
  configure(f"event_file:{event_file}")
495
+ global_cancel.register_token(event_file)
485
496
  auto_command(user_input)
486
497
 
487
498
  elif memory["mode"] == "voice_input" and not user_input.startswith("/"):
@@ -508,6 +519,9 @@ def main():
508
519
  index_query(query)
509
520
 
510
521
  elif user_input.startswith("/index/build"):
522
+ event_file, file_id = gengerate_event_file_path()
523
+ configure(f"event_file:{event_file}")
524
+ global_cancel.register_token(event_file)
511
525
  index_build()
512
526
 
513
527
  elif user_input.startswith("/index/export"):
@@ -523,10 +537,7 @@ def main():
523
537
 
524
538
  elif user_input.startswith("/models"):
525
539
  query = user_input[len("/models") :].strip()
526
- if not query:
527
- print("Please enter your query.")
528
- else:
529
- manage_models(query)
540
+ handle_models_command(query, get_memory())
530
541
 
531
542
  elif user_input.startswith("/mode"):
532
543
  conf = user_input[len("/mode") :].strip()
@@ -538,27 +549,19 @@ def main():
538
549
  elif user_input.startswith("/conf/export"):
539
550
  from autocoder.common.conf_import_export import export_conf
540
551
 
541
- export_path = user_input[len("/conf/export") :].strip()
542
- export_conf(os.getcwd(), export_path)
543
-
544
- elif user_input.startswith("/conf/import"):
545
- from autocoder.common.conf_import_export import import_conf
546
-
547
- import_path = user_input[len("/conf/import") :].strip()
548
- import_conf(os.getcwd(), import_path)
549
-
550
552
  elif user_input.startswith("/plugins"):
551
553
  # 提取命令参数并交由 plugin_manager 处理
552
554
  args = user_input[len("/plugins") :].strip().split()
553
555
  result = plugin_manager.handle_plugins_command(args)
554
556
  print(result, end="")
555
557
 
558
+ # Handle /conf and its subcommands like /conf /export, /conf /import
556
559
  elif user_input.startswith("/conf"):
557
- conf = user_input[len("/conf") :].strip()
558
- if not conf:
559
- print_conf(memory["conf"])
560
- else:
561
- configure(conf)
560
+ # Extract everything after "/conf"
561
+ command_args = user_input[len("/conf"):].strip()
562
+ # Call the handler from conf_command.py and print its string result
563
+ result_message = handle_conf_command(command_args, memory)
564
+ print(result_message)
562
565
  elif user_input.startswith("/revert"):
563
566
  revert()
564
567
  elif user_input.startswith("/commit"):
@@ -592,14 +595,16 @@ def main():
592
595
  elif user_input.startswith("/coding"):
593
596
  event_file, file_id = gengerate_event_file_path()
594
597
  configure(f"event_file:{event_file}")
598
+ global_cancel.register_token(event_file)
595
599
  query = user_input[len("/coding") :].strip()
596
600
  if not query:
597
601
  print("\033[91mPlease enter your request.\033[0m")
598
602
  continue
599
- coding(query)
603
+ coding(query)
600
604
  elif user_input.startswith("/chat"):
601
605
  event_file, file_id = gengerate_event_file_path()
602
606
  configure(f"event_file:{event_file}")
607
+ global_cancel.register_token(event_file)
603
608
  query = user_input[len("/chat") :].strip()
604
609
  if not query:
605
610
  print("\033[91mPlease enter your request.\033[0m")
@@ -624,6 +629,10 @@ def main():
624
629
  args = user_input[len("/lib") :].strip().split()
625
630
  lib_command(args)
626
631
 
632
+ elif user_input.startswith("/rules"):
633
+ query = user_input[len("/rules") :].strip()
634
+ rules(query)
635
+
627
636
  elif user_input.startswith("/mcp"):
628
637
  query = user_input[len("/mcp") :].strip()
629
638
  if not query:
@@ -656,6 +665,7 @@ def main():
656
665
  else:
657
666
  if command.startswith("/chat"):
658
667
  event_file, file_id = gengerate_event_file_path()
668
+ global_cancel.register_token(event_file)
659
669
  configure(f"event_file:{event_file}")
660
670
  command = command[len("/chat") :].strip()
661
671
  gen_and_exec_shell_command(command)