Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion astrbot/builtin_stars/astrbot/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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,
Expand Down
79 changes: 79 additions & 0 deletions tests/unit/test_empty_mention_wake_prefix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
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,
):
"""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):
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()
Loading