-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
feat: 分离指令前缀与唤醒词,支持独立配置 #8201
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
feat: 分离指令前缀与唤醒词,支持独立配置 #8201
Changes from all commits
0a62ce0
62e2317
60e3c82
92ad571
1594579
01baad2
cab3e05
46e0698
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -5,6 +5,7 @@ | |||||
| from astrbot.core.message.message_event_result import MessageChain, MessageEventResult | ||||||
| from astrbot.core.platform.astr_message_event import AstrMessageEvent | ||||||
| from astrbot.core.platform.message_type import MessageType | ||||||
| from astrbot.core.star.filter.command import CommandFilter | ||||||
| from astrbot.core.star.filter.command_group import CommandGroupFilter | ||||||
| from astrbot.core.star.filter.permission import PermissionTypeFilter | ||||||
| from astrbot.core.star.session_plugin_manager import SessionPluginManager | ||||||
|
|
@@ -38,7 +39,8 @@ class WakingCheckStage(Stage): | |||||
|
|
||||||
| 1. 机器人被 @ 了 | ||||||
| 2. 机器人的消息被提到了 | ||||||
| 3. 以 wake_prefix 前缀开头,并且消息没有以 At 消息段开头 | ||||||
| 3. 以 command_prefix 指令前缀开头(只触发指令),或以 wake_prefix 唤醒词开头(触发 LLM), | ||||||
| 且消息没有以 At 消息段开头 | ||||||
| 4. 插件(Star)的 handler filter 通过 | ||||||
| 5. 私聊情况下,位于 admins_id 列表中的管理员的消息(在白名单阶段中) | ||||||
| """ | ||||||
|
|
@@ -73,6 +75,8 @@ async def initialize(self, ctx: PipelineContext) -> None: | |||||
| ) | ||||||
| platform_settings = self.ctx.astrbot_config.get("platform_settings", {}) | ||||||
| self.unique_session = platform_settings.get("unique_session", False) | ||||||
| # 以下配置在 process() 中每次读取以支持热更新,此处仅作初始化说明 | ||||||
| # wake_prefix, command_prefix, ignore_unknown_prefix_command 通过 self.ctx.astrbot_config 热读取 | ||||||
|
|
||||||
| async def process( | ||||||
| self, | ||||||
|
|
@@ -100,24 +104,58 @@ async def process( | |||||
| break | ||||||
|
|
||||||
| # 检查 wake | ||||||
| # command_prefix 用于匹配指令前缀,与唤醒词(wake_prefix)分开配置。 | ||||||
| # 启动时 check_config_integrity 保证 command_prefix 已有默认值,不会为 None。 | ||||||
| wake_prefixes = self.ctx.astrbot_config["wake_prefix"] | ||||||
| command_prefixes = self.ctx.astrbot_config.get("command_prefix", wake_prefixes) | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The retrieval of
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 启动时会将None替换为默认值,运行时不会出现None。 |
||||||
| messages = event.get_messages() | ||||||
| is_wake = False | ||||||
| for wake_prefix in wake_prefixes: | ||||||
| if event.message_str.startswith(wake_prefix): | ||||||
| if ( | ||||||
| not event.is_private_chat() | ||||||
| and isinstance(messages[0], At) | ||||||
| and str(messages[0].qq) != str(event.get_self_id()) | ||||||
| and str(messages[0].qq) != "all" | ||||||
| ): | ||||||
| # 如果是群聊,且第一个消息段是 At 消息,但不是 At 机器人或 At 全体成员,则不唤醒 | ||||||
|
|
||||||
| # 提取公共的 At 检查逻辑:群聊中首个消息段是 At 他人(非机器人/全体)时不唤醒 | ||||||
|
sourcery-ai[bot] marked this conversation as resolved.
|
||||||
| is_at_others = ( | ||||||
| messages | ||||||
| and not event.is_private_chat() | ||||||
| and isinstance(messages[0], At) | ||||||
| and str(messages[0].qq) != str(event.get_self_id()) | ||||||
| and str(messages[0].qq) != "all" | ||||||
| ) | ||||||
| # 预计算前缀差异标记:command_prefix 非空且与 wake_prefix 不同时,唤醒词只触发 LLM。 | ||||||
| # command_prefix=[] 时不标记,避免唤醒词触发的指令全部失效。 | ||||||
| is_different_prefixes = bool( | ||||||
| command_prefixes and set(command_prefixes) != set(wake_prefixes) | ||||||
| ) | ||||||
|
|
||||||
| # 先检查是否以指令前缀开头(只匹配指令,不触发 LLM 闲聊) | ||||||
| # command_prefix 与 wake_prefix 相同时,行为与原版一致。 | ||||||
| # command_prefix 与 wake_prefix 不同时,指令前缀只触发指令,唤醒词只触发 LLM。 | ||||||
| is_command_prefix_triggered = False | ||||||
| for cmd_prefix in command_prefixes: | ||||||
| if cmd_prefix and event.message_str.startswith(cmd_prefix): | ||||||
| if is_at_others: | ||||||
| break | ||||||
| is_command_prefix_triggered = True | ||||||
| event.message_str = event.message_str[len(cmd_prefix) :].strip() | ||||||
| is_wake = True | ||||||
| event.is_at_or_wake_command = True | ||||||
| event.is_wake = True | ||||||
| event.message_str = event.message_str[len(wake_prefix) :].strip() | ||||||
| event.is_at_or_wake_command = True | ||||||
| break | ||||||
|
|
||||||
| # 再检查是否以唤醒词开头(触发 LLM 对话) | ||||||
| # 若 command_prefix 与 wake_prefix 不同(分开配置),唤醒词分支不触发指令匹配, | ||||||
| # 只触发 LLM,CommandFilter 会通过 matched_wake_prefix_only 标记跳过指令检查。 | ||||||
| if not is_wake: | ||||||
| for wake_prefix in wake_prefixes: | ||||||
| if wake_prefix and event.message_str.startswith(wake_prefix): | ||||||
| if is_at_others: | ||||||
| # 如果是群聊,且第一个消息段是 At 消息,但不是 At 机器人或 At 全体成员,则不唤醒 | ||||||
| break | ||||||
| is_wake = True | ||||||
| event.is_wake = True | ||||||
| event.is_at_or_wake_command = True | ||||||
| event.message_str = event.message_str[len(wake_prefix) :].strip() | ||||||
| if is_different_prefixes: | ||||||
| event.set_extra("matched_wake_prefix_only", True) | ||||||
| break | ||||||
|
lingyun14beta marked this conversation as resolved.
|
||||||
| if not is_wake: | ||||||
| # 检查是否有at消息 / at全体成员消息 / 引用了bot的消息 | ||||||
| for message in messages: | ||||||
|
|
@@ -234,5 +272,25 @@ async def process( | |||||
| event.set_extra("activated_handlers", activated_handlers) | ||||||
| event.set_extra("handlers_parsed_params", handlers_parsed_params) | ||||||
|
|
||||||
| # 若消息以指令前缀开头,但没有任何「带 CommandFilter 的指令 handler」命中, | ||||||
| # 且 ignore_unknown_prefix_command=True,则静默忽略,不触发 LLM。 | ||||||
| # 默认 False(保持原版行为);设为 True 后可避免误响应其他机器人的指令(如 /grok)。 | ||||||
| # 注意:部分 handler(如 on_message)没有 CommandFilter,不算指令 handler。 | ||||||
| ignore_unknown = self.ctx.astrbot_config.get("platform_settings", {}).get( | ||||||
| "ignore_unknown_prefix_command", False | ||||||
| ) | ||||||
| if is_command_prefix_triggered and ignore_unknown: | ||||||
| # 检查是否有真正的指令 handler 被激活(含 CommandFilter 或 CommandGroupFilter) | ||||||
| has_command_handler = any( | ||||||
| any( | ||||||
| isinstance(f, (CommandFilter, CommandGroupFilter)) | ||||||
| for f in handler.event_filters | ||||||
| ) | ||||||
|
sourcery-ai[bot] marked this conversation as resolved.
|
||||||
| for handler in activated_handlers | ||||||
| ) | ||||||
| if not has_command_handler: | ||||||
| event.stop_event() | ||||||
| return | ||||||
|
|
||||||
| if not is_wake: | ||||||
| event.stop_event() | ||||||
Uh oh!
There was an error while loading. Please reload this page.