mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-15 17:30:13 +08:00
feat: show quoted message content in group chat context
* feat: show quoted message content in group chat context 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> * fix: use isinstance, add truncation, unify language to English - 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> * fix: add Forward, AtAll, Face to _describe_chain for completeness Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * style: format group chat context --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Soulter <905617992@qq.com>
This commit is contained in:
@@ -7,7 +7,18 @@ from collections import defaultdict, deque
|
||||
from astrbot import logger
|
||||
from astrbot.api import star
|
||||
from astrbot.api.event import AstrMessageEvent
|
||||
from astrbot.api.message_components import At, Image, Plain
|
||||
from astrbot.api.message_components import (
|
||||
At,
|
||||
AtAll,
|
||||
Face,
|
||||
File,
|
||||
Forward,
|
||||
Image,
|
||||
Plain,
|
||||
Record,
|
||||
Reply,
|
||||
Video,
|
||||
)
|
||||
from astrbot.api.platform import MessageType
|
||||
from astrbot.api.provider import Provider, ProviderRequest
|
||||
from astrbot.core.agent.message import TextPart
|
||||
@@ -214,10 +225,60 @@ class GroupChatContext:
|
||||
if is_at_self:
|
||||
parts.insert(1, "⚠️[DIRECTED AT YOU] ")
|
||||
parts.append(f" [At: {comp.name}]")
|
||||
elif isinstance(comp, Reply):
|
||||
if comp.message_str:
|
||||
parts.append(
|
||||
f" [Quote({comp.sender_nickname}: {_truncate_reply_text(comp.message_str)})]"
|
||||
)
|
||||
elif comp.chain:
|
||||
chain_desc = _describe_chain(comp.chain)
|
||||
parts.append(f" [Quote({comp.sender_nickname}: {chain_desc})]")
|
||||
else:
|
||||
parts.append(" [Quote]")
|
||||
|
||||
return "".join(parts)
|
||||
|
||||
|
||||
_MAX_REPLY_TEXT_LENGTH = 200
|
||||
|
||||
|
||||
def _describe_chain(chain: list) -> str:
|
||||
"""Summarize message chain content for quoted reply display."""
|
||||
desc = []
|
||||
for c in chain:
|
||||
if isinstance(c, Plain) and getattr(c, "text", None):
|
||||
desc.append(c.text)
|
||||
elif isinstance(c, Image):
|
||||
desc.append("[Image]")
|
||||
elif isinstance(c, At):
|
||||
name = getattr(c, "name", "") or getattr(c, "qq", "")
|
||||
desc.append(f"[At: {name}]")
|
||||
elif isinstance(c, Record):
|
||||
desc.append("[Voice]")
|
||||
elif isinstance(c, Video):
|
||||
desc.append("[Video]")
|
||||
elif isinstance(c, File):
|
||||
desc.append(f"[File: {getattr(c, 'name', '') or ''}]")
|
||||
elif isinstance(c, Forward):
|
||||
desc.append("[Forward]")
|
||||
elif isinstance(c, AtAll):
|
||||
desc.append("[At: All]")
|
||||
elif isinstance(c, Face):
|
||||
desc.append(f"[Sticker: {getattr(c, 'id', '')}]")
|
||||
elif isinstance(c, Reply):
|
||||
desc.append("[Quote]")
|
||||
else:
|
||||
desc.append(f"[{c.__class__.__name__}]")
|
||||
return "".join(desc) or "[Unknown]"
|
||||
|
||||
|
||||
def _truncate_reply_text(text: str) -> str:
|
||||
"""Truncate overly long quoted reply text."""
|
||||
if len(text) <= _MAX_REPLY_TEXT_LENGTH:
|
||||
return text
|
||||
return text[:_MAX_REPLY_TEXT_LENGTH] + "..."
|
||||
|
||||
|
||||
def _positive_int(value, fallback: int) -> int:
|
||||
try:
|
||||
parsed = int(value)
|
||||
|
||||
Reference in New Issue
Block a user