feat: add message-level markdown control for QQ Official platform (#6980)

* feat: add message-level markdown control for QQ Official platform

* feat: propagate MessageChain metadata through RespondStage chain splitting
This commit is contained in:
時壹
2026-04-27 22:21:56 +09:00
committed by GitHub
parent 72f4e748e8
commit b711425b73
3 changed files with 46 additions and 10 deletions

View File

@@ -27,9 +27,25 @@ class MessageChain:
chain: list[BaseMessageComponent] = field(default_factory=list)
use_t2i_: bool | None = None # None 为跟随用户设置
use_markdown_: bool | None = (
None # 是否使用 Markdown 发送消息。None 跟随平台默认True 强制 MarkdownFalse 强制纯文本。
)
type: str | None = None
"""消息链承载的消息的类型。可选,用于让消息平台区分不同业务场景的消息链。"""
def derive(self, chain: list[BaseMessageComponent] | None = None) -> "MessageChain":
"""基于当前消息链创建一个新的 MessageChain继承元数据use_t2i_、use_markdown_ 等)。
Args:
chain: 新消息链的组件列表。如果为 None则使用空列表。
"""
new = MessageChain(chain=chain if chain is not None else [])
new.use_t2i_ = self.use_t2i_
new.use_markdown_ = self.use_markdown_
new.type = self.type
return new
def message(self, message: str):
"""添加一条文本消息到消息链 `chain` 中。
@@ -118,6 +134,18 @@ class MessageChain:
self.use_t2i_ = use_t2i
return self
def use_markdown(self, use: bool | None = True):
"""设置是否使用 Markdown 发送消息。
仅对支持 Markdown 的平台生效(如 QQ Official不支持的平台会忽略此字段。
Args:
use: True 强制使用 MarkdownFalse 强制纯文本None 跟随平台默认行为。
"""
self.use_markdown_ = use
return self
def get_plain_text(self, with_other_comps_mark: bool = False) -> str:
"""获取纯文本消息。这个方法将获取 chain 中所有 Plain 组件的文本并拼接成一条消息。空格分隔。

View File

@@ -246,9 +246,9 @@ class RespondStage(Stage):
await asyncio.sleep(i)
try:
if comp.type in need_separately:
await event.send(MessageChain([comp]))
await event.send(result.derive([comp]))
else:
await event.send(MessageChain([*header_comps, comp]))
await event.send(result.derive([*header_comps, comp]))
header_comps.clear()
except Exception as e:
logger.error(
@@ -271,7 +271,7 @@ class RespondStage(Stage):
modify_raw_chain=True,
)
for comp in sep_comps:
chain = MessageChain([comp])
chain = result.derive([comp])
try:
await event.send(chain)
except Exception as e:
@@ -279,7 +279,7 @@ class RespondStage(Stage):
f"发送消息链失败: chain = {chain}, error = {e}",
exc_info=True,
)
chain = MessageChain(result.chain)
chain = result.derive(result.chain)
if result.chain and len(result.chain) > 0:
try:
await event.send(chain)

View File

@@ -235,12 +235,20 @@ class QQOfficialMessageEvent(AstrMessageEvent):
):
plain_text = plain_text + "\n"
payload: dict = {
# "content": plain_text,
"markdown": MarkdownPayload(content=plain_text) if plain_text else None,
"msg_type": 2,
"msg_id": self.message_obj.message_id,
}
# 根据消息链的 use_markdown_ 标记决定发送模式
use_md = getattr(self.send_buffer, "use_markdown_", None)
if use_md is False:
payload: dict = {
"content": plain_text,
"msg_type": 0,
"msg_id": self.message_obj.message_id,
}
else:
payload = {
"markdown": MarkdownPayload(content=plain_text) if plain_text else None,
"msg_type": 2,
"msg_id": self.message_obj.message_id,
}
if not isinstance(source, botpy.message.Message | botpy.message.DirectMessage):
payload["msg_seq"] = random.randint(1, 10000)