Skip to main content

symbi_runtime/routing/
error.rs

1//! Error types for the routing module
2
3use crate::config::ModelCapability;
4use thiserror::Error;
5
6/// Errors that can occur during routing operations
7#[derive(Debug, Error)]
8pub enum RoutingError {
9    #[error("Policy evaluation failed: {reason}")]
10    PolicyEvaluationFailed { reason: String },
11
12    #[error("No suitable model found for task: {task_type:?}")]
13    NoSuitableModel { task_type: TaskType },
14
15    #[error("Model execution failed: {model_id} - {reason}")]
16    ModelExecutionFailed { model_id: String, reason: String },
17
18    #[error("LLM fallback failed: {provider} - {reason}")]
19    LLMFallbackFailed { provider: String, reason: String },
20
21    #[error("Routing denied by policy: {policy} - {reason}")]
22    RoutingDenied { policy: String, reason: String },
23
24    #[error("Task classification failed: {reason}")]
25    ClassificationFailed { reason: String },
26
27    #[error("Configuration error: {key} - {reason}")]
28    ConfigurationError { key: String, reason: String },
29
30    #[error("Resource constraint violation: {constraint}")]
31    ResourceConstraintViolation { constraint: String },
32
33    #[error("Confidence evaluation failed: {reason}")]
34    ConfidenceEvaluationFailed { reason: String },
35
36    #[error("Invalid routing context: {reason}")]
37    InvalidContext { reason: String },
38
39    #[error("Model catalog error: {reason}")]
40    ModelCatalogError { reason: String },
41
42    #[error("Timeout during routing: {operation}")]
43    Timeout { operation: String },
44
45    #[error("Invalid model selection: {model_id} - {reason}")]
46    InvalidModelSelection { model_id: String, reason: String },
47
48    #[error("Policy rule parsing failed: {rule} - {reason}")]
49    PolicyRuleParsingFailed { rule: String, reason: String },
50
51    #[error("Confidence threshold not met: current={current}, required={required}")]
52    ConfidenceThresholdNotMet { current: f64, required: f64 },
53
54    #[error("Routing context validation failed: {field} - {reason}")]
55    ContextValidationFailed { field: String, reason: String },
56
57    #[error("Model capability mismatch: required={required:?}, available={available:?}")]
58    CapabilityMismatch {
59        required: Vec<crate::config::ModelCapability>,
60        available: Vec<crate::config::ModelCapability>,
61    },
62
63    #[error("External provider error: {provider} - {error}")]
64    ExternalProviderError { provider: String, error: String },
65
66    #[error("Concurrent access error: {resource}")]
67    ConcurrentAccessError { resource: String },
68
69    #[error("Resource exhaustion: {resource} - {details}")]
70    ResourceExhaustion { resource: String, details: String },
71
72    #[error("Serialization error: {context} - {source}")]
73    SerializationError {
74        context: String,
75        #[source]
76        source: serde_json::Error,
77    },
78}
79
80/// Result type for routing operations
81pub type RoutingResult<T> = Result<T, RoutingError>;
82
83impl RoutingError {
84    /// Check if the error is retryable
85    pub fn is_retryable(&self) -> bool {
86        matches!(
87            self,
88            RoutingError::Timeout { .. }
89                | RoutingError::ExternalProviderError { .. }
90                | RoutingError::ConcurrentAccessError { .. }
91                | RoutingError::ResourceExhaustion { .. }
92                | RoutingError::ModelExecutionFailed { .. }
93        )
94    }
95
96    /// Get error severity level
97    pub fn severity(&self) -> ErrorSeverity {
98        match self {
99            RoutingError::PolicyEvaluationFailed { .. } => ErrorSeverity::High,
100            RoutingError::NoSuitableModel { .. } => ErrorSeverity::High,
101            RoutingError::LLMFallbackFailed { .. } => ErrorSeverity::Critical,
102            RoutingError::RoutingDenied { .. } => ErrorSeverity::Medium,
103            RoutingError::ConfigurationError { .. } => ErrorSeverity::High,
104            RoutingError::InvalidContext { .. } => ErrorSeverity::Medium,
105            RoutingError::CapabilityMismatch { .. } => ErrorSeverity::Medium,
106            RoutingError::ExternalProviderError { .. } => ErrorSeverity::Medium,
107            RoutingError::ResourceExhaustion { .. } => ErrorSeverity::High,
108            _ => ErrorSeverity::Low,
109        }
110    }
111}
112
113/// Error severity levels
114#[derive(Debug, Clone, Copy, PartialEq, Eq)]
115pub enum ErrorSeverity {
116    Low,
117    Medium,
118    High,
119    Critical,
120}
121
122/// Task type enumeration for routing decisions
123#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
124pub enum TaskType {
125    Intent,
126    Extract,
127    Template,
128    BoilerplateCode,
129    CodeGeneration,
130    Reasoning,
131    Analysis,
132    Summarization,
133    Translation,
134    QA,
135    Custom(String),
136}
137
138impl TaskType {
139    /// Convert task type to required model capabilities
140    pub fn to_capabilities(&self) -> Vec<ModelCapability> {
141        match self {
142            TaskType::CodeGeneration | TaskType::BoilerplateCode => {
143                vec![
144                    ModelCapability::CodeGeneration,
145                    ModelCapability::TextGeneration,
146                ]
147            }
148            TaskType::Reasoning | TaskType::Analysis => {
149                vec![ModelCapability::Reasoning, ModelCapability::TextGeneration]
150            }
151            TaskType::Intent | TaskType::Extract | TaskType::Template => {
152                vec![ModelCapability::TextGeneration]
153            }
154            TaskType::Summarization | TaskType::Translation | TaskType::QA => {
155                vec![ModelCapability::TextGeneration]
156            }
157            TaskType::Custom(_) => {
158                vec![ModelCapability::TextGeneration]
159            }
160        }
161    }
162
163    /// Get the complexity level of the task type
164    pub fn complexity_level(&self) -> u8 {
165        match self {
166            TaskType::Intent | TaskType::Extract | TaskType::Template => 1,
167            TaskType::BoilerplateCode | TaskType::Summarization | TaskType::Translation => 2,
168            TaskType::QA | TaskType::CodeGeneration => 3,
169            TaskType::Reasoning | TaskType::Analysis => 4,
170            TaskType::Custom(_) => 2, // Default to medium complexity
171        }
172    }
173}
174
175impl std::fmt::Display for TaskType {
176    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177        match self {
178            TaskType::Intent => write!(f, "Intent"),
179            TaskType::Extract => write!(f, "Extract"),
180            TaskType::Template => write!(f, "Template"),
181            TaskType::BoilerplateCode => write!(f, "BoilerplateCode"),
182            TaskType::CodeGeneration => write!(f, "CodeGeneration"),
183            TaskType::Reasoning => write!(f, "Reasoning"),
184            TaskType::Analysis => write!(f, "Analysis"),
185            TaskType::Summarization => write!(f, "Summarization"),
186            TaskType::Translation => write!(f, "Translation"),
187            TaskType::QA => write!(f, "QA"),
188            TaskType::Custom(name) => write!(f, "Custom({})", name),
189        }
190    }
191}
192
193impl From<crate::models::ModelCatalogError> for RoutingError {
194    fn from(err: crate::models::ModelCatalogError) -> Self {
195        RoutingError::ModelCatalogError {
196            reason: err.to_string(),
197        }
198    }
199}
200
201impl From<super::confidence::ConfidenceError> for RoutingError {
202    fn from(err: super::confidence::ConfidenceError) -> Self {
203        RoutingError::ConfidenceEvaluationFailed {
204            reason: err.to_string(),
205        }
206    }
207}