oxo-call 0.11.0

Model-intelligent orchestration for CLI bioinformatics — call any tool with LLM intelligence
Documentation
use thiserror::Error;

#[derive(Debug, Error)]
pub enum OxoError {
    #[error("Tool '{0}' not found in PATH")]
    ToolNotFound(String),

    #[error("Failed to fetch documentation for '{0}': {1}")]
    DocFetchError(String, String),

    #[error("LLM request failed: {0}")]
    LlmError(String),

    #[error("Configuration error: {0}")]
    ConfigError(String),

    #[error("Index error: {0}")]
    IndexError(String),

    #[error("Command execution failed: {0}")]
    ExecutionError(String),

    #[error("IO error: {0}")]
    IoError(#[from] std::io::Error),

    #[error("JSON error: {0}")]
    JsonError(#[from] serde_json::Error),

    #[cfg(not(target_arch = "wasm32"))]
    #[error("HTTP error: {0}")]
    HttpError(#[from] reqwest::Error),

    #[error("TOML deserialization error: {0}")]
    TomlDeError(#[from] toml::de::Error),

    #[error("TOML serialization error: {0}")]
    TomlSeError(#[from] toml::ser::Error),
}

pub type Result<T> = std::result::Result<T, OxoError>;

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_tool_not_found_display() {
        let e = OxoError::ToolNotFound("samtools".to_string());
        assert_eq!(e.to_string(), "Tool 'samtools' not found in PATH");
    }

    #[test]
    fn test_doc_fetch_error_display() {
        let e = OxoError::DocFetchError("bwa".to_string(), "timeout".to_string());
        assert_eq!(
            e.to_string(),
            "Failed to fetch documentation for 'bwa': timeout"
        );
    }

    #[test]
    fn test_llm_error_display() {
        let e = OxoError::LlmError("rate limit exceeded".to_string());
        assert_eq!(e.to_string(), "LLM request failed: rate limit exceeded");
    }

    #[test]
    fn test_config_error_display() {
        let e = OxoError::ConfigError("missing api_token".to_string());
        assert_eq!(e.to_string(), "Configuration error: missing api_token");
    }

    #[test]
    fn test_index_error_display() {
        let e = OxoError::IndexError("corrupt index".to_string());
        assert_eq!(e.to_string(), "Index error: corrupt index");
    }

    #[test]
    fn test_execution_error_display() {
        let e = OxoError::ExecutionError("exit code 1".to_string());
        assert_eq!(e.to_string(), "Command execution failed: exit code 1");
    }

    #[test]
    fn test_from_io_error() {
        let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
        let e: OxoError = io_err.into();
        assert!(e.to_string().contains("IO error"));
    }

    #[test]
    fn test_from_json_error() {
        let json_err = serde_json::from_str::<serde_json::Value>("{bad json").unwrap_err();
        let e: OxoError = json_err.into();
        assert!(e.to_string().contains("JSON error"));
    }

    #[test]
    fn test_from_toml_de_error() {
        let toml_err = toml::from_str::<toml::Value>("bad = [[[").unwrap_err();
        let e: OxoError = toml_err.into();
        assert!(e.to_string().contains("TOML deserialization error"));
    }

    #[test]
    fn test_result_type_alias() {
        let ok: Result<i32> = Ok(42);
        assert_eq!(ok.unwrap(), 42);

        let err: Result<i32> = Err(OxoError::LlmError("test".to_string()));
        assert!(err.is_err());
    }
}