use crate::benchmarks::BenchmarkData;
use async_trait::async_trait;
#[derive(Debug, thiserror::Error)]
pub enum PortError {
#[error("Source not available: {0}")]
NotAvailable(String),
#[error("Data not found: {0}")]
NotFound(String),
#[error("Connection error: {0}")]
ConnectionError(String),
#[error("Parse error: {0}")]
ParseError(String),
#[error("Timeout: {0}")]
Timeout(String),
}
pub type PortResult<T> = Result<T, PortError>;
#[async_trait]
pub trait BenchmarkPort: Send + Sync {
async fn get_benchmark(&self, model_id: &str) -> PortResult<Option<BenchmarkData>>;
async fn get_all_benchmarks(&self) -> PortResult<Vec<BenchmarkData>>;
async fn refresh(&self) -> PortResult<()>;
async fn is_available(&self) -> bool;
fn source_name(&self) -> &str;
}
use crate::benchmarks::cliproxy_metrics::{ModelMetrics, ProviderMetrics};
#[async_trait]
pub trait MetricsPort: Send + Sync {
async fn get_provider_metrics(&self) -> PortResult<Vec<ProviderMetrics>>;
async fn get_model_metrics(&self) -> PortResult<Vec<ModelMetrics>>;
async fn get_model_realtime(&self, model_id: &str) -> PortResult<Option<ModelMetrics>>;
async fn is_available(&self) -> bool;
fn source_name(&self) -> &str;
}
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RoutingDecision {
pub model: String,
pub provider: String,
pub strategy: String,
pub confidence: f64,
pub reason: String,
pub alternatives: Vec<RoutingAlternative>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RoutingAlternative {
pub model: String,
pub provider: String,
pub score: f64,
pub reason: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct RoutingCriteria {
pub min_quality: Option<f64>,
pub max_cost: Option<f64>,
pub max_latency: Option<u32>,
pub min_throughput: Option<f64>,
pub min_context: Option<u64>,
pub task_type: Option<String>,
pub is_agentic: Option<bool>,
pub allow_fallback: Option<bool>,
}
#[async_trait]
pub trait RoutingPort: Send + Sync {
async fn select(&self, criteria: &RoutingCriteria) -> PortResult<RoutingDecision>;
async fn get_rankings(
&self,
category: Option<&str>,
limit: Option<u32>,
) -> PortResult<Vec<RoutingAlternative>>;
async fn is_available(&self) -> bool;
fn source_name(&self) -> &str;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModelMapping {
pub source_model: String,
pub canonical_model: String,
pub provider: Option<String>,
pub harness: Option<String>,
pub confidence: f64,
pub rule: String,
}
#[async_trait]
pub trait ModelMappingPort: Send + Sync {
async fn map_model(&self, source_model: &str) -> PortResult<ModelMapping>;
async fn resolve_provider(&self, model: &str) -> PortResult<Option<String>>;
async fn resolve_harness(&self, model: &str) -> PortResult<Option<String>>;
async fn all_mappings(&self) -> PortResult<Vec<ModelMapping>>;
async fn is_available(&self) -> bool;
fn source_name(&self) -> &str;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProviderHarnessModel {
pub provider: String,
pub harness: String,
pub model: String,
pub quality_score: Option<f64>,
pub cost_per_1k: Option<f64>,
pub latency_ms: Option<u32>,
pub throughput_tps: Option<f64>,
pub context_window: Option<u64>,
pub success_rate: Option<f64>,
}
#[async_trait]
pub trait TrioPort: Send + Sync {
async fn resolve_trio(
&self,
provider: Option<&str>,
harness: Option<&str>,
model: &str,
) -> PortResult<ProviderHarnessModel>;
async fn all_trios(&self) -> PortResult<Vec<ProviderHarnessModel>>;
async fn is_available(&self) -> bool;
fn source_name(&self) -> &str;
}