mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-02 03:55:55 +00:00
fix: handle telegram eba non-message updates
This commit is contained in:
@@ -13,15 +13,21 @@ import traceback
|
|||||||
import telegram
|
import telegram
|
||||||
import telegram.ext
|
import telegram.ext
|
||||||
from telegram import Update
|
from telegram import Update
|
||||||
from telegram.ext import ApplicationBuilder, ContextTypes, MessageHandler, filters
|
from telegram.ext import (
|
||||||
|
ApplicationBuilder,
|
||||||
|
CallbackQueryHandler,
|
||||||
|
ChatMemberHandler,
|
||||||
|
ContextTypes,
|
||||||
|
MessageHandler,
|
||||||
|
MessageReactionHandler,
|
||||||
|
filters,
|
||||||
|
)
|
||||||
import telegramify_markdown
|
import telegramify_markdown
|
||||||
import pydantic
|
import pydantic
|
||||||
|
|
||||||
from langbot.pkg.utils import httpclient
|
|
||||||
import langbot_plugin.api.definition.abstract.platform.adapter as abstract_platform_adapter
|
import langbot_plugin.api.definition.abstract.platform.adapter as abstract_platform_adapter
|
||||||
import langbot_plugin.api.entities.builtin.platform.message as platform_message
|
import langbot_plugin.api.entities.builtin.platform.message as platform_message
|
||||||
import langbot_plugin.api.entities.builtin.platform.events as platform_events
|
import langbot_plugin.api.entities.builtin.platform.events as platform_events
|
||||||
import langbot_plugin.api.entities.builtin.platform.entities as platform_entities
|
|
||||||
import langbot_plugin.api.definition.abstract.platform.event_logger as abstract_platform_logger
|
import langbot_plugin.api.definition.abstract.platform.event_logger as abstract_platform_logger
|
||||||
|
|
||||||
from langbot.pkg.platform.adapters.telegram.message_converter import TelegramMessageConverter
|
from langbot.pkg.platform.adapters.telegram.message_converter import TelegramMessageConverter
|
||||||
@@ -58,8 +64,14 @@ class TelegramAdapter(TelegramAPIMixin, abstract_platform_adapter.AbstractPlatfo
|
|||||||
|
|
||||||
def __init__(self, config: dict, logger: abstract_platform_logger.AbstractEventLogger):
|
def __init__(self, config: dict, logger: abstract_platform_logger.AbstractEventLogger):
|
||||||
async def telegram_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
async def telegram_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
if not update.message and not update.edited_message and not update.chat_member \
|
if (
|
||||||
and not update.my_chat_member and not update.callback_query and not update.message_reaction:
|
not update.message
|
||||||
|
and not update.edited_message
|
||||||
|
and not update.chat_member
|
||||||
|
and not update.my_chat_member
|
||||||
|
and not update.callback_query
|
||||||
|
and not update.message_reaction
|
||||||
|
):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Skip messages from the bot itself
|
# Skip messages from the bot itself
|
||||||
@@ -68,23 +80,16 @@ class TelegramAdapter(TelegramAPIMixin, abstract_platform_adapter.AbstractPlatfo
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
# Legacy event type callbacks (compat with existing botmgr FriendMessage / GroupMessage listeners)
|
# Legacy event type callbacks (compat with existing botmgr FriendMessage / GroupMessage listeners)
|
||||||
if update.message and (platform_events.FriendMessage in self.listeners
|
if update.message and (
|
||||||
or platform_events.GroupMessage in self.listeners):
|
platform_events.FriendMessage in self.listeners or platform_events.GroupMessage in self.listeners
|
||||||
|
):
|
||||||
legacy_event = await self.legacy_event_converter.target2yiri(update, self.bot, self.bot_account_id)
|
legacy_event = await self.legacy_event_converter.target2yiri(update, self.bot, self.bot_account_id)
|
||||||
if legacy_event and type(legacy_event) in self.listeners:
|
if legacy_event and type(legacy_event) in self.listeners:
|
||||||
await self.listeners[type(legacy_event)](legacy_event, self)
|
await self.listeners[type(legacy_event)](legacy_event, self)
|
||||||
|
|
||||||
# EBA wildcard event callback (Event base class registered as wildcard)
|
eba_event = await self.event_converter.target2yiri(update, self.bot, self.bot_account_id)
|
||||||
if platform_events.Event in self.listeners:
|
if eba_event:
|
||||||
eba_event = await self.event_converter.target2yiri(update, self.bot, self.bot_account_id)
|
await self._dispatch_eba_event(eba_event)
|
||||||
if eba_event:
|
|
||||||
await self.listeners[platform_events.Event](eba_event, self)
|
|
||||||
|
|
||||||
# EBA specific event type callback
|
|
||||||
if platform_events.EBAEvent in self.listeners:
|
|
||||||
eba_event = await self.event_converter.target2yiri(update, self.bot, self.bot_account_id)
|
|
||||||
if eba_event:
|
|
||||||
await self.listeners[platform_events.EBAEvent](eba_event, self)
|
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
await self.logger.error(f'Error in telegram callback: {traceback.format_exc()}')
|
await self.logger.error(f'Error in telegram callback: {traceback.format_exc()}')
|
||||||
@@ -106,6 +111,25 @@ class TelegramAdapter(TelegramAPIMixin, abstract_platform_adapter.AbstractPlatfo
|
|||||||
telegram_callback,
|
telegram_callback,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
application.add_handler(
|
||||||
|
ChatMemberHandler(
|
||||||
|
telegram_callback,
|
||||||
|
ChatMemberHandler.CHAT_MEMBER,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
application.add_handler(
|
||||||
|
ChatMemberHandler(
|
||||||
|
telegram_callback,
|
||||||
|
ChatMemberHandler.MY_CHAT_MEMBER,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
application.add_handler(CallbackQueryHandler(telegram_callback))
|
||||||
|
application.add_handler(
|
||||||
|
MessageReactionHandler(
|
||||||
|
telegram_callback,
|
||||||
|
MessageReactionHandler.MESSAGE_REACTION,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
super().__init__(
|
super().__init__(
|
||||||
config=config,
|
config=config,
|
||||||
@@ -122,35 +146,33 @@ class TelegramAdapter(TelegramAPIMixin, abstract_platform_adapter.AbstractPlatfo
|
|||||||
|
|
||||||
def get_supported_events(self) -> list[str]:
|
def get_supported_events(self) -> list[str]:
|
||||||
return [
|
return [
|
||||||
"message.received",
|
'message.received',
|
||||||
"message.edited",
|
'message.edited',
|
||||||
"message.deleted",
|
'message.reaction',
|
||||||
"message.reaction",
|
'group.member_joined',
|
||||||
"group.member_joined",
|
'group.member_left',
|
||||||
"group.member_left",
|
'group.member_banned',
|
||||||
"group.member_banned",
|
'bot.invited_to_group',
|
||||||
"group.info_updated",
|
'bot.removed_from_group',
|
||||||
"bot.invited_to_group",
|
|
||||||
"bot.removed_from_group",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_supported_apis(self) -> list[str]:
|
def get_supported_apis(self) -> list[str]:
|
||||||
return [
|
return [
|
||||||
"send_message",
|
'send_message',
|
||||||
"reply_message",
|
'reply_message',
|
||||||
"edit_message",
|
'edit_message',
|
||||||
"delete_message",
|
'delete_message',
|
||||||
"forward_message",
|
'forward_message',
|
||||||
"get_group_info",
|
'get_group_info',
|
||||||
"get_group_member_list",
|
'get_group_member_list',
|
||||||
"get_group_member_info",
|
'get_group_member_info',
|
||||||
"get_user_info",
|
'get_user_info',
|
||||||
"get_file_url",
|
'get_file_url',
|
||||||
"mute_member",
|
'mute_member',
|
||||||
"unmute_member",
|
'unmute_member',
|
||||||
"kick_member",
|
'kick_member',
|
||||||
"leave_group",
|
'leave_group',
|
||||||
"call_platform_api",
|
'call_platform_api',
|
||||||
]
|
]
|
||||||
|
|
||||||
# ---- Message Send / Reply (preserving original logic) ----
|
# ---- Message Send / Reply (preserving original logic) ----
|
||||||
@@ -337,6 +359,14 @@ class TelegramAdapter(TelegramAPIMixin, abstract_platform_adapter.AbstractPlatfo
|
|||||||
|
|
||||||
# ---- Event Listeners ----
|
# ---- Event Listeners ----
|
||||||
|
|
||||||
|
async def _dispatch_eba_event(self, event: platform_events.EBAEvent):
|
||||||
|
"""Dispatch once, preferring the most specific registered listener."""
|
||||||
|
for event_type in (type(event), platform_events.EBAEvent, platform_events.Event):
|
||||||
|
callback = self.listeners.get(event_type)
|
||||||
|
if callback:
|
||||||
|
await callback(event, self)
|
||||||
|
return
|
||||||
|
|
||||||
def register_listener(
|
def register_listener(
|
||||||
self,
|
self,
|
||||||
event_type: typing.Type[platform_events.Event],
|
event_type: typing.Type[platform_events.Event],
|
||||||
@@ -366,7 +396,8 @@ class TelegramAdapter(TelegramAPIMixin, abstract_platform_adapter.AbstractPlatfo
|
|||||||
handler = PLATFORM_API_MAP.get(action)
|
handler = PLATFORM_API_MAP.get(action)
|
||||||
if handler is None:
|
if handler is None:
|
||||||
from langbot_plugin.api.entities.builtin.platform.errors import NotSupportedError
|
from langbot_plugin.api.entities.builtin.platform.errors import NotSupportedError
|
||||||
raise NotSupportedError(f"call_platform_api:{action}")
|
|
||||||
|
raise NotSupportedError(f'call_platform_api:{action}')
|
||||||
return await handler(self.bot, params)
|
return await handler(self.bot, params)
|
||||||
|
|
||||||
# ---- Lifecycle ----
|
# ---- Lifecycle ----
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ from telegram import Update
|
|||||||
|
|
||||||
import langbot_plugin.api.entities.builtin.platform.events as platform_events
|
import langbot_plugin.api.entities.builtin.platform.events as platform_events
|
||||||
import langbot_plugin.api.entities.builtin.platform.entities as platform_entities
|
import langbot_plugin.api.entities.builtin.platform.entities as platform_entities
|
||||||
import langbot_plugin.api.entities.builtin.platform.message as platform_message
|
|
||||||
import langbot_plugin.api.definition.abstract.platform.adapter as abstract_platform_adapter
|
import langbot_plugin.api.definition.abstract.platform.adapter as abstract_platform_adapter
|
||||||
|
|
||||||
from langbot.pkg.platform.adapters.telegram.message_converter import TelegramMessageConverter
|
from langbot.pkg.platform.adapters.telegram.message_converter import TelegramMessageConverter
|
||||||
@@ -22,7 +21,7 @@ def _make_user(tg_user: telegram.User) -> platform_entities.User:
|
|||||||
"""Convert a Telegram User to a unified User entity."""
|
"""Convert a Telegram User to a unified User entity."""
|
||||||
return platform_entities.User(
|
return platform_entities.User(
|
||||||
id=tg_user.id,
|
id=tg_user.id,
|
||||||
nickname=tg_user.first_name or "",
|
nickname=tg_user.first_name or '',
|
||||||
username=tg_user.username,
|
username=tg_user.username,
|
||||||
is_bot=tg_user.is_bot,
|
is_bot=tg_user.is_bot,
|
||||||
)
|
)
|
||||||
@@ -32,7 +31,7 @@ def _make_user_group(tg_chat: telegram.Chat) -> platform_entities.UserGroup:
|
|||||||
"""Convert a Telegram Chat to a unified UserGroup entity."""
|
"""Convert a Telegram Chat to a unified UserGroup entity."""
|
||||||
return platform_entities.UserGroup(
|
return platform_entities.UserGroup(
|
||||||
id=tg_chat.id,
|
id=tg_chat.id,
|
||||||
name=tg_chat.title or tg_chat.first_name or "",
|
name=tg_chat.title or tg_chat.first_name or '',
|
||||||
description=tg_chat.description if hasattr(tg_chat, 'description') else None,
|
description=tg_chat.description if hasattr(tg_chat, 'description') else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -69,8 +68,10 @@ class TelegramEventConverter(abstract_platform_adapter.AbstractEventConverter):
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
# ---- Message event ----
|
# ---- Message event ----
|
||||||
if update.message and update.message.text is not None or (
|
if (
|
||||||
update.message and (update.message.photo or update.message.voice or update.message.document)
|
update.message
|
||||||
|
and update.message.text is not None
|
||||||
|
or (update.message and (update.message.photo or update.message.voice or update.message.document))
|
||||||
):
|
):
|
||||||
return await TelegramEventConverter._convert_message(update, bot, bot_account_id)
|
return await TelegramEventConverter._convert_message(update, bot, bot_account_id)
|
||||||
|
|
||||||
@@ -89,15 +90,15 @@ class TelegramEventConverter(abstract_platform_adapter.AbstractEventConverter):
|
|||||||
# ---- Callback query (button clicks, etc.) ----
|
# ---- Callback query (button clicks, etc.) ----
|
||||||
if update.callback_query:
|
if update.callback_query:
|
||||||
return platform_events.PlatformSpecificEvent(
|
return platform_events.PlatformSpecificEvent(
|
||||||
type="platform.specific",
|
type='platform.specific',
|
||||||
timestamp=time.time(),
|
timestamp=time.time(),
|
||||||
adapter_name="telegram",
|
adapter_name='telegram',
|
||||||
action="callback_query",
|
action='callback_query',
|
||||||
data={
|
data={
|
||||||
"callback_query_id": update.callback_query.id,
|
'callback_query_id': update.callback_query.id,
|
||||||
"data": update.callback_query.data,
|
'data': update.callback_query.data,
|
||||||
"from_user_id": update.callback_query.from_user.id if update.callback_query.from_user else None,
|
'from_user_id': update.callback_query.from_user.id if update.callback_query.from_user else None,
|
||||||
"message_id": update.callback_query.message.message_id if update.callback_query.message else None,
|
'message_id': update.callback_query.message.message_id if update.callback_query.message else None,
|
||||||
},
|
},
|
||||||
source_platform_object=update,
|
source_platform_object=update,
|
||||||
)
|
)
|
||||||
@@ -108,23 +109,25 @@ class TelegramEventConverter(abstract_platform_adapter.AbstractEventConverter):
|
|||||||
|
|
||||||
# ---- Fallback: wrap as PlatformSpecificEvent ----
|
# ---- Fallback: wrap as PlatformSpecificEvent ----
|
||||||
return platform_events.PlatformSpecificEvent(
|
return platform_events.PlatformSpecificEvent(
|
||||||
type="platform.specific",
|
type='platform.specific',
|
||||||
timestamp=time.time(),
|
timestamp=time.time(),
|
||||||
adapter_name="telegram",
|
adapter_name='telegram',
|
||||||
action="unknown_update",
|
action='unknown_update',
|
||||||
data={"update_id": update.update_id},
|
data={'update_id': update.update_id},
|
||||||
source_platform_object=update,
|
source_platform_object=update,
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def _convert_message(
|
async def _convert_message(
|
||||||
update: Update, bot: telegram.Bot, bot_account_id: str,
|
update: Update,
|
||||||
|
bot: telegram.Bot,
|
||||||
|
bot_account_id: str,
|
||||||
) -> platform_events.MessageReceivedEvent:
|
) -> platform_events.MessageReceivedEvent:
|
||||||
"""Convert a Telegram message to MessageReceivedEvent."""
|
"""Convert a Telegram message to MessageReceivedEvent."""
|
||||||
message = update.message
|
message = update.message
|
||||||
lb_message = await TelegramMessageConverter.target2yiri(message, bot, bot_account_id)
|
lb_message = await TelegramMessageConverter.target2yiri(message, bot, bot_account_id)
|
||||||
|
|
||||||
sender = _make_user(message.from_user) if message.from_user else platform_entities.User(id="")
|
sender = _make_user(message.from_user) if message.from_user else platform_entities.User(id='')
|
||||||
chat = message.chat
|
chat = message.chat
|
||||||
ct = _chat_type(chat)
|
ct = _chat_type(chat)
|
||||||
|
|
||||||
@@ -133,9 +136,9 @@ class TelegramEventConverter(abstract_platform_adapter.AbstractEventConverter):
|
|||||||
group = _make_user_group(chat)
|
group = _make_user_group(chat)
|
||||||
|
|
||||||
return platform_events.MessageReceivedEvent(
|
return platform_events.MessageReceivedEvent(
|
||||||
type="message.received",
|
type='message.received',
|
||||||
timestamp=message.date.timestamp() if message.date else 0.0,
|
timestamp=message.date.timestamp() if message.date else 0.0,
|
||||||
adapter_name="telegram",
|
adapter_name='telegram',
|
||||||
message_id=message.message_id,
|
message_id=message.message_id,
|
||||||
message_chain=lb_message,
|
message_chain=lb_message,
|
||||||
sender=sender,
|
sender=sender,
|
||||||
@@ -147,13 +150,15 @@ class TelegramEventConverter(abstract_platform_adapter.AbstractEventConverter):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def _convert_edited_message(
|
async def _convert_edited_message(
|
||||||
update: Update, bot: telegram.Bot, bot_account_id: str,
|
update: Update,
|
||||||
|
bot: telegram.Bot,
|
||||||
|
bot_account_id: str,
|
||||||
) -> platform_events.MessageEditedEvent:
|
) -> platform_events.MessageEditedEvent:
|
||||||
"""Convert a Telegram edited message to MessageEditedEvent."""
|
"""Convert a Telegram edited message to MessageEditedEvent."""
|
||||||
message = update.edited_message
|
message = update.edited_message
|
||||||
lb_message = await TelegramMessageConverter.target2yiri(message, bot, bot_account_id)
|
lb_message = await TelegramMessageConverter.target2yiri(message, bot, bot_account_id)
|
||||||
|
|
||||||
editor = _make_user(message.from_user) if message.from_user else platform_entities.User(id="")
|
editor = _make_user(message.from_user) if message.from_user else platform_entities.User(id='')
|
||||||
chat = message.chat
|
chat = message.chat
|
||||||
ct = _chat_type(chat)
|
ct = _chat_type(chat)
|
||||||
|
|
||||||
@@ -162,9 +167,9 @@ class TelegramEventConverter(abstract_platform_adapter.AbstractEventConverter):
|
|||||||
group = _make_user_group(chat)
|
group = _make_user_group(chat)
|
||||||
|
|
||||||
return platform_events.MessageEditedEvent(
|
return platform_events.MessageEditedEvent(
|
||||||
type="message.edited",
|
type='message.edited',
|
||||||
timestamp=message.edit_date.timestamp() if message.edit_date else 0.0,
|
timestamp=message.edit_date.timestamp() if message.edit_date else 0.0,
|
||||||
adapter_name="telegram",
|
adapter_name='telegram',
|
||||||
message_id=message.message_id,
|
message_id=message.message_id,
|
||||||
new_content=lb_message,
|
new_content=lb_message,
|
||||||
editor=editor,
|
editor=editor,
|
||||||
@@ -182,22 +187,27 @@ class TelegramEventConverter(abstract_platform_adapter.AbstractEventConverter):
|
|||||||
cm = update.chat_member
|
cm = update.chat_member
|
||||||
chat = cm.chat
|
chat = cm.chat
|
||||||
group = _make_user_group(chat)
|
group = _make_user_group(chat)
|
||||||
member = _make_user(cm.new_chat_member.user) if cm.new_chat_member else platform_entities.User(id="")
|
member = _make_user(cm.new_chat_member.user) if cm.new_chat_member else platform_entities.User(id='')
|
||||||
inviter = _make_user(cm.from_user) if cm.from_user else None
|
inviter = _make_user(cm.from_user) if cm.from_user else None
|
||||||
|
|
||||||
old_status = cm.old_chat_member.status if cm.old_chat_member else None
|
old_status = cm.old_chat_member.status if cm.old_chat_member else None
|
||||||
new_status = cm.new_chat_member.status if cm.new_chat_member else None
|
new_status = cm.new_chat_member.status if cm.new_chat_member else None
|
||||||
|
|
||||||
# Member joined
|
# Member joined
|
||||||
if old_status in (None, 'left', 'kicked') and new_status in ('member', 'administrator', 'creator', 'restricted'):
|
if old_status in (None, 'left', 'kicked') and new_status in (
|
||||||
|
'member',
|
||||||
|
'administrator',
|
||||||
|
'creator',
|
||||||
|
'restricted',
|
||||||
|
):
|
||||||
return platform_events.MemberJoinedEvent(
|
return platform_events.MemberJoinedEvent(
|
||||||
type="group.member_joined",
|
type='group.member_joined',
|
||||||
timestamp=cm.date.timestamp() if cm.date else time.time(),
|
timestamp=cm.date.timestamp() if cm.date else time.time(),
|
||||||
adapter_name="telegram",
|
adapter_name='telegram',
|
||||||
group=group,
|
group=group,
|
||||||
member=member,
|
member=member,
|
||||||
inviter=inviter,
|
inviter=inviter,
|
||||||
join_type="invite" if inviter and inviter.id != member.id else "direct",
|
join_type='invite' if inviter and inviter.id != member.id else 'direct',
|
||||||
source_platform_object=update,
|
source_platform_object=update,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -205,9 +215,9 @@ class TelegramEventConverter(abstract_platform_adapter.AbstractEventConverter):
|
|||||||
if old_status in ('member', 'administrator', 'creator', 'restricted') and new_status in ('left', 'kicked'):
|
if old_status in ('member', 'administrator', 'creator', 'restricted') and new_status in ('left', 'kicked'):
|
||||||
is_kicked = new_status == 'kicked'
|
is_kicked = new_status == 'kicked'
|
||||||
return platform_events.MemberLeftEvent(
|
return platform_events.MemberLeftEvent(
|
||||||
type="group.member_left",
|
type='group.member_left',
|
||||||
timestamp=cm.date.timestamp() if cm.date else time.time(),
|
timestamp=cm.date.timestamp() if cm.date else time.time(),
|
||||||
adapter_name="telegram",
|
adapter_name='telegram',
|
||||||
group=group,
|
group=group,
|
||||||
member=member,
|
member=member,
|
||||||
is_kicked=is_kicked,
|
is_kicked=is_kicked,
|
||||||
@@ -223,9 +233,9 @@ class TelegramEventConverter(abstract_platform_adapter.AbstractEventConverter):
|
|||||||
if hasattr(restricted, 'until_date') and restricted.until_date:
|
if hasattr(restricted, 'until_date') and restricted.until_date:
|
||||||
duration = int(restricted.until_date.timestamp() - time.time())
|
duration = int(restricted.until_date.timestamp() - time.time())
|
||||||
return platform_events.MemberBannedEvent(
|
return platform_events.MemberBannedEvent(
|
||||||
type="group.member_banned",
|
type='group.member_banned',
|
||||||
timestamp=cm.date.timestamp() if cm.date else time.time(),
|
timestamp=cm.date.timestamp() if cm.date else time.time(),
|
||||||
adapter_name="telegram",
|
adapter_name='telegram',
|
||||||
group=group,
|
group=group,
|
||||||
member=member,
|
member=member,
|
||||||
operator=inviter,
|
operator=inviter,
|
||||||
@@ -235,15 +245,15 @@ class TelegramEventConverter(abstract_platform_adapter.AbstractEventConverter):
|
|||||||
|
|
||||||
# Other chat_member changes -> PlatformSpecificEvent
|
# Other chat_member changes -> PlatformSpecificEvent
|
||||||
return platform_events.PlatformSpecificEvent(
|
return platform_events.PlatformSpecificEvent(
|
||||||
type="platform.specific",
|
type='platform.specific',
|
||||||
timestamp=cm.date.timestamp() if cm.date else time.time(),
|
timestamp=cm.date.timestamp() if cm.date else time.time(),
|
||||||
adapter_name="telegram",
|
adapter_name='telegram',
|
||||||
action="chat_member_updated",
|
action='chat_member_updated',
|
||||||
data={
|
data={
|
||||||
"old_status": old_status,
|
'old_status': old_status,
|
||||||
"new_status": new_status,
|
'new_status': new_status,
|
||||||
"chat_id": chat.id,
|
'chat_id': chat.id,
|
||||||
"user_id": member.id,
|
'user_id': member.id,
|
||||||
},
|
},
|
||||||
source_platform_object=update,
|
source_platform_object=update,
|
||||||
)
|
)
|
||||||
@@ -264,9 +274,9 @@ class TelegramEventConverter(abstract_platform_adapter.AbstractEventConverter):
|
|||||||
# Bot invited to group
|
# Bot invited to group
|
||||||
if old_status in (None, 'left', 'kicked') and new_status in ('member', 'administrator'):
|
if old_status in (None, 'left', 'kicked') and new_status in ('member', 'administrator'):
|
||||||
return platform_events.BotInvitedToGroupEvent(
|
return platform_events.BotInvitedToGroupEvent(
|
||||||
type="bot.invited_to_group",
|
type='bot.invited_to_group',
|
||||||
timestamp=mcm.date.timestamp() if mcm.date else time.time(),
|
timestamp=mcm.date.timestamp() if mcm.date else time.time(),
|
||||||
adapter_name="telegram",
|
adapter_name='telegram',
|
||||||
group=group,
|
group=group,
|
||||||
inviter=inviter,
|
inviter=inviter,
|
||||||
source_platform_object=update,
|
source_platform_object=update,
|
||||||
@@ -275,9 +285,9 @@ class TelegramEventConverter(abstract_platform_adapter.AbstractEventConverter):
|
|||||||
# Bot removed from group
|
# Bot removed from group
|
||||||
if old_status in ('member', 'administrator', 'creator') and new_status in ('left', 'kicked'):
|
if old_status in ('member', 'administrator', 'creator') and new_status in ('left', 'kicked'):
|
||||||
return platform_events.BotRemovedFromGroupEvent(
|
return platform_events.BotRemovedFromGroupEvent(
|
||||||
type="bot.removed_from_group",
|
type='bot.removed_from_group',
|
||||||
timestamp=mcm.date.timestamp() if mcm.date else time.time(),
|
timestamp=mcm.date.timestamp() if mcm.date else time.time(),
|
||||||
adapter_name="telegram",
|
adapter_name='telegram',
|
||||||
group=group,
|
group=group,
|
||||||
operator=inviter,
|
operator=inviter,
|
||||||
source_platform_object=update,
|
source_platform_object=update,
|
||||||
@@ -291,9 +301,9 @@ class TelegramEventConverter(abstract_platform_adapter.AbstractEventConverter):
|
|||||||
if hasattr(restricted, 'until_date') and restricted.until_date:
|
if hasattr(restricted, 'until_date') and restricted.until_date:
|
||||||
duration = int(restricted.until_date.timestamp() - time.time())
|
duration = int(restricted.until_date.timestamp() - time.time())
|
||||||
return platform_events.BotMutedEvent(
|
return platform_events.BotMutedEvent(
|
||||||
type="bot.muted",
|
type='bot.muted',
|
||||||
timestamp=mcm.date.timestamp() if mcm.date else time.time(),
|
timestamp=mcm.date.timestamp() if mcm.date else time.time(),
|
||||||
adapter_name="telegram",
|
adapter_name='telegram',
|
||||||
group=group,
|
group=group,
|
||||||
operator=inviter,
|
operator=inviter,
|
||||||
duration=duration,
|
duration=duration,
|
||||||
@@ -301,14 +311,14 @@ class TelegramEventConverter(abstract_platform_adapter.AbstractEventConverter):
|
|||||||
)
|
)
|
||||||
|
|
||||||
return platform_events.PlatformSpecificEvent(
|
return platform_events.PlatformSpecificEvent(
|
||||||
type="platform.specific",
|
type='platform.specific',
|
||||||
timestamp=mcm.date.timestamp() if mcm.date else time.time(),
|
timestamp=mcm.date.timestamp() if mcm.date else time.time(),
|
||||||
adapter_name="telegram",
|
adapter_name='telegram',
|
||||||
action="my_chat_member_updated",
|
action='my_chat_member_updated',
|
||||||
data={
|
data={
|
||||||
"old_status": old_status,
|
'old_status': old_status,
|
||||||
"new_status": new_status,
|
'new_status': new_status,
|
||||||
"chat_id": chat.id,
|
'chat_id': chat.id,
|
||||||
},
|
},
|
||||||
source_platform_object=update,
|
source_platform_object=update,
|
||||||
)
|
)
|
||||||
@@ -330,7 +340,7 @@ class TelegramEventConverter(abstract_platform_adapter.AbstractEventConverter):
|
|||||||
elif hasattr(r, 'custom_emoji_id'):
|
elif hasattr(r, 'custom_emoji_id'):
|
||||||
new_emojis.append(str(r.custom_emoji_id))
|
new_emojis.append(str(r.custom_emoji_id))
|
||||||
|
|
||||||
user = platform_entities.User(id="")
|
user = platform_entities.User(id='')
|
||||||
if reaction.user:
|
if reaction.user:
|
||||||
user = _make_user(reaction.user)
|
user = _make_user(reaction.user)
|
||||||
|
|
||||||
@@ -338,12 +348,12 @@ class TelegramEventConverter(abstract_platform_adapter.AbstractEventConverter):
|
|||||||
group = _make_user_group(chat) if ct == platform_entities.ChatType.GROUP else None
|
group = _make_user_group(chat) if ct == platform_entities.ChatType.GROUP else None
|
||||||
|
|
||||||
return platform_events.MessageReactionEvent(
|
return platform_events.MessageReactionEvent(
|
||||||
type="message.reaction",
|
type='message.reaction',
|
||||||
timestamp=reaction.date.timestamp() if reaction.date else time.time(),
|
timestamp=reaction.date.timestamp() if reaction.date else time.time(),
|
||||||
adapter_name="telegram",
|
adapter_name='telegram',
|
||||||
message_id=reaction.message_id,
|
message_id=reaction.message_id,
|
||||||
user=user,
|
user=user,
|
||||||
reaction=new_emojis[0] if new_emojis else "",
|
reaction=new_emojis[0] if new_emojis else '',
|
||||||
is_add=len(new_emojis) > 0,
|
is_add=len(new_emojis) > 0,
|
||||||
chat_type=ct,
|
chat_type=ct,
|
||||||
chat_id=chat.id,
|
chat_id=chat.id,
|
||||||
|
|||||||
@@ -41,12 +41,10 @@ spec:
|
|||||||
supported_events:
|
supported_events:
|
||||||
- message.received
|
- message.received
|
||||||
- message.edited
|
- message.edited
|
||||||
- message.deleted
|
|
||||||
- message.reaction
|
- message.reaction
|
||||||
- group.member_joined
|
- group.member_joined
|
||||||
- group.member_left
|
- group.member_left
|
||||||
- group.member_banned
|
- group.member_banned
|
||||||
- group.info_updated
|
|
||||||
- bot.invited_to_group
|
- bot.invited_to_group
|
||||||
- bot.removed_from_group
|
- bot.removed_from_group
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ Migrated from the original sources/telegram.py TelegramMessageConverter. Logic u
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import typing
|
|
||||||
|
|
||||||
import telegram
|
import telegram
|
||||||
|
|
||||||
|
|||||||
127
tests/unit_tests/platform/test_telegram_eba_adapter.py
Normal file
127
tests/unit_tests/platform/test_telegram_eba_adapter.py
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import pathlib
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import yaml
|
||||||
|
from telegram.ext import CallbackQueryHandler, ChatMemberHandler, MessageHandler, MessageReactionHandler
|
||||||
|
|
||||||
|
from langbot.pkg.platform.adapters.telegram.adapter import TelegramAdapter
|
||||||
|
from langbot_plugin.api.definition.abstract.platform.event_logger import AbstractEventLogger
|
||||||
|
from langbot_plugin.api.entities.builtin.platform import entities as platform_entities
|
||||||
|
from langbot_plugin.api.entities.builtin.platform import events as platform_events
|
||||||
|
from langbot_plugin.api.entities.builtin.platform import message as platform_message
|
||||||
|
|
||||||
|
|
||||||
|
class DummyLogger(AbstractEventLogger):
|
||||||
|
async def info(self, text, images=None, message_session_id=None, no_throw=True):
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def debug(self, text, images=None, message_session_id=None, no_throw=True):
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def warning(self, text, images=None, message_session_id=None, no_throw=True):
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def error(self, text, images=None, message_session_id=None, no_throw=True):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def make_adapter() -> TelegramAdapter:
|
||||||
|
return TelegramAdapter(
|
||||||
|
{
|
||||||
|
'token': '123456:ABCDEF_fake_token_for_object_parsing',
|
||||||
|
'markdown_card': False,
|
||||||
|
'enable-stream-reply': False,
|
||||||
|
},
|
||||||
|
DummyLogger(),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_telegram_adapter_registers_all_declared_update_handlers():
|
||||||
|
adapter = make_adapter()
|
||||||
|
|
||||||
|
handlers = adapter.application.handlers[0]
|
||||||
|
|
||||||
|
assert sum(isinstance(handler, MessageHandler) for handler in handlers) == 2
|
||||||
|
assert sum(isinstance(handler, ChatMemberHandler) for handler in handlers) == 2
|
||||||
|
assert any(isinstance(handler, CallbackQueryHandler) for handler in handlers)
|
||||||
|
assert any(isinstance(handler, MessageReactionHandler) for handler in handlers)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_telegram_adapter_dispatches_only_most_specific_eba_listener():
|
||||||
|
adapter = make_adapter()
|
||||||
|
calls: list[str] = []
|
||||||
|
|
||||||
|
async def wildcard_listener(event, adapter):
|
||||||
|
calls.append('event')
|
||||||
|
|
||||||
|
async def eba_listener(event, adapter):
|
||||||
|
calls.append('eba')
|
||||||
|
|
||||||
|
async def message_listener(event, adapter):
|
||||||
|
calls.append('message.received')
|
||||||
|
|
||||||
|
adapter.register_listener(platform_events.Event, wildcard_listener)
|
||||||
|
adapter.register_listener(platform_events.EBAEvent, eba_listener)
|
||||||
|
adapter.register_listener(platform_events.MessageReceivedEvent, message_listener)
|
||||||
|
|
||||||
|
event = platform_events.MessageReceivedEvent(
|
||||||
|
message_id=1,
|
||||||
|
message_chain=platform_message.MessageChain([platform_message.Plain(text='hello')]),
|
||||||
|
sender=platform_entities.User(id=1),
|
||||||
|
chat_id=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
await adapter._dispatch_eba_event(event)
|
||||||
|
|
||||||
|
assert calls == ['message.received']
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_telegram_adapter_dispatch_falls_back_to_eba_then_event_listener():
|
||||||
|
adapter = make_adapter()
|
||||||
|
calls: list[str] = []
|
||||||
|
|
||||||
|
async def wildcard_listener(event, adapter):
|
||||||
|
calls.append('event')
|
||||||
|
|
||||||
|
async def eba_listener(event, adapter):
|
||||||
|
calls.append('eba')
|
||||||
|
|
||||||
|
adapter.register_listener(platform_events.Event, wildcard_listener)
|
||||||
|
adapter.register_listener(platform_events.EBAEvent, eba_listener)
|
||||||
|
|
||||||
|
event = platform_events.MessageEditedEvent(
|
||||||
|
message_id=1,
|
||||||
|
new_content=platform_message.MessageChain([platform_message.Plain(text='edited')]),
|
||||||
|
editor=platform_entities.User(id=1),
|
||||||
|
chat_id=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
await adapter._dispatch_eba_event(event)
|
||||||
|
assert calls == ['eba']
|
||||||
|
|
||||||
|
adapter.unregister_listener(platform_events.EBAEvent, eba_listener)
|
||||||
|
await adapter._dispatch_eba_event(event)
|
||||||
|
assert calls == ['eba', 'event']
|
||||||
|
|
||||||
|
|
||||||
|
def test_telegram_supported_events_match_manifest():
|
||||||
|
adapter_events = make_adapter().get_supported_events()
|
||||||
|
manifest_path = (
|
||||||
|
pathlib.Path(__file__).parents[3]
|
||||||
|
/ 'src'
|
||||||
|
/ 'langbot'
|
||||||
|
/ 'pkg'
|
||||||
|
/ 'platform'
|
||||||
|
/ 'adapters'
|
||||||
|
/ 'telegram'
|
||||||
|
/ 'manifest.yaml'
|
||||||
|
)
|
||||||
|
manifest_events = yaml.safe_load(manifest_path.read_text())['spec']['supported_events']
|
||||||
|
|
||||||
|
assert adapter_events == manifest_events
|
||||||
|
assert 'message.deleted' not in adapter_events
|
||||||
|
assert 'group.info_updated' not in adapter_events
|
||||||
Reference in New Issue
Block a user