From 03f0a53310eba53736d714901dcc661e4942cd67 Mon Sep 17 00:00:00 2001 From: wcqqq1214 Date: Tue, 1 Sep 2026 02:29:42 +0800 Subject: [PATCH 1/2] fix: respect LLM wake prefix for empty mentions --- astrbot/builtin_stars/astrbot/main.py | 12 +++- tests/unit/test_empty_mention_wake_prefix.py | 72 ++++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 tests/unit/test_empty_mention_wake_prefix.py diff --git a/astrbot/builtin_stars/astrbot/main.py b/astrbot/builtin_stars/astrbot/main.py index cc2c368a23..ee3ae13a48 100644 --- a/astrbot/builtin_stars/astrbot/main.py +++ b/astrbot/builtin_stars/astrbot/main.py @@ -58,6 +58,13 @@ async def handle_empty_mention(self, event: AstrMessageEvent): cfg = self.context.get_config(umo=event.unified_msg_origin) p_settings = cfg["platform_settings"] wake_prefix = cfg.get("wake_prefix", []) + provider_wake_prefix = cfg.get("provider_settings", {}).get( + "wake_prefix", + "", + ) + for bot_wake_prefix in wake_prefix: + if provider_wake_prefix.startswith(bot_wake_prefix): + provider_wake_prefix = provider_wake_prefix[len(bot_wake_prefix) :] if len(messages) != 1: return @@ -74,7 +81,10 @@ async def handle_empty_mention(self, event: AstrMessageEvent): if not (is_empty_mention or is_wake_prefix_only): return - if p_settings.get("empty_mention_waiting_need_reply", True): + if ( + p_settings.get("empty_mention_waiting_need_reply", True) + and not provider_wake_prefix + ): try: curr_cid = await self.context.conversation_manager.get_curr_conversation_id( event.unified_msg_origin, diff --git a/tests/unit/test_empty_mention_wake_prefix.py b/tests/unit/test_empty_mention_wake_prefix.py new file mode 100644 index 0000000000..052dc8253c --- /dev/null +++ b/tests/unit/test_empty_mention_wake_prefix.py @@ -0,0 +1,72 @@ +from types import SimpleNamespace +from unittest.mock import AsyncMock, MagicMock + +import pytest + +import astrbot.builtin_stars.astrbot.main as main_module +from astrbot.api.message_components import At, Plain + + +@pytest.mark.asyncio +@pytest.mark.parametrize( + ("provider_wake_prefix", "messages", "should_request_llm"), + [ + ("chat", [At(qq="bot")], False), + ("/chat", [At(qq="bot")], False), + ("chat", [Plain(text="/")], False), + ("", [At(qq="bot")], True), + ("/", [At(qq="bot")], True), + ], +) +async def test_empty_mention_reply_respects_provider_wake_prefix( + monkeypatch, + provider_wake_prefix, + messages, + should_request_llm, +): + """Only request an immediate LLM reply when no extra prefix is required.""" + + def skip_waiting(_timeout): + def decorator(_callback): + async def wait(*_args, **_kwargs): + raise TimeoutError + + return wait + + return decorator + + monkeypatch.setattr(main_module, "session_waiter", skip_waiting) + + conversation_manager = SimpleNamespace( + get_curr_conversation_id=AsyncMock(return_value="conversation-id"), + get_conversation=AsyncMock(return_value=None), + ) + main = main_module.Main.__new__(main_module.Main) + main.context = MagicMock() + main.context.conversation_manager = conversation_manager + main.context.get_config.return_value = { + "wake_prefix": ["/"], + "provider_settings": {"wake_prefix": provider_wake_prefix}, + "platform_settings": { + "empty_mention_waiting": True, + "empty_mention_waiting_need_reply": True, + }, + } + + event = MagicMock() + event.unified_msg_origin = "aiocqhttp:GroupMessage:group" + event.get_messages.return_value = messages + event.get_self_id.return_value = "bot" + event.get_platform_id.return_value = "aiocqhttp" + llm_request = object() + event.request_llm.return_value = llm_request + + results = [item async for item in main.handle_empty_mention(event)] + + assert results == ([llm_request] if should_request_llm else []) + if should_request_llm: + event.request_llm.assert_called_once() + conversation_manager.get_curr_conversation_id.assert_awaited_once() + else: + event.request_llm.assert_not_called() + conversation_manager.get_curr_conversation_id.assert_not_awaited() From c3526ca2a6a6d16807bb4c229afa89b4d673036d Mon Sep 17 00:00:00 2001 From: wcqqq1214 Date: Tue, 1 Sep 2026 02:45:27 +0800 Subject: [PATCH 2/2] test: document empty mention test parameters --- tests/unit/test_empty_mention_wake_prefix.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/unit/test_empty_mention_wake_prefix.py b/tests/unit/test_empty_mention_wake_prefix.py index 052dc8253c..99c537bed0 100644 --- a/tests/unit/test_empty_mention_wake_prefix.py +++ b/tests/unit/test_empty_mention_wake_prefix.py @@ -24,7 +24,14 @@ async def test_empty_mention_reply_respects_provider_wake_prefix( messages, should_request_llm, ): - """Only request an immediate LLM reply when no extra prefix is required.""" + """Verify that empty-mention replies respect the additional LLM wake prefix. + + Args: + monkeypatch: Pytest fixture used to replace the 60-second session waiter. + provider_wake_prefix: Additional LLM wake prefix configured for the provider. + messages: Message components passed to the empty-mention handler. + should_request_llm: Whether an immediate LLM request should be produced. + """ def skip_waiting(_timeout): def decorator(_callback):