use serde::{Deserialize, Serialize};
use std::collections::HashSet;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ServingBackend {
Realizar,
Ollama,
LlamaCpp,
Llamafile,
Candle,
Vllm,
Tgi,
LocalAI,
HuggingFace,
Together,
Replicate,
Anyscale,
Modal,
Fireworks,
Groq,
OpenAI,
Anthropic,
AzureOpenAI,
AwsBedrock,
GoogleVertex,
AwsLambda,
CloudflareWorkers,
}
impl ServingBackend {
#[must_use]
pub const fn is_local(&self) -> bool {
matches!(
self,
Self::Realizar
| Self::Ollama
| Self::LlamaCpp
| Self::Llamafile
| Self::Candle
| Self::Vllm
| Self::Tgi
| Self::LocalAI
)
}
#[must_use]
pub const fn is_remote(&self) -> bool {
!self.is_local()
}
#[must_use]
pub const fn api_host(&self) -> Option<&'static str> {
match self {
Self::HuggingFace => Some("api-inference.huggingface.co"),
Self::Together => Some("api.together.xyz"),
Self::Replicate => Some("api.replicate.com"),
Self::Anyscale => Some("api.anyscale.com"),
Self::Modal => Some("api.modal.com"),
Self::Fireworks => Some("api.fireworks.ai"),
Self::Groq => Some("api.groq.com"),
Self::OpenAI => Some("api.openai.com"),
Self::Anthropic => Some("api.anthropic.com"),
Self::AzureOpenAI => Some("openai.azure.com"),
Self::AwsBedrock => Some("bedrock-runtime.amazonaws.com"),
Self::GoogleVertex => Some("aiplatform.googleapis.com"),
Self::AwsLambda => Some("lambda.amazonaws.com"),
Self::CloudflareWorkers => Some("workers.cloudflare.com"),
_ => None,
}
}
#[must_use]
pub const fn is_serverless(&self) -> bool {
matches!(self, Self::AwsLambda | Self::CloudflareWorkers | Self::Modal)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum PrivacyTier {
Sovereign,
Private,
#[default]
Standard,
}
impl PrivacyTier {
#[must_use]
pub fn allows(&self, backend: ServingBackend) -> bool {
match self {
Self::Sovereign => backend.is_local(),
Self::Private => {
backend.is_local()
|| matches!(
backend,
ServingBackend::AzureOpenAI
| ServingBackend::AwsBedrock
| ServingBackend::GoogleVertex
| ServingBackend::AwsLambda )
}
Self::Standard => true,
}
}
#[must_use]
pub fn blocked_hosts(&self) -> Vec<&'static str> {
match self {
Self::Sovereign => {
vec![
"api-inference.huggingface.co",
"api.together.xyz",
"api.replicate.com",
"api.anyscale.com",
"api.modal.com",
"api.fireworks.ai",
"api.groq.com",
"api.openai.com",
"api.anthropic.com",
"openai.azure.com",
"bedrock-runtime.amazonaws.com",
"aiplatform.googleapis.com",
"lambda.amazonaws.com",
"workers.cloudflare.com",
]
}
Self::Private => {
vec![
"api-inference.huggingface.co",
"api.together.xyz",
"api.replicate.com",
"api.anyscale.com",
"api.modal.com",
"api.fireworks.ai",
"api.groq.com",
"api.openai.com",
"api.anthropic.com",
"workers.cloudflare.com", ]
}
Self::Standard => vec![],
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum LatencyTier {
RealTime,
#[default]
Interactive,
Batch,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum ThroughputTier {
#[default]
Low,
Medium,
High,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum CostTier {
Frugal,
#[default]
Balanced,
Premium,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct BackendSelector {
pub privacy: PrivacyTier,
pub latency: LatencyTier,
pub throughput: ThroughputTier,
pub cost: CostTier,
pub disabled: HashSet<ServingBackend>,
pub preferred: Vec<ServingBackend>,
}
impl BackendSelector {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn with_privacy(mut self, tier: PrivacyTier) -> Self {
self.privacy = tier;
self
}
#[must_use]
pub fn with_latency(mut self, tier: LatencyTier) -> Self {
self.latency = tier;
self
}
#[must_use]
pub fn with_throughput(mut self, tier: ThroughputTier) -> Self {
self.throughput = tier;
self
}
#[must_use]
pub fn with_cost(mut self, tier: CostTier) -> Self {
self.cost = tier;
self
}
#[must_use]
pub fn disable(mut self, backend: ServingBackend) -> Self {
self.disabled.insert(backend);
self
}
#[must_use]
pub fn prefer(mut self, backend: ServingBackend) -> Self {
self.preferred.push(backend);
self
}
#[must_use]
pub fn recommend(&self) -> Vec<ServingBackend> {
let mut candidates: Vec<ServingBackend> = Vec::new();
for backend in &self.preferred {
if self.is_valid(*backend) {
candidates.push(*backend);
}
}
let tier_backends = self.get_tier_backends();
for backend in tier_backends {
if self.is_valid(backend) && !candidates.contains(&backend) {
candidates.push(backend);
}
}
candidates
}
#[must_use]
pub fn is_valid(&self, backend: ServingBackend) -> bool {
!self.disabled.contains(&backend) && self.privacy.allows(backend)
}
pub fn validate(&self, backend: ServingBackend) -> Result<(), PrivacyViolation> {
if self.disabled.contains(&backend) {
return Err(PrivacyViolation::BackendDisabled(backend));
}
if !self.privacy.allows(backend) {
return Err(PrivacyViolation::TierViolation { backend, tier: self.privacy });
}
Ok(())
}
fn get_tier_backends(&self) -> Vec<ServingBackend> {
match (self.latency, self.privacy) {
(LatencyTier::RealTime, PrivacyTier::Sovereign) => {
vec![ServingBackend::Realizar, ServingBackend::LlamaCpp]
}
(LatencyTier::RealTime, _) => {
vec![ServingBackend::Groq, ServingBackend::Realizar, ServingBackend::Fireworks]
}
(LatencyTier::Interactive, PrivacyTier::Sovereign) => {
vec![ServingBackend::Realizar, ServingBackend::Ollama, ServingBackend::LlamaCpp]
}
(LatencyTier::Interactive, PrivacyTier::Private) => {
vec![
ServingBackend::Realizar,
ServingBackend::Ollama,
ServingBackend::AzureOpenAI,
ServingBackend::AwsBedrock,
ServingBackend::AwsLambda,
]
}
(LatencyTier::Interactive, PrivacyTier::Standard) => {
vec![
ServingBackend::Realizar,
ServingBackend::Groq,
ServingBackend::Together,
ServingBackend::Fireworks,
]
}
(LatencyTier::Batch, PrivacyTier::Sovereign) => {
vec![ServingBackend::Realizar, ServingBackend::Ollama]
}
(LatencyTier::Batch, PrivacyTier::Private) => {
vec![
ServingBackend::AwsLambda,
ServingBackend::Realizar,
ServingBackend::AwsBedrock,
]
}
(LatencyTier::Batch, PrivacyTier::Standard) => {
vec![
ServingBackend::AwsLambda,
ServingBackend::Together,
ServingBackend::HuggingFace,
ServingBackend::Replicate,
]
}
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PrivacyViolation {
BackendDisabled(ServingBackend),
TierViolation { backend: ServingBackend, tier: PrivacyTier },
}
impl std::fmt::Display for PrivacyViolation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::BackendDisabled(b) => write!(f, "Backend {:?} is disabled", b),
Self::TierViolation { backend, tier } => {
write!(f, "Backend {:?} violates {:?} privacy tier", backend, tier)
}
}
}
}
impl std::error::Error for PrivacyViolation {}
#[cfg(test)]
#[allow(non_snake_case)]
mod tests {
use super::*;
#[test]
fn test_SERVE_BKD_001_local_backends() {
assert!(ServingBackend::Realizar.is_local());
assert!(ServingBackend::Ollama.is_local());
assert!(ServingBackend::LlamaCpp.is_local());
assert!(ServingBackend::Llamafile.is_local());
assert!(ServingBackend::Candle.is_local());
assert!(ServingBackend::Vllm.is_local());
assert!(ServingBackend::Tgi.is_local());
assert!(ServingBackend::LocalAI.is_local());
}
#[test]
fn test_SERVE_BKD_001_remote_backends() {
assert!(ServingBackend::OpenAI.is_remote());
assert!(ServingBackend::Anthropic.is_remote());
assert!(ServingBackend::Together.is_remote());
assert!(ServingBackend::Groq.is_remote());
assert!(ServingBackend::HuggingFace.is_remote());
}
#[test]
fn test_SERVE_BKD_001_api_hosts() {
assert_eq!(ServingBackend::OpenAI.api_host(), Some("api.openai.com"));
assert_eq!(ServingBackend::Anthropic.api_host(), Some("api.anthropic.com"));
assert_eq!(ServingBackend::Realizar.api_host(), None);
}
#[test]
fn test_SERVE_BKD_002_sovereign_blocks_remote() {
let tier = PrivacyTier::Sovereign;
assert!(tier.allows(ServingBackend::Realizar));
assert!(tier.allows(ServingBackend::Ollama));
assert!(!tier.allows(ServingBackend::OpenAI));
assert!(!tier.allows(ServingBackend::Anthropic));
assert!(!tier.allows(ServingBackend::AzureOpenAI));
}
#[test]
fn test_SERVE_BKD_002_private_allows_enterprise() {
let tier = PrivacyTier::Private;
assert!(tier.allows(ServingBackend::Realizar));
assert!(tier.allows(ServingBackend::AzureOpenAI));
assert!(tier.allows(ServingBackend::AwsBedrock));
assert!(tier.allows(ServingBackend::GoogleVertex));
assert!(!tier.allows(ServingBackend::OpenAI));
assert!(!tier.allows(ServingBackend::Together));
}
#[test]
fn test_SERVE_BKD_002_standard_allows_all() {
let tier = PrivacyTier::Standard;
assert!(tier.allows(ServingBackend::Realizar));
assert!(tier.allows(ServingBackend::OpenAI));
assert!(tier.allows(ServingBackend::Together));
}
#[test]
fn test_SERVE_BKD_002_sovereign_blocked_hosts() {
let hosts = PrivacyTier::Sovereign.blocked_hosts();
assert!(hosts.contains(&"api.openai.com"));
assert!(hosts.contains(&"api.anthropic.com"));
assert!(hosts.contains(&"api.together.xyz"));
assert!(hosts.contains(&"lambda.amazonaws.com"));
assert!(hosts.contains(&"workers.cloudflare.com"));
assert_eq!(hosts.len(), 14);
}
#[test]
fn test_SERVE_BKD_002_standard_no_blocked_hosts() {
let hosts = PrivacyTier::Standard.blocked_hosts();
assert!(hosts.is_empty());
}
#[test]
fn test_SERVE_BKD_003_default_selector() {
let selector = BackendSelector::new();
assert_eq!(selector.privacy, PrivacyTier::Standard);
assert_eq!(selector.latency, LatencyTier::Interactive);
}
#[test]
fn test_SERVE_BKD_003_sovereign_recommend() {
let selector = BackendSelector::new().with_privacy(PrivacyTier::Sovereign);
let backends = selector.recommend();
for backend in &backends {
assert!(backend.is_local(), "{:?} should be local", backend);
}
}
#[test]
fn test_SERVE_BKD_003_realtime_recommend() {
let selector = BackendSelector::new().with_latency(LatencyTier::RealTime);
let backends = selector.recommend();
assert!(backends.contains(&ServingBackend::Groq));
}
#[test]
fn test_SERVE_BKD_003_disabled_backend() {
let selector = BackendSelector::new().disable(ServingBackend::OpenAI);
assert!(!selector.is_valid(ServingBackend::OpenAI));
assert!(selector.is_valid(ServingBackend::Anthropic));
}
#[test]
fn test_SERVE_BKD_003_preferred_backend() {
let selector = BackendSelector::new().prefer(ServingBackend::Anthropic);
let backends = selector.recommend();
assert_eq!(backends[0], ServingBackend::Anthropic);
}
#[test]
fn test_SERVE_BKD_004_validate_sovereign_blocks_openai() {
let selector = BackendSelector::new().with_privacy(PrivacyTier::Sovereign);
let result = selector.validate(ServingBackend::OpenAI);
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), PrivacyViolation::TierViolation { .. }));
}
#[test]
fn test_SERVE_BKD_004_validate_sovereign_allows_local() {
let selector = BackendSelector::new().with_privacy(PrivacyTier::Sovereign);
assert!(selector.validate(ServingBackend::Realizar).is_ok());
assert!(selector.validate(ServingBackend::Ollama).is_ok());
}
#[test]
fn test_SERVE_BKD_004_validate_disabled() {
let selector = BackendSelector::new().disable(ServingBackend::Together);
let result = selector.validate(ServingBackend::Together);
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), PrivacyViolation::BackendDisabled(_)));
}
#[test]
fn test_SERVE_BKD_004_privacy_violation_display() {
let err = PrivacyViolation::TierViolation {
backend: ServingBackend::OpenAI,
tier: PrivacyTier::Sovereign,
};
assert!(err.to_string().contains("OpenAI"));
assert!(err.to_string().contains("Sovereign"));
}
#[test]
fn test_SERVE_BKD_005_builder_chain() {
let selector = BackendSelector::new()
.with_privacy(PrivacyTier::Private)
.with_latency(LatencyTier::RealTime)
.with_throughput(ThroughputTier::High)
.with_cost(CostTier::Premium)
.prefer(ServingBackend::AzureOpenAI)
.disable(ServingBackend::AwsBedrock);
assert_eq!(selector.privacy, PrivacyTier::Private);
assert_eq!(selector.latency, LatencyTier::RealTime);
assert_eq!(selector.throughput, ThroughputTier::High);
assert_eq!(selector.cost, CostTier::Premium);
assert!(selector.preferred.contains(&ServingBackend::AzureOpenAI));
assert!(selector.disabled.contains(&ServingBackend::AwsBedrock));
}
#[test]
fn test_SERVE_BKD_006_empty_recommend() {
let selector = BackendSelector::new()
.with_privacy(PrivacyTier::Sovereign)
.with_latency(LatencyTier::Interactive)
.disable(ServingBackend::Realizar)
.disable(ServingBackend::Ollama)
.disable(ServingBackend::LlamaCpp);
let backends = selector.recommend();
assert!(backends.is_empty());
}
#[test]
fn test_SERVE_BKD_006_batch_tier_prefers_cheap() {
let selector = BackendSelector::new()
.with_latency(LatencyTier::Batch)
.with_privacy(PrivacyTier::Standard);
let backends = selector.recommend();
assert!(backends.contains(&ServingBackend::AwsLambda));
}
#[test]
fn test_SERVE_BKD_007_lambda_is_serverless() {
assert!(ServingBackend::AwsLambda.is_serverless());
assert!(ServingBackend::CloudflareWorkers.is_serverless());
assert!(ServingBackend::Modal.is_serverless());
assert!(!ServingBackend::Realizar.is_serverless());
assert!(!ServingBackend::OpenAI.is_serverless());
}
#[test]
fn test_SERVE_BKD_007_lambda_api_host() {
assert_eq!(ServingBackend::AwsLambda.api_host(), Some("lambda.amazonaws.com"));
assert_eq!(ServingBackend::CloudflareWorkers.api_host(), Some("workers.cloudflare.com"));
}
#[test]
fn test_SERVE_BKD_007_lambda_privacy_tier() {
assert!(PrivacyTier::Private.allows(ServingBackend::AwsLambda));
assert!(PrivacyTier::Standard.allows(ServingBackend::AwsLambda));
assert!(!PrivacyTier::Sovereign.allows(ServingBackend::AwsLambda));
}
#[test]
fn test_SERVE_BKD_007_batch_private_includes_lambda() {
let selector = BackendSelector::new()
.with_latency(LatencyTier::Batch)
.with_privacy(PrivacyTier::Private);
let backends = selector.recommend();
assert!(backends.contains(&ServingBackend::AwsLambda));
}
#[test]
fn test_SERVE_BKD_007_interactive_private_includes_lambda() {
let selector = BackendSelector::new()
.with_latency(LatencyTier::Interactive)
.with_privacy(PrivacyTier::Private);
let backends = selector.recommend();
assert!(backends.contains(&ServingBackend::AwsLambda));
}
#[test]
fn test_SERVE_BKD_007_lambda_is_remote() {
assert!(ServingBackend::AwsLambda.is_remote());
assert!(ServingBackend::CloudflareWorkers.is_remote());
}
#[test]
fn test_SERVE_BKD_007_cloudflare_blocked_in_private() {
assert!(!PrivacyTier::Private.allows(ServingBackend::CloudflareWorkers));
}
#[test]
fn test_SERVE_BKD_007_private_blocked_hosts_includes_cloudflare() {
let hosts = PrivacyTier::Private.blocked_hosts();
assert!(hosts.contains(&"workers.cloudflare.com"));
assert!(!hosts.contains(&"lambda.amazonaws.com"));
}
}