diff options
Diffstat (limited to 'crates/asist-core/src/error.rs')
| -rw-r--r-- | crates/asist-core/src/error.rs | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/crates/asist-core/src/error.rs b/crates/asist-core/src/error.rs new file mode 100644 index 0000000..b559bee --- /dev/null +++ b/crates/asist-core/src/error.rs @@ -0,0 +1,82 @@ +use std::fmt; + +pub type Result<T> = std::result::Result<T, Error>; + +/// Un fallo de una etapa del pipeline. El orquestador decide si es fatal o si +/// basta con abortar el turno en curso, así que el error lleva esa distinción +/// en lugar de dejarla al criterio de quien lo recibe. +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("configuración inválida: {0}")] + Config(String), + + #[error("audio: {0}")] + Audio(String), + + #[error("ASR: {0}")] + Asr(String), + + #[error("LLM: {0}")] + Llm(String), + + #[error("TTS: {0}")] + Tts(String), + + #[error("HTTP {status} en {url}: {body}")] + Http { + status: u16, + url: String, + body: String, + }, + + #[error("transporte hacia {url}: {source}")] + Transport { + url: String, + #[source] + source: std::io::Error, + }, + + #[error("herramienta «{tool}»: {message}")] + Tool { tool: String, message: String }, + + #[error("operación cancelada")] + Cancelled, + + #[error(transparent)] + Json(#[from] serde_json::Error), + + #[error(transparent)] + Io(#[from] std::io::Error), +} + +impl Error { + /// Un error fatal tumba el asistente; el resto sólo aborta el turno. + /// + /// Los servidores locales se caen y se reinician, y el usuario prefiere + /// oír «no te he entendido» a que el proceso muera, así que sólo la + /// configuración y el audio (que no se pueden reintentar) son fatales. + pub fn is_fatal(&self) -> bool { + matches!(self, Error::Config(_) | Error::Audio(_)) + } + + /// `true` cuando reintentar tiene sentido: el servidor aún está cargando + /// el modelo, o se ha caído la conexión a mitad de una petición. + pub fn is_retryable(&self) -> bool { + match self { + Error::Transport { .. } => true, + Error::Http { status, .. } => *status == 503 || *status == 429 || *status >= 500, + _ => false, + } + } +} + +/// Contexto legible para los `Result` que cruzan una frontera de crate. +pub trait Context<T> { + fn ctx(self, f: impl FnOnce() -> String) -> Result<T>; +} + +impl<T, E: fmt::Display> Context<T> for std::result::Result<T, E> { + fn ctx(self, f: impl FnOnce() -> String) -> Result<T> { + self.map_err(|e| Error::Config(format!("{}: {}", f(), e))) + } +} |