fm_rs/
error.rs

1//! Error types for `FoundationModels` operations.
2
3use std::ffi::NulError;
4use std::fmt;
5use std::sync::PoisonError as StdPoisonError;
6
7/// Result type for `FoundationModels` operations.
8pub type Result<T> = std::result::Result<T, Error>;
9
10/// Error types for `FoundationModels` operations.
11#[derive(Debug)]
12pub enum Error {
13    /// Model is not available on this device.
14    ModelNotAvailable,
15
16    /// Device is not eligible for Apple Intelligence.
17    DeviceNotEligible,
18
19    /// Apple Intelligence is not enabled in system settings.
20    AppleIntelligenceNotEnabled,
21
22    /// Model is not ready (downloading or other system reasons).
23    ModelNotReady,
24
25    /// Invalid input provided (e.g., string contains null bytes).
26    InvalidInput(String),
27
28    /// Error during generation.
29    GenerationError(String),
30
31    /// Operation timed out.
32    Timeout(String),
33
34    /// Error during tool invocation.
35    ToolCall(ToolCallError),
36
37    /// Internal error in the FFI layer.
38    InternalError(String),
39
40    /// A lock was poisoned.
41    PoisonError,
42
43    /// JSON serialization/deserialization error.
44    Json(String),
45}
46
47/// Error that occurred during tool invocation.
48#[derive(Debug, Clone)]
49pub struct ToolCallError {
50    /// Name of the tool that failed.
51    pub tool_name: String,
52    /// Arguments passed to the tool.
53    pub arguments: serde_json::Value,
54    /// Description of the error.
55    pub inner_error: String,
56}
57
58impl fmt::Display for Error {
59    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60        match self {
61            Error::ModelNotAvailable => {
62                write!(f, "FoundationModels is not available on this device")
63            }
64            Error::DeviceNotEligible => write!(f, "Device is not eligible for Apple Intelligence"),
65            Error::AppleIntelligenceNotEnabled => {
66                write!(f, "Apple Intelligence is not enabled in system settings")
67            }
68            Error::ModelNotReady => {
69                write!(
70                    f,
71                    "Model is not ready (downloading or other system reasons)"
72                )
73            }
74            Error::InvalidInput(msg) => write!(f, "Invalid input: {msg}"),
75            Error::GenerationError(msg) => write!(f, "Generation error: {msg}"),
76            Error::Timeout(msg) => write!(f, "Operation timed out: {msg}"),
77            Error::ToolCall(err) => {
78                write!(f, "Tool '{}' failed: {}", err.tool_name, err.inner_error)
79            }
80            Error::InternalError(msg) => write!(f, "Internal error: {msg}"),
81            Error::PoisonError => write!(f, "A lock was poisoned"),
82            Error::Json(msg) => write!(f, "JSON error: {msg}"),
83        }
84    }
85}
86
87impl std::error::Error for Error {
88    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
89        None
90    }
91}
92
93impl From<NulError> for Error {
94    fn from(_: NulError) -> Self {
95        Error::InvalidInput("String contains null byte".to_string())
96    }
97}
98
99impl<T> From<StdPoisonError<T>> for Error {
100    fn from(_: StdPoisonError<T>) -> Self {
101        Error::PoisonError
102    }
103}
104
105impl From<serde_json::Error> for Error {
106    fn from(err: serde_json::Error) -> Self {
107        Error::Json(err.to_string())
108    }
109}
110
111impl fmt::Display for ToolCallError {
112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113        write!(
114            f,
115            "Tool '{}' failed with arguments {}: {}",
116            self.tool_name, self.arguments, self.inner_error
117        )
118    }
119}
120
121impl std::error::Error for ToolCallError {}