vtcode_config/core/
tools.rs

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