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
37impl Default for ToolsConfig {
38    fn default() -> Self {
39        let mut policies = IndexMap::new();
40        policies.insert(tools::GREP_FILE.to_string(), ToolPolicy::Allow);
41        policies.insert(tools::LIST_FILES.to_string(), ToolPolicy::Allow);
42        policies.insert(tools::UPDATE_PLAN.to_string(), ToolPolicy::Allow);
43        policies.insert(tools::READ_FILE.to_string(), ToolPolicy::Allow);
44        policies.insert(tools::GIT_DIFF.to_string(), ToolPolicy::Allow);
45        policies.insert(tools::AST_GREP_SEARCH.to_string(), ToolPolicy::Allow);
46        policies.insert(tools::CLOSE_PTY_SESSION.to_string(), ToolPolicy::Allow);
47        policies.insert(tools::CREATE_PTY_SESSION.to_string(), ToolPolicy::Allow);
48        policies.insert(tools::LIST_PTY_SESSIONS.to_string(), ToolPolicy::Allow);
49        policies.insert(tools::READ_PTY_SESSION.to_string(), ToolPolicy::Allow);
50        policies.insert(tools::RESIZE_PTY_SESSION.to_string(), ToolPolicy::Allow);
51        policies.insert(tools::CURL.to_string(), ToolPolicy::Prompt);
52        policies.insert(tools::RUN_COMMAND.to_string(), ToolPolicy::Prompt);
53        policies.insert(tools::SEND_PTY_INPUT.to_string(), ToolPolicy::Prompt);
54        policies.insert(tools::WRITE_FILE.to_string(), ToolPolicy::Allow);
55        policies.insert(tools::EDIT_FILE.to_string(), ToolPolicy::Allow);
56        policies.insert(tools::APPLY_PATCH.to_string(), ToolPolicy::Prompt);
57        Self {
58            default_policy: default_tool_policy(),
59            policies,
60            max_tool_loops: default_max_tool_loops(),
61            max_repeated_tool_calls: default_max_repeated_tool_calls(),
62        }
63    }
64}
65
66/// Tool execution policy
67#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
68#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
69#[serde(rename_all = "lowercase")]
70pub enum ToolPolicy {
71    /// Allow execution without confirmation
72    Allow,
73    /// Prompt user for confirmation
74    Prompt,
75    /// Deny execution
76    Deny,
77}
78
79fn default_tool_policy() -> ToolPolicy {
80    ToolPolicy::Prompt
81}
82
83fn default_max_tool_loops() -> usize {
84    defaults::DEFAULT_MAX_TOOL_LOOPS
85}
86
87fn default_max_repeated_tool_calls() -> usize {
88    defaults::DEFAULT_MAX_REPEATED_TOOL_CALLS
89}