Skip to main content

systemprompt_traits/
extension_error.rs

1//! `ExtensionError` trait for consistent error handling across extensions.
2
3use http::StatusCode;
4
5#[derive(Debug, Clone)]
6pub struct ApiError {
7    pub code: String,
8    pub message: String,
9    pub status: StatusCode,
10}
11
12impl ApiError {
13    #[must_use]
14    pub fn new(code: impl Into<String>, message: impl Into<String>, status: StatusCode) -> Self {
15        Self {
16            code: code.into(),
17            message: message.into(),
18            status,
19        }
20    }
21}
22
23#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
24pub struct McpErrorData {
25    pub code: i32,
26    pub message: String,
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub data: Option<serde_json::Value>,
29}
30
31impl McpErrorData {
32    #[must_use]
33    pub fn new(code: i32, message: impl Into<String>) -> Self {
34        Self {
35            code,
36            message: message.into(),
37            data: None,
38        }
39    }
40
41    #[must_use]
42    pub fn with_data(mut self, data: serde_json::Value) -> Self {
43        self.data = Some(data);
44        self
45    }
46}
47
48pub trait ExtensionError: std::error::Error + Send + Sync + 'static {
49    fn code(&self) -> &'static str;
50
51    fn status(&self) -> StatusCode {
52        StatusCode::INTERNAL_SERVER_ERROR
53    }
54
55    fn is_retryable(&self) -> bool {
56        false
57    }
58
59    fn user_message(&self) -> String {
60        self.to_string()
61    }
62
63    fn to_mcp_error(&self) -> McpErrorData {
64        McpErrorData {
65            code: i32::from(self.status().as_u16()),
66            message: self.user_message(),
67            data: Some(serde_json::json!({
68                "code": self.code(),
69                "retryable": self.is_retryable(),
70            })),
71        }
72    }
73
74    fn to_api_error(&self) -> ApiError {
75        ApiError {
76            code: self.code().to_string(),
77            message: self.user_message(),
78            status: self.status(),
79        }
80    }
81}