systemprompt_traits/
extension_error.rs1use 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}