use serde::{Deserialize, Serialize};
use std::sync::atomic::{AtomicU64, Ordering};
use super::error::{Result, RuvLlmIntegrationError};
#[derive(Debug)]
pub struct RuvLlmAdapter {
config: AdapterConfig,
stats: AdapterStats,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdapterConfig {
pub storage_path: String,
pub embedding_dim: usize,
pub async_enabled: bool,
pub connection_timeout_ms: u64,
pub max_retries: u32,
pub cache_coherence: bool,
pub cache_ttl_secs: u64,
}
impl Default for AdapterConfig {
fn default() -> Self {
Self {
storage_path: ".prime-radiant/ruvllm".to_string(),
embedding_dim: 768,
async_enabled: true,
connection_timeout_ms: 5000,
max_retries: 3,
cache_coherence: true,
cache_ttl_secs: 300,
}
}
}
#[derive(Debug, Default)]
pub struct AdapterStats {
pub requests: AtomicU64,
pub passed: AtomicU64,
pub failed: AtomicU64,
pub escalated: AtomicU64,
pub cache_hits: AtomicU64,
pub cache_misses: AtomicU64,
pub total_time_us: AtomicU64,
}
impl AdapterStats {
pub fn pass_rate(&self) -> f64 {
let total = self.requests.load(Ordering::Relaxed);
if total == 0 {
return 1.0;
}
let passed = self.passed.load(Ordering::Relaxed);
passed as f64 / total as f64
}
pub fn cache_hit_rate(&self) -> f64 {
let hits = self.cache_hits.load(Ordering::Relaxed);
let misses = self.cache_misses.load(Ordering::Relaxed);
let total = hits + misses;
if total == 0 {
return 0.0;
}
hits as f64 / total as f64
}
pub fn avg_time_us(&self) -> f64 {
let total = self.requests.load(Ordering::Relaxed);
if total == 0 {
return 0.0;
}
let time = self.total_time_us.load(Ordering::Relaxed);
time as f64 / total as f64
}
pub fn snapshot(&self) -> AdapterStatsSnapshot {
AdapterStatsSnapshot {
requests: self.requests.load(Ordering::Relaxed),
passed: self.passed.load(Ordering::Relaxed),
failed: self.failed.load(Ordering::Relaxed),
escalated: self.escalated.load(Ordering::Relaxed),
cache_hits: self.cache_hits.load(Ordering::Relaxed),
cache_misses: self.cache_misses.load(Ordering::Relaxed),
total_time_us: self.total_time_us.load(Ordering::Relaxed),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdapterStatsSnapshot {
pub requests: u64,
pub passed: u64,
pub failed: u64,
pub escalated: u64,
pub cache_hits: u64,
pub cache_misses: u64,
pub total_time_us: u64,
}
impl RuvLlmAdapter {
pub fn new(config: AdapterConfig) -> Result<Self> {
Ok(Self {
config,
stats: AdapterStats::default(),
})
}
pub fn config(&self) -> &AdapterConfig {
&self.config
}
pub fn stats(&self) -> &AdapterStats {
&self.stats
}
pub fn record_pass(&self, time_us: u64) {
self.stats.requests.fetch_add(1, Ordering::Relaxed);
self.stats.passed.fetch_add(1, Ordering::Relaxed);
self.stats.total_time_us.fetch_add(time_us, Ordering::Relaxed);
}
pub fn record_fail(&self, time_us: u64) {
self.stats.requests.fetch_add(1, Ordering::Relaxed);
self.stats.failed.fetch_add(1, Ordering::Relaxed);
self.stats.total_time_us.fetch_add(time_us, Ordering::Relaxed);
}
pub fn record_escalation(&self, time_us: u64) {
self.stats.requests.fetch_add(1, Ordering::Relaxed);
self.stats.escalated.fetch_add(1, Ordering::Relaxed);
self.stats.total_time_us.fetch_add(time_us, Ordering::Relaxed);
}
pub fn record_cache_hit(&self) {
self.stats.cache_hits.fetch_add(1, Ordering::Relaxed);
}
pub fn record_cache_miss(&self) {
self.stats.cache_misses.fetch_add(1, Ordering::Relaxed);
}
pub fn validate(&self) -> Result<()> {
if self.config.embedding_dim == 0 {
return Err(RuvLlmIntegrationError::Config(
"Embedding dimension must be > 0".to_string(),
));
}
if self.config.connection_timeout_ms == 0 {
return Err(RuvLlmIntegrationError::Config(
"Connection timeout must be > 0".to_string(),
));
}
Ok(())
}
}