from __future__ import annotations MATTERMOST_CONFIG_SCHEMA = { "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "title": "Mattermost Channel Configuration", "properties": { "server_url": { "type": "string", "format": "uri", "description": "Mattermost 服务器 URL", "examples": ["https://mattermost.example.com"], }, "bot_token": { "type": "string", "description": "Bot Personal Access Token", "writeOnly": True, }, "dm_policy": { "type": "string", "enum": ["open", "allowlist", "pairing", "disabled"], "default": "open", "description": "DM 安全策略", }, "group_policy": { "type": "string", "enum": ["open", "allowlist", "disabled"], "default": "open", "description": "群组安全策略", }, "allow_from": { "type": "array", "items": {"type": "string"}, "description": "DM 白名单(用户 ID 或 @username)", }, "group_allow_from": { "type": "array", "items": {"type": "string"}, "description": "群组白名单", }, "chatmode": { "type": "string", "enum": ["oncall", "onmessage", "onchar"], "default": "onmessage", "description": "消息响应模式", }, "require_mention": { "type": "boolean", "default": True, "description": "群组消息是否需要 @提及", }, "onchar_prefixes": { "type": "array", "items": {"type": "string"}, "default": [">", "!"], "description": "onchar 模式触发前缀", }, "reply_to_mode": { "type": "string", "enum": ["off", "first", "all", "batched"], "default": "off", "description": "回复线程绑定模式", }, "text_chunk_limit": { "type": "integer", "minimum": 1000, "maximum": 16383, "default": 4000, "description": "消息分块大小上限", }, "media_filename": { "type": "string", "default": "file", "description": "媒体文件默认文件名", }, "max_media_size_mb": { "type": "integer", "minimum": 1, "maximum": 100, "default": 100, "description": "最大媒体文件大小 (MB)", }, "dangerously_allow_name_matching": { "type": "boolean", "default": False, "description": "允许白名单名称匹配(安全风险)", }, "auto_register_commands": { "type": "boolean", "default": False, "description": "自动注册 Slash Commands", }, "commands": { "type": "array", "items": { "type": "object", "properties": { "command": {"type": "string"}, "description": {"type": "string"}, }, }, "description": "自定义 Slash Commands", }, "silence_send": { "type": "boolean", "default": False, "description": "静默发送模式 — 发送 message 时不连带任何 props/attachments", }, "block_streaming": { "type": "boolean", "default": True, "description": "启用/禁用块流式输出", }, "stream_min_chars": { "type": "integer", "minimum": 1, "maximum": 16383, "default": 50, "description": "partial/block 流式模式下缓冲区最小字符数,达到后刷新", }, "stream_idle_ms": { "type": "integer", "minimum": 100, "maximum": 30000, "default": 1000, "description": "partial/block 流式模式下最大空闲等待 (ms),超时后刷新缓冲", }, "blockStreamingCoalesce": { "type": "object", "properties": { "minChars": {"type": "integer", "default": 1500}, "idleMs": {"type": "integer", "default": 1000}, }, "description": "block 流式合并配置", }, "dmChannelRetry": { "type": "object", "properties": { "baseDelayMs": {"type": "integer", "default": 1000}, "maxRetries": {"type": "integer", "default": 3}, }, "description": "DM 频道创建重试配置", }, "responsePrefix": { "type": "string", "default": "", "description": "所有回复前添加的前缀", }, "network": { "type": "object", "properties": { "dangerouslyAllowPrivateNetwork": { "type": "boolean", "default": False, }, }, "description": "网络配置", }, "configWrites": { "type": "boolean", "default": False, "description": "允许通过命令写入配置", }, "agent_routes": { "type": "object", "description": "Per-channel/Per-team Agent 路由配置", }, "default_agent_id": { "type": "string", "description": "默认 Agent ID", }, "groups": { "type": "object", "description": "Per-Group 配置,支持 requireMention 覆盖", "additionalProperties": { "type": "object", "properties": { "requireMention": {"type": "boolean"}, }, }, }, }, "required": ["server_url", "bot_token"], "additionalProperties": True, } def validate_config_schema(config: dict) -> list[str]: """基于 JSON Schema 验证配置。返回错误列表。""" errors = [] for req in MATTERMOST_CONFIG_SCHEMA.get("required", []): if not config.get(req): errors.append(f"Missing required field: {req}") dm_policy = config.get("dm_policy", "") allowed_dm = MATTERMOST_CONFIG_SCHEMA["properties"]["dm_policy"]["enum"] if dm_policy and dm_policy not in allowed_dm: errors.append(f"dm_policy must be one of {allowed_dm}") group_policy = config.get("group_policy", "") allowed_gp = MATTERMOST_CONFIG_SCHEMA["properties"]["group_policy"]["enum"] if group_policy and group_policy not in allowed_gp: errors.append(f"group_policy must be one of {allowed_gp}") chatmode = config.get("chatmode", "") allowed_cm = MATTERMOST_CONFIG_SCHEMA["properties"]["chatmode"]["enum"] if chatmode and chatmode not in allowed_cm: errors.append(f"chatmode must be one of {allowed_cm}") text_chunk_limit = config.get("text_chunk_limit", 0) if text_chunk_limit and (text_chunk_limit < 1000 or text_chunk_limit > 16383): errors.append("text_chunk_limit must be between 1000 and 16383") return errors def get_config_schema() -> dict: """返回配置 JSON Schema。""" return MATTERMOST_CONFIG_SCHEMA