use std::fmt::Formatter;
use std::path::Path;
use error_stack::Report;
use serde_json::Value;
use thiserror::Error;
use super::tool::ResultStruct;
use crate::constants::MSG_FAILED_TO_PREFIX;
use crate::constants::MSG_INVALID_PREFIX;
use crate::constants::MSG_MISSING_PREFIX;
pub(crate) type Result<T> = core::result::Result<T, Report<Error>>;
#[derive(Error)]
pub(crate) enum Error {
#[error("BRP communication failed: {0}")]
BrpCommunication(String),
#[error("File operation failed: {0}")]
FileOperation(String),
#[error("File or path not found error: {0}")]
FileOrPathNotFound(String),
#[error("{0}")]
General(String),
#[error("Invalid argument: {0}")]
InvalidArgument(String),
#[error("Invalid state: {0}")]
InvalidState(String),
#[error("JSON-RPC error: {0}")]
JsonRpc(String),
#[error("Log operation failed: {0}")]
LogOperation(String),
#[error("Configuration error: {0}")]
MissingMessageTemplate(String),
#[error("Unable to extract parameters: {0}")]
ParameterExtraction(String),
#[error("Process management error: {0}")]
ProcessManagement(String),
#[error("Schema processing error: {message}")]
SchemaProcessing {
message: String,
type_name: Option<String>,
operation: Option<String>,
details: Option<String>,
},
#[error("Structured error")] Structured { result: Box<dyn ResultStruct> },
#[error("Tool call error: {message}")]
ToolCall {
message: String,
details: Option<Value>,
},
#[error("Watch operation failed: {0}")]
WatchOperation(String),
}
impl std::fmt::Debug for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::BrpCommunication(s) => f.debug_tuple("BrpCommunication").field(s).finish(),
Self::FileOperation(s) => f.debug_tuple("FileOperation").field(s).finish(),
Self::FileOrPathNotFound(s) => f.debug_tuple("FileOrPathNotFound").field(s).finish(),
Self::General(s) => f.debug_tuple("General").field(s).finish(),
Self::InvalidArgument(s) => f.debug_tuple("InvalidArgument").field(s).finish(),
Self::InvalidState(s) => f.debug_tuple("InvalidState").field(s).finish(),
Self::JsonRpc(s) => f.debug_tuple("JsonRpc").field(s).finish(),
Self::LogOperation(s) => f.debug_tuple("LogOperation").field(s).finish(),
Self::MissingMessageTemplate(s) => f.debug_tuple("Configuration").field(s).finish(),
Self::ParameterExtraction(s) => f.debug_tuple("ParameterExtraction").field(s).finish(),
Self::ProcessManagement(s) => f.debug_tuple("ProcessManagement").field(s).finish(),
Self::SchemaProcessing {
message,
type_name,
operation,
details,
} => f
.debug_struct("SchemaProcessing")
.field("message", message)
.field("type_name", type_name)
.field("operation", operation)
.field("details", details)
.finish(),
Self::Structured { .. } => f
.debug_struct("Structured")
.field("result", &"<dyn ResultStruct>")
.finish(),
Self::ToolCall { message, details } => f
.debug_struct("ToolCall")
.field("message", message)
.field("details", details)
.finish(),
Self::WatchOperation(s) => f.debug_tuple("WatchOperation").field(s).finish(),
}
}
}
impl Error {
pub(crate) fn failed_to(action: &str, details: impl std::fmt::Display) -> Self {
Self::General(format!("{MSG_FAILED_TO_PREFIX} {action}: {details}"))
}
pub(crate) fn invalid(what: &str, details: impl std::fmt::Display) -> Self {
Self::InvalidArgument(format!("{MSG_INVALID_PREFIX} {what}: {details}"))
}
pub(crate) fn missing(what: &str) -> Self {
Self::InvalidArgument(format!("{MSG_MISSING_PREFIX} {what}"))
}
pub(crate) fn io_failed(operation: &str, path: &Path, error: impl std::fmt::Display) -> Self {
Self::LogOperation(format!(
"{MSG_FAILED_TO_PREFIX} {operation} {}: {error}",
path.display()
))
}
pub(crate) fn tool_call_failed(message: impl Into<String>) -> Self {
Self::ToolCall {
message: message.into(),
details: None,
}
}
pub(crate) fn tool_call_failed_with_details(
message: impl Into<String>,
details: Value,
) -> Self {
Self::ToolCall {
message: message.into(),
details: Some(details),
}
}
pub(crate) fn schema_processing_for_type(
type_name: impl Into<String>,
operation: impl Into<String>,
details: impl Into<String>,
) -> Self {
Self::SchemaProcessing {
message: "Failed to process schema for type".to_string(),
type_name: Some(type_name.into()),
operation: Some(operation.into()),
details: Some(details.into()),
}
}
}