From dd1995ae0b62e1b48dcbffdfe10d044576e41ba8 Mon Sep 17 00:00:00 2001 From: Alero Date: Wed, 12 Feb 2025 03:05:51 +0800 Subject: [PATCH 01/10] feat: add a way to define custom permission filter. --- astrbot/api/event/filter/__init__.py | 2 ++ astrbot/core/star/filter/permission.py | 10 +++++++++- astrbot/core/star/register/__init__.py | 2 ++ astrbot/core/star/register/star_handler.py | 17 ++++++++++++++++- 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/astrbot/api/event/filter/__init__.py b/astrbot/api/event/filter/__init__.py index 69e884b89..6dffbb4e6 100644 --- a/astrbot/api/event/filter/__init__.py +++ b/astrbot/api/event/filter/__init__.py @@ -5,6 +5,7 @@ from astrbot.core.star.register import ( register_regex as regex, register_platform_adapter_type as platform_adapter_type, register_permission_type as permission_type, + register_custom_permission_type as custom_permission_type, register_on_llm_request as on_llm_request, register_on_llm_response as on_llm_response, register_llm_tool as llm_tool, @@ -28,6 +29,7 @@ __all__ = [ 'PlatformAdapterTypeFilter', 'PlatformAdapterType', 'PermissionTypeFilter', + 'register_custom_permission_type', 'PermissionType', 'on_llm_request', 'llm_tool', diff --git a/astrbot/core/star/filter/permission.py b/astrbot/core/star/filter/permission.py index 5e961aa5b..23d357338 100644 --- a/astrbot/core/star/filter/permission.py +++ b/astrbot/core/star/filter/permission.py @@ -9,7 +9,15 @@ class PermissionType(enum.Flag): ADMIN = enum.auto() MEMBER = enum.auto() -class PermissionTypeFilter(HandlerFilter): +class BasePermissionTypeFilter(HandlerFilter): + def __init__(self, raise_error: bool = True): + self.raise_error = raise_error + + def filter(self, event: AstrMessageEvent, cfg: AstrBotConfig) -> bool: + ''' 一个用于重写的自定义Filter ''' + raise NotImplementedError + +class PermissionTypeFilter(BasePermissionTypeFilter): def __init__(self, permission_type: PermissionType, raise_error: bool = True): self.permission_type = permission_type self.raise_error = raise_error diff --git a/astrbot/core/star/register/__init__.py b/astrbot/core/star/register/__init__.py index 422c87b4c..56f40e0e3 100644 --- a/astrbot/core/star/register/__init__.py +++ b/astrbot/core/star/register/__init__.py @@ -6,6 +6,7 @@ from .star_handler import ( register_platform_adapter_type, register_regex, register_permission_type, + register_custom_permission_type, register_on_llm_request, register_on_llm_response, register_llm_tool, @@ -21,6 +22,7 @@ __all__ = [ 'register_platform_adapter_type', 'register_regex', 'register_permission_type', + 'register_custom_permission_type', 'register_on_llm_request', 'register_on_llm_response', 'register_llm_tool', diff --git a/astrbot/core/star/register/star_handler.py b/astrbot/core/star/register/star_handler.py index 0055ce05b..3263eddbe 100644 --- a/astrbot/core/star/register/star_handler.py +++ b/astrbot/core/star/register/star_handler.py @@ -6,7 +6,7 @@ from ..filter.command import CommandFilter from ..filter.command_group import CommandGroupFilter from ..filter.event_message_type import EventMessageTypeFilter, EventMessageType from ..filter.platform_adapter_type import PlatformAdapterTypeFilter, PlatformAdapterType -from ..filter.permission import PermissionTypeFilter, PermissionType +from ..filter.permission import PermissionTypeFilter, BasePermissionTypeFilter, PermissionType from ..filter.regex import RegexFilter from typing import Awaitable from astrbot.core.provider.func_tool_manager import SUPPORTED_TYPES @@ -156,6 +156,21 @@ def register_permission_type(permission_type: PermissionType, raise_error: bool return decorator +def register_custom_permission_type(cunstom_permission_type_filter: BasePermissionTypeFilter, raise_error: bool = True): + '''注册一个自定义的 PermissionFilter + + Args: + cunstom_permission_type_filter: 一个继承自HandlerFilter + raise_error: 如果没有权限,是否抛出错误到消息平台,并且停止事件传播。默认为 True + ''' + + def decorator(awaitable): + handler_md = get_handler_or_create(awaitable, EventType.AdapterMessageEvent) + handler_md.event_filters.append(cunstom_permission_type_filter()) + return awaitable + + return decorator + def register_on_llm_request(**kwargs): '''当有 LLM 请求时的事件 From c6f037cae2f5cbce3b3352ec59616cd8bfcf3331 Mon Sep 17 00:00:00 2001 From: Alero Date: Wed, 12 Feb 2025 03:25:01 +0800 Subject: [PATCH 02/10] fix: a undefine mistake --- astrbot/api/event/filter/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/astrbot/api/event/filter/__init__.py b/astrbot/api/event/filter/__init__.py index 6dffbb4e6..c53536634 100644 --- a/astrbot/api/event/filter/__init__.py +++ b/astrbot/api/event/filter/__init__.py @@ -29,7 +29,7 @@ __all__ = [ 'PlatformAdapterTypeFilter', 'PlatformAdapterType', 'PermissionTypeFilter', - 'register_custom_permission_type', + 'custom_permission_type', 'PermissionType', 'on_llm_request', 'llm_tool', From d013320bec90117c89e510951abb3951e7c1ecc6 Mon Sep 17 00:00:00 2001 From: Alero Date: Fri, 14 Feb 2025 19:15:19 +0800 Subject: [PATCH 03/10] feat: more powerful CustomFilter --- astrbot/api/event/filter/__init__.py | 4 +- astrbot/core/star/filter/command.py | 12 +++- astrbot/core/star/filter/command_group.py | 14 +++- astrbot/core/star/filter/custom_filter.py | 14 ++++ astrbot/core/star/filter/permission.py | 10 +-- astrbot/core/star/register/__init__.py | 4 +- astrbot/core/star/register/star_handler.py | 78 ++++++++++++++++------ 7 files changed, 101 insertions(+), 35 deletions(-) create mode 100644 astrbot/core/star/filter/custom_filter.py diff --git a/astrbot/api/event/filter/__init__.py b/astrbot/api/event/filter/__init__.py index c53536634..89729219d 100644 --- a/astrbot/api/event/filter/__init__.py +++ b/astrbot/api/event/filter/__init__.py @@ -5,7 +5,7 @@ from astrbot.core.star.register import ( register_regex as regex, register_platform_adapter_type as platform_adapter_type, register_permission_type as permission_type, - register_custom_permission_type as custom_permission_type, + register_custom_filter as custom_filter, register_on_llm_request as on_llm_request, register_on_llm_response as on_llm_response, register_llm_tool as llm_tool, @@ -29,7 +29,7 @@ __all__ = [ 'PlatformAdapterTypeFilter', 'PlatformAdapterType', 'PermissionTypeFilter', - 'custom_permission_type', + 'custom_filter', 'PermissionType', 'on_llm_request', 'llm_tool', diff --git a/astrbot/core/star/filter/command.py b/astrbot/core/star/filter/command.py index 3e1394f38..41fdb61dc 100644 --- a/astrbot/core/star/filter/command.py +++ b/astrbot/core/star/filter/command.py @@ -1,10 +1,12 @@ import re import inspect +from typing import List from . import HandlerFilter from astrbot.core.platform.astr_message_event import AstrMessageEvent from astrbot.core.config import AstrBotConfig from astrbot.core.utils.param_validation_mixin import ParameterValidationMixin +from .custom_filter import CustomFilter from ..star_handler import StarHandlerMetadata # 标准指令受到 wake_prefix 的制约。 @@ -14,6 +16,7 @@ class CommandFilter(HandlerFilter, ParameterValidationMixin): self.command_name = command_name if handler_md: self.init_handler_md(handler_md) + self.custom_filter_list: List[CustomFilter] = [] def print_types(self): result = "" @@ -42,10 +45,17 @@ class CommandFilter(HandlerFilter, ParameterValidationMixin): def get_handler_md(self) -> StarHandlerMetadata: return self.handler_md + def add_custom_filter(self, custom_filter: CustomFilter): + self.custom_filter_list.append(custom_filter) + def filter(self, event: AstrMessageEvent, cfg: AstrBotConfig) -> bool: if not event.is_at_or_wake_command: return False - + + for custom_filter in self.custom_filter_list: + if not custom_filter.filter(event, cfg): + raise ValueError(f"没有执行该指令(组)的权限\n") + if event.get_extra("parsing_command"): message_str = event.get_extra("parsing_command").strip() else: diff --git a/astrbot/core/star/filter/command_group.py b/astrbot/core/star/filter/command_group.py index 0dca9916f..0bb298cca 100644 --- a/astrbot/core/star/filter/command_group.py +++ b/astrbot/core/star/filter/command_group.py @@ -6,6 +6,7 @@ from . import HandlerFilter from .command import CommandFilter from astrbot.core.platform.astr_message_event import AstrMessageEvent from astrbot.core.config import AstrBotConfig +from .custom_filter import CustomFilter from ..star_handler import StarHandlerMetadata # 指令组受到 wake_prefix 的制约。 @@ -13,10 +14,14 @@ class CommandGroupFilter(HandlerFilter): def __init__(self, group_name: str): self.group_name = group_name self.sub_command_filters: List[Union[CommandFilter, CommandGroupFilter]] = [] + self.custom_filter_list: List[CustomFilter] = [] def add_sub_command_filter(self, sub_command_filter: Union[CommandFilter, CommandGroupFilter]): self.sub_command_filters.append(sub_command_filter) - + + def add_custom_filter(self, custom_filter: CustomFilter): + self.custom_filter_list.append(custom_filter) + # 以树的形式打印出来 def print_cmd_tree(self, sub_command_filters: List[Union[CommandFilter, CommandGroupFilter]], prefix: str = "") -> str: result = "" @@ -61,7 +66,12 @@ class CommandGroupFilter(HandlerFilter): # 当前还是指令组 tree = self.group_name + "\n" + self.print_cmd_tree(self.sub_command_filters) raise ValueError(f"指令组 {self.group_name} 未填写完全。这个指令组下有如下指令:\n"+tree) - + + # 判断当前指令组的自定义过滤器 + for custom_filter in self.custom_filter_list: + if not custom_filter.filter(event, cfg): + raise ValueError(f"没有执行该指令(组)的权限\n") + child_command_handler_md = None for sub_filter in self.sub_command_filters: if isinstance(sub_filter, CommandFilter): diff --git a/astrbot/core/star/filter/custom_filter.py b/astrbot/core/star/filter/custom_filter.py new file mode 100644 index 000000000..cfe80099e --- /dev/null +++ b/astrbot/core/star/filter/custom_filter.py @@ -0,0 +1,14 @@ +from abc import abstractmethod + +from . import HandlerFilter +from astrbot.core.platform.astr_message_event import AstrMessageEvent +from astrbot.core.config import AstrBotConfig + +class CustomFilter(HandlerFilter): + def __init__(self, raise_error: bool = True): + self.raise_error = raise_error + + @abstractmethod + def filter(self, event: AstrMessageEvent, cfg: AstrBotConfig) -> bool: + ''' 一个用于重写的自定义Filter ''' + raise NotImplementedError diff --git a/astrbot/core/star/filter/permission.py b/astrbot/core/star/filter/permission.py index 23d357338..5e961aa5b 100644 --- a/astrbot/core/star/filter/permission.py +++ b/astrbot/core/star/filter/permission.py @@ -9,15 +9,7 @@ class PermissionType(enum.Flag): ADMIN = enum.auto() MEMBER = enum.auto() -class BasePermissionTypeFilter(HandlerFilter): - def __init__(self, raise_error: bool = True): - self.raise_error = raise_error - - def filter(self, event: AstrMessageEvent, cfg: AstrBotConfig) -> bool: - ''' 一个用于重写的自定义Filter ''' - raise NotImplementedError - -class PermissionTypeFilter(BasePermissionTypeFilter): +class PermissionTypeFilter(HandlerFilter): def __init__(self, permission_type: PermissionType, raise_error: bool = True): self.permission_type = permission_type self.raise_error = raise_error diff --git a/astrbot/core/star/register/__init__.py b/astrbot/core/star/register/__init__.py index 56f40e0e3..ba51f7ab6 100644 --- a/astrbot/core/star/register/__init__.py +++ b/astrbot/core/star/register/__init__.py @@ -6,7 +6,7 @@ from .star_handler import ( register_platform_adapter_type, register_regex, register_permission_type, - register_custom_permission_type, + register_custom_filter, register_on_llm_request, register_on_llm_response, register_llm_tool, @@ -22,7 +22,7 @@ __all__ = [ 'register_platform_adapter_type', 'register_regex', 'register_permission_type', - 'register_custom_permission_type', + 'register_custom_filter', 'register_on_llm_request', 'register_on_llm_response', 'register_llm_tool', diff --git a/astrbot/core/star/register/star_handler.py b/astrbot/core/star/register/star_handler.py index 7ff0412b8..320915a5c 100644 --- a/astrbot/core/star/register/star_handler.py +++ b/astrbot/core/star/register/star_handler.py @@ -1,14 +1,16 @@ from __future__ import annotations import docstring_parser +import traceback from ..star_handler import star_handlers_registry, StarHandlerMetadata, EventType from ..filter.command import CommandFilter from ..filter.command_group import CommandGroupFilter from ..filter.event_message_type import EventMessageTypeFilter, EventMessageType from ..filter.platform_adapter_type import PlatformAdapterTypeFilter, PlatformAdapterType -from ..filter.permission import PermissionTypeFilter, BasePermissionTypeFilter, PermissionType +from ..filter.permission import PermissionTypeFilter, PermissionType +from ..filter.custom_filter import CustomFilter from ..filter.regex import RegexFilter -from typing import Awaitable +from typing import Awaitable, Union from astrbot.core.provider.func_tool_manager import SUPPORTED_TYPES from astrbot.core.provider.register import llm_tools from astrbot.core import logger @@ -80,6 +82,58 @@ def register_command(command_name: str = None, *args, **kwargs): return decorator +def register_custom_filter(custom_type_filter: CustomFilter, *args, **kwargs): + '''注册一个自定义的 CustomFilter + + Args: + cunstom_permission_type_filter: 在裸指令时为CustomFilter对象 + 在指令组时为父指令的RegisteringCommandable对象,即self或者command_group的返回 + raise_error: 如果没有权限,是否抛出错误到消息平台,并且停止事件传播。默认为 True + ''' + add_to_event_filters = False + raise_error = True + + # 判断是否是指令组,指令组则添加到指令组的CommandGroupFilter对象中在waking_check的时候一起判断 + if isinstance(custom_type_filter, RegisteringCommandable): + # 子指令, 此时函数为RegisteringCommandable对象的方法,首位参数为RegisteringCommandable对象的self。 + parent_rigister_commandable = custom_type_filter + custom_filter = args[0] + if len(args) > 1: + raise_error = args[1] + else: + # 裸指令 + add_to_event_filters = True + custom_filter = custom_type_filter + if args: + raise_error = args[0] + + def decorator(awaitable): + # 裸指令,子指令与指令组的区分,指令组会因为标记跳过wake。 + if not add_to_event_filters and isinstance(awaitable, RegisteringCommandable): + # 指令组,添加到本层的grouphandle中一起判断 + awaitable.parent_group.add_custom_filter(custom_filter(raise_error)) + else: + handler_md = get_handler_or_create(awaitable, EventType.AdapterMessageEvent, **kwargs) + + if not add_to_event_filters and not isinstance(awaitable, RegisteringCommandable): + # 底层子指令 + handle_full_name = get_handler_full_name(awaitable) + command_handle = None + for sub_handle in parent_rigister_commandable.parent_group.sub_command_filters: + # 所有符合fullname一致的子指令handle添加自定义过滤器。 + # 不确定是否会有多个子指令有一样的fullname,比如一个方法添加多个command装饰器? + sub_handle_md = sub_handle.get_handler_md() + if sub_handle_md and sub_handle_md.handler_full_name == handle_full_name: + sub_handle.add_custom_filter(custom_filter(raise_error)) + + else: + # 裸指令 + handler_md = get_handler_or_create(awaitable, EventType.AdapterMessageEvent, **kwargs) + handler_md.event_filters.append(custom_filter(raise_error)) + + return awaitable + return decorator + def register_command_group(command_group_name: str = None, *args, **kwargs): '''注册一个 CommandGroup ''' @@ -102,7 +156,7 @@ def register_command_group(command_group_name: str = None, *args, **kwargs): # 根指令组 handler_md = get_handler_or_create(obj, EventType.AdapterMessageEvent, **kwargs) handler_md.event_filters.append(new_group) - + return RegisteringCommandable(new_group) return decorator @@ -111,7 +165,8 @@ class RegisteringCommandable(): '''用于指令组级联注册''' group = register_command_group command = register_command - + custom_filter = register_custom_filter + def __init__(self, parent_group: CommandGroupFilter): self.parent_group = parent_group @@ -156,21 +211,6 @@ def register_permission_type(permission_type: PermissionType, raise_error: bool return decorator -def register_custom_permission_type(cunstom_permission_type_filter: BasePermissionTypeFilter, raise_error: bool = True): - '''注册一个自定义的 PermissionFilter - - Args: - cunstom_permission_type_filter: 一个继承自HandlerFilter - raise_error: 如果没有权限,是否抛出错误到消息平台,并且停止事件传播。默认为 True - ''' - - def decorator(awaitable): - handler_md = get_handler_or_create(awaitable, EventType.AdapterMessageEvent) - handler_md.event_filters.append(cunstom_permission_type_filter()) - return awaitable - - return decorator - def register_on_llm_request(**kwargs): '''当有 LLM 请求时的事件 From dff7cc4ca5ae5b1a6e5d3fc08e8221efeb2e9995 Mon Sep 17 00:00:00 2001 From: Alero Date: Fri, 14 Feb 2025 20:34:31 +0800 Subject: [PATCH 04/10] feat: when custom filter cant pass, won't raise error anymore. and when you use a command group and dont have custom filter access, the return group tree wont contain the command that you dont have permisson. --- astrbot/core/star/filter/command.py | 12 +++-- astrbot/core/star/filter/command_group.py | 62 ++++++++++++++++------- 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/astrbot/core/star/filter/command.py b/astrbot/core/star/filter/command.py index 41fdb61dc..d34d19a00 100644 --- a/astrbot/core/star/filter/command.py +++ b/astrbot/core/star/filter/command.py @@ -8,6 +8,7 @@ from astrbot.core.config import AstrBotConfig from astrbot.core.utils.param_validation_mixin import ParameterValidationMixin from .custom_filter import CustomFilter from ..star_handler import StarHandlerMetadata +from ... import logger # 标准指令受到 wake_prefix 的制约。 class CommandFilter(HandlerFilter, ParameterValidationMixin): @@ -48,13 +49,18 @@ class CommandFilter(HandlerFilter, ParameterValidationMixin): def add_custom_filter(self, custom_filter: CustomFilter): self.custom_filter_list.append(custom_filter) + def custom_filter_ok(self, event: AstrMessageEvent, cfg: AstrBotConfig) -> bool: + for custom_filter in self.custom_filter_list: + if not custom_filter.filter(event, cfg): + return False + return True + def filter(self, event: AstrMessageEvent, cfg: AstrBotConfig) -> bool: if not event.is_at_or_wake_command: return False - for custom_filter in self.custom_filter_list: - if not custom_filter.filter(event, cfg): - raise ValueError(f"没有执行该指令(组)的权限\n") + if not self.custom_filter_ok(event, cfg): + return False if event.get_extra("parsing_command"): message_str = event.get_extra("parsing_command").strip() diff --git a/astrbot/core/star/filter/command_group.py b/astrbot/core/star/filter/command_group.py index 0bb298cca..e75efbfd5 100644 --- a/astrbot/core/star/filter/command_group.py +++ b/astrbot/core/star/filter/command_group.py @@ -8,6 +8,7 @@ from astrbot.core.platform.astr_message_event import AstrMessageEvent from astrbot.core.config import AstrBotConfig from .custom_filter import CustomFilter from ..star_handler import StarHandlerMetadata +from ... import logger # 指令组受到 wake_prefix 的制约。 class CommandGroupFilter(HandlerFilter): @@ -23,24 +24,52 @@ class CommandGroupFilter(HandlerFilter): self.custom_filter_list.append(custom_filter) # 以树的形式打印出来 - def print_cmd_tree(self, sub_command_filters: List[Union[CommandFilter, CommandGroupFilter]], prefix: str = "") -> str: + def print_cmd_tree(self, + sub_command_filters: List[Union[CommandFilter, + CommandGroupFilter]], + prefix: str = "", + event: AstrMessageEvent = None, + cfg: AstrBotConfig = None, + ) -> str: result = "" for sub_filter in sub_command_filters: if isinstance(sub_filter, CommandFilter): - cmd_th = sub_filter.print_types() - result += f"{prefix}├── {sub_filter.command_name}" - if cmd_th: - result += f" ({cmd_th})" + if event and cfg: + if sub_filter.custom_filter_ok(event, cfg): + permission_pass = True + else: + permission_pass = False else: - result += " (无参数指令)" - - result += "\n" + permission_pass = True + if permission_pass: + cmd_th = sub_filter.print_types() + result += f"{prefix}├── {sub_filter.command_name}" + if cmd_th: + result += f" ({cmd_th})" + else: + result += " (无参数指令)" + result += "\n" elif isinstance(sub_filter, CommandGroupFilter): - result += f"{prefix}├── {sub_filter.group_name}" - result += "\n" - result += sub_filter.print_cmd_tree(sub_filter.sub_command_filters, prefix+"│ ") + if event and cfg: + if sub_filter.custom_filter_ok(event, cfg): + permission_pass = True + else: + permission_pass = False + else: + permission_pass = True + if permission_pass: + result += f"{prefix}├── {sub_filter.group_name}" + result += "\n" + result += sub_filter.print_cmd_tree(sub_filter.sub_command_filters, prefix+"│ ", event=event, cfg=cfg) + return result - + + def custom_filter_ok(self, event: AstrMessageEvent, cfg: AstrBotConfig) -> bool: + for custom_filter in self.custom_filter_list: + if not custom_filter.filter(event, cfg): + return False + return True + def filter(self, event: AstrMessageEvent, cfg: AstrBotConfig) -> Tuple[bool, StarHandlerMetadata]: if not event.is_at_or_wake_command: return False, None @@ -64,13 +93,12 @@ class CommandGroupFilter(HandlerFilter): if parsing_command == "": # 当前还是指令组 - tree = self.group_name + "\n" + self.print_cmd_tree(self.sub_command_filters) + tree = self.group_name + "\n" + self.print_cmd_tree(self.sub_command_filters, event=event, cfg=cfg) raise ValueError(f"指令组 {self.group_name} 未填写完全。这个指令组下有如下指令:\n"+tree) # 判断当前指令组的自定义过滤器 - for custom_filter in self.custom_filter_list: - if not custom_filter.filter(event, cfg): - raise ValueError(f"没有执行该指令(组)的权限\n") + if not self.custom_filter_ok(event, cfg): + return False, None child_command_handler_md = None for sub_filter in self.sub_command_filters: @@ -83,5 +111,5 @@ class CommandGroupFilter(HandlerFilter): if ok: child_command_handler_md = handler return True, child_command_handler_md - tree = self.group_name + "\n" + self.print_cmd_tree(self.sub_command_filters) + tree = self.group_name + "\n" + self.print_cmd_tree(self.sub_command_filters, event=event, cfg=cfg) raise ValueError(f"指令组 {self.group_name} 下没有找到对应的指令。这个指令组下有如下指令:\n"+tree) From fd460b19d45d2b326473cd781c6d929e1a228ce9 Mon Sep 17 00:00:00 2001 From: Alero Date: Fri, 14 Feb 2025 20:43:54 +0800 Subject: [PATCH 05/10] fix: cleancode err --- astrbot/core/star/filter/command.py | 1 - astrbot/core/star/filter/command_group.py | 1 - astrbot/core/star/register/star_handler.py | 4 +--- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/astrbot/core/star/filter/command.py b/astrbot/core/star/filter/command.py index d34d19a00..e0b6d47e2 100644 --- a/astrbot/core/star/filter/command.py +++ b/astrbot/core/star/filter/command.py @@ -8,7 +8,6 @@ from astrbot.core.config import AstrBotConfig from astrbot.core.utils.param_validation_mixin import ParameterValidationMixin from .custom_filter import CustomFilter from ..star_handler import StarHandlerMetadata -from ... import logger # 标准指令受到 wake_prefix 的制约。 class CommandFilter(HandlerFilter, ParameterValidationMixin): diff --git a/astrbot/core/star/filter/command_group.py b/astrbot/core/star/filter/command_group.py index e75efbfd5..cf7472edf 100644 --- a/astrbot/core/star/filter/command_group.py +++ b/astrbot/core/star/filter/command_group.py @@ -8,7 +8,6 @@ from astrbot.core.platform.astr_message_event import AstrMessageEvent from astrbot.core.config import AstrBotConfig from .custom_filter import CustomFilter from ..star_handler import StarHandlerMetadata -from ... import logger # 指令组受到 wake_prefix 的制约。 class CommandGroupFilter(HandlerFilter): diff --git a/astrbot/core/star/register/star_handler.py b/astrbot/core/star/register/star_handler.py index 320915a5c..14b710ace 100644 --- a/astrbot/core/star/register/star_handler.py +++ b/astrbot/core/star/register/star_handler.py @@ -1,6 +1,5 @@ from __future__ import annotations import docstring_parser -import traceback from ..star_handler import star_handlers_registry, StarHandlerMetadata, EventType from ..filter.command import CommandFilter @@ -10,7 +9,7 @@ from ..filter.platform_adapter_type import PlatformAdapterTypeFilter, PlatformAd from ..filter.permission import PermissionTypeFilter, PermissionType from ..filter.custom_filter import CustomFilter from ..filter.regex import RegexFilter -from typing import Awaitable, Union +from typing import Awaitable from astrbot.core.provider.func_tool_manager import SUPPORTED_TYPES from astrbot.core.provider.register import llm_tools from astrbot.core import logger @@ -118,7 +117,6 @@ def register_custom_filter(custom_type_filter: CustomFilter, *args, **kwargs): if not add_to_event_filters and not isinstance(awaitable, RegisteringCommandable): # 底层子指令 handle_full_name = get_handler_full_name(awaitable) - command_handle = None for sub_handle in parent_rigister_commandable.parent_group.sub_command_filters: # 所有符合fullname一致的子指令handle添加自定义过滤器。 # 不确定是否会有多个子指令有一样的fullname,比如一个方法添加多个command装饰器? From 6374c5d49d51a9dbf76515c39f0b489bd1710979 Mon Sep 17 00:00:00 2001 From: Alero Date: Fri, 14 Feb 2025 22:33:32 +0800 Subject: [PATCH 06/10] fix: add & | operation to customfilter --- astrbot/core/star/filter/command_group.py | 12 +++--- astrbot/core/star/filter/custom_filter.py | 44 +++++++++++++++++++++- astrbot/core/star/register/star_handler.py | 12 +++--- 3 files changed, 55 insertions(+), 13 deletions(-) diff --git a/astrbot/core/star/filter/command_group.py b/astrbot/core/star/filter/command_group.py index cf7472edf..5678b1af4 100644 --- a/astrbot/core/star/filter/command_group.py +++ b/astrbot/core/star/filter/command_group.py @@ -79,7 +79,7 @@ class CommandGroupFilter(HandlerFilter): message_str = event.get_message_str().strip() ls = re.split(r"\s+", message_str) - + if ls[0] != self.group_name: return False, None # 改写 message_str @@ -89,16 +89,16 @@ class CommandGroupFilter(HandlerFilter): parsing_command = " ".join(ls) parsing_command = parsing_command.strip() event.set_extra("parsing_command", parsing_command) - - if parsing_command == "": - # 当前还是指令组 - tree = self.group_name + "\n" + self.print_cmd_tree(self.sub_command_filters, event=event, cfg=cfg) - raise ValueError(f"指令组 {self.group_name} 未填写完全。这个指令组下有如下指令:\n"+tree) # 判断当前指令组的自定义过滤器 if not self.custom_filter_ok(event, cfg): return False, None + if parsing_command == "": + # 当前还是指令组 + tree = self.group_name + "\n" + self.print_cmd_tree(self.sub_command_filters, event=event, cfg=cfg) + raise ValueError(f"指令组 {self.group_name} 未填写完全。这个指令组下有如下指令:\n"+tree) + child_command_handler_md = None for sub_filter in self.sub_command_filters: if isinstance(sub_filter, CommandFilter): diff --git a/astrbot/core/star/filter/custom_filter.py b/astrbot/core/star/filter/custom_filter.py index cfe80099e..4a5fe5357 100644 --- a/astrbot/core/star/filter/custom_filter.py +++ b/astrbot/core/star/filter/custom_filter.py @@ -1,10 +1,22 @@ -from abc import abstractmethod +from abc import abstractmethod, ABCMeta +from typing import Union from . import HandlerFilter from astrbot.core.platform.astr_message_event import AstrMessageEvent from astrbot.core.config import AstrBotConfig -class CustomFilter(HandlerFilter): +class CustomFilterMeta(ABCMeta): + def __and__(cls, other): + if not issubclass(other, CustomFilter): + raise TypeError("Operands must be subclasses of CustomFilter.") + return CustomFilterAnd(cls(), other()) + + def __or__(cls, other): + if not issubclass(other, CustomFilter): + raise TypeError("Operands must be subclasses of CustomFilter.") + return CustomFilterOr(cls(), other()) + +class CustomFilter(HandlerFilter, metaclass=CustomFilterMeta): def __init__(self, raise_error: bool = True): self.raise_error = raise_error @@ -12,3 +24,31 @@ class CustomFilter(HandlerFilter): def filter(self, event: AstrMessageEvent, cfg: AstrBotConfig) -> bool: ''' 一个用于重写的自定义Filter ''' raise NotImplementedError + + def __or__(self, other): + return CustomFilterOr(self, other) + + def __and__(self, other): + return CustomFilterAnd(self, other) + +class CustomFilterOr(CustomFilter): + def __init__(self, filter1: CustomFilter, filter2: CustomFilter): + super().__init__() + if not isinstance(filter1, (CustomFilter, CustomFilterAnd, CustomFilterOr)): + raise ValueError("CustomFilter lass can only operate with other CustomFilter.") + self.filter1 = filter1 + self.filter2 = filter2 + + def filter(self, event: AstrMessageEvent, cfg: AstrBotConfig) -> bool: + return self.filter1.filter(event, cfg) or self.filter2.filter(event, cfg) + +class CustomFilterAnd(CustomFilter): + def __init__(self, filter1: CustomFilter, filter2: CustomFilter): + super().__init__() + if not isinstance(filter1, (CustomFilter, CustomFilterAnd, CustomFilterOr)): + raise ValueError("CustomFilter lass can only operate with other CustomFilter.") + self.filter1 = filter1 + self.filter2 = filter2 + + def filter(self, event: AstrMessageEvent, cfg: AstrBotConfig) -> bool: + return self.filter1.filter(event, cfg) and self.filter2.filter(event, cfg) diff --git a/astrbot/core/star/register/star_handler.py b/astrbot/core/star/register/star_handler.py index 14b710ace..c2909e47e 100644 --- a/astrbot/core/star/register/star_handler.py +++ b/astrbot/core/star/register/star_handler.py @@ -7,7 +7,7 @@ from ..filter.command_group import CommandGroupFilter from ..filter.event_message_type import EventMessageTypeFilter, EventMessageType from ..filter.platform_adapter_type import PlatformAdapterTypeFilter, PlatformAdapterType from ..filter.permission import PermissionTypeFilter, PermissionType -from ..filter.custom_filter import CustomFilter +from ..filter.custom_filter import CustomFilter, CustomFilterAnd, CustomFilterOr from ..filter.regex import RegexFilter from typing import Awaitable from astrbot.core.provider.func_tool_manager import SUPPORTED_TYPES @@ -81,7 +81,7 @@ def register_command(command_name: str = None, *args, **kwargs): return decorator -def register_custom_filter(custom_type_filter: CustomFilter, *args, **kwargs): +def register_custom_filter(custom_type_filter, *args, **kwargs): '''注册一个自定义的 CustomFilter Args: @@ -106,11 +106,13 @@ def register_custom_filter(custom_type_filter: CustomFilter, *args, **kwargs): if args: raise_error = args[0] + if not isinstance(custom_filter, (CustomFilterAnd, CustomFilterOr)): + custom_filter = custom_filter(raise_error) def decorator(awaitable): # 裸指令,子指令与指令组的区分,指令组会因为标记跳过wake。 if not add_to_event_filters and isinstance(awaitable, RegisteringCommandable): # 指令组,添加到本层的grouphandle中一起判断 - awaitable.parent_group.add_custom_filter(custom_filter(raise_error)) + awaitable.parent_group.add_custom_filter(custom_filter) else: handler_md = get_handler_or_create(awaitable, EventType.AdapterMessageEvent, **kwargs) @@ -122,12 +124,12 @@ def register_custom_filter(custom_type_filter: CustomFilter, *args, **kwargs): # 不确定是否会有多个子指令有一样的fullname,比如一个方法添加多个command装饰器? sub_handle_md = sub_handle.get_handler_md() if sub_handle_md and sub_handle_md.handler_full_name == handle_full_name: - sub_handle.add_custom_filter(custom_filter(raise_error)) + sub_handle.add_custom_filter(custom_filter) else: # 裸指令 handler_md = get_handler_or_create(awaitable, EventType.AdapterMessageEvent, **kwargs) - handler_md.event_filters.append(custom_filter(raise_error)) + handler_md.event_filters.append(custom_filter) return awaitable return decorator From 7a1b158f83316af4ef5998694dcc18de60bcf5c1 Mon Sep 17 00:00:00 2001 From: Alero Date: Fri, 14 Feb 2025 22:46:22 +0800 Subject: [PATCH 07/10] fix: cleancode err --- astrbot/core/star/filter/custom_filter.py | 1 - astrbot/core/star/register/star_handler.py | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/astrbot/core/star/filter/custom_filter.py b/astrbot/core/star/filter/custom_filter.py index 4a5fe5357..bee88ad81 100644 --- a/astrbot/core/star/filter/custom_filter.py +++ b/astrbot/core/star/filter/custom_filter.py @@ -1,5 +1,4 @@ from abc import abstractmethod, ABCMeta -from typing import Union from . import HandlerFilter from astrbot.core.platform.astr_message_event import AstrMessageEvent diff --git a/astrbot/core/star/register/star_handler.py b/astrbot/core/star/register/star_handler.py index c2909e47e..bc40978c7 100644 --- a/astrbot/core/star/register/star_handler.py +++ b/astrbot/core/star/register/star_handler.py @@ -7,7 +7,7 @@ from ..filter.command_group import CommandGroupFilter from ..filter.event_message_type import EventMessageTypeFilter, EventMessageType from ..filter.platform_adapter_type import PlatformAdapterTypeFilter, PlatformAdapterType from ..filter.permission import PermissionTypeFilter, PermissionType -from ..filter.custom_filter import CustomFilter, CustomFilterAnd, CustomFilterOr +from ..filter.custom_filter import CustomFilterAnd, CustomFilterOr from ..filter.regex import RegexFilter from typing import Awaitable from astrbot.core.provider.func_tool_manager import SUPPORTED_TYPES @@ -108,6 +108,7 @@ def register_custom_filter(custom_type_filter, *args, **kwargs): if not isinstance(custom_filter, (CustomFilterAnd, CustomFilterOr)): custom_filter = custom_filter(raise_error) + def decorator(awaitable): # 裸指令,子指令与指令组的区分,指令组会因为标记跳过wake。 if not add_to_event_filters and isinstance(awaitable, RegisteringCommandable): From 45e627c33c1ed50d5b6952f151a5f9093f5eaa22 Mon Sep 17 00:00:00 2001 From: Alero Date: Fri, 14 Feb 2025 23:52:31 +0800 Subject: [PATCH 08/10] fix: a bug when add filter to root command group --- astrbot/core/star/register/star_handler.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/astrbot/core/star/register/star_handler.py b/astrbot/core/star/register/star_handler.py index bc40978c7..2c8cc5361 100644 --- a/astrbot/core/star/register/star_handler.py +++ b/astrbot/core/star/register/star_handler.py @@ -111,8 +111,9 @@ def register_custom_filter(custom_type_filter, *args, **kwargs): def decorator(awaitable): # 裸指令,子指令与指令组的区分,指令组会因为标记跳过wake。 - if not add_to_event_filters and isinstance(awaitable, RegisteringCommandable): - # 指令组,添加到本层的grouphandle中一起判断 + if not add_to_event_filters and isinstance(awaitable, RegisteringCommandable) or \ + (add_to_event_filters and isinstance(awaitable, RegisteringCommandable)): + # 指令组 与 根指令组,添加到本层的grouphandle中一起判断 awaitable.parent_group.add_custom_filter(custom_filter) else: handler_md = get_handler_or_create(awaitable, EventType.AdapterMessageEvent, **kwargs) From ebb8c43fd0ff8219b49b50ce3f8bd7128a009421 Mon Sep 17 00:00:00 2001 From: Alero Date: Sun, 16 Feb 2025 04:02:46 +0800 Subject: [PATCH 09/10] =?UTF-8?q?bug:=20=E5=B0=9D=E8=AF=95=E4=BF=AE?= =?UTF-8?q?=E5=A4=8Dcleancode=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- astrbot/core/star/filter/custom_filter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/astrbot/core/star/filter/custom_filter.py b/astrbot/core/star/filter/custom_filter.py index bee88ad81..5be1b8dbe 100644 --- a/astrbot/core/star/filter/custom_filter.py +++ b/astrbot/core/star/filter/custom_filter.py @@ -16,7 +16,7 @@ class CustomFilterMeta(ABCMeta): return CustomFilterOr(cls(), other()) class CustomFilter(HandlerFilter, metaclass=CustomFilterMeta): - def __init__(self, raise_error: bool = True): + def __init__(self, raise_error: bool = True, **kwargs): self.raise_error = raise_error @abstractmethod From 26cbc9e8b1b06d2c0c69ccd9db59d16e5e14b006 Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Sun, 16 Feb 2025 13:32:28 +0800 Subject: [PATCH 10/10] chore: cleanup --- astrbot/api/event/filter/__init__.py | 2 ++ astrbot/core/star/filter/command_group.py | 31 ++++++++-------------- astrbot/core/star/register/star_handler.py | 6 ++--- 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/astrbot/api/event/filter/__init__.py b/astrbot/api/event/filter/__init__.py index 89729219d..7174be0fd 100644 --- a/astrbot/api/event/filter/__init__.py +++ b/astrbot/api/event/filter/__init__.py @@ -16,6 +16,7 @@ from astrbot.core.star.register import ( from astrbot.core.star.filter.event_message_type import EventMessageTypeFilter, EventMessageType from astrbot.core.star.filter.platform_adapter_type import PlatformAdapterTypeFilter, PlatformAdapterType from astrbot.core.star.filter.permission import PermissionTypeFilter, PermissionType +from astrbot.core.star.filter.custom_filter import CustomFilter __all__ = [ 'command', @@ -29,6 +30,7 @@ __all__ = [ 'PlatformAdapterTypeFilter', 'PlatformAdapterType', 'PermissionTypeFilter', + 'CustomFilter', 'custom_filter', 'PermissionType', 'on_llm_request', diff --git a/astrbot/core/star/filter/command_group.py b/astrbot/core/star/filter/command_group.py index 5678b1af4..750d01803 100644 --- a/astrbot/core/star/filter/command_group.py +++ b/astrbot/core/star/filter/command_group.py @@ -24,23 +24,18 @@ class CommandGroupFilter(HandlerFilter): # 以树的形式打印出来 def print_cmd_tree(self, - sub_command_filters: List[Union[CommandFilter, - CommandGroupFilter]], - prefix: str = "", - event: AstrMessageEvent = None, - cfg: AstrBotConfig = None, - ) -> str: + sub_command_filters: List[Union[CommandFilter, CommandGroupFilter]], + prefix: str = "", + event: AstrMessageEvent = None, + cfg: AstrBotConfig = None, + ) -> str: result = "" for sub_filter in sub_command_filters: if isinstance(sub_filter, CommandFilter): + custom_filter_pass = True if event and cfg: - if sub_filter.custom_filter_ok(event, cfg): - permission_pass = True - else: - permission_pass = False - else: - permission_pass = True - if permission_pass: + custom_filter_pass = sub_filter.custom_filter_ok(event, cfg) + if custom_filter_pass: cmd_th = sub_filter.print_types() result += f"{prefix}├── {sub_filter.command_name}" if cmd_th: @@ -49,14 +44,10 @@ class CommandGroupFilter(HandlerFilter): result += " (无参数指令)" result += "\n" elif isinstance(sub_filter, CommandGroupFilter): + custom_filter_pass = True if event and cfg: - if sub_filter.custom_filter_ok(event, cfg): - permission_pass = True - else: - permission_pass = False - else: - permission_pass = True - if permission_pass: + custom_filter_pass = sub_filter.custom_filter_ok(event, cfg) + if custom_filter_pass: result += f"{prefix}├── {sub_filter.group_name}" result += "\n" result += sub_filter.print_cmd_tree(sub_filter.sub_command_filters, prefix+"│ ", event=event, cfg=cfg) diff --git a/astrbot/core/star/register/star_handler.py b/astrbot/core/star/register/star_handler.py index 2c8cc5361..14e221e6a 100644 --- a/astrbot/core/star/register/star_handler.py +++ b/astrbot/core/star/register/star_handler.py @@ -85,7 +85,7 @@ def register_custom_filter(custom_type_filter, *args, **kwargs): '''注册一个自定义的 CustomFilter Args: - cunstom_permission_type_filter: 在裸指令时为CustomFilter对象 + custom_type_filter: 在裸指令时为CustomFilter对象 在指令组时为父指令的RegisteringCommandable对象,即self或者command_group的返回 raise_error: 如果没有权限,是否抛出错误到消息平台,并且停止事件传播。默认为 True ''' @@ -95,7 +95,7 @@ def register_custom_filter(custom_type_filter, *args, **kwargs): # 判断是否是指令组,指令组则添加到指令组的CommandGroupFilter对象中在waking_check的时候一起判断 if isinstance(custom_type_filter, RegisteringCommandable): # 子指令, 此时函数为RegisteringCommandable对象的方法,首位参数为RegisteringCommandable对象的self。 - parent_rigister_commandable = custom_type_filter + parent_register_commandable = custom_type_filter custom_filter = args[0] if len(args) > 1: raise_error = args[1] @@ -121,7 +121,7 @@ def register_custom_filter(custom_type_filter, *args, **kwargs): if not add_to_event_filters and not isinstance(awaitable, RegisteringCommandable): # 底层子指令 handle_full_name = get_handler_full_name(awaitable) - for sub_handle in parent_rigister_commandable.parent_group.sub_command_filters: + for sub_handle in parent_register_commandable.parent_group.sub_command_filters: # 所有符合fullname一致的子指令handle添加自定义过滤器。 # 不确定是否会有多个子指令有一样的fullname,比如一个方法添加多个command装饰器? sub_handle_md = sub_handle.get_handler_md()