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("Rate limit exceeded on {provider}, retry after {retry_after}s")]
39 RateLimited {
40 provider: String,
42 retry_after: u64,
44 },
45
46 #[error("Truncated response from {provider} - response ended prematurely")]
48 TruncatedResponse {
49 provider: String,
51 },
52
53 #[error("Configuration error: {message}")]
55 Config {
56 message: String,
58 },
59
60 #[error("Invalid JSON response from AI")]
62 InvalidAIResponse(#[source] serde_json::Error),
63
64 #[error("Network error: {0}")]
66 Network(#[from] reqwest::Error),
67
68 #[cfg(feature = "keyring")]
70 #[error("Keyring error: {0}")]
71 Keyring(#[from] keyring::Error),
72
73 #[error("Circuit breaker is open - AI provider is temporarily unavailable")]
75 CircuitOpen,
76
77 #[error("#{number} is {actual}, not {expected}")]
79 TypeMismatch {
80 number: u64,
82 expected: ResourceType,
84 actual: ResourceType,
86 },
87
88 #[error("Model registry error: {message}")]
90 ModelRegistry {
91 message: String,
93 },
94
95 #[error("Invalid model ID: {model_id}. Did you mean one of these?\n{suggestions}")]
97 ModelValidation {
98 model_id: String,
100 suggestions: String,
102 },
103}
104
105#[derive(Debug, Clone, Copy)]
107pub enum ResourceType {
108 Issue,
110 PullRequest,
112}
113
114impl std::fmt::Display for ResourceType {
115 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116 match self {
117 ResourceType::Issue => write!(f, "issue"),
118 ResourceType::PullRequest => write!(f, "pull request"),
119 }
120 }
121}
122
123impl From<octocrab::Error> for AptuError {
124 fn from(err: octocrab::Error) -> Self {
125 AptuError::GitHub {
126 message: err.to_string(),
127 }
128 }
129}
130
131impl From<config::ConfigError> for AptuError {
132 fn from(err: config::ConfigError) -> Self {
133 AptuError::Config {
134 message: err.to_string(),
135 }
136 }
137}