Skip to main content

ucp_agent/
error.rs

1//! Error types for the agent traversal system.
2
3use std::time::Duration;
4use thiserror::Error;
5use ucm_core::BlockId;
6
7/// Unique identifier for an agent session.
8#[derive(Debug, Clone, PartialEq, Eq, Hash)]
9pub struct AgentSessionId(pub uuid::Uuid);
10
11impl AgentSessionId {
12    pub fn new() -> Self {
13        Self(uuid::Uuid::new_v4())
14    }
15}
16
17impl Default for AgentSessionId {
18    fn default() -> Self {
19        Self::new()
20    }
21}
22
23impl std::fmt::Display for AgentSessionId {
24    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25        write!(f, "{}", self.0)
26    }
27}
28
29/// Errors that can occur during agent traversal operations.
30#[derive(Debug, Error)]
31pub enum AgentError {
32    // Session errors
33    #[error("Session not found: {0}")]
34    SessionNotFound(AgentSessionId),
35
36    #[error("Session expired: {0}")]
37    SessionExpired(AgentSessionId),
38
39    #[error("Maximum sessions reached: {max}")]
40    MaxSessionsReached { max: usize },
41
42    #[error("Session already closed: {0}")]
43    SessionClosed(AgentSessionId),
44
45    // Navigation errors
46    #[error("Block not found: {0}")]
47    BlockNotFound(BlockId),
48
49    #[error("Navigation blocked: {reason}")]
50    NavigationBlocked { reason: String },
51
52    #[error("Invalid edge type: {edge_type}")]
53    InvalidEdgeType { edge_type: String },
54
55    #[error("No path exists from {from} to {to}")]
56    NoPathExists { from: BlockId, to: BlockId },
57
58    #[error("Cannot navigate: history is empty")]
59    EmptyHistory,
60
61    // Limit errors
62    #[error("Depth limit exceeded: {current} > {max}")]
63    DepthLimitExceeded { current: usize, max: usize },
64
65    #[error("Context size limit exceeded: {current} tokens > {max} tokens")]
66    ContextLimitExceeded { current: usize, max: usize },
67
68    #[error("Block limit exceeded: {current} blocks > {max} blocks")]
69    BlockLimitExceeded { current: usize, max: usize },
70
71    #[error("Operation budget exhausted: {operation_type}")]
72    BudgetExhausted { operation_type: String },
73
74    #[error("Rate limit exceeded")]
75    RateLimitExceeded,
76
77    #[error("Operation timed out after {0:?}")]
78    OperationTimeout(Duration),
79
80    // Circuit breaker errors
81    #[error("Circuit breaker open: {reason}")]
82    CircuitOpen { reason: String },
83
84    // RAG errors
85    #[error("RAG provider not configured")]
86    RagNotConfigured,
87
88    #[error("RAG search failed: {0}")]
89    RagSearchFailed(String),
90
91    // Coordination errors
92    #[error("Coordination lock timeout")]
93    CoordinationLockTimeout,
94
95    #[error("Agent coordination failed: {0}")]
96    CoordinationFailed(String),
97
98    #[error("Block already claimed by another agent: {block_id}")]
99    BlockAlreadyClaimed { block_id: BlockId },
100
101    // Capability errors
102    #[error("Operation not permitted: {operation}")]
103    OperationNotPermitted { operation: String },
104
105    // Context window errors
106    #[error("No results available from last search/find")]
107    NoResultsAvailable,
108
109    #[error("Focus block not set")]
110    NoFocusBlock,
111
112    // Underlying errors
113    #[error("Document error: {0}")]
114    DocumentError(String),
115
116    #[error("Engine error: {0}")]
117    EngineError(String),
118
119    #[error("Parse error: {0}")]
120    ParseError(String),
121
122    #[error("Internal error: {0}")]
123    Internal(String),
124}
125
126impl From<ucm_core::Error> for AgentError {
127    fn from(e: ucm_core::Error) -> Self {
128        AgentError::DocumentError(e.to_string())
129    }
130}
131
132impl From<ucm_engine::error::Error> for AgentError {
133    fn from(e: ucm_engine::error::Error) -> Self {
134        AgentError::EngineError(e.to_string())
135    }
136}
137
138impl From<ucl_parser::ParseError> for AgentError {
139    fn from(e: ucl_parser::ParseError) -> Self {
140        AgentError::ParseError(e.to_string())
141    }
142}
143
144/// Result type for agent operations.
145pub type Result<T> = std::result::Result<T, AgentError>;
146
147#[cfg(test)]
148mod tests {
149    use super::*;
150
151    #[test]
152    fn test_session_id_display() {
153        let id = AgentSessionId::new();
154        let display = format!("{}", id);
155        assert!(!display.is_empty());
156    }
157
158    #[test]
159    fn test_error_display() {
160        let err = AgentError::SessionNotFound(AgentSessionId::new());
161        let msg = format!("{}", err);
162        assert!(msg.contains("Session not found"));
163    }
164}