X Tutup
Skip to content

fix:Mobile QQ triggers empty messages that get sent to LLM#5797

Open
gangcaiyoule wants to merge 1 commit intoAstrBotDevs:masterfrom
gangcaiyoule:master
Open

fix:Mobile QQ triggers empty messages that get sent to LLM#5797
gangcaiyoule wants to merge 1 commit intoAstrBotDevs:masterfrom
gangcaiyoule:master

Conversation

@gangcaiyoule
Copy link

@gangcaiyoule gangcaiyoule commented Mar 6, 2026

Mobile QQ sends an empty notice event (e.g. input status change) when the user taps the input box and then leaves the chat page. The aiocqhttp adapter did not filter out these empty notice events, causing them to enter the pipeline and get forwarded to the LLM as blank user messages.

手机 QQ 在用户点击输入框后离开聊天页面时,会发送一个空的 notice 事件(如输入状态变化通知)。aiocqhttp 适配器未过滤这些空通知事件,导致它们进入消息流水线并作为空白用户消息被转发给 LLM。

Modifications / 改动点

File: astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py

  1. _convert_handle_notice_event (core fix): Added a check at the end of the method — if no meaningful message component (e.g. Poke) was produced from the notice event, return None to prevent it from entering the pipeline. Updated return type annotation to AstrBotMessage | None.
  2. convert_message (defensive): Added None check for _convert_handle_message_event return value before accessing abm.sender.user_id.

  1. _convert_handle_notice_event(核心修复):在方法末尾增加判断,若通知事件未产生任何有意义的消息组件(如 Poke),则返回 None,阻止其进入流水线。同时更新返回类型注解为 AstrBotMessage | None
  2. convert_message(防御性措施):对 _convert_handle_message_event 的返回值增加 None 检查,防止访问 abm.sender.user_id 时出现异常。
  • This is NOT a breaking change. / 这不是一个破坏性变更。

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

Before fix / 修复前:

[2026-03-06 15:38:17.743] [Core] [INFO] [respond.stage:184]: Prepare to send - LLLL/964389211: 哈? 我一直活着! 你才要确认活着没! 别老问我这种废话…… [图片] 
[2026-03-06 15:41:47.405] [Core] [INFO] [routes.config:214]: Saving config, is_core=True
[2026-03-06 15:41:47.407] [Core] [INFO] [respond.stage:89]: 分段回复间隔时间:[1.5, 3.5]
[2026-03-06 15:49:59.923] [Core] [INFO] [core.event_bus:59]: [default] [test(aiocqhttp)] 964389211/964389211: 
[2026-03-06 15:50:08.156] [Core] [INFO] [core.event_bus:59]: [default] [test(aiocqhttp)] 964389211/964389211: 

Tapping the input box on mobile QQ and leaving the chat page produced empty messages that were sent to the LLM.

在手机 QQ 点击输入框后离开聊天页面,会产生空消息并被发送给 LLM。

After fix / 修复后:

Tapping the input box on mobile QQ and leaving the chat page no longer produces empty message logs. Normal messages are unaffected.

修复后,在手机 QQ 点击输入框后离开聊天页面不再产生空消息日志,正常消息不受影响。

Checklist / 检查清单

  • 👀 我的更改经过了良好的测试,并已在上方提供了"验证步骤"和"运行截图"。/ My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
  • 🤓 我确保没有引入新依赖库。/ I have ensured that no new dependencies are introduced.
  • 😮 我的更改没有引入恶意代码。/ My changes do not introduce malicious code.

Summary by Sourcery

防止空的 aiocqhttp 通知事件被转换为用户消息,并强化消息转换的处理逻辑。

Bug 修复:

  • 忽略不会产生有意义消息内容的通知事件,从而避免移动端 QQ 输入状态通知再生成发送给 LLM 的空消息。

增强:

  • 为已转换的消息事件添加防御性 None 检查,并在 aiocqhttp 适配器中调整戳一戳(poke)通知消息的构造方式。
Original summary in English

Summary by Sourcery

Prevent empty aiocqhttp notice events from being converted into user messages and harden message conversion handling.

Bug Fixes:

  • Ignore notice events that do not produce meaningful message content so that mobile QQ input-status notices no longer generate empty messages sent to the LLM.

Enhancements:

  • Add a defensive None check for converted message events and adjust poke notice message construction in the aiocqhttp adapter.

@dosubot dosubot bot added the size:S This PR changes 10-29 lines, ignoring generated files. label Mar 6, 2026
@auto-assign auto-assign bot requested review from Soulter and advent259141 March 6, 2026 09:32
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses an issue where Mobile QQ's empty notice events were being processed as blank user messages and forwarded to the LLM. The changes introduce robust filtering for these non-meaningful events, ensuring that only relevant messages proceed through the pipeline. This prevents unnecessary processing by the LLM and cleans up log outputs, improving system efficiency and accuracy.

Highlights

  • Empty Notice Event Filtering: Implemented a mechanism in _convert_handle_notice_event to filter out and return None for notice events that do not contain any meaningful message components, such as those generated by Mobile QQ when a user taps the input box and leaves the chat page.
  • Defensive None Check: Added a defensive None check in the convert_message method for the return value of _convert_handle_message_event to prevent potential errors when accessing abm.sender.user_id if _convert_handle_message_event were to return None.
  • Type Annotation Update: Updated the return type annotation for _convert_handle_notice_event to AstrBotMessage | None to reflect its new behavior of potentially returning None.
  • Poke Object Instantiation: Modified the instantiation of the Poke object within _convert_handle_notice_event to include qq and type arguments, aligning with updated Poke object requirements.
Changelog
  • astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py
    • Added a None check for the return value of _convert_handle_message_event in convert_message.
    • Updated the return type annotation of _convert_handle_notice_event to AstrBotMessage | None.
    • Modified the Poke object instantiation to include qq and type parameters.
    • Implemented logic to return None from _convert_handle_notice_event if no meaningful message content is produced, effectively filtering empty notice events.
Activity
  • The author, gangcaiyoule, has provided a detailed description of the problem, the modifications made, and before/after screenshots demonstrating the fix.
  • The author has confirmed that this is not a breaking change, no new dependencies were introduced, and no malicious code was added.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

你好,我在这里给出了一些整体性的反馈:

  • 由于 _convert_handle_notice_event 现在可能返回 Noneconvert_message 应当仿照你为 _convert_handle_message_event 添加的防御性检查:当得到 None 的 notice 结果时应直接短路返回,而不是继续向下传递并当作 AstrBotMessage 来处理(这样也能保证 convert_message 以及其调用处的类型标注保持准确)。
  • 当前对被忽略的 notice 事件的调试日志会直接输出整个 event 对象;建议只记录关键字段(例如 post_typenotice_typesub_type),以避免日志过于冗长,并减少潜在敏感载荷信息泄露的风险。
给 AI Agent 的提示词
Please address the comments from this code review:

## Overall Comments
- Since `_convert_handle_notice_event` can now return `None`, `convert_message` should mirror the defensive check you added for `_convert_handle_message_event`, so that a `None` notice result is short-circuited instead of being passed along as if it were an `AstrBotMessage` (and the type hints on `convert_message`/call sites stay accurate).
- The debug log for ignored notice events currently dumps the entire `event` object; consider logging only key fields (e.g. `post_type`, `notice_type`, `sub_type`) to avoid overly verbose logs and leaking potentially sensitive payload details.

Sourcery 对开源项目免费——如果你觉得我们的评审对你有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续的代码评审。
Original comment in English

Hey - I've left some high level feedback:

  • Since _convert_handle_notice_event can now return None, convert_message should mirror the defensive check you added for _convert_handle_message_event, so that a None notice result is short-circuited instead of being passed along as if it were an AstrBotMessage (and the type hints on convert_message/call sites stay accurate).
  • The debug log for ignored notice events currently dumps the entire event object; consider logging only key fields (e.g. post_type, notice_type, sub_type) to avoid overly verbose logs and leaking potentially sensitive payload details.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Since `_convert_handle_notice_event` can now return `None`, `convert_message` should mirror the defensive check you added for `_convert_handle_message_event`, so that a `None` notice result is short-circuited instead of being passed along as if it were an `AstrBotMessage` (and the type hints on `convert_message`/call sites stay accurate).
- The debug log for ignored notice events currently dumps the entire `event` object; consider logging only key fields (e.g. `post_type`, `notice_type`, `sub_type`) to avoid overly verbose logs and leaking potentially sensitive payload details.

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.

@dosubot dosubot bot added the area:platform The bug / feature is about IM platform adapter, such as QQ, Lark, Telegram, WebChat and so on. label Mar 6, 2026
Copy link
Contributor

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

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 effectively addresses the issue of empty notice events from Mobile QQ being processed as user messages. The core fix in _convert_handle_notice_event to check for meaningful message content before proceeding is well-implemented and correctly filters out the unwanted events. The accompanying type hint update and adjustment to Poke message construction are also good improvements.

I have one minor point of feedback on a defensive check added in convert_message, which appears to be inconsistent with the called function's signature, potentially leading to confusion.

Comment on lines +133 to +134
if abm is None:
return None
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This check for None appears to be unreachable. The _convert_handle_message_event function is type-hinted to return AstrBotMessage and its implementation does not have a code path that returns None. This makes the check inconsistent with the function's current contract and could be confusing. If _convert_handle_message_event is not intended to return None, this check could be removed to avoid dead code.

if "sub_type" in event:
if event["sub_type"] == "poke" and "target_id" in event:
abm.message.append(Poke(id=str(event["target_id"])))
abm.message.append(Poke(qq=str(event["target_id"]), type="poke"))
Copy link
Member

Choose a reason for hiding this comment

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

#5773 给出的改动是用 id 来代替 qq @gangcaiyoule

Copy link
Author

Choose a reason for hiding this comment

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

已修复。已 rebase 到 upstream/master,Poke 构造保持 #5773 的 Poke(id=...) 不变,本 PR 不再改动这行

Copy link
Author

Choose a reason for hiding this comment

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

这部分推送的代码还做了如下修复:过滤 aiocqhttp 适配器中的空消息事件

问题

在某些操作(如 skill 调用发送文件)完成后,部分 QQ 协议端(NapCat、Lagrange 等)会推送一条
post_type 为 "message" 但 message 为空数组、raw_message 为空字符串的幽灵消息事件。
该空消息会进入 pipeline,在私聊场景下触发 LLM 回复,询问用户为什么发了空白消息——但用户实际上并没有发送任何消息。

原因

_convert_handle_message_event 在返回前没有检查解析后的消息是否为空。
同类方法 _convert_handle_notice_event 已经有对应的空消息过滤逻辑,但 _convert_handle_message_event 缺少这一检查。

修复

  • _convert_handle_message_event 末尾增加空消息检查:当 abm.message 为空且 message_str 为空白时,
    记录 debug 日志并返回 None,阻止空消息进入 pipeline。
  • 将返回类型注解从 AstrBotMessage 更新为 AstrBotMessage | None 以匹配新逻辑。
    调用方 convert_message 已正确处理 None 返回值。

改动文件

  • astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py

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. size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

X Tutup