| from __future__ import annotations |
|
|
| from typing import Any |
|
|
| from astrbot import logger |
| from astrbot.core.agent.agent import Agent |
| from astrbot.core.agent.handoff import HandoffTool |
| from astrbot.core.persona_mgr import PersonaManager |
| from astrbot.core.provider.func_tool_manager import FunctionToolManager |
|
|
|
|
| class SubAgentOrchestrator: |
| """Loads subagent definitions from config and registers handoff tools. |
| |
| This is intentionally lightweight: it does not execute agents itself. |
| Execution happens via HandoffTool in FunctionToolExecutor. |
| """ |
|
|
| def __init__( |
| self, tool_mgr: FunctionToolManager, persona_mgr: PersonaManager |
| ) -> None: |
| self._tool_mgr = tool_mgr |
| self._persona_mgr = persona_mgr |
| self.handoffs: list[HandoffTool] = [] |
|
|
| async def reload_from_config(self, cfg: dict[str, Any]) -> None: |
| from astrbot.core.astr_agent_context import AstrAgentContext |
|
|
| agents = cfg.get("agents", []) |
| if not isinstance(agents, list): |
| logger.warning("subagent_orchestrator.agents must be a list") |
| return |
|
|
| handoffs: list[HandoffTool] = [] |
| for item in agents: |
| if not isinstance(item, dict): |
| continue |
| if not item.get("enabled", True): |
| continue |
|
|
| name = str(item.get("name", "")).strip() |
| if not name: |
| continue |
|
|
| persona_id = item.get("persona_id") |
| persona_data = None |
| if persona_id: |
| try: |
| persona_data = await self._persona_mgr.get_persona(persona_id) |
| except StopIteration: |
| logger.warning( |
| "SubAgent persona %s not found, fallback to inline prompt.", |
| persona_id, |
| ) |
|
|
| instructions = str(item.get("system_prompt", "")).strip() |
| public_description = str(item.get("public_description", "")).strip() |
| provider_id = item.get("provider_id") |
| if provider_id is not None: |
| provider_id = str(provider_id).strip() or None |
| tools = item.get("tools", []) |
| begin_dialogs = None |
|
|
| if persona_data: |
| instructions = persona_data.system_prompt or instructions |
| begin_dialogs = persona_data.begin_dialogs |
| tools = persona_data.tools |
| if public_description == "" and persona_data.system_prompt: |
| public_description = persona_data.system_prompt[:120] |
| if tools is None: |
| tools = None |
| elif not isinstance(tools, list): |
| tools = [] |
| else: |
| tools = [str(t).strip() for t in tools if str(t).strip()] |
|
|
| agent = Agent[AstrAgentContext]( |
| name=name, |
| instructions=instructions, |
| tools=tools, |
| ) |
| agent.begin_dialogs = begin_dialogs |
| |
| |
| handoff = HandoffTool( |
| agent=agent, |
| tool_description=public_description or None, |
| ) |
|
|
| |
| handoff.provider_id = provider_id |
|
|
| handoffs.append(handoff) |
|
|
| for handoff in handoffs: |
| logger.info(f"Registered subagent handoff tool: {handoff.name}") |
|
|
| self.handoffs = handoffs |
|
|