You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
55 lines
1.9 KiB
Rust
55 lines
1.9 KiB
Rust
//! LLM provider abstraction layer.
|
|
//!
|
|
//! Defines the `LlmProvider` trait that all LLM providers implement,
|
|
//! along with shared types and the provider factory function.
|
|
|
|
pub mod anthropic;
|
|
pub mod factory;
|
|
pub mod gemini;
|
|
pub mod openai;
|
|
pub mod schema;
|
|
|
|
use async_trait::async_trait;
|
|
use serde_json::Value;
|
|
|
|
use crate::errors::AppError;
|
|
|
|
/// Trait defining the contract for LLM provider implementations.
|
|
///
|
|
/// Each provider (Gemini, OpenAI, Anthropic) implements this trait
|
|
/// to provide a unified interface for structured LLM calls.
|
|
#[async_trait]
|
|
pub trait LlmProvider: Send + Sync {
|
|
/// Returns the provider identifier (e.g., "gemini", "openai", "anthropic").
|
|
fn provider_id(&self) -> &str;
|
|
|
|
/// Call the LLM with a prompt and expected JSON schema.
|
|
///
|
|
/// # Arguments
|
|
/// * `model` — The model identifier (e.g., "gpt-4o-mini")
|
|
/// * `system_prompt` — System-level instructions
|
|
/// * `user_prompt` — The user's prompt
|
|
/// * `response_schema` — JSON Schema defining the expected response structure
|
|
async fn call_llm(
|
|
&self,
|
|
model: &str,
|
|
system_prompt: &str,
|
|
user_prompt: &str,
|
|
response_schema: &Value,
|
|
) -> Result<Value, AppError>;
|
|
}
|
|
|
|
/// Shared HTTP error mapping for LLM provider responses.
|
|
pub fn map_provider_http_error(status: u16, provider_name: &str) -> AppError {
|
|
match status {
|
|
400 => AppError::BadRequest("Invalid request to LLM provider".into()),
|
|
401 => AppError::BadRequest("Invalid or unauthorized API key".into()),
|
|
403 => AppError::BadRequest("Access denied by LLM provider".into()),
|
|
404 => AppError::BadRequest("Model not found or not available".into()),
|
|
429 | 529 => AppError::RateLimited(
|
|
"LLM provider rate limit exceeded. Please try again later.".into(),
|
|
),
|
|
_ => AppError::Internal(anyhow::anyhow!("{} returned HTTP {}", provider_name, status)),
|
|
}
|
|
}
|