新增飞书机器人适配器全套功能,包括: - 基础适配器入口与工具导出 - 消息格式化、卡片渲染、回复调度逻辑 - 会话ID生成、模型覆盖策略 - 消息发送缓存、顺序队列管理 - 飞书签名验证、加解密webhook请求 - 审批权限校验、机器人菜单事件处理 - 文档评论、钉消息、语音转码处理 - 静态/动态目录管理、子代理生命周期管理 - 各类工具集:聊天、云盘、文档、知识库API封装
74 lines
2.1 KiB
Python
74 lines
2.1 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
import time
|
|
from dataclasses import dataclass, field
|
|
|
|
from yuxi.utils.logging_config import logger
|
|
|
|
|
|
@dataclass
|
|
class CardActionEnvelope:
|
|
"""ocf1 交互信封"""
|
|
|
|
oc: str = "ocf1"
|
|
k: str = ""
|
|
a: str = ""
|
|
q: str = ""
|
|
m: dict = field(default_factory=dict)
|
|
c: dict | None = None
|
|
|
|
|
|
def decode_card_action(value: str) -> tuple[str, CardActionEnvelope | None]:
|
|
try:
|
|
data = json.loads(value) if isinstance(value, str) else value
|
|
if not isinstance(data, dict) or data.get("oc") != "ocf1":
|
|
return ("legacy", None)
|
|
|
|
envelope = CardActionEnvelope(
|
|
oc=data.get("oc", "ocf1"),
|
|
k=data.get("k", ""),
|
|
a=data.get("a", ""),
|
|
q=data.get("q", ""),
|
|
m=data.get("m", {}),
|
|
c=data.get("c"),
|
|
)
|
|
return ("structured", envelope)
|
|
except (json.JSONDecodeError, TypeError) as e:
|
|
logger.debug(f"[CardAction] Decode error: {e}")
|
|
return ("invalid:malformed", None)
|
|
|
|
|
|
def validate_card_context(
|
|
envelope: CardActionEnvelope,
|
|
open_id: str,
|
|
chat_id: str,
|
|
chat_type: str,
|
|
max_age_s: float = 300,
|
|
) -> bool:
|
|
if envelope.c is None:
|
|
return True
|
|
|
|
ctx_open_id = envelope.c.get("u", "")
|
|
ctx_chat_id = envelope.c.get("h", "")
|
|
ctx_chat_type = envelope.c.get("t", "")
|
|
created_at = envelope.c.get("e", 0)
|
|
|
|
if ctx_open_id and ctx_open_id != open_id:
|
|
logger.debug(f"[CardAction] Context user mismatch: {ctx_open_id} != {open_id}")
|
|
return False
|
|
|
|
if ctx_chat_id and ctx_chat_id != chat_id:
|
|
logger.debug(f"[CardAction] Context chat mismatch: {ctx_chat_id} != {chat_id}")
|
|
return False
|
|
|
|
if ctx_chat_type and ctx_chat_type != chat_type:
|
|
logger.debug(f"[CardAction] Context type mismatch: {ctx_chat_type} != {chat_type}")
|
|
return False
|
|
|
|
if created_at and (time.time() - created_at) > max_age_s:
|
|
logger.debug(f"[CardAction] Context expired: age={time.time() - created_at:.0f}s")
|
|
return False
|
|
|
|
return True
|