entelix_memory_openai/lib.rs
1//! # entelix-memory-openai
2//!
3//! Concrete [`entelix_memory::Embedder`] implementation backed by
4//! OpenAI's `/v1/embeddings` endpoint. Ships the
5//! `text-embedding-3-{small,large}` models plus operator-supplied
6//! custom model identifiers for forward compatibility.
7//!
8//! Companion to the trait-only [`entelix_memory`] crate (invariant
9//! 13's "trait-only `entelix-memory`" principle): concrete vendor
10//! impls live in their own crate so the core memory trait surface
11//! ships without pulling `reqwest` + `secrecy` for users who
12//! provide their own embedder.
13//!
14//! ## One-call setup
15//!
16//! ```ignore
17//! use std::sync::Arc;
18//! use entelix_core::auth::ApiKeyProvider;
19//! use entelix_memory_openai::OpenAiEmbedder;
20//!
21//! let credentials = Arc::new(ApiKeyProvider::new(
22//! "authorization",
23//! format!("Bearer {}", std::env::var("OPENAI_API_KEY")?),
24//! )?);
25//! let embedder = OpenAiEmbedder::small().with_credentials(credentials).build()?;
26//! ```
27//!
28//! ## Invariant alignment
29//!
30//! - **Invariant 10** — credentials never reach `Tool::execute`. The
31//! embedder holds an `Arc<dyn CredentialProvider>` and resolves
32//! per-call; no token enters request scope state.
33//! - **F10** — `Embedder` is wrapped in `Arc` at the call boundary.
34//! Cloning the embedder is cheap (`Arc::clone` of the inner
35//! `reqwest::Client` plus a credential handle).
36//! - **F4** — `EmbeddingUsage` is populated only on the `Ok` branch
37//! of `embed`/`embed_batch`; failed calls produce no phantom
38//! token charge in downstream meters.
39
40#![cfg_attr(docsrs, feature(doc_cfg))]
41#![doc(html_root_url = "https://docs.rs/entelix-memory-openai/0.5.3")]
42#![deny(missing_docs)]
43// `OpenAI` ride through doc strings as the vendor name (not as code
44// identifier) frequently — backticking each occurrence noisily.
45#![allow(clippy::doc_markdown)]
46
47mod embedder;
48mod error;
49
50pub use embedder::{
51 DEFAULT_BASE_URL, OpenAiEmbedder, OpenAiEmbedderBuilder, TEXT_EMBEDDING_3_LARGE,
52 TEXT_EMBEDDING_3_LARGE_DIMENSION, TEXT_EMBEDDING_3_SMALL, TEXT_EMBEDDING_3_SMALL_DIMENSION,
53};
54pub use error::{OpenAiEmbedderError, OpenAiEmbedderResult};