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