274 lines
8.2 KiB
Python
274 lines
8.2 KiB
Python
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
from typing import Any
|
|||
|
|
|
|||
|
|
FEISHU_MESSAGE_ACTIONS: dict[str, dict[str, Any]] = {
|
|||
|
|
"send": {
|
|||
|
|
"status": "implemented",
|
|||
|
|
"description": "?????????????????????,"
|
|||
|
|
"api": "im/v1/messages",
|
|||
|
|
},
|
|||
|
|
"sendAttachment": {
|
|||
|
|
"status": "implemented",
|
|||
|
|
"description": "??????/??????/?????????????????????,"
|
|||
|
|
"api": "im/v1/messages + content",
|
|||
|
|
},
|
|||
|
|
"sendCard": {
|
|||
|
|
"status": "implemented",
|
|||
|
|
"description": "???????????????????????????",
|
|||
|
|
"api": "im/v1/messages + card",
|
|||
|
|
},
|
|||
|
|
"sendPoll": {
|
|||
|
|
"status": "unsupported",
|
|||
|
|
"description": "?????????????????????????????????,"
|
|||
|
|
"api": "N/A",
|
|||
|
|
},
|
|||
|
|
"sendSticker": {
|
|||
|
|
"status": "planned",
|
|||
|
|
"description": "??????????????????,"
|
|||
|
|
"api": "im/v1/stickers",
|
|||
|
|
},
|
|||
|
|
"reply": {
|
|||
|
|
"status": "implemented",
|
|||
|
|
"description": "??????????????????????????? root_id???,"
|
|||
|
|
"api": "im/v1/messages/reply",
|
|||
|
|
},
|
|||
|
|
"edit": {
|
|||
|
|
"status": "implemented",
|
|||
|
|
"description": "????????????????????????",
|
|||
|
|
"api": "im/v1/messages/{message_id} PATCH",
|
|||
|
|
},
|
|||
|
|
"delete": {
|
|||
|
|
"status": "implemented",
|
|||
|
|
"description": "??????/????????????",
|
|||
|
|
"api": "im/v1/messages/{message_id} DELETE",
|
|||
|
|
},
|
|||
|
|
"read": {
|
|||
|
|
"status": "implemented",
|
|||
|
|
"description": "??????????????????",
|
|||
|
|
"api": "im/v1/messages/{message_id}/read",
|
|||
|
|
},
|
|||
|
|
"react": {
|
|||
|
|
"status": "implemented",
|
|||
|
|
"description": "????????????????????????,"
|
|||
|
|
"api": "im/v1/messages/{message_id}/reactions",
|
|||
|
|
},
|
|||
|
|
"listReactions": {
|
|||
|
|
"status": "implemented",
|
|||
|
|
"description": "????????????????????????",
|
|||
|
|
"api": "im/v1/messages/{message_id}/reactions GET",
|
|||
|
|
},
|
|||
|
|
"pin": {
|
|||
|
|
"status": "implemented",
|
|||
|
|
"description": "????????????",
|
|||
|
|
"api": "im/v1/pins",
|
|||
|
|
},
|
|||
|
|
"unpin": {
|
|||
|
|
"status": "implemented",
|
|||
|
|
"description": "??????????????????",
|
|||
|
|
"api": "im/v1/pins/{message_id} DELETE",
|
|||
|
|
},
|
|||
|
|
"listPins": {
|
|||
|
|
"status": "implemented",
|
|||
|
|
"description": "????????????????????????",
|
|||
|
|
"api": "im/v1/chats/{chat_id}/pins GET",
|
|||
|
|
},
|
|||
|
|
"broadcast": {
|
|||
|
|
"status": "unsupported",
|
|||
|
|
"description": "???????????????????????????API",
|
|||
|
|
"api": "N/A",
|
|||
|
|
},
|
|||
|
|
"typing": {
|
|||
|
|
"status": "implemented",
|
|||
|
|
"description": "通过 Reactions API 实现 typing indicator(含退避/年龄限制)",
|
|||
|
|
"api": "im/v1/reactions",
|
|||
|
|
},
|
|||
|
|
"thread": {
|
|||
|
|
"status": "implemented",
|
|||
|
|
"description": "????????????/????????????",
|
|||
|
|
"api": "im/v1/threads",
|
|||
|
|
},
|
|||
|
|
"streamChunk": {
|
|||
|
|
"status": "implemented",
|
|||
|
|
"description": "?????????????????????????????????????????????,"
|
|||
|
|
"api": "im/v1/messages/{message_id} PATCH (streaming)",
|
|||
|
|
},
|
|||
|
|
"kick": {
|
|||
|
|
"status": "unsupported",
|
|||
|
|
"description": "?????? Bot ???????????????????????????,"
|
|||
|
|
"api": "N/A",
|
|||
|
|
},
|
|||
|
|
"ban": {
|
|||
|
|
"status": "unsupported",
|
|||
|
|
"description": "?????? Bot ?????????????????????,"
|
|||
|
|
"api": "N/A",
|
|||
|
|
},
|
|||
|
|
"mute": {
|
|||
|
|
"status": "unsupported",
|
|||
|
|
"description": "?????? Bot ?????????????????????",
|
|||
|
|
"api": "N/A",
|
|||
|
|
},
|
|||
|
|
"leave": {
|
|||
|
|
"status": "unsupported",
|
|||
|
|
"description": "Bot ???????????????????????????",
|
|||
|
|
"api": "N/A",
|
|||
|
|
},
|
|||
|
|
"addParticipant": {
|
|||
|
|
"status": "planned",
|
|||
|
|
"description": "?????????????????????,"
|
|||
|
|
"api": "im/v1/chats/{chat_id}/members POST",
|
|||
|
|
},
|
|||
|
|
"removeParticipant": {
|
|||
|
|
"status": "planned",
|
|||
|
|
"description": "?????????????????????,"
|
|||
|
|
"api": "im/v1/chats/{chat_id}/members/{member_id} DELETE",
|
|||
|
|
},
|
|||
|
|
"renameGroup": {
|
|||
|
|
"status": "planned",
|
|||
|
|
"description": "??????????????????",
|
|||
|
|
"api": "im/v1/chats/{chat_id} PATCH",
|
|||
|
|
},
|
|||
|
|
"setGroupIcon": {
|
|||
|
|
"status": "unsupported",
|
|||
|
|
"description": "????????????????????? API ???????????????,"
|
|||
|
|
"api": "N/A",
|
|||
|
|
},
|
|||
|
|
"channelInfo": {
|
|||
|
|
"status": "implemented",
|
|||
|
|
"description": "????????????/????????????",
|
|||
|
|
"api": "im/v1/chats/{chat_id} GET",
|
|||
|
|
},
|
|||
|
|
"channelList": {
|
|||
|
|
"status": "implemented",
|
|||
|
|
"description": "????????????????????????????????????",
|
|||
|
|
"api": "im/v1/chats GET",
|
|||
|
|
},
|
|||
|
|
"channelCreate": {
|
|||
|
|
"status": "planned",
|
|||
|
|
"description": "????????????",
|
|||
|
|
"api": "im/v1/chats POST",
|
|||
|
|
},
|
|||
|
|
"channelEdit": {
|
|||
|
|
"status": "planned",
|
|||
|
|
"description": "??????????????????",
|
|||
|
|
"api": "im/v1/chats/{chat_id} PATCH",
|
|||
|
|
},
|
|||
|
|
"memberInfo": {
|
|||
|
|
"status": "implemented",
|
|||
|
|
"description": "????????????/????????????",
|
|||
|
|
"api": "contact/v3/users/{user_id} GET",
|
|||
|
|
},
|
|||
|
|
"roleInfo": {
|
|||
|
|
"status": "unsupported",
|
|||
|
|
"description": "?????????????????????API",
|
|||
|
|
"api": "N/A",
|
|||
|
|
},
|
|||
|
|
"downloadFile": {
|
|||
|
|
"status": "implemented",
|
|||
|
|
"description": "????????????/??????",
|
|||
|
|
"api": "im/v1/messages/{message_id}/resources/{file_key} GET",
|
|||
|
|
},
|
|||
|
|
"uploadFile": {
|
|||
|
|
"status": "implemented",
|
|||
|
|
"description": "????????????",
|
|||
|
|
"api": "im/v1/files POST ???im/v1/images POST",
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
_FEISHU_ACTION_MAPPING: dict[str, str] = {
|
|||
|
|
"send": "send",
|
|||
|
|
"sendAttachment": "send_attachment",
|
|||
|
|
"sendPoll": "create_poll",
|
|||
|
|
"sendSticker": "sticker",
|
|||
|
|
"reply": "reply",
|
|||
|
|
"edit": "edit",
|
|||
|
|
"delete": "delete",
|
|||
|
|
"read": "read",
|
|||
|
|
"react": "react",
|
|||
|
|
"listReactions": "list_reactions",
|
|||
|
|
"pin": "pin",
|
|||
|
|
"unpin": "unpin",
|
|||
|
|
"listPins": "list_pins",
|
|||
|
|
"typing": "typing",
|
|||
|
|
"broadcast": "broadcast",
|
|||
|
|
"thread": "thread_create",
|
|||
|
|
"streamChunk": "stream",
|
|||
|
|
"kick": "kick",
|
|||
|
|
"ban": "ban",
|
|||
|
|
"mute": "mute",
|
|||
|
|
"leave": "leave_group",
|
|||
|
|
"addParticipant": "add_participant",
|
|||
|
|
"removeParticipant": "remove_participant",
|
|||
|
|
"renameGroup": "rename_group",
|
|||
|
|
"setGroupIcon": "set_group_icon",
|
|||
|
|
"channelInfo": "channel_info",
|
|||
|
|
"channelList": "channel_list",
|
|||
|
|
"channelCreate": "channel_create",
|
|||
|
|
"channelEdit": "channel_edit",
|
|||
|
|
"memberInfo": "member_info",
|
|||
|
|
"roleInfo": "role_info",
|
|||
|
|
"downloadFile": "download_file",
|
|||
|
|
"uploadFile": "upload_file",
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
def register_feishu_actions() -> None:
|
|||
|
|
from yuxi.channels.message_actions import ActionDeclaration, ActionRegistry, ActionStatus, MessageAction
|
|||
|
|
|
|||
|
|
declarations: dict[MessageAction, ActionDeclaration] = {}
|
|||
|
|
for action_name, info in FEISHU_MESSAGE_ACTIONS.items():
|
|||
|
|
mapped = _FEISHU_ACTION_MAPPING.get(action_name)
|
|||
|
|
if mapped is None:
|
|||
|
|
continue
|
|||
|
|
try:
|
|||
|
|
action_enum = MessageAction(mapped)
|
|||
|
|
except ValueError:
|
|||
|
|
continue
|
|||
|
|
status_str = info.get("status", "unsupported")
|
|||
|
|
status = {
|
|||
|
|
"implemented": ActionStatus.SUPPORTED,
|
|||
|
|
"planned": ActionStatus.PARTIAL,
|
|||
|
|
"unsupported": ActionStatus.UNSUPPORTED,
|
|||
|
|
}.get(status_str, ActionStatus.UNSUPPORTED)
|
|||
|
|
declarations[action_enum] = ActionDeclaration(
|
|||
|
|
action=action_enum,
|
|||
|
|
status=status,
|
|||
|
|
reason=info.get("description", ""),
|
|||
|
|
impl=info.get("api", ""),
|
|||
|
|
)
|
|||
|
|
ActionRegistry.register_channel_actions("feishu", declarations)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def resolve_feishu_action_target(params: dict[str, Any]) -> str | None:
|
|||
|
|
chat_id = params.get("chatId", params.get("chat_id", ""))
|
|||
|
|
open_id = params.get("openId", params.get("open_id", ""))
|
|||
|
|
msg_id = params.get("messageId", params.get("message_id", ""))
|
|||
|
|
|
|||
|
|
if msg_id:
|
|||
|
|
return msg_id
|
|||
|
|
if chat_id:
|
|||
|
|
return chat_id
|
|||
|
|
if open_id:
|
|||
|
|
return open_id
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
|
|||
|
|
def resolve_feishu_chat_id(params: dict[str, Any]) -> str:
|
|||
|
|
chat_id = params.get("chatId", params.get("chat_id", ""))
|
|||
|
|
if chat_id:
|
|||
|
|
if chat_id.startswith("oc_"):
|
|||
|
|
return f"feishu:group:{chat_id}"
|
|||
|
|
return chat_id
|
|||
|
|
return ""
|
|||
|
|
|
|||
|
|
|
|||
|
|
def resolve_feishu_member_id(params: dict[str, Any]) -> str:
|
|||
|
|
open_id = params.get("openId", params.get("open_id", ""))
|
|||
|
|
member_id = params.get("memberId", params.get("member_id", ""))
|
|||
|
|
return open_id or member_id or ""
|
|||
|
|
|
|||
|
|
|
|||
|
|
def resolve_feishu_message_id(params: dict[str, Any]) -> str:
|
|||
|
|
return params.get("messageId", params.get("message_id", ""))
|