Skip to main content

vtcode_core/tools/registry/
interfaces.rs

1//! Trait interfaces for ToolRegistry subsystems.
2//!
3//! Each trait isolates a single responsibility from the monolithic `ToolRegistry`,
4//! enabling independent testing and substitutability. Implementors can be swapped
5//! for test doubles without constructing the full 35-field registry.
6//!
7//! # Design Principles
8//!
9//! - **One trait per concern**: security, PTY, MCP, resilience, catalog, metrics.
10//! - **Async where needed**: methods that touch I/O or locks are `async`.
11//! - **Send + Sync bounds**: all traits require thread-safety for `Arc<dyn Trait>` usage.
12//! - **Return owned types**: avoid lifetime entanglement with the implementor.
13
14use anyhow::Result;
15use serde_json::Value;
16use std::path::PathBuf;
17use std::sync::Arc;
18use std::time::Duration;
19
20use crate::config::types::CapabilityLevel;
21use crate::llm::provider::ToolDefinition;
22use crate::llm::providers::gemini::wire::FunctionDeclaration;
23use crate::tool_policy::ToolPolicy;
24use crate::tools::handlers::{SessionSurface, SessionToolsConfig, ToolCallError, ToolSchemaEntry};
25
26use super::{ToolExecutionRecord, ToolPermissionDecision, ToolRegistration};
27
28// ============================================================================
29// Security & Policy
30// ============================================================================
31
32/// Security and policy enforcement for tool execution.
33///
34/// Encapsulates policy evaluation, sandbox configuration, approval management,
35/// and shell policy checks. Implementors can provide different security
36/// postures (e.g., auto-approve for CI, prompt-for-everything in interactive).
37#[async_trait::async_trait]
38pub trait ToolSecurity: Send + Sync {
39    /// Evaluate the permission policy for a given tool.
40    async fn evaluate_tool_policy(&self, tool_name: &str) -> Result<ToolPermissionDecision>;
41
42    /// Get the current policy for a tool.
43    async fn get_tool_policy(&self, tool_name: &str) -> ToolPolicy;
44
45    /// Set the policy for a specific tool.
46    async fn set_tool_policy(&self, tool_name: &str, policy: ToolPolicy) -> Result<()>;
47
48    /// Mark a tool as pre-approved for a single execution.
49    async fn mark_tool_preapproved(&self, tool_name: &str);
50
51    /// Enable full-auto mode with an allowlist of tools.
52    async fn enable_full_auto_permission(&self, allowed_tools: &[String]);
53
54    /// Disable full-auto mode.
55    async fn disable_full_auto_permission(&self);
56
57    /// Check if a tool is allowed in full-auto mode.
58    async fn is_allowed_in_full_auto(&self, tool_name: &str) -> bool;
59
60    /// Check if a tool is denied by the full-auto allowlist.
61    async fn is_denied_in_full_auto(&self, tool_name: &str) -> bool;
62
63    /// Apply tool policies from configuration.
64    async fn apply_config_policies(&self, tools_config: &crate::config::ToolsConfig) -> Result<()>;
65
66    /// Get the current sandbox configuration.
67    fn sandbox_config(&self) -> vtcode_config::SandboxConfig;
68
69    /// Apply a sandbox configuration.
70    fn apply_sandbox_config(&self, config: &vtcode_config::SandboxConfig);
71
72    /// Persist an approval cache key for future sessions.
73    async fn persist_approval_cache_key(&self, key: &str) -> Result<()>;
74
75    /// Check if an approval has been persisted.
76    async fn has_persisted_approval(&self, key: &str) -> bool;
77}
78
79// ============================================================================
80// PTY Session Management
81// ============================================================================
82
83/// PTY (pseudo-terminal) session lifecycle management.
84///
85/// Manages creation, tracking, and teardown of PTY sessions used for
86/// interactive shell command execution.
87#[async_trait::async_trait]
88pub trait PtySessionControl: Send + Sync {
89    /// Check whether a new PTY session can be started.
90    fn can_start_session(&self) -> bool;
91
92    /// Get the number of currently active PTY sessions.
93    fn active_session_count(&self) -> usize;
94
95    /// Terminate all active PTY sessions.
96    async fn terminate_all_sessions(&self) -> Result<()>;
97
98    /// Get the exec session manager for subprocess tracking.
99    fn exec_session_manager(&self) -> crate::tools::exec_session::ExecSessionManager;
100}
101
102// ============================================================================
103// MCP Bridge
104// ============================================================================
105
106/// Model Context Protocol (MCP) tool bridge.
107///
108/// Provides access to external tools exposed via MCP servers. Handles
109/// client lifecycle, tool discovery, and execution delegation.
110#[async_trait::async_trait]
111pub trait McpBridge: Send + Sync {
112    /// Set or replace the MCP client.
113    async fn set_mcp_client(&self, client: Arc<crate::mcp::McpClient>);
114
115    /// Clear the current MCP client and all cached tool indexes.
116    async fn clear_mcp_client(&self);
117
118    /// Get the current MCP client, if any.
119    fn mcp_client(&self) -> Option<Arc<crate::mcp::McpClient>>;
120
121    /// List all tools available via MCP.
122    async fn list_mcp_tools(&self) -> Result<Vec<crate::mcp::McpToolInfo>>;
123
124    /// Check if a tool name corresponds to an MCP-provided tool.
125    async fn has_mcp_tool(&self, tool_name: &str) -> bool;
126
127    /// Execute a tool via the MCP client.
128    async fn execute_mcp_tool(&self, tool_name: &str, args: Value) -> Result<Value>;
129
130    /// Refresh MCP tool registrations from all connected servers.
131    async fn refresh_mcp_tools(&self) -> Result<()>;
132}
133
134// ============================================================================
135// Resilience (Circuit Breakers, Timeouts, Retries)
136// ============================================================================
137
138/// Execution resilience: circuit breakers, adaptive timeouts, failure tracking.
139///
140/// Protects the system from cascading failures by tracking tool execution
141/// health and applying backpressure when tools become unreliable.
142pub trait ToolResilience: Send + Sync {
143    /// Get the effective timeout for a tool category, considering adaptive tuning.
144    fn effective_timeout(&self, category: super::ToolTimeoutCategory) -> Option<Duration>;
145
146    /// Record a tool execution failure and check if circuit breaking should activate.
147    /// Returns `true` if the circuit breaker tripped.
148    fn record_failure(&self, category: super::ToolTimeoutCategory) -> bool;
149
150    /// Reset failure tracking for a tool category (e.g., after a success streak).
151    fn reset_failure(&self, category: super::ToolTimeoutCategory);
152
153    /// Record a tool execution latency for adaptive timeout tuning.
154    fn record_latency(&self, category: super::ToolTimeoutCategory, duration: Duration);
155
156    /// Check if the circuit breaker is tripped for a category. Returns the
157    /// recommended backoff duration if so.
158    fn should_circuit_break(&self, category: super::ToolTimeoutCategory) -> Option<Duration>;
159
160    /// Decay adaptive timeouts after a success streak (relax backpressure).
161    fn decay_adaptive_timeout(&self, category: super::ToolTimeoutCategory);
162}
163
164// ============================================================================
165// Tool Catalog (Registration, Lookup, Schema)
166// ============================================================================
167
168/// Tool catalog: registration, lookup, and schema access.
169///
170/// The catalog is the source of truth for which tools are available and how
171/// to invoke them. It supports dynamic registration (e.g., MCP tools added
172/// at runtime) and provides schema information for LLM tool-calling.
173#[async_trait::async_trait]
174pub trait ToolCatalog: Send + Sync {
175    /// Register a tool. Replaces any existing registration with the same name.
176    async fn register_tool(&self, registration: ToolRegistration) -> Result<()>;
177
178    /// Unregister a tool by name. Returns `true` if the tool existed.
179    async fn unregister_tool(&self, name: &str) -> Result<bool>;
180
181    /// Get a tool by name (with hot-cache optimization).
182    fn get_tool(&self, name: &str) -> Option<Arc<dyn crate::tools::traits::Tool>>;
183
184    /// Get the workspace root path.
185    fn workspace_root(&self) -> PathBuf;
186
187    /// List public tool names for a given surface and capability level.
188    async fn public_tool_names(&self, surface: SessionSurface, capability_level: CapabilityLevel) -> Vec<String>;
189
190    /// Get schema entries for all available tools.
191    async fn schema_entries(&self, config: SessionToolsConfig) -> Vec<ToolSchemaEntry>;
192
193    /// Get Gemini-style function declarations for tool-calling.
194    async fn function_declarations(&self, config: SessionToolsConfig) -> Vec<FunctionDeclaration>;
195
196    /// Get OpenAI/Anthropic-style tool definitions.
197    async fn model_tools(&self, config: SessionToolsConfig) -> Vec<ToolDefinition>;
198
199    /// Resolve a public tool name to its canonical registration name.
200    fn resolve_tool_name(&self, name: &str) -> Result<String, ToolCallError>;
201}
202
203// ============================================================================
204// Metrics & Execution History
205// ============================================================================
206
207/// Tool execution metrics and history tracking.
208///
209/// Records execution outcomes for observability, debugging, and loop detection.
210pub trait ToolMetrics: Send + Sync {
211    /// Record a tool execution for history and metrics.
212    fn record_execution(&self, record: ToolExecutionRecord);
213
214    /// Get the total number of tool calls in this session.
215    fn call_count(&self) -> u64;
216
217    /// Get the total PTY poll iterations (for CPU monitoring).
218    fn pty_poll_count(&self) -> u64;
219
220    /// Get the shared metrics collector for external observability.
221    fn metrics_collector(&self) -> Arc<crate::metrics::MetricsCollector>;
222}
223
224// ============================================================================
225// Composite Supertrait
226// ============================================================================
227
228/// Full tool registry API: the union of all subsystem traits.
229///
230/// Use this as a bound when a consumer needs access to the complete registry
231/// surface. For narrower needs, prefer the individual traits
232/// (`ToolCatalog`, `ToolSecurity`, etc.) to reduce coupling.
233///
234/// # Migration Guide
235///
236/// Current code passes `Arc<ToolRegistry>` or `&ToolRegistry` directly.
237/// To migrate a consumer to the trait-based interface:
238///
239/// 1. Replace `Arc<ToolRegistry>` with `Arc<dyn ToolRegistryApi>`.
240/// 2. Replace `&ToolRegistry` with `&dyn ToolRegistryApi`.
241/// 3. The consumer can now be tested with a mock that implements
242///    only the traits it actually uses.
243///
244/// `ToolRegistry` implements this supertrait automatically.
245pub trait ToolRegistryApi:
246    ToolSecurity + PtySessionControl + McpBridge + ToolResilience + ToolCatalog + ToolMetrics + Send + Sync + 'static
247{
248}
249
250/// Blanket impl: any type that implements all subsystem traits gets
251/// `ToolRegistryApi` for free.
252impl<T> ToolRegistryApi for T where
253    T: ToolSecurity
254        + PtySessionControl
255        + McpBridge
256        + ToolResilience
257        + ToolCatalog
258        + ToolMetrics
259        + Send
260        + Sync
261        + 'static
262{
263}
264
265/// Type alias for a shared, dynamically-dispatched tool registry.
266///
267/// Use this in struct fields and function signatures when the concrete
268/// `ToolRegistry` type is not needed. This enables test doubles.
269pub type SharedRegistry = Arc<dyn ToolRegistryApi>;