Skip to main content

vtcode_config/
optimization.rs

1//! Configuration for performance optimization features
2
3use serde::{Deserialize, Serialize};
4
5/// Configuration for all optimization features
6#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
7#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8pub struct OptimizationConfig {
9    /// Memory pool configuration
10    #[serde(default)]
11    pub memory_pool: MemoryPoolConfig,
12
13    /// Tool registry optimization settings
14    #[serde(default)]
15    pub tool_registry: ToolRegistryConfig,
16
17    /// Async pipeline configuration
18    #[serde(default)]
19    async_pipeline: AsyncPipelineConfig,
20
21    /// LLM client optimization settings
22    #[serde(default)]
23    llm_client: LLMClientConfig,
24
25    /// Agent execution optimization
26    #[serde(default)]
27    pub agent_execution: AgentExecutionConfig,
28
29    /// Performance profiling settings
30    #[serde(default)]
31    profiling: ProfilingConfig,
32
33    /// File read cache configuration
34    #[serde(default)]
35    pub file_read_cache: FileReadCacheConfig,
36
37    /// Read-only command result cache
38    #[serde(default)]
39    pub command_cache: CommandCacheConfig,
40}
41
42/// File read cache configuration
43#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
44#[derive(Debug, Clone, Serialize, Deserialize)]
45#[serde(default)]
46pub struct FileReadCacheConfig {
47    /// Enable file read caching
48    pub enabled: bool,
49
50    /// Minimum file size (bytes) before caching
51    pub min_size_bytes: usize,
52
53    /// Maximum cached file size (bytes)
54    pub max_size_bytes: usize,
55
56    /// Cache TTL in seconds
57    pub ttl_secs: u64,
58
59    /// Maximum number of cached entries
60    max_entries: usize,
61
62    /// Absolute ceiling (in lines) for a single line-based `read_file` call.
63    /// Any read requesting more lines is clamped to this value and the response
64    /// exposes a `next_read_args` continuation to read the remainder.
65    #[serde(default = "default_max_read_lines")]
66    pub max_read_lines: usize,
67}
68
69/// Serde default for [`FileReadCacheConfig::max_read_lines`].
70fn default_max_read_lines() -> usize {
71    crate::constants::optimization::DEFAULT_MAX_READ_LINES
72}
73
74/// Read-only command cache configuration
75#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
76#[derive(Debug, Clone, Serialize, Deserialize)]
77#[serde(default)]
78pub struct CommandCacheConfig {
79    /// Enable command caching
80    pub enabled: bool,
81
82    /// Cache TTL in milliseconds
83    pub ttl_ms: u64,
84
85    /// Maximum number of cached entries
86    pub max_entries: usize,
87
88    /// Allowlist of command prefixes eligible for caching
89    pub allowlist: Vec<String>,
90}
91
92/// Memory pool configuration
93#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
94#[derive(Debug, Clone, Serialize, Deserialize)]
95#[serde(default)]
96pub struct MemoryPoolConfig {
97    /// Enable memory pool (can be disabled for debugging)
98    pub enabled: bool,
99
100    /// Maximum number of strings to pool
101    pub max_string_pool_size: usize,
102
103    /// Maximum number of Values to pool
104    pub max_value_pool_size: usize,
105
106    /// Maximum number of `Vec<String>` to pool
107    pub max_vec_pool_size: usize,
108}
109
110/// Tool registry optimization configuration
111#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
112#[derive(Debug, Clone, Serialize, Deserialize)]
113#[serde(default)]
114pub struct ToolRegistryConfig {
115    /// Enable optimized registry
116    pub use_optimized_registry: bool,
117
118    /// Maximum concurrent tool executions
119    max_concurrent_tools: usize,
120
121    /// Hot cache size for frequently used tools
122    pub hot_cache_size: usize,
123
124    /// Deprecated and unused for enforcement.
125    ///
126    /// The authoritative tool deadline is `[timeouts] default_ceiling_seconds`.
127    /// Kept as a private field so existing files keep parsing; it is not read
128    /// by the tool registry.
129    default_timeout_secs: u64,
130
131    /// When `true`, middleware `before_execute` failures are logged but do
132    /// not block the tool call (fail-open). When `false` (the default),
133    /// middleware errors deny execution (fail-closed).
134    pub middleware_fail_open: bool,
135}
136
137/// Async pipeline configuration
138#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
139#[derive(Debug, Clone, Serialize, Deserialize)]
140#[serde(default)]
141pub struct AsyncPipelineConfig {
142    /// Enable request batching
143    enable_batching: bool,
144
145    /// Enable result caching
146    enable_caching: bool,
147
148    /// Maximum batch size for tool requests
149    max_batch_size: usize,
150
151    /// Batch timeout in milliseconds
152    batch_timeout_ms: u64,
153
154    /// Result cache size
155    cache_size: usize,
156}
157
158/// LLM client optimization configuration
159#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
160#[derive(Debug, Clone, Serialize, Deserialize)]
161#[serde(default)]
162pub struct LLMClientConfig {
163    /// Enable connection pooling
164    enable_connection_pooling: bool,
165
166    /// Enable response caching
167    enable_response_caching: bool,
168
169    /// Enable request batching
170    enable_request_batching: bool,
171
172    /// Connection pool size
173    connection_pool_size: usize,
174
175    /// Response cache size
176    response_cache_size: usize,
177
178    /// Response cache TTL in seconds
179    cache_ttl_secs: u64,
180
181    /// Rate limit: requests per second
182    rate_limit_rps: f64,
183
184    /// Rate limit burst capacity
185    rate_limit_burst: usize,
186}
187
188/// Agent execution optimization configuration
189#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
190#[derive(Debug, Clone, Serialize, Deserialize)]
191#[serde(default)]
192pub struct AgentExecutionConfig {
193    /// Enable optimized agent execution loop
194    use_optimized_loop: bool,
195
196    /// Enable performance prediction
197    enable_performance_prediction: bool,
198
199    /// State transition history size
200    state_history_size: usize,
201
202    /// Resource monitoring interval in milliseconds
203    resource_monitor_interval_ms: u64,
204
205    /// Maximum memory usage in MB
206    max_memory_mb: u64,
207
208    /// Maximum execution time in seconds
209    pub max_execution_time_secs: u64,
210
211    /// Idle detection timeout in milliseconds (0 to disable)
212    /// When the agent is idle for this duration, it will enter a low-power state
213    pub idle_timeout_ms: u64,
214
215    /// Back-off duration in milliseconds when no work is pending
216    /// This reduces CPU usage during idle periods
217    pub idle_backoff_ms: u64,
218
219    /// Maximum consecutive idle cycles before entering deep sleep
220    pub max_idle_cycles: usize,
221}
222
223/// Performance profiling configuration
224#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
225#[derive(Debug, Clone, Serialize, Deserialize)]
226#[serde(default)]
227pub struct ProfilingConfig {
228    /// Enable performance profiling
229    enabled: bool,
230
231    /// Resource monitoring interval in milliseconds
232    monitor_interval_ms: u64,
233
234    /// Maximum benchmark history size
235    max_history_size: usize,
236
237    /// Auto-export results to file
238    auto_export_results: bool,
239
240    /// Export file path
241    export_file_path: String,
242
243    /// Enable regression testing
244    enable_regression_testing: bool,
245
246    /// Maximum allowed performance regression percentage
247    max_regression_percent: f64,
248}
249
250impl Default for MemoryPoolConfig {
251    fn default() -> Self {
252        Self {
253            enabled: true,
254            max_string_pool_size: 64,
255            max_value_pool_size: 32,
256            max_vec_pool_size: 16,
257        }
258    }
259}
260
261impl Default for FileReadCacheConfig {
262    fn default() -> Self {
263        Self {
264            enabled: true,
265            min_size_bytes: crate::constants::optimization::FILE_READ_CACHE_MIN_SIZE_BYTES,
266            max_size_bytes: crate::constants::optimization::FILE_READ_CACHE_MAX_SIZE_BYTES,
267            ttl_secs: crate::constants::optimization::FILE_READ_CACHE_TTL_SECS,
268            max_entries: crate::constants::optimization::FILE_READ_CACHE_MAX_ENTRIES,
269            // Same source as the serde default, so a partial config and
270            // `FileReadCacheConfig::default()` cannot disagree.
271            max_read_lines: default_max_read_lines(),
272        }
273    }
274}
275
276impl Default for CommandCacheConfig {
277    fn default() -> Self {
278        Self {
279            enabled: true,
280            ttl_ms: crate::constants::optimization::COMMAND_CACHE_TTL_MS,
281            max_entries: crate::constants::optimization::COMMAND_CACHE_MAX_ENTRIES,
282            allowlist: crate::constants::optimization::COMMAND_CACHE_ALLOWLIST
283                .iter()
284                .map(|s| s.to_string())
285                .collect(),
286        }
287    }
288}
289
290impl Default for ToolRegistryConfig {
291    fn default() -> Self {
292        Self {
293            use_optimized_registry: true, // Enable by default for better performance
294            max_concurrent_tools: 4,
295            hot_cache_size: 16,
296            default_timeout_secs: 180,
297            middleware_fail_open: false, // Fail-closed by default; opt-in to fail-open
298        }
299    }
300}
301
302impl Default for AsyncPipelineConfig {
303    fn default() -> Self {
304        Self {
305            enable_batching: false, // Conservative default
306            enable_caching: true,
307            max_batch_size: 5,
308            batch_timeout_ms: 100,
309            cache_size: 100,
310        }
311    }
312}
313
314impl Default for LLMClientConfig {
315    fn default() -> Self {
316        Self {
317            enable_connection_pooling: false, // Conservative default
318            enable_response_caching: true,
319            enable_request_batching: false, // Conservative default
320            connection_pool_size: 4,
321            response_cache_size: 50,
322            cache_ttl_secs: 300,
323            rate_limit_rps: 10.0,
324            rate_limit_burst: 20,
325        }
326    }
327}
328
329impl Default for AgentExecutionConfig {
330    fn default() -> Self {
331        Self {
332            use_optimized_loop: true,             // Enable by default for better performance
333            enable_performance_prediction: false, // Conservative default
334            state_history_size: 1000,
335            resource_monitor_interval_ms: 100,
336            max_memory_mb: 1024,
337            // Aligned with `DEFAULT_MAX_TOOL_WALL_CLOCK_SECS` (600). Previously 300,
338            // which conflicted with the harness wall-clock budget (600) and could
339            // truncate long agentic runs at 5 minutes, forcing "continue" nudges.
340            max_execution_time_secs: 600,
341            idle_timeout_ms: 5000, // 5 seconds idle timeout
342            idle_backoff_ms: 100,  // 100ms backoff during idle
343            max_idle_cycles: 10,   // 10 consecutive idle cycles before deep sleep
344        }
345    }
346}
347
348impl Default for ProfilingConfig {
349    fn default() -> Self {
350        Self {
351            enabled: false, // Disabled by default to avoid overhead
352            monitor_interval_ms: 100,
353            max_history_size: 1000,
354            auto_export_results: false,
355            export_file_path: "benchmark_results.json".to_string(),
356            enable_regression_testing: false,
357            max_regression_percent: 10.0,
358        }
359    }
360}
361
362impl OptimizationConfig {
363    /// Get optimized configuration for development
364    pub fn development() -> Self {
365        Self {
366            memory_pool: MemoryPoolConfig { enabled: true, ..Default::default() },
367            tool_registry: ToolRegistryConfig {
368                use_optimized_registry: true,
369                max_concurrent_tools: 2,
370                middleware_fail_open: false,
371                ..Default::default()
372            },
373            async_pipeline: AsyncPipelineConfig {
374                enable_batching: true,
375                enable_caching: true,
376                max_batch_size: 3,
377                ..Default::default()
378            },
379            llm_client: LLMClientConfig {
380                enable_connection_pooling: true,
381                enable_response_caching: true,
382                connection_pool_size: 2,
383                rate_limit_rps: 5.0,
384                ..Default::default()
385            },
386            agent_execution: AgentExecutionConfig {
387                use_optimized_loop: true,
388                enable_performance_prediction: false, // Disabled for dev
389                max_memory_mb: 512,
390                idle_timeout_ms: 2000, // Shorter idle timeout for development
391                idle_backoff_ms: 50,   // Shorter backoff for development
392                max_idle_cycles: 5,    // Fewer idle cycles for development
393                ..Default::default()
394            },
395            profiling: ProfilingConfig {
396                enabled: true, // Enabled for development
397                auto_export_results: true,
398                ..Default::default()
399            },
400            file_read_cache: FileReadCacheConfig::default(),
401            command_cache: CommandCacheConfig::default(),
402        }
403    }
404
405    /// Get optimized configuration for production
406    pub fn production() -> Self {
407        Self {
408            memory_pool: MemoryPoolConfig {
409                enabled: true,
410                max_string_pool_size: 128,
411                max_value_pool_size: 64,
412                max_vec_pool_size: 32,
413            },
414            tool_registry: ToolRegistryConfig {
415                use_optimized_registry: true,
416                max_concurrent_tools: 8,
417                hot_cache_size: 32,
418                default_timeout_secs: 300,
419                middleware_fail_open: false,
420            },
421            async_pipeline: AsyncPipelineConfig {
422                enable_batching: true,
423                enable_caching: true,
424                max_batch_size: 10,
425                batch_timeout_ms: 50,
426                cache_size: 200,
427            },
428            llm_client: LLMClientConfig {
429                enable_connection_pooling: true,
430                enable_response_caching: true,
431                enable_request_batching: true,
432                connection_pool_size: 8,
433                response_cache_size: 100,
434                cache_ttl_secs: 600,
435                rate_limit_rps: 20.0,
436                rate_limit_burst: 50,
437            },
438            agent_execution: AgentExecutionConfig {
439                use_optimized_loop: true,
440                enable_performance_prediction: true,
441                state_history_size: 2000,
442                resource_monitor_interval_ms: 50,
443                max_memory_mb: 2048,
444                max_execution_time_secs: 600,
445                idle_timeout_ms: 10000, // Longer idle timeout for production
446                idle_backoff_ms: 200,   // Longer backoff for production
447                max_idle_cycles: 20,    // More idle cycles for production
448            },
449            profiling: ProfilingConfig {
450                enabled: false, // Disabled in production unless needed
451                monitor_interval_ms: 1000,
452                max_history_size: 500,
453                auto_export_results: false,
454                export_file_path: "/var/log/vtcode/benchmark_results.json".to_string(),
455                enable_regression_testing: true,
456                max_regression_percent: 5.0,
457            },
458            file_read_cache: FileReadCacheConfig {
459                enabled: true,
460                min_size_bytes: crate::constants::optimization::FILE_READ_CACHE_PROD_MIN_SIZE_BYTES,
461                max_size_bytes: crate::constants::optimization::FILE_READ_CACHE_PROD_MAX_SIZE_BYTES,
462                ttl_secs: crate::constants::optimization::FILE_READ_CACHE_PROD_TTL_SECS,
463                max_entries: crate::constants::optimization::FILE_READ_CACHE_PROD_MAX_ENTRIES,
464                max_read_lines: crate::constants::optimization::DEFAULT_MAX_READ_LINES,
465            },
466            command_cache: CommandCacheConfig {
467                enabled: true,
468                ttl_ms: crate::constants::optimization::COMMAND_CACHE_PROD_TTL_MS,
469                max_entries: crate::constants::optimization::COMMAND_CACHE_PROD_MAX_ENTRIES,
470                allowlist: crate::constants::optimization::COMMAND_CACHE_PROD_ALLOWLIST
471                    .iter()
472                    .map(|s| s.to_string())
473                    .collect(),
474            },
475        }
476    }
477}