from __future__ import annotations from dataclasses import dataclass, field from typing import Any @dataclass class SlashCommand: command: str description: str auto_complete: bool = True hint: str = "" auto_complete_desc: str = "" auto_complete_hint: str = "" DEFAULT_COMMANDS = [ SlashCommand( command="/forcepilot", description="与 ForcePilot AI 助手对话", hint="[消息内容]", auto_complete_desc="向 AI 发送消息", auto_complete_hint="输入你想问的问题", ), SlashCommand( command="/fp", description="ForcePilot 快捷命令", hint="[消息内容]", auto_complete_desc="快速对话", auto_complete_hint="输入消息", ), SlashCommand( command="/model", description="切换 AI 模型", auto_complete_desc="选择 AI 模型", auto_complete_hint="选择要切换到的模型", ), SlashCommand(command="/clear", description="清除对话上下文", auto_complete_desc="清除对话历史"), SlashCommand(command="/help", description="显示帮助信息", auto_complete_desc="查看命令帮助"), ] @dataclass class SlashCommandConfig: commands: list[SlashCommand] = field(default_factory=lambda: list(DEFAULT_COMMANDS)) auto_register: bool = False callback_url: str = "" @classmethod def from_config(cls, config: dict) -> SlashCommandConfig: raw_commands = config.get("commands", []) if not raw_commands: return cls(commands=list(DEFAULT_COMMANDS)) commands = [] for raw in raw_commands: if isinstance(raw, str): commands.append(SlashCommand(command=raw, description=f"执行 {raw} 命令")) elif isinstance(raw, dict): commands.append( SlashCommand( command=raw.get("command", ""), description=raw.get("description", ""), auto_complete=raw.get("auto_complete", True), ) ) return cls( commands=commands if commands else list(DEFAULT_COMMANDS), auto_register=bool(config.get("auto_register", False)), callback_url=config.get("callback_url", ""), ) def build_command_payload(cmd: SlashCommand, team_id: str, callback_url: str) -> dict[str, Any]: """构建 Mattermost Slash Command 注册请求体。""" payload: dict[str, Any] = { "team_id": team_id, "method": "P", "trigger": cmd.command.lstrip("/"), "url": callback_url or "", "display_name": cmd.command, "description": cmd.description, "auto_complete": cmd.auto_complete, } if cmd.hint: payload["hint"] = cmd.hint if cmd.auto_complete_desc: payload["auto_complete_desc"] = cmd.auto_complete_desc if cmd.auto_complete_hint: payload["auto_complete_hint"] = cmd.auto_complete_hint return payload def get_supported_commands(config: SlashCommandConfig | None = None) -> list[SlashCommand]: if config: return config.commands return list(DEFAULT_COMMANDS) def build_skill_commands(skills: list[str]) -> list[SlashCommand]: return [ SlashCommand( command=f"/oc_{skill}", description=f"执行技能: {skill}", auto_complete_desc=f"运行 {skill} 技能", auto_complete_hint=f"输入 {skill} 的命令参数", ) for skill in skills ]