reasonkit-core 0.1.8

The Reasoning Engine — Auditable Reasoning for Production AI | Rust-Native | Turn Prompts into Protocols
//! Datalog Deductive Reasoning Engine
//!
//! This module provides compile-time Datalog inference using the Crepe library.
//! Datalog is excellent for deductive reasoning, particularly transitive closure
//! and reachability problems.
//!
//! # Features
//! - Compile-time rule optimization
//! - Type-safe fact and rule definitions
//! - Efficient join algorithms
//! - Integration with ReasonKit's belief state management
//!
//! Enable with: `cargo build --features datalog`

pub mod trust_relations {
    //! Trust Relationship Datalog Program
    //!
    //! Demonstrates transitive trust inference:
    //! - If A trusts B, and B trusts C, then A trusts C (transitively)

    use crepe::crepe;

    crepe! {
        @input
        pub struct DirectTrust<'a>(&'a str, &'a str);

        @output
        pub struct TransitiveTrust<'a>(&'a str, &'a str);

        // Base case: direct trust implies transitive trust
        TransitiveTrust(a, b) <- DirectTrust(a, b);

        // Recursive case: trust is transitive
        TransitiveTrust(a, c) <- DirectTrust(a, b), TransitiveTrust(b, c);
    }
}

pub mod access_control {
    //! Access Control Policy Datalog Program
    //!
    //! Implements role-based access control (RBAC) with:
    //! - User-role assignments
    //! - Role-permission grants
    //! - Derived user permissions

    use crepe::crepe;

    crepe! {
        @input
        pub struct HasRole<'a>(&'a str, &'a str);  // user, role

        @input
        pub struct RoleGrants<'a>(&'a str, &'a str);  // role, permission

        @output
        pub struct HasPermission<'a>(&'a str, &'a str);  // user, permission

        // Users have permissions granted to their roles
        HasPermission(user, perm) <- HasRole(user, role), RoleGrants(role, perm);
    }
}

pub mod knowledge_graph_inference {
    //! Knowledge Graph Inference Program
    //!
    //! Derives implicit relationships in a knowledge graph:
    //! - Superclass hierarchies
    //! - Property inheritance
    //! - Type inference

    use crepe::crepe;

    crepe! {
        @input
        pub struct IsA<'a>(&'a str, &'a str);  // entity, type

        @input
        pub struct SubclassOf<'a>(&'a str, &'a str);  // subtype, supertype

        @output
        pub struct DerivedType<'a>(&'a str, &'a str);  // entity, derived_type

        // Direct type assignment
        DerivedType(entity, typ) <- IsA(entity, typ);

        // Type inheritance through subclass hierarchy
        DerivedType(entity, supertype) <- DerivedType(entity, subtype), SubclassOf(subtype, supertype);
    }
}

/// Belief State Manager
///
/// Maintains a consistent belief state using Datalog inference.
/// Facts are added as observations, and derived beliefs are computed automatically.
pub struct BeliefState {
    /// Observed facts (entity, property, value)
    observations: Vec<(String, String, String)>,
}

impl BeliefState {
    /// Create a new empty belief state
    pub fn new() -> Self {
        Self {
            observations: Vec::new(),
        }
    }

    /// Add an observation to the belief state
    pub fn observe(&mut self, entity: &str, property: &str, value: &str) {
        self.observations
            .push((entity.to_string(), property.to_string(), value.to_string()));
    }

    /// Get all observations
    pub fn observations(&self) -> &[(String, String, String)] {
        &self.observations
    }

    /// Clear all observations
    pub fn clear(&mut self) {
        self.observations.clear();
    }
}

impl Default for BeliefState {
    fn default() -> Self {
        Self::new()
    }
}

/// Policy Engine using Datalog
///
/// Evaluates safety constraints and access policies.
/// Rules are compiled at build time for maximum performance.
pub struct PolicyEngine {
    /// Denied actions (for safety guardrails)
    denied_actions: Vec<(String, String)>, // (actor, action)
    /// Allowed actions (explicit permissions)
    allowed_actions: Vec<(String, String)>,
}

impl PolicyEngine {
    /// Create a new policy engine
    pub fn new() -> Self {
        Self {
            denied_actions: Vec::new(),
            allowed_actions: Vec::new(),
        }
    }

    /// Add a denial rule
    pub fn deny(&mut self, actor: &str, action: &str) {
        self.denied_actions
            .push((actor.to_string(), action.to_string()));
    }

    /// Add an allow rule
    pub fn allow(&mut self, actor: &str, action: &str) {
        self.allowed_actions
            .push((actor.to_string(), action.to_string()));
    }

    /// Check if an action is permitted (allow unless explicitly denied)
    pub fn is_permitted(&self, actor: &str, action: &str) -> bool {
        // Denial takes precedence
        if self
            .denied_actions
            .iter()
            .any(|(a, act)| a == actor && act == action)
        {
            return false;
        }
        // Check if explicitly allowed (or default allow if no rules)
        self.allowed_actions.is_empty()
            || self
                .allowed_actions
                .iter()
                .any(|(a, act)| a == actor && act == action)
    }
}

impl Default for PolicyEngine {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_belief_state() {
        let mut state = BeliefState::new();
        state.observe("object1", "location", "room_a");
        state.observe("object1", "color", "red");

        assert_eq!(state.observations().len(), 2);
    }

    #[test]
    fn test_policy_engine() {
        let mut engine = PolicyEngine::new();
        engine.allow("agent", "read_file");
        engine.deny("agent", "delete_system");

        assert!(engine.is_permitted("agent", "read_file"));
        assert!(!engine.is_permitted("agent", "delete_system"));
    }
}