Skip to main content

tower_llm/
error.rs

1//! # Error Handling for the Agents SDK
2//!
3//! This module defines the centralized error handling system for the SDK. It
4//! provides a unified `Result` type and a comprehensive `AgentsError` enum that
5//! covers all potential issues that can arise during an agent's execution.
6//!
7//! ## The `AgentsError` Enum
8//!
9//! The [`AgentsError`] enum is the primary error type used throughout the SDK. It
10//! encapsulates a wide range of possible failures, from API-level errors to
11//! internal logic issues like guardrail violations or tool execution failures.
12//! The use of `thiserror` allows for clean and descriptive error messages.
13//!
14//! ## The `Result` Type Alias
15//!
16//! For convenience, this module provides a `Result<T>` type alias, which is a
17//! shorthand for `std::result::Result<T, AgentsError>`. This simplifies function
18//! signatures throughout the codebase and ensures consistent error handling.
19//!
20//! ### Example: Using the Custom `Result` Type
21//!
22//! ```rust
23//! use tower_llm::error::{Result, AgentsError};
24//!
25//! fn check_input(input: &str) -> Result<()> {
26//!     if input.is_empty() {
27//!         Err(AgentsError::UserError {
28//!             message: "Input cannot be empty.".to_string(),
29//!         })
30//!     } else {
31//!         Ok(())
32//!     }
33//! }
34//!
35//! assert!(check_input("Hello").is_ok());
36//! let error = check_input("").unwrap_err();
37//! assert_eq!(error.to_string(), "User error: Input cannot be empty.");
38//! ```
39//! Error types for the Agents SDK
40
41use thiserror::Error;
42
43/// A specialized `Result` type for the Agents SDK.
44///
45/// This type alias simplifies function signatures by providing a default
46/// error type of [`AgentsError`].
47pub type Result<T> = std::result::Result<T, AgentsError>;
48
49/// The main error enum for the Agents SDK.
50///
51/// `AgentsError` consolidates all possible errors that can occur within the
52/// SDK into a single, comprehensive type. This allows for robust and centralized
53/// error handling.
54#[derive(Debug, Error)]
55pub enum AgentsError {
56    /// An error originating from the underlying `async-openai` crate.
57    #[error("OpenAI API error: {0}")]
58    OpenAIError(#[from] async_openai::error::OpenAIError),
59
60    /// Indicates that the maximum number of turns for an agent run has been
61    /// exceeded, preventing infinite loops.
62    #[error("Maximum turns exceeded: {max_turns}")]
63    MaxTurnsExceeded { max_turns: usize },
64
65    /// An input guardrail was triggered, indicating that the user's input
66    /// violated a predefined constraint.
67    #[error("Input guardrail triggered: {message}")]
68    InputGuardrailTriggered { message: String },
69
70    /// An output guardrail was triggered, indicating that the agent's response
71    /// violated a predefined constraint.
72    #[error("Output guardrail triggered: {message}")]
73    OutputGuardrailTriggered { message: String },
74
75    /// An error occurred during the execution of a tool.
76    #[error("Tool execution error: {message}")]
77    ToolExecutionError { message: String },
78
79    /// An error occurred during a handoff between agents.
80    #[error("Handoff error: {message}")]
81    HandoffError { message: String },
82
83    /// An error indicating unexpected or invalid behavior from the LLM.
84    #[error("Model behavior error: {message}")]
85    ModelBehaviorError { message: String },
86
87    /// An error caused by invalid user input or configuration.
88    #[error("User error: {message}")]
89    UserError { message: String },
90
91    /// An error related to session management, such as a failure to read or
92    /// write to the session store.
93    #[error("Session error: {0}")]
94    SessionError(String),
95
96    /// An error that occurred during JSON serialization or deserialization.
97    #[error("Serialization error: {0}")]
98    SerializationError(#[from] serde_json::Error),
99
100    /// An I/O error, typically related to file system operations.
101    #[error("IO error: {0}")]
102    IoError(#[from] std::io::Error),
103
104    /// An error from the database, used by persistent session stores.
105    #[error("Database error: {0}")]
106    DatabaseError(#[from] sqlx::Error),
107
108    /// A catch-all for any other type of error.
109    #[error("{0}")]
110    Other(String),
111}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116
117    #[test]
118    fn test_error_display() {
119        let err = AgentsError::MaxTurnsExceeded { max_turns: 10 };
120        assert_eq!(err.to_string(), "Maximum turns exceeded: 10");
121
122        let err = AgentsError::InputGuardrailTriggered {
123            message: "Inappropriate content".to_string(),
124        };
125        assert_eq!(
126            err.to_string(),
127            "Input guardrail triggered: Inappropriate content"
128        );
129    }
130
131    #[test]
132    fn test_error_from_openai() {
133        // This tests that the From trait is properly implemented
134        let openai_err = async_openai::error::OpenAIError::InvalidArgument("test".to_string());
135        let agents_err: AgentsError = openai_err.into();
136        assert!(matches!(agents_err, AgentsError::OpenAIError(_)));
137    }
138
139    #[test]
140    fn test_result_type() {
141        fn example_function() -> Result<String> {
142            Ok("success".to_string())
143        }
144
145        let result = example_function();
146        assert!(result.is_ok());
147        assert_eq!(result.unwrap(), "success");
148    }
149
150    #[test]
151    fn test_error_chaining() {
152        fn might_fail() -> Result<()> {
153            Err(AgentsError::UserError {
154                message: "Something went wrong".to_string(),
155            })
156        }
157
158        let result = might_fail();
159        assert!(result.is_err());
160
161        if let Err(e) = result {
162            assert!(matches!(e, AgentsError::UserError { .. }));
163        }
164    }
165}