117 lines
3.3 KiB
Python
117 lines
3.3 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
_SLASH_COMMANDS: dict[str, dict[str, Any]] = {
|
|
"/new": {
|
|
"description": "Start a new conversation session",
|
|
"handler": "reset_session",
|
|
"args": [],
|
|
},
|
|
"/reset": {
|
|
"description": "Reset the current conversation context",
|
|
"handler": "reset_session",
|
|
"args": [],
|
|
},
|
|
"/model": {
|
|
"description": "Show or change the current model",
|
|
"handler": "show_model",
|
|
"args": [{"name": "model_name", "required": False, "description": "Model name to switch to"}],
|
|
},
|
|
"/help": {
|
|
"description": "Show available commands",
|
|
"handler": "show_help",
|
|
"args": [],
|
|
},
|
|
"/status": {
|
|
"description": "Show bot connection status",
|
|
"handler": "show_status",
|
|
"args": [],
|
|
},
|
|
"/channels": {
|
|
"description": "List connected channels",
|
|
"handler": "list_channels",
|
|
"args": [],
|
|
},
|
|
"/proxy": {
|
|
"description": "Start an ACP agent session proxy",
|
|
"handler": "acp_proxy",
|
|
"args": [
|
|
{"name": "spawn", "required": False, "description": "Spawn a new agent session"},
|
|
{"name": "bind", "required": False, "description": "Bind to thread"},
|
|
],
|
|
},
|
|
"/skill": {
|
|
"description": "Invoke a specific skill",
|
|
"handler": "invoke_skill",
|
|
"args": [{"name": "skill_name", "required": True, "description": "Name of the skill to invoke"}],
|
|
},
|
|
"/room_info": {
|
|
"description": "Show room information",
|
|
"handler": "room_info",
|
|
"args": [],
|
|
},
|
|
}
|
|
|
|
|
|
def detect_slash_command(text: str) -> dict[str, Any] | None:
|
|
if not text or not text.startswith("/"):
|
|
return None
|
|
|
|
parts = text.strip().split()
|
|
if not parts:
|
|
return None
|
|
|
|
command = parts[0].lower()
|
|
cmd_def = _SLASH_COMMANDS.get(command)
|
|
if not cmd_def:
|
|
return None
|
|
|
|
raw_args = parts[1:] if len(parts) > 1 else []
|
|
args: dict[str, str] = {}
|
|
|
|
cmd_args = cmd_def.get("args", [])
|
|
for i, arg_def in enumerate(cmd_args):
|
|
if i < len(raw_args):
|
|
arg_name = arg_def["name"]
|
|
if arg_name in ("spawn", "bind") and not raw_args[i].startswith("--"):
|
|
args[arg_name] = raw_args[i]
|
|
else:
|
|
args[arg_name] = raw_args[i]
|
|
|
|
return {
|
|
"command": command,
|
|
"handler": cmd_def["handler"],
|
|
"description": cmd_def["description"],
|
|
"args": args,
|
|
"raw": text,
|
|
}
|
|
|
|
|
|
def is_slash_command(text: str) -> bool:
|
|
if not text or not text.startswith("/"):
|
|
return False
|
|
parts = text.strip().split()
|
|
if not parts:
|
|
return False
|
|
return parts[0].lower() in _SLASH_COMMANDS
|
|
|
|
|
|
def get_command_list() -> list[dict[str, Any]]:
|
|
return [
|
|
{
|
|
"command": cmd,
|
|
"description": info["description"],
|
|
"args": info["args"],
|
|
}
|
|
for cmd, info in _SLASH_COMMANDS.items()
|
|
]
|
|
|
|
|
|
def format_help_text() -> str:
|
|
lines = ["**可用命令:**", ""]
|
|
for cmd, info in _SLASH_COMMANDS.items():
|
|
args_str = " ".join(f"[{a['name']}]" for a in info.get("args", []))
|
|
lines.append(f"**{cmd}** {args_str} - {info['description']}")
|
|
return "\n".join(lines)
|