1use thiserror::Error;
2
3#[derive(Debug, Error)]
4pub enum CloudAiError {
5 #[error("provider '{0}' not registered")]
6 ProviderNotFound(String),
7 #[error("missing API key for provider '{provider}'. Set {env_var} in your environment.")]
8 MissingApiKey { provider: String, env_var: String },
9 #[error("cloud AI is disabled by policy (allow_cloud_ai = false)")]
10 PolicyDenied,
11 #[error("provider '{provider}' is disabled in settings")]
12 ProviderDisabled { provider: String },
13 #[error("HTTP error from provider '{provider}': {reason}")]
14 Http { provider: String, reason: String },
15 #[error("provider '{provider}' returned status {status}: {body}")]
16 Status {
17 provider: String,
18 status: u16,
19 body: String,
20 },
21 #[error("failed to parse provider '{provider}' response: {reason}")]
22 Parse { provider: String, reason: String },
23 #[error("unexpected response shape from provider '{provider}': {detail}")]
24 Shape { provider: String, detail: String },
25 #[error("provider '{provider}' does not support {capability}")]
26 Unsupported { provider: String, capability: String },
27}
28
29pub const MAX_ERROR_BODY_LEN: usize = 1024;
38
39pub fn redact_error_body(body: &str) -> String {
43 let trimmed = body.trim();
44 if trimmed.len() <= MAX_ERROR_BODY_LEN {
45 return trimmed.to_string();
46 }
47 let mut end = MAX_ERROR_BODY_LEN;
48 while end > 0 && !trimmed.is_char_boundary(end) {
49 end -= 1;
50 }
51 format!("{}…[truncated]", &trimmed[..end])
52}