zoey-core 0.1.1

ZoeyAI core runtime and types — privacy-first AI agent framework optimized for local models
Documentation
//! IPO Pattern - Input, Process, Output
//!
//! Structured event processing pattern for agent interactions

use crate::types::*;
use crate::{ZoeyError, Result};
use std::sync::Arc;
use tracing::{debug, info};

/// Input stage - receives and validates events
#[derive(Debug, Clone)]
pub struct Input {
    /// Event type
    pub event_type: EventType,

    /// Raw event data
    pub event_data: EventPayload,

    /// Input timestamp
    pub timestamp: i64,

    /// Validation result
    pub validated: bool,

    /// Compliance check result
    pub compliance_passed: bool,
}

/// Process stage - transforms input into actionable items
#[derive(Debug, Clone)]
pub struct Process {
    /// Input that was processed
    pub input_id: uuid::Uuid,

    /// Planned actions
    pub planned_actions: Vec<String>,

    /// State composed from providers
    pub state_hash: String,

    /// Processing decisions
    pub decisions: Vec<ProcessDecision>,

    /// Risk assessment
    pub risk_level: String,
}

/// Processing decision
#[derive(Debug, Clone)]
pub struct ProcessDecision {
    /// Decision type
    pub decision_type: String,

    /// Reasoning
    pub reasoning: String,

    /// Confidence (0.0 - 1.0)
    pub confidence: f32,
}

/// Output stage - generates and validates responses
#[derive(Debug, Clone)]
pub struct Output {
    /// Process that generated this output
    pub process_id: uuid::Uuid,

    /// Generated responses
    pub responses: Vec<Memory>,

    /// PII redactions applied
    pub pii_redacted: Vec<String>,

    /// Compliance validated
    pub compliance_validated: bool,

    /// Output approved
    pub approved: bool,
}

/// IPO Pipeline - Input => Process => Output
pub struct IPOPipeline {
    /// Whether to enforce strict compliance
    strict_mode: bool,

    /// Whether to use local LLM only
    local_only: bool,
}

impl IPOPipeline {
    /// Create a new IPO pipeline
    pub fn new(strict_mode: bool, local_only: bool) -> Self {
        Self {
            strict_mode,
            local_only,
        }
    }

    /// Check if pipeline is in local-only mode
    pub fn is_local_only(&self) -> bool {
        self.local_only
    }

    /// Check if pipeline is in strict mode
    pub fn is_strict_mode(&self) -> bool {
        self.strict_mode
    }

    /// Process an event through the IPO pipeline
    pub async fn process_event(
        &self,
        event_type: EventType,
        event_data: EventPayload,
        runtime: Arc<dyn std::any::Any + Send + Sync>,
    ) -> Result<Output> {
        info!(
            "IPO Pipeline: Processing {:?} event (strict_mode={}, local_only={})",
            event_type, self.strict_mode, self.local_only
        );

        // === INPUT STAGE ===
        debug!("IPO: Input stage - validating event");
        let input = self.input_stage(event_type, event_data).await?;

        if !input.validated {
            return Err(ZoeyError::validation("Input validation failed"));
        }

        if self.strict_mode && !input.compliance_passed {
            return Err(ZoeyError::validation("Input failed compliance check"));
        }

        // === PROCESS STAGE ===
        debug!("IPO: Process stage - planning and execution");
        let process = self.process_stage(&input, runtime.clone()).await?;

        // === OUTPUT STAGE ===
        debug!("IPO: Output stage - generating and validating output");
        let output = self.output_stage(&process, runtime).await?;

        if self.strict_mode && !output.approved {
            return Err(ZoeyError::validation("Output failed approval"));
        }

        info!(
            "IPO Pipeline: Complete - {} responses generated",
            output.responses.len()
        );
        Ok(output)
    }

    /// Input stage - validate and check compliance
    async fn input_stage(&self, event_type: EventType, event_data: EventPayload) -> Result<Input> {
        let timestamp = chrono::Utc::now().timestamp();

        // Validate input
        let validated = true; // Would perform actual validation

        // Check compliance (placeholder)
        let compliance_passed = true; // Would check against judgment plugin

        Ok(Input {
            event_type,
            event_data,
            timestamp,
            validated,
            compliance_passed,
        })
    }

    /// Process stage - plan and prepare
    async fn process_stage(
        &self,
        _input: &Input,
        _runtime: Arc<dyn std::any::Any + Send + Sync>,
    ) -> Result<Process> {
        let input_id = uuid::Uuid::new_v4();

        // Use reaction planner functor to determine actions
        let planned_actions = vec!["REPLY".to_string()]; // Would use ReactionPlannerFunctor

        // Compose state (would use actual runtime)
        let state_hash = "state_hash_placeholder".to_string();

        // Make processing decisions
        let decisions = vec![ProcessDecision {
            decision_type: "RESPOND".to_string(),
            reasoning: "User asked a question".to_string(),
            confidence: 0.9,
        }];

        // Assess risk
        let risk_level = "LOW".to_string();

        Ok(Process {
            input_id,
            planned_actions,
            state_hash,
            decisions,
            risk_level,
        })
    }

    /// Output stage - generate and validate
    async fn output_stage(
        &self,
        _process: &Process,
        _runtime: Arc<dyn std::any::Any + Send + Sync>,
    ) -> Result<Output> {
        let process_id = uuid::Uuid::new_v4();

        // Generate responses (would use OutputPlannerFunctor + LLM)
        let responses = vec![]; // Placeholder

        // Scan for PII and redact (would use judgment plugin)
        let pii_redacted = vec![];

        // Validate compliance
        let compliance_validated = true;

        // Approve output if compliant
        let approved = compliance_validated && (!self.strict_mode || pii_redacted.is_empty());

        Ok(Output {
            process_id,
            responses,
            pii_redacted,
            compliance_validated,
            approved,
        })
    }
}

impl Default for IPOPipeline {
    fn default() -> Self {
        Self::new(false, false)
    }
}

/// Government-compliant IPO pipeline
pub fn create_government_pipeline() -> IPOPipeline {
    IPOPipeline::new(true, true) // Strict mode + local only
}

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

    #[tokio::test]
    async fn test_ipo_pipeline() {
        let _pipeline = IPOPipeline::default();

        let _event_type = EventType::MessageReceived;
        let _event_data = EventPayload::Generic(std::collections::HashMap::new());

        // This would fail without actual runtime, but tests the structure
        // let result = pipeline.process_event(event_type, event_data, Arc::new(())).await;
    }

    #[test]
    fn test_government_pipeline() {
        let pipeline = create_government_pipeline();
        assert!(pipeline.strict_mode);
        assert!(pipeline.local_only);
    }

    #[tokio::test]
    async fn test_input_stage() {
        let pipeline = IPOPipeline::default();
        let event_type = EventType::MessageReceived;
        let event_data = EventPayload::Generic(std::collections::HashMap::new());

        let input = pipeline.input_stage(event_type, event_data).await.unwrap();
        assert!(input.validated);
    }
}