diff --git a/astrbot/core/astr_agent_tool_exec.py b/astrbot/core/astr_agent_tool_exec.py index eb3afd2d1..57f2b34b8 100644 --- a/astrbot/core/astr_agent_tool_exec.py +++ b/astrbot/core/astr_agent_tool_exec.py @@ -17,8 +17,7 @@ from astrbot.core.agent.run_context import ContextWrapper from astrbot.core.agent.tool import FunctionTool, ToolSet from astrbot.core.agent.tool_executor import BaseFunctionToolExecutor from astrbot.core.astr_agent_context import AstrAgentContext -from astrbot.core.computer.computer_tool_provider import ComputerToolProvider -from astrbot.core.tool_provider import ToolProviderContext + from astrbot.core.tools.prompts import ( BACKGROUND_TASK_RESULT_WOKE_SYSTEM_PROMPT, BACKGROUND_TASK_WOKE_USER_PROMPT, @@ -176,6 +175,9 @@ class FunctionToolExecutor(BaseFunctionToolExecutor[AstrAgentContext]): @classmethod def _get_runtime_computer_tools(cls, runtime: str) -> dict[str, FunctionTool]: + from astrbot.core.computer.computer_tool_provider import ComputerToolProvider + from astrbot.core.tool_provider import ToolProviderContext + provider = ComputerToolProvider() ctx = ToolProviderContext(computer_use_runtime=runtime) tools = provider.get_tools(ctx) @@ -469,11 +471,14 @@ class FunctionToolExecutor(BaseFunctionToolExecutor[AstrAgentContext]): message_type=session.message_type, ) cron_event.role = event.role + from astrbot.core.computer.computer_tool_provider import ComputerToolProvider + config = MainAgentBuildConfig( tool_call_timeout=3600, streaming_response=ctx.get_config() .get("provider_settings", {}) .get("stream", False), + tool_providers=[ComputerToolProvider()], ) req = ProviderRequest() diff --git a/astrbot/core/astr_main_agent.py b/astrbot/core/astr_main_agent.py index 863d4cb9a..680892c45 100644 --- a/astrbot/core/astr_main_agent.py +++ b/astrbot/core/astr_main_agent.py @@ -18,9 +18,7 @@ from astrbot.core.astr_agent_context import AgentContextWrapper, AstrAgentContex from astrbot.core.astr_agent_hooks import MAIN_AGENT_HOOKS from astrbot.core.astr_agent_run_util import AgentRunner from astrbot.core.astr_agent_tool_exec import FunctionToolExecutor -from astrbot.core.computer.computer_tool_provider import ComputerToolProvider -from astrbot.core.cron.cron_tool_provider import CronToolProvider -from astrbot.core.tool_provider import ToolProviderContext +from astrbot.core.tool_provider import ToolProvider, ToolProviderContext from astrbot.core.tools.kb_query import ( KNOWLEDGE_BASE_QUERY_TOOL, retrieve_knowledge_base, @@ -114,6 +112,9 @@ class MainAgentBuildConfig: computer_use_runtime: str = "local" """The runtime for agent computer use: none, local, or sandbox.""" sandbox_cfg: dict = field(default_factory=dict) + tool_providers: list[ToolProvider] = field(default_factory=list) + """Decoupled tool providers injected by the caller. + Each provider is queried for tools and system-prompt addons at build time.""" add_cron_tools: bool = True """This will add cron job management tools to the main agent for proactive cron job execution.""" provider_settings: dict = field(default_factory=dict) @@ -798,14 +799,7 @@ def _apply_llm_safety_mode(config: MainAgentBuildConfig, req: ProviderRequest) - # See astrbot.core.computer.computer_tool_provider for details. -def _proactive_cron_job_tools(req: ProviderRequest) -> None: - _cron_provider = CronToolProvider() - _cron_tools = _cron_provider.get_tools(ToolProviderContext()) - if _cron_tools: - if req.func_tool is None: - req.func_tool = ToolSet() - for _tool in _cron_tools: - req.func_tool.add_tool(_tool) + def _get_compress_provider( @@ -1032,22 +1026,23 @@ async def build_main_agent( if config.llm_safety_mode: _apply_llm_safety_mode(config, req) - # Computer-use tools (local / sandbox) via decoupled ToolProvider - _computer_provider = ComputerToolProvider() - _computer_ctx = ToolProviderContext( - computer_use_runtime=config.computer_use_runtime, - sandbox_cfg=config.sandbox_cfg, - session_id=req.session_id or "", - ) - _computer_tools = _computer_provider.get_tools(_computer_ctx) - if _computer_tools: - if req.func_tool is None: - req.func_tool = ToolSet() - for _tool in _computer_tools: - req.func_tool.add_tool(_tool) - _prompt_addon = _computer_provider.get_system_prompt_addon(_computer_ctx) - if _prompt_addon: - req.system_prompt = f"{req.system_prompt or ''}{_prompt_addon}" + # Decoupled tool providers — each provider injects its tools and prompt addons + if config.tool_providers: + _provider_ctx = ToolProviderContext( + computer_use_runtime=config.computer_use_runtime, + sandbox_cfg=config.sandbox_cfg, + session_id=req.session_id or "", + ) + for _tp in config.tool_providers: + _tp_tools = _tp.get_tools(_provider_ctx) + if _tp_tools: + if req.func_tool is None: + req.func_tool = ToolSet() + for _tool in _tp_tools: + req.func_tool.add_tool(_tool) + _tp_addon = _tp.get_system_prompt_addon(_provider_ctx) + if _tp_addon: + req.system_prompt = f"{req.system_prompt or ''}{_tp_addon}" agent_runner = AgentRunner() astr_agent_ctx = AstrAgentContext( @@ -1055,9 +1050,6 @@ async def build_main_agent( event=event, ) - if config.add_cron_tools: - _proactive_cron_job_tools(req) - if event.platform_meta.support_proactive_message: if req.func_tool is None: req.func_tool = ToolSet() diff --git a/astrbot/core/cron/manager.py b/astrbot/core/cron/manager.py index 0218fef56..843cc339b 100644 --- a/astrbot/core/cron/manager.py +++ b/astrbot/core/cron/manager.py @@ -309,10 +309,13 @@ class CronJobManager: if cron_payload.get("origin", "tool") == "api": cron_event.role = "admin" + from astrbot.core.computer.computer_tool_provider import ComputerToolProvider + config = MainAgentBuildConfig( tool_call_timeout=3600, llm_safety_mode=False, streaming_response=False, + tool_providers=[ComputerToolProvider()], ) req = ProviderRequest() conv = await _get_session_conv(event=cron_event, plugin_context=self.ctx) diff --git a/astrbot/core/pipeline/process_stage/method/agent_sub_stages/internal.py b/astrbot/core/pipeline/process_stage/method/agent_sub_stages/internal.py index 523d758a0..572c4214d 100644 --- a/astrbot/core/pipeline/process_stage/method/agent_sub_stages/internal.py +++ b/astrbot/core/pipeline/process_stage/method/agent_sub_stages/internal.py @@ -113,6 +113,14 @@ class InternalAgentSubStage(Stage): self.conv_manager = ctx.plugin_manager.context.conversation_manager + # Build decoupled tool providers + from astrbot.core.computer.computer_tool_provider import ComputerToolProvider + from astrbot.core.cron.cron_tool_provider import CronToolProvider + + _tool_providers = [ComputerToolProvider()] + if self.add_cron_tools: + _tool_providers.append(CronToolProvider()) + self.main_agent_cfg = MainAgentBuildConfig( tool_call_timeout=self.tool_call_timeout, tool_schema_mode=self.tool_schema_mode, @@ -131,6 +139,7 @@ class InternalAgentSubStage(Stage): safety_mode_strategy=self.safety_mode_strategy, computer_use_runtime=self.computer_use_runtime, sandbox_cfg=self.sandbox_cfg, + tool_providers=_tool_providers, add_cron_tools=self.add_cron_tools, provider_settings=settings, subagent_orchestrator=conf.get("subagent_orchestrator", {}),