Skip to main content

talon_core/expansion/
error.rs

1//! Error type for the LLM expansion client.
2
3use thiserror::Error;
4
5use crate::llm::ChatError;
6
7/// Errors returned by [`ExpansionClient`].
8///
9/// JSON decode failures are treated as graceful degradation (empty result)
10/// rather than errors; only transport-level problems reach this type.
11///
12/// [`ExpansionClient`]: crate::expansion::ExpansionClient
13#[derive(Debug, Error)]
14#[non_exhaustive]
15pub enum ExpansionError {
16    /// `reqwest::Client` could not be constructed.
17    #[error("expansion client build failed: {message}")]
18    Build {
19        /// Redacted error detail.
20        message: String,
21    },
22
23    /// HTTP transport failure or non-2xx status from the sidecar.
24    #[error(
25        "expansion HTTP error{}: {message}",
26        .status.map(|s| format!(" ({s})")).unwrap_or_default()
27    )]
28    Http {
29        /// HTTP status code when a response was received, `None` for transport failures.
30        status: Option<u16>,
31        /// Redacted detail (URL or response body snippet).
32        message: String,
33        /// Whether the underlying transport failure was a timeout.
34        timed_out: bool,
35    },
36}
37
38impl From<ChatError> for ExpansionError {
39    fn from(value: ChatError) -> Self {
40        match value {
41            ChatError::Build { message } => Self::Build { message },
42            ChatError::Http {
43                status,
44                message,
45                timed_out,
46            } => Self::Http {
47                status,
48                message,
49                timed_out,
50            },
51            ChatError::MalformedResponse => Self::Http {
52                status: None,
53                message: "malformed chat response".to_string(),
54                timed_out: false,
55            },
56        }
57    }
58}