1use thiserror::Error;
9
10#[derive(Error, Debug)]
12pub enum AptuError {
13 #[error("GitHub API error: {message}")]
15 GitHub {
16 message: String,
18 },
19
20 #[error("AI provider error: {message}")]
22 AI {
23 message: String,
25 status: Option<u16>,
27 provider: String,
29 },
30
31 #[error(
33 "Authentication required - run `aptu auth login` first, or set GITHUB_TOKEN environment variable"
34 )]
35 NotAuthenticated,
36
37 #[error("AI provider '{provider}' is not authenticated - set {env_var} environment variable")]
39 AiProviderNotAuthenticated {
40 provider: String,
42 env_var: String,
44 },
45
46 #[error("Rate limit exceeded on {provider}, retry after {retry_after}s")]
48 RateLimited {
49 provider: String,
51 retry_after: u64,
53 },
54
55 #[error("Truncated response from {provider} - response ended prematurely")]
57 TruncatedResponse {
58 provider: String,
60 },
61
62 #[error("Configuration error: {message}")]
64 Config {
65 message: String,
67 },
68
69 #[error("Invalid JSON response from AI")]
71 InvalidAIResponse(#[source] serde_json::Error),
72
73 #[error("Network error: {0}")]
75 Network(#[from] reqwest::Error),
76
77 #[cfg(feature = "keyring")]
79 #[error("Keyring error: {0}")]
80 Keyring(#[from] keyring::Error),
81
82 #[error("Circuit breaker is open - AI provider is temporarily unavailable")]
84 CircuitOpen,
85
86 #[error("#{number} is {actual}, not {expected}")]
88 TypeMismatch {
89 number: u64,
91 expected: ResourceType,
93 actual: ResourceType,
95 },
96
97 #[error("Model registry error: {message}")]
99 ModelRegistry {
100 message: String,
102 },
103
104 #[error("Invalid model ID: {model_id}. Did you mean one of these?\n{suggestions}")]
106 ModelValidation {
107 model_id: String,
109 suggestions: String,
111 },
112
113 #[error("Security scan error: {message}")]
115 SecurityScan {
116 message: String,
118 },
119}
120
121#[derive(Debug, Clone, Copy)]
123pub enum ResourceType {
124 Issue,
126 PullRequest,
128}
129
130impl std::fmt::Display for ResourceType {
131 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132 match self {
133 ResourceType::Issue => write!(f, "issue"),
134 ResourceType::PullRequest => write!(f, "pull request"),
135 }
136 }
137}
138
139impl From<octocrab::Error> for AptuError {
140 fn from(err: octocrab::Error) -> Self {
141 AptuError::GitHub {
142 message: err.to_string(),
143 }
144 }
145}
146
147impl From<config::ConfigError> for AptuError {
148 fn from(err: config::ConfigError) -> Self {
149 AptuError::Config {
150 message: err.to_string(),
151 }
152 }
153}