Skip to main content

soma_codemode/
error.rs

1use serde::Serialize;
2
3#[derive(Debug, Clone)]
4pub enum ToolError {
5    UnknownAction {
6        message: String,
7        valid: Vec<String>,
8        hint: Option<String>,
9    },
10    MissingParam {
11        message: String,
12        param: String,
13    },
14    InvalidParam {
15        message: String,
16        param: String,
17    },
18    UnknownInstance {
19        message: String,
20        valid: Vec<String>,
21    },
22    AmbiguousTool {
23        message: String,
24        valid: Vec<String>,
25    },
26    ConfirmationRequired {
27        message: String,
28    },
29    Conflict {
30        message: String,
31        existing_id: String,
32    },
33    Forbidden {
34        message: String,
35        required_scopes: Vec<String>,
36    },
37    Sdk {
38        sdk_kind: String,
39        message: String,
40    },
41}
42
43impl Serialize for ToolError {
44    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
45        let value = match self {
46            Self::UnknownAction {
47                message,
48                valid,
49                hint,
50            } => serde_json::json!({
51                "kind": "unknown_action",
52                "message": message,
53                "valid": valid,
54                "hint": hint,
55            }),
56            Self::MissingParam { message, param } => {
57                serde_json::json!({"kind": "missing_param", "message": message, "param": param})
58            }
59            Self::InvalidParam { message, param } => {
60                serde_json::json!({"kind": "invalid_param", "message": message, "param": param})
61            }
62            Self::UnknownInstance { message, valid } => {
63                serde_json::json!({"kind": "unknown_instance", "message": message, "valid": valid})
64            }
65            Self::AmbiguousTool { message, valid } => {
66                serde_json::json!({"kind": "ambiguous_tool", "message": message, "valid": valid})
67            }
68            Self::ConfirmationRequired { message } => {
69                serde_json::json!({"kind": "confirmation_required", "message": message})
70            }
71            Self::Conflict {
72                message,
73                existing_id,
74            } => serde_json::json!({
75                "kind": "conflict",
76                "message": message,
77                "existing_id": existing_id,
78            }),
79            Self::Forbidden {
80                message,
81                required_scopes,
82            } => serde_json::json!({
83                "kind": "forbidden",
84                "message": message,
85                "required_scopes": required_scopes,
86            }),
87            Self::Sdk { sdk_kind, message } => {
88                serde_json::json!({"kind": sdk_kind, "message": message})
89            }
90        };
91        value.serialize(serializer)
92    }
93}
94
95impl std::fmt::Display for ToolError {
96    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97        match serde_json::to_string(self) {
98            Ok(value) => f.write_str(&value),
99            Err(_) => write!(f, "{self:?}"),
100        }
101    }
102}
103
104impl std::error::Error for ToolError {}
105
106impl ToolError {
107    #[must_use]
108    pub fn kind(&self) -> &str {
109        match self {
110            Self::UnknownAction { .. } => "unknown_action",
111            Self::MissingParam { .. } => "missing_param",
112            Self::InvalidParam { .. } => "invalid_param",
113            Self::UnknownInstance { .. } => "unknown_instance",
114            Self::AmbiguousTool { .. } => "ambiguous_tool",
115            Self::ConfirmationRequired { .. } => "confirmation_required",
116            Self::Conflict { .. } => "conflict",
117            Self::Forbidden { .. } => "forbidden",
118            Self::Sdk { sdk_kind, .. } => sdk_kind.as_str(),
119        }
120    }
121
122    #[must_use]
123    pub fn user_message(&self) -> &str {
124        match self {
125            Self::UnknownAction { message, .. }
126            | Self::MissingParam { message, .. }
127            | Self::InvalidParam { message, .. }
128            | Self::UnknownInstance { message, .. }
129            | Self::AmbiguousTool { message, .. }
130            | Self::ConfirmationRequired { message }
131            | Self::Conflict { message, .. }
132            | Self::Forbidden { message, .. }
133            | Self::Sdk { message, .. } => message.as_str(),
134        }
135    }
136
137    #[must_use]
138    pub fn internal_message(message: impl Into<String>) -> Self {
139        Self::Sdk {
140            sdk_kind: "internal_error".to_string(),
141            message: message.into(),
142        }
143    }
144}