use crate::{
AnthropicRequest, AnthropicResponse, AnthropicStreamEvent, AudioSpeechRequest,
ChatCompletionChunk, ChatCompletionRequest, ChatCompletionResponse, EmbeddingRequest,
EmbeddingResponse, Error, GeminiRequest, GeminiResponse, ImageRequest, MultipartField, ir,
};
use bytes::Bytes;
use futures_core::Stream;
use std::{future::Future, pin::Pin};
pub type BoxStream<'a, T> = Pin<Box<dyn Stream<Item = T> + Send + 'a>>;
pub type ByteStream = Pin<Box<dyn Stream<Item = Result<Bytes, std::io::Error>> + Send>>;
pub trait Provider: Send + Sync {
fn chat_completion(
&self,
request: &ChatCompletionRequest,
) -> impl Future<Output = Result<ChatCompletionResponse, Error>> + Send;
fn chat_completion_stream(
&self,
request: &ChatCompletionRequest,
) -> impl Future<Output = Result<BoxStream<'static, Result<ChatCompletionChunk, Error>>, Error>> + Send;
fn anthropic_messages(
&self,
request: &AnthropicRequest,
) -> impl Future<Output = Result<AnthropicResponse, Error>> + Send;
fn anthropic_messages_stream(
&self,
request: &AnthropicRequest,
) -> impl Future<Output = Result<BoxStream<'static, Result<AnthropicStreamEvent, Error>>, Error>>
+ Send;
fn gemini_generate_content(
&self,
model: &str,
request: &GeminiRequest,
) -> impl Future<Output = Result<GeminiResponse, Error>> + Send {
async move {
let mut ir_req = ir::Request::from(request);
ir_req.model = model.to_string();
let ir_resp = self.complete(&ir_req).await?;
Ok(GeminiResponse::from(&ir_resp))
}
}
fn gemini_generate_content_stream(
&self,
model: &str,
request: &GeminiRequest,
) -> impl Future<Output = Result<BoxStream<'static, Result<GeminiResponse, Error>>, Error>> + Send;
fn complete(
&self,
_request: &ir::Request,
) -> impl Future<Output = Result<ir::Response, Error>> + Send {
async { Err(Error::not_implemented("complete")) }
}
fn complete_stream(
&self,
_request: &ir::Request,
) -> impl Future<Output = Result<BoxStream<'static, Result<ir::StreamEvent, Error>>, Error>> + Send
{
async { Err(Error::not_implemented("complete_stream")) }
}
fn embedding(
&self,
_request: &EmbeddingRequest,
) -> impl Future<Output = Result<EmbeddingResponse, Error>> + Send {
async { Err(Error::not_implemented("embedding")) }
}
fn image_generation(
&self,
_request: &ImageRequest,
) -> impl Future<Output = Result<(Bytes, String), Error>> + Send {
async { Err(Error::not_implemented("image_generation")) }
}
fn audio_speech(
&self,
_request: &AudioSpeechRequest,
) -> impl Future<Output = Result<(Bytes, String), Error>> + Send {
async { Err(Error::not_implemented("audio_speech")) }
}
fn audio_transcription(
&self,
_model: &str,
_fields: &[MultipartField],
) -> impl Future<Output = Result<(Bytes, String), Error>> + Send {
async { Err(Error::not_implemented("audio_transcription")) }
}
fn is_openai_compat(&self) -> bool {
false
}
fn is_anthropic_compat(&self) -> bool {
false
}
fn is_gemini_compat(&self) -> bool {
false
}
fn chat_completion_stream_passthrough(
&self,
_model: &str,
_body_stream: crate::ByteStream,
) -> impl Future<Output = Result<crate::ByteStream, Error>> + Send {
async { Err(Error::not_implemented("chat_completion_stream_passthrough")) }
}
fn chat_completion_stream_raw(
&self,
_model: &str,
_raw_body: Bytes,
) -> impl Future<Output = Result<crate::ByteStream, Error>> + Send {
async { Err(Error::not_implemented("chat_completion_stream_raw")) }
}
fn chat_completion_raw(
&self,
_model: &str,
raw_body: Bytes,
) -> impl Future<Output = Result<Bytes, Error>> + Send {
async move {
let request: ChatCompletionRequest =
crate::json::from_slice(&raw_body).map_err(|e| Error::Internal(e.to_string()))?;
let resp = self.chat_completion(&request).await?;
Ok(Bytes::from(
crate::json::to_vec(&resp).map_err(|e| Error::Internal(e.to_string()))?,
))
}
}
fn anthropic_messages_raw(
&self,
_raw_body: Bytes,
) -> impl Future<Output = Result<Bytes, Error>> + Send {
async { Err(Error::not_implemented("anthropic_messages_raw")) }
}
fn anthropic_messages_stream_raw(
&self,
_raw_body: Bytes,
) -> impl Future<Output = Result<crate::ByteStream, Error>> + Send {
async { Err(Error::not_implemented("anthropic_messages_stream_raw")) }
}
fn gemini_generate_content_raw(
&self,
model: &str,
raw_body: Bytes,
) -> impl Future<Output = Result<Bytes, Error>> + Send {
async move {
let request: GeminiRequest =
crate::json::from_slice(&raw_body).map_err(|e| Error::Internal(e.to_string()))?;
let resp = self.gemini_generate_content(model, &request).await?;
Ok(Bytes::from(
crate::json::to_vec(&resp).map_err(|e| Error::Internal(e.to_string()))?,
))
}
}
fn gemini_generate_content_stream_raw(
&self,
_model: &str,
_raw_body: Bytes,
) -> impl Future<Output = Result<crate::ByteStream, Error>> + Send {
async { Err(Error::not_implemented("gemini_generate_content_stream_raw")) }
}
}