#![cfg(feature = "llm")]
mod genai_backend;
mod prompts;
#[allow(dead_code)]
mod subscription_cli;
pub(crate) use genai_backend::GenaiBackend;
pub(crate) use prompts::{
CLASSIFIER_SYSTEM_PROMPT, HYDE_SYSTEM_PROMPT, build_classify_prompt, build_hyde_prompt,
parse_route_from_llm_output,
};
pub(crate) use subscription_cli::SubscriptionCliBackend;
use crate::search::agent_classifier::AgentRoute;
#[async_trait::async_trait]
pub trait LlmCapability: Send + Sync {
async fn classify_route(&self, query: &str) -> anyhow::Result<AgentRoute>;
async fn synthesize_hyde_doc(&self, query: &str) -> anyhow::Result<String>;
fn label(&self) -> &str;
}
#[allow(private_interfaces)]
pub enum LlmBackend {
Genai(GenaiBackend),
SubscriptionCli(SubscriptionCliBackend),
}
impl LlmBackend {
pub fn from_env() -> anyhow::Result<Option<Self>> {
if let Some(b) = GenaiBackend::from_env()? {
return Ok(Some(Self::Genai(b)));
}
if let Some(b) = SubscriptionCliBackend::from_env()? {
return Ok(Some(Self::SubscriptionCli(b)));
}
Ok(None)
}
pub fn as_capability(&self) -> &dyn LlmCapability {
match self {
Self::Genai(b) => b,
Self::SubscriptionCli(b) => b,
}
}
#[must_use]
pub fn into_arc(self) -> std::sync::Arc<dyn LlmCapability> {
match self {
Self::Genai(b) => std::sync::Arc::new(b),
Self::SubscriptionCli(b) => std::sync::Arc::new(b),
}
}
}
#[cfg(test)]
pub(crate) static TEST_ENV_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());