headless_lms_chatbot/
chatbot_error.rs1use std::fmt::Display;
6
7use backtrace::Backtrace;
8use headless_lms_models::ModelError;
9use tracing_error::SpanTrace;
10
11use headless_lms_utils::error::backend_error::BackendError;
12
13pub type ChatbotResult<T> = Result<T, ChatbotError>;
17
18#[derive(Debug)]
20pub enum ChatbotErrorType {
21 InvalidMessageShape,
22 InvalidToolName,
23 InvalidToolArguments,
24 ChatbotModelError,
25 UrlParse,
26 TokioIo,
27 SerdeJson,
28 Other,
29 DeserializationError,
30}
31
32#[derive(Debug)]
84pub struct ChatbotError {
85 error_type: <ChatbotError as BackendError>::ErrorType,
86 message: String,
87 source: Option<anyhow::Error>,
89 span_trace: Box<SpanTrace>,
91 backtrace: Box<Backtrace>,
93}
94
95impl std::error::Error for ChatbotError {
96 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
97 self.source.as_ref().and_then(|o| o.source())
98 }
99
100 fn cause(&self) -> Option<&dyn std::error::Error> {
101 self.source()
102 }
103}
104
105impl Display for ChatbotError {
106 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107 write!(f, "ChatbotError {:?} {:?}", self.error_type, self.message)
108 }
109}
110
111impl BackendError for ChatbotError {
112 type ErrorType = ChatbotErrorType;
113
114 fn new<M: Into<String>, S: Into<Option<anyhow::Error>>>(
115 error_type: Self::ErrorType,
116 message: M,
117 source_error: S,
118 ) -> Self {
119 Self::new_with_traces(
120 error_type,
121 message,
122 source_error,
123 Backtrace::new(),
124 SpanTrace::capture(),
125 )
126 }
127
128 fn backtrace(&self) -> Option<&Backtrace> {
129 Some(&self.backtrace)
130 }
131
132 fn error_type(&self) -> &Self::ErrorType {
133 &self.error_type
134 }
135
136 fn message(&self) -> &str {
137 &self.message
138 }
139
140 fn span_trace(&self) -> &SpanTrace {
141 &self.span_trace
142 }
143
144 fn new_with_traces<M: Into<String>, S: Into<Option<anyhow::Error>>>(
145 error_type: Self::ErrorType,
146 message: M,
147 source_error: S,
148 backtrace: Backtrace,
149 span_trace: SpanTrace,
150 ) -> Self {
151 Self {
152 error_type,
153 message: message.into(),
154 source: source_error.into(),
155 span_trace: Box::new(span_trace),
156 backtrace: Box::new(backtrace),
157 }
158 }
159}
160
161impl From<url::ParseError> for ChatbotError {
162 fn from(source: url::ParseError) -> Self {
163 ChatbotError::new(
164 ChatbotErrorType::UrlParse,
165 source.to_string(),
166 Some(source.into()),
167 )
168 }
169}
170
171impl From<tokio::io::Error> for ChatbotError {
172 fn from(source: tokio::io::Error) -> Self {
173 ChatbotError::new(
174 ChatbotErrorType::TokioIo,
175 source.to_string(),
176 Some(source.into()),
177 )
178 }
179}
180
181impl From<serde_json::Error> for ChatbotError {
182 fn from(source: serde_json::Error) -> Self {
183 ChatbotError::new(
184 ChatbotErrorType::SerdeJson,
185 source.to_string(),
186 Some(source.into()),
187 )
188 }
189}
190
191impl From<anyhow::Error> for ChatbotError {
192 fn from(err: anyhow::Error) -> ChatbotError {
193 Self::new(ChatbotErrorType::Other, err.to_string(), Some(err))
194 }
195}
196
197impl From<ModelError> for ChatbotError {
198 fn from(err: ModelError) -> ChatbotError {
199 Self::new(
200 ChatbotErrorType::ChatbotModelError,
201 err.to_string(),
202 Some(err.into()),
203 )
204 }
205}