Skip to main content

agent_diva_agent/agent_loop/
loop_tools.rs

1use super::{AgentLoop, ToolConfig};
2use crate::tool_assembly::{SubagentSpawner, ToolAssembly};
3use crate::tool_config::network::NetworkToolConfig;
4use agent_diva_core::config::MCPServerConfig;
5use agent_diva_tooling::ToolError;
6use std::collections::HashMap;
7use std::sync::Arc;
8use tracing::info;
9
10struct RuntimeSubagentSpawner {
11    manager: Arc<crate::subagent::SubagentManager>,
12}
13
14#[async_trait::async_trait]
15impl SubagentSpawner for RuntimeSubagentSpawner {
16    async fn spawn(
17        &self,
18        task: String,
19        label: Option<String>,
20        channel: String,
21        chat_id: String,
22    ) -> Result<String, ToolError> {
23        self.manager
24            .spawn(task, label, channel, chat_id)
25            .await
26            .map_err(|e| ToolError::ExecutionFailed(e.to_string()))
27    }
28}
29
30impl AgentLoop {
31    /// Register default tools (for use after construction)
32    pub fn register_default_tools(&mut self, tool_config: ToolConfig) {
33        self.tool_config = tool_config.clone();
34        let mut assembly = ToolAssembly::new(self.workspace.clone())
35            .builtin(tool_config.builtin)
36            .with_network_config(tool_config.network)
37            .with_exec_timeout(tool_config.exec_timeout)
38            .restrict_to_workspace(tool_config.restrict_to_workspace)
39            .mcp_servers(tool_config.mcp_servers)
40            .with_subagent_spawner(Arc::new(RuntimeSubagentSpawner {
41                manager: self.subagent_manager.clone(),
42            }))
43            .with_file_manager(self.file_manager.clone());
44        if let Some(cron_service) = tool_config.cron_service {
45            assembly = assembly.with_cron_service(cron_service);
46        }
47        self.tools = assembly.build();
48    }
49
50    pub(super) async fn apply_network_config(&mut self, network: NetworkToolConfig) {
51        self.tool_config.network = network.clone();
52        self.tools.unregister("web_search");
53        self.tools.unregister("web_fetch");
54        if self.tool_config.builtin.web_search && network.web.search.enabled {
55            self.tools.register(Arc::new(
56                agent_diva_tools::WebSearchTool::with_provider_and_max_results(
57                    network.web.search.provider.clone(),
58                    network.web.search.api_key.clone(),
59                    network.web.search.normalized_max_results(),
60                ),
61            ));
62        }
63        if self.tool_config.builtin.web_fetch && network.web.fetch.enabled {
64            self.tools
65                .register(Arc::new(agent_diva_tools::WebFetchTool::new()));
66        }
67        self.subagent_manager.update_network_config(network).await;
68        info!("Applied runtime network tool configuration update");
69    }
70
71    pub(super) async fn apply_mcp_config(&mut self, servers: HashMap<String, MCPServerConfig>) {
72        self.tool_config.mcp_servers = servers.clone();
73        for name in self
74            .tools
75            .tool_names()
76            .into_iter()
77            .filter(|name| name.starts_with("mcp_"))
78        {
79            self.tools.unregister(&name);
80        }
81
82        if self.tool_config.builtin.mcp {
83            for mcp_tool in agent_diva_tools::load_mcp_tools_sync(&servers) {
84                self.tools.register(mcp_tool);
85            }
86        }
87
88        self.subagent_manager.update_mcp_servers(servers).await;
89
90        info!("Applied runtime MCP tool configuration update");
91    }
92}