artificial_openai/
adapter.rs

1use std::{env, sync::Arc};
2
3use artificial_core::error::{ArtificialError, Result};
4
5use crate::client::OpenAiClient;
6
7/// Thin wrapper that wires the HTTP client [`OpenAiClient`] into a value that
8/// implements [`artificial_core::backend::Backend`].
9///
10/// Think of it as the **service locator** for the OpenAI back-end:
11///
12/// * stores the API key (and optionally a custom base URL in the future),
13/// * owns a shareable, connection-pooled `reqwest::Client`,
14/// * provides a fluent [`OpenAiAdapterBuilder`] so callers don’t have to juggle
15///   `Option<String>` manually.
16///
17/// The type itself purposefully exposes **no additional methods**—all user-
18/// facing functionality sits on the generic [`artificial_core::ArtificialClient`]
19/// once the adapter is plugged in.
20pub struct OpenAiAdapter {
21    pub(crate) client: Arc<OpenAiClient>,
22}
23
24impl OpenAiAdapter {}
25
26/// Builder for [`OpenAiAdapter`].
27///
28/// # Typical usage
29///
30/// ```rust,no_run
31/// use artificial_openai::OpenAiAdapterBuilder;
32///
33/// let backend = OpenAiAdapterBuilder::new_from_env()
34///     .build()
35///     .expect("OPENAI_API_KEY must be set");
36/// ```
37///
38/// The builder pattern keeps future options (proxy URL, organisation ID, …)
39/// backwards compatible without breaking existing `build()` calls.
40#[derive(Default)]
41pub struct OpenAiAdapterBuilder {
42    pub(crate) api_key: Option<String>,
43}
44
45impl OpenAiAdapterBuilder {
46    /// Create an *empty* builder. Remember to supply an API key manually.
47    pub fn new() -> Self {
48        Self::default()
49    }
50
51    /// Convenience constructor that tries to load the `OPENAI_API_KEY`
52    /// environment variable.
53    ///
54    /// # Panics
55    ///
56    /// Never panics. Missing keys only surface during [`Self::build`].
57    pub fn new_from_env() -> Self {
58        Self {
59            api_key: env::var("OPENAI_API_KEY").ok(),
60        }
61    }
62
63    /// Finalise the builder and return a ready-to-use adapter.
64    ///
65    /// # Errors
66    ///
67    /// * [`ArtificialError::Invalid`] – if the API key is missing.
68    pub fn build(self) -> Result<OpenAiAdapter> {
69        Ok(OpenAiAdapter {
70            client: Arc::new(OpenAiClient::new(self.api_key.ok_or(
71                ArtificialError::Invalid("missing env variable: `OPENAI_API_KEY`".into()),
72            )?)),
73        })
74    }
75}