Skip to content

Feat/telegram reply to message and read user display name#9041

Open
g2nnyS wants to merge 3 commits into
AstrBotDevs:masterfrom
g2nnyS:feat/telegram-reply-to-message
Open

Feat/telegram reply to message and read user display name#9041
g2nnyS wants to merge 3 commits into
AstrBotDevs:masterfrom
g2nnyS:feat/telegram-reply-to-message

Conversation

@g2nnyS

@g2nnyS g2nnyS commented Jun 26, 2026

Copy link
Copy Markdown

当前 Telegram 适配器存在两个不足:

  1. 只读取 username@handle)作为发送者昵称,忽略 first_name / last_name 显示名,导致传给 LLM 的昵称信息不完整。
  2. 机器人回复时不引用原消息,群聊中多条消息交错时难以分辨 bot 在回复谁。

本 PR 补充显示名读取和可配置的回复引用功能。

Modifications / 改动点

核心文件:

  • astrbot/core/config/default.py — 新增 telegram_reply_to_message 配置项(四档枚举:off/private/group/all,默认 off),含 schema 元数据和默认模板。
  • astrbot/core/platform/sources/telegram/tg_adapter.py — 读取配置;构建 sender.nickname显示名称 (@username) 格式。
  • astrbot/core/platform/sources/telegram/tg_event.py — 按配置策略决定是否引用原消息;off 时清除全局 pipeline 注入的 Reply 组件。

国际化文件:

  • dashboard/src/i18n/locales/zh-CN/features/config-metadata.json
  • dashboard/src/i18n/locales/en-US/features/config-metadata.json
  • dashboard/src/i18n/locales/ru-RU/features/config-metadata.json

实现的功能:

  1. sender nickname 同时展示显示名和 @username,缺失时优雅回退
  2. 可配置回复引用范围(关闭 / 仅私聊 / 仅群聊 / 私聊和群聊),下拉标签支持中英俄三语
  3. off 档严格屏蔽全局 pipeline 注入的 Reply
  • This is NOT a breaking change. / 这不是一个破坏性变更。

Screenshots or Test Results / 运行截图或测试结果

显示名称测试:

图片
[2026-06-27 01:36:56.158] [Core][INFO][respond.stage:183]: Prepare to send - 王小美 Ganyu (@Ganyu_Genshin)/2112780557: [引用消息] ✅ Switched to new conversation: ddc7。 

[2026-06-27 01:37:04.520] [Core][INFO][core.event_bus:74]: [default] [telegram(telegram)] 王小美 Ganyu (@Ganyu_Genshin)/2112780557: 你好!你是谁? 

[2026-06-27 01:37:07.790] [Core][INFO][respond.stage:183]: Prepare to send - 王小美 Ganyu (@Ganyu_Genshin)/2112780557: [引用消息] 你好!👋 我是你的智能助手,很高兴为你服务!

我是一个由人工智能驱动的虚拟助手,可以帮你处理各种任务,比如:

- 💬 **聊天交流** — 陪你聊天、回答问题
- ⏰ **定时任务** — 设置提醒、定期提醒、定时发送消息等
- 📄 **处理文件** — 帮你整理信息、阅读文件内容
- 🔍 **查找信息** — 根据我的知识为你解答疑惑

有什么我可以帮你的吗?尽管说,我会尽全力协助你!😊 

[2026-06-27 01:37:10.805] [Core][INFO][core.event_bus:74]: [default] [telegram(telegram)] 王小美 Ganyu (@Ganyu_Genshin)/2112780557: 我是谁? 

[2026-06-27 01:37:13.338] [Core][INFO][respond.stage:183]: Prepare to send - 王小美 Ganyu (@Ganyu_Genshin)/2112780557: [引用消息] 你是 **王小美 Ganyu**(@Ganyu_Genshin)!🌟

从名字来看,你似乎很喜欢《原神》里的 **甘雨**(Ganyu)对吧?是个很有品位的选择呢~😊

请问有什么我可以帮你的吗? 

引用模式测试:

图片

WebUI 下拉渲染:
机器人>Telegram>编辑的配置页出现「Telegram 回复时引用消息」下拉框,选项显示「关闭 / 仅私聊 / 仅群聊 / 私聊和群聊」。

图片

我已通过ruff执行格式与代码检查

图片

Checklist / 检查清单

  • 😊 If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
    / 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。

  • 👀 My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
    / 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”

  • 🤓 I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in requirements.txt and pyproject.toml.
    / 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到 requirements.txtpyproject.toml 文件相应位置。

  • 😮 My changes do not introduce malicious code.
    / 我的更改没有引入恶意代码。

Summary by Sourcery

Add configurable reply behavior and richer sender display names to the Telegram adapter.

New Features:

  • Expose a telegram_reply_to_message configuration option to control when Telegram replies quote the original message (off/private/group/all).

Enhancements:

  • Include both display name and @username when building Telegram sender nicknames, with sensible fallbacks when fields are missing.
  • Honor the telegram_reply_to_message setting in Telegram events so replies can default to referencing the triggering message or omit all quoting, overriding global reply behavior when disabled.
  • Localize the new Telegram reply configuration option in the dashboard i18n metadata for supported languages.

g2nnyS added 3 commits June 26, 2026 23:26
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.
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.
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.
@dosubot dosubot Bot added size:M This PR changes 30-99 lines, ignoring generated files. area:platform The bug / feature is about IM platform adapter, such as QQ, Lark, Telegram, WebChat and so on. area:webui The bug / feature is about webui(dashboard) of astrbot. labels Jun 26, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • The reply_to_message setting is passed around as raw string literals ("off", "private", "group", "all"); consider centralizing these as constants or an enum-like structure and validating the config on load to avoid typos and make future changes safer.
  • In TelegramPlatformEvent.send, mutating message.chain in-place to strip Reply components couples this behavior tightly to Telegram; you might consider doing this on a cloned MessageChain or in a small helper to make side effects clearer and avoid surprising other platform-specific logic that reuses the same instance.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `reply_to_message` setting is passed around as raw string literals (`"off"`, `"private"`, `"group"`, `"all"`); consider centralizing these as constants or an enum-like structure and validating the config on load to avoid typos and make future changes safer.
- In `TelegramPlatformEvent.send`, mutating `message.chain` in-place to strip `Reply` components couples this behavior tightly to Telegram; you might consider doing this on a cloned `MessageChain` or in a small helper to make side effects clearer and avoid surprising other platform-specific logic that reuses the same instance.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new configuration option telegram_reply_to_message allowing users to configure whether the Telegram bot quotes the triggering message in replies (with options for off, private, group, or all). It also refactors how sender nicknames are constructed by combining display names and usernames. The review feedback points out a potential issue in unit tests where unconfigured MagicMock attributes for user names could cause TypeError or leak mock strings, and suggests adding defensive type checks.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +490 to +496
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"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

在单元测试中,_from_user 经常会被 Mock 为 MagicMock 对象。如果未显式为 Mock 对象设置 first_namelast_nameusername,直接访问它们会返回新的 MagicMock 实例(其布尔值为 True)。这会导致 " ".join(...) 尝试拼接 MagicMock 对象而抛出 TypeError,或者在 nickname 中泄露 Mock 对象的字符串表示。

建议使用 isinstance(part, str) 进行防御性类型检查,以确保代码在测试和各种边界情况下都能鲁棒运行。

        display_name = " ".join(
            part for part in (_from_user.first_name, _from_user.last_name) if isinstance(part, str)
        ).strip()
        username = _from_user.username if isinstance(_from_user.username, str) else None
        if display_name and username:
            nickname = f"{display_name} (@{username})"
        else:
            nickname = display_name or username or "Unknown"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:platform The bug / feature is about IM platform adapter, such as QQ, Lark, Telegram, WebChat and so on. area:webui The bug / feature is about webui(dashboard) of astrbot. size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant