Skip to main content

ferrin_core/middleware/builtin/
default_embedding_settings.rs

1//! Default embedding call settings.
2
3use ferrin_spec::BoxFuture;
4use ferrin_spec::Headers;
5use ferrin_spec::ProviderOptions;
6use ferrin_spec::embedding_model::EmbedOptions;
7use ferrin_spec::error::ProviderError;
8
9use super::default_settings::merge_provider_options;
10use crate::middleware::EmbeddingMiddlewareContext;
11use crate::middleware::EmbeddingModelMiddleware;
12
13/// Settings applied when the embedding call does not set them.
14///
15/// `headers` and `provider_options` are merged with the call's values taking
16/// precedence (provider options merge recursively).
17#[derive(Debug, Clone, Default)]
18pub struct EmbeddingDefaults {
19    /// See [`EmbedOptions::headers`].
20    pub headers: Headers,
21    /// See [`EmbedOptions::provider_options`].
22    pub provider_options: ProviderOptions,
23}
24
25/// Middleware created by [`default_embedding_settings`].
26#[derive(Debug, Clone)]
27pub struct DefaultEmbeddingSettings {
28    defaults: EmbeddingDefaults,
29}
30
31/// Fills unset embedding call options from `defaults`.
32#[must_use]
33pub fn default_embedding_settings(defaults: EmbeddingDefaults) -> DefaultEmbeddingSettings {
34    DefaultEmbeddingSettings { defaults }
35}
36
37impl DefaultEmbeddingSettings {
38    /// Applies the defaults to `options`.
39    #[must_use]
40    pub fn apply(&self, mut options: EmbedOptions) -> EmbedOptions {
41        let defaults = &self.defaults;
42        if !defaults.headers.is_empty() {
43            let mut headers = defaults.headers.clone();
44            headers.merge(&options.headers);
45            options.headers = headers;
46        }
47        if !defaults.provider_options.is_empty() {
48            options.provider_options =
49                merge_provider_options(&defaults.provider_options, options.provider_options);
50        }
51        options
52    }
53}
54
55impl EmbeddingModelMiddleware for DefaultEmbeddingSettings {
56    fn transform_params<'a>(
57        &'a self,
58        options: EmbedOptions,
59        _ctx: EmbeddingMiddlewareContext<'a>,
60    ) -> BoxFuture<'a, Result<EmbedOptions, ProviderError>> {
61        let options = self.apply(options);
62        Box::pin(async move { Ok(options) })
63    }
64}