use super::{NanoAgent, NanoBus, Message, TickResult};
use super::bus::MessageData;
use std::collections::HashMap;
use std::sync::Arc;
use parking_lot::RwLock;
#[derive(Debug, Clone)]
pub struct PolicyUpdate {
pub agent_name: &'static str,
pub parameter: String,
pub value: PolicyValue,
}
#[derive(Debug, Clone)]
pub enum PolicyValue {
U64(u64),
F64(f64),
Bool(bool),
}
pub struct CriticReflector {
trace_window: usize,
recent_traces: Vec<AgentPerformance>,
policy_cache: Arc<RwLock<HashMap<String, PolicyValue>>>,
learning_rate: f64,
}
#[derive(Debug, Clone)]
struct AgentPerformance {
agent_name: &'static str,
avg_latency_ns: f64,
message_rate: f64,
budget_violations: u32,
}
impl CriticReflector {
pub fn new(trace_window: usize, learning_rate: f64) -> Self {
Self {
trace_window,
recent_traces: Vec::with_capacity(trace_window),
policy_cache: Arc::new(RwLock::new(HashMap::new())),
learning_rate,
}
}
pub fn analyze(&mut self, traces: &[AgentPerformance]) -> Vec<PolicyUpdate> {
let mut updates = Vec::new();
for trace in traces {
if trace.budget_violations > 0 {
updates.push(PolicyUpdate {
agent_name: trace.agent_name,
parameter: "tick_frequency".to_string(),
value: PolicyValue::F64(0.9), });
}
if trace.avg_latency_ns > 1000.0 {
updates.push(PolicyUpdate {
agent_name: trace.agent_name,
parameter: "complexity".to_string(),
value: PolicyValue::U64(1), });
}
if trace.message_rate > 1000.0 {
updates.push(PolicyUpdate {
agent_name: trace.agent_name,
parameter: "batch_size".to_string(),
value: PolicyValue::U64(10),
});
}
}
self.recent_traces.extend_from_slice(traces);
if self.recent_traces.len() > self.trace_window {
self.recent_traces.drain(0..self.recent_traces.len() - self.trace_window);
}
updates
}
pub fn learn(&mut self) -> f64 {
if self.recent_traces.is_empty() {
return 0.0;
}
let total_latency: f64 = self.recent_traces.iter()
.map(|t| t.avg_latency_ns)
.sum();
let avg_latency = total_latency / self.recent_traces.len() as f64;
let improvement = if self.recent_traces.len() > 10 {
let recent_avg = self.recent_traces[self.recent_traces.len() - 5..]
.iter()
.map(|t| t.avg_latency_ns)
.sum::<f64>() / 5.0;
let past_avg = self.recent_traces[..5]
.iter()
.map(|t| t.avg_latency_ns)
.sum::<f64>() / 5.0;
(past_avg - recent_avg) / past_avg
} else {
0.0
};
if improvement > 0.0 {
self.learning_rate *= 1.1; } else {
self.learning_rate *= 0.9; }
improvement
}
pub fn get_policy(&self, key: &str) -> Option<PolicyValue> {
self.policy_cache.read().get(key).cloned()
}
pub fn set_policy(&mut self, key: String, value: PolicyValue) {
self.policy_cache.write().insert(key, value);
}
}
impl NanoAgent for CriticReflector {
fn name(&self) -> &'static str {
"critic_reflector"
}
fn tick(&mut self, now_ns: u128, bus: &NanoBus) -> TickResult {
let mut messages_recv = 0u32;
let mut messages_sent = 0u32;
for _ in 0..16 {
if let Some(msg) = bus.try_recv() {
messages_recv += 1;
if msg.topic == "metrics:agent" {
if let MessageData::F64(latency) = msg.data {
}
}
} else {
break;
}
}
if now_ns % 1_000_000_000 == 0 {
let improvement = self.learn();
bus.publish(Message {
topic: "critic:improvement",
data: MessageData::F64(improvement),
timestamp_ns: now_ns,
});
messages_sent += 1;
}
TickResult {
cycles: 0,
messages_sent,
messages_recv,
budget_used_ns: 100, }
}
fn budget_ns(&self) -> u128 {
10_000 }
fn reflect(&mut self, update: PolicyUpdate) {
self.set_policy(update.parameter, update.value);
}
}