From 46928ab6f679dcd64e0542e4f421f97fc039089b Mon Sep 17 00:00:00 2001 From: SXP-Simon Date: Wed, 25 Feb 2026 19:53:41 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix(core):=20=E4=BF=AE=E5=A4=8D=E5=AD=90?= =?UTF-8?q?=E6=99=BA=E8=83=BD=E4=BD=93=E5=B7=A5=E5=85=B7=E5=8E=BB=E9=87=8D?= =?UTF-8?q?=E5=A4=B1=E6=95=88=E5=8F=8A=E5=86=85=E7=BD=AE=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E8=AF=AF=E5=88=A0=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 调整 build_main_agent 逻辑顺序,确保在去重装饰逻辑执行前已加载内置工具(如 Computer Use、Cron 等)。 - 修正人格(Persona)工具查找逻辑,使其能正确识别并处理人格配置为“全部工具”的情况。 - 优化 _plugin_tool_fix,确保在插件过滤时保留没有模块路径的内置工具和 MCP 工具。 - 解决子智能体开启去重后主智能体依然保留重复内置工具的问题。 --- astrbot/core/astr_main_agent.py | 50 ++++++++++++++++----------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/astrbot/core/astr_main_agent.py b/astrbot/core/astr_main_agent.py index 6c1242f61..80ad152c4 100644 --- a/astrbot/core/astr_main_agent.py +++ b/astrbot/core/astr_main_agent.py @@ -348,20 +348,18 @@ async def _ensure_persona_and_skills( continue if a.get("enabled", True) is False: continue - persona_tools = None pid = a.get("persona_id") + persona_info_found = False + persona_info_tools = None if pid: - persona_tools = next( - ( - p.get("tools") - for p in plugin_context.persona_manager.personas_v3 - if p["name"] == pid - ), - None, - ) + for p in plugin_context.persona_manager.personas_v3: + if p["name"] == pid: + persona_info_tools = p.get("tools") + persona_info_found = True + break tools = a.get("tools", []) - if persona_tools is not None: - tools = persona_tools + if persona_info_found: + tools = persona_info_tools if tools is None: assigned_tools.update( [ @@ -739,6 +737,7 @@ def _plugin_tool_fix(event: AstrMessageEvent, req: ProviderRequest) -> None: continue mp = tool.handler_module_path if not mp: + new_tool_set.add_tool(tool) continue plugin = star_map.get(mp) if not plugin: @@ -1034,10 +1033,24 @@ async def build_main_agent( else: return None - await _decorate_llm_request(event, req, plugin_context, config) + # add built-in tools before decoration so they can be deduplicated by subagents + if config.computer_use_runtime == "sandbox": + _apply_sandbox_tools(config, req, req.session_id) + elif config.computer_use_runtime == "local": + _apply_local_env_tools(req) + + if config.add_cron_tools: + _proactive_cron_job_tools(req) + + if event.platform_meta.support_proactive_message: + if req.func_tool is None: + req.func_tool = ToolSet() + req.func_tool.add_tool(SEND_MESSAGE_TO_USER_TOOL) await _apply_kb(event, req, plugin_context, config) + await _decorate_llm_request(event, req, plugin_context, config) + if not req.session_id: req.session_id = event.unified_msg_origin @@ -1048,25 +1061,12 @@ async def build_main_agent( if config.llm_safety_mode: _apply_llm_safety_mode(config, req) - if config.computer_use_runtime == "sandbox": - _apply_sandbox_tools(config, req, req.session_id) - elif config.computer_use_runtime == "local": - _apply_local_env_tools(req) - agent_runner = AgentRunner() astr_agent_ctx = AstrAgentContext( context=plugin_context, event=event, ) - if config.add_cron_tools: - _proactive_cron_job_tools(req) - - if event.platform_meta.support_proactive_message: - if req.func_tool is None: - req.func_tool = ToolSet() - req.func_tool.add_tool(SEND_MESSAGE_TO_USER_TOOL) - if provider.provider_config.get("max_context_tokens", 0) <= 0: model = provider.get_model() if model_info := LLM_METADATAS.get(model): From 72a1caad5c8c010f9debd74756384f94ae1b1416 Mon Sep 17 00:00:00 2001 From: SXP-Simon Date: Wed, 25 Feb 2026 20:27:35 +0800 Subject: [PATCH 2/2] =?UTF-8?q?style:=20=E4=BC=98=E5=8C=96=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E8=A1=A8=E8=BE=BE=E5=B9=B6=E8=A1=A5=E5=85=A8=E6=A0=B8?= =?UTF-8?q?=E5=BF=83=E6=9E=84=E5=BB=BA=E9=93=BE=E8=B7=AF=E7=9A=84=E5=85=B3?= =?UTF-8?q?=E9=94=AE=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 为内置工具加载顺序、工具保留原则等关键逻辑点添加详细说明文档。 - 简化子智能体人格工具的判定写法,提升代码可读性。 --- astrbot/core/astr_main_agent.py | 35 ++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/astrbot/core/astr_main_agent.py b/astrbot/core/astr_main_agent.py index 80ad152c4..860b9097b 100644 --- a/astrbot/core/astr_main_agent.py +++ b/astrbot/core/astr_main_agent.py @@ -349,17 +349,25 @@ async def _ensure_persona_and_skills( if a.get("enabled", True) is False: continue pid = a.get("persona_id") - persona_info_found = False - persona_info_tools = None - if pid: - for p in plugin_context.persona_manager.personas_v3: - if p["name"] == pid: - persona_info_tools = p.get("tools") - persona_info_found = True - break + # Using a sentinel-like approach to distinguish "not found" from "found with tools=None" + # If persona exists, its tool config (could be None) overrides the subagent's manual tool list. + target_persona = ( + next( + ( + p + for p in plugin_context.persona_manager.personas_v3 + if p["name"] == pid + ), + None, + ) + if pid + else None + ) + tools = a.get("tools", []) - if persona_info_found: - tools = persona_info_tools + if target_persona: + tools = target_persona.get("tools") + if tools is None: assigned_tools.update( [ @@ -737,6 +745,8 @@ def _plugin_tool_fix(event: AstrMessageEvent, req: ProviderRequest) -> None: continue mp = tool.handler_module_path if not mp: + # Preservation: Tools without a handler_module_path are built-in tools or MCP tools. + # These lack a direct plugin mapping and must be preserved during plugin filtering. new_tool_set.add_tool(tool) continue plugin = star_map.get(mp) @@ -1033,7 +1043,10 @@ async def build_main_agent( else: return None - # add built-in tools before decoration so they can be deduplicated by subagents + # Execution Order Significance: + # Built-in tools (Computer Use, Cron, Proactive Messaging) must be added BEFORE _decorate_llm_request. + # This is because _decorate_llm_request invokes subagent deduplication logic, which needs to see + # these tools in the main toolset to determine if they should be removed (delegated to a subagent). if config.computer_use_runtime == "sandbox": _apply_sandbox_tools(config, req, req.session_id) elif config.computer_use_runtime == "local":