xynthe 0.1.0

A unified orchestration framework for autonomous intelligence with temporal continuity
Documentation
//! Core types used throughout Xynthe

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;

/// Timestamp for temporal awareness
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Timestamp(DateTime<Utc>);

impl Timestamp {
    /// Create a new timestamp with current time
    pub fn now() -> Self {
        Self(Utc::now())
    }

    /// Create a timestamp from a DateTime
    pub fn from_datetime(dt: DateTime<Utc>) -> Self {
        Self(dt)
    }

    /// Get the inner DateTime
    pub fn as_datetime(&self) -> DateTime<Utc> {
        self.0
    }

    /// Get the duration since another timestamp
    pub fn duration_since(&self, other: Timestamp) -> chrono::Duration {
        self.0.signed_duration_since(other.0)
    }
}

impl Default for Timestamp {
    fn default() -> Self {
        Self::now()
    }
}

/// Structured content for thought events
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type", content = "data")]
pub enum StructuredContent {
    /// Plain text content
    Text(String),

    /// JSON content
    Json(serde_json::Value),

    /// Binary content
    Binary(Vec<u8>),

    /// Composite content
    Composite(Vec<StructuredContent>),
}

impl StructuredContent {
    /// Create text content
    pub fn text(content: impl Into<String>) -> Self {
        Self::Text(content.into())
    }

    /// Create JSON content
    pub fn json(value: serde_json::Value) -> Self {
        Self::Json(value)
    }

    /// Create binary content
    pub fn binary(data: Vec<u8>) -> Self {
        Self::Binary(data)
    }

    /// Try to get content as text
    pub fn as_text(&self) -> Option<&str> {
        match self {
            Self::Text(s) => Some(s),
            _ => None,
        }
    }

    /// Try to get content as JSON
    pub fn as_json(&self) -> Option<&serde_json::Value> {
        match self {
            Self::Json(v) => Some(v),
            _ => None,
        }
    }
}

impl Default for StructuredContent {
    fn default() -> Self {
        Self::Text(String::new())
    }
}

/// Chain of provenance tracking the origin of events
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct ProvenanceChain {
    /// Unique identifier for this chain
    pub id: Uuid,

    /// Parent event IDs in the chain
    pub parents: Vec<Uuid>,

    /// Creation timestamp
    pub created_at: Timestamp,
}

impl ProvenanceChain {
    /// Create a new provenance chain
    pub fn new() -> Self {
        Self {
            id: Uuid::new_v4(),
            parents: Vec::new(),
            created_at: Timestamp::now(),
        }
    }

    /// Create a provenance chain from a parent
    pub fn from_parent(parent_id: Uuid) -> Self {
        Self {
            id: Uuid::new_v4(),
            parents: vec![parent_id],
            created_at: Timestamp::now(),
        }
    }

    /// Add a parent to the chain
    pub fn with_parent(mut self, parent_id: Uuid) -> Self {
        self.parents.push(parent_id);
        self
    }

    /// Create a merged provenance chain
    pub fn merge(parents: Vec<Uuid>) -> Self {
        Self {
            id: Uuid::new_v4(),
            parents,
            created_at: Timestamp::now(),
        }
    }
}

impl From<Uuid> for ProvenanceChain {
    fn from(id: Uuid) -> Self {
        Self::from_parent(id)
    }
}

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

    #[test]
    fn test_timestamp_creation() {
        let ts = Timestamp::now();
        std::thread::sleep(std::time::Duration::from_millis(1));
        let ts2 = Timestamp::now();
        assert!(ts2 > ts);
    }

    #[test]
    fn test_structured_content() {
        let content = StructuredContent::text("Hello, world!");
        assert_eq!(content.as_text(), Some("Hello, world!"));
        assert_eq!(content.as_json(), None);
    }

    #[test]
    fn test_provenance_chain() {
        let chain = ProvenanceChain::new();
        assert!(chain.parents.is_empty());

        let parent_id = Uuid::new_v4();
        let child = ProvenanceChain::from_parent(parent_id);
        assert_eq!(child.parents, vec![parent_id]);
    }
}