Skip to main content

walrus_model/remote/openai/
mod.rs

1//! OpenAI-compatible LLM provider.
2//!
3//! Covers OpenAI, Grok (xAI), Qwen (Alibaba), Kimi (Moonshot), Ollama,
4//! and any other service exposing the OpenAI chat completions API.
5
6use compact_str::CompactString;
7use reqwest::{Client, header::HeaderMap};
8
9mod provider;
10mod request;
11
12/// OpenAI-compatible endpoint URLs.
13pub mod endpoint {
14    /// OpenAI chat completions.
15    pub const OPENAI: &str = "https://api.openai.com/v1/chat/completions";
16    /// DeepSeek chat completions.
17    pub const DEEPSEEK: &str = "https://api.deepseek.com/chat/completions";
18    /// Grok (xAI) chat completions.
19    pub const GROK: &str = "https://api.x.ai/v1/chat/completions";
20    /// Qwen (Alibaba DashScope) chat completions.
21    pub const QWEN: &str = "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions";
22    /// Kimi (Moonshot) chat completions.
23    pub const KIMI: &str = "https://api.moonshot.cn/v1/chat/completions";
24    /// Ollama local chat completions.
25    pub const OLLAMA: &str = "http://localhost:11434/v1/chat/completions";
26}
27
28/// An OpenAI-compatible LLM provider.
29#[derive(Clone)]
30pub struct OpenAI {
31    /// The HTTP client.
32    pub client: Client,
33    /// Request headers (authorization, content-type).
34    headers: HeaderMap,
35    /// Chat completions endpoint URL.
36    endpoint: String,
37    /// The configured model name (used by `active_model()`).
38    model: CompactString,
39}
40
41impl OpenAI {
42    /// Create a provider targeting a custom OpenAI-compatible endpoint with Bearer auth.
43    pub fn custom(client: Client, key: &str, endpoint: &str, model: &str) -> anyhow::Result<Self> {
44        use reqwest::header;
45        let mut headers = HeaderMap::new();
46        headers.insert(header::CONTENT_TYPE, "application/json".parse()?);
47        headers.insert(header::ACCEPT, "application/json".parse()?);
48        headers.insert(header::AUTHORIZATION, format!("Bearer {key}").parse()?);
49        Ok(Self {
50            client,
51            headers,
52            endpoint: endpoint.to_owned(),
53            model: CompactString::from(model),
54        })
55    }
56
57    /// Create a provider targeting a custom endpoint without authentication (e.g. Ollama).
58    pub fn no_auth(client: Client, endpoint: &str, model: &str) -> Self {
59        use reqwest::header;
60        let mut headers = HeaderMap::new();
61        headers.insert(header::CONTENT_TYPE, "application/json".parse().unwrap());
62        headers.insert(header::ACCEPT, "application/json".parse().unwrap());
63        Self {
64            client,
65            headers,
66            endpoint: endpoint.to_owned(),
67            model: CompactString::from(model),
68        }
69    }
70}