feat: show quoted message content in group chat context#8634
feat: show quoted message content in group chat context#8634ScarletPupil wants to merge 3 commits into
Conversation
Include Reply component content in _format_message so the LLM can see what message was quoted when someone replies to the bot. - Add Reply import - Handle Reply in _format_message with message_str or chain fallback - Add _describe_chain helper for non-text quoted content (images, etc.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- Consider truncating very long
Replycontents (bothmessage_strand_describe_chainoutput) to avoid excessively inflating the group chat context sent to the LLM. - _describe_chain` largely re-implements formatting logic for message components; you might want to refactor common formatting into a shared helper so normal messages and quoted messages stay consistent as new component types are added.
- The reply descriptions mix English markers like
[At: ...]with Chinese markers like[图片]and[语音]; it may be worth standardizing the language and format of these tags to keep the context output consistent.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Consider truncating very long `Reply` contents (both `message_str` and `_describe_chain` output) to avoid excessively inflating the group chat context sent to the LLM.
- _describe_chain` largely re-implements formatting logic for message components; you might want to refactor common formatting into a shared helper so normal messages and quoted messages stay consistent as new component types are added.
- The reply descriptions mix English markers like `[At: ...]` with Chinese markers like `[图片]` and `[语音]`; it may be worth standardizing the language and format of these tags to keep the context output consistent.
## Individual Comments
### Comment 1
<location path="astrbot/builtin_stars/astrbot/group_chat_context.py" line_range="236-237" />
<code_context>
+def _describe_chain(chain: list) -> str:
+ """简要描述消息链内容,用于引用消息的展示"""
+ desc = []
+ for c in chain:
+ cls_name = c.__class__.__name__
+ if cls_name == "Plain" and getattr(c, "text", None):
+ desc.append(c.text)
</code_context>
<issue_to_address>
**suggestion:** Using class-name string checks may be brittle; consider `isinstance` against the concrete types instead.
This approach will fail silently if class names change due to refactors, subclassing, or alternative implementations. If the concrete types are available (e.g. `Plain`, `Image`, `At`), preferring `isinstance(c, Plain)` etc. makes the check more stable without changing behavior.
Suggested implementation:
```python
def _describe_chain(chain: list) -> str:
"""简要描述消息链内容,用于引用消息的展示"""
desc = []
for c in chain:
if isinstance(c, Plain) and getattr(c, "text", None):
desc.append(c.text)
elif isinstance(c, Image):
desc.append("[图片]")
elif isinstance(c, At):
name = getattr(c, "name", "") or getattr(c, "qq", "")
desc.append(f"[At: {name}]")
elif isinstance(c, Record):
desc.append("[语音]")
elif isinstance(c, Video):
desc.append("[视频]")
elif isinstance(c, File):
```
If `Plain`, `Image`, `At`, `Record`, `Video`, and `File` are not already imported in this module, add the appropriate imports (e.g. from the library providing the message segment types) at the top of `group_chat_context.py`. Keep the import style consistent with how other message element types are imported elsewhere in the file or codebase.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Code Review
This pull request introduces support for formatting replied messages in group chat contexts by handling the Reply component. The reviewer suggested reusing the existing _outline_chain method from AstrMessageEvent instead of introducing a new _describe_chain helper function to avoid code duplication and ensure consistent formatting across the application.
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.
| elif isinstance(comp, Reply): | ||
| if comp.message_str: | ||
| parts.append( | ||
| f" [引用消息({comp.sender_nickname}: {comp.message_str})]" | ||
| ) | ||
| elif comp.chain: | ||
| chain_desc = _describe_chain(comp.chain) | ||
| parts.append( | ||
| f" [引用消息({comp.sender_nickname}: {chain_desc})]" | ||
| ) | ||
| else: | ||
| parts.append(" [引用消息]") | ||
|
|
||
| return "".join(parts) | ||
|
|
||
|
|
||
| def _describe_chain(chain: list) -> str: | ||
| """简要描述消息链内容,用于引用消息的展示""" | ||
| desc = [] | ||
| for c in chain: | ||
| cls_name = c.__class__.__name__ | ||
| if cls_name == "Plain" and getattr(c, "text", None): | ||
| desc.append(c.text) | ||
| elif cls_name == "Image": | ||
| desc.append("[图片]") | ||
| elif cls_name == "At": | ||
| name = getattr(c, "name", "") or getattr(c, "qq", "") | ||
| desc.append(f"[At: {name}]") | ||
| elif cls_name == "Record": | ||
| desc.append("[语音]") | ||
| elif cls_name == "Video": | ||
| desc.append("[视频]") | ||
| elif cls_name == "File": | ||
| desc.append(f"[文件: {getattr(c, 'name', '') or ''}]") | ||
| else: | ||
| desc.append(f"[{cls_name}]") | ||
| return "".join(desc) or "[未知内容]" |
There was a problem hiding this comment.
为了避免代码重复并保持消息格式化逻辑的一致性,建议直接复用 AstrMessageEvent 中已有的 _outline_chain 方法来描述引用消息链的内容。这样可以完全省去新增的 _describe_chain 辅助函数,并确保所有消息组件(如 Face、AtAll、Forward 等)的展示格式在整个应用中保持一致。
| elif isinstance(comp, Reply): | |
| if comp.message_str: | |
| parts.append( | |
| f" [引用消息({comp.sender_nickname}: {comp.message_str})]" | |
| ) | |
| elif comp.chain: | |
| chain_desc = _describe_chain(comp.chain) | |
| parts.append( | |
| f" [引用消息({comp.sender_nickname}: {chain_desc})]" | |
| ) | |
| else: | |
| parts.append(" [引用消息]") | |
| return "".join(parts) | |
| def _describe_chain(chain: list) -> str: | |
| """简要描述消息链内容,用于引用消息的展示""" | |
| desc = [] | |
| for c in chain: | |
| cls_name = c.__class__.__name__ | |
| if cls_name == "Plain" and getattr(c, "text", None): | |
| desc.append(c.text) | |
| elif cls_name == "Image": | |
| desc.append("[图片]") | |
| elif cls_name == "At": | |
| name = getattr(c, "name", "") or getattr(c, "qq", "") | |
| desc.append(f"[At: {name}]") | |
| elif cls_name == "Record": | |
| desc.append("[语音]") | |
| elif cls_name == "Video": | |
| desc.append("[视频]") | |
| elif cls_name == "File": | |
| desc.append(f"[文件: {getattr(c, 'name', '') or ''}]") | |
| else: | |
| desc.append(f"[{cls_name}]") | |
| return "".join(desc) or "[未知内容]" | |
| elif isinstance(comp, Reply): | |
| if comp.message_str: | |
| parts.append( | |
| f" [引用消息({comp.sender_nickname}: {comp.message_str})]" | |
| ) | |
| elif comp.chain: | |
| chain_desc = event._outline_chain(comp.chain).strip() | |
| parts.append( | |
| f" [引用消息({comp.sender_nickname}: {chain_desc})]" | |
| ) | |
| else: | |
| parts.append(" [引用消息]") | |
| return "".join(parts) |
References
- When implementing similar functionality for different cases (e.g., direct vs. quoted attachments), refactor the logic into a shared helper function to avoid code duplication.
- Replace string class-name checks with isinstance() for robustness - Add _truncate_reply_text to prevent long quoted content inflating context - Unify markers to English ([Image], [Voice], [Quote] etc.) - Import Record, Video, File for isinstance checks Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Include Reply component content in _format_message so the LLM can see what message was quoted when someone replies to the bot.
Problem
群聊中,当有人引用(Reply)机器人的消息时,
group_chat_context.py的_format_message()方法只处理 Plain、Image、At 三种消息段,跳过了 Reply。虽然 Reply 组件通过 OneBot API 已经拿到了被引用消息的完整信息(sender_nickname、message_str、chain等),但这些内容没有传递给 LLM。结果:LLM 知道有人回复了我,但不知道被引用的消息具体说了什么。
Solution
在
_format_message中新增 Reply 消息段的处理:[引用消息(发送者: 文本内容)]_describe_chain()辅助函数描述引用内容Before:
After:
Modifications
仅修改一个文件:
astrbot/builtin_stars/astrbot/group_chat_context.pyReply_format_message(): 新增elif isinstance(comp, Reply)分支_describe_chain()辅助函数Test Results
Summary by Sourcery
Include quoted reply message content in formatted group chat context so the LLM can see what was replied to.
New Features:
Enhancements: