rig_core/providers/
llamafile.rs1use crate::client::{
27 self, Capabilities, Capable, DebugExt, Nothing, Provider, ProviderBuilder, ProviderClient,
28 Transport,
29};
30use crate::http_client::{self, HttpClientExt};
31use crate::providers::openai;
32
33const LLAMAFILE_API_BASE_URL: &str = "http://localhost:8080";
37
38pub const LLAMA_CPP: &str = "LLaMA_CPP";
40
41#[derive(Debug, Default, Clone, Copy)]
42pub struct LlamafileExt;
43
44#[derive(Debug, Default, Clone, Copy)]
45pub struct LlamafileBuilder;
46
47impl Provider for LlamafileExt {
48 type Builder = LlamafileBuilder;
49 const VERIFY_PATH: &'static str = "/models";
50
51 fn build_uri(&self, base_url: &str, path: &str, _transport: Transport) -> String {
55 let base_url = base_url.trim_end_matches('/');
56 format!("{base_url}/v1/{}", path.trim_start_matches('/'))
57 }
58}
59
60impl openai::completion::OpenAICompatibleProvider for LlamafileExt {
61 const PROVIDER_NAME: &'static str = "llamafile";
62
63 type StreamingUsage = openai::Usage;
64
65 const EMITS_COMPLETE_SINGLE_CHUNK_TOOL_CALLS: bool = true;
67
68 type Response = openai::CompletionResponse;
69}
70
71impl<H> Capabilities<H> for LlamafileExt {
72 type Completion = Capable<openai::completion::GenericCompletionModel<LlamafileExt, H>>;
73 type Embeddings = Capable<openai::embedding::GenericEmbeddingModel<LlamafileExt, H>>;
74 type Transcription = Nothing;
75 type ModelListing = Nothing;
76 #[cfg(feature = "image")]
77 type ImageGeneration = Nothing;
78 #[cfg(feature = "audio")]
79 type AudioGeneration = Nothing;
80 type Rerank = Nothing;
81}
82
83impl DebugExt for LlamafileExt {}
84
85impl ProviderBuilder for LlamafileBuilder {
86 type Extension<H>
87 = LlamafileExt
88 where
89 H: HttpClientExt;
90 type ApiKey = Nothing;
91
92 const BASE_URL: &'static str = LLAMAFILE_API_BASE_URL;
93
94 fn build<H>(
95 _builder: &client::ClientBuilder<Self, Self::ApiKey, H>,
96 ) -> http_client::Result<Self::Extension<H>>
97 where
98 H: HttpClientExt,
99 {
100 Ok(LlamafileExt)
101 }
102}
103
104pub type Client<H = reqwest::Client> = client::Client<LlamafileExt, H>;
105pub type ClientBuilder<H = crate::markers::Missing> =
106 client::ClientBuilder<LlamafileBuilder, Nothing, H>;
107
108pub type CompletionModel<H = reqwest::Client> =
110 openai::completion::GenericCompletionModel<LlamafileExt, H>;
111
112pub type EmbeddingModel<H = reqwest::Client> =
114 openai::embedding::GenericEmbeddingModel<LlamafileExt, H>;
115
116impl Client {
117 pub fn from_url(base_url: &str) -> crate::client::ProviderClientResult<Self> {
120 Self::builder()
121 .api_key(Nothing)
122 .base_url(base_url)
123 .build()
124 .map_err(Into::into)
125 }
126}
127
128impl ProviderClient for Client {
129 type Input = Nothing;
130 type Error = crate::client::ProviderClientError;
131
132 fn from_env() -> Result<Self, Self::Error> {
133 let api_base = crate::client::required_env_var("LLAMAFILE_API_BASE_URL")?;
134 Self::from_url(&api_base)
135 }
136
137 fn from_val(_: Self::Input) -> Result<Self, Self::Error> {
138 Self::builder().api_key(Nothing).build().map_err(Into::into)
139 }
140}
141
142#[cfg(test)]
146mod tests {
147 use super::*;
148 use crate::client::Nothing;
149
150 #[test]
151 fn test_client_initialization() {
152 let _client =
153 crate::providers::llamafile::Client::new(Nothing).expect("Client::new() failed");
154 let _client_from_builder = crate::providers::llamafile::Client::builder()
155 .api_key(Nothing)
156 .build()
157 .expect("Client::builder() failed");
158 }
159
160 #[test]
161 fn test_client_from_url() {
162 let _client = crate::providers::llamafile::Client::from_url("http://localhost:8080");
163 }
164
165 #[test]
166 fn test_build_uri_routes_through_v1() {
167 let ext = LlamafileExt;
168 assert_eq!(
169 ext.build_uri(
170 "http://localhost:8080",
171 "/chat/completions",
172 Transport::Http
173 ),
174 "http://localhost:8080/v1/chat/completions"
175 );
176 assert_eq!(
177 ext.build_uri("http://localhost:8080/", "/embeddings", Transport::Http),
178 "http://localhost:8080/v1/embeddings"
179 );
180 assert_eq!(
181 ext.build_uri(
182 "http://localhost:8080",
183 LlamafileExt::VERIFY_PATH,
184 Transport::Http
185 ),
186 "http://localhost:8080/v1/models"
187 );
188 }
189}