ultrafast_mcp_sequential_thinking/thinking/
error.rs1use thiserror::Error;
10
11#[derive(Error, Debug)]
13pub enum SequentialThinkingError {
14 #[error("Invalid thought data: {message}")]
16 InvalidThoughtData { message: String },
17
18 #[error("Thought processing error: {message}")]
20 ProcessingError { message: String },
21
22 #[error("Session error: {message}")]
24 SessionError { message: String },
25
26 #[error("Branch error: {message}")]
28 BranchError { message: String },
29
30 #[error("Validation error: {message}")]
32 ValidationError { message: String },
33
34 #[error("Configuration error: {message}")]
36 ConfigError { message: String },
37
38 #[error("Serialization error: {message}")]
40 SerializationError { message: String },
41
42 #[error("Transport error: {message}")]
44 TransportError { message: String },
45
46 #[error("Internal error: {message}")]
48 InternalError { message: String },
49
50 #[error("Resource not found: {resource}")]
52 NotFound { resource: String },
53
54 #[error("Permission denied: {reason}")]
56 PermissionDenied { reason: String },
57
58 #[error("Rate limit exceeded: {limit}")]
60 RateLimitExceeded { limit: String },
61
62 #[error("Operation timed out after {duration:?}")]
64 Timeout { duration: std::time::Duration },
65
66 #[error("Operation was cancelled: {reason}")]
68 Cancelled { reason: String },
69
70 #[error("Wrapped error: {source}")]
72 Wrapped {
73 #[from]
74 source: Box<dyn std::error::Error + Send + Sync>,
75 },
76}
77
78impl SequentialThinkingError {
79 pub fn invalid_thought_data(message: impl Into<String>) -> Self {
81 Self::InvalidThoughtData {
82 message: message.into(),
83 }
84 }
85
86 pub fn processing_error(message: impl Into<String>) -> Self {
88 Self::ProcessingError {
89 message: message.into(),
90 }
91 }
92
93 pub fn session_error(message: impl Into<String>) -> Self {
95 Self::SessionError {
96 message: message.into(),
97 }
98 }
99
100 pub fn branch_error(message: impl Into<String>) -> Self {
102 Self::BranchError {
103 message: message.into(),
104 }
105 }
106
107 pub fn validation_error(message: impl Into<String>) -> Self {
109 Self::ValidationError {
110 message: message.into(),
111 }
112 }
113
114 pub fn config_error(message: impl Into<String>) -> Self {
116 Self::ConfigError {
117 message: message.into(),
118 }
119 }
120
121 pub fn serialization_error(message: impl Into<String>) -> Self {
123 Self::SerializationError {
124 message: message.into(),
125 }
126 }
127
128 pub fn transport_error(message: impl Into<String>) -> Self {
130 Self::TransportError {
131 message: message.into(),
132 }
133 }
134
135 pub fn internal_error(message: impl Into<String>) -> Self {
137 Self::InternalError {
138 message: message.into(),
139 }
140 }
141
142 pub fn not_found(resource: impl Into<String>) -> Self {
144 Self::NotFound {
145 resource: resource.into(),
146 }
147 }
148
149 pub fn permission_denied(reason: impl Into<String>) -> Self {
151 Self::PermissionDenied {
152 reason: reason.into(),
153 }
154 }
155
156 pub fn rate_limit_exceeded(limit: impl Into<String>) -> Self {
158 Self::RateLimitExceeded {
159 limit: limit.into(),
160 }
161 }
162
163 pub fn timeout(duration: std::time::Duration) -> Self {
165 Self::Timeout { duration }
166 }
167
168 pub fn cancelled(reason: impl Into<String>) -> Self {
170 Self::Cancelled {
171 reason: reason.into(),
172 }
173 }
174
175 pub fn is_retryable(&self) -> bool {
177 matches!(
178 self,
179 Self::TransportError { .. } | Self::Timeout { .. } | Self::RateLimitExceeded { .. }
180 )
181 }
182
183 pub fn is_client_error(&self) -> bool {
185 matches!(
186 self,
187 Self::InvalidThoughtData { .. }
188 | Self::ValidationError { .. }
189 | Self::ConfigError { .. }
190 | Self::NotFound { .. }
191 | Self::PermissionDenied { .. }
192 )
193 }
194
195 pub fn is_server_error(&self) -> bool {
197 matches!(
198 self,
199 Self::ProcessingError { .. }
200 | Self::SessionError { .. }
201 | Self::BranchError { .. }
202 | Self::InternalError { .. }
203 | Self::SerializationError { .. }
204 )
205 }
206
207 pub fn user_message(&self) -> String {
209 match self {
210 Self::InvalidThoughtData { message } => {
211 format!("Invalid thought data: {message}")
212 }
213 Self::ProcessingError { message } => {
214 format!("Failed to process thought: {message}")
215 }
216 Self::SessionError { message } => {
217 format!("Session error: {message}")
218 }
219 Self::BranchError { message } => {
220 format!("Branch error: {message}")
221 }
222 Self::ValidationError { message } => {
223 format!("Validation failed: {message}")
224 }
225 Self::ConfigError { message } => {
226 format!("Configuration error: {message}")
227 }
228 Self::SerializationError { message } => {
229 format!("Data format error: {message}")
230 }
231 Self::TransportError { message } => {
232 format!("Connection error: {message}")
233 }
234 Self::InternalError { message } => {
235 format!("System error: {message}")
236 }
237 Self::NotFound { resource } => {
238 format!("Resource not found: {resource}")
239 }
240 Self::PermissionDenied { reason } => {
241 format!("Access denied: {reason}")
242 }
243 Self::RateLimitExceeded { limit } => {
244 format!("Too many requests: {limit}")
245 }
246 Self::Timeout { duration } => {
247 format!("Operation timed out after {duration:?}")
248 }
249 Self::Cancelled { reason } => {
250 format!("Operation cancelled: {reason}")
251 }
252 Self::Wrapped { source } => {
253 format!("Error: {source}")
254 }
255 }
256 }
257
258 pub fn error_code(&self) -> &'static str {
260 match self {
261 Self::InvalidThoughtData { .. } => "INVALID_THOUGHT_DATA",
262 Self::ProcessingError { .. } => "PROCESSING_ERROR",
263 Self::SessionError { .. } => "SESSION_ERROR",
264 Self::BranchError { .. } => "BRANCH_ERROR",
265 Self::ValidationError { .. } => "VALIDATION_ERROR",
266 Self::ConfigError { .. } => "CONFIG_ERROR",
267 Self::SerializationError { .. } => "SERIALIZATION_ERROR",
268 Self::TransportError { .. } => "TRANSPORT_ERROR",
269 Self::InternalError { .. } => "INTERNAL_ERROR",
270 Self::NotFound { .. } => "NOT_FOUND",
271 Self::PermissionDenied { .. } => "PERMISSION_DENIED",
272 Self::RateLimitExceeded { .. } => "RATE_LIMIT_EXCEEDED",
273 Self::Timeout { .. } => "TIMEOUT",
274 Self::Cancelled { .. } => "CANCELLED",
275 Self::Wrapped { .. } => "WRAPPED_ERROR",
276 }
277 }
278}
279
280pub type SequentialThinkingResult<T> = Result<T, SequentialThinkingError>;
282
283#[derive(Debug, Clone)]
285pub struct ErrorContext {
286 pub operation: String,
288 pub context: std::collections::HashMap<String, String>,
290 pub timestamp: chrono::DateTime<chrono::Utc>,
292}
293
294impl ErrorContext {
295 pub fn new(operation: impl Into<String>) -> Self {
297 Self {
298 operation: operation.into(),
299 context: std::collections::HashMap::new(),
300 timestamp: chrono::Utc::now(),
301 }
302 }
303
304 pub fn with_context(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
306 self.context.insert(key.into(), value.into());
307 self
308 }
309
310 pub fn with_contexts(mut self, contexts: Vec<(String, String)>) -> Self {
312 for (key, value) in contexts {
313 self.context.insert(key, value);
314 }
315 self
316 }
317}
318
319pub mod utils {
321 use super::*;
322
323 pub fn from_string_error(error: String) -> SequentialThinkingError {
325 SequentialThinkingError::InternalError { message: error }
326 }
327
328 pub fn from_generic_error<E: std::error::Error + Send + Sync + 'static>(
330 error: E,
331 ) -> SequentialThinkingError {
332 SequentialThinkingError::Wrapped {
333 source: Box::new(error),
334 }
335 }
336
337 pub fn timeout_error(duration: std::time::Duration) -> SequentialThinkingError {
339 SequentialThinkingError::Timeout { duration }
340 }
341
342 pub fn field_validation_error(field: &str, message: &str) -> SequentialThinkingError {
344 SequentialThinkingError::ValidationError {
345 message: format!("Field '{field}': {message}"),
346 }
347 }
348
349 pub fn required_field_error(field: &str) -> SequentialThinkingError {
351 field_validation_error(field, "Field is required")
352 }
353
354 pub fn invalid_format_error(field: &str, expected: &str) -> SequentialThinkingError {
356 field_validation_error(field, &format!("Expected format: {expected}"))
357 }
358}
359
360impl From<std::io::Error> for SequentialThinkingError {
362 fn from(err: std::io::Error) -> Self {
363 Self::TransportError {
364 message: err.to_string(),
365 }
366 }
367}
368
369impl From<serde_json::Error> for SequentialThinkingError {
370 fn from(err: serde_json::Error) -> Self {
371 Self::SerializationError {
372 message: err.to_string(),
373 }
374 }
375}
376
377impl From<uuid::Error> for SequentialThinkingError {
378 fn from(err: uuid::Error) -> Self {
379 Self::ValidationError {
380 message: err.to_string(),
381 }
382 }
383}
384
385impl From<chrono::ParseError> for SequentialThinkingError {
386 fn from(err: chrono::ParseError) -> Self {
387 Self::ValidationError {
388 message: err.to_string(),
389 }
390 }
391}
392
393#[cfg(test)]
394mod tests {
395 use super::*;
396
397 #[test]
398 fn test_error_creation() {
399 let error = SequentialThinkingError::invalid_thought_data("Empty thought");
400 assert!(matches!(
401 error,
402 SequentialThinkingError::InvalidThoughtData { .. }
403 ));
404 assert!(error.is_client_error());
405 assert!(!error.is_retryable());
406 }
407
408 #[test]
409 fn test_error_codes() {
410 let error = SequentialThinkingError::processing_error("Test");
411 assert_eq!(error.error_code(), "PROCESSING_ERROR");
412 }
413
414 #[test]
415 fn test_user_message() {
416 let error = SequentialThinkingError::validation_error("Invalid input");
417 let message = error.user_message();
418 assert!(message.contains("Validation failed"));
419 assert!(message.contains("Invalid input"));
420 }
421
422 #[test]
423 fn test_error_context() {
424 let context = ErrorContext::new("test_operation")
425 .with_context("user_id", "123")
426 .with_context("session_id", "abc");
427
428 assert_eq!(context.operation, "test_operation");
429 assert_eq!(context.context.get("user_id"), Some(&"123".to_string()));
430 assert_eq!(context.context.get("session_id"), Some(&"abc".to_string()));
431 }
432
433 #[test]
434 fn test_from_implementations() {
435 let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, "File not found");
436 let mcp_error: SequentialThinkingError = io_error.into();
437 assert!(matches!(
438 mcp_error,
439 SequentialThinkingError::TransportError { .. }
440 ));
441
442 let json_error = serde_json::from_str::<serde_json::Value>("invalid json").unwrap_err();
443 let mcp_error: SequentialThinkingError = json_error.into();
444 assert!(matches!(
445 mcp_error,
446 SequentialThinkingError::SerializationError { .. }
447 ));
448 }
449}