vtcode_core/tools/
error_messages.rs1pub mod agent_execution {
11 pub const PLAN_MODE_DENIED_CONTEXT: &str = "tool denied by plan mode";
13 pub const LOOP_DETECTION_PREFIX: &str = "LOOP DETECTION";
15 pub const LOOP_RETRY_BLOCKED_LINE: &str = "ACTION REQUIRED: DO NOT retry this tool call. The tool execution has been prevented to avoid infinite loops.";
17
18 pub const POLICY_DENIED_HINT: &str = "Hint: If this command should be allowed, run `/mode auto` to enable \
20 classifier-backed auto-approval, or `/mode cycle` to cycle modes. \
21 You can also configure `[permissions]` rules in vtcode.toml to allow specific tools.";
22
23 pub fn plan_mode_denial_message(tool_name: &str) -> String {
25 format!(
26 "Tool '{}' execution failed: tool denied by plan mode\n\n\
27 ACTION REQUIRED: You are in Plan Mode (read-only). To start implementation:\n\
28 1. Call `exit_plan_mode` tool to show the user your plan for approval\n\
29 2. Wait for user to confirm (they will see the Implementation Blueprint)\n\
30 3. After approval, mutating tools will be enabled\n\n\
31 Fallback if automatic Plan->Edit switching keeps failing: manually switch using `/plan off` or `/mode` (or `Shift+Tab`/`Alt+M` in interactive mode).",
32 tool_name
33 )
34 }
35
36 pub fn policy_denied_hint_message(tool_name: &str) -> String {
38 format!(
39 "Tool '{}' execution denied by policy.\n\n{}",
40 tool_name, POLICY_DENIED_HINT
41 )
42 }
43
44 pub fn loop_detection_block_message(
46 tool_name: &str,
47 repeat_count: u64,
48 original_error: Option<&str>,
49 ) -> String {
50 let mut message = format!(
51 "{}: Tool '{}' has been called {} times with identical parameters and is now blocked.\n\n\
52 {}\n\n\
53 If you need the result from this tool:\n\
54 1. Check if you already have the result from a previous successful call in your conversation history\n\
55 2. If not available, use a different approach or modify your request",
56 LOOP_DETECTION_PREFIX, tool_name, repeat_count, LOOP_RETRY_BLOCKED_LINE
57 );
58
59 if let Some(error) = original_error {
60 message.push_str("\n\nOriginal error: ");
61 message.push_str(error);
62 }
63
64 message
65 }
66
67 pub fn is_plan_mode_denial(error: &str) -> bool {
69 error.contains(PLAN_MODE_DENIED_CONTEXT)
70 }
71}
72
73pub mod skill_ops {
75 pub const SKILL_NOT_FOUND: &str = "Skill not found";
76 pub const SKILL_ALREADY_EXISTS: &str = "Skill already exists";
77 pub const INVALID_SKILL_FORMAT: &str = "Invalid skill format";
78 pub const SKILL_SAVE_FAILED: &str = "Failed to save skill";
79 pub const SKILL_LOAD_FAILED: &str = "Failed to load skill";
80
81 pub fn skill_not_found_error(name: &str) -> anyhow::Error {
83 anyhow::anyhow!("Skill '{}' not found", name)
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 #[test]
92 fn test_error_messages_are_not_empty() {
93 assert!(!agent_execution::PLAN_MODE_DENIED_CONTEXT.is_empty());
94 assert!(!agent_execution::LOOP_RETRY_BLOCKED_LINE.is_empty());
95 assert!(!agent_execution::POLICY_DENIED_HINT.is_empty());
96 assert!(!skill_ops::SKILL_NOT_FOUND.is_empty());
97 }
98
99 #[test]
100 fn test_agent_execution_message_helpers() {
101 let plan_mode_msg = agent_execution::plan_mode_denial_message("write_file");
102 assert!(agent_execution::is_plan_mode_denial(&plan_mode_msg));
103 assert!(plan_mode_msg.contains("exit_plan_mode"));
104 assert!(plan_mode_msg.contains("/plan off"));
105 assert!(plan_mode_msg.contains("/mode"));
106 assert!(plan_mode_msg.contains("Shift+Tab"));
107 assert!(!plan_mode_msg.contains("DO NOT retry this tool or use /plan off"));
108
109 let loop_msg =
110 agent_execution::loop_detection_block_message("read_file", 3, Some("base error"));
111 assert!(loop_msg.contains("LOOP DETECTION"));
112 assert!(loop_msg.contains("DO NOT retry"));
113 assert!(loop_msg.contains("Original error: base error"));
114
115 let policy_msg = agent_execution::policy_denied_hint_message("unified_exec");
116 assert!(policy_msg.contains("unified_exec"));
117 assert!(policy_msg.contains("/mode auto"));
118 assert!(policy_msg.contains("/mode cycle"));
119 assert!(policy_msg.contains("vtcode.toml"));
120 }
121}