modular_agent_core/
error.rs1use thiserror::Error;
2
3#[derive(Clone, Debug, Error)]
14pub enum AgentError {
15 #[error("Invalid {0} value in array")]
17 InvalidArrayValue(String),
18
19 #[error("{0}: Agent definition \"{1}\" is invalid")]
21 InvalidDefinition(String, String),
22
23 #[error("Invalid port: {0}")]
25 InvalidPin(String),
26
27 #[error("Invalid preset name: {0}")]
29 InvalidPresetName(String),
30
31 #[error("Invalid {0} value")]
33 InvalidValue(String),
34
35 #[error("{0}: Agent definition \"{1}\" is missing")]
37 MissingDefinition(String, String),
38
39 #[error("Failed to rename preset: {0}")]
41 RenamePresetFailed(String),
42
43 #[error("Unknown agent def kind: {0}")]
45 UnknownDefKind(String),
46
47 #[error("Unknown agent def name: {0}")]
49 UnknownDefName(String),
50
51 #[error("Agent definition \"{0}\" is not implemented")]
53 NotImplemented(String),
54
55 #[error("Agent {0} already exists")]
57 AgentAlreadyExists(String),
58
59 #[error("Failed to create agent {0}")]
61 AgentCreationFailed(String),
62
63 #[error("Agent {0} not found")]
65 AgentNotFound(String),
66
67 #[error("Source agent {0} not found")]
69 SourceAgentNotFound(String),
70
71 #[error("Duplicate id: {0}")]
73 DuplicateId(String),
74
75 #[error("Source handle is empty")]
77 EmptySourceHandle,
78
79 #[error("Target handle is empty")]
81 EmptyTargetHandle,
82
83 #[error("Connection already exists")]
85 ConnectionAlreadyExists,
86
87 #[error("Connection {0} not found")]
89 ConnectionNotFound(String),
90
91 #[error("Preset {0} not found")]
93 PresetNotFound(String),
94
95 #[error("Agent {0} definition not found")]
97 AgentDefinitionNotFound(String),
98
99 #[error("Agent tx for {0} not found")]
101 AgentTxNotFound(String),
102
103 #[error("Failed to send message: {0}")]
105 SendMessageFailed(String),
106
107 #[error("Failed to serialize/deserialize: {0}")]
109 SerializationError(String),
110
111 #[error("Message sender not initialized")]
113 TxNotInitialized,
114
115 #[error("IO error: {0}")]
117 IoError(String),
118
119 #[error("JSON parsing error: {0}")]
121 JsonParseError(String),
122
123 #[error("Invalid file extension: expected JSON")]
125 InvalidFileExtension,
126
127 #[error("Empty file name")]
129 EmptyFileName,
130
131 #[error("Failed to get file stem from path")]
133 FileSystemError,
134
135 #[error("Configuration error: {0}")]
137 InvalidConfig(String),
138
139 #[error("No configuration available")]
141 NoConfig,
142
143 #[error("Unknown configuration: {0}")]
145 UnknownConfig(String),
146
147 #[error("No global configuration available")]
149 NoGlobalConfig,
150
151 #[error("Pin not found: {0}")]
153 PinNotFound(String),
154
155 #[error("Rate limited: {message}")]
160 RateLimited {
161 message: String,
162 retry_after: Option<std::time::Duration>,
163 },
164
165 #[error("Provider overloaded: {0}")]
167 Overloaded(String),
168
169 #[error("Request timed out: {0}")]
171 Timeout(String),
172
173 #[error("Context overflow: {0}")]
175 ContextOverflow(String),
176
177 #[error("Cancelled")]
179 Cancelled,
180
181 #[error("Agent error: {0}")]
183 Other(String),
184}
185
186impl AgentError {
187 pub fn is_retryable(&self) -> bool {
189 matches!(
190 self,
191 Self::RateLimited { .. } | Self::Overloaded(_) | Self::Timeout(_)
192 )
193 }
194}
195
196#[cfg(test)]
197mod tests {
198 use super::*;
199
200 #[test]
201 fn retryable_variants_are_retryable() {
202 assert!(
203 AgentError::RateLimited {
204 message: "slow down".into(),
205 retry_after: None,
206 }
207 .is_retryable()
208 );
209 assert!(AgentError::Overloaded("busy".into()).is_retryable());
210 assert!(AgentError::Timeout("deadline exceeded".into()).is_retryable());
211 }
212
213 #[test]
214 fn non_retryable_variants_are_not_retryable() {
215 assert!(!AgentError::ContextOverflow("too long".into()).is_retryable());
216 assert!(!AgentError::Cancelled.is_retryable());
217 assert!(!AgentError::InvalidValue("bad".into()).is_retryable());
218 assert!(!AgentError::IoError("disk full".into()).is_retryable());
219 }
220}