vtcode_core/lib.rs
1//! # vtcode-core - Runtime for VT Code
2//!
3//! `vtcode-core` powers the VT Code terminal coding agent. It provides the
4//! reusable building blocks for multi-provider LLM orchestration, tool
5//! execution, semantic code analysis, and configurable safety policies.
6//!
7//! ## Highlights
8//!
9//! - **Provider Abstraction**: unified LLM interface with adapters for OpenAI,
10//! Anthropic, xAI, DeepSeek, Gemini, and OpenRouter, including automatic
11//! failover and spend controls.
12//! - **Prompt Caching**: cross-provider prompt caching system that leverages
13//! provider-specific caching capabilities (OpenAI's automatic caching, Anthropic's
14//! cache_control blocks, Gemini's implicit/explicit caching) to reduce costs and
15//! latency, with configurable settings per provider.
16//! - **Semantic Workspace Model**: incremental tree-sitter parsing for Rust,
17//! Python, JavaScript, TypeScript, Go, and Java augmented by ast-grep based
18//! structural search and refactoring.
19//! - **Tool System**: trait-driven registry for shell execution, file IO,
20//! search, and custom commands, with Tokio-powered concurrency and PTY
21//! streaming.
22//! - **Configuration-First**: everything is driven by `vtcode.toml`, with
23//! model, safety, and automation constants centralized in
24//! `config::constants` and curated metadata in `docs/models.json`.
25//! - **Safety & Observability**: workspace boundary enforcement, command
26//! allow/deny lists, human-in-the-loop confirmation, and structured event
27//! logging.
28//!
29//! ## Architecture Overview
30//!
31//! The crate is organized into several key modules:
32//!
33//! - `config/`: configuration loader, defaults, and schema validation.
34//! - `llm/`: provider clients, request shaping, and response handling.
35//! - `tools/`: built-in tool implementations plus registration utilities.
36//! - `context/`: conversation management, summarization, and memory.
37//! - `executor/`: async orchestration for tool invocations and streaming output.
38//! - `tree_sitter/`: language-specific parsers, syntax tree caching, and
39//! semantic extraction helpers.
40//! - `core/prompt_caching`: cross-provider prompt caching system that leverages
41//! provider-specific caching mechanisms for cost optimization and reduced latency.
42//!
43//! ## Quickstart
44//!
45//! ```rust,ignore
46//! use vtcode_core::{Agent, VTCodeConfig};
47//!
48//! #[tokio::main]
49//! async fn main() -> Result<(), anyhow::Error> {
50//! // Load configuration from vtcode.toml or environment overrides
51//! let config = VTCodeConfig::load()?;
52//!
53//! // Construct the agent runtime
54//! let agent = Agent::new(config).await?;
55//!
56//! // Execute an interactive session
57//! agent.run().await?;
58//!
59//! Ok(())
60//! }
61//! ```
62//!
63//! ## Extending VT Code
64//!
65//! Register custom tools or providers by composing the existing traits:
66//!
67//! ```rust,ignore
68//! use vtcode_core::tools::{ToolRegistry, ToolRegistration};
69//!
70//! #[tokio::main]
71//! async fn main() -> Result<(), anyhow::Error> {
72//! let workspace = std::env::current_dir()?;
73//! let mut registry = ToolRegistry::new(workspace);
74//!
75//! let custom_tool = ToolRegistration {
76//! name: "my_custom_tool".into(),
77//! description: "A custom tool for specific tasks".into(),
78//! parameters: serde_json::json!({
79//! "type": "object",
80//! "properties": { "input": { "type": "string" } }
81//! }),
82//! handler: |_args| async move {
83//! // Implement your tool behavior here
84//! Ok(serde_json::json!({ "result": "success" }))
85//! },
86//! };
87//!
88//! registry.register_tool(custom_tool).await?;
89//! Ok(())
90//! }
91//! ```
92//!
93//! For a complete tour of modules and extension points, read
94//! `docs/ARCHITECTURE.md` and the guides in `docs/project/`.
95
96//! VTCode Core Library
97//!
98//! This crate provides the core functionality for the VTCode agent,
99//! including tool implementations, LLM integration, and utility functions.
100
101// Public modules
102pub mod bash_runner;
103pub mod cli;
104pub mod code;
105pub mod commands;
106pub mod config;
107pub mod constants;
108pub mod core;
109pub mod gemini;
110pub mod llm;
111pub mod markdown_storage;
112pub mod mcp_client;
113pub mod models;
114pub mod project;
115pub mod project_doc;
116pub mod prompts;
117pub mod safety;
118pub mod simple_indexer;
119pub mod tool_policy;
120pub mod tools;
121pub mod types;
122pub mod ui;
123pub mod utils;
124
125// Re-exports for convenience
126pub use bash_runner::BashRunner;
127pub use cli::args::{Cli, Commands};
128pub use code::code_completion::{CompletionEngine, CompletionSuggestion};
129pub use commands::stats::handle_stats_command;
130pub use config::types::{
131 AnalysisDepth, CapabilityLevel, CommandResult, CompressionLevel, ContextConfig, LoggingConfig,
132 OutputFormat, PerformanceMetrics, ReasoningEffortLevel, SessionInfo, ToolConfig,
133};
134pub use config::{AgentConfig, VTCodeConfig};
135pub use core::agent::core::Agent;
136pub use core::context_compression::{
137 CompressedContext, ContextCompressionConfig, ContextCompressor,
138};
139pub use core::conversation_summarizer::ConversationSummarizer;
140pub use core::performance_profiler::PerformanceProfiler;
141pub use core::prompt_caching::{CacheStats, PromptCache, PromptCacheConfig, PromptOptimizer};
142pub use core::timeout_detector::TimeoutDetector;
143pub use gemini::{Content, FunctionDeclaration, Part};
144pub use llm::{AnyClient, make_client};
145pub use markdown_storage::{MarkdownStorage, ProjectData, ProjectStorage, SimpleKVStorage};
146pub use project::{SimpleCache, SimpleProjectManager};
147pub use prompts::{
148 generate_lightweight_instruction, generate_specialized_instruction, generate_system_instruction,
149};
150pub use simple_indexer::SimpleIndexer;
151pub use tool_policy::{ToolPolicy, ToolPolicyManager};
152pub use tools::advanced_search::{AdvancedSearchTool, SearchOptions};
153pub use tools::grep_search::GrepSearchManager;
154pub use tools::tree_sitter::TreeSitterAnalyzer;
155pub use tools::{
156 ToolRegistration, ToolRegistry, build_function_declarations,
157 build_function_declarations_for_level,
158};
159pub use ui::diff_renderer::DiffRenderer;
160pub use utils::dot_config::{
161 CacheConfig, DotConfig, DotManager, ProviderConfigs, UiConfig, UserPreferences,
162 WorkspaceTrustLevel, WorkspaceTrustRecord, WorkspaceTrustStore, initialize_dot_folder,
163 load_user_config, save_user_config, update_theme_preference,
164};
165pub use utils::vtcodegitignore::initialize_vtcode_gitignore;
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170
171 use tempfile::TempDir;
172
173 #[test]
174 fn test_library_exports() {
175 // Test that all public exports are accessible
176 let _cache = PromptCache::new();
177 }
178
179 #[test]
180 fn test_module_structure() {
181 // Test that all modules can be imported
182 // This is a compile-time test that ensures module structure is correct
183 }
184
185 #[test]
186 fn test_version_consistency() {
187 // Test that version information is consistent across modules
188 // This would be more meaningful with actual version checking
189 }
190
191 #[tokio::test]
192 async fn test_tool_registry_integration() {
193 use crate::config::constants::tools;
194
195 let temp_dir = TempDir::new().unwrap();
196 std::env::set_current_dir(&temp_dir).unwrap();
197
198 let mut registry = ToolRegistry::new(temp_dir.path().to_path_buf());
199
200 // Test that we can execute basic tools
201 let list_args = serde_json::json!({
202 "path": "."
203 });
204
205 let result = registry.execute_tool(tools::LIST_FILES, list_args).await;
206 assert!(result.is_ok());
207
208 let response: serde_json::Value = result.unwrap();
209 assert!(response["files"].is_array());
210 }
211
212 #[tokio::test]
213 async fn test_pty_basic_command() {
214 let temp_dir = TempDir::new().unwrap();
215 let workspace = temp_dir.path().to_path_buf();
216 let mut registry = ToolRegistry::new(workspace.clone());
217
218 // Test a simple PTY command
219 let args = serde_json::json!({
220 "command": "echo",
221 "args": ["Hello, PTY!"]
222 });
223
224 let result = registry.execute_tool("run_pty_cmd", args).await;
225 assert!(result.is_ok());
226 let response: serde_json::Value = result.unwrap();
227 assert_eq!(response["success"], true);
228 assert_eq!(response["code"], 0);
229 assert!(response["output"].as_str().unwrap().contains("Hello, PTY!"));
230 }
231
232 #[tokio::test]
233 async fn test_pty_session_management() {
234 let temp_dir = TempDir::new().unwrap();
235 let workspace = temp_dir.path().to_path_buf();
236 let mut registry = ToolRegistry::new(workspace.clone());
237
238 // Test creating a PTY session
239 let args = serde_json::json!({
240 "session_id": "test_session",
241 "command": "bash"
242 });
243
244 let result = registry.execute_tool("create_pty_session", args).await;
245 assert!(result.is_ok());
246 let response: serde_json::Value = result.unwrap();
247 assert_eq!(response["success"], true);
248 assert_eq!(response["session_id"], "test_session");
249
250 // Test listing PTY sessions
251 let args = serde_json::json!({});
252 let result = registry.execute_tool("list_pty_sessions", args).await;
253 assert!(result.is_ok());
254 let response: serde_json::Value = result.unwrap();
255 assert!(
256 response["sessions"]
257 .as_array()
258 .unwrap()
259 .contains(&"test_session".into())
260 );
261
262 // Test closing a PTY session
263 let args = serde_json::json!({
264 "session_id": "test_session"
265 });
266
267 let result = registry.execute_tool("close_pty_session", args).await;
268 assert!(result.is_ok());
269 let response: serde_json::Value = result.unwrap();
270 assert_eq!(response["success"], true);
271 assert_eq!(response["session_id"], "test_session");
272 }
273}