新增元宝(Yuanbao)渠道的完整适配器实现,包含以下核心模块: - 基础适配器与导出入口 - 协议编解码与WebSocket帧处理 - 会话管理与路由逻辑 - 事件队列与出站消息队列 - 消息格式转换与发送重试 - 安全审计与权限校验 - 配置映射与账户管理 - 视觉分析与工具函数 - 文档生成与设置向导
75 lines
2.5 KiB
Python
75 lines
2.5 KiB
Python
from __future__ import annotations
|
|
|
|
from copy import deepcopy
|
|
from typing import Any
|
|
|
|
OPENCLAW_TO_FORCEPILOT = {
|
|
"appKey": "app_key",
|
|
"appSecret": "app_secret",
|
|
"botAppId": "bot_app_id",
|
|
"dm.policy": "dm_policy",
|
|
"dm.allowFrom": "allow_from",
|
|
"requireMention": "group_require_mention",
|
|
"overflowPolicy": "overflowPolicy",
|
|
"replyToMode": "replyToMode",
|
|
"outboundQueueStrategy": "outboundQueueStrategy",
|
|
"minChars": "minChars",
|
|
"maxChars": "maxChars",
|
|
"idleMs": "idleMs",
|
|
"mediaMaxMb": "mediaMaxMb",
|
|
"historyLimit": "historyLimit",
|
|
"fallbackReply": "fallbackReply",
|
|
"markdownHintEnabled": "markdownHintEnabled",
|
|
"debugBotIds": "debugBotIds",
|
|
"disableBlockStreaming": "disableBlockStreaming",
|
|
"apiBase": "apiBase",
|
|
"defaultAccount": "defaultAccount",
|
|
"maxConcurrency": "maxConcurrency",
|
|
"textChunkLimit": "textChunkLimit",
|
|
}
|
|
|
|
REVERSE_MAP = {v: k for k, v in OPENCLAW_TO_FORCEPILOT.items()}
|
|
|
|
|
|
def normalize_config(config: dict[str, Any]) -> dict[str, Any]:
|
|
config = deepcopy(config)
|
|
config = _flatten_nested_dm(config)
|
|
config = _flatten_accounts(config)
|
|
config = _flatten_groups(config)
|
|
return config
|
|
|
|
|
|
def _flatten_nested_dm(config: dict[str, Any]) -> dict[str, Any]:
|
|
dm = config.get("dm", {})
|
|
if isinstance(dm, dict):
|
|
if "policy" in dm and "dm_policy" not in config:
|
|
config["dm_policy"] = dm["policy"]
|
|
if "allowFrom" in dm and "allow_from" not in config:
|
|
config["allow_from"] = dm["allowFrom"]
|
|
return config
|
|
|
|
|
|
def _flatten_accounts(config: dict[str, Any]) -> dict[str, Any]:
|
|
accounts = config.get("accounts", {})
|
|
if isinstance(accounts, dict):
|
|
for acc_id, acc_cfg in accounts.items():
|
|
if isinstance(acc_cfg, dict):
|
|
for oc_key, fp_key in [("appKey", "app_key"), ("appSecret", "app_secret"), ("botAppId", "bot_app_id")]:
|
|
if oc_key in acc_cfg and fp_key not in acc_cfg:
|
|
acc_cfg[fp_key] = acc_cfg[oc_key]
|
|
return config
|
|
|
|
|
|
def _flatten_groups(config: dict[str, Any]) -> dict[str, Any]:
|
|
groups = config.get("groups", {})
|
|
if isinstance(groups, dict):
|
|
for gid, gcfg in groups.items():
|
|
if isinstance(gcfg, dict):
|
|
if "requireMention" in gcfg and "require_mention" not in gcfg:
|
|
gcfg["require_mention"] = gcfg["requireMention"]
|
|
return config
|
|
|
|
|
|
def to_openclaw_key(fp_key: str) -> str:
|
|
return REVERSE_MAP.get(fp_key, fp_key)
|