Squashed 'vendor/ruvector/' content from commit b64c2172
git-subtree-dir: vendor/ruvector git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
This commit is contained in:
251
crates/prime-radiant/examples/basic_coherence.rs
Normal file
251
crates/prime-radiant/examples/basic_coherence.rs
Normal file
@@ -0,0 +1,251 @@
|
||||
//! Basic Coherence Example
|
||||
//!
|
||||
//! This example demonstrates the core sheaf coherence concepts:
|
||||
//! - Creating a small sheaf graph with nodes
|
||||
//! - Adding edges with restriction maps
|
||||
//! - Computing coherence energy
|
||||
//! - Comparing coherent vs incoherent scenarios
|
||||
//!
|
||||
//! Run with: `cargo run --example basic_coherence`
|
||||
|
||||
use prime_radiant::substrate::{SheafEdgeBuilder, SheafGraph, SheafNodeBuilder, StateVector};
|
||||
|
||||
fn main() {
|
||||
println!("=== Prime-Radiant: Basic Coherence Example ===\n");
|
||||
|
||||
// Example 1: Coherent Sheaf Graph
|
||||
// When all nodes have consistent states, energy is low
|
||||
println!("--- Example 1: Coherent Graph ---");
|
||||
run_coherent_example();
|
||||
|
||||
println!();
|
||||
|
||||
// Example 2: Incoherent Sheaf Graph
|
||||
// When nodes have contradictory states, energy is high
|
||||
println!("--- Example 2: Incoherent Graph ---");
|
||||
run_incoherent_example();
|
||||
|
||||
println!();
|
||||
|
||||
// Example 3: Mixed coherence with different edge weights
|
||||
println!("--- Example 3: Weighted Edges ---");
|
||||
run_weighted_example();
|
||||
}
|
||||
|
||||
/// Demonstrates a coherent sheaf graph where all nodes agree
|
||||
fn run_coherent_example() {
|
||||
// Create a new sheaf graph
|
||||
let graph = SheafGraph::new();
|
||||
|
||||
// Create nodes with similar state vectors
|
||||
// In a coherent system, connected nodes should have consistent states
|
||||
// that satisfy the restriction map constraints
|
||||
|
||||
// Node A: represents a "fact" with embedding [1.0, 0.5, 0.0, 0.2]
|
||||
let node_a = SheafNodeBuilder::new()
|
||||
.state(StateVector::new(vec![1.0, 0.5, 0.0, 0.2]))
|
||||
.label("fact_a")
|
||||
.node_type("assertion")
|
||||
.namespace("knowledge")
|
||||
.build();
|
||||
let id_a = graph.add_node(node_a);
|
||||
|
||||
// Node B: represents a related "fact" with very similar embedding
|
||||
let node_b = SheafNodeBuilder::new()
|
||||
.state(StateVector::new(vec![1.0, 0.5, 0.0, 0.2])) // Same as A = coherent
|
||||
.label("fact_b")
|
||||
.node_type("assertion")
|
||||
.namespace("knowledge")
|
||||
.build();
|
||||
let id_b = graph.add_node(node_b);
|
||||
|
||||
// Node C: also consistent with A and B
|
||||
let node_c = SheafNodeBuilder::new()
|
||||
.state(StateVector::new(vec![1.0, 0.5, 0.0, 0.2])) // Same state
|
||||
.label("fact_c")
|
||||
.node_type("assertion")
|
||||
.namespace("knowledge")
|
||||
.build();
|
||||
let id_c = graph.add_node(node_c);
|
||||
|
||||
// Add edges with identity restriction maps
|
||||
// Identity restriction means: source state should equal target state
|
||||
let edge_ab = SheafEdgeBuilder::new(id_a, id_b)
|
||||
.identity_restrictions(4) // 4-dimensional identity map
|
||||
.weight(1.0)
|
||||
.edge_type("semantic")
|
||||
.build();
|
||||
graph.add_edge(edge_ab).expect("Failed to add edge A->B");
|
||||
|
||||
let edge_bc = SheafEdgeBuilder::new(id_b, id_c)
|
||||
.identity_restrictions(4)
|
||||
.weight(1.0)
|
||||
.edge_type("semantic")
|
||||
.build();
|
||||
graph.add_edge(edge_bc).expect("Failed to add edge B->C");
|
||||
|
||||
let edge_ca = SheafEdgeBuilder::new(id_c, id_a)
|
||||
.identity_restrictions(4)
|
||||
.weight(1.0)
|
||||
.edge_type("semantic")
|
||||
.build();
|
||||
graph.add_edge(edge_ca).expect("Failed to add edge C->A");
|
||||
|
||||
// Compute coherence energy
|
||||
let energy = graph.compute_energy();
|
||||
|
||||
println!("Graph with 3 coherent nodes and 3 edges:");
|
||||
println!(" Nodes: fact_a, fact_b, fact_c (all identical states)");
|
||||
println!(" Edges: A<->B, B<->C, C<->A (identity restrictions)");
|
||||
println!();
|
||||
println!("Coherence Results:");
|
||||
println!(" Total Energy: {:.6}", energy.total_energy);
|
||||
println!(" Node Count: {}", graph.node_count());
|
||||
println!(" Edge Count: {}", energy.edge_count);
|
||||
println!();
|
||||
|
||||
// Energy should be 0 or very close to 0 for perfectly coherent system
|
||||
if energy.total_energy < 0.01 {
|
||||
println!(" Status: COHERENT (energy near zero)");
|
||||
} else {
|
||||
println!(" Status: Some incoherence detected");
|
||||
}
|
||||
}
|
||||
|
||||
/// Demonstrates an incoherent sheaf graph where nodes contradict
|
||||
fn run_incoherent_example() {
|
||||
let graph = SheafGraph::new();
|
||||
|
||||
// Node A: represents one "fact"
|
||||
let node_a = SheafNodeBuilder::new()
|
||||
.state(StateVector::new(vec![1.0, 0.0, 0.0, 0.0]))
|
||||
.label("claim_positive")
|
||||
.node_type("assertion")
|
||||
.namespace("knowledge")
|
||||
.build();
|
||||
let id_a = graph.add_node(node_a);
|
||||
|
||||
// Node B: represents a CONTRADICTORY "fact"
|
||||
// This embedding is opposite to Node A
|
||||
let node_b = SheafNodeBuilder::new()
|
||||
.state(StateVector::new(vec![-1.0, 0.0, 0.0, 0.0])) // Opposite!
|
||||
.label("claim_negative")
|
||||
.node_type("assertion")
|
||||
.namespace("knowledge")
|
||||
.build();
|
||||
let id_b = graph.add_node(node_b);
|
||||
|
||||
// Node C: partially different
|
||||
let node_c = SheafNodeBuilder::new()
|
||||
.state(StateVector::new(vec![0.0, 1.0, 0.0, 0.0])) // Orthogonal
|
||||
.label("claim_other")
|
||||
.node_type("assertion")
|
||||
.namespace("knowledge")
|
||||
.build();
|
||||
let id_c = graph.add_node(node_c);
|
||||
|
||||
// Add edges - these constrain that states should be equal
|
||||
// But they're NOT equal, so residual energy will be high
|
||||
let edge_ab = SheafEdgeBuilder::new(id_a, id_b)
|
||||
.identity_restrictions(4)
|
||||
.weight(1.0)
|
||||
.edge_type("contradiction")
|
||||
.build();
|
||||
graph.add_edge(edge_ab).expect("Failed to add edge A->B");
|
||||
|
||||
let edge_bc = SheafEdgeBuilder::new(id_b, id_c)
|
||||
.identity_restrictions(4)
|
||||
.weight(1.0)
|
||||
.edge_type("mismatch")
|
||||
.build();
|
||||
graph.add_edge(edge_bc).expect("Failed to add edge B->C");
|
||||
|
||||
// Compute coherence energy
|
||||
let energy = graph.compute_energy();
|
||||
|
||||
println!("Graph with 3 incoherent nodes:");
|
||||
println!(" Node A: [1.0, 0.0, 0.0, 0.0] (positive claim)");
|
||||
println!(" Node B: [-1.0, 0.0, 0.0, 0.0] (contradictory)");
|
||||
println!(" Node C: [0.0, 1.0, 0.0, 0.0] (orthogonal)");
|
||||
println!();
|
||||
println!("Coherence Results:");
|
||||
println!(" Total Energy: {:.6}", energy.total_energy);
|
||||
println!(" Node Count: {}", graph.node_count());
|
||||
println!(" Edge Count: {}", energy.edge_count);
|
||||
println!();
|
||||
|
||||
// Show per-edge energy breakdown
|
||||
println!(" Per-Edge Energy:");
|
||||
for (edge_id, edge_energy) in &energy.edge_energies {
|
||||
println!(" Edge {}: {:.6}", edge_id, edge_energy);
|
||||
}
|
||||
println!();
|
||||
|
||||
// Energy should be high for incoherent system
|
||||
if energy.total_energy > 0.5 {
|
||||
println!(" Status: INCOHERENT (high energy indicates contradiction)");
|
||||
} else {
|
||||
println!(" Status: Mostly coherent");
|
||||
}
|
||||
}
|
||||
|
||||
/// Demonstrates how edge weights affect coherence energy
|
||||
fn run_weighted_example() {
|
||||
let graph = SheafGraph::new();
|
||||
|
||||
// Create nodes with different states
|
||||
let node_a = SheafNodeBuilder::new()
|
||||
.state(StateVector::new(vec![1.0, 0.5, 0.0, 0.0]))
|
||||
.label("primary")
|
||||
.build();
|
||||
let id_a = graph.add_node(node_a);
|
||||
|
||||
let node_b = SheafNodeBuilder::new()
|
||||
.state(StateVector::new(vec![0.8, 0.6, 0.1, 0.0])) // Slightly different
|
||||
.label("secondary")
|
||||
.build();
|
||||
let id_b = graph.add_node(node_b);
|
||||
|
||||
let node_c = SheafNodeBuilder::new()
|
||||
.state(StateVector::new(vec![0.0, 0.0, 1.0, 0.0])) // Very different
|
||||
.label("tertiary")
|
||||
.build();
|
||||
let id_c = graph.add_node(node_c);
|
||||
|
||||
// Edge A->B: LOW weight (we don't care much if they match)
|
||||
let edge_ab = SheafEdgeBuilder::new(id_a, id_b)
|
||||
.identity_restrictions(4)
|
||||
.weight(0.1) // Low weight
|
||||
.edge_type("weak_constraint")
|
||||
.build();
|
||||
graph.add_edge(edge_ab).expect("Failed to add edge A->B");
|
||||
|
||||
// Edge A->C: HIGH weight (important constraint)
|
||||
let edge_ac = SheafEdgeBuilder::new(id_a, id_c)
|
||||
.identity_restrictions(4)
|
||||
.weight(5.0) // High weight
|
||||
.edge_type("strong_constraint")
|
||||
.build();
|
||||
graph.add_edge(edge_ac).expect("Failed to add edge A->C");
|
||||
|
||||
let energy = graph.compute_energy();
|
||||
|
||||
println!("Graph demonstrating weighted edges:");
|
||||
println!(" Node A: [1.0, 0.5, 0.0, 0.0]");
|
||||
println!(" Node B: [0.8, 0.6, 0.1, 0.0] (slightly different)");
|
||||
println!(" Node C: [0.0, 0.0, 1.0, 0.0] (very different)");
|
||||
println!();
|
||||
println!(" Edge A->B: weight 0.1 (weak constraint)");
|
||||
println!(" Edge A->C: weight 5.0 (strong constraint)");
|
||||
println!();
|
||||
println!("Coherence Results:");
|
||||
println!(" Total Energy: {:.6}", energy.total_energy);
|
||||
println!();
|
||||
println!(" Per-Edge Energy:");
|
||||
for (edge_id, edge_energy) in &energy.edge_energies {
|
||||
println!(" Edge {}: {:.6}", edge_id, edge_energy);
|
||||
}
|
||||
println!();
|
||||
println!(" Notice: The high-weight edge contributes much more to total energy,");
|
||||
println!(" even though A->B has a smaller residual (state difference).");
|
||||
}
|
||||
368
crates/prime-radiant/examples/compute_ladder.rs
Normal file
368
crates/prime-radiant/examples/compute_ladder.rs
Normal file
@@ -0,0 +1,368 @@
|
||||
//! Compute Ladder Example
|
||||
//!
|
||||
//! This example demonstrates Prime-Radiant's 4-lane compute ladder
|
||||
//! for energy-based routing and escalation.
|
||||
//!
|
||||
//! The compute ladder routes actions to different processing lanes based on
|
||||
//! coherence energy:
|
||||
//! - Lane 0 (Reflex): Instant, low-cost processing for coherent actions
|
||||
//! - Lane 1 (Retrieval): Light reasoning with evidence fetching
|
||||
//! - Lane 2 (Heavy): Multi-step planning, spectral analysis
|
||||
//! - Lane 3 (Human): Escalation for sustained incoherence
|
||||
//!
|
||||
//! Run with: `cargo run --example compute_ladder`
|
||||
|
||||
use prime_radiant::execution::{
|
||||
Action, ActionImpact, ActionMetadata, CoherenceGate, ComputeLane, EnergySnapshot, GateDecision,
|
||||
LaneThresholds, PolicyBundleRef, ScopeId,
|
||||
};
|
||||
use std::time::Duration;
|
||||
|
||||
fn main() {
|
||||
println!("=== Prime-Radiant: Compute Ladder Example ===\n");
|
||||
|
||||
// Example 1: Low energy - Reflex lane
|
||||
println!("--- Example 1: Low Energy -> Reflex Lane ---");
|
||||
run_reflex_example();
|
||||
|
||||
println!();
|
||||
|
||||
// Example 2: Medium energy - Retrieval lane
|
||||
println!("--- Example 2: Medium Energy -> Retrieval Lane ---");
|
||||
run_retrieval_example();
|
||||
|
||||
println!();
|
||||
|
||||
// Example 3: High energy - Heavy lane
|
||||
println!("--- Example 3: High Energy -> Heavy Lane ---");
|
||||
run_heavy_example();
|
||||
|
||||
println!();
|
||||
|
||||
// Example 4: Very high energy - Human escalation
|
||||
println!("--- Example 4: Very High Energy -> Human Escalation ---");
|
||||
run_human_escalation_example();
|
||||
|
||||
println!();
|
||||
|
||||
// Example 5: Custom thresholds
|
||||
println!("--- Example 5: Custom Threshold Configuration ---");
|
||||
run_custom_thresholds_example();
|
||||
}
|
||||
|
||||
/// Simple error type for example actions
|
||||
#[derive(Debug)]
|
||||
struct ExampleError(String);
|
||||
|
||||
impl std::fmt::Display for ExampleError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for ExampleError {}
|
||||
|
||||
/// Example action for demonstration
|
||||
struct ExampleAction {
|
||||
name: String,
|
||||
scope: ScopeId,
|
||||
impact: ActionImpact,
|
||||
metadata: ActionMetadata,
|
||||
}
|
||||
|
||||
impl ExampleAction {
|
||||
fn new(name: &str, scope: &str, impact: ActionImpact) -> Self {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
scope: ScopeId::new(scope),
|
||||
impact,
|
||||
metadata: ActionMetadata::new("ExampleAction", name, "example"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Execution context for actions
|
||||
struct ExampleContext;
|
||||
|
||||
impl Action for ExampleAction {
|
||||
type Output = String;
|
||||
type Error = ExampleError;
|
||||
|
||||
fn scope(&self) -> &ScopeId {
|
||||
&self.scope
|
||||
}
|
||||
|
||||
fn impact(&self) -> ActionImpact {
|
||||
self.impact
|
||||
}
|
||||
|
||||
fn metadata(&self) -> &ActionMetadata {
|
||||
&self.metadata
|
||||
}
|
||||
|
||||
fn execute(
|
||||
&self,
|
||||
_ctx: &prime_radiant::execution::ExecutionContext,
|
||||
) -> Result<Self::Output, Self::Error> {
|
||||
Ok(format!("Executed action: {}", self.name))
|
||||
}
|
||||
|
||||
fn content_hash(&self) -> [u8; 32] {
|
||||
let mut hash = [0u8; 32];
|
||||
let name_bytes = self.name.as_bytes();
|
||||
for (i, &b) in name_bytes.iter().enumerate().take(32) {
|
||||
hash[i] = b;
|
||||
}
|
||||
hash
|
||||
}
|
||||
|
||||
fn make_rollback_not_supported_error() -> Self::Error {
|
||||
ExampleError("Rollback not supported".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
fn create_test_gate() -> CoherenceGate {
|
||||
let policy_ref = PolicyBundleRef::placeholder();
|
||||
CoherenceGate::with_defaults(policy_ref)
|
||||
}
|
||||
|
||||
fn run_reflex_example() {
|
||||
let mut gate = create_test_gate();
|
||||
|
||||
// Create an action
|
||||
let action = ExampleAction::new("simple_query", "knowledge/facts", ActionImpact::low());
|
||||
|
||||
// Create a LOW energy snapshot
|
||||
// Low energy = system is coherent = fast reflex processing
|
||||
let energy_snapshot = EnergySnapshot::new(
|
||||
0.1, // total_energy: Very low (coherent)
|
||||
0.05, // scope_energy: Also very low
|
||||
ScopeId::new("knowledge/facts"),
|
||||
);
|
||||
|
||||
println!("Action: {}", action.name);
|
||||
println!("Energy Snapshot:");
|
||||
println!(" Total energy: {:.2}", energy_snapshot.total_energy);
|
||||
println!(" Scope energy: {:.2}", energy_snapshot.scope_energy);
|
||||
println!();
|
||||
|
||||
// Evaluate with the gate
|
||||
let (decision, witness) = gate.evaluate_with_witness(&action, &energy_snapshot);
|
||||
|
||||
println!("Gate Decision:");
|
||||
println!(" Allowed: {}", decision.allow);
|
||||
println!(
|
||||
" Compute Lane: {:?} ({})",
|
||||
decision.lane,
|
||||
lane_description(decision.lane)
|
||||
);
|
||||
if let Some(reason) = &decision.reason {
|
||||
println!(" Reason: {}", reason);
|
||||
}
|
||||
println!();
|
||||
println!("Witness Record:");
|
||||
println!(" ID: {}", witness.id);
|
||||
println!(" Integrity verified: {}", witness.verify_integrity());
|
||||
println!();
|
||||
|
||||
explain_decision(decision.lane);
|
||||
}
|
||||
|
||||
fn run_retrieval_example() {
|
||||
let mut gate = create_test_gate();
|
||||
|
||||
let action = ExampleAction::new(
|
||||
"complex_query",
|
||||
"reasoning/inference",
|
||||
ActionImpact::medium(),
|
||||
);
|
||||
|
||||
// Create MEDIUM energy snapshot
|
||||
// Moderate energy = some inconsistency = needs evidence retrieval
|
||||
let energy_snapshot = EnergySnapshot::new(
|
||||
0.45, // total_energy: Medium
|
||||
0.35, // scope_energy: Medium (above reflex threshold)
|
||||
ScopeId::new("reasoning/inference"),
|
||||
);
|
||||
|
||||
println!("Action: {}", action.name);
|
||||
println!("Energy Snapshot:");
|
||||
println!(" Total energy: {:.2}", energy_snapshot.total_energy);
|
||||
println!(" Scope energy: {:.2}", energy_snapshot.scope_energy);
|
||||
println!();
|
||||
|
||||
let (decision, _) = gate.evaluate_with_witness(&action, &energy_snapshot);
|
||||
|
||||
println!("Gate Decision:");
|
||||
println!(" Allowed: {}", decision.allow);
|
||||
println!(
|
||||
" Compute Lane: {:?} ({})",
|
||||
decision.lane,
|
||||
lane_description(decision.lane)
|
||||
);
|
||||
if let Some(reason) = &decision.reason {
|
||||
println!(" Reason: {}", reason);
|
||||
}
|
||||
println!();
|
||||
|
||||
explain_decision(decision.lane);
|
||||
}
|
||||
|
||||
fn run_heavy_example() {
|
||||
let mut gate = create_test_gate();
|
||||
|
||||
let action = ExampleAction::new(
|
||||
"multi_step_planning",
|
||||
"planning/complex",
|
||||
ActionImpact::high(),
|
||||
);
|
||||
|
||||
// Create HIGH energy snapshot
|
||||
// High energy = significant inconsistency = needs heavy computation
|
||||
let energy_snapshot = EnergySnapshot::new(
|
||||
0.75, // total_energy: High
|
||||
0.65, // scope_energy: High (above retrieval threshold)
|
||||
ScopeId::new("planning/complex"),
|
||||
);
|
||||
|
||||
println!("Action: {}", action.name);
|
||||
println!("Energy Snapshot:");
|
||||
println!(" Total energy: {:.2}", energy_snapshot.total_energy);
|
||||
println!(" Scope energy: {:.2}", energy_snapshot.scope_energy);
|
||||
println!();
|
||||
|
||||
let (decision, _) = gate.evaluate_with_witness(&action, &energy_snapshot);
|
||||
|
||||
println!("Gate Decision:");
|
||||
println!(" Allowed: {}", decision.allow);
|
||||
println!(
|
||||
" Compute Lane: {:?} ({})",
|
||||
decision.lane,
|
||||
lane_description(decision.lane)
|
||||
);
|
||||
if let Some(reason) = &decision.reason {
|
||||
println!(" Reason: {}", reason);
|
||||
}
|
||||
println!();
|
||||
|
||||
explain_decision(decision.lane);
|
||||
}
|
||||
|
||||
fn run_human_escalation_example() {
|
||||
let mut gate = create_test_gate();
|
||||
|
||||
let action = ExampleAction::new(
|
||||
"critical_decision",
|
||||
"safety/critical",
|
||||
ActionImpact::critical(),
|
||||
);
|
||||
|
||||
// Create VERY HIGH energy snapshot
|
||||
// Very high energy = sustained incoherence = requires human intervention
|
||||
let energy_snapshot = EnergySnapshot::new(
|
||||
0.95, // total_energy: Very high (near 1.0)
|
||||
0.92, // scope_energy: Very high (above heavy threshold)
|
||||
ScopeId::new("safety/critical"),
|
||||
);
|
||||
|
||||
println!("Action: {}", action.name);
|
||||
println!("Energy Snapshot:");
|
||||
println!(" Total energy: {:.2}", energy_snapshot.total_energy);
|
||||
println!(" Scope energy: {:.2}", energy_snapshot.scope_energy);
|
||||
println!();
|
||||
|
||||
let (decision, _) = gate.evaluate_with_witness(&action, &energy_snapshot);
|
||||
|
||||
println!("Gate Decision:");
|
||||
println!(" Allowed: {}", decision.allow);
|
||||
println!(
|
||||
" Compute Lane: {:?} ({})",
|
||||
decision.lane,
|
||||
lane_description(decision.lane)
|
||||
);
|
||||
if let Some(reason) = &decision.reason {
|
||||
println!(" Reason: {}", reason);
|
||||
}
|
||||
println!();
|
||||
|
||||
explain_decision(decision.lane);
|
||||
|
||||
if decision.lane == ComputeLane::Human {
|
||||
println!();
|
||||
println!(" >> HUMAN ESCALATION TRIGGERED <<");
|
||||
println!(" The system has detected sustained incoherence that");
|
||||
println!(" requires human review before proceeding.");
|
||||
}
|
||||
}
|
||||
|
||||
fn run_custom_thresholds_example() {
|
||||
// Create a gate with custom thresholds
|
||||
let policy_ref = PolicyBundleRef::placeholder();
|
||||
|
||||
// Use custom thresholds: more lenient for reflex, stricter for escalation
|
||||
let custom_thresholds = LaneThresholds::new(0.4, 0.7, 0.9);
|
||||
|
||||
let mut gate = CoherenceGate::new(custom_thresholds, Duration::from_secs(10), policy_ref);
|
||||
|
||||
println!("Custom Threshold Configuration:");
|
||||
println!(" Reflex threshold: 0.40 (more lenient)");
|
||||
println!(" Retrieval threshold: 0.70");
|
||||
println!(" Heavy threshold: 0.90");
|
||||
println!();
|
||||
|
||||
// Test with energy that would trigger retrieval with default thresholds
|
||||
// but stays in reflex with custom thresholds
|
||||
let action = ExampleAction::new("test_action", "test/scope", ActionImpact::medium());
|
||||
|
||||
let energy_snapshot = EnergySnapshot::new(0.35, 0.35, ScopeId::new("test/scope"));
|
||||
|
||||
let (decision, _) = gate.evaluate_with_witness(&action, &energy_snapshot);
|
||||
|
||||
println!("With energy 0.35:");
|
||||
println!(" Default thresholds (reflex=0.3) would route to: Retrieval");
|
||||
println!(
|
||||
" Custom thresholds (reflex=0.4) route to: {:?} ({})",
|
||||
decision.lane,
|
||||
lane_description(decision.lane)
|
||||
);
|
||||
println!();
|
||||
println!("Custom thresholds allow you to:");
|
||||
println!(" - Tune sensitivity based on domain requirements");
|
||||
println!(" - Make critical scopes more conservative");
|
||||
println!(" - Allow more autonomy in low-risk areas");
|
||||
}
|
||||
|
||||
fn lane_description(lane: ComputeLane) -> &'static str {
|
||||
match lane {
|
||||
ComputeLane::Reflex => "instant processing, <1ms",
|
||||
ComputeLane::Retrieval => "evidence fetching, ~10ms",
|
||||
ComputeLane::Heavy => "multi-step reasoning, ~100ms",
|
||||
ComputeLane::Human => "human escalation",
|
||||
}
|
||||
}
|
||||
|
||||
fn explain_decision(lane: ComputeLane) {
|
||||
println!("Lane Explanation:");
|
||||
match lane {
|
||||
ComputeLane::Reflex => {
|
||||
println!(" The system is highly coherent (low energy).");
|
||||
println!(" Action can proceed with minimal computation.");
|
||||
println!(" Typical use: Simple queries, cached responses, routine actions.");
|
||||
}
|
||||
ComputeLane::Retrieval => {
|
||||
println!(" The system shows some uncertainty (medium energy).");
|
||||
println!(" Additional evidence retrieval is recommended.");
|
||||
println!(" Typical use: Questions needing context lookup, clarification.");
|
||||
}
|
||||
ComputeLane::Heavy => {
|
||||
println!(" The system shows significant inconsistency (high energy).");
|
||||
println!(" Multi-step reasoning or spectral analysis is needed.");
|
||||
println!(" Typical use: Complex planning, conflict resolution, deep analysis.");
|
||||
}
|
||||
ComputeLane::Human => {
|
||||
println!(" The system shows sustained incoherence (very high energy).");
|
||||
println!(" Human intervention is required before proceeding.");
|
||||
println!(" Typical use: Safety-critical decisions, policy violations, edge cases.");
|
||||
}
|
||||
}
|
||||
}
|
||||
371
crates/prime-radiant/examples/governance_audit.rs
Normal file
371
crates/prime-radiant/examples/governance_audit.rs
Normal file
@@ -0,0 +1,371 @@
|
||||
//! Governance and Audit Trail Example
|
||||
//!
|
||||
//! This example demonstrates Prime-Radiant's governance features:
|
||||
//! - Creating policy bundles with rules and scopes
|
||||
//! - Generating witness records for audit trails
|
||||
//! - Verifying witness integrity
|
||||
//! - Policy lifecycle management
|
||||
//!
|
||||
//! Run with: `cargo run --example governance_audit`
|
||||
|
||||
use prime_radiant::execution::{
|
||||
Action, ActionImpact, ActionMetadata, CoherenceGate, EnergySnapshot, LaneThresholds,
|
||||
PolicyBundleRef as ExecutionPolicyRef, ScopeId, WitnessRecord,
|
||||
};
|
||||
use prime_radiant::governance::{
|
||||
ApprovalSignature, ApproverId, EscalationCondition, EscalationRule, Hash, PolicyBundle,
|
||||
PolicyBundleBuilder, PolicyBundleRef, PolicyBundleStatus, PolicyError, ThresholdConfig,
|
||||
Timestamp, Version,
|
||||
};
|
||||
use std::time::Duration;
|
||||
|
||||
fn main() {
|
||||
println!("=== Prime-Radiant: Governance & Audit Trail Example ===\n");
|
||||
|
||||
// Example 1: Create a policy bundle
|
||||
println!("--- Example 1: Policy Bundle Creation ---");
|
||||
let policy_bundle = run_policy_bundle_example();
|
||||
|
||||
println!();
|
||||
|
||||
// Example 2: Policy lifecycle
|
||||
println!("--- Example 2: Policy Lifecycle Management ---");
|
||||
run_policy_lifecycle_example();
|
||||
|
||||
println!();
|
||||
|
||||
// Example 3: Generate witness records
|
||||
println!("--- Example 3: Witness Record Generation ---");
|
||||
run_witness_generation_example();
|
||||
|
||||
println!();
|
||||
|
||||
// Example 4: Verify witness chain integrity
|
||||
println!("--- Example 4: Witness Chain Integrity ---");
|
||||
run_chain_verification_example();
|
||||
|
||||
println!();
|
||||
|
||||
// Example 5: Tamper detection
|
||||
println!("--- Example 5: Tamper Detection ---");
|
||||
run_tamper_detection_example();
|
||||
}
|
||||
|
||||
fn run_policy_bundle_example() -> PolicyBundle {
|
||||
println!("Creating a policy bundle for LLM governance...");
|
||||
println!();
|
||||
|
||||
// Create the policy bundle using the builder
|
||||
let policy = PolicyBundleBuilder::new()
|
||||
.name("llm-safety-policy")
|
||||
.description("Safety policies for LLM deployments")
|
||||
.with_threshold("default", ThresholdConfig::default())
|
||||
.with_threshold("safety", ThresholdConfig::strict())
|
||||
.with_threshold("quality", ThresholdConfig::new(0.4, 0.7, 0.9))
|
||||
.with_escalation_rule(EscalationRule::new(
|
||||
"high-energy-escalation",
|
||||
EscalationCondition::EnergyAbove(0.8),
|
||||
3, // Human lane
|
||||
))
|
||||
.with_escalation_rule(
|
||||
EscalationRule::new(
|
||||
"persistent-incoherence",
|
||||
EscalationCondition::PersistentEnergy {
|
||||
threshold: 0.5,
|
||||
duration_secs: 30,
|
||||
},
|
||||
2, // Heavy lane
|
||||
)
|
||||
.with_notify("ops-team"),
|
||||
)
|
||||
.with_required_approvals(2)
|
||||
.with_approver(ApproverId::new("admin@example.com"))
|
||||
.with_approver(ApproverId::new("security@example.com"))
|
||||
.build()
|
||||
.expect("Failed to build policy");
|
||||
|
||||
println!("Policy Bundle Created:");
|
||||
println!(" ID: {}", policy.id);
|
||||
println!(" Name: {}", policy.name);
|
||||
println!(" Version: {}", policy.version);
|
||||
println!(" Status: {:?}", policy.status);
|
||||
println!(" Required approvals: {}", policy.required_approvals);
|
||||
println!();
|
||||
println!("Threshold Configurations:");
|
||||
for (scope, config) in &policy.thresholds {
|
||||
println!(
|
||||
" {}: reflex={:.2}, retrieval={:.2}, heavy={:.2}",
|
||||
scope, config.reflex, config.retrieval, config.heavy
|
||||
);
|
||||
}
|
||||
println!();
|
||||
println!("Escalation Rules:");
|
||||
for rule in &policy.escalation_rules {
|
||||
println!(" - {} -> lane {}", rule.name, rule.target_lane);
|
||||
}
|
||||
|
||||
policy
|
||||
}
|
||||
|
||||
fn run_policy_lifecycle_example() {
|
||||
println!("Demonstrating policy lifecycle transitions...");
|
||||
println!();
|
||||
|
||||
// Create a new policy
|
||||
let mut policy = PolicyBundle::new("lifecycle-demo");
|
||||
println!("1. Created policy in {:?} status", policy.status);
|
||||
println!(" Editable: {}", policy.status.is_editable());
|
||||
|
||||
// Add configuration while in draft
|
||||
policy
|
||||
.add_threshold("default", ThresholdConfig::default())
|
||||
.expect("Failed to add threshold");
|
||||
policy
|
||||
.set_required_approvals(2)
|
||||
.expect("Failed to set approvals");
|
||||
println!("2. Added configuration (still in Draft)");
|
||||
|
||||
// Submit for approval
|
||||
policy.submit_for_approval().expect("Failed to submit");
|
||||
println!("3. Submitted for approval -> {:?}", policy.status);
|
||||
|
||||
// Add first approval
|
||||
let approval1 = ApprovalSignature::placeholder(ApproverId::new("approver1"));
|
||||
policy
|
||||
.add_approval(approval1)
|
||||
.expect("Failed to add approval");
|
||||
println!(
|
||||
"4. Added first approval -> {:?} (approvals: {}/{})",
|
||||
policy.status,
|
||||
policy.approvals.len(),
|
||||
policy.required_approvals
|
||||
);
|
||||
|
||||
// Add second approval (triggers activation)
|
||||
let approval2 = ApprovalSignature::placeholder(ApproverId::new("approver2"));
|
||||
policy
|
||||
.add_approval(approval2)
|
||||
.expect("Failed to add approval");
|
||||
println!("5. Added second approval -> {:?}", policy.status);
|
||||
println!(
|
||||
" Activated at: {:?}",
|
||||
policy.activated_at.map(|t| t.to_string())
|
||||
);
|
||||
|
||||
// Try to modify (should fail)
|
||||
let result = policy.add_threshold("new-scope", ThresholdConfig::strict());
|
||||
println!("6. Attempted modification: {:?}", result.err());
|
||||
|
||||
// Create new version
|
||||
let new_version = policy.create_new_version();
|
||||
println!("7. Created new version:");
|
||||
println!(" New ID: {}", new_version.id);
|
||||
println!(" New version: {}", new_version.version);
|
||||
println!(" Supersedes: {:?}", new_version.supersedes);
|
||||
println!(" Status: {:?}", new_version.status);
|
||||
}
|
||||
|
||||
/// Simple error type for audit actions
|
||||
#[derive(Debug)]
|
||||
struct AuditError(String);
|
||||
|
||||
impl std::fmt::Display for AuditError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for AuditError {}
|
||||
|
||||
/// Example action for witness generation
|
||||
struct AuditAction {
|
||||
name: String,
|
||||
scope: ScopeId,
|
||||
metadata: ActionMetadata,
|
||||
}
|
||||
|
||||
impl AuditAction {
|
||||
fn new(name: &str, scope: &str) -> Self {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
scope: ScopeId::new(scope),
|
||||
metadata: ActionMetadata::new("AuditAction", name, "audit-example"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Action for AuditAction {
|
||||
type Output = String;
|
||||
type Error = AuditError;
|
||||
|
||||
fn scope(&self) -> &ScopeId {
|
||||
&self.scope
|
||||
}
|
||||
|
||||
fn impact(&self) -> ActionImpact {
|
||||
ActionImpact::medium()
|
||||
}
|
||||
|
||||
fn metadata(&self) -> &ActionMetadata {
|
||||
&self.metadata
|
||||
}
|
||||
|
||||
fn execute(
|
||||
&self,
|
||||
_ctx: &prime_radiant::execution::ExecutionContext,
|
||||
) -> Result<Self::Output, Self::Error> {
|
||||
Ok(format!("Executed: {}", self.name))
|
||||
}
|
||||
|
||||
fn content_hash(&self) -> [u8; 32] {
|
||||
let hash = blake3::hash(self.name.as_bytes());
|
||||
let mut result = [0u8; 32];
|
||||
result.copy_from_slice(hash.as_bytes());
|
||||
result
|
||||
}
|
||||
|
||||
fn make_rollback_not_supported_error() -> Self::Error {
|
||||
AuditError("Rollback not supported".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
fn run_witness_generation_example() {
|
||||
println!("Generating witness records for gate decisions...");
|
||||
println!();
|
||||
|
||||
let policy_ref = ExecutionPolicyRef::placeholder();
|
||||
let mut gate = CoherenceGate::with_defaults(policy_ref);
|
||||
|
||||
// Simulate several gate decisions
|
||||
let scenarios = [
|
||||
("Query about Rust programming", "knowledge", 0.15),
|
||||
("Complex code generation", "generation", 0.45),
|
||||
("Ambiguous safety question", "safety", 0.72),
|
||||
("Potentially harmful request", "safety/critical", 0.92),
|
||||
("Follow-up clarification", "chat", 0.25),
|
||||
];
|
||||
|
||||
for (i, (description, scope, energy)) in scenarios.iter().enumerate() {
|
||||
let action = AuditAction::new(description, scope);
|
||||
let energy_snapshot = EnergySnapshot::new(*energy, *energy, ScopeId::new(*scope));
|
||||
|
||||
let (decision, witness) = gate.evaluate_with_witness(&action, &energy_snapshot);
|
||||
|
||||
println!("Decision #{}: {}", i + 1, description);
|
||||
println!(" Allowed: {}", decision.allow);
|
||||
println!(" Lane: {:?}", decision.lane);
|
||||
println!(" Energy: {:.2}", energy);
|
||||
println!(" Witness ID: {}", witness.id);
|
||||
println!(
|
||||
" Previous witness: {}",
|
||||
witness
|
||||
.previous_witness
|
||||
.as_ref()
|
||||
.map(|w| w.to_string())
|
||||
.unwrap_or_else(|| "None (genesis)".to_string())
|
||||
);
|
||||
println!();
|
||||
}
|
||||
}
|
||||
|
||||
fn run_chain_verification_example() {
|
||||
println!("Verifying witness chain integrity...");
|
||||
println!();
|
||||
|
||||
let policy_ref = ExecutionPolicyRef::placeholder();
|
||||
let mut gate = CoherenceGate::with_defaults(policy_ref);
|
||||
|
||||
// Generate a chain of witnesses
|
||||
let mut witnesses = Vec::new();
|
||||
|
||||
for i in 0..5 {
|
||||
let action = AuditAction::new(&format!("action_{}", i), "test");
|
||||
let energy = EnergySnapshot::new(0.2, 0.2, ScopeId::new("test"));
|
||||
let (_, witness) = gate.evaluate_with_witness(&action, &energy);
|
||||
witnesses.push(witness);
|
||||
}
|
||||
|
||||
// Verify each witness's content hash
|
||||
println!("Content Hash Verification:");
|
||||
for (i, witness) in witnesses.iter().enumerate() {
|
||||
let verified = witness.verify_integrity();
|
||||
println!(
|
||||
" Witness #{}: {} (ID: {})",
|
||||
i + 1,
|
||||
if verified { "VALID" } else { "INVALID" },
|
||||
witness.id
|
||||
);
|
||||
}
|
||||
println!();
|
||||
|
||||
// Verify chain linkage
|
||||
println!("Chain Linkage:");
|
||||
println!(
|
||||
" Witness #1: Genesis (previous: {})",
|
||||
witnesses[0]
|
||||
.previous_witness
|
||||
.as_ref()
|
||||
.map(|_| "linked")
|
||||
.unwrap_or("none")
|
||||
);
|
||||
|
||||
for i in 1..witnesses.len() {
|
||||
let current = &witnesses[i];
|
||||
let previous = &witnesses[i - 1];
|
||||
|
||||
let linked = current
|
||||
.previous_witness
|
||||
.as_ref()
|
||||
.map(|prev| prev == &previous.id)
|
||||
.unwrap_or(false);
|
||||
|
||||
println!(
|
||||
" Witness #{}: {} (links to #{})",
|
||||
i + 1,
|
||||
if linked { "LINKED" } else { "BROKEN" },
|
||||
i
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn run_tamper_detection_example() {
|
||||
println!("Demonstrating tamper detection...");
|
||||
println!();
|
||||
|
||||
let policy_ref = ExecutionPolicyRef::placeholder();
|
||||
let mut gate = CoherenceGate::with_defaults(policy_ref);
|
||||
|
||||
// Create a witness
|
||||
let action = AuditAction::new("test_action", "test");
|
||||
let energy = EnergySnapshot::new(0.5, 0.5, ScopeId::new("test"));
|
||||
let (_, mut witness) = gate.evaluate_with_witness(&action, &energy);
|
||||
|
||||
// Verify original
|
||||
println!("Original Witness:");
|
||||
println!(" ID: {}", witness.id);
|
||||
println!(" Content hash: {:x?}", &witness.content_hash[..8]);
|
||||
println!(" Integrity verified: {}", witness.verify_integrity());
|
||||
println!();
|
||||
|
||||
// Tamper with the witness by modifying the decision
|
||||
println!("Tampering with witness (changing allowed status)...");
|
||||
witness.decision.allow = !witness.decision.allow;
|
||||
|
||||
// Verify after tampering
|
||||
println!();
|
||||
println!("After Tampering:");
|
||||
println!(" Decision.allow changed to: {}", witness.decision.allow);
|
||||
println!(" Integrity verified: {}", witness.verify_integrity());
|
||||
println!();
|
||||
|
||||
if !witness.verify_integrity() {
|
||||
println!(" >> TAMPER DETECTED <<");
|
||||
println!(" The witness content has been modified after creation.");
|
||||
println!(" This breaks the audit trail integrity.");
|
||||
println!();
|
||||
println!(" In a production system, this would:");
|
||||
println!(" - Trigger security alerts");
|
||||
println!(" - Invalidate the entire chain from this point");
|
||||
println!(" - Require investigation and remediation");
|
||||
}
|
||||
}
|
||||
289
crates/prime-radiant/examples/llm_validation.rs
Normal file
289
crates/prime-radiant/examples/llm_validation.rs
Normal file
@@ -0,0 +1,289 @@
|
||||
//! LLM Response Validation Example
|
||||
//!
|
||||
//! This example demonstrates how to use Prime-Radiant's sheaf coherence
|
||||
//! to validate LLM responses against their context.
|
||||
//!
|
||||
//! The validator:
|
||||
//! 1. Converts context and response embeddings into sheaf graph nodes
|
||||
//! 2. Adds edges with semantic consistency constraints
|
||||
//! 3. Computes coherence energy
|
||||
//! 4. Produces a validation result with witness record for audit
|
||||
//!
|
||||
//! Run with: `cargo run --example llm_validation --features ruvllm`
|
||||
|
||||
#[cfg(feature = "ruvllm")]
|
||||
use prime_radiant::ruvllm_integration::{
|
||||
EdgeWeights, SheafCoherenceValidator, ValidationContext, ValidatorConfig,
|
||||
};
|
||||
|
||||
#[cfg(feature = "ruvllm")]
|
||||
fn main() {
|
||||
println!("=== Prime-Radiant: LLM Validation Example ===\n");
|
||||
|
||||
// Example 1: Coherent response (passes validation)
|
||||
println!("--- Example 1: Coherent LLM Response ---");
|
||||
run_coherent_validation();
|
||||
|
||||
println!();
|
||||
|
||||
// Example 2: Incoherent response (fails validation)
|
||||
println!("--- Example 2: Incoherent LLM Response ---");
|
||||
run_incoherent_validation();
|
||||
|
||||
println!();
|
||||
|
||||
// Example 3: Validation with supporting evidence
|
||||
println!("--- Example 3: Validation with Supporting Evidence ---");
|
||||
run_validation_with_support();
|
||||
|
||||
println!();
|
||||
|
||||
// Example 4: Demonstrate witness generation
|
||||
println!("--- Example 4: Witness Generation for Audit Trail ---");
|
||||
run_witness_example();
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ruvllm"))]
|
||||
fn main() {
|
||||
println!("This example requires the 'ruvllm' feature.");
|
||||
println!("Run with: cargo run --example llm_validation --features ruvllm");
|
||||
}
|
||||
|
||||
#[cfg(feature = "ruvllm")]
|
||||
fn run_coherent_validation() {
|
||||
// Create a validator with default configuration
|
||||
let mut validator = SheafCoherenceValidator::with_defaults();
|
||||
|
||||
// Create context and response embeddings
|
||||
// In practice, these would come from an embedding model
|
||||
// Here we simulate a coherent scenario: response is very similar to context
|
||||
|
||||
let context_embedding = create_embedding(64, 1.0, 0.5);
|
||||
let response_embedding = create_embedding(64, 1.0, 0.5); // Same as context
|
||||
|
||||
let ctx = ValidationContext::new()
|
||||
.with_context_embedding(context_embedding)
|
||||
.with_response_embedding(response_embedding)
|
||||
.with_scope("general")
|
||||
.with_metadata("model", "example-llm")
|
||||
.with_metadata("prompt_type", "factual_qa");
|
||||
|
||||
// Validate the response
|
||||
match validator.validate(&ctx) {
|
||||
Ok(result) => {
|
||||
println!("Validation Context:");
|
||||
println!(" Embedding dimension: {}", ctx.embedding_dim());
|
||||
println!(" Scope: {}", ctx.scope);
|
||||
println!();
|
||||
println!("Validation Result:");
|
||||
println!(" Allowed: {}", result.allowed);
|
||||
println!(" Energy: {:.6}", result.energy);
|
||||
println!(" Reason: {}", result.reason.as_deref().unwrap_or("N/A"));
|
||||
println!();
|
||||
println!("Witness:");
|
||||
println!(" ID: {}", result.witness.id);
|
||||
println!(" Energy at validation: {:.6}", result.witness.energy);
|
||||
println!(" Decision allowed: {}", result.witness.decision.allowed);
|
||||
println!(
|
||||
" Integrity verified: {}",
|
||||
result.witness.verify_integrity()
|
||||
);
|
||||
|
||||
if result.allowed {
|
||||
println!();
|
||||
println!(" -> Response passed coherence validation!");
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Validation failed: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ruvllm")]
|
||||
fn run_incoherent_validation() {
|
||||
// Configure a strict validator
|
||||
let config = ValidatorConfig {
|
||||
default_dim: 64,
|
||||
reflex_threshold: 0.01, // Very strict - low energy required
|
||||
retrieval_threshold: 0.05,
|
||||
heavy_threshold: 0.1,
|
||||
include_supporting: false,
|
||||
create_cross_support_edges: false,
|
||||
};
|
||||
|
||||
let mut validator = SheafCoherenceValidator::with_defaults().with_config(config);
|
||||
|
||||
// Create DIFFERENT embeddings to simulate incoherent response
|
||||
// This could represent:
|
||||
// - A hallucinated response not supported by context
|
||||
// - An off-topic response
|
||||
// - Factually inconsistent information
|
||||
|
||||
let context_embedding = create_embedding(64, 1.0, 0.0); // Context about topic A
|
||||
let response_embedding = create_embedding(64, -1.0, 0.5); // Response about opposite topic
|
||||
|
||||
let ctx = ValidationContext::new()
|
||||
.with_context_embedding(context_embedding)
|
||||
.with_response_embedding(response_embedding)
|
||||
.with_scope("strict")
|
||||
.with_edge_weights(EdgeWeights::strict()) // Use strict weights
|
||||
.with_metadata("model", "example-llm")
|
||||
.with_metadata("risk_level", "high");
|
||||
|
||||
match validator.validate(&ctx) {
|
||||
Ok(result) => {
|
||||
println!("Validation Context:");
|
||||
println!(" Embedding dimension: {}", ctx.embedding_dim());
|
||||
println!(" Edge weights: Strict mode");
|
||||
println!();
|
||||
println!("Validation Result:");
|
||||
println!(" Allowed: {}", result.allowed);
|
||||
println!(" Energy: {:.6}", result.energy);
|
||||
println!(" Reason: {}", result.reason.as_deref().unwrap_or("N/A"));
|
||||
println!();
|
||||
|
||||
if !result.allowed {
|
||||
println!(" -> Response REJECTED due to high incoherence!");
|
||||
println!(" The response embedding differs significantly from context.");
|
||||
println!(" In a real system, this might indicate:");
|
||||
println!(" - Hallucination (making up facts)");
|
||||
println!(" - Off-topic response");
|
||||
println!(" - Contradiction with given context");
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Validation failed: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ruvllm")]
|
||||
fn run_validation_with_support() {
|
||||
// Configure validator to include supporting embeddings
|
||||
let config = ValidatorConfig {
|
||||
default_dim: 64,
|
||||
reflex_threshold: 0.3,
|
||||
retrieval_threshold: 0.6,
|
||||
heavy_threshold: 0.9,
|
||||
include_supporting: true, // Enable supporting evidence
|
||||
create_cross_support_edges: true, // Create edges between support docs
|
||||
};
|
||||
|
||||
let mut validator = SheafCoherenceValidator::with_defaults().with_config(config);
|
||||
|
||||
// Create embeddings: context, response, and retrieved support documents
|
||||
let context_embedding = create_embedding(64, 0.8, 0.3);
|
||||
let response_embedding = create_embedding(64, 0.75, 0.35); // Similar to context
|
||||
|
||||
// Supporting documents (e.g., from RAG retrieval)
|
||||
let support_1 = create_embedding(64, 0.85, 0.28); // Close to context
|
||||
let support_2 = create_embedding(64, 0.78, 0.32); // Also close
|
||||
|
||||
let ctx = ValidationContext::new()
|
||||
.with_context_embedding(context_embedding)
|
||||
.with_response_embedding(response_embedding)
|
||||
.with_supporting_embedding(support_1)
|
||||
.with_supporting_embedding(support_2)
|
||||
.with_scope("rag_qa")
|
||||
.with_metadata("retriever", "dense_passage")
|
||||
.with_metadata("num_docs", "2");
|
||||
|
||||
match validator.validate(&ctx) {
|
||||
Ok(result) => {
|
||||
println!("Validation with Supporting Evidence:");
|
||||
println!(" Context embedding: 64 dimensions");
|
||||
println!(" Response embedding: 64 dimensions");
|
||||
println!(" Supporting documents: 2");
|
||||
println!();
|
||||
println!("Sheaf Graph Structure:");
|
||||
println!(" - Context node connected to Response");
|
||||
println!(" - Context node connected to each Support doc");
|
||||
println!(" - Response node connected to each Support doc");
|
||||
println!(" - Support docs connected to each other (cross-edges enabled)");
|
||||
println!();
|
||||
println!("Validation Result:");
|
||||
println!(" Allowed: {}", result.allowed);
|
||||
println!(" Energy: {:.6}", result.energy);
|
||||
println!();
|
||||
|
||||
// Show edge breakdown
|
||||
if !result.edge_breakdown.is_empty() {
|
||||
println!("Edge Energy Breakdown:");
|
||||
for (edge_type, energy) in &result.edge_breakdown {
|
||||
println!(" {}: {:.6}", edge_type, energy);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Validation failed: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ruvllm")]
|
||||
fn run_witness_example() {
|
||||
let mut validator = SheafCoherenceValidator::with_defaults();
|
||||
|
||||
let context_embedding = create_embedding(64, 1.0, 0.0);
|
||||
let response_embedding = create_embedding(64, 0.9, 0.1);
|
||||
|
||||
let ctx = ValidationContext::new()
|
||||
.with_context_embedding(context_embedding)
|
||||
.with_response_embedding(response_embedding)
|
||||
.with_scope("audit_example")
|
||||
.with_metadata("user_id", "user_12345")
|
||||
.with_metadata("session_id", "sess_abc");
|
||||
|
||||
match validator.validate(&ctx) {
|
||||
Ok(result) => {
|
||||
println!("Witness Record for Audit Trail:");
|
||||
println!("================================");
|
||||
println!();
|
||||
println!("Witness ID: {}", result.witness.id);
|
||||
println!("Timestamp: {:?}", result.witness.timestamp);
|
||||
println!();
|
||||
println!("Content Hashes (for integrity verification):");
|
||||
println!(" Context hash: {}", result.witness.context_hash);
|
||||
println!(" Response hash: {}", result.witness.response_hash);
|
||||
println!(" Fingerprint: {}", result.witness.fingerprint);
|
||||
println!();
|
||||
println!("Decision Details:");
|
||||
println!(" Scope: {}", result.witness.scope);
|
||||
println!(" Allowed: {}", result.witness.decision.allowed);
|
||||
println!(
|
||||
" Compute lane: {} (0=Reflex, 1=Retrieval, 2=Heavy, 3=Human)",
|
||||
result.witness.decision.lane
|
||||
);
|
||||
println!(" Confidence: {:.4}", result.witness.decision.confidence);
|
||||
println!(" Energy: {:.6}", result.witness.energy);
|
||||
println!();
|
||||
println!("Integrity Verification:");
|
||||
println!(" Hash matches: {}", result.witness.verify_integrity());
|
||||
println!();
|
||||
println!("Request Correlation:");
|
||||
println!(" Request ID: {}", result.request_id);
|
||||
println!();
|
||||
println!("This witness record provides:");
|
||||
println!(" - Cryptographic proof of the validation decision");
|
||||
println!(" - Content hashes for tamper detection");
|
||||
println!(" - Correlation ID for request tracing");
|
||||
println!(" - Energy metrics for monitoring");
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Validation failed: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function to create a test embedding
|
||||
/// base_value and variation control the embedding pattern
|
||||
#[cfg(feature = "ruvllm")]
|
||||
fn create_embedding(dim: usize, base_value: f32, variation: f32) -> Vec<f32> {
|
||||
(0..dim)
|
||||
.map(|i| {
|
||||
let angle = (i as f32) * std::f32::consts::PI / (dim as f32);
|
||||
base_value * angle.cos() + variation * angle.sin()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
353
crates/prime-radiant/examples/memory_tracking.rs
Normal file
353
crates/prime-radiant/examples/memory_tracking.rs
Normal file
@@ -0,0 +1,353 @@
|
||||
//! Memory Coherence Tracking Example
|
||||
//!
|
||||
//! This example demonstrates how to use Prime-Radiant's MemoryCoherenceLayer
|
||||
//! to track and validate memories in an AI agent system.
|
||||
//!
|
||||
//! The memory system tracks three types of memory:
|
||||
//! - Agentic (long-term patterns)
|
||||
//! - Working (current context)
|
||||
//! - Episodic (conversation history)
|
||||
//!
|
||||
//! Run with: `cargo run --example memory_tracking --features ruvllm`
|
||||
|
||||
#[cfg(feature = "ruvllm")]
|
||||
use prime_radiant::ruvllm_integration::{
|
||||
AgenticMemory, EpisodicMemory, MemoryCoherenceConfig, MemoryCoherenceLayer, MemoryEntry,
|
||||
MemoryType, WorkingMemory,
|
||||
};
|
||||
|
||||
#[cfg(feature = "ruvllm")]
|
||||
fn main() {
|
||||
println!("=== Prime-Radiant: Memory Coherence Tracking Example ===\n");
|
||||
|
||||
// Example 1: Basic memory operations
|
||||
println!("--- Example 1: Basic Memory Operations ---");
|
||||
run_basic_memory_example();
|
||||
|
||||
println!();
|
||||
|
||||
// Example 2: Contradiction detection
|
||||
println!("--- Example 2: Contradiction Detection ---");
|
||||
run_contradiction_example();
|
||||
|
||||
println!();
|
||||
|
||||
// Example 3: Episodic memory tracking
|
||||
println!("--- Example 3: Episodic Memory (Conversation History) ---");
|
||||
run_episodic_example();
|
||||
|
||||
println!();
|
||||
|
||||
// Example 4: Query related memories
|
||||
println!("--- Example 4: Finding Related Memories ---");
|
||||
run_related_memory_example();
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ruvllm"))]
|
||||
fn main() {
|
||||
println!("This example requires the 'ruvllm' feature.");
|
||||
println!("Run with: cargo run --example memory_tracking --features ruvllm");
|
||||
}
|
||||
|
||||
#[cfg(feature = "ruvllm")]
|
||||
fn run_basic_memory_example() {
|
||||
// Configure the memory layer
|
||||
let config = MemoryCoherenceConfig {
|
||||
embedding_dim: 8, // Small dimension for demo
|
||||
coherence_threshold: 0.5,
|
||||
auto_semantic_edges: true,
|
||||
semantic_similarity_threshold: 0.7,
|
||||
auto_hierarchical_edges: true,
|
||||
max_semantic_edges: 3,
|
||||
};
|
||||
|
||||
let mut layer = MemoryCoherenceLayer::with_config(config);
|
||||
|
||||
println!("Creating MemoryCoherenceLayer with:");
|
||||
println!(" Embedding dimension: 8");
|
||||
println!(" Coherence threshold: 0.5");
|
||||
println!();
|
||||
|
||||
// Add an agentic (long-term) memory
|
||||
let pattern_embedding = vec![1.0, 0.0, 0.5, 0.0, 0.3, 0.0, 0.1, 0.0];
|
||||
let entry = MemoryEntry::new(
|
||||
"user_prefers_concise",
|
||||
pattern_embedding,
|
||||
MemoryType::Agentic,
|
||||
);
|
||||
|
||||
println!("Adding agentic memory: 'user_prefers_concise'");
|
||||
let result = layer
|
||||
.add_with_coherence(entry)
|
||||
.expect("Failed to add memory");
|
||||
|
||||
println!(" Memory ID: {}", result.memory_id);
|
||||
println!(" Node ID: {}", result.node_id);
|
||||
println!(" Is coherent: {}", result.is_coherent);
|
||||
println!(" Total energy: {:.6}", result.energy);
|
||||
println!(" Edges created: {}", result.edges_created.len());
|
||||
println!();
|
||||
|
||||
// Add working (current context) memory
|
||||
let context_embedding = vec![0.9, 0.1, 0.4, 0.1, 0.2, 0.1, 0.0, 0.1];
|
||||
let context = MemoryEntry::new("current_topic_rust", context_embedding, MemoryType::Working);
|
||||
|
||||
println!("Adding working memory: 'current_topic_rust'");
|
||||
let result2 = layer
|
||||
.add_with_coherence(context)
|
||||
.expect("Failed to add memory");
|
||||
|
||||
println!(" Memory ID: {}", result2.memory_id);
|
||||
println!(" Is coherent: {}", result2.is_coherent);
|
||||
println!(" Local energy: {:.6}", result2.local_energy);
|
||||
println!();
|
||||
|
||||
// Check overall coherence
|
||||
println!("Memory System State:");
|
||||
println!(" Total memories: {}", layer.memory_count());
|
||||
println!(" Overall energy: {:.6}", layer.compute_energy());
|
||||
println!(" System coherent: {}", layer.is_coherent());
|
||||
}
|
||||
|
||||
#[cfg(feature = "ruvllm")]
|
||||
fn run_contradiction_example() {
|
||||
let config = MemoryCoherenceConfig {
|
||||
embedding_dim: 4,
|
||||
coherence_threshold: 0.3, // Strict threshold
|
||||
auto_semantic_edges: true,
|
||||
semantic_similarity_threshold: 0.5,
|
||||
auto_hierarchical_edges: false,
|
||||
max_semantic_edges: 5,
|
||||
};
|
||||
|
||||
let mut layer = MemoryCoherenceLayer::with_config(config);
|
||||
|
||||
println!("Setting up contradiction detection scenario...");
|
||||
println!(" Coherence threshold: 0.3 (strict)");
|
||||
println!();
|
||||
|
||||
// Add a fact about user preference
|
||||
let pref_a = vec![1.0, 0.0, 0.0, 0.0];
|
||||
let entry_a = MemoryEntry::new("user_likes_verbose", pref_a, MemoryType::Agentic);
|
||||
layer
|
||||
.add_with_coherence(entry_a)
|
||||
.expect("Failed to add memory A");
|
||||
println!("Added: 'user_likes_verbose' [1.0, 0.0, 0.0, 0.0]");
|
||||
|
||||
// Add a CONTRADICTORY fact
|
||||
let pref_b = vec![-1.0, 0.0, 0.0, 0.0]; // Opposite direction!
|
||||
let entry_b = MemoryEntry::new("user_likes_concise", pref_b, MemoryType::Agentic);
|
||||
|
||||
println!("Adding potentially contradictory memory...");
|
||||
println!(" 'user_likes_concise' [-1.0, 0.0, 0.0, 0.0]");
|
||||
println!();
|
||||
|
||||
let result = layer
|
||||
.add_with_coherence(entry_b)
|
||||
.expect("Failed to add memory B");
|
||||
|
||||
println!("Contradiction Detection Result:");
|
||||
println!(" Is coherent: {}", result.is_coherent);
|
||||
println!(" Local energy: {:.6}", result.local_energy);
|
||||
println!(" Total system energy: {:.6}", result.energy);
|
||||
|
||||
if !result.is_coherent {
|
||||
println!();
|
||||
println!(" WARNING: Memory contradiction detected!");
|
||||
println!(
|
||||
" Conflicting memories: {} found",
|
||||
result.conflicting_memories.len()
|
||||
);
|
||||
|
||||
for conflict_id in &result.conflicting_memories {
|
||||
println!(" - Conflicts with: {}", conflict_id);
|
||||
}
|
||||
|
||||
println!();
|
||||
println!(" In a real system, you might:");
|
||||
println!(" - Ask for clarification");
|
||||
println!(" - Prefer the newer memory");
|
||||
println!(" - Mark as uncertain/needs-resolution");
|
||||
}
|
||||
|
||||
// Find all incoherent memories
|
||||
println!();
|
||||
println!("Finding all incoherent memories in the system:");
|
||||
let incoherent = layer.find_incoherent_memories();
|
||||
for (memory_id, energy) in &incoherent {
|
||||
println!(" Memory {}: energy = {:.6}", memory_id, energy);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ruvllm")]
|
||||
fn run_episodic_example() {
|
||||
let config = MemoryCoherenceConfig {
|
||||
embedding_dim: 4,
|
||||
coherence_threshold: 0.5,
|
||||
auto_semantic_edges: true,
|
||||
semantic_similarity_threshold: 0.6,
|
||||
auto_hierarchical_edges: false,
|
||||
max_semantic_edges: 2,
|
||||
};
|
||||
|
||||
let mut layer = MemoryCoherenceLayer::with_config(config);
|
||||
|
||||
println!("Simulating a conversation with episodic memory...");
|
||||
println!();
|
||||
|
||||
// Simulate conversation turns
|
||||
let turns = [
|
||||
("user_asks_about_rust", vec![1.0, 0.5, 0.0, 0.0]),
|
||||
("assistant_explains_ownership", vec![0.9, 0.6, 0.1, 0.0]),
|
||||
("user_asks_about_borrowing", vec![0.8, 0.5, 0.3, 0.0]),
|
||||
("assistant_explains_references", vec![0.85, 0.55, 0.25, 0.1]),
|
||||
("user_thanks", vec![0.2, 0.1, 0.0, 0.9]),
|
||||
];
|
||||
|
||||
for (i, (key, embedding)) in turns.iter().enumerate() {
|
||||
let (memory_id, sequence) = layer
|
||||
.add_episode(key, embedding)
|
||||
.expect("Failed to add episode");
|
||||
|
||||
println!(
|
||||
"Turn {}: {} (seq: {}, id: {})",
|
||||
i + 1,
|
||||
key,
|
||||
sequence,
|
||||
memory_id
|
||||
);
|
||||
}
|
||||
|
||||
println!();
|
||||
println!("Episodic Memory State:");
|
||||
println!(" Current sequence: {}", layer.current_sequence());
|
||||
println!(" Total memories: {}", layer.memory_count());
|
||||
println!(" System coherent: {}", layer.is_coherent());
|
||||
println!();
|
||||
|
||||
// Query recent episodes
|
||||
println!("Recent 3 episodes:");
|
||||
for (seq, embedding) in layer.recent_episodes(3) {
|
||||
println!(
|
||||
" Sequence {}: [{:.2}, {:.2}, {:.2}, {:.2}]",
|
||||
seq, embedding[0], embedding[1], embedding[2], embedding[3]
|
||||
);
|
||||
}
|
||||
|
||||
println!();
|
||||
|
||||
// Query range
|
||||
println!("Episodes in range 2-4:");
|
||||
for (seq, embedding) in layer.episodes_in_range(2, 5) {
|
||||
println!(
|
||||
" Sequence {}: [{:.2}, {:.2}, {:.2}, {:.2}]",
|
||||
seq, embedding[0], embedding[1], embedding[2], embedding[3]
|
||||
);
|
||||
}
|
||||
|
||||
println!();
|
||||
|
||||
// Get specific episode
|
||||
if let Some(episode_2) = layer.get_episode(2) {
|
||||
println!(
|
||||
"Episode 2 specifically: [{:.2}, {:.2}, {:.2}, {:.2}]",
|
||||
episode_2[0], episode_2[1], episode_2[2], episode_2[3]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ruvllm")]
|
||||
fn run_related_memory_example() {
|
||||
let config = MemoryCoherenceConfig {
|
||||
embedding_dim: 4,
|
||||
coherence_threshold: 0.5,
|
||||
auto_semantic_edges: true,
|
||||
semantic_similarity_threshold: 0.6,
|
||||
auto_hierarchical_edges: true,
|
||||
max_semantic_edges: 3,
|
||||
};
|
||||
|
||||
let mut layer = MemoryCoherenceLayer::with_config(config);
|
||||
|
||||
println!("Building a knowledge base with interconnected memories...");
|
||||
println!();
|
||||
|
||||
// Add agentic patterns (general knowledge)
|
||||
let patterns = [
|
||||
("pattern_programming", vec![1.0, 0.0, 0.0, 0.0]),
|
||||
("pattern_web_dev", vec![0.5, 0.5, 0.0, 0.0]),
|
||||
("pattern_databases", vec![0.0, 1.0, 0.0, 0.0]),
|
||||
];
|
||||
|
||||
for (key, emb) in &patterns {
|
||||
layer
|
||||
.store_pattern(key, emb)
|
||||
.expect("Failed to store pattern");
|
||||
println!("Stored pattern: {}", key);
|
||||
}
|
||||
|
||||
println!();
|
||||
|
||||
// Add working context related to programming
|
||||
let context_emb = vec![0.9, 0.1, 0.0, 0.0]; // Close to "programming"
|
||||
layer
|
||||
.set_context("current_focus", &context_emb)
|
||||
.expect("Failed to set context");
|
||||
println!("Set current context: 'current_focus' (similar to programming)");
|
||||
println!();
|
||||
|
||||
// Add an episode related to databases
|
||||
let episode_emb = vec![0.1, 0.95, 0.0, 0.0]; // Close to "databases"
|
||||
layer
|
||||
.add_episode("discussed_sql", &episode_emb)
|
||||
.expect("Failed to add episode");
|
||||
println!("Added episode: 'discussed_sql' (similar to databases)");
|
||||
println!();
|
||||
|
||||
// Check system state
|
||||
println!("Memory System Analysis:");
|
||||
println!(" Total memories: {}", layer.memory_count());
|
||||
println!(" Overall energy: {:.6}", layer.compute_energy());
|
||||
println!(" System coherent: {}", layer.is_coherent());
|
||||
println!();
|
||||
|
||||
// List all patterns
|
||||
println!("Stored patterns:");
|
||||
for key in layer.pattern_keys() {
|
||||
println!(" - {}", key);
|
||||
}
|
||||
|
||||
println!();
|
||||
|
||||
// List all context
|
||||
println!("Working context:");
|
||||
for key in layer.context_keys() {
|
||||
if let Some(emb) = layer.get_context(&key) {
|
||||
println!(
|
||||
" - {}: [{:.2}, {:.2}, {:.2}, {:.2}]",
|
||||
key, emb[0], emb[1], emb[2], emb[3]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
println!();
|
||||
|
||||
// Find memories that might be incoherent
|
||||
let incoherent = layer.find_incoherent_memories();
|
||||
if incoherent.is_empty() {
|
||||
println!("All memories are coherent!");
|
||||
} else {
|
||||
println!("Incoherent memories found:");
|
||||
for (id, energy) in &incoherent {
|
||||
println!(" - {}: energy = {:.6}", id, energy);
|
||||
}
|
||||
}
|
||||
|
||||
println!();
|
||||
println!("The memory layer automatically creates edges between:");
|
||||
println!(" - Semantically similar memories (via embedding similarity)");
|
||||
println!(" - Working/Episodic memories and related Agentic patterns (hierarchical)");
|
||||
println!(" - Consecutive episodic memories (temporal sequence)");
|
||||
println!();
|
||||
println!("These edges enable coherence checking across the entire memory graph.");
|
||||
}
|
||||
Reference in New Issue
Block a user