Skip to main content

aster/skills/
error.rs

1//! Skill Error Types
2//!
3//! 定义 Skills 系统的错误类型,用于执行引擎和工作流处理。
4//!
5//! # 错误分类
6//!
7//! | 错误类型 | 触发条件 | 处理策略 |
8//! |---------|---------|---------|
9//! | `InvalidConfig` | Workflow 模式但无 workflow 定义 | 立即返回错误 |
10//! | `ProviderError` | LLM API 调用失败 | 重试或返回错误 |
11//! | `ExecutionFailed` | 步骤执行失败且重试耗尽 | 根据 continue_on_failure 决定 |
12//! | `NotImplemented` | 尝试执行 Agent 模式 | 立即返回错误 |
13//! | `CyclicDependency` | 工作流存在循环依赖 | 立即返回错误 |
14//! | `MissingDependency` | 步骤引用不存在的依赖 | 立即返回错误 |
15//!
16//! # 示例
17//!
18//! ```rust
19//! use aster::skills::error::SkillError;
20//!
21//! // 创建配置错误
22//! let err = SkillError::InvalidConfig("缺少 workflow 定义".to_string());
23//! assert!(err.to_string().contains("配置错误"));
24//!
25//! // 创建循环依赖错误
26//! let err = SkillError::CyclicDependency("step1 -> step2 -> step1".to_string());
27//! assert!(err.to_string().contains("循环依赖"));
28//! ```
29
30/// Skill 错误类型
31///
32/// 定义 Skills 系统执行过程中可能发生的各种错误。
33/// 每种错误类型都包含一个描述性消息字符串。
34///
35/// # 变体说明
36///
37/// - `InvalidConfig`: 配置错误,如 Workflow 模式缺少 workflow 定义
38/// - `ProviderError`: LLM Provider 调用失败
39/// - `ExecutionFailed`: 步骤执行失败(重试耗尽后)
40/// - `NotImplemented`: 功能未实现(如 Agent 模式)
41/// - `CyclicDependency`: 工作流步骤存在循环依赖
42/// - `MissingDependency`: 步骤引用了不存在的依赖
43#[derive(Debug, Clone, PartialEq, Eq)]
44pub enum SkillError {
45    /// 配置错误(如缺少 workflow 定义)
46    ///
47    /// 当 Skill 配置不完整或无效时返回此错误。
48    ///
49    /// # 示例场景
50    /// - Workflow 模式但未定义 workflow
51    /// - 必需字段缺失
52    InvalidConfig(String),
53
54    /// Provider 调用错误
55    ///
56    /// 当 LLM Provider API 调用失败时返回此错误。
57    ///
58    /// # 示例场景
59    /// - API 请求超时
60    /// - 认证失败
61    /// - 速率限制
62    ProviderError(String),
63
64    /// 执行失败
65    ///
66    /// 当步骤执行失败且重试耗尽时返回此错误。
67    ///
68    /// # 示例场景
69    /// - LLM 返回无效响应
70    /// - 步骤处理逻辑错误
71    ExecutionFailed(String),
72
73    /// 功能未实现
74    ///
75    /// 当尝试使用尚未实现的功能时返回此错误。
76    ///
77    /// # 示例场景
78    /// - 尝试执行 Agent 模式
79    /// - 使用预留但未实现的特性
80    NotImplemented(String),
81
82    /// 循环依赖
83    ///
84    /// 当工作流步骤之间存在循环依赖时返回此错误。
85    ///
86    /// # 示例场景
87    /// - step1 依赖 step2,step2 依赖 step1
88    /// - 更复杂的循环链:A -> B -> C -> A
89    CyclicDependency(String),
90
91    /// 依赖不存在
92    ///
93    /// 当步骤引用了不存在的依赖时返回此错误。
94    ///
95    /// # 示例场景
96    /// - 步骤声明依赖 "step_x",但 "step_x" 不存在
97    /// - 依赖 ID 拼写错误
98    MissingDependency(String),
99}
100
101impl std::fmt::Display for SkillError {
102    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103        match self {
104            Self::InvalidConfig(msg) => write!(f, "配置错误: {}", msg),
105            Self::ProviderError(msg) => write!(f, "Provider 错误: {}", msg),
106            Self::ExecutionFailed(msg) => write!(f, "执行失败: {}", msg),
107            Self::NotImplemented(msg) => write!(f, "未实现: {}", msg),
108            Self::CyclicDependency(msg) => write!(f, "循环依赖: {}", msg),
109            Self::MissingDependency(msg) => write!(f, "依赖不存在: {}", msg),
110        }
111    }
112}
113
114impl std::error::Error for SkillError {}
115
116impl SkillError {
117    /// 创建配置错误
118    ///
119    /// # Arguments
120    /// * `msg` - 错误描述消息
121    ///
122    /// # Returns
123    /// `InvalidConfig` 变体的 `SkillError`
124    pub fn invalid_config(msg: impl Into<String>) -> Self {
125        Self::InvalidConfig(msg.into())
126    }
127
128    /// 创建 Provider 错误
129    ///
130    /// # Arguments
131    /// * `msg` - 错误描述消息
132    ///
133    /// # Returns
134    /// `ProviderError` 变体的 `SkillError`
135    pub fn provider_error(msg: impl Into<String>) -> Self {
136        Self::ProviderError(msg.into())
137    }
138
139    /// 创建执行失败错误
140    ///
141    /// # Arguments
142    /// * `msg` - 错误描述消息
143    ///
144    /// # Returns
145    /// `ExecutionFailed` 变体的 `SkillError`
146    pub fn execution_failed(msg: impl Into<String>) -> Self {
147        Self::ExecutionFailed(msg.into())
148    }
149
150    /// 创建未实现错误
151    ///
152    /// # Arguments
153    /// * `msg` - 错误描述消息
154    ///
155    /// # Returns
156    /// `NotImplemented` 变体的 `SkillError`
157    pub fn not_implemented(msg: impl Into<String>) -> Self {
158        Self::NotImplemented(msg.into())
159    }
160
161    /// 创建循环依赖错误
162    ///
163    /// # Arguments
164    /// * `msg` - 错误描述消息(通常包含循环路径)
165    ///
166    /// # Returns
167    /// `CyclicDependency` 变体的 `SkillError`
168    pub fn cyclic_dependency(msg: impl Into<String>) -> Self {
169        Self::CyclicDependency(msg.into())
170    }
171
172    /// 创建依赖不存在错误
173    ///
174    /// # Arguments
175    /// * `msg` - 错误描述消息(通常包含缺失的依赖名称)
176    ///
177    /// # Returns
178    /// `MissingDependency` 变体的 `SkillError`
179    pub fn missing_dependency(msg: impl Into<String>) -> Self {
180        Self::MissingDependency(msg.into())
181    }
182
183    /// 检查是否为配置错误
184    pub fn is_invalid_config(&self) -> bool {
185        matches!(self, Self::InvalidConfig(_))
186    }
187
188    /// 检查是否为 Provider 错误
189    pub fn is_provider_error(&self) -> bool {
190        matches!(self, Self::ProviderError(_))
191    }
192
193    /// 检查是否为执行失败错误
194    pub fn is_execution_failed(&self) -> bool {
195        matches!(self, Self::ExecutionFailed(_))
196    }
197
198    /// 检查是否为未实现错误
199    pub fn is_not_implemented(&self) -> bool {
200        matches!(self, Self::NotImplemented(_))
201    }
202
203    /// 检查是否为循环依赖错误
204    pub fn is_cyclic_dependency(&self) -> bool {
205        matches!(self, Self::CyclicDependency(_))
206    }
207
208    /// 检查是否为依赖不存在错误
209    pub fn is_missing_dependency(&self) -> bool {
210        matches!(self, Self::MissingDependency(_))
211    }
212
213    /// 获取错误消息
214    pub fn message(&self) -> &str {
215        match self {
216            Self::InvalidConfig(msg) => msg,
217            Self::ProviderError(msg) => msg,
218            Self::ExecutionFailed(msg) => msg,
219            Self::NotImplemented(msg) => msg,
220            Self::CyclicDependency(msg) => msg,
221            Self::MissingDependency(msg) => msg,
222        }
223    }
224}
225
226#[cfg(test)]
227mod tests {
228    use super::*;
229
230    // ==================== 错误创建测试 ====================
231
232    #[test]
233    fn test_invalid_config_creation() {
234        let err = SkillError::InvalidConfig("缺少 workflow 定义".to_string());
235        assert!(err.is_invalid_config());
236        assert_eq!(err.message(), "缺少 workflow 定义");
237    }
238
239    #[test]
240    fn test_provider_error_creation() {
241        let err = SkillError::ProviderError("API 请求超时".to_string());
242        assert!(err.is_provider_error());
243        assert_eq!(err.message(), "API 请求超时");
244    }
245
246    #[test]
247    fn test_execution_failed_creation() {
248        let err = SkillError::ExecutionFailed("步骤执行失败".to_string());
249        assert!(err.is_execution_failed());
250        assert_eq!(err.message(), "步骤执行失败");
251    }
252
253    #[test]
254    fn test_not_implemented_creation() {
255        let err = SkillError::NotImplemented("Agent 模式".to_string());
256        assert!(err.is_not_implemented());
257        assert_eq!(err.message(), "Agent 模式");
258    }
259
260    #[test]
261    fn test_cyclic_dependency_creation() {
262        let err = SkillError::CyclicDependency("step1 -> step2 -> step1".to_string());
263        assert!(err.is_cyclic_dependency());
264        assert_eq!(err.message(), "step1 -> step2 -> step1");
265    }
266
267    #[test]
268    fn test_missing_dependency_creation() {
269        let err = SkillError::MissingDependency("step_x".to_string());
270        assert!(err.is_missing_dependency());
271        assert_eq!(err.message(), "step_x");
272    }
273
274    // ==================== 便捷构造函数测试 ====================
275
276    #[test]
277    fn test_invalid_config_helper() {
278        let err = SkillError::invalid_config("测试消息");
279        assert!(err.is_invalid_config());
280        assert_eq!(err.message(), "测试消息");
281    }
282
283    #[test]
284    fn test_provider_error_helper() {
285        let err = SkillError::provider_error("测试消息");
286        assert!(err.is_provider_error());
287        assert_eq!(err.message(), "测试消息");
288    }
289
290    #[test]
291    fn test_execution_failed_helper() {
292        let err = SkillError::execution_failed("测试消息");
293        assert!(err.is_execution_failed());
294        assert_eq!(err.message(), "测试消息");
295    }
296
297    #[test]
298    fn test_not_implemented_helper() {
299        let err = SkillError::not_implemented("测试消息");
300        assert!(err.is_not_implemented());
301        assert_eq!(err.message(), "测试消息");
302    }
303
304    #[test]
305    fn test_cyclic_dependency_helper() {
306        let err = SkillError::cyclic_dependency("测试消息");
307        assert!(err.is_cyclic_dependency());
308        assert_eq!(err.message(), "测试消息");
309    }
310
311    #[test]
312    fn test_missing_dependency_helper() {
313        let err = SkillError::missing_dependency("测试消息");
314        assert!(err.is_missing_dependency());
315        assert_eq!(err.message(), "测试消息");
316    }
317
318    // ==================== Display trait 测试 ====================
319
320    #[test]
321    fn test_display_invalid_config() {
322        let err = SkillError::InvalidConfig("缺少必需字段".to_string());
323        assert_eq!(err.to_string(), "配置错误: 缺少必需字段");
324    }
325
326    #[test]
327    fn test_display_provider_error() {
328        let err = SkillError::ProviderError("连接超时".to_string());
329        assert_eq!(err.to_string(), "Provider 错误: 连接超时");
330    }
331
332    #[test]
333    fn test_display_execution_failed() {
334        let err = SkillError::ExecutionFailed("重试耗尽".to_string());
335        assert_eq!(err.to_string(), "执行失败: 重试耗尽");
336    }
337
338    #[test]
339    fn test_display_not_implemented() {
340        let err = SkillError::NotImplemented("Agent 模式".to_string());
341        assert_eq!(err.to_string(), "未实现: Agent 模式");
342    }
343
344    #[test]
345    fn test_display_cyclic_dependency() {
346        let err = SkillError::CyclicDependency("A -> B -> A".to_string());
347        assert_eq!(err.to_string(), "循环依赖: A -> B -> A");
348    }
349
350    #[test]
351    fn test_display_missing_dependency() {
352        let err = SkillError::MissingDependency("unknown_step".to_string());
353        assert_eq!(err.to_string(), "依赖不存在: unknown_step");
354    }
355
356    // ==================== std::error::Error trait 测试 ====================
357
358    #[test]
359    fn test_error_trait_implementation() {
360        let err: Box<dyn std::error::Error> =
361            Box::new(SkillError::InvalidConfig("test".to_string()));
362
363        // 验证可以作为 dyn Error 使用
364        assert!(err.to_string().contains("配置错误"));
365    }
366
367    #[test]
368    fn test_error_source_is_none() {
369        use std::error::Error;
370        let err = SkillError::InvalidConfig("test".to_string());
371        // SkillError 没有 source,应返回 None
372        assert!(err.source().is_none());
373    }
374
375    // ==================== Clone 和 PartialEq 测试 ====================
376
377    #[test]
378    fn test_clone() {
379        let err = SkillError::InvalidConfig("test".to_string());
380        let cloned = err.clone();
381        assert_eq!(err, cloned);
382    }
383
384    #[test]
385    fn test_partial_eq() {
386        let err1 = SkillError::InvalidConfig("test".to_string());
387        let err2 = SkillError::InvalidConfig("test".to_string());
388        let err3 = SkillError::InvalidConfig("different".to_string());
389        let err4 = SkillError::ProviderError("test".to_string());
390
391        assert_eq!(err1, err2);
392        assert_ne!(err1, err3);
393        assert_ne!(err1, err4);
394    }
395
396    // ==================== Debug trait 测试 ====================
397
398    #[test]
399    fn test_debug_format() {
400        let err = SkillError::InvalidConfig("test message".to_string());
401        let debug_str = format!("{:?}", err);
402        assert!(debug_str.contains("InvalidConfig"));
403        assert!(debug_str.contains("test message"));
404    }
405
406    // ==================== is_* 方法互斥性测试 ====================
407
408    #[test]
409    fn test_is_methods_are_mutually_exclusive() {
410        let errors = vec![
411            SkillError::InvalidConfig("".to_string()),
412            SkillError::ProviderError("".to_string()),
413            SkillError::ExecutionFailed("".to_string()),
414            SkillError::NotImplemented("".to_string()),
415            SkillError::CyclicDependency("".to_string()),
416            SkillError::MissingDependency("".to_string()),
417        ];
418
419        for err in &errors {
420            let checks = [
421                err.is_invalid_config(),
422                err.is_provider_error(),
423                err.is_execution_failed(),
424                err.is_not_implemented(),
425                err.is_cyclic_dependency(),
426                err.is_missing_dependency(),
427            ];
428
429            // 确保只有一个 is_* 方法返回 true
430            let true_count = checks.iter().filter(|&&x| x).count();
431            assert_eq!(true_count, 1, "每个错误应该只匹配一个 is_* 方法");
432        }
433    }
434
435    // ==================== 空消息测试 ====================
436
437    #[test]
438    fn test_empty_message() {
439        let err = SkillError::InvalidConfig(String::new());
440        assert_eq!(err.message(), "");
441        assert_eq!(err.to_string(), "配置错误: ");
442    }
443
444    // ==================== Unicode 消息测试 ====================
445
446    #[test]
447    fn test_unicode_message() {
448        let err = SkillError::InvalidConfig("配置文件格式错误 🔧".to_string());
449        assert_eq!(err.message(), "配置文件格式错误 🔧");
450        assert!(err.to_string().contains("🔧"));
451    }
452
453    // ==================== 长消息测试 ====================
454
455    #[test]
456    fn test_long_message() {
457        let long_msg = "a".repeat(10000);
458        let err = SkillError::InvalidConfig(long_msg.clone());
459        assert_eq!(err.message(), long_msg);
460    }
461}