use std::collections::HashMap;
use std::time::Duration;
use serde_json::Value;
use crate::error::GatewayError;
pub const DEFAULT_BASE_URL: &str = "https://api.typesafe.ai";
pub const DEFAULT_MODEL: &str = "jev-latest";
#[derive(Debug, Clone)]
pub struct JevNativeProvider {
http: reqwest::Client,
api_key: String,
base_url: String,
}
impl JevNativeProvider {
pub fn new(api_key: String, base_url: Option<String>, request_timeout: Duration) -> Self {
Self {
http: reqwest::Client::builder()
.timeout(request_timeout)
.build()
.unwrap(),
api_key,
base_url: base_url.unwrap_or_else(|| DEFAULT_BASE_URL.to_string()),
}
}
pub fn from_env(env: &HashMap<String, String>, request_timeout: Duration) -> Option<Self> {
let api_key = env
.get("TYPESAFE_API_KEY")
.map(|s| s.trim())
.filter(|s| !s.is_empty())?;
let base_url = env
.get("TYPESAFE_BASE_URL")
.map(|s| s.trim())
.filter(|s| !s.is_empty())
.map(str::to_string);
Some(Self::new(api_key.to_string(), base_url, request_timeout))
}
pub async fn evaluate(&self, body: Value) -> Result<reqwest::Response, GatewayError> {
self.http
.post(format!("{}/v1/systemone", self.base_url))
.bearer_auth(&self.api_key)
.json(&body)
.send()
.await
.map_err(|e| GatewayError::Upstream {
status: 502,
body: e.to_string(),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn from_env_is_none_without_key() {
assert!(JevNativeProvider::from_env(&HashMap::new(), Duration::from_secs(1)).is_none());
let blank = HashMap::from([("TYPESAFE_API_KEY".to_string(), " ".to_string())]);
assert!(JevNativeProvider::from_env(&blank, Duration::from_secs(1)).is_none());
}
#[test]
fn from_env_picks_up_key_and_base_url_override() {
let env = HashMap::from([
("TYPESAFE_API_KEY".to_string(), "key".to_string()),
(
"TYPESAFE_BASE_URL".to_string(),
"http://localhost:9".to_string(),
),
]);
let provider = JevNativeProvider::from_env(&env, Duration::from_secs(1)).unwrap();
assert_eq!(provider.base_url, "http://localhost:9");
}
#[test]
fn defaults_to_the_hosted_api() {
let provider = JevNativeProvider::new("key".into(), None, Duration::from_secs(1));
assert_eq!(provider.base_url, DEFAULT_BASE_URL);
}
}