rig_core/client/
completion.rs1use crate::completion::CompletionModel;
2
3pub trait CompletionClient {
8 type CompletionModel: CompletionModel;
10
11 fn completion_model(&self, model: impl Into<String>) -> Self::CompletionModel;
31}
32
33pub trait ConstructCompletionModel<C>: Sized {
51 fn construct(client: &C, model: String) -> Self;
53}
54
55#[cfg(test)]
56mod tests {
57 use super::*;
58 use crate::completion::{CompletionError, CompletionRequest, CompletionResponse};
59 use crate::streaming::StreamingCompletionResponse;
60
61 #[derive(Clone)]
65 struct ExternalModel {
66 name: String,
67 }
68
69 impl CompletionModel for ExternalModel {
70 async fn completion(
71 &self,
72 _request: CompletionRequest,
73 ) -> Result<CompletionResponse, CompletionError> {
74 Err(CompletionError::ResponseError(format!(
75 "{} is a compile-coverage model",
76 self.name
77 )))
78 }
79
80 async fn stream(
81 &self,
82 _request: CompletionRequest,
83 ) -> Result<StreamingCompletionResponse, CompletionError> {
84 Err(CompletionError::ResponseError(format!(
85 "{} is a compile-coverage model",
86 self.name
87 )))
88 }
89 }
90
91 struct ExternalClient;
92
93 impl CompletionClient for ExternalClient {
94 type CompletionModel = ExternalModel;
95
96 fn completion_model(&self, model: impl Into<String>) -> Self::CompletionModel {
97 ExternalModel { name: model.into() }
98 }
99 }
100
101 #[test]
102 fn external_model_needs_no_client_or_response_associated_types() {
103 let model = ExternalClient.completion_model("external-model");
104 assert_eq!(model.name, "external-model");
105 }
106
107 #[test]
108 fn external_model_is_usable_without_a_client() {
109 fn assert_completion_model<M: CompletionModel>(_: &M) {}
111
112 assert_completion_model(&ExternalModel {
113 name: "standalone".to_owned(),
114 });
115 }
116
117 mod external_generic_extension {
123 use super::*;
124 use crate::client::{
125 BearerAuth, Capabilities, Capable, Client, ClientBuilder, DebugExt, Nothing, Provider,
126 ProviderBuilder,
127 };
128 use crate::http_client::{self, HttpClientExt};
129
130 #[derive(Debug, Default, Clone, Copy)]
131 struct ExternalExt;
132 #[derive(Debug, Default, Clone, Copy)]
133 struct ExternalExtBuilder;
134
135 impl Provider for ExternalExt {
136 type Builder = ExternalExtBuilder;
137 const VERIFY_PATH: &'static str = "/";
138 }
139
140 impl ProviderBuilder for ExternalExtBuilder {
141 type Extension<H>
142 = ExternalExt
143 where
144 H: HttpClientExt;
145 type ApiKey = BearerAuth;
146
147 const BASE_URL: &'static str = "https://external.invalid";
148
149 fn build<H>(
150 _builder: &ClientBuilder<Self, Self::ApiKey, H>,
151 ) -> http_client::Result<Self::Extension<H>>
152 where
153 H: HttpClientExt,
154 {
155 Ok(ExternalExt)
156 }
157 }
158
159 impl<H> Capabilities<H> for ExternalExt {
160 type Completion = Capable<ExternalGenericModel<H>>;
161 type Embeddings = Nothing;
162 type Transcription = Nothing;
163 type ModelListing = Nothing;
164 #[cfg(feature = "image")]
165 type ImageGeneration = Nothing;
166 #[cfg(feature = "audio")]
167 type AudioGeneration = Nothing;
168 type Rerank = Nothing;
169 }
170
171 impl DebugExt for ExternalExt {}
172
173 #[derive(Clone)]
174 struct ExternalGenericModel<H> {
175 _client: Client<ExternalExt, H>,
176 model: String,
177 }
178
179 impl<H> CompletionModel for ExternalGenericModel<H>
180 where
181 H: Clone + Send + Sync + std::fmt::Debug + 'static,
182 {
183 async fn completion(
184 &self,
185 _request: CompletionRequest,
186 ) -> Result<CompletionResponse, CompletionError> {
187 Err(CompletionError::ResponseError(format!(
188 "{} is a compile-coverage model",
189 self.model
190 )))
191 }
192
193 async fn stream(
194 &self,
195 _request: CompletionRequest,
196 ) -> Result<StreamingCompletionResponse, CompletionError> {
197 Err(CompletionError::ResponseError(format!(
198 "{} is a compile-coverage model",
199 self.model
200 )))
201 }
202 }
203
204 impl<H> ConstructCompletionModel<Client<ExternalExt, H>> for ExternalGenericModel<H>
205 where
206 H: Clone + Send + Sync + std::fmt::Debug + 'static,
207 {
208 fn construct(client: &Client<ExternalExt, H>, model: String) -> Self {
209 Self {
210 _client: client.clone(),
211 model,
212 }
213 }
214 }
215
216 #[test]
217 fn external_extension_reaches_the_blanket_completion_client_impl() {
218 fn assert_completion_client<C: CompletionClient>() {}
219
220 assert_completion_client::<Client<ExternalExt, reqwest::Client>>();
221 }
222 }
223}