From da4bb6549c4e3f23dc627314a591eb8610e4e79b Mon Sep 17 00:00:00 2001 From: Soulter <37870767+Soulter@users.noreply.github.com> Date: Mon, 9 Feb 2026 22:38:05 +0800 Subject: [PATCH] feat: enhance persona tool management and update UI localization for subagent orchestration (#4990) * feat: enhance persona tool management and update UI localization for subagent orchestration * fix: remove debug logging for final ProviderRequest in build_main_agent function --- astrbot/core/astr_main_agent.py | 57 +++++++++---------- astrbot/core/config/default.py | 5 +- .../i18n/locales/en-US/features/subagent.json | 2 +- .../i18n/locales/zh-CN/features/subagent.json | 2 +- dashboard/src/views/SubAgentPage.vue | 11 ---- 5 files changed, 32 insertions(+), 45 deletions(-) diff --git a/astrbot/core/astr_main_agent.py b/astrbot/core/astr_main_agent.py index 690a6404c..4e70f3d59 100644 --- a/astrbot/core/astr_main_agent.py +++ b/astrbot/core/astr_main_agent.py @@ -326,6 +326,24 @@ async def _ensure_persona_and_skills( ) tmgr = plugin_context.get_llm_tool_manager() + # inject toolset in the persona + if (persona and persona.get("tools") is None) or not persona: + persona_toolset = tmgr.get_full_tool_set() + for tool in list(persona_toolset): + if not tool.active: + persona_toolset.remove_tool(tool.name) + else: + persona_toolset = ToolSet() + if persona["tools"]: + for tool_name in persona["tools"]: + tool = tmgr.get_func(tool_name) + if tool and tool.active: + persona_toolset.add_tool(tool) + if not req.func_tool: + req.func_tool = persona_toolset + else: + req.func_tool.merge(persona_toolset) + # sub agents integration orch_cfg = plugin_context.get_config().get("subagent_orchestrator", {}) so = plugin_context.subagent_orchestrator @@ -371,22 +389,19 @@ async def _ensure_persona_and_skills( assigned_tools.add(name) if req.func_tool is None: - toolset = ToolSet() - else: - toolset = req.func_tool + req.func_tool = ToolSet() # add subagent handoff tools for tool in so.handoffs: - toolset.add_tool(tool) + req.func_tool.add_tool(tool) # check duplicates if remove_dup: - names = toolset.names() + handoff_names = {tool.name for tool in so.handoffs} for tool_name in assigned_tools: - if tool_name in names: - toolset.remove_tool(tool_name) - - req.func_tool = toolset + if tool_name in handoff_names: + continue + req.func_tool.remove_tool(tool_name) router_prompt = ( plugin_context.get_config() @@ -395,32 +410,14 @@ async def _ensure_persona_and_skills( ).strip() if router_prompt: req.system_prompt += f"\n{router_prompt}\n" - return - - # inject toolset in the persona - if (persona and persona.get("tools") is None) or not persona: - toolset = tmgr.get_full_tool_set() - for tool in list(toolset): - if not tool.active: - toolset.remove_tool(tool.name) - else: - toolset = ToolSet() - if persona["tools"]: - for tool_name in persona["tools"]: - tool = tmgr.get_func(tool_name) - if tool and tool.active: - toolset.add_tool(tool) - if not req.func_tool: - req.func_tool = toolset - else: - req.func_tool.merge(toolset) try: event.trace.record( - "sel_persona", persona_id=persona_id, persona_toolset=toolset.names() + "sel_persona", + persona_id=persona_id, + persona_toolset=persona_toolset.names(), ) except Exception: pass - logger.debug("Tool set for persona %s: %s", persona_id, toolset.names()) async def _request_img_caption( diff --git a/astrbot/core/config/default.py b/astrbot/core/config/default.py index 01a0aebaa..8df72a0e8 100644 --- a/astrbot/core/config/default.py +++ b/astrbot/core/config/default.py @@ -129,8 +129,9 @@ DEFAULT_CONFIG = { }, # SubAgent orchestrator mode: # - main_enable = False: disabled; main LLM mounts tools normally (persona selection). - # - main_enable = True: enabled; main LLM will include handoff tools and can optionally - # remove tools that are duplicated on subagents via remove_main_duplicate_tools. + # - main_enable = True: enabled; main LLM keeps its own tools and includes handoff + # tools (transfer_to_*). remove_main_duplicate_tools can remove tools that are + # duplicated on subagents from the main LLM toolset. "subagent_orchestrator": { "main_enable": False, "remove_main_duplicate_tools": False, diff --git a/dashboard/src/i18n/locales/en-US/features/subagent.json b/dashboard/src/i18n/locales/en-US/features/subagent.json index ae05f06c5..b72ef1b40 100644 --- a/dashboard/src/i18n/locales/en-US/features/subagent.json +++ b/dashboard/src/i18n/locales/en-US/features/subagent.json @@ -2,7 +2,7 @@ "page": { "title": "SubAgent Orchestration", "beta": "Experimental", - "subtitle": "The main LLM only chats and delegates; tools live on individual SubAgents." + "subtitle": "The main LLM can use its own tools directly and delegate tasks to SubAgents via handoff." }, "actions": { "refresh": "Refresh", diff --git a/dashboard/src/i18n/locales/zh-CN/features/subagent.json b/dashboard/src/i18n/locales/zh-CN/features/subagent.json index f9df1d000..2e210720b 100644 --- a/dashboard/src/i18n/locales/zh-CN/features/subagent.json +++ b/dashboard/src/i18n/locales/zh-CN/features/subagent.json @@ -2,7 +2,7 @@ "page": { "title": "SubAgent 编排", "beta": "实验性", - "subtitle": "主 LLM 只负责聊天与分派(handoff),工具挂载在各个 SubAgent 上。" + "subtitle": "主 LLM 可直接使用自身工具,也可通过 handoff 分派给各个 SubAgent。" }, "actions": { "refresh": "刷新", diff --git a/dashboard/src/views/SubAgentPage.vue b/dashboard/src/views/SubAgentPage.vue index 892b628b6..3870f2d0c 100644 --- a/dashboard/src/views/SubAgentPage.vue +++ b/dashboard/src/views/SubAgentPage.vue @@ -142,17 +142,6 @@ -
-
{{ tm('cards.previewTitle') }}
-
- - {{ tm('cards.transferPrefix', { name: agent.name || '...' }) }} - - - {{ tm('cards.personaChip', { id: agent.persona_id }) }} - -
-