1use crate::ai::ProviderConfig;
4use crate::core::Adr;
5use crate::Error;
6
7#[derive(Debug)]
9pub struct AiService {
10 config: ProviderConfig,
11}
12
13impl AiService {
14 #[must_use]
16 pub fn new(config: ProviderConfig) -> Self {
17 Self { config }
18 }
19
20 pub async fn generate_adr(&self, title: &str, context: &str) -> Result<Adr, Error> {
26 let _api_key = self.config.get_api_key()?;
27
28 let mut adr = Adr::new("DRAFT".to_string(), title.to_string());
31 adr.body = format!(
32 "## Context\n\n{context}\n\n## Decision\n\nTo be determined.\n\n## Consequences\n\nTo be determined."
33 );
34
35 Ok(adr)
36 }
37
38 pub async fn suggest_improvements(&self, adr: &Adr) -> Result<Vec<String>, Error> {
44 let _api_key = self.config.get_api_key()?;
45
46 let _ = adr;
48 Ok(vec![
49 "Consider adding more context about the decision drivers.".to_string(),
50 "The consequences section could be more detailed.".to_string(),
51 ])
52 }
53
54 pub async fn summarize(&self, adr: &Adr) -> Result<String, Error> {
60 let _api_key = self.config.get_api_key()?;
61
62 Ok(format!(
64 "ADR {} proposes: {}",
65 adr.id, adr.frontmatter.title
66 ))
67 }
68
69 pub async fn suggest_status(&self, adr: &Adr) -> Result<String, Error> {
75 let _api_key = self.config.get_api_key()?;
76
77 let _ = adr;
79 Ok("proposed".to_string())
80 }
81
82 pub async fn generate_tags(&self, adr: &Adr) -> Result<Vec<String>, Error> {
88 let _api_key = self.config.get_api_key()?;
89
90 let _ = adr;
92 Ok(vec!["architecture".to_string(), "decision".to_string()])
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99 use crate::ai::AiProvider;
100
101 #[tokio::test]
102 #[ignore = "requires API key"]
103 async fn test_generate_adr() {
104 let config = ProviderConfig::new(AiProvider::Anthropic);
105 let service = AiService::new(config);
106
107 let adr = service
108 .generate_adr("Test ADR", "Testing the AI service")
109 .await
110 .expect("ADR generation should succeed with valid API key");
111
112 assert_eq!(adr.title(), "Test ADR");
113 }
114}