Repository navigation
fix: apply command group custom filters to sub-commands - #10646
AraragiEro wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Hey - I've found 2 issues
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="astrbot/core/star/filter/command_group.py" line_range="116-121" />
<code_context>
+ if cached is not None:
+ return cached
+
+ result = True
for custom_filter in self.custom_filter_list:
if not custom_filter.filter(event, cfg):
+ result = False
+ break
+ event.set_extra(cache_key, result)
+ return result
+
</code_context>
<issue_to_address>
**Group filters run on unrelated messages**
When a message reaches `waking_check` while a registered command-group handler is enabled, but the message does not start with that group’s command name, `waking_check` calls each handler filter before checking whether its command matches, and `CommandGroupFilter.filter()` calls `custom_filter_ok()` before `startswith()`. A group custom filter that sends a hint therefore sends it for unrelated messages too, despite the unrelated-message test passing when only the sub-command filter is called directly.
Check whether the message matches the group before evaluating its custom filters, while retaining the filter check for exact group-name messages that produce the insufficient-parameters help.
</issue_to_address>
### Comment 2
<location path="astrbot/core/star/filter/command.py" line_range="45" />
<code_context>
alias: set | None = None,
handler_md: StarHandlerMetadata | None = None,
parent_command_names: list[str] | None = None,
+ parent_group: CommandGroupFilter | None = None,
) -> None:
self.command_name = command_name
</code_context>
<issue_to_address>
**Type hint inspection raises NameError**
When a plugin or tooling caller evaluates the constructor annotations with `typing.get_type_hints`, `typing.get_type_hints(CommandFilter.__init__)` tries to resolve the new `CommandGroupFilter` annotation, but that name is only imported under `TYPE_CHECKING`, so introspection raises `NameError` instead of returning the constructor hints.
Make the annotation resolvable at runtime or avoid exposing an unresolved forward reference in the constructor hints.
</issue_to_address>Sourcery assessment
Approval pending. 2 findings to address first.
Blocking findings: astrbot/core/star/filter/command_group.py:121, astrbot/core/star/filter/command.py:45
7369051 to
ec8cc5f
Compare
A custom filter registered on a command group was only consulted by CommandGroupFilter.filter(), i.e. by the group handler, which the waking check excludes from the activated handlers. Sub-command handlers are evaluated independently and their CommandFilter never looked at the ancestor groups, so @group.custom_filter(...) silently did nothing for sub-commands. CommandFilter now keeps a reference to its parent command group and checks the ancestor groups' custom filters once the command name matches. CommandGroupFilter also checks its ancestors so nested groups are gated consistently. Group filter results are cached on the event, keeping a filter call to once per message even though both the group handler and the matching sub-command consult it. CommandGroupFilter now matches the command name before evaluating the custom filters, so a filter with side effects (for example sending a hint) is not triggered by unrelated messages. The parent group annotation uses a small protocol so the constructor type hints stay resolvable at runtime without a circular import. Adds tests/unit/test_group_custom_filter.py covering the cascade, nested groups, the sub-command's own filter, single evaluation, group-name help behavior and the registration wiring.
ec8cc5f to
bcebd70
Compare
|
Both findings addressed in 1. Group filters run on unrelated messages
Tests added:
2. Type hint inspection raises NameError
Verified locally with the stub-loaded modules:
|
Problem
A custom filter registered on a command group does not constrain its sub-commands.
@group.custom_filter(...)stores the filter inCommandGroupFilter.custom_filter_list, which is only consulted byCommandGroupFilter.filter()— i.e. by the group handler. The waking check excludes group handlers from the activated handlers, and sub-command handlers are evaluated independently: theirCommandFilter.filter()only checks their owncustom_filter_listand never looks at the ancestor groups.So
@filter.custom_filter(...)on a command group silently does nothing for sub-commands (its only remaining effect was suppressing the "insufficient parameters" tree when only the group name is sent). Verified with a minimal probe onmaster:True(still runs)FalseFor comparison, a group-level
permission_typeis enforced, becausewaking_checkspecial-casesPermissionTypeFilterand stops the event propagation.Fix
CommandFilterkeeps a reference to its parentCommandGroupFilter(parent_group=..., wired inregister_command) and checks the ancestor groups' custom filters once the command name matches.CommandGroupFilter.filter()also checks its ancestors, so nested groups are gated consistently (e.g. a filter onmathalso applies tomath calc add).custom_filter_ok:<id>), so a filter is evaluated once per message even though both the group handler and the matching sub-command consult it. Without the cache a filter that sends a hint (as suggested in the docs) would fire twice.Tests
tests/unit/test_group_custom_filter.py:register_commandattaches the parent group to the createdCommandFilterNotes
@group.custom_filter(...)will apply to the whole group, and the docs section should be updated to say so — I can follow up on docs: document register_custom_filter in listen-message-event guide #10643 once this lands.ruff format --checkandruff checkpass on the touched files.Summary by Sourcery
Ensure command-group custom filters constrain all matching sub-commands and nested command groups.
Bug Fixes:
Enhancements:
Tests: