Skip to main content

adk_realtime/
error.rs

1//! Error types for the realtime module.
2
3use thiserror::Error;
4
5/// Result type for realtime operations.
6pub type Result<T> = std::result::Result<T, RealtimeError>;
7
8/// Errors that can occur during realtime operations.
9#[derive(Error, Debug)]
10pub enum RealtimeError {
11    /// WebSocket connection error.
12    #[error("WebSocket connection error: {0}")]
13    ConnectionError(String),
14
15    /// WebSocket message error.
16    #[error("WebSocket message error: {0}")]
17    MessageError(String),
18
19    /// Authentication error.
20    #[error("Authentication error: {0}")]
21    AuthError(String),
22
23    /// Session not connected.
24    #[error("Session not connected")]
25    NotConnected,
26
27    /// Session already closed.
28    #[error("Session already closed")]
29    SessionClosed,
30
31    /// Invalid configuration.
32    #[error("Invalid configuration: {0}")]
33    ConfigError(String),
34
35    /// Audio format error.
36    #[error("Audio format error: {0}")]
37    AudioFormatError(String),
38
39    /// Tool execution error.
40    #[error("Tool execution error: {0}")]
41    ToolError(String),
42
43    /// Server returned an error.
44    #[error("Server error: {code} - {message}")]
45    ServerError {
46        /// Error code from the server.
47        code: String,
48        /// Error message from the server.
49        message: String,
50    },
51
52    /// Timeout waiting for response.
53    #[error("Timeout: {0}")]
54    Timeout(String),
55
56    /// Serialization/deserialization error.
57    #[error("Serialization error: {0}")]
58    SerializationError(#[from] serde_json::Error),
59
60    /// Provider-specific error.
61    #[error("Provider error: {0}")]
62    ProviderError(String),
63
64    /// Generic IO error.
65    #[error("IO error: {0}")]
66    IoError(#[from] std::io::Error),
67
68    /// Opus codec error.
69    #[error("Opus codec error: {0}")]
70    OpusCodecError(String),
71
72    /// WebRTC error.
73    #[error("WebRTC error: {0}")]
74    WebRTCError(String),
75
76    /// LiveKit bridge error (legacy string format).
77    #[error("LiveKit error: {0}")]
78    LiveKitError(String),
79
80    /// Native LiveKit component error.
81    #[cfg(feature = "livekit")]
82    #[error(transparent)]
83    LiveKitNativeError(Box<crate::livekit::LiveKitError>),
84}
85
86#[cfg(feature = "livekit")]
87/// Manually implemented to box the inner error, keeping `Result` small on the happy path.
88impl From<crate::livekit::LiveKitError> for RealtimeError {
89    fn from(err: crate::livekit::LiveKitError) -> Self {
90        RealtimeError::LiveKitNativeError(Box::new(err))
91    }
92}
93
94impl RealtimeError {
95    /// Create a new connection error.
96    pub fn connection<S: Into<String>>(msg: S) -> Self {
97        Self::ConnectionError(msg.into())
98    }
99
100    /// Create a new server error.
101    pub fn server<S: Into<String>>(code: S, message: S) -> Self {
102        Self::ServerError { code: code.into(), message: message.into() }
103    }
104
105    /// Create a new provider error.
106    pub fn provider<S: Into<String>>(msg: S) -> Self {
107        Self::ProviderError(msg.into())
108    }
109
110    /// Create a new avatar provider error.
111    ///
112    /// Convenience constructor that prefixes the message with "avatar:"
113    /// for clear identification in logs.
114    #[cfg(feature = "video-avatar")]
115    pub fn avatar<S: Into<String>>(msg: S) -> Self {
116        Self::ProviderError(format!("avatar: {}", msg.into()))
117    }
118
119    /// Create a new configuration error.
120    pub fn config<S: Into<String>>(msg: S) -> Self {
121        Self::ConfigError(msg.into())
122    }
123
124    /// Create a new protocol error.
125    pub fn protocol<S: Into<String>>(msg: S) -> Self {
126        Self::MessageError(msg.into())
127    }
128
129    /// Create a new audio format error.
130    pub fn audio<S: Into<String>>(msg: S) -> Self {
131        Self::AudioFormatError(msg.into())
132    }
133
134    /// Create a new Opus codec error.
135    pub fn opus(msg: impl Into<String>) -> Self {
136        Self::OpusCodecError(msg.into())
137    }
138
139    /// Create a new WebRTC error.
140    pub fn webrtc(msg: impl Into<String>) -> Self {
141        Self::WebRTCError(msg.into())
142    }
143
144    /// Create a new LiveKit error.
145    pub fn livekit(msg: impl Into<String>) -> Self {
146        Self::LiveKitError(msg.into())
147    }
148}
149
150#[cfg(test)]
151mod tests {
152
153    #[cfg(feature = "livekit")]
154    #[test]
155    fn test_livekit_native_error_conversion() {
156        // Construct a simple LiveKitError variant
157        let inner = crate::livekit::LiveKitError::ConfigError("test config error".to_string());
158
159        // Convert into RealtimeError
160        let realtime_err: crate::error::RealtimeError = inner.into();
161
162        // Verify it matches the Boxed variant and formats correctly
163        match realtime_err {
164            crate::error::RealtimeError::LiveKitNativeError(boxed_err) => {
165                assert!(matches!(*boxed_err, crate::livekit::LiveKitError::ConfigError(_)));
166                assert_eq!(
167                    format!("{}", boxed_err),
168                    "LiveKit configuration error: test config error"
169                );
170            }
171            _ => panic!("Expected LiveKitNativeError variant"),
172        }
173    }
174}