Skip to main content

vtcode_core/tools/registry/
mod.rs

1//! Tool registry and function declarations
2
3mod approval_recorder;
4mod assembly;
5mod availability_facade;
6mod builder;
7mod builtins;
8mod cache;
9mod catalog_facade;
10mod cgp_facade;
11mod circuit_breaker;
12mod commands_facade;
13mod config_helpers;
14mod distributed;
15mod dual_output;
16mod error;
17mod execution_attempts;
18mod execution_facade;
19mod execution_handlers;
20mod execution_history;
21mod execution_kernel;
22mod execution_request;
23mod execution_results;
24mod execution_stages;
25mod executors;
26pub mod file_helpers;
27mod file_monitor_facade;
28mod harness;
29mod harness_facade;
30mod history_facade;
31pub mod interfaces;
32mod inventory;
33mod inventory_facade;
34mod justification;
35mod justification_extractor;
36pub mod labels;
37mod maintenance;
38mod mcp_facade;
39mod mcp_helpers;
40mod metrics_facade;
41mod optimization_facade;
42mod output_processing;
43mod pack;
44mod pack_impls;
45mod patch_recovery;
46mod planning_workflow_checks;
47mod planning_workflow_facade;
48mod policy;
49mod policy_facade;
50mod progress_facade;
51mod pty;
52mod pty_facade;
53mod reentrancy;
54mod registration;
55mod registration_facade;
56mod resiliency;
57mod resiliency_facade;
58mod risk_scorer;
59mod runtime_config_facade;
60mod sandbox_facade;
61mod scheduler_facade;
62mod search_runtime_facade;
63mod shell_policy;
64mod shell_policy_facade;
65mod spool_processing;
66mod spooler_facade;
67mod subagent_facade;
68mod telemetry;
69mod timeout;
70mod timeout_category;
71mod timeout_facade;
72mod tool_catalog_facade;
73mod tool_executor_impl;
74mod tool_search_index;
75mod trait_impls;
76mod unified_actions;
77mod utils;
78
79pub use approval_recorder::ApprovalRecorder;
80pub use cgp_facade::CgpRuntimeMode;
81pub use cgp_facade::native_cgp_tool_factory;
82pub use cgp_facade::wrap_registered_native_tool;
83pub use error::{ToolErrorType, ToolExecutionError};
84pub use execution_history::{
85    HarnessContextSnapshot, ToolExecutionHistory, ToolExecutionRecord, ToolTaskTelemetrySnapshot,
86};
87pub use execution_kernel::ToolPreflightOutcome;
88pub use execution_request::{ExecSettlementMode, ExecutionPolicySnapshot, ToolExecutionOutcome, ToolExecutionRequest};
89pub use executors::sandbox_policy_from_runtime_config;
90pub use harness::HarnessContext;
91pub use justification::{ApprovalPattern, JustificationManager, ToolJustification};
92pub use justification_extractor::JustificationExtractor;
93pub use pty::{PtySessionGuard, PtySessionManager};
94pub use registration::{
95    NativeCgpToolFactory, ToolCatalogSource, ToolExecutorFn, ToolHandler, ToolNetworkAccess, ToolRegistration,
96    ToolRegistrationSpec as ToolMetadata,
97};
98pub use resiliency::{ResiliencyContext, ToolFailureTracker};
99pub use risk_scorer::{RiskLevel, ToolRiskContext, ToolRiskScorer, ToolSource, WorkspaceTrust};
100pub use shell_policy::ShellPolicyChecker;
101pub use telemetry::ToolTelemetryEvent;
102pub use timeout::{AdaptiveTimeoutTuning, ToolLatencyStats, ToolTimeoutCategory, ToolTimeoutPolicy};
103pub use tool_catalog_facade::{SessionToolCatalogState, ToolGroup, tool_groups};
104
105// Re-export trait interfaces for external consumers.
106pub use interfaces::{
107    McpBridge, PtySessionControl, SharedRegistry, ToolCatalog, ToolMetrics, ToolRegistryApi, ToolResilience,
108    ToolSecurity,
109};
110
111use assembly::ToolAssembly;
112use inventory::ToolInventory;
113use policy::ToolPolicyGateway;
114use utils::normalize_tool_output;
115
116use crate::tool_policy::ToolPolicy;
117use crate::tools::exec_session::ExecSessionManager;
118use crate::tools::handlers::PlanningWorkflowState;
119pub(super) use crate::tools::pty::PtyManager;
120use crate::tools::result::ToolResult as SplitToolResult;
121use crate::tools::safety_gateway::SafetyGateway;
122use indexmap::IndexMap;
123use parking_lot::Mutex; // Use parking_lot for better performance
124use rustc_hash::FxHashMap;
125use std::sync::{Arc, Weak};
126
127use crate::exec::code_executor::{BuiltinToolExecutor, BuiltinToolInfo};
128use crate::mcp::McpClient;
129use crate::subagents::SubagentController;
130use crate::tools::edited_file_monitor::EditedFileMonitor;
131use async_trait::async_trait;
132use std::sync::RwLock;
133
134pub type SessionModelTools = Arc<tokio::sync::RwLock<Vec<crate::llm::provider::ToolDefinition>>>;
135
136/// Callback for tool progress and output streaming
137pub type ToolProgressCallback = Arc<dyn Fn(&str, &str) + Send + Sync>;
138
139use super::traits::Tool;
140
141#[cfg(test)]
142use crate::config::types::CapabilityLevel;
143
144/// Default window size for loop detection.
145const DEFAULT_LOOP_DETECT_WINDOW: usize = 5;
146
147#[derive(Clone)]
148pub struct ToolRegistry {
149    inventory: ToolInventory,
150    /// Persistent-memory settings captured with the workspace tool snapshot.
151    persistent_memory_config: Arc<crate::config::PersistentMemoryConfig>,
152    persistent_memory_enabled: bool,
153    edited_file_monitor: Arc<EditedFileMonitor>,
154    policy_gateway: Arc<ToolPolicyGateway>,
155    pty_sessions: PtySessionManager,
156    exec_sessions: ExecSessionManager,
157    mcp_client: Arc<parking_lot::RwLock<Option<Arc<McpClient>>>>,
158    mcp_tool_index: Arc<tokio::sync::RwLock<FxHashMap<String, Vec<String>>>>,
159    mcp_reverse_index: Arc<tokio::sync::RwLock<FxHashMap<String, String>>>,
160    timeout_policy: Arc<parking_lot::RwLock<ToolTimeoutPolicy>>,
161    execution_history: ToolExecutionHistory,
162    patch_recovery_reads: Arc<Mutex<patch_recovery::PatchRecoveryReads>>,
163    harness_context: HarnessContext,
164
165    // Mutable runtime state wrapped for concurrent access
166    resiliency: Arc<Mutex<ResiliencyContext>>,
167
168    /// MP-3: Circuit breaker for MCP client failures
169    mcp_circuit_breaker: Arc<circuit_breaker::McpCircuitBreaker>,
170    /// Shared per-tool circuit breaker state used by the runloop.
171    shared_circuit_breaker: Arc<RwLock<Option<Arc<crate::tools::circuit_breaker::CircuitBreaker>>>>,
172    initialized: Arc<std::sync::atomic::AtomicBool>,
173    // Security & Identity
174    shell_policy: Arc<RwLock<ShellPolicyChecker>>,
175    runtime_sandbox_config: Arc<RwLock<vtcode_config::SandboxConfig>>,
176    agent_type: Arc<RwLock<String>>,
177    // PTY Session Management
178    active_pty_sessions: Arc<RwLock<Option<Arc<std::sync::atomic::AtomicUsize>>>>,
179
180    // Caching
181    cached_available_tools: Arc<parking_lot::RwLock<Option<Vec<String>>>>,
182    /// Active model-facing profile used by catalogue and policy projections.
183    active_tool_profile: Arc<RwLock<crate::config::ToolProfile>>,
184    /// Callback for streaming tool output and progress
185    progress_callback: Arc<RwLock<Option<ToolProgressCallback>>>,
186    // Performance Observability
187    /// Total tool calls made in current session
188    tool_call_counter: Arc<std::sync::atomic::AtomicU64>,
189    /// Total PTY poll iterations (for monitoring CPU usage)
190    pty_poll_counter: Arc<std::sync::atomic::AtomicU64>,
191    /// Canonical `.vtcode/plans` directory, resolved once per registry for
192    /// the planning-mode hot path (`is_plan_file_operation`).
193    canonical_plans_dir: Arc<std::sync::OnceLock<std::path::PathBuf>>,
194    /// Shared metrics collector for reliability and execution observability
195    metrics: Arc<crate::metrics::MetricsCollector>,
196
197    // PERFORMANCE OPTIMIZATIONS - Actually integrated into the real registry
198    /// Memory pool for reducing allocations in hot paths
199    memory_pool: Arc<crate::core::memory_pool::MemoryPool>,
200    /// Hot cache for frequently accessed tools (reduces HashMap lookups)
201    hot_tool_cache: Arc<parking_lot::RwLock<lru::LruCache<String, Arc<dyn Tool>>>>,
202    /// Optimization configuration
203    optimization_config: vtcode_config::OptimizationConfig,
204
205    /// Composable middleware chain for pre/post tool execution hooks.
206    middleware: crate::tools::tool_middleware::MiddlewareChain,
207
208    /// Output spooler for dynamic context discovery (large outputs to files)
209    output_spooler: Arc<super::output_spooler::ToolOutputSpooler>,
210
211    /// Shared Planning workflow state (plan file tracking, active flag) for enter/exit tools
212    /// and read-only enforcement. This is the single source of truth for planning workflow;
213    /// use `is_planning_active()` / `enable_planning()` / `disable_planning()` as accessors.
214    planning_workflow_state: PlanningWorkflowState,
215    /// Saved policies for tools whose permissions are overridden during planning
216    /// workflow entry, so they can be restored on exit without disturbing other
217    /// user-configured policies.
218    planning_mode_policy_overrides: Arc<parking_lot::RwLock<Option<IndexMap<String, ToolPolicy>>>>,
219    /// Canonical safety gateway shared across registry execution surfaces.
220    safety_gateway: Arc<SafetyGateway>,
221    /// Active CGP runtime mode for wrapping registrations added after startup.
222    cgp_runtime_mode: Arc<RwLock<Option<CgpRuntimeMode>>>,
223    /// Canonical manifest-driven tool assembly used by routing, catalog projections, and policy sync.
224    tool_assembly: Arc<RwLock<ToolAssembly>>,
225    /// Registry-owned tool catalog snapshot cache shared by harnesses.
226    tool_catalog_state: Arc<SessionToolCatalogState>,
227    /// Shared subagent controller when the session enables delegated child agents.
228    subagent_controller: Arc<RwLock<Option<Arc<SubagentController>>>>,
229    matrix_worker: Arc<parking_lot::RwLock<Option<crate::subagents::matrix::MatrixWorkerContext>>>,
230    matrix_coordinator: Arc<std::sync::atomic::AtomicBool>,
231    /// Session-scoped scheduled prompts for interactive loops and cron tools.
232    session_scheduler: Arc<tokio::sync::Mutex<crate::scheduler::SessionScheduler>>,
233    /// Live model-facing tool definitions attached by the runloop.
234    session_model_tools: Arc<RwLock<Option<SessionModelTools>>>,
235    /// Weak self-reference used by the code executor's built-in tool bridge.
236    self_ref: Arc<RwLock<Option<Weak<ToolRegistry>>>>,
237}
238
239const BUILTIN_CODE_TOOLS: &[&str] = &[
240    crate::config::constants::tools::UNIFIED_FILE,
241    crate::config::constants::tools::CODE_SEARCH,
242    crate::config::constants::tools::WEB_FETCH,
243    crate::config::constants::tools::WEB_SEARCH,
244    crate::config::constants::tools::CRON,
245    crate::config::constants::tools::MEMORY,
246    crate::config::constants::tools::TASK_TRACKER,
247];
248
249fn builtin_code_tool_description(name: &str) -> String {
250    match name {
251        n if n == crate::config::constants::tools::UNIFIED_FILE => "Read, write, edit, move, copy, or delete files.",
252        n if n == crate::config::constants::tools::CODE_SEARCH => {
253            "Search code by query, with optional path, file_types, result_types, and max_results."
254        }
255        n if n == crate::config::constants::tools::WEB_FETCH => {
256            "Fetch a URL and return an analysed summary or markdown."
257        }
258        n if n == crate::config::constants::tools::WEB_SEARCH => "Run a web search and return ranked results.",
259        n if n == crate::config::constants::tools::CRON => "Manage scheduled prompts.",
260        n if n == crate::config::constants::tools::MEMORY => "Read or update persistent project memory.",
261        n if n == crate::config::constants::tools::TASK_TRACKER => "Track multi-step task checklists.",
262        _ => "Built-in VT Code tool.",
263    }
264    .to_string()
265}
266
267impl ToolRegistry {
268    pub fn set_self_ref(&self, registry: Arc<ToolRegistry>) {
269        *self.self_ref.write().unwrap_or_else(std::sync::PoisonError::into_inner) = Some(Arc::downgrade(&registry));
270    }
271
272    fn builtin_executor_for_code(&self) -> Option<Arc<dyn BuiltinToolExecutor>> {
273        self.self_ref
274            .read()
275            .unwrap_or_else(std::sync::PoisonError::into_inner)
276            .as_ref()
277            .and_then(Weak::upgrade)
278            .map(|registry| registry as Arc<dyn BuiltinToolExecutor>)
279    }
280}
281
282#[async_trait]
283impl BuiltinToolExecutor for ToolRegistry {
284    async fn execute_builtin_tool(
285        &self,
286        tool_name: &str,
287        args: &serde_json::Value,
288    ) -> anyhow::Result<serde_json::Value> {
289        if !BUILTIN_CODE_TOOLS.contains(&tool_name) {
290            anyhow::bail!("tool '{tool_name}' is not exposed to code snippets");
291        }
292        self.execute_tool(tool_name, args.clone()).await
293    }
294
295    fn list_builtin_tools(&self) -> anyhow::Result<Vec<BuiltinToolInfo>> {
296        Ok(BUILTIN_CODE_TOOLS
297            .iter()
298            .map(|name| BuiltinToolInfo {
299                name: (*name).to_string(),
300                description: builtin_code_tool_description(name),
301            })
302            .collect())
303    }
304}
305
306#[derive(Debug, Clone, Copy, PartialEq, Eq)]
307pub enum ToolPermissionDecision {
308    Allow,
309    Deny,
310    Prompt,
311}
312
313#[cfg(test)]
314mod tests;