Skip to content
Closed
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
44d2364
feat: enhanced subagent
elecvoid243 Mar 26, 2026
01b78d7
Merge branch 'master' of https://github.com/elecvoid243/AstrBot
elecvoid243 Mar 26, 2026
c70d0a5
no message
elecvoid243 Mar 26, 2026
f195754
no message
elecvoid243 Mar 27, 2026
3b005da
no message
elecvoid243 Mar 28, 2026
2b67fd3
no message
elecvoid243 Mar 28, 2026
9d38048
formatting
elecvoid243 Mar 28, 2026
378a6e6
no message
elecvoid243 Mar 28, 2026
2d33670
no message
elecvoid243 Mar 28, 2026
5e45821
test
elecvoid243 Mar 28, 2026
ad34dce
no message
elecvoid243 Mar 28, 2026
2389f27
Merge branch 'master' into master
elecvoid243 Mar 29, 2026
549ff85
no message
elecvoid243 Mar 29, 2026
38a6b2e
Merge branch 'master' of https://github.com/elecvoid243/AstrBot
elecvoid243 Mar 29, 2026
58d5141
Merge branch 'AstrBotDevs:master' into master
elecvoid243 Mar 29, 2026
a9cf8d3
添加Reset工具
elecvoid243 Mar 29, 2026
923a58e
Merge branch 'AstrBotDevs:master' into master
elecvoid243 Mar 29, 2026
bf88368
结构化的共享上下文;更新subagent后台任务逻辑
elecvoid243 Mar 30, 2026
97cfedf
Merge branch 'AstrBotDevs:master' into master
elecvoid243 Mar 30, 2026
9f7e208
主动等待机制;Prompt优化
elecvoid243 Apr 2, 2026
163ce55
Merge branch 'master' of https://github.com/elecvoid243/AstrBot
elecvoid243 Apr 2, 2026
ee0a85e
Merge branch 'AstrBotDevs:master' into master
elecvoid243 Apr 2, 2026
fb39593
Merge branch 'AstrBotDevs:master' into master
elecvoid243 Apr 5, 2026
06cb7ea
subagent运行状态监控
elecvoid243 Apr 6, 2026
a579ac3
Merge branch 'master' into master
elecvoid243 Apr 6, 2026
3f02d54
rollback local.py
elecvoid243 Apr 6, 2026
03deaac
Merge branch 'AstrBotDevs:master' into master
elecvoid243 Apr 7, 2026
d3cee00
merge
elecvoid243 Apr 7, 2026
47b61ec
Merge branch 'AstrBotDevs:master' into master
elecvoid243 Apr 8, 2026
7dbfb6e
后台subagent任务:若主agent已结束,回退到原始唤醒机制
elecvoid243 Apr 9, 2026
6a6d030
移除logger;prompt简化
elecvoid243 Apr 11, 2026
cea5611
subagent历史带工具调用信息
elecvoid243 Apr 11, 2026
a9dd635
Merge branch 'master' into master
elecvoid243 Apr 11, 2026
1222aae
formatting
elecvoid243 Apr 11, 2026
25200f2
no message
elecvoid243 Apr 11, 2026
603072c
no message
elecvoid243 Apr 11, 2026
2e2a60b
Merge branch 'AstrBotDevs:master' into master
elecvoid243 Apr 12, 2026
65bb50c
no message
elecvoid243 Apr 13, 2026
7d567b6
Merge branch 'AstrBotDevs:master' into master
elecvoid243 Apr 13, 2026
4366d37
Merge branch 'master' of https://github.com/elecvoid243/AstrBot
elecvoid243 Apr 13, 2026
7490ea3
添加subagent超时保护(总时长)
elecvoid243 Apr 14, 2026
cd912b3
Merge branch 'AstrBotDevs:master' into master
elecvoid243 Apr 14, 2026
f4fabc2
Merge branch 'master' of https://github.com/elecvoid243/AstrBot
elecvoid243 Apr 14, 2026
7ef86e4
formatting
elecvoid243 Apr 14, 2026
09da25c
Merge branch 'master' into master
elecvoid243 Apr 19, 2026
00465ee
更新dashborad
elecvoid243 Apr 19, 2026
ee3d6fe
fix dashboard
elecvoid243 Apr 20, 2026
0999ba1
formatting
elecvoid243 Apr 20, 2026
8705d81
bug fix
elecvoid243 Apr 21, 2026
17134ef
Merge branch 'AstrBotDevs:master' into master
elecvoid243 Apr 21, 2026
f26fbf4
Merge branch 'AstrBotDevs:master' into master
elecvoid243 Apr 23, 2026
a064451
bug fix
elecvoid243 Apr 23, 2026
e3ace42
resolve conficts
elecvoid243 Apr 27, 2026
ffa3cbc
Merge branch 'AstrBotDevs:master' into master
elecvoid243 Apr 27, 2026
095603c
合并subagent与enhanced subagent实现
elecvoid243 Apr 28, 2026
c098de9
Merge branch 'AstrBotDevs:master' into master
elecvoid243 Apr 29, 2026
0d6567a
format
elecvoid243 Apr 29, 2026
2f93e9e
format
elecvoid243 Apr 29, 2026
b70439b
Merge branch 'master' of https://github.com/elecvoid243/AstrBot
elecvoid243 Apr 29, 2026
ceba3ae
no message
elecvoid243 Apr 29, 2026
f0b3872
历史上下文功能变为可配置的
elecvoid243 Apr 30, 2026
49be025
Merge branch 'AstrBotDevs:master' into master
elecvoid243 Apr 30, 2026
885e1e0
bug fix
elecvoid243 May 3, 2026
40ce239
Merge branch 'AstrBotDevs:master' into master
elecvoid243 May 3, 2026
b7c3a88
Merge branch 'master' of https://github.com/elecvoid243/AstrBot
elecvoid243 May 3, 2026
b2a8593
为配置项更新dashboard
elecvoid243 May 4, 2026
c73a542
Merge branch 'AstrBotDevs:master' into master
elecvoid243 May 4, 2026
e0e8da9
Merge branch 'master' of https://github.com/elecvoid243/AstrBot
elecvoid243 May 4, 2026
116ec55
啥时候改的这个文件?还原
elecvoid243 May 4, 2026
820a9dd
no message
elecvoid243 May 4, 2026
1cd37f1
优化dashboard
elecvoid243 May 4, 2026
822de54
no message
elecvoid243 May 4, 2026
734e3a3
no message
elecvoid243 May 4, 2026
238ee93
no message
elecvoid243 May 4, 2026
12d761e
no message
elecvoid243 May 4, 2026
239d576
分离manager和tools
elecvoid243 May 4, 2026
5a11f81
ruff
elecvoid243 May 4, 2026
e2f8f5e
Merge branch 'AstrBotDevs:master' into master
elecvoid243 May 5, 2026
a0aa3d8
Merge branch 'AstrBotDevs:master' into master
elecvoid243 May 6, 2026
4f02492
优化router prompt; 更多dashboard配置
elecvoid243 May 6, 2026
d5fb9f9
共享上下文放到system_reminder防止缓存不命中
elecvoid243 May 7, 2026
56e0192
Merge branch 'AstrBotDevs:master' into master
elecvoid243 May 7, 2026
97d19cc
移除变化的router prompt
elecvoid243 May 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 109 additions & 1 deletion astrbot/core/astr_agent_tool_exec.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import asyncio
import datetime
import inspect
import json
import traceback
Expand Down Expand Up @@ -233,6 +234,21 @@ def _build_handoff_toolset(
toolset.add_tool(runtime_tool)
elif isinstance(tool_name_or_obj, FunctionTool):
toolset.add_tool(tool_name_or_obj)

# Always add send_shared_context tool for shared context feature
try:
from astrbot.core.dynamic_subagent_manager import (
SEND_SHARED_CONTEXT_TOOL,
DynamicSubAgentManager,
)

session_id = event.unified_msg_origin
session = DynamicSubAgentManager.get_session(session_id)
if session and session.shared_context_enabled:
toolset.add_tool(SEND_SHARED_CONTEXT_TOOL)
except Exception:
pass
Comment thread
elecvoid243 marked this conversation as resolved.
Outdated

return None if toolset.empty() else toolset

@classmethod
Expand Down Expand Up @@ -291,21 +307,113 @@ async def _execute_handoff(
except Exception:
continue

# 获取子代理的历史上下文
agent_name = getattr(tool.agent, "name", None)
subagent_history = []
if agent_name:
try:
from astrbot.core.dynamic_subagent_manager import DynamicSubAgentManager

stored_history = DynamicSubAgentManager.get_subagent_history(
umo, agent_name
)
if stored_history:
# 将历史消息转换为 Message 对象
for hist_msg in stored_history:
try:
if isinstance(hist_msg, dict):
subagent_history.append(
Message.model_validate(hist_msg)
)
elif isinstance(hist_msg, Message):
subagent_history.append(hist_msg)
except Exception:
continue
if subagent_history:
logger.info(
f"[SubAgentHistory] Loaded {len(subagent_history)} history messages for {agent_name}"
)
except Exception:
pass
Comment thread
elecvoid243 marked this conversation as resolved.
Outdated

prov_settings: dict = ctx.get_config(umo=umo).get("provider_settings", {})
agent_max_step = int(prov_settings.get("max_agent_step", 30))
stream = prov_settings.get("streaming_response", False)
# 如果有历史上下文,合并到 contexts 中
if subagent_history:
if contexts is None:
contexts = subagent_history
else:
contexts = subagent_history + contexts

# 构建子代理的 system_prompt,添加 skills 提示词和公共上下文
subagent_system_prompt = tool.agent.instructions or ""
if agent_name:
try:
from astrbot.core.dynamic_subagent_manager import DynamicSubAgentManager

# 注入 skills
runtime = prov_settings.get("computer_use_runtime", "local")
skills_prompt = DynamicSubAgentManager.build_subagent_skills_prompt(
umo, agent_name, runtime
)
if skills_prompt:
subagent_system_prompt += f"\n\n# Available Skills\n{skills_prompt}"
logger.info(f"[SubAgentSkills] Injected skills for {agent_name}")

# 注入公共上下文
shared_context_prompt = (
DynamicSubAgentManager.build_shared_context_prompt(umo, agent_name)
)
if shared_context_prompt:
subagent_system_prompt += f"\n{shared_context_prompt}"
logger.info(
f"[SubAgentSharedContext] Injected shared context for {agent_name}"
)

# 注入时间信息
current_time = (
datetime.datetime.now().astimezone().strftime("%Y-%m-%d %H:%M (%Z)")
)
subagent_system_prompt += f"Current datetime: {current_time}"

except Exception:
pass

llm_resp = await ctx.tool_loop_agent(
event=event,
chat_provider_id=prov_id,
prompt=input_,
image_urls=image_urls,
system_prompt=tool.agent.instructions,
system_prompt=subagent_system_prompt,
tools=toolset,
contexts=contexts,
max_steps=agent_max_step,
tool_call_timeout=run_context.tool_call_timeout,
stream=stream,
)

# 保存历史上下文
try:
from astrbot.core.dynamic_subagent_manager import DynamicSubAgentManager

agent_name = getattr(tool.agent, "name", None)
if agent_name:
# 构建当前对话的历史消息
current_messages = []
# 添加本轮用户输入
current_messages.append({"role": "user", "content": input_})
# 添加助手回复
current_messages.append(
{"role": "assistant", "content": llm_resp.completion_text}
)
if current_messages:
DynamicSubAgentManager.save_subagent_history(
umo, agent_name, current_messages
)
except Exception:
pass # 不影响主流程

yield mcp.types.CallToolResult(
content=[mcp.types.TextContent(type="text", text=llm_resp.completion_text)]
)
Expand Down
98 changes: 98 additions & 0 deletions astrbot/core/astr_main_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ class MainAgentBuildConfig:
timezone: str | None = None
max_quoted_fallback_images: int = 20
"""Maximum number of images injected from quoted-message fallback extraction."""
enhanced_subagent: dict = field(default_factory=dict)
"""Log level for enhanced SubAgent: info or debug."""


@dataclass(slots=True)
Expand Down Expand Up @@ -929,6 +931,99 @@ def _apply_llm_safety_mode(config: MainAgentBuildConfig, req: ProviderRequest) -
)


def _apply_enhanced_subagent_tools(
config: MainAgentBuildConfig, req: ProviderRequest, event: AstrMessageEvent
) -> None:
"""Apply enhanced SubAgent tools and system prompt

When enabled:
1. Inject enhanced capability prompt into system prompt
2. Register dynamic SubAgent management tools
3. Register session's transfer_to_xxx tools
"""
if not config.enhanced_subagent.get("enabled", False):
return

if req.func_tool is None:
req.func_tool = ToolSet()

try:
from astrbot.core.dynamic_subagent_manager import (
CLEANUP_DYNAMIC_SUBAGENT_TOOL,
CREATE_DYNAMIC_SUBAGENT_TOOL,
LIST_DYNAMIC_SUBAGENTS_TOOL,
PROTECT_SUBAGENT_TOOL,
SEND_SHARED_CONTEXT_TOOL_FOR_MAIN_AGENT,
UNPROTECT_SUBAGENT_TOOL,
VIEW_SHARED_CONTEXT_TOOL,
DynamicSubAgentManager,
)
from astrbot.core.subagent_logger import SubAgentLogger

# Register dynamic SubAgent management tools
req.func_tool.add_tool(CREATE_DYNAMIC_SUBAGENT_TOOL)
req.func_tool.add_tool(CLEANUP_DYNAMIC_SUBAGENT_TOOL)
req.func_tool.add_tool(LIST_DYNAMIC_SUBAGENTS_TOOL)
req.func_tool.add_tool(PROTECT_SUBAGENT_TOOL)
req.func_tool.add_tool(UNPROTECT_SUBAGENT_TOOL)
req.func_tool.add_tool(VIEW_SHARED_CONTEXT_TOOL)
req.func_tool.add_tool(SEND_SHARED_CONTEXT_TOOL_FOR_MAIN_AGENT)

# Configure logger
SubAgentLogger.configure(level=config.enhanced_subagent.get("log_level"))

# Configure DynamicSubAgentManager with settings
shared_context_enabled = config.enhanced_subagent.get(
"shared_context_enabled", False
)
DynamicSubAgentManager.configure(
max_subagent_count=config.enhanced_subagent.get("max_subagent_count"),
auto_cleanup_per_turn=config.enhanced_subagent.get("auto_cleanup_per_turn"),
shared_context_enabled=shared_context_enabled,
shared_context_maxlen=config.enhanced_subagent.get(
"shared_context_maxlen", 200
),
)

# Enable shared context if configured
if shared_context_enabled:
DynamicSubAgentManager.set_shared_context_enabled(
event.unified_msg_origin, True
)

# Inject enhanced system prompt
dynamic_subagent_prompt = DynamicSubAgentManager.get_dynamic_subagent_prompt()
req.system_prompt = f"{req.system_prompt}\n{dynamic_subagent_prompt}\n"
Comment thread
elecvoid243 marked this conversation as resolved.
Outdated

# Register existing handoff tools from config
plugin_context = getattr(event, "_plugin_context", None)
if plugin_context and plugin_context.subagent_orchestrator:
so = plugin_context.subagent_orchestrator
if hasattr(so, "handoffs"):
for tool in so.handoffs:
req.func_tool.add_tool(tool)
# Register dynamically created handoff tools
session_id = event.unified_msg_origin
dynamic_handoffs = DynamicSubAgentManager.get_handoff_tools_for_session(
session_id
)
for handoff in dynamic_handoffs:
req.func_tool.add_tool(handoff)

# Check if we should cleanup subagents from previous turn
# This is done at the START of a new turn to clean up from previous turn
try:
DynamicSubAgentManager.cleanup_session_turn_start(session_id)
except Exception as e:
from astrbot import logger

logger.warning(f"[DynamicSubAgent] Cleanup failed: {e}")
except ImportError as e:
from astrbot import logger

logger.warning(f"[DynamicSubAgent] Cannot import module: {e}")


def _apply_sandbox_tools(
config: MainAgentBuildConfig, req: ProviderRequest, session_id: str
) -> None:
Expand Down Expand Up @@ -1254,6 +1349,9 @@ async def build_main_agent(
elif config.computer_use_runtime == "local":
_apply_local_env_tools(req)

# Apply enhanced SubAgent tools
_apply_enhanced_subagent_tools(config, req, event)

agent_runner = AgentRunner()
astr_agent_ctx = AstrAgentContext(
context=plugin_context,
Expand Down
17 changes: 13 additions & 4 deletions astrbot/core/config/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from astrbot.core.utils.astrbot_path import get_astrbot_data_path

VERSION = "4.22.1"
VERSION = "4.22.0"
DB_PATH = os.path.join(get_astrbot_data_path(), "data_v4.db")
PERSONAL_WECHAT_CONFIG_METADATA = {
"weixin_oc_base_url": {
Expand Down Expand Up @@ -195,6 +195,15 @@
),
"agents": [],
},
# 增强版动态SubAgent配置(独立于subagent_orchestrator)
"enhanced_subagent": {
"enabled": False,
"log_level": "debug",
"max_subagent_count": 3,
"auto_cleanup_per_turn": True,
"shared_context_enabled": False,
"shared_context_maxlen": 200,
},
"provider_stt_settings": {
"enable": False,
"provider_id": "",
Expand Down Expand Up @@ -2442,17 +2451,17 @@ class ChatProviderTemplate(TypedDict):
"mimo-tts-style-prompt": {
"description": "风格提示词",
"type": "string",
"hint": "会以 <style>...</style> 标签形式添加到待合成文本开头,用于控制语速、情绪、角色或风格,例如 开心、变快、孙悟空、悄悄话。可留空。",
"hint": "用于控制生成语音的说话风格、语气或情绪,例如温柔、活泼、沉稳等。可留空。",
},
"mimo-tts-dialect": {
"description": "方言",
"type": "string",
"hint": "会与风格提示词一起写入开头的 <style>...</style> 标签中,例如 东北话、四川话、河南话、粤语。可留空。",
"hint": "指定生成语音时使用的方言或口音,例如四川话、粤语口音等。可留空。",
},
"mimo-tts-seed-text": {
"description": "种子文本",
"type": "string",
"hint": "作为可选的 user 消息发送,用于辅助调节语气和风格,不会拼接到待合成文本中。",
"hint": "用于引导音色和说话方式的参考文本,会影响生成语音的表达风格。",
},
"fishaudio-tts-character": {
"description": "character",
Expand Down
Loading