vtcode_core/tools/registry/
error.rs

1use anyhow::Error;
2use serde::{Deserialize, Serialize};
3use serde_json::{Value, json};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct ToolExecutionError {
7    pub tool_name: String,
8    pub error_type: ToolErrorType,
9    pub message: String,
10    pub is_recoverable: bool,
11    pub recovery_suggestions: Vec<String>,
12    pub original_error: Option<String>,
13}
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub enum ToolErrorType {
17    InvalidParameters,
18    ToolNotFound,
19    PermissionDenied,
20    ResourceNotFound,
21    NetworkError,
22    Timeout,
23    ExecutionError,
24    PolicyViolation,
25}
26
27impl ToolExecutionError {
28    pub fn new(tool_name: String, error_type: ToolErrorType, message: String) -> Self {
29        let (is_recoverable, recovery_suggestions) = generate_recovery_info(&error_type);
30
31        Self {
32            tool_name,
33            error_type,
34            message,
35            is_recoverable,
36            recovery_suggestions,
37            original_error: None,
38        }
39    }
40
41    pub fn with_original_error(
42        tool_name: String,
43        error_type: ToolErrorType,
44        message: String,
45        original_error: String,
46    ) -> Self {
47        let mut error = Self::new(tool_name, error_type, message);
48        error.original_error = Some(original_error);
49        error
50    }
51
52    pub fn to_json_value(&self) -> Value {
53        json!({
54            "error": {
55                "tool_name": self.tool_name,
56                "error_type": format!("{:?}", self.error_type),
57                "message": self.message,
58                "is_recoverable": self.is_recoverable,
59                "recovery_suggestions": self.recovery_suggestions,
60                "original_error": self.original_error,
61            }
62        })
63    }
64}
65
66pub fn classify_error(error: &Error) -> ToolErrorType {
67    let error_msg = error.to_string().to_lowercase();
68
69    if error_msg.contains("permission") || error_msg.contains("access denied") {
70        ToolErrorType::PermissionDenied
71    } else if error_msg.contains("not found") || error_msg.contains("no such file") {
72        ToolErrorType::ResourceNotFound
73    } else if error_msg.contains("timeout") || error_msg.contains("timed out") {
74        ToolErrorType::Timeout
75    } else if error_msg.contains("network") || error_msg.contains("connection") {
76        ToolErrorType::NetworkError
77    } else if error_msg.contains("invalid") || error_msg.contains("malformed") {
78        ToolErrorType::InvalidParameters
79    } else if error_msg.contains("policy") || error_msg.contains("denied") {
80        ToolErrorType::PolicyViolation
81    } else {
82        ToolErrorType::ExecutionError
83    }
84}
85
86fn generate_recovery_info(error_type: &ToolErrorType) -> (bool, Vec<String>) {
87    match error_type {
88        ToolErrorType::InvalidParameters => (
89            true,
90            vec![
91                "Check parameter names and types against the tool schema".to_string(),
92                "Ensure required parameters are provided".to_string(),
93                "Verify parameter values are within acceptable ranges".to_string(),
94            ],
95        ),
96        ToolErrorType::ToolNotFound => (
97            false,
98            vec![
99                "Verify the tool name is spelled correctly".to_string(),
100                "Check if the tool is available in the current context".to_string(),
101                "Contact administrator if tool should be available".to_string(),
102            ],
103        ),
104        ToolErrorType::PermissionDenied => (
105            true,
106            vec![
107                "Check file permissions and access rights".to_string(),
108                "Ensure workspace boundaries are respected".to_string(),
109                "Try running with appropriate permissions".to_string(),
110            ],
111        ),
112        ToolErrorType::ResourceNotFound => (
113            true,
114            vec![
115                "Verify file paths and resource locations".to_string(),
116                "Check if files exist and are accessible".to_string(),
117                "Use list_dir to explore available resources".to_string(),
118            ],
119        ),
120        ToolErrorType::NetworkError => (
121            true,
122            vec![
123                "Check network connectivity".to_string(),
124                "Retry the operation after a brief delay".to_string(),
125                "Verify external service availability".to_string(),
126            ],
127        ),
128        ToolErrorType::Timeout => (
129            true,
130            vec![
131                "Increase timeout values if appropriate".to_string(),
132                "Break large operations into smaller chunks".to_string(),
133                "Check system resources and performance".to_string(),
134            ],
135        ),
136        ToolErrorType::ExecutionError => (
137            false,
138            vec![
139                "Review error details for specific issues".to_string(),
140                "Check tool documentation for known limitations".to_string(),
141                "Report the issue if it appears to be a bug".to_string(),
142            ],
143        ),
144        ToolErrorType::PolicyViolation => (
145            false,
146            vec![
147                "Review workspace policies and restrictions".to_string(),
148                "Contact administrator for policy changes".to_string(),
149                "Use alternative tools that comply with policies".to_string(),
150            ],
151        ),
152    }
153}