use super::openai_compat::{OpenAiCompatAdapter, OpenAiCompatConfig};
use crate::inference::adapter::InferenceAdapter;
use crate::inference::configurator::ResolvedProvider;
use crate::inference::error::InferenceError;
use crate::inference::registry::ProviderId;
pub const OPENAI_BASE_URL: &str = "https://api.openai.com/v1";
pub fn build(
resolved: &ResolvedProvider,
base_url: &str,
) -> Result<Box<dyn InferenceAdapter>, InferenceError> {
let key = resolved
.key()
.ok_or(InferenceError::MissingCredential {
provider: ProviderId::OpenAI,
})?
.clone();
let config = OpenAiCompatConfig {
name: ProviderId::OpenAI.as_str().to_string(),
base_url: base_url.to_string(),
api_key: key,
extra_headers: Vec::new(),
capabilities: *resolved.capabilities(),
};
Ok(Box::new(OpenAiCompatAdapter::new(config)?))
}
pub fn factory(resolved: &ResolvedProvider) -> Result<Box<dyn InferenceAdapter>, InferenceError> {
build(resolved, OPENAI_BASE_URL)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::inference::types::SecretString;
fn resolved(key: &str) -> ResolvedProvider {
ResolvedProvider::new(
ProviderId::OpenAI,
"gpt-4o-mini".to_string(),
Some(SecretString::new(key)),
)
}
#[test]
fn factory_builds_named_adapter() {
let adapter = build(&resolved("sk-openai-test"), OPENAI_BASE_URL) .expect("built");
assert_eq!(adapter.name(), "openai");
assert!(!adapter.wants_detailed_usage());
assert_eq!(adapter.capabilities().id, ProviderId::OpenAI);
}
#[test]
fn missing_key_errors() {
let resolved = ResolvedProvider::new(ProviderId::OpenAI, "gpt-4o-mini".to_string(), None);
let Err(err) = build(&resolved, OPENAI_BASE_URL) else {
panic!("expected MissingCredential");
};
assert!(matches!(
err,
InferenceError::MissingCredential {
provider: ProviderId::OpenAI
}
));
}
}