- 新增钉钉工具调用审计日志功能 - 新增参数校验装饰器与基础工具集(文档、审批、多维表格) - 完善事件类型映射与会话ID生成逻辑 - 新增消息去重、访问策略匹配、配置校验与UI提示 - 新增酷应用卡片、目录管理、表情反应支持 - 优化消息发送逻辑,添加401重试机制 - 新增配置化的权限控制与流式输出支持
83 lines
2.4 KiB
Python
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}
|