feat: enhance persona tool management and update UI localization for subagent orchestration#4990
Conversation
…subagent orchestration
|
Documentation Updates 1 document(s) were updated by changes in this PR: pr4697的改动View Changes@@ -8,7 +8,7 @@
#### 架构说明
主动代理系统引入了 SubAgent(子代理)架构。主代理(MainAgent)不仅专注于对话和任务委派,还可以直接使用自身工具集。具体工具和任务也可以由子代理(SubAgent)处理。这样可以有效避免 prompt 膨胀和调用失败,同时提升主代理的灵活性。
-- 工具分配:每个 SubAgent 继承自 Persona,拥有独立的工具集、技能、名称和描述。主代理可以直接调用自身工具,也可以通过 `transfer_to_<subagent>` 工具将任务转交给指定子代理。
+- 工具分配:每个 SubAgent 继承自 Persona,拥有独立的工具集、技能、名称和描述。主代理可以直接调用自身工具,也可以通过 `transfer_to_<subagent>` 工具将任务转交给指定子代理。启用 SubAgent 编排后,主代理会保留自身工具,并自动挂载 handoff 工具(transfer_to_*),可根据配置决定是否移除与子代理重复的工具。
- 任务流转:主代理既可以直接处理任务,也可以分发任务给子代理。子代理之间可通过 transfer 工具实现任务转移。主代理和子代理的工具集可以根据配置灵活分配,支持去重和 handoff 工具自动挂载。
#### 使用示例
@@ -24,7 +24,15 @@
这样,主代理既可以自主处理,也可以灵活委派任务。
#### 配置说明
-SubAgent 的定义与 Persona 配置一致,需在配置文件中指定 tools、skills、name、description 等。主代理在未启用 SubAgent 编排时,可直接挂载自身工具集(按 persona 规则,默认全部),并直接调用工具。启用 SubAgent 编排后,主代理仅挂载 transfer_to_* 委派工具,不再直接挂载 persona/全局工具;由 SubAgent 负责工具调用与结果整理。工具分配可通过 UI 或配置文件完成。
+SubAgent 的定义与 Persona 配置一致,需在配置文件中指定 tools、skills、name、description 等。
+
+主代理在未启用 SubAgent 编排时,可直接挂载自身工具集(按 persona 规则,默认全部),并直接调用工具。
+
+启用 SubAgent 编排后,主代理会保留自身工具,并自动挂载 transfer_to_* 委派工具。是否移除与子代理重复的工具由 `remove_main_duplicate_tools` 配置项控制:
+- `remove_main_duplicate_tools: false`(默认):主代理保留自身工具,即使与子代理重复。
+- `remove_main_duplicate_tools: true`:主代理会移除与子代理重复的工具,仅保留独有工具和 handoff 工具。
+
+工具分配可通过 UI 或配置文件完成。相关配置项说明已在配置文件注释中明确。
### 2. FutureTask(定时任务)机制
@@ -96,7 +104,7 @@
- Persona 选择与工具分配
- 配置持久化
- 供应商类型选择:现在支持在“选择供应商”下拉菜单中选择 `chat_completion` 和 `agent_runner` 类型,便于根据不同需求配置子代理的执行方式。
-- 页面副标题已更新为:“主 LLM 负责聊天与委派(transfer_to_*),工具挂载在各个 SubAgent 上。”
+- 页面副标题已更新为:“主 LLM 可直接使用自身工具,也可通过 handoff 分派给各个 SubAgent。”
主代理和子代理的工具分配逻辑在 UI 中有清晰展示,支持灵活配置。
|
There was a problem hiding this comment.
Hey - 我发现了 1 个问题,并留下了一些总体反馈:
- 子代理 orchestrator 代码块里的去重逻辑看起来被反转了:现在在
remove_dup为 true 时,不再是从主工具集里移除交接工具(handoff tools),而是从req.func_tool中移除任何不在handoff_names中的assigned_tools,这很可能会把非交接工具也无意中删掉;建议恢复为基于主工具集名称来检查/移除。 build_main_agent中新增的调试日志会打印完整的prompt、system_prompt、contexts以及工具名称,这可能过于冗长且潜在包含敏感信息;建议对这些字段做截断,或者把这条日志放到更严格的配置/详细等级标志后面。
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The duplicate-removal logic in the subagent orchestrator block looks inverted: instead of removing handoff tools from the main toolset when `remove_dup` is true, it now removes any `assigned_tools` not in `handoff_names` from `req.func_tool`, which is likely to strip non-handoff tools unintentionally; consider reverting to checking/removing against the main toolset’s names.
- The new debug log in `build_main_agent` prints full `prompt`, `system_prompt`, `contexts`, and tool names, which may be verbose and potentially sensitive; consider truncating these fields or gating this log behind a more restrictive config/verbosity flag.
## Individual Comments
### Comment 1
<location> `astrbot/core/astr_main_agent.py:961-966` </location>
<code_context>
if action_type == "live":
req.system_prompt += f"\n{LIVE_MODE_SYSTEM_PROMPT}\n"
+ logger.debug("Final ProviderRequest: prompt=%s, system_prompt=%s, image_urls=%s, contexts=%s, func_tool=%s",
+ req.prompt,
+ req.system_prompt,
+ req.image_urls,
+ req.contexts,
+ req.func_tool.names() if req.func_tool else None,
+ )
+
</code_context>
<issue_to_address>
**🚨 suggestion (security):** 最终的调试日志可能过于冗长,并可能暴露大量或敏感内容。
在一条调试日志中包含完整的 `prompt`、`system_prompt` 和 `contexts`,可能会泄露用户数据,并生成非常长的日志行,尤其是在生产或高并发环境中。请考虑对这些字段进行截断、根据配置做脱敏处理,或者把这条日志隐藏在更细粒度的调试标志之后,以便在需要时可以关闭完整内容的日志。
建议实现方式:
```python
if action_type == "live":
req.system_prompt += f"\n{LIVE_MODE_SYSTEM_PROMPT}\n"
def _preview_for_logging(value, max_len: int = 512):
"""Return a truncated string representation for safe logging."""
if value is None:
return None
text = str(value)
if len(text) <= max_len:
return text
return text[:max_len] + f"... [truncated {len(text) - max_len} chars]"
logger.debug(
"Final ProviderRequest: prompt_preview=%s, system_prompt_preview=%s, image_urls=%s, contexts_preview=%s, func_tool=%s",
_preview_for_logging(req.prompt),
_preview_for_logging(req.system_prompt),
req.image_urls,
_preview_for_logging(req.contexts),
req.func_tool.names() if req.func_tool else None,
)
# inject toolset in the persona
if (persona and persona.get("tools") is None) or not persona:
```
如果你希望对敏感内容的日志有更严格的控制,可以考虑:
1. 引入一个配置开关(例如 `settings.LOG_FULL_LLM_CONTENT`),并:
- 当该开关为 `False` 时仅使用 `_preview_for_logging`(如上)。
- 只在非生产环境中为调试目的显式开启时,才记录完整内容。
2. 如果其他地方也需要类似的截断逻辑,可以将 `_preview_for_logging` 移动到一个共享的 logging/util 模块中。
</issue_to_address>帮我变得更有用!请在每条评论上点击 👍 或 👎,我会根据你的反馈改进后续评审。
Original comment in English
Hey - I've found 1 issue, and left some high level feedback:
- The duplicate-removal logic in the subagent orchestrator block looks inverted: instead of removing handoff tools from the main toolset when
remove_dupis true, it now removes anyassigned_toolsnot inhandoff_namesfromreq.func_tool, which is likely to strip non-handoff tools unintentionally; consider reverting to checking/removing against the main toolset’s names. - The new debug log in
build_main_agentprints fullprompt,system_prompt,contexts, and tool names, which may be verbose and potentially sensitive; consider truncating these fields or gating this log behind a more restrictive config/verbosity flag.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The duplicate-removal logic in the subagent orchestrator block looks inverted: instead of removing handoff tools from the main toolset when `remove_dup` is true, it now removes any `assigned_tools` not in `handoff_names` from `req.func_tool`, which is likely to strip non-handoff tools unintentionally; consider reverting to checking/removing against the main toolset’s names.
- The new debug log in `build_main_agent` prints full `prompt`, `system_prompt`, `contexts`, and tool names, which may be verbose and potentially sensitive; consider truncating these fields or gating this log behind a more restrictive config/verbosity flag.
## Individual Comments
### Comment 1
<location> `astrbot/core/astr_main_agent.py:961-966` </location>
<code_context>
if action_type == "live":
req.system_prompt += f"\n{LIVE_MODE_SYSTEM_PROMPT}\n"
+ logger.debug("Final ProviderRequest: prompt=%s, system_prompt=%s, image_urls=%s, contexts=%s, func_tool=%s",
+ req.prompt,
+ req.system_prompt,
+ req.image_urls,
+ req.contexts,
+ req.func_tool.names() if req.func_tool else None,
+ )
+
</code_context>
<issue_to_address>
**🚨 suggestion (security):** Final debug log may be overly verbose and could expose large or sensitive content.
Including full `prompt`, `system_prompt`, and `contexts` in a single debug log can leak user data and produce very large log lines, especially in production or high-traffic environments. Please consider truncating these fields, redacting them based on configuration, or guarding this behind a more targeted debug flag so full content logging can be disabled where needed.
Suggested implementation:
```python
if action_type == "live":
req.system_prompt += f"\n{LIVE_MODE_SYSTEM_PROMPT}\n"
def _preview_for_logging(value, max_len: int = 512):
"""Return a truncated string representation for safe logging."""
if value is None:
return None
text = str(value)
if len(text) <= max_len:
return text
return text[:max_len] + f"... [truncated {len(text) - max_len} chars]"
logger.debug(
"Final ProviderRequest: prompt_preview=%s, system_prompt_preview=%s, image_urls=%s, contexts_preview=%s, func_tool=%s",
_preview_for_logging(req.prompt),
_preview_for_logging(req.system_prompt),
req.image_urls,
_preview_for_logging(req.contexts),
req.func_tool.names() if req.func_tool else None,
)
# inject toolset in the persona
if (persona and persona.get("tools") is None) or not persona:
```
If you want even stricter control over logging sensitive content, consider:
1. Introducing a configuration flag (e.g. `settings.LOG_FULL_LLM_CONTENT`) and:
- Only use `_preview_for_logging` (as above) when the flag is `False`.
- Log full content only when explicitly enabled for debugging in non-production environments.
2. Moving `_preview_for_logging` to a shared logging/util module if similar truncation is needed elsewhere.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
astrbot/core/astr_main_agent.py
Outdated
| logger.debug("Final ProviderRequest: prompt=%s, system_prompt=%s, image_urls=%s, contexts=%s, func_tool=%s", | ||
| req.prompt, | ||
| req.system_prompt, | ||
| req.image_urls, | ||
| req.contexts, | ||
| req.func_tool.names() if req.func_tool else None, |
There was a problem hiding this comment.
🚨 suggestion (security): 最终的调试日志可能过于冗长,并可能暴露大量或敏感内容。
在一条调试日志中包含完整的 prompt、system_prompt 和 contexts,可能会泄露用户数据,并生成非常长的日志行,尤其是在生产或高并发环境中。请考虑对这些字段进行截断、根据配置做脱敏处理,或者把这条日志隐藏在更细粒度的调试标志之后,以便在需要时可以关闭完整内容的日志。
建议实现方式:
if action_type == "live":
req.system_prompt += f"\n{LIVE_MODE_SYSTEM_PROMPT}\n"
def _preview_for_logging(value, max_len: int = 512):
"""Return a truncated string representation for safe logging."""
if value is None:
return None
text = str(value)
if len(text) <= max_len:
return text
return text[:max_len] + f"... [truncated {len(text) - max_len} chars]"
logger.debug(
"Final ProviderRequest: prompt_preview=%s, system_prompt_preview=%s, image_urls=%s, contexts_preview=%s, func_tool=%s",
_preview_for_logging(req.prompt),
_preview_for_logging(req.system_prompt),
req.image_urls,
_preview_for_logging(req.contexts),
req.func_tool.names() if req.func_tool else None,
)
# inject toolset in the persona
if (persona and persona.get("tools") is None) or not persona:如果你希望对敏感内容的日志有更严格的控制,可以考虑:
- 引入一个配置开关(例如
settings.LOG_FULL_LLM_CONTENT),并:- 当该开关为
False时仅使用_preview_for_logging(如上)。 - 只在非生产环境中为调试目的显式开启时,才记录完整内容。
- 当该开关为
- 如果其他地方也需要类似的截断逻辑,可以将
_preview_for_logging移动到一个共享的 logging/util 模块中。
Original comment in English
🚨 suggestion (security): Final debug log may be overly verbose and could expose large or sensitive content.
Including full prompt, system_prompt, and contexts in a single debug log can leak user data and produce very large log lines, especially in production or high-traffic environments. Please consider truncating these fields, redacting them based on configuration, or guarding this behind a more targeted debug flag so full content logging can be disabled where needed.
Suggested implementation:
if action_type == "live":
req.system_prompt += f"\n{LIVE_MODE_SYSTEM_PROMPT}\n"
def _preview_for_logging(value, max_len: int = 512):
"""Return a truncated string representation for safe logging."""
if value is None:
return None
text = str(value)
if len(text) <= max_len:
return text
return text[:max_len] + f"... [truncated {len(text) - max_len} chars]"
logger.debug(
"Final ProviderRequest: prompt_preview=%s, system_prompt_preview=%s, image_urls=%s, contexts_preview=%s, func_tool=%s",
_preview_for_logging(req.prompt),
_preview_for_logging(req.system_prompt),
req.image_urls,
_preview_for_logging(req.contexts),
req.func_tool.names() if req.func_tool else None,
)
# inject toolset in the persona
if (persona and persona.get("tools") is None) or not persona:If you want even stricter control over logging sensitive content, consider:
- Introducing a configuration flag (e.g.
settings.LOG_FULL_LLM_CONTENT) and:- Only use
_preview_for_logging(as above) when the flag isFalse. - Log full content only when explicitly enabled for debugging in non-production environments.
- Only use
- Moving
_preview_for_loggingto a shared logging/util module if similar truncation is needed elsewhere.
fix: #4971
Modifications / 改动点
Screenshots or Test Results / 运行截图或测试结果
Checklist / 检查清单
requirements.txt和pyproject.toml文件相应位置。/ I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations inrequirements.txtandpyproject.toml.Summary by Sourcery
优化人物(persona)工具分配与子代理(subagent)编排行为,并让仪表盘 UI 和本地化与更新后的子代理流程保持一致。
改进点:
ProviderRequest的详细调试日志记录,以便排查提示词、上下文及工具选择行为相关问题。Original summary in English
Summary by Sourcery
Refine persona tool assignment and subagent orchestration behavior while aligning dashboard UI and localization with the updated subagent flow.
Enhancements: