aptu_core/ai/mod.rs
1// SPDX-License-Identifier: Apache-2.0
2
3//! AI integration module.
4//!
5//! Provides AI-assisted issue triage using multiple AI providers (Gemini, `OpenRouter`, Groq, Cerebras).
6
7pub mod circuit_breaker;
8pub mod client;
9pub mod context;
10pub mod models;
11pub mod provider;
12pub mod registry;
13pub mod types;
14
15pub use circuit_breaker::CircuitBreaker;
16pub use client::AiClient;
17pub use models::{AiModel, ModelProvider};
18pub use provider::AiProvider;
19pub use registry::{ProviderConfig, all_providers, get_provider};
20pub use types::{CreateIssueResponse, CreditsStatus, TriageResponse};
21
22use crate::history::AiStats;
23
24/// Response from AI analysis containing both triage data and usage stats.
25#[derive(Debug, Clone)]
26pub struct AiResponse {
27 /// The triage analysis result.
28 pub triage: TriageResponse,
29 /// AI usage statistics.
30 pub stats: AiStats,
31}
32
33/// Checks if a model is in the free tier (no cost).
34/// Free models on `OpenRouter` always have the `:free` suffix.
35#[must_use]
36pub fn is_free_model(model: &str) -> bool {
37 model.ends_with(":free")
38}
39
40/// Creates a formatted GitHub issue using AI assistance.
41///
42/// Takes raw issue title and body, formats them professionally using the configured AI provider.
43/// Returns formatted title, body, and suggested labels.
44///
45/// # Arguments
46///
47/// * `title` - Raw issue title from user
48/// * `body` - Raw issue body/description from user
49/// * `repo` - Repository name for context (owner/repo format)
50///
51/// # Errors
52///
53/// Returns an error if AI formatting fails or API is unavailable.
54pub async fn create_issue(
55 title: &str,
56 body: &str,
57 repo: &str,
58) -> anyhow::Result<(CreateIssueResponse, AiStats)> {
59 let config = crate::config::load_config()?;
60
61 // Create generic client for the configured provider
62 let client = AiClient::new(&config.ai.provider, &config.ai)?;
63 client.create_issue(title, body, repo).await
64}