From b711425b7347dc0f4e547cf74bf2ef25a1ac2b95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=82=E5=A3=B9?= <137363396+KBVsent@users.noreply.github.com> Date: Mon, 27 Apr 2026 22:21:56 +0900 Subject: [PATCH] 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 --- astrbot/core/message/message_event_result.py | 28 +++++++++++++++++++ astrbot/core/pipeline/respond/stage.py | 8 +++--- .../qqofficial/qqofficial_message_event.py | 20 +++++++++---- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/astrbot/core/message/message_event_result.py b/astrbot/core/message/message_event_result.py index 0965fe7f7..72dc481a2 100644 --- a/astrbot/core/message/message_event_result.py +++ b/astrbot/core/message/message_event_result.py @@ -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 强制 Markdown,False 强制纯文本。 + ) 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 强制使用 Markdown,False 强制纯文本,None 跟随平台默认行为。 + + """ + self.use_markdown_ = use + return self + def get_plain_text(self, with_other_comps_mark: bool = False) -> str: """获取纯文本消息。这个方法将获取 chain 中所有 Plain 组件的文本并拼接成一条消息。空格分隔。 diff --git a/astrbot/core/pipeline/respond/stage.py b/astrbot/core/pipeline/respond/stage.py index aea6a74b3..604f1ded0 100644 --- a/astrbot/core/pipeline/respond/stage.py +++ b/astrbot/core/pipeline/respond/stage.py @@ -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) diff --git a/astrbot/core/platform/sources/qqofficial/qqofficial_message_event.py b/astrbot/core/platform/sources/qqofficial/qqofficial_message_event.py index 59ef6f056..fa10d2876 100644 --- a/astrbot/core/platform/sources/qqofficial/qqofficial_message_event.py +++ b/astrbot/core/platform/sources/qqofficial/qqofficial_message_event.py @@ -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)