use thiserror::Error;
#[derive(Debug, Error)]
pub enum WasmError {
#[error("Engine creation failed: {0}")]
EngineCreationFailed(String),
#[error("Compilation failed: {0}")]
CompilationFailed(String),
#[error("Validation failed: {0}")]
ValidationFailed(String),
#[error("Instantiation failed: {0}")]
InstantiationFailed(String),
#[error("Execution trapped: {0}")]
Trapped(String),
#[error("Execution panicked: {0}")]
ExecutionPanicked(String),
#[error("Fuel exhausted: execution exceeded {limit} fuel units")]
FuelExhausted {
limit: u64,
},
#[error("Memory limit exceeded: {used} bytes used, {limit} bytes allowed")]
MemoryExceeded {
used: u64,
limit: u64,
},
#[error("Missing export: {0}")]
MissingExport(String),
#[error("IO error: {0}")]
IoError(String),
#[error("Configuration error: {0}")]
ConfigError(String),
#[error("Host error: {0}")]
HostError(String),
#[error("Execution timed out after {0:?}")]
Timeout(std::time::Duration),
#[error("Tool error: {message}{}", if hint.is_empty() { String::new() } else { format!("\n\nTool usage hint:\n{hint}") })]
ToolReturnedError {
message: String,
hint: String,
},
#[error("Invalid response JSON: {0}")]
InvalidResponseJson(String),
#[error("Path traversal blocked: {0}")]
PathTraversalBlocked(String),
}
impl From<std::io::Error> for WasmError {
fn from(e: std::io::Error) -> Self {
WasmError::IoError(e.to_string())
}
}
impl From<WasmError> for crate::tools::ToolError {
fn from(e: WasmError) -> Self {
crate::tools::ToolError::Sandbox(e.to_string())
}
}
#[cfg(test)]
mod tests {
use crate::tools::wasm::error::WasmError;
#[test]
fn test_error_display() {
let err = WasmError::FuelExhausted { limit: 1_000_000 };
assert!(err.to_string().contains("1000000"));
let err = WasmError::MemoryExceeded {
used: 20_000_000,
limit: 10_000_000,
};
assert!(err.to_string().contains("20000000"));
assert!(err.to_string().contains("10000000"));
}
#[test]
fn test_conversion_to_tool_error() {
let wasm_err = WasmError::Trapped("test trap".to_string());
let tool_err: crate::tools::ToolError = wasm_err.into();
match tool_err {
crate::tools::ToolError::Sandbox(msg) => {
assert!(msg.contains("test trap"));
}
_ => panic!("Expected Sandbox variant"),
}
}
#[test]
fn test_tool_returned_error_without_hint() {
let err = WasmError::ToolReturnedError {
message: "unknown action: foobar".to_string(),
hint: String::new(),
};
let display = err.to_string();
assert!(display.contains("unknown action: foobar"));
assert!(!display.contains("Tool usage hint"));
}
#[test]
fn test_tool_returned_error_with_hint() {
let err = WasmError::ToolReturnedError {
message: "unknown action: foobar".to_string(),
hint: "Tip: call tool_info(name: \"gmail\", include_schema: true) for the full parameter schema.".to_string(),
};
let display = err.to_string();
assert!(display.contains("unknown action: foobar"));
assert!(display.contains("Tool usage hint"));
assert!(display.contains("tool_info"));
}
}