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