vtcode_config/core/
automation.rs1use crate::constants::{defaults, tool_limits, tools};
2use serde::{Deserialize, Serialize};
3use std::path::PathBuf;
4
5#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
7#[derive(Debug, Clone, Deserialize, Serialize, Default)]
8pub struct AutomationConfig {
9 #[serde(default)]
11 pub full_auto: FullAutoConfig,
12 #[serde(default)]
14 pub scheduled_tasks: ScheduledTasksConfig,
15 #[serde(default)]
17 pub loop_engine: LoopEngineConfig,
18}
19
20#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
22#[derive(Debug, Clone, Deserialize, Serialize)]
23pub struct ScheduledTasksConfig {
24 #[serde(default = "default_scheduled_tasks_enabled")]
26 pub enabled: bool,
27}
28
29impl Default for ScheduledTasksConfig {
30 fn default() -> Self {
31 Self { enabled: default_scheduled_tasks_enabled() }
32 }
33}
34
35#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
37#[derive(Debug, Clone, Deserialize, Serialize)]
38pub struct FullAutoConfig {
39 #[serde(default = "default_full_auto_enabled")]
41 pub enabled: bool,
42
43 #[serde(default = "default_full_auto_max_turns")]
45 pub max_turns: usize,
46
47 #[serde(default = "default_full_auto_allowed_tools")]
49 pub allowed_tools: Vec<String>,
50
51 #[serde(default = "default_require_profile_ack")]
53 pub require_profile_ack: bool,
54
55 #[serde(default)]
57 pub profile_path: Option<PathBuf>,
58
59 #[serde(default)]
64 verify_mutations: bool,
65
66 #[serde(default = "default_auto_grant_tool_limits")]
71 pub auto_grant_tool_limits: bool,
72}
73
74impl Default for FullAutoConfig {
75 fn default() -> Self {
76 Self {
77 enabled: default_full_auto_enabled(),
78 max_turns: default_full_auto_max_turns(),
79 allowed_tools: default_full_auto_allowed_tools(),
80 require_profile_ack: default_require_profile_ack(),
81 profile_path: None,
82 verify_mutations: false,
83 auto_grant_tool_limits: default_auto_grant_tool_limits(),
84 }
85 }
86}
87
88fn default_full_auto_enabled() -> bool {
89 false
90}
91
92fn default_scheduled_tasks_enabled() -> bool {
93 false
94}
95
96fn default_full_auto_allowed_tools() -> Vec<String> {
97 vec![
98 tools::EXEC_COMMAND.to_string(),
99 tools::WRITE_STDIN.to_string(),
100 tools::APPLY_PATCH.to_string(),
101 tools::CODE_SEARCH.to_string(),
102 tools::TASK_TRACKER.to_string(),
106 tools::START_PLANNING.to_string(),
107 tools::REQUEST_USER_INPUT.to_string(),
108 ]
109}
110
111fn default_require_profile_ack() -> bool {
112 true
113}
114
115fn default_auto_grant_tool_limits() -> bool {
116 true
117}
118
119fn default_full_auto_max_turns() -> usize {
120 tool_limits::DEFAULT_FULL_AUTO_MAX_TURNS
121}
122
123#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
125#[derive(Debug, Clone, Deserialize, Serialize)]
126pub struct LoopEngineConfig {
127 #[serde(default)]
130 enabled: bool,
131
132 #[serde(default)]
135 max_iterations: Option<usize>,
136
137 #[serde(default = "default_reconcile_on_complete")]
140 pub reconcile_on_complete: bool,
141
142 #[serde(default)]
145 preload_skills: Vec<String>,
146}
147
148impl Default for LoopEngineConfig {
149 fn default() -> Self {
150 Self {
151 enabled: false,
152 max_iterations: None,
153 reconcile_on_complete: default_reconcile_on_complete(),
154 preload_skills: Vec::new(),
155 }
156 }
157}
158
159fn default_reconcile_on_complete() -> bool {
160 true
161}
162
163pub fn loop_engine_enabled(config: &AutomationConfig) -> bool {
166 if std::env::var("VTCODE_DISABLE_LOOP_ENGINE").is_ok() {
167 return false;
168 }
169 config.loop_engine.enabled
170}
171
172#[cfg(test)]
173mod tests {
174 use super::*;
175
176 #[test]
177 fn full_auto_defaults_to_shared_turn_budget() {
178 assert_eq!(FullAutoConfig::default().max_turns, tool_limits::DEFAULT_FULL_AUTO_MAX_TURNS);
179 }
180
181 #[test]
182 fn full_auto_grants_loop_limits_without_prompting_by_default() {
183 assert!(FullAutoConfig::default().auto_grant_tool_limits);
184 }
185
186 #[test]
187 fn full_auto_loop_grants_survive_missing_field_for_backward_compatibility() {
188 let without_field = toml::from_str::<FullAutoConfig>("enabled = true").expect("minimal full-auto parses");
189 assert!(without_field.auto_grant_tool_limits);
190
191 let opted_out = toml::from_str::<FullAutoConfig>("enabled = true\nauto_grant_tool_limits = false")
192 .expect("explicit opt-out parses");
193 assert!(!opted_out.auto_grant_tool_limits);
194 }
195}