Skip to content

Commit a9cf8d3

Browse files
committed
添加Reset工具
1 parent 58d5141 commit a9cf8d3

2 files changed

Lines changed: 102 additions & 41 deletions

File tree

astrbot/core/astr_main_agent.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -949,10 +949,11 @@ def _apply_enhanced_subagent_tools(
949949

950950
try:
951951
from astrbot.core.dynamic_subagent_manager import (
952-
CLEANUP_DYNAMIC_SUBAGENT_TOOL,
953952
CREATE_DYNAMIC_SUBAGENT_TOOL,
954953
LIST_DYNAMIC_SUBAGENTS_TOOL,
955954
PROTECT_SUBAGENT_TOOL,
955+
REMOVE_DYNAMIC_SUBAGENT_TOOL,
956+
RESET_SUBAGENT_TOOL,
956957
SEND_SHARED_CONTEXT_TOOL_FOR_MAIN_AGENT,
957958
UNPROTECT_SUBAGENT_TOOL,
958959
VIEW_SHARED_CONTEXT_TOOL,
@@ -962,7 +963,8 @@ def _apply_enhanced_subagent_tools(
962963

963964
# Register dynamic SubAgent management tools
964965
req.func_tool.add_tool(CREATE_DYNAMIC_SUBAGENT_TOOL)
965-
req.func_tool.add_tool(CLEANUP_DYNAMIC_SUBAGENT_TOOL)
966+
req.func_tool.add_tool(RESET_SUBAGENT_TOOL)
967+
req.func_tool.add_tool(REMOVE_DYNAMIC_SUBAGENT_TOOL)
966968
req.func_tool.add_tool(LIST_DYNAMIC_SUBAGENTS_TOOL)
967969
if DynamicSubAgentManager.is_auto_cleanup_per_turn():
968970
req.func_tool.add_tool(PROTECT_SUBAGENT_TOOL)

astrbot/core/dynamic_subagent_manager.py

Lines changed: 98 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ def _cleanup_single_subagent(cls, session_id: str, agent_name: str) -> None:
213213
session.agent_histories.pop(agent_name, None)
214214
SubAgentLogger.info(
215215
session_id,
216-
"DynamicSubAgentManager:auto_cleanup",
216+
"DynamicSubAgentrManager:auto_cleanup",
217217
f"Auto cleaned: {agent_name}",
218218
agent_name,
219219
)
@@ -309,19 +309,25 @@ def get_subagent_tools(cls, session_id: str, agent_name: str) -> list | None:
309309
return config.tools
310310

311311
@classmethod
312-
def clear_subagent_history(cls, session_id: str, agent_name: str) -> None:
312+
def clear_subagent_history(cls, session_id: str, agent_name: str) -> str:
313313
"""Clear conversation history for a subagent"""
314314
session = cls.get_session(session_id)
315315
if not session:
316-
return
316+
return f"__HISTORY_CLEARED_FAILED_: Session_id {session_id} does not exist."
317317
if agent_name in session.agent_histories:
318318
session.agent_histories.pop(agent_name)
319+
320+
if session.shared_context_enabled:
321+
cls.cleanup_shared_context_by_agent(session_id, agent_name)
319322
SubAgentLogger.debug(
320323
session_id,
321324
"DynamicSubAgentManager:history",
322325
f"Cleared history for: {agent_name}",
323326
agent_name,
324327
)
328+
return "__HISTORY_CLEARED__"
329+
else:
330+
return f"__HISTORY_CLEARED_FAILED_: Agent name {agent_name} not found. Available names {list(session.agents.keys())}"
325331

326332
@classmethod
327333
def set_shared_context_enabled(cls, session_id: str, enabled: bool) -> None:
@@ -342,7 +348,7 @@ def add_shared_context(
342348
context_type: str,
343349
content: str,
344350
target: str = "all",
345-
) -> None:
351+
) -> str:
346352
"""Add a message to the shared context
347353
348354
Args:
@@ -355,7 +361,11 @@ def add_shared_context(
355361

356362
session = cls.get_or_create_session(session_id)
357363
if not session.shared_context_enabled:
358-
return
364+
return "__SHARED_CONTEXT_ADDED_FAILED__: Shared context disabled."
365+
if (sender not in list(session.agents.keys())) and (sender != "System"):
366+
return f"__SHARED_CONTEXT_ADDED_FAILED__: Sender name {sender} not found. Available names {list(session.agents.keys())}"
367+
if (target not in list(session.agents.keys())) and (target != "all"):
368+
return f"__SHARED_CONTEXT_ADDED_FAILED__: Target name {sender} not found. Available names {list(session.agents.keys())} and 'all' "
359369

360370
if len(session.shared_context) >= cls._shared_context_maxlen:
361371
# 删除最旧的消息
@@ -378,6 +388,7 @@ def add_shared_context(
378388
f"[{context_type}] {sender} -> {target}: {content[:50]}...",
379389
sender,
380390
)
391+
return "__SHARED_CONTEXT_ADDED__"
381392

382393
@classmethod
383394
def get_shared_context(cls, session_id: str, filter_by_agent: str = None) -> list:
@@ -582,22 +593,30 @@ async def cleanup_session(cls, session_id: str) -> dict:
582593
return {"status": "cleaned", "cleaned_agents": cleaned}
583594

584595
@classmethod
585-
async def cleanup_subagent(cls, session_id: str, agent_name: str) -> bool:
596+
def remove_subagent(cls, session_id: str, agent_name: str) -> str:
586597
session = cls.get_session(session_id)
587-
if not session or agent_name not in session.agents:
588-
return False
589-
session.agents.pop(agent_name, None)
590-
session.handoff_tools.pop(agent_name, None)
591-
session.agent_histories.pop(agent_name, None)
592-
# 清理公共上下文中包含该Agent的内容
593-
cls.cleanup_shared_context_by_agent(session_id, agent_name)
594-
SubAgentLogger.info(
595-
session_id,
596-
"DynamicSubAgentManager:cleanup",
597-
f"Cleaned: {agent_name}",
598-
agent_name,
599-
)
600-
return True
598+
if agent_name == "all":
599+
session.agents.clear()
600+
session.handoff_tools.clear()
601+
session.agent_histories.clear()
602+
session.shared_context.clear()
603+
return "__SUBAGENT_REMOVED__"
604+
else:
605+
if agent_name not in session.agents:
606+
return f"__SUBAGENT_REMOVE_FAILED__: {agent_name} not found. Available subagent names {list(session.agents.keys())}"
607+
else:
608+
session.agents.pop(agent_name, None)
609+
session.handoff_tools.pop(agent_name, None)
610+
session.agent_histories.pop(agent_name, None)
611+
# 清理公共上下文中包含该Agent的内容
612+
cls.cleanup_shared_context_by_agent(session_id, agent_name)
613+
SubAgentLogger.info(
614+
session_id,
615+
"DynamicSubAgentManager:cleanup",
616+
f"Cleaned: {agent_name}",
617+
agent_name,
618+
)
619+
return "__SUBAGENT_REMOVED__"
601620

602621
@classmethod
603622
def get_handoff_tools_for_session(cls, session_id: str) -> list:
@@ -681,17 +700,22 @@ async def call(self, context, **kwargs) -> str:
681700
if handoff_tool:
682701
return f"__DYNAMIC_TOOL_CREATED__:{tool_name}:{handoff_tool.name}:Created. Use {tool_name} to delegate."
683702
else:
684-
return f"__FAILED_TO_CREATE_DYNAMIC_TOOL__:{tool_name}"
703+
return f"__DYNAMIC_TOOL_CREATE_FAILED_:{tool_name}"
685704

686705

687706
@dataclass
688-
class CleanupDynamicSubagentTool(FunctionTool):
689-
name: str = "cleanup_dynamic_subagent"
690-
description: str = "Clean up dynamic subagent."
707+
class RemoveDynamicSubagentTool(FunctionTool):
708+
name: str = "remove_dynamic_subagent"
709+
description: str = "Remove dynamic subagent by name."
691710
parameters: dict = field(
692711
default_factory=lambda: {
693712
"type": "object",
694-
"properties": {"name": {"type": "string"}},
713+
"properties": {
714+
"name": {
715+
"type": "string",
716+
"description": "Subagent name to remove. Use 'all' to remove all dynamic subagents.",
717+
}
718+
},
695719
"required": ["name"],
696720
}
697721
)
@@ -701,8 +725,11 @@ async def call(self, context, **kwargs) -> str:
701725
if not name:
702726
return "Error: name required"
703727
session_id = context.context.event.unified_msg_origin
704-
success = await DynamicSubAgentManager.cleanup_subagent(session_id, name)
705-
return f"Cleaned {name}" if success else f"Not found: {name}"
728+
remove_status = DynamicSubAgentManager.remove_subagent(session_id, name)
729+
if remove_status == "__SUBAGENT_REMOVED__":
730+
return f"Cleaned {name} Subagent"
731+
else:
732+
return remove_status
706733

707734

708735
@dataclass
@@ -748,7 +775,7 @@ async def call(self, context, **kwargs) -> str:
748775
session_id = context.context.event.unified_msg_origin
749776
session = DynamicSubAgentManager.get_or_create_session(session_id)
750777
if name not in session.agents:
751-
return f"Error: Subagent {name} not found"
778+
return f"Error: Subagent {name} not found. Available subagents: {session.agents.keys()}"
752779
DynamicSubAgentManager.protect_subagent(session_id, name)
753780
return f"Subagent {name} is now protected from auto cleanup"
754781

@@ -783,12 +810,32 @@ async def call(self, context, **kwargs) -> str:
783810
return f"Subagent {name} was not protected"
784811

785812

786-
# Tool instances
787-
CREATE_DYNAMIC_SUBAGENT_TOOL = CreateDynamicSubAgentTool()
788-
CLEANUP_DYNAMIC_SUBAGENT_TOOL = CleanupDynamicSubagentTool()
789-
LIST_DYNAMIC_SUBAGENTS_TOOL = ListDynamicSubagentsTool()
790-
PROTECT_SUBAGENT_TOOL = ProtectSubagentTool()
791-
UNPROTECT_SUBAGENT_TOOL = UnprotectSubagentTool()
813+
@dataclass
814+
class ResetSubAgentTool(FunctionTool):
815+
"""Tool to reset a subagent"""
816+
817+
name: str = "reset_subagent"
818+
description: str = "Reset an existing subagent. This will clean the dialog history of the subagent."
819+
parameters: dict = field(
820+
default_factory=lambda: {
821+
"type": "object",
822+
"properties": {
823+
"name": {"type": "string", "description": "Subagent name to reset"},
824+
},
825+
"required": ["name"],
826+
}
827+
)
828+
829+
async def call(self, context, **kwargs) -> str:
830+
name = kwargs.get("name", "")
831+
if not name:
832+
return "Error: name required"
833+
session_id = context.context.event.unified_msg_origin
834+
reset_status = DynamicSubAgentManager.clear_subagent_history(session_id, name)
835+
if reset_status == "__HISTORY_CLEARED__":
836+
return f"Subagent {name} was reset"
837+
else:
838+
return reset_status
792839

793840

794841
# Shared Context Tools
@@ -826,10 +873,13 @@ async def call(self, context, **kwargs) -> str:
826873
if not content:
827874
return "Error: content is required"
828875
session_id = context.context.event.unified_msg_origin
829-
DynamicSubAgentManager.add_shared_context(
876+
add_status = DynamicSubAgentManager.add_shared_context(
830877
session_id, "System", context_type, content, target
831878
)
832-
return f"Shared context updated: [{context_type}] System -> {target}: {content[:100]}{'...' if len(content) > 100 else ''}"
879+
if add_status == "__SHARED_CONTEXT_ADDED__":
880+
return f"Shared context updated: [{context_type}] System -> {target}: {content[:100]}{'...' if len(content) > 100 else ''}"
881+
else:
882+
return add_status
833883

834884

835885
@dataclass
@@ -873,10 +923,13 @@ async def call(self, context, **kwargs) -> str:
873923
if not content:
874924
return "Error: content is required"
875925
session_id = context.context.event.unified_msg_origin
876-
DynamicSubAgentManager.add_shared_context(
926+
add_status = DynamicSubAgentManager.add_shared_context(
877927
session_id, sender, context_type, content, target
878928
)
879-
return f"Shared context updated: [{context_type}] {sender} -> {target}: {content[:100]}{'...' if len(content) > 100 else ''}"
929+
if add_status == "__SHARED_CONTEXT_ADDED__":
930+
return f"Shared context updated: [{context_type}] {sender} -> {target}: {content[:100]}{'...' if len(content) > 100 else ''}"
931+
else:
932+
return add_status
880933

881934

882935
@dataclass
@@ -914,7 +967,13 @@ async def call(self, context, **kwargs) -> str:
914967
return "\n".join(lines)
915968

916969

917-
# Shared context tool instances
970+
# Tool instances
971+
CREATE_DYNAMIC_SUBAGENT_TOOL = CreateDynamicSubAgentTool()
972+
REMOVE_DYNAMIC_SUBAGENT_TOOL = RemoveDynamicSubagentTool()
973+
LIST_DYNAMIC_SUBAGENTS_TOOL = ListDynamicSubagentsTool()
974+
RESET_SUBAGENT_TOOL = ResetSubAgentTool()
975+
PROTECT_SUBAGENT_TOOL = ProtectSubagentTool()
976+
UNPROTECT_SUBAGENT_TOOL = UnprotectSubagentTool()
918977
SEND_SHARED_CONTEXT_TOOL = SendSharedContextTool()
919978
SEND_SHARED_CONTEXT_TOOL_FOR_MAIN_AGENT = SendSharedContextToolForMainAgent()
920979
VIEW_SHARED_CONTEXT_TOOL = ViewSharedContextTool()

0 commit comments

Comments
 (0)