llmoxide 0.1.0

Provider-agnostic Rust SDK for OpenAI, Anthropic, Gemini, and Ollama (streaming + tools)
Documentation
use crate::error::Result;
use crate::providers::{
    ProviderApi, anthropic::AnthropicApi, gemini::GeminiApi, ollama::OllamaApi, openai::OpenAiApi,
};
use crate::types::{Event, ModelInfo, Provider, Response, ResponseRequest};
use std::sync::Arc;

#[derive(Clone)]
pub struct ClientConfig {
    provider_kind: Provider,
    provider: Arc<dyn ProviderApi>,
}

impl ClientConfig {
    pub fn openai(api_key: impl Into<String>) -> Self {
        let api_key = api_key.into();
        Self {
            provider_kind: Provider::OpenAi,
            provider: Arc::new(OpenAiApi::new(
                api_key,
                "https://api.openai.com".to_string(),
            )),
        }
    }

    pub fn anthropic(api_key: impl Into<String>) -> Self {
        let api_key = api_key.into();
        Self {
            provider_kind: Provider::Anthropic,
            provider: Arc::new(AnthropicApi::new(
                api_key,
                "https://api.anthropic.com".to_string(),
            )),
        }
    }

    pub fn gemini(api_key: impl Into<String>) -> Self {
        let api_key = api_key.into();
        Self {
            provider_kind: Provider::Gemini,
            provider: Arc::new(GeminiApi::new(
                api_key,
                "https://generativelanguage.googleapis.com".to_string(),
            )),
        }
    }

    pub fn ollama(base_url: impl Into<String>) -> Self {
        Self {
            provider_kind: Provider::Ollama,
            provider: Arc::new(OllamaApi::new(base_url)),
        }
    }

    pub fn ollama_default() -> Self {
        Self::ollama("http://localhost:11434".to_string())
    }
}

#[derive(Clone)]
pub struct Client {
    http: reqwest::Client,
    cfg: ClientConfig,
}

impl Client {
    pub fn new(cfg: ClientConfig) -> Self {
        Self {
            http: reqwest::Client::new(),
            cfg,
        }
    }

    pub fn provider(&self) -> &Provider {
        &self.cfg.provider_kind
    }

    pub async fn send(&self, req: ResponseRequest) -> Result<Response> {
        self.cfg.provider.send(&self.http, req).await
    }

    pub async fn stream<F>(&self, req: ResponseRequest, mut on_event: F) -> Result<Response>
    where
        F: FnMut(Event),
    {
        self.cfg
            .provider
            .stream(&self.http, req, &mut on_event)
            .await
    }

    pub async fn list_models(&self) -> Result<Vec<ModelInfo>> {
        self.cfg.provider.list_models(&self.http).await
    }

    pub fn chat(&self, model: impl Into<String>) -> crate::chat::ChatSession<'_> {
        crate::chat::ChatSession::new(self, crate::chat::Chat::new(model))
    }

    pub fn chat_auto(&self) -> crate::chat::ChatSession<'_> {
        crate::chat::ChatSession::new(self, crate::chat::Chat::new_auto())
    }

    pub fn chat_from(&self, chat: crate::chat::Chat) -> crate::chat::ChatSession<'_> {
        crate::chat::ChatSession::new(self, chat)
    }
}