新增飞书机器人适配器全套功能,包括: - 基础适配器入口与工具导出 - 消息格式化、卡片渲染、回复调度逻辑 - 会话ID生成、模型覆盖策略 - 消息发送缓存、顺序队列管理 - 飞书签名验证、加解密webhook请求 - 审批权限校验、机器人菜单事件处理 - 文档评论、钉消息、语音转码处理 - 静态/动态目录管理、子代理生命周期管理 - 各类工具集:聊天、云盘、文档、知识库API封装
124 lines
3.8 KiB
Python
124 lines
3.8 KiB
Python
from __future__ import annotations
|
|
|
|
from enum import StrEnum
|
|
|
|
CHAT_ID_PREFIX_DM = "feishu:dm:"
|
|
CHAT_ID_PREFIX_GROUP = "feishu:group:"
|
|
CHAT_ID_PREFIX_THREAD = "feishu:thread:"
|
|
CHAT_ID_PREFIX_GROUP_SENDER = "feishu:group_sender:"
|
|
CHAT_ID_PREFIX_GROUP_TOPIC = "feishu:group_topic:"
|
|
CHAT_ID_PREFIX_GROUP_TOPIC_SENDER = "feishu:group_topic_sender:"
|
|
|
|
GroupSessionScope = str # "group" | "group_sender" | "group_topic" | "group_topic_sender"
|
|
|
|
|
|
class SessionMode(StrEnum):
|
|
RAW = "raw"
|
|
THREAD = "thread"
|
|
CHAT_RAW = "chat_raw"
|
|
CHAT_RESOLVE = "chat_resolve"
|
|
|
|
|
|
def generate_feishu_chat_id(
|
|
raw_chat_id: str,
|
|
chat_type: str,
|
|
*,
|
|
root_id: str | None = None,
|
|
sender_id: str | None = None,
|
|
mode: SessionMode = SessionMode.CHAT_RESOLVE,
|
|
scope: GroupSessionScope = "group",
|
|
) -> str:
|
|
if mode == SessionMode.RAW:
|
|
return raw_chat_id
|
|
|
|
if mode == SessionMode.CHAT_RAW:
|
|
prefix = f"feishu:{chat_type}:"
|
|
return f"{prefix}{raw_chat_id}"
|
|
|
|
if mode == SessionMode.THREAD and root_id:
|
|
return f"{CHAT_ID_PREFIX_THREAD}{root_id}"
|
|
|
|
if chat_type in ("group", "thread") and root_id:
|
|
if scope == "group_topic_sender" and sender_id:
|
|
return f"{CHAT_ID_PREFIX_GROUP_TOPIC_SENDER}{root_id}:{raw_chat_id}:{sender_id}"
|
|
if scope == "group_topic":
|
|
return f"{CHAT_ID_PREFIX_GROUP_TOPIC}{root_id}:{raw_chat_id}"
|
|
if scope == "group_sender" and sender_id:
|
|
return f"{CHAT_ID_PREFIX_GROUP_SENDER}{raw_chat_id}:{sender_id}"
|
|
return f"{CHAT_ID_PREFIX_GROUP}{root_id}:{raw_chat_id}"
|
|
|
|
if chat_type == "group" or chat_type == "direct" or chat_type == "p2p":
|
|
if scope == "group_sender" and sender_id:
|
|
prefix = CHAT_ID_PREFIX_DM if (chat_type == "direct" or chat_type == "p2p") else CHAT_ID_PREFIX_GROUP_SENDER
|
|
return f"{prefix}{raw_chat_id}:{sender_id}"
|
|
prefix = CHAT_ID_PREFIX_DM if (chat_type == "direct" or chat_type == "p2p") else CHAT_ID_PREFIX_GROUP
|
|
return f"{prefix}{raw_chat_id}"
|
|
|
|
return f"{CHAT_ID_PREFIX_DM}{raw_chat_id}"
|
|
|
|
|
|
def resolve_feishu_chat_type(raw_chat_id: str) -> str:
|
|
return "direct" if raw_chat_id.startswith("ou_") else "group"
|
|
|
|
|
|
def resolve_feishu_command_conversation(
|
|
chat_id: str,
|
|
user_id: str,
|
|
*,
|
|
scope: GroupSessionScope = "group",
|
|
) -> str:
|
|
if user_id.startswith("ou_"):
|
|
return f"{CHAT_ID_PREFIX_DM}{user_id}"
|
|
return generate_feishu_chat_id(chat_id, "group", scope=scope)
|
|
|
|
|
|
def normalize_feishu_acp_conversation_id(conv_id: str) -> str:
|
|
if conv_id.startswith("feishu:"):
|
|
return conv_id
|
|
if conv_id.startswith("ou_"):
|
|
return f"{CHAT_ID_PREFIX_DM}{conv_id}"
|
|
if conv_id.startswith("oc_"):
|
|
return f"{CHAT_ID_PREFIX_GROUP}{conv_id}"
|
|
return conv_id
|
|
|
|
|
|
def match_feishu_acp_conversation(conv_id: str, pattern: str) -> bool:
|
|
import fnmatch
|
|
|
|
normalized = normalize_feishu_acp_conversation_id(conv_id)
|
|
return fnmatch.fnmatch(normalized, pattern)
|
|
|
|
|
|
_FEISHU_ID_PREFIXES = ("ou_", "oc_", "on_", "om_", "od_", "og_", "tg_")
|
|
|
|
|
|
def looks_like_feishu_id(value: str) -> bool:
|
|
if not value or not isinstance(value, str):
|
|
return False
|
|
return any(value.startswith(p) for p in _FEISHU_ID_PREFIXES)
|
|
|
|
|
|
def normalize_feishu_target(target: str) -> str:
|
|
if not target or not isinstance(target, str):
|
|
return target
|
|
|
|
target = target.strip()
|
|
|
|
if target.startswith("feishu:"):
|
|
return target
|
|
|
|
if target.startswith("lark:"):
|
|
return "feishu:" + target[5:]
|
|
|
|
if target.startswith("feishu://"):
|
|
return "feishu:" + target[9:]
|
|
|
|
for prefix in _FEISHU_ID_PREFIXES:
|
|
if target.startswith(prefix):
|
|
if prefix in ("ou_", "on_"):
|
|
return f"{CHAT_ID_PREFIX_DM}{target}"
|
|
if prefix in ("oc_", "om_", "od_", "og_"):
|
|
return f"{CHAT_ID_PREFIX_GROUP}{target}"
|
|
|
|
return target
|