pub mod circuit_breaker;
pub mod client;
pub mod context;
pub mod models;
pub mod prompts;
pub mod provider;
pub mod registry;
pub mod types;
pub use circuit_breaker::CircuitBreaker;
pub use client::{AiClient, AuthMethod};
pub use models::{AiModel, ModelProvider};
pub use provider::AiProvider;
pub use registry::{PROVIDER_ANTHROPIC, ProviderConfig, all_providers, get_provider};
pub use types::{CreateIssueResponse, CreditsStatus, TriageResponse};
use crate::history::AiStats;
#[derive(Debug, Clone)]
pub struct AiResponse {
pub triage: TriageResponse,
pub stats: AiStats,
}
#[must_use]
pub fn is_free_model(model: &str) -> bool {
model.ends_with(":free")
}
#[must_use]
pub fn resolve_anthropic_credential(ai_config: &crate::config::AiConfig) -> Option<AiClient> {
if let Ok(Some(client)) = AiClient::from_keyring_oauth(ai_config) {
return Some(client);
}
if let Ok(Some(client)) = AiClient::from_claude_credentials(ai_config) {
return Some(client);
}
AiClient::new(PROVIDER_ANTHROPIC, ai_config).ok()
}
pub fn setup_primary_client(config: &crate::config::AppConfig) -> anyhow::Result<AiClient> {
if config.ai.provider == PROVIDER_ANTHROPIC
&& let Some(client) = resolve_anthropic_credential(&config.ai)
{
return Ok(client);
}
AiClient::new(&config.ai.provider, &config.ai)
}
pub async fn create_issue(
title: &str,
body: &str,
repo: &str,
) -> anyhow::Result<(CreateIssueResponse, AiStats)> {
let config = crate::config::load_config()?;
let client = setup_primary_client(&config)?;
client.create_issue(title, body, repo).await
}