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