quantumclaw 0.1.0

Single-crate public API for the QuantumClaw agent runtime built on ZeroClaw.
Documentation
use crate::quantumclaw_core::{Observer, Result, SolverKind};
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::BTreeMap;
use std::sync::{Arc, RwLock};

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TraceEvent {
    pub trace_id: String,
    pub event_type: String,
    pub message: String,
    pub selected_backend: Option<String>,
    pub rejected_backend: Option<String>,
    pub plan_score: Option<f64>,
    pub latency_ms: Option<u64>,
    pub cost_estimate: Option<f64>,
    pub confidence: Option<f64>,
    pub policy_decision: Option<String>,
    pub metadata: BTreeMap<String, String>,
}

impl TraceEvent {
    pub fn new(event_type: impl Into<String>, message: impl Into<String>) -> Self {
        Self {
            trace_id: "trace-local".into(),
            event_type: event_type.into(),
            message: message.into(),
            selected_backend: None,
            rejected_backend: None,
            plan_score: None,
            latency_ms: None,
            cost_estimate: None,
            confidence: None,
            policy_decision: None,
            metadata: BTreeMap::new(),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct MetricEvent {
    pub name: String,
    pub value: f64,
    pub dimensions: BTreeMap<String, String>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PlannerComparisonEvent {
    pub primary_backend: String,
    pub primary_backend_kind: SolverKind,
    pub shadow_backend: String,
    pub shadow_backend_kind: SolverKind,
    pub primary_score: f64,
    pub shadow_score: f64,
    pub latency_ms: u64,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BackendTelemetry {
    pub backend: String,
    pub backend_kind: SolverKind,
    pub selected: bool,
    pub latency_ms: u64,
    pub cost_estimate: f64,
    pub confidence: f64,
}

#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct ExecutionTrace {
    pub events: Vec<TraceEvent>,
    pub metrics: Vec<MetricEvent>,
    pub comparisons: Vec<PlannerComparisonEvent>,
}

#[async_trait]
pub trait AuditSink: Send + Sync {
    async fn write_audit(&self, event: Value) -> Result<()>;
}

#[derive(Debug, Default, Clone)]
pub struct InMemoryObserver {
    trace_events: Arc<RwLock<Vec<TraceEvent>>>,
    metric_events: Arc<RwLock<Vec<MetricEvent>>>,
    comparison_events: Arc<RwLock<Vec<PlannerComparisonEvent>>>,
    audit_events: Arc<RwLock<Vec<Value>>>,
}

impl InMemoryObserver {
    pub fn record_trace(&self, event: TraceEvent) {
        self.trace_events
            .write()
            .expect("observer trace lock")
            .push(event);
    }

    pub fn record_metric(&self, event: MetricEvent) {
        self.metric_events
            .write()
            .expect("observer metric lock")
            .push(event);
    }

    pub fn record_comparison(&self, event: PlannerComparisonEvent) {
        self.comparison_events
            .write()
            .expect("observer comparison lock")
            .push(event);
    }

    pub fn execution_trace(&self) -> ExecutionTrace {
        ExecutionTrace {
            events: self
                .trace_events
                .read()
                .expect("observer trace lock")
                .clone(),
            metrics: self
                .metric_events
                .read()
                .expect("observer metric lock")
                .clone(),
            comparisons: self
                .comparison_events
                .read()
                .expect("observer comparison lock")
                .clone(),
        }
    }
}

#[async_trait]
impl Observer for InMemoryObserver {
    async fn observe(&self, event: Value) -> Result<()> {
        self.record_trace(TraceEvent::new("generic", event.to_string()));
        Ok(())
    }
}

#[async_trait]
impl AuditSink for InMemoryObserver {
    async fn write_audit(&self, event: Value) -> Result<()> {
        self.audit_events
            .write()
            .expect("observer audit lock")
            .push(event);
        Ok(())
    }
}