vtcode_config/core/
tools.rs

1use indexmap::IndexMap;
2use serde::{Deserialize, Serialize};
3
4use crate::constants::{defaults, tools};
5use crate::core::plugins::PluginRuntimeConfig;
6
7/// Tools configuration
8#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
9#[derive(Debug, Clone, Deserialize, Serialize)]
10pub struct ToolsConfig {
11    /// Default policy for tools not explicitly listed
12    #[serde(default = "default_tool_policy")]
13    pub default_policy: ToolPolicy,
14
15    /// Specific tool policies
16    #[serde(default)]
17    #[cfg_attr(
18        feature = "schema",
19        schemars(with = "std::collections::BTreeMap<String, ToolPolicy>")
20    )]
21    pub policies: IndexMap<String, ToolPolicy>,
22
23    /// Maximum inner tool-call loops per user turn
24    ///
25    /// Prevents infinite tool-calling cycles in interactive chat. This limits how
26    /// many back-and-forths the agent will perform executing tools and
27    /// re-asking the model before returning a final answer.
28    ///
29    #[serde(default = "default_max_tool_loops")]
30    pub max_tool_loops: usize,
31
32    /// Maximum number of times the same tool invocation can be retried with the
33    /// identical arguments within a single turn.
34    #[serde(default = "default_max_repeated_tool_calls")]
35    pub max_repeated_tool_calls: usize,
36
37    /// Optional per-second rate limit for tool calls to smooth bursty retries.
38    /// When unset, the runtime defaults apply.
39    #[serde(default = "default_max_tool_rate_per_second")]
40    pub max_tool_rate_per_second: Option<usize>,
41
42    /// Web Fetch tool security configuration
43    #[serde(default)]
44    pub web_fetch: WebFetchConfig,
45
46    /// Dynamic plugin runtime configuration
47    #[serde(default)]
48    pub plugins: PluginRuntimeConfig,
49}
50
51/// Web Fetch tool security configuration
52#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
53#[derive(Debug, Clone, Deserialize, Serialize)]
54pub struct WebFetchConfig {
55    /// Security mode: "restricted" (blocklist) or "whitelist" (allowlist)
56    #[serde(default = "default_web_fetch_mode")]
57    pub mode: String,
58
59    /// Enable dynamic blocklist loading from external file
60    #[serde(default)]
61    pub dynamic_blocklist_enabled: bool,
62
63    /// Path to dynamic blocklist file
64    #[serde(default)]
65    pub dynamic_blocklist_path: String,
66
67    /// Enable dynamic whitelist loading from external file
68    #[serde(default)]
69    pub dynamic_whitelist_enabled: bool,
70
71    /// Path to dynamic whitelist file
72    #[serde(default)]
73    pub dynamic_whitelist_path: String,
74
75    /// Inline blocklist - Additional domains to block
76    #[serde(default)]
77    pub blocked_domains: Vec<String>,
78
79    /// Inline whitelist - Domains to allow in restricted mode
80    #[serde(default)]
81    pub allowed_domains: Vec<String>,
82
83    /// Additional blocked patterns
84    #[serde(default)]
85    pub blocked_patterns: Vec<String>,
86
87    /// Enable audit logging of URL validation decisions
88    #[serde(default)]
89    pub enable_audit_logging: bool,
90
91    /// Path to audit log file
92    #[serde(default)]
93    pub audit_log_path: String,
94
95    /// Strict HTTPS-only mode
96    #[serde(default = "default_strict_https")]
97    pub strict_https_only: bool,
98}
99
100impl Default for ToolsConfig {
101    fn default() -> Self {
102        let policies = DEFAULT_TOOL_POLICIES
103            .iter()
104            .map(|(tool, policy)| ((*tool).into(), *policy))
105            .collect::<IndexMap<_, _>>();
106        Self {
107            default_policy: default_tool_policy(),
108            policies,
109            max_tool_loops: default_max_tool_loops(),
110            max_repeated_tool_calls: default_max_repeated_tool_calls(),
111            max_tool_rate_per_second: default_max_tool_rate_per_second(),
112            web_fetch: WebFetchConfig::default(),
113            plugins: PluginRuntimeConfig::default(),
114        }
115    }
116}
117
118const DEFAULT_BLOCKLIST_PATH: &str = "~/.vtcode/web_fetch_blocklist.json";
119const DEFAULT_WHITELIST_PATH: &str = "~/.vtcode/web_fetch_whitelist.json";
120const DEFAULT_AUDIT_LOG_PATH: &str = "~/.vtcode/web_fetch_audit.log";
121
122impl Default for WebFetchConfig {
123    fn default() -> Self {
124        Self {
125            mode: default_web_fetch_mode(),
126            dynamic_blocklist_enabled: false,
127            dynamic_blocklist_path: DEFAULT_BLOCKLIST_PATH.into(),
128            dynamic_whitelist_enabled: false,
129            dynamic_whitelist_path: DEFAULT_WHITELIST_PATH.into(),
130            blocked_domains: Vec::new(),
131            allowed_domains: Vec::new(),
132            blocked_patterns: Vec::new(),
133            enable_audit_logging: false,
134            audit_log_path: DEFAULT_AUDIT_LOG_PATH.into(),
135            strict_https_only: true,
136        }
137    }
138}
139
140/// Tool execution policy
141#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
142#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)]
143#[serde(rename_all = "lowercase")]
144pub enum ToolPolicy {
145    /// Allow execution without confirmation
146    Allow,
147    /// Prompt user for confirmation
148    Prompt,
149    /// Deny execution
150    Deny,
151}
152
153#[inline]
154const fn default_tool_policy() -> ToolPolicy {
155    ToolPolicy::Prompt
156}
157
158#[inline]
159const fn default_max_tool_loops() -> usize {
160    defaults::DEFAULT_MAX_TOOL_LOOPS
161}
162
163#[inline]
164const fn default_max_repeated_tool_calls() -> usize {
165    defaults::DEFAULT_MAX_REPEATED_TOOL_CALLS
166}
167
168#[inline]
169const fn default_max_tool_rate_per_second() -> Option<usize> {
170    None
171}
172
173#[inline]
174fn default_web_fetch_mode() -> String {
175    "restricted".into()
176}
177
178fn default_strict_https() -> bool {
179    true
180}
181
182const DEFAULT_TOOL_POLICIES: &[(&str, ToolPolicy)] = &[
183    // File operations (non-destructive)
184    (tools::LIST_FILES, ToolPolicy::Allow),
185    (tools::GREP_FILE, ToolPolicy::Allow),
186    (tools::READ_FILE, ToolPolicy::Allow),
187    // File operations (write/create)
188    (tools::WRITE_FILE, ToolPolicy::Allow),
189    (tools::EDIT_FILE, ToolPolicy::Allow),
190    (tools::CREATE_FILE, ToolPolicy::Allow),
191    // File operations (destructive - require confirmation)
192    (tools::DELETE_FILE, ToolPolicy::Prompt),
193    (tools::APPLY_PATCH, ToolPolicy::Prompt),
194    (tools::SEARCH_REPLACE, ToolPolicy::Prompt),
195    // PTY/Terminal operations
196    (tools::RUN_PTY_CMD, ToolPolicy::Prompt),
197    (tools::CREATE_PTY_SESSION, ToolPolicy::Allow),
198    (tools::READ_PTY_SESSION, ToolPolicy::Allow),
199    (tools::LIST_PTY_SESSIONS, ToolPolicy::Allow),
200    (tools::RESIZE_PTY_SESSION, ToolPolicy::Allow),
201    (tools::SEND_PTY_INPUT, ToolPolicy::Prompt),
202    (tools::CLOSE_PTY_SESSION, ToolPolicy::Allow),
203    // Code execution (requires confirmation)
204    (tools::EXECUTE_CODE, ToolPolicy::Prompt),
205    // Planning and meta tools
206    (tools::SEARCH_TOOLS, ToolPolicy::Allow),
207    (tools::SKILL, ToolPolicy::Allow),
208    // Diagnostic and introspection tools
209    // Web operations (requires confirmation)
210    (tools::WEB_FETCH, ToolPolicy::Prompt),
211];