#[cfg(feature = "deepseek")]
mod deepseek;
#[cfg(feature = "openai-compat")]
mod openai_compat;
pub mod validation;
use std::sync::Arc;
use async_trait::async_trait;
use self::validation::{into_validated_streaming_request, validate_non_streaming_request};
use crate::{
CapabilityNegotiation, Identifiable,
capability::ChatCompletionStream,
error::{BackendConstructError, BackendError},
types::chat::{ChatCompletionRequest, ChatCompletionResponse, ChatMessage, ToolDefinition},
};
#[cfg(feature = "deepseek")]
pub use deepseek::DeepSeekBackend;
#[cfg(feature = "openai-compat")]
pub use openai_compat::OpenAiCompatBackend;
#[async_trait]
pub trait LlmBackend: Identifiable + CapabilityNegotiation + Send + Sync {
fn prepare(&self, request: ChatCompletionRequest) -> Result<reqwest::Request, BackendError>;
fn prepare_streaming(
&self,
request: ChatCompletionRequest,
) -> Result<reqwest::Request, BackendError>;
async fn send(&self, prepared: reqwest::Request) -> Result<reqwest::Response, BackendError>;
async fn parse(
&self,
response: reqwest::Response,
) -> Result<ChatCompletionResponse, BackendError>;
async fn parse_streaming(
&self,
response: reqwest::Response,
) -> Result<ChatCompletionStream, BackendError>;
async fn chat_completion(
&self,
request: ChatCompletionRequest,
) -> Result<ChatCompletionResponse, BackendError> {
validate_non_streaming_request(&request, "chat_completion", "stream_chat_completion")?;
let prepared = self.prepare(request)?;
let response = self.send(prepared).await?;
self.parse(response).await
}
async fn stream_chat_completion(
&self,
request: ChatCompletionRequest,
) -> Result<ChatCompletionStream, BackendError> {
let request = into_validated_streaming_request(request, "stream_chat_completion")?;
let prepared = self.prepare_streaming(request)?;
let response = self.send(prepared).await?;
self.parse_streaming(response).await
}
fn render_messages(&self, messages: &[ChatMessage]) -> Result<String, BackendError>;
fn render_tools(&self, tools: &[ToolDefinition]) -> Result<String, BackendError>;
fn family() -> &'static str
where
Self: Sized;
#[allow(clippy::new_ret_no_self)]
fn new(
http: reqwest::ClientBuilder,
api_key: &str,
base_url: Option<&str>,
) -> Result<Arc<dyn LlmBackend>, BackendConstructError>
where
Self: Sized;
}