From d746f01c77c9012fc6cd53bc13d0bd3accbc3fad Mon Sep 17 00:00:00 2001 From: Wang Xiaomei Date: Fri, 26 Jun 2026 23:26:44 +0800 Subject: [PATCH 1/3] feat: add configurable reply-to message behavior for Telegram Introduces a new `telegram_reply_to_message` configuration option, allowing users to control whether the bot automatically quotes the original message when sending a reply. This behavior can be set for `private` chats, `group` chats, `all` chats, or turned `off`. This provides greater flexibility in how the bot interacts in different Telegram chat environments. Additionally, this commit improves the resolution of sender nicknames for Telegram messages, prioritizing a combination of first/last name and username for a more comprehensive display. --- astrbot/core/config/default.py | 7 ++++ .../platform/sources/telegram/tg_adapter.py | 13 +++++++- .../platform/sources/telegram/tg_event.py | 33 +++++++++++++++++-- 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/astrbot/core/config/default.py b/astrbot/core/config/default.py index 700a345ccc..3aea7b1c21 100644 --- a/astrbot/core/config/default.py +++ b/astrbot/core/config/default.py @@ -455,6 +455,7 @@ "telegram_command_auto_refresh": True, "telegram_command_register_interval": 300, "telegram_polling_restart_delay": 5.0, + "telegram_reply_to_message": "off", }, "Discord": { "id": "discord", @@ -774,6 +775,12 @@ "type": "float", "hint": "当轮询意外结束尝试自动重启时的延迟时间,理论上越短恢复越快,但过短(<0.1s)可能导致死循环针对 API 服务器的请求阻断。单位为秒。默认为 5s。", }, + "telegram_reply_to_message": { + "description": "Telegram 回复时引用消息", + "type": "string", + "options": ["off", "private", "group", "all"], + "hint": "机器人回复时是否引用(reply to)触发该回复的原消息。off:关闭;private:仅私聊;group:仅群聊;all:私聊和群聊都引用。默认 off。", + }, "id": { "description": "机器人名称", "type": "string", diff --git a/astrbot/core/platform/sources/telegram/tg_adapter.py b/astrbot/core/platform/sources/telegram/tg_adapter.py index 8e6722ccff..0e1d84698a 100644 --- a/astrbot/core/platform/sources/telegram/tg_adapter.py +++ b/astrbot/core/platform/sources/telegram/tg_adapter.py @@ -79,6 +79,8 @@ def __init__( True, ) self.last_command_hash = None + # 机器人回复时引用原消息的范围:off / private / group / all + self.reply_to_message = self.config.get("telegram_reply_to_message", "off") self.scheduler = AsyncIOScheduler() self.scheduler.add_listener( @@ -484,9 +486,17 @@ def _apply_caption() -> None: if not _from_user: logger.warning("[Telegram] Received a message without a from_user.") return None + # 同时读取显示名称和用户名,都不存在时回退为 "Unknown" + display_name = " ".join( + part for part in (_from_user.first_name, _from_user.last_name) if part + ).strip() + if display_name and _from_user.username: + nickname = f"{display_name} (@{_from_user.username})" + else: + nickname = display_name or _from_user.username or "Unknown" message.sender = MessageMember( str(_from_user.id), - _from_user.username or "Unknown", + nickname, ) message.self_id = str(context.bot.username) message.raw_message = update @@ -751,6 +761,7 @@ def create_event(self, message: AstrBotMessage) -> TelegramPlatformEvent: platform_meta=self.meta(), session_id=message.session_id, client=self.client, + reply_to_message=self.reply_to_message, ) async def handle_msg(self, message: AstrBotMessage) -> None: diff --git a/astrbot/core/platform/sources/telegram/tg_event.py b/astrbot/core/platform/sources/telegram/tg_event.py index 8445a8ea1e..db8b17bae0 100644 --- a/astrbot/core/platform/sources/telegram/tg_event.py +++ b/astrbot/core/platform/sources/telegram/tg_event.py @@ -76,9 +76,12 @@ def __init__( platform_meta: PlatformMetadata, session_id: str, client: ExtBot, + reply_to_message: str = "off", ) -> None: super().__init__(message_str, message_obj, platform_meta, session_id) self.client = client + # 机器人回复时引用原消息的范围:off / private / group / all + self.reply_to_message = reply_to_message @classmethod def _split_message(cls, text: str) -> list[str]: @@ -271,6 +274,7 @@ async def send_with_client( client: ExtBot, message: MessageChain, user_name: str, + default_reply_to_message_id: str | None = None, ) -> None: image_path = None @@ -284,6 +288,11 @@ async def send_with_client( if isinstance(i, At): at_user_id = i.name + # 消息链未显式包含引用时,按配置默认引用触发该回复的原消息 + if not has_reply and default_reply_to_message_id: + has_reply = True + reply_message_id = default_reply_to_message_id + at_flag = False message_thread_id = None if "#" in user_name: @@ -341,10 +350,28 @@ async def send_with_client( ) async def send(self, message: MessageChain) -> None: - if self.get_message_type() == MessageType.GROUP_MESSAGE: - await self.send_with_client(self.client, message, self.message_obj.group_id) + is_group = self.get_message_type() == MessageType.GROUP_MESSAGE + # 根据配置范围决定是否默认引用触发该回复的原消息 + should_reply = self.reply_to_message == "all" or self.reply_to_message == ( + "group" if is_group else "private" + ) + default_reply_to_message_id = ( + self.message_obj.message_id if should_reply else None + ) + if is_group: + await self.send_with_client( + self.client, + message, + self.message_obj.group_id, + default_reply_to_message_id, + ) else: - await self.send_with_client(self.client, message, self.get_sender_id()) + await self.send_with_client( + self.client, + message, + self.get_sender_id(), + default_reply_to_message_id, + ) await super().send(message) async def react(self, emoji: str | None, big: bool = False) -> None: From 895c22f78e9f5068d6044adc423ef5d1fc4c6384 Mon Sep 17 00:00:00 2001 From: Wang Xiaomei Date: Sat, 27 Jun 2026 00:49:28 +0800 Subject: [PATCH 2/3] feat: add display labels for telegram reply-to message setting This improves the user experience and internationalization of the recently introduced 'telegram_reply_to_message' configuration by providing clear, localized labels for its options in the dashboard. --- astrbot/core/config/default.py | 1 + .../i18n/locales/en-US/features/config-metadata.json | 10 ++++++++++ .../i18n/locales/ru-RU/features/config-metadata.json | 10 ++++++++++ .../i18n/locales/zh-CN/features/config-metadata.json | 10 ++++++++++ 4 files changed, 31 insertions(+) diff --git a/astrbot/core/config/default.py b/astrbot/core/config/default.py index 3aea7b1c21..770b5a20b6 100644 --- a/astrbot/core/config/default.py +++ b/astrbot/core/config/default.py @@ -779,6 +779,7 @@ "description": "Telegram 回复时引用消息", "type": "string", "options": ["off", "private", "group", "all"], + "labels": ["关闭", "仅私聊", "仅群聊", "私聊和群聊"], "hint": "机器人回复时是否引用(reply to)触发该回复的原消息。off:关闭;private:仅私聊;group:仅群聊;all:私聊和群聊都引用。默认 off。", }, "id": { diff --git a/dashboard/src/i18n/locales/en-US/features/config-metadata.json b/dashboard/src/i18n/locales/en-US/features/config-metadata.json index 27c24af179..2d6bac0e36 100644 --- a/dashboard/src/i18n/locales/en-US/features/config-metadata.json +++ b/dashboard/src/i18n/locales/en-US/features/config-metadata.json @@ -600,6 +600,16 @@ "description": "Telegram Polling Restart Delay", "hint": "Waiting time in seconds when the polling loop needs to restart after unexpected exits. Defaults to 5s." }, + "telegram_reply_to_message": { + "description": "Telegram Reply To Message", + "labels": [ + "Disabled", + "Direct messages only", + "Group chats only", + "Direct and group chats" + ], + "hint": "Whether the bot quotes (replies to) the message that triggered its response. off: disabled; private: direct messages only; group: group chats only; all: both direct messages and group chats. Defaults to off." + }, "telegram_token": { "description": "Bot Token", "hint": "If you are in mainland China, set a proxy or change api_base in Other Settings." diff --git a/dashboard/src/i18n/locales/ru-RU/features/config-metadata.json b/dashboard/src/i18n/locales/ru-RU/features/config-metadata.json index 2c59e76261..cb16b7306a 100644 --- a/dashboard/src/i18n/locales/ru-RU/features/config-metadata.json +++ b/dashboard/src/i18n/locales/ru-RU/features/config-metadata.json @@ -596,6 +596,16 @@ "description": "Интервал автообновления команд Telegram", "hint": "Интервал автоматического обновления команд Telegram в секундах." }, + "telegram_reply_to_message": { + "description": "Цитировать сообщение при ответе в Telegram", + "labels": [ + "Отключено", + "Только личные сообщения", + "Только групповые чаты", + "Личные и групповые чаты" + ], + "hint": "Цитирует ли бот (отвечает на) сообщение, вызвавшее его ответ. off: отключено; private: только личные сообщения; group: только групповые чаты; all: и личные сообщения, и групповые чаты. По умолчанию off." + }, "telegram_token": { "description": "Токен бота", "hint": "Если вы находитесь в материковом Китае, установите прокси или измените api_base в разделе «Другие настройки»." diff --git a/dashboard/src/i18n/locales/zh-CN/features/config-metadata.json b/dashboard/src/i18n/locales/zh-CN/features/config-metadata.json index ca7fa48f7f..82c10670b3 100644 --- a/dashboard/src/i18n/locales/zh-CN/features/config-metadata.json +++ b/dashboard/src/i18n/locales/zh-CN/features/config-metadata.json @@ -602,6 +602,16 @@ "description": "Telegram 轮询重启延迟", "hint": "当轮询意外结束尝试自动重启时的延迟时间,单位为秒。默认为 5s。" }, + "telegram_reply_to_message": { + "description": "Telegram 回复时引用消息", + "labels": [ + "关闭", + "仅私聊", + "仅群聊", + "私聊和群聊" + ], + "hint": "机器人回复时是否引用触发该回复的原消息。off:关闭;private:仅私聊;group:仅群聊;all:私聊和群聊都引用。默认 off。" + }, "telegram_token": { "description": "Bot Token", "hint": "如果你的网络环境为中国大陆,请在 `其他配置` 处设置代理或更改 api_base。" From 02ddbc346d8c8a965ced7649e196db99753295ff Mon Sep 17 00:00:00 2001 From: Wang Xiaomei Date: Sat, 27 Jun 2026 01:22:21 +0800 Subject: [PATCH 3/3] feat: strictly apply "off" setting for Telegram reply-to messages When the `telegram_reply_to_message` configuration is set to prevent replies, remove any `Reply` components that may have been added to the message chain by other global settings. This ensures the Telegram platform's specific setting to disable quoting is always respected, overriding any default reply behavior. --- astrbot/core/platform/sources/telegram/tg_event.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/astrbot/core/platform/sources/telegram/tg_event.py b/astrbot/core/platform/sources/telegram/tg_event.py index db8b17bae0..1ae3c855c3 100644 --- a/astrbot/core/platform/sources/telegram/tg_event.py +++ b/astrbot/core/platform/sources/telegram/tg_event.py @@ -351,10 +351,14 @@ async def send_with_client( async def send(self, message: MessageChain) -> None: is_group = self.get_message_type() == MessageType.GROUP_MESSAGE - # 根据配置范围决定是否默认引用触发该回复的原消息 + # 根据配置范围决定是否默认引用触发该回复的原消息。 + # 当配置为 off 时,清除消息链中已有的 Reply 组件(来自全局管道 + # 「回复时引用发送人消息」等设置),确保 Telegram 平台完全不引用。 should_reply = self.reply_to_message == "all" or self.reply_to_message == ( "group" if is_group else "private" ) + if not should_reply: + message.chain = [c for c in message.chain if not isinstance(c, Reply)] default_reply_to_message_id = ( self.message_obj.message_id if should_reply else None )