ForcePilot/backend/package/yuxi/channels/adapters/dingding/session.py
Kris 9c01d480cc feat(dingding): 完整实现钉钉适配器功能模块
- 新增钉钉工具调用审计日志功能
- 新增参数校验装饰器与基础工具集(文档、审批、多维表格)
- 完善事件类型映射与会话ID生成逻辑
- 新增消息去重、访问策略匹配、配置校验与UI提示
- 新增酷应用卡片、目录管理、表情反应支持
- 优化消息发送逻辑,添加401重试机制
- 新增配置化的权限控制与流式输出支持
2026-05-13 16:06:10 +08:00

83 lines
2.4 KiB
Python

from __future__ import annotations
from enum import StrEnum
CHAT_ID_PREFIX_DM = "dingding:dm:"
CHAT_ID_PREFIX_GROUP = "dingding:group:"
CHAT_ID_PREFIX_THREAD = "dingding:thread:"
CHAT_ID_PREFIX_GROUP_SENDER = "dingding:group_sender:"
class SessionScope(StrEnum):
DIRECT = "dm"
GROUP = "group"
GROUP_SENDER = "group_sender"
TOPIC = "topic"
class SessionMode(StrEnum):
RAW = "raw"
CHAT_RAW = "chat_raw"
CHAT_RESOLVE = "chat_resolve"
def generate_dingding_chat_id(
raw: dict,
chat_type: str,
*,
sender_id: str | None = None,
scope: str = "group",
) -> str:
raw_sender_id = sender_id or raw.get("senderId", "")
if chat_type == "direct":
return f"dm_{raw_sender_id}"
conversation_id = raw.get("conversationId", "")
if scope == "group_sender" and raw_sender_id:
return f"{CHAT_ID_PREFIX_GROUP_SENDER}{conversation_id}:{raw_sender_id}"
return f"group_{conversation_id}"
def resolve_dingding_chat_type(raw: dict) -> str:
is_group = raw.get("isGroupChat", False)
return "group" if is_group else "direct"
def generate_thread_key(channel_id: str, chat_id: str, *, scope: str = "group") -> str:
if chat_id.startswith("dm_"):
return f"{channel_id}:direct:{chat_id}"
if scope == "group_sender":
return f"{channel_id}:group_sender:{chat_id}"
return f"{channel_id}:group:{chat_id}"
def normalize_chat_id(chat_id: str) -> str:
if chat_id.startswith("dingding:") or chat_id.startswith("dm_") or chat_id.startswith("group_"):
return chat_id
if chat_id.startswith("group_sender_"):
return f"{CHAT_ID_PREFIX_GROUP_SENDER}{chat_id}"
return f"{CHAT_ID_PREFIX_GROUP}{chat_id}"
def resolve_session_scope(chat_id: str) -> str:
if chat_id.startswith("dm_"):
return SessionScope.DIRECT
if CHAT_ID_PREFIX_GROUP_SENDER in chat_id:
return SessionScope.GROUP_SENDER
return SessionScope.GROUP
def parse_chat_id(chat_id: str) -> dict[str, str]:
if chat_id.startswith("dm_"):
return {"type": "direct", "open_id": chat_id[3:]}
if chat_id.startswith("group_"):
return {"type": "group", "open_conversation_id": chat_id[6:]}
if CHAT_ID_PREFIX_GROUP_SENDER in chat_id:
parts = chat_id.split(":")
if len(parts) >= 3:
return {"type": "group_sender", "group_id": parts[-2], "sender_id": parts[-1]}
return {"type": "unknown", "raw": chat_id}