1pub mod circuit_breaker;
8pub mod client;
9pub mod models;
10pub mod provider;
11pub mod registry;
12pub mod types;
13
14pub use circuit_breaker::CircuitBreaker;
15pub use client::AiClient;
16pub use models::{AiModel, ModelProvider};
17pub use provider::AiProvider;
18pub use registry::{ModelInfo, ProviderConfig, all_providers, get_provider};
19pub use types::{CreateIssueResponse, CreditsStatus, TriageResponse};
20
21use crate::history::AiStats;
22
23pub const CEREBRAS_API_URL: &str = "https://api.cerebras.ai/v1/chat/completions";
25
26pub const CEREBRAS_API_KEY_ENV: &str = "CEREBRAS_API_KEY";
28
29pub const GEMINI_API_URL: &str =
31 "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions";
32
33pub const GEMINI_API_KEY_ENV: &str = "GEMINI_API_KEY";
35
36pub const GROQ_API_URL: &str = "https://api.groq.com/openai/v1/chat/completions";
38
39pub const GROQ_API_KEY_ENV: &str = "GROQ_API_KEY";
41
42pub const OPENROUTER_API_URL: &str = "https://openrouter.ai/api/v1/chat/completions";
44
45pub const OPENROUTER_API_KEY_ENV: &str = "OPENROUTER_API_KEY";
47
48#[derive(Debug, Clone)]
50pub struct AiResponse {
51 pub triage: TriageResponse,
53 pub stats: AiStats,
55}
56
57#[must_use]
60pub fn is_free_model(model: &str) -> bool {
61 model.ends_with(":free")
62}
63
64pub async fn create_issue(
79 title: &str,
80 body: &str,
81 repo: &str,
82) -> anyhow::Result<CreateIssueResponse> {
83 let config = crate::config::load_config()?;
84
85 let client = AiClient::new(&config.ai.provider, &config.ai)?;
87 client.create_issue(title, body, repo).await
88}