From f120ebb80c86aaa44d56d7cc50877650bf5c6dc1 Mon Sep 17 00:00:00 2001 From: lingyun14 Date: Sun, 3 May 2026 18:38:29 +0800 Subject: [PATCH 1/3] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E4=BC=9A=E8=AF=9D?= =?UTF-8?q?=E7=BA=A7=E6=8F=92=E4=BB=B6=E7=A6=81=E7=94=A8=E8=A7=84=E5=88=99?= =?UTF-8?q?=E5=AF=B9=E4=BA=8B=E4=BB=B6=E9=92=A9=E5=AD=90=E4=B8=8D=E7=94=9F?= =?UTF-8?q?=E6=95=88=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- astrbot/core/pipeline/context_utils.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/astrbot/core/pipeline/context_utils.py b/astrbot/core/pipeline/context_utils.py index 9402ce3e62..1ceaa04b45 100644 --- a/astrbot/core/pipeline/context_utils.py +++ b/astrbot/core/pipeline/context_utils.py @@ -85,11 +85,31 @@ async def call_event_hook( # """ + from astrbot.core import sp + + session_id = event.unified_msg_origin + session_plugin_config = await sp.get_async( + scope="umo", + scope_id=session_id, + key="session_plugin_config", + default={}, + ) + session_disabled = session_plugin_config.get(session_id, {}).get( + "disabled_plugins", [] + ) + handlers = star_handlers_registry.get_handlers_by_event_type( hook_type, plugins_name=event.plugins_name, ) for handler in handlers: + plugin = star_map.get(handler.handler_module_path) + if plugin and not plugin.reserved and plugin.name in session_disabled: + logger.debug( + f"hook({hook_type.name}) -> {plugin.name} - {handler.handler_name} " + f"在会话 {session_id} 中被禁用,跳过。", + ) + continue try: assert inspect.iscoroutinefunction(handler.handler) logger.debug( From 0390c0ce023c30bc675e4e2cc58b645e7187d8d1 Mon Sep 17 00:00:00 2001 From: lingyun14 Date: Sun, 3 May 2026 18:40:07 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E4=BC=9A=E8=AF=9D?= =?UTF-8?q?=E7=BA=A7=E6=8F=92=E4=BB=B6=E7=A6=81=E7=94=A8=E8=A7=84=E5=88=99?= =?UTF-8?q?=E5=AF=B9=E4=BA=8B=E4=BB=B6=E9=92=A9=E5=AD=90=E4=B8=8D=E7=94=9F?= =?UTF-8?q?=E6=95=88=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- astrbot/core/astr_main_agent.py | 94 ++++++++++++++++++++++++--------- 1 file changed, 69 insertions(+), 25 deletions(-) diff --git a/astrbot/core/astr_main_agent.py b/astrbot/core/astr_main_agent.py index 3916215e5b..388d0edc6e 100644 --- a/astrbot/core/astr_main_agent.py +++ b/astrbot/core/astr_main_agent.py @@ -383,6 +383,7 @@ def _build_local_mode_prompt() -> str: def _filter_skills_for_current_config( skills: list[SkillInfo], cfg: dict, + session_disabled: set[str] | None = None, ) -> list[SkillInfo]: plugin_set = cfg.get("plugin_set", ["*"]) allowed_plugins = ( @@ -404,7 +405,12 @@ def _filter_skills_for_current_config( plugin = plugin_by_root_dir.get(skill.plugin_name) if not plugin or not plugin.activated: continue - if plugin.reserved or allowed_plugins is None: + if plugin.reserved: + filtered.append(skill) + continue + if session_disabled and plugin.name in session_disabled: + continue + if allowed_plugins is None: filtered.append(skill) continue if plugin.name is not None and plugin.name in allowed_plugins: @@ -422,6 +428,19 @@ async def _ensure_persona_and_skills( if not req.conversation: return + from astrbot.core import sp + + session_id = event.unified_msg_origin + session_plugin_config = await sp.get_async( + scope="umo", + scope_id=session_id, + key="session_plugin_config", + default={}, + ) + session_disabled = set( + session_plugin_config.get(session_id, {}).get("disabled_plugins", []) + ) + ( persona_id, persona, @@ -454,7 +473,7 @@ async def _ensure_persona_and_skills( runtime = cfg.get("computer_use_runtime", "local") skill_manager = SkillManager() skills = skill_manager.list_skills(active_only=True, runtime=runtime) - skills = _filter_skills_for_current_config(skills, cfg) + skills = _filter_skills_for_current_config(skills, cfg, session_disabled) if skills: if persona and persona.get("skills") is not None: @@ -898,33 +917,58 @@ async def _decorate_llm_request( _apply_workspace_extra_prompt(event, req) -def _plugin_tool_fix(event: AstrMessageEvent, req: ProviderRequest) -> None: +async def _plugin_tool_fix(event: AstrMessageEvent, req: ProviderRequest) -> None: """根据事件中的插件设置,过滤请求中的工具列表。 注意:没有 handler_module_path 的工具(如 MCP 工具)会被保留, 因为它们不属于任何插件,不应被插件过滤逻辑影响。 """ - if event.plugins_name is not None and req.func_tool: - new_tool_set = ToolSet() - for tool in req.func_tool.tools: - if isinstance(tool, MCPTool): - # 保留 MCP 工具 - new_tool_set.add_tool(tool) - continue - mp = tool.handler_module_path - if not mp: - # 没有 plugin 归属信息的工具(如 subagent transfer_to_*) - # 不应受到会话插件过滤影响。 - new_tool_set.add_tool(tool) - continue - plugin = star_map.get(mp) - if not plugin: - # 无法解析插件归属时,保守保留工具,避免误过滤。 - new_tool_set.add_tool(tool) - continue - if plugin.name in event.plugins_name or plugin.reserved: - new_tool_set.add_tool(tool) - req.func_tool = new_tool_set + if not req.func_tool: + return + + from astrbot.core import sp + + session_id = event.unified_msg_origin + session_plugin_config = await sp.get_async( + scope="umo", + scope_id=session_id, + key="session_plugin_config", + default={}, + ) + session_disabled = set( + session_plugin_config.get(session_id, {}).get("disabled_plugins", []) + ) + + global_whitelist = event.plugins_name # None 表示全部允许 + + new_tool_set = ToolSet() + for tool in req.func_tool.tools: + if isinstance(tool, MCPTool): + # 保留 MCP 工具 + new_tool_set.add_tool(tool) + continue + mp = tool.handler_module_path + if not mp: + # 没有 plugin 归属信息的工具(如 subagent transfer_to_*) + # 不应受到会话插件过滤影响。 + new_tool_set.add_tool(tool) + continue + plugin = star_map.get(mp) + if not plugin: + # 无法解析插件归属时,保守保留工具,避免误过滤。 + new_tool_set.add_tool(tool) + continue + if plugin.reserved: + new_tool_set.add_tool(tool) + continue + # 全局白名单过滤 + if global_whitelist is not None and plugin.name not in global_whitelist: + continue + # 会话级禁用过滤 + if plugin.name in session_disabled: + continue + new_tool_set.add_tool(tool) + req.func_tool = new_tool_set async def _handle_webchat( @@ -1372,7 +1416,7 @@ async def build_main_agent( if not req.session_id: req.session_id = event.unified_msg_origin - _plugin_tool_fix(event, req) + await _plugin_tool_fix(event, req) await _apply_web_search_tools(event, req, plugin_context) if config.llm_safety_mode: From 2b4f3b3a60afbbb0d926be535e010d4c612f45d5 Mon Sep 17 00:00:00 2001 From: lingyun14 Date: Sun, 3 May 2026 22:03:52 +0800 Subject: [PATCH 3/3] refactor: simplify call_event_hook by reusing SessionPluginManager --- astrbot/core/pipeline/context_utils.py | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/astrbot/core/pipeline/context_utils.py b/astrbot/core/pipeline/context_utils.py index 1ceaa04b45..28426be1ff 100644 --- a/astrbot/core/pipeline/context_utils.py +++ b/astrbot/core/pipeline/context_utils.py @@ -85,31 +85,14 @@ async def call_event_hook( # """ - from astrbot.core import sp - - session_id = event.unified_msg_origin - session_plugin_config = await sp.get_async( - scope="umo", - scope_id=session_id, - key="session_plugin_config", - default={}, - ) - session_disabled = session_plugin_config.get(session_id, {}).get( - "disabled_plugins", [] - ) + from astrbot.core.star.session_plugin_manager import SessionPluginManager handlers = star_handlers_registry.get_handlers_by_event_type( hook_type, plugins_name=event.plugins_name, ) + handlers = await SessionPluginManager.filter_handlers_by_session(event, handlers) for handler in handlers: - plugin = star_map.get(handler.handler_module_path) - if plugin and not plugin.reserved and plugin.name in session_disabled: - logger.debug( - f"hook({hook_type.name}) -> {plugin.name} - {handler.handler_name} " - f"在会话 {session_id} 中被禁用,跳过。", - ) - continue try: assert inspect.iscoroutinefunction(handler.handler) logger.debug(