use crate::llm::error::{BackendErrorKind, LlmError};
pub(super) fn should_failover(err: &LlmError) -> bool {
match err {
LlmError::Transport { status: None, .. } => true,
LlmError::Transport {
status: Some(code), ..
} => is_retryable_status(*code),
LlmError::Unparseable(_) => true,
LlmError::ModelStopped { .. } => false,
LlmError::NotConfigured(_) => false,
LlmError::Backend { kind, .. } => matches!(kind, BackendErrorKind::UsageLimit),
}
}
pub(super) fn is_sticky(err: &LlmError) -> bool {
(should_failover(err) && !matches!(err, LlmError::Unparseable(_)))
|| is_auth_failure(err)
|| is_sticky_backend_failure(err)
}
fn is_sticky_backend_failure(err: &LlmError) -> bool {
matches!(
err,
LlmError::Backend {
kind: BackendErrorKind::Contract | BackendErrorKind::Authentication,
..
}
)
}
fn is_auth_failure(err: &LlmError) -> bool {
matches!(
err,
LlmError::Transport {
status: Some(401 | 403),
..
}
)
}
fn is_retryable_status(code: u16) -> bool {
matches!(code, 408 | 429) || (500..=599).contains(&code)
}