switchyard_libsy/
error.rs1use std::error::Error as StdError;
7
8use switchyard_protocol::LlmClientError;
9use thiserror::Error;
10
11pub type Result<T> = std::result::Result<T, LibsyError>;
13
14#[derive(Debug, Error)]
16pub enum LibsyError {
17 #[error("target {target:?} was not found")]
19 TargetNotFound {
20 target: String,
22 },
23
24 #[error("no routing targets are configured")]
26 NoTargets,
27
28 #[error("{message}")]
30 AlgorithmError {
31 message: String,
33 },
34
35 #[error(transparent)]
37 Driver(#[from] DriverError),
38
39 #[error("algorithm run ended without a final response")]
41 MissingFinalResponse,
42
43 #[error("client call to target {target:?} failed: {source}")]
45 ClientCall {
46 target: String,
48 #[source]
50 source: LlmClientError,
51 },
52
53 #[error("every target exceeded its context window")]
55 AllTargetsExcluded,
56
57 #[error("{operation} failed: {source}")]
59 External {
60 operation: &'static str,
62 #[source]
64 source: Box<dyn StdError + Send + Sync>,
65 },
66}
67
68impl LibsyError {
69 pub fn client_call(target: impl Into<String>, source: LlmClientError) -> Self {
71 Self::ClientCall {
72 target: target.into(),
73 source,
74 }
75 }
76
77 pub fn external(
79 operation: &'static str,
80 source: impl StdError + Send + Sync + 'static,
81 ) -> Self {
82 Self::External {
83 operation,
84 source: Box::new(source),
85 }
86 }
87}
88
89#[derive(Debug, Error)]
91pub enum DriverError {
92 #[error("driver stream is closed")]
94 StreamClosed,
95
96 #[error("driver response promise was dropped")]
98 ResponseDropped,
99
100 #[error("model call was abandoned by the consumer")]
104 Abandoned,
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn client_call_preserves_target_and_source() {
113 let error = LibsyError::client_call(
114 "strong",
115 LlmClientError::General("upstream down".to_string()),
116 );
117 match &error {
118 LibsyError::ClientCall { target, source } => {
119 assert_eq!(target, "strong");
120 assert_eq!(source.to_string(), "upstream down");
121 }
122 other => panic!("expected ClientCall, got {other:?}"),
123 }
124 assert_eq!(
125 StdError::source(&error).map(ToString::to_string),
126 Some("upstream down".to_string())
127 );
128 }
129
130 #[test]
131 fn external_preserves_operation_and_source() {
132 let error = LibsyError::external(
133 "loading extension",
134 std::io::Error::other("bad configuration"),
135 );
136 assert!(matches!(
137 &error,
138 LibsyError::External { operation, .. } if *operation == "loading extension"
139 ));
140 assert_eq!(
141 StdError::source(&error).map(ToString::to_string),
142 Some("bad configuration".to_string())
143 );
144 }
145}