use thiserror::Error;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Error, Debug)]
pub enum Error {
#[error("Inference error: {0}")]
Inference(String),
#[error("Context length exceeded: {0}")]
ContextLengthExceeded(String),
#[error("Retries exceeded: {0}")]
RetriesExceeded(String),
#[error("Non-retryable error: {0}")]
NonRetryable(String),
#[error("Parse error: {0}")]
Parse(String),
#[error("Validation error: {0}")]
Validation(String),
#[error("Tool not found: {0}")]
ToolNotFound(String),
#[error("Network error: {0}")]
Network(#[from] reqwest::Error),
#[error("JSON error: {0}")]
Json(#[from] serde_json::Error),
#[error("UTF-8 error: {0}")]
Utf8(#[from] std::str::Utf8Error),
#[error("UTF-8 conversion error: {0}")]
FromUtf8(#[from] std::string::FromUtf8Error),
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Invalid provider: {0}")]
InvalidProvider(String),
#[error("Missing API key: {0}")]
MissingApiKey(String),
#[error("Runtime was not used in agentic function")]
RuntimeNotUsed,
}
impl Error {
pub fn is_retryable(&self) -> bool {
matches!(self, Error::Inference(_) | Error::Network(_) | Error::Io(_))
}
pub fn is_retries_exceeded(&self) -> bool {
matches!(self, Error::RetriesExceeded(_))
}
pub fn is_incomplete(&self) -> bool {
matches!(self, Error::Parse(msg) if msg.contains("incomplete"))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display() {
let err = Error::Inference("rate limit".to_string());
assert_eq!(err.to_string(), "Inference error: rate limit");
}
#[test]
fn test_is_retryable() {
assert!(Error::Inference("test".to_string()).is_retryable());
assert!(Error::Io(std::io::Error::other("test")).is_retryable());
assert!(!Error::NonRetryable("test".to_string()).is_retryable());
assert!(!Error::Validation("test".to_string()).is_retryable());
}
#[test]
fn test_is_retries_exceeded() {
assert!(Error::RetriesExceeded("test".to_string()).is_retries_exceeded());
assert!(!Error::Inference("test".to_string()).is_retries_exceeded());
}
#[test]
fn test_is_incomplete() {
assert!(Error::Parse("incomplete data".to_string()).is_incomplete());
assert!(!Error::Parse("malformed json".to_string()).is_incomplete());
}
#[test]
fn test_from_conversions() {
let json_err: Error = serde_json::from_str::<i32>("invalid").unwrap_err().into();
assert!(matches!(json_err, Error::Json(_)));
let io_err: Error = std::io::Error::other("test").into();
assert!(matches!(io_err, Error::Io(_)));
}
}