vtcode_core/prompts/
system.rs

1//! System instructions and prompt management
2
3use crate::config::constants::project_doc as project_doc_constants;
4use crate::gemini::Content;
5use crate::project_doc::{ProjectDocBundle, read_project_doc};
6use std::fs;
7use std::path::Path;
8use tracing::warn;
9
10const DEFAULT_SYSTEM_PROMPT: &str = r#"You are a coding agent running in VTCode, a terminal-based coding assistant created by
11vinhnx. You are expected to be precise, safe, helpful, and smart.
12
13## WORKSPACE CONTEXT
14- The `WORKSPACE_DIR` environment variable points to the active project; treat it as your default operating surface.
15- You may read, create, and modify files within this workspace and run shell commands scoped to it.
16- Perform light workspace reconnaissance (directory listings, targeted searches) before major changes so
17  your decisions reflect the live codebase.
18- For new feature work, inspect modules under `WORKSPACE_DIR` that align with the request before
19  implementing changes.
20- When debugging, consult workspace tests, logs, or recent diffs to ground hypotheses in current project
21  state.
22- Ask before touching paths outside `WORKSPACE_DIR` or downloading untrusted artifacts.
23
24## CONTEXT MANAGEMENT
25- Pull only the files and sections required for the current step; avoid bulk-reading directories or large
26  outputs unless they are essential.
27- Prefer targeted inspection tools (for example `rg` or `ast-grep`) instead of dumping entire files to
28  stdout.
29- Summarize long command results rather than echoing every line back to the user, keeping shared context
30  concise.
31
32## AVAILABLE TOOLS
33- **File Operations**: list_files, read_file, write_file, edit_file.
34- **Search & Analysis**: rg, rp_search, ast_grep_search.
35- **Terminal Access**: run_terminal_cmd for shell operations.
36- **PTY Access**: Enhanced terminal emulation for interactive commands.
37
38## SAFETY EXPECTATIONS
39- Only access the network via the sandboxed `curl` tool. Validate HTTPS URLs, refuse localhost or private
40  targets, and tell the user which URL you fetched along with the security_notice returned by the tool.
41- Store temporary files under `/tmp/vtcode-*` and remove them when you finish using them.
42
43Your capabilities:
44- Receive user prompts and other context provided by the harness, such as files in the workspace.
45- Communicate with the user by streaming thinking & responses, and by making & updating plans.
46- Output is rendered with ANSI styles; return plain text and let the interface style the response.
47- Emit function calls to run terminal commands and apply patches.
48
49Within this context, VTCode refers to the open-source agentic coding interface created by vinhnx, not any other coding tools or models."#;
50
51const DEFAULT_LIGHTWEIGHT_PROMPT: &str = r#"You are a coding agent running in VTCode, a terminal-based coding assistant created by
52vinhnx. You are expected to be precise, safe, helpful, and smart.
53
54## CONTEXT MANAGEMENT
55- Pull only the files and sections required for the current step; avoid bulk-reading directories or large
56  outputs unless they are essential.
57- Prefer targeted inspection tools (for example `rg` or `ast-grep`) instead of dumping entire files to
58  stdout.
59- Summarize long command results rather than echoing every line back to the user, keeping shared context
60  concise.
61
62## AVAILABLE TOOLS
63- **File Operations**: list_files, read_file, write_file, edit_file.
64- **Search & Analysis**: rg, rp_search, ast_grep_search.
65- **Terminal Access**: run_terminal_cmd for shell operations.
66
67## SAFETY EXPECTATIONS
68- Only access the network via the sandboxed `curl` tool. Validate HTTPS URLs, refuse localhost or private
69  targets, and tell the user which URL you fetched along with the security_notice returned by the tool.
70- Store temporary files under `/tmp/vtcode-*` and remove them when you finish using them.
71
72Your capabilities:
73- Receive user prompts and other context provided by the harness, such as files in the workspace.
74- Communicate with the user by streaming thinking & responses, and by making & updating plans.
75- Output is rendered with ANSI styles; return plain text and let the interface style the response.
76- Emit function calls to run terminal commands and apply patches.
77
78Within this context, VTCode refers to the open-source agentic coding interface created by vinhnx, not any other coding tools or models."#;
79
80const DEFAULT_SPECIALIZED_PROMPT: &str = r#"You are a specialized coding agent running in VTCode, a terminal-based coding assistant
81created by vinhnx. You are expected to be precise, safe, helpful, and smart with advanced capabilities.
82
83## CONTEXT MANAGEMENT
84- Pull only the files and sections required for the current step; avoid bulk-reading directories or large
85  outputs unless they are essential.
86- Prefer targeted inspection tools (for example `rg` or `ast-grep`) instead of dumping entire files to
87  stdout.
88- Summarize long command results rather than echoing every line back to the user, keeping shared context
89  concise.
90
91## AVAILABLE TOOLS
92- **File Operations**: list_files, read_file, write_file, edit_file.
93- **Search & Analysis**: rg, rp_search, ast_grep_search.
94- **Terminal Access**: run_terminal_cmd for shell operations.
95- **PTY Access**: Enhanced terminal emulation for interactive commands.
96- **Advanced Analysis**: Tree-sitter parsing, performance profiling, prompt caching.
97
98## SAFETY EXPECTATIONS
99- Only access the network via the sandboxed `curl` tool. Validate HTTPS URLs, refuse localhost or private
100  targets, and tell the user which URL you fetched along with the security_notice returned by the tool.
101- Store temporary files under `/tmp/vtcode-*` and remove them when you finish using them.
102
103Your capabilities:
104- Receive user prompts and other context provided by the harness, such as files in the workspace.
105- Communicate with the user by streaming thinking & responses, and by making & updating plans.
106- Output is rendered with ANSI styles; return plain text and let the interface style the response.
107- Emit function calls to run terminal commands and apply patches.
108- Perform advanced code analysis and optimization.
109- Handle complex multi-step operations with proper error handling.
110
111Within this context, VTCode refers to the open-source agentic coding interface created by vinhnx, not any other coding tools or models."#;
112
113/// System instruction configuration
114#[derive(Debug, Clone)]
115pub struct SystemPromptConfig {
116    pub include_examples: bool,
117    pub include_debugging_guides: bool,
118    pub include_error_handling: bool,
119    pub max_response_length: Option<usize>,
120    pub enable_thorough_reasoning: bool,
121}
122
123impl Default for SystemPromptConfig {
124    fn default() -> Self {
125        Self {
126            include_examples: true,
127            include_debugging_guides: true,
128            include_error_handling: true,
129            max_response_length: None,
130            enable_thorough_reasoning: true,
131        }
132    }
133}
134
135/// Read system prompt from markdown file
136pub fn read_system_prompt_from_md() -> Result<String, std::io::Error> {
137    // Try to read from prompts/system.md relative to project root
138    let prompt_paths = [
139        "prompts/system.md",
140        "../prompts/system.md",
141        "../../prompts/system.md",
142    ];
143
144    for path in &prompt_paths {
145        if let Ok(content) = fs::read_to_string(path) {
146            // Extract the main system prompt content (skip the markdown header)
147            if let Some(start) = content.find("## Core System Prompt") {
148                // Find the end of the prompt (look for the next major section)
149                let after_start = &content[start..];
150                if let Some(end) = after_start.find("## Specialized System Prompts") {
151                    let prompt_content = &after_start[..end].trim();
152                    // Remove the header and return the content
153                    if let Some(content_start) = prompt_content.find("```rust\nr#\"") {
154                        if let Some(content_end) = prompt_content[content_start..].find("\"#\n```")
155                        {
156                            let prompt_start = content_start + 9; // Skip ```rust\nr#"
157                            let prompt_end = content_start + content_end;
158                            return Ok(prompt_content[prompt_start..prompt_end].to_string());
159                        }
160                    }
161                    // If no code block found, return the section content
162                    return Ok(prompt_content.to_string());
163                }
164            }
165            // If no specific section found, return the entire content
166            return Ok(content);
167        }
168    }
169
170    // Fallback to the in-code default prompt if the markdown file cannot be read
171    Ok(DEFAULT_SYSTEM_PROMPT.to_string())
172}
173
174/// Generate system instruction by loading from system.md
175pub fn generate_system_instruction(_config: &SystemPromptConfig) -> Content {
176    match read_system_prompt_from_md() {
177        Ok(prompt_content) => Content::system_text(prompt_content),
178        Err(_) => Content::system_text(DEFAULT_SYSTEM_PROMPT.to_string()),
179    }
180}
181
182/// Read AGENTS.md file if present and extract agent guidelines
183pub fn read_agent_guidelines(project_root: &Path) -> Option<String> {
184    match read_project_doc(project_root, project_doc_constants::DEFAULT_MAX_BYTES) {
185        Ok(Some(bundle)) => Some(bundle.contents),
186        Ok(None) => None,
187        Err(err) => {
188            warn!("failed to load project documentation: {err:#}");
189            None
190        }
191    }
192}
193
194/// Generate system instruction with configuration and AGENTS.md guidelines incorporated
195pub fn generate_system_instruction_with_config(
196    _config: &SystemPromptConfig,
197    project_root: &Path,
198    vtcode_config: Option<&crate::config::VTCodeConfig>,
199) -> Content {
200    let mut instruction = match read_system_prompt_from_md() {
201        Ok(content) => content,
202        Err(_) => DEFAULT_SYSTEM_PROMPT.to_string(),
203    };
204
205    // Add configuration awareness
206    if let Some(cfg) = vtcode_config {
207        instruction.push_str("\n\n## CONFIGURATION AWARENESS\n");
208        instruction
209            .push_str("The agent is configured with the following policies from vtcode.toml:\n\n");
210
211        // Add security settings info
212        if cfg.security.human_in_the_loop {
213            instruction.push_str("- **Human-in-the-loop**: Required for critical actions\n");
214        }
215
216        // Add command policy info
217        if !cfg.commands.allow_list.is_empty() {
218            instruction.push_str(&format!(
219                "- **Allowed commands**: {} commands in allow list\n",
220                cfg.commands.allow_list.len()
221            ));
222        }
223        if !cfg.commands.deny_list.is_empty() {
224            instruction.push_str(&format!(
225                "- **Denied commands**: {} commands in deny list\n",
226                cfg.commands.deny_list.len()
227            ));
228        }
229
230        // Add PTY configuration info
231        if cfg.pty.enabled {
232            instruction.push_str("- **PTY functionality**: Enabled\n");
233            let (rows, cols) = (cfg.pty.default_rows, cfg.pty.default_cols);
234            instruction.push_str(&format!(
235                "- **Default terminal size**: {} rows × {} columns\n",
236                rows, cols
237            ));
238            instruction.push_str(&format!(
239                "- **PTY command timeout**: {} seconds\n",
240                cfg.pty.command_timeout_seconds
241            ));
242        } else {
243            instruction.push_str("- **PTY functionality**: Disabled\n");
244        }
245
246        instruction.push_str("\n**IMPORTANT**: Respect these configuration policies. Commands not in the allow list will require user confirmation. Always inform users when actions require confirmation due to security policies.\n");
247    }
248
249    // Read and incorporate AGENTS.md guidelines if available
250    if let Some(bundle) = read_project_guidelines(
251        project_root,
252        vtcode_config.map(|cfg| cfg.agent.project_doc_max_bytes),
253    ) {
254        instruction.push_str("\n\n## AGENTS.MD GUIDELINES\n");
255        instruction.push_str("Please follow these project-specific guidelines from AGENTS.md:\n\n");
256        instruction.push_str(&bundle.contents);
257        instruction.push_str("\n\nThese guidelines take precedence over general instructions.");
258    }
259
260    Content::system_text(instruction)
261}
262
263/// Generate system instruction with AGENTS.md guidelines incorporated
264pub fn generate_system_instruction_with_guidelines(
265    _config: &SystemPromptConfig,
266    project_root: &Path,
267) -> Content {
268    let mut instruction = match read_system_prompt_from_md() {
269        Ok(content) => content,
270        Err(_) => DEFAULT_SYSTEM_PROMPT.to_string(),
271    };
272
273    // Read and incorporate AGENTS.md guidelines if available
274    if let Some(bundle) = read_project_guidelines(project_root, None) {
275        instruction.push_str("\n\n## AGENTS.MD GUIDELINES\n");
276        instruction.push_str("Please follow these project-specific guidelines from AGENTS.md:\n\n");
277        instruction.push_str(&bundle.contents);
278        instruction.push_str("\n\nThese guidelines take precedence over general instructions.");
279    }
280
281    Content::system_text(instruction)
282}
283
284fn read_project_guidelines(project_root: &Path, limit: Option<usize>) -> Option<ProjectDocBundle> {
285    let max_bytes = limit.unwrap_or(project_doc_constants::DEFAULT_MAX_BYTES);
286    match read_project_doc(project_root, max_bytes) {
287        Ok(Some(bundle)) => Some(bundle),
288        Ok(None) => None,
289        Err(err) => {
290            warn!("failed to load project documentation: {err:#}");
291            None
292        }
293    }
294}
295
296/// Generate a lightweight system instruction for simple operations
297pub fn generate_lightweight_instruction() -> Content {
298    Content::system_text(DEFAULT_LIGHTWEIGHT_PROMPT.to_string())
299}
300
301/// Generate a specialized system instruction for advanced operations
302pub fn generate_specialized_instruction() -> Content {
303    Content::system_text(DEFAULT_SPECIALIZED_PROMPT.to_string())
304}