ForcePilot/backend/package/yuxi/channels/adapters/wechat/config_schema.py
Kris a1d9ba9683 refactor(wechat): 整理代码风格与导入顺序,新增多项微信适配功能
本次提交包含多项优化与新增功能:
1. 清理多个文件中多余的空行与导入顺序
2. 修复voice.py中的多行字符串格式化问题
3. 新增微信公众号被动回复构建函数与配置项
4. 新增企业微信markdown消息发送支持
5. 新增消息去重TTL与最大条目配置
6. 新增markdown文本截断工具函数
7. 新增微信授权与OAuth相关工具方法
8. 重构消息去重逻辑,使用DedupPolicy替代本地字典实现
9. 新增子账号多租户支持功能
10. 新增消息动作处理适配器,支持send/reply等操作
11. 修复token持久化逻辑,新增状态存储支持
2026-05-13 16:16:52 +08:00

132 lines
5.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from __future__ import annotations
from typing import Any
WECHAT_CONFIG_SCHEMA: dict[str, Any] = {
"type": "object",
"additionalProperties": False,
"properties": {
"enabled": {"type": "boolean"},
"accounts": {
"type": "object",
"patternProperties": {
"^[a-zA-Z0-9_-]+$": {
"type": "object",
"oneOf": [
{
"required": ["corp_id", "corp_secret", "agent_id"],
"properties": {
"corp_id": {"type": "string", "minLength": 1},
"corp_secret": {"type": "string", "minLength": 1},
"agent_id": {"type": "string", "minLength": 1},
},
},
{
"required": ["app_id", "app_secret"],
"properties": {
"app_id": {"type": "string", "minLength": 1},
"app_secret": {"type": "string", "minLength": 1},
},
},
{
"required": ["bridge_url"],
"properties": {
"bridge_url": {"type": "string", "format": "uri"},
},
},
],
},
},
},
"dmPolicy": {"enum": ["open", "pairing", "allowlist", "disabled"]},
"groupPolicy": {"enum": ["open", "allowlist", "disabled"]},
"retry_attempts": {"type": "integer", "minimum": 1, "maximum": 10},
"retry_min_delay": {"type": "number", "minimum": 0.1, "maximum": 60.0},
"retry_max_delay": {"type": "number", "minimum": 1.0, "maximum": 120.0},
"outbound_priority_enabled": {"type": "boolean"},
"exec_approval_timeout": {"type": "integer", "minimum": 1, "maximum": 30},
"ban_backoff_intervals": {
"type": "array",
"items": {"type": "integer", "minimum": 1},
"minItems": 1,
"maxItems": 5,
},
"passive_reply_mode": {
"type": "string",
"enum": ["auto", "transfer_cs", "disabled"],
"default": "auto",
"description": (
"MP 模式被动回复策略:"
"auto - 自动尝试被动回复(优先缓存 → 空回复 + 客服消息兜底);"
"transfer_cs - 始终转发到客服;"
"disabled - 仅使用客服消息(当前行为)"
),
},
},
}
def validate_wechat_config(config: dict[str, Any]) -> list[str]:
errors: list[str] = []
if not isinstance(config, dict):
return ["配置必须是对象(dict)"]
enabled = config.get("enabled")
if enabled is not None and not isinstance(enabled, bool):
errors.append("enabled 必须是布尔值")
dm_policy = config.get("dm_policy", "pairing")
if dm_policy not in ("open", "pairing", "allowlist", "disabled"):
errors.append(f"dm_policy 值无效: {dm_policy}(可选: open/pairing/allowlist/disabled")
group_policy = config.get("group_policy", "allowlist")
if group_policy not in ("open", "allowlist", "disabled"):
errors.append(f"group_policy 值无效: {group_policy}(可选: open/allowlist/disabled")
retry_attempts = config.get("retry_attempts")
if retry_attempts is not None and (not isinstance(retry_attempts, int) or retry_attempts < 0):
errors.append("retry_attempts 必须是非负整数")
retry_min_delay = config.get("retry_min_delay")
if retry_min_delay is not None and (not isinstance(retry_min_delay, (int, float)) or retry_min_delay < 0):
errors.append("retry_min_delay 必须是非负数")
retry_max_delay = config.get("retry_max_delay")
if retry_max_delay is not None and (not isinstance(retry_max_delay, (int, float)) or retry_max_delay < 0):
errors.append("retry_max_delay 必须是非负数")
outbound_priority_enabled = config.get("outbound_priority_enabled")
if outbound_priority_enabled is not None and not isinstance(outbound_priority_enabled, bool):
errors.append("outbound_priority_enabled 必须是布尔值")
exec_approval_timeout = config.get("exec_approval_timeout")
if exec_approval_timeout is not None and (not isinstance(exec_approval_timeout, int) or exec_approval_timeout < 0):
errors.append("exec_approval_timeout 必须是非负整数")
ban_backoff_intervals = config.get("ban_backoff_intervals")
if ban_backoff_intervals is not None:
if not isinstance(ban_backoff_intervals, list) or not all(
isinstance(x, int) and x > 0 for x in ban_backoff_intervals
):
errors.append("ban_backoff_intervals 必须是正整数列表")
has_corp = all(config.get(k) for k in ("corp_id", "corp_secret", "agent_id"))
has_mp = all(config.get(k) for k in ("app_id", "app_secret"))
has_bridge = bool(config.get("bridge_url"))
if not (has_corp or has_mp or has_bridge):
errors.append("缺少有效的微信配置 (wecom/mp/bridge)")
accounts = config.get("accounts", {})
if accounts and isinstance(accounts, dict):
for account_id, account_cfg in accounts.items():
if not isinstance(account_id, str) or not account_id.replace("-", "").replace("_", "").isalnum():
errors.append(f"账户 ID 格式无效: {account_id}")
return errors
def get_schema() -> dict[str, Any]:
return dict(WECHAT_CONFIG_SCHEMA)