kaynine-core 0.1.0

Core agent loop, messages, events, policies, and provider abstractions for Kaynine
Documentation
use serde::{Deserialize, Serialize};
use uuid::Uuid;

macro_rules! define_id {
    ($name:ident) => {
        #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
        pub struct $name(pub String);

        impl $name {
            pub fn generate() -> Self {
                Self(Uuid::new_v4().to_string())
            }
        }

        impl From<&str> for $name {
            fn from(value: &str) -> Self {
                Self(value.to_string())
            }
        }

        impl From<String> for $name {
            fn from(value: String) -> Self {
                Self(value)
            }
        }

        impl AsRef<str> for $name {
            fn as_ref(&self) -> &str {
                &self.0
            }
        }

        impl std::fmt::Display for $name {
            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                f.write_str(&self.0)
            }
        }
    };
}

define_id!(SessionId);
define_id!(BranchId);
define_id!(RunId);
define_id!(TurnId);
define_id!(EntryId);
define_id!(ToolCallId);
define_id!(ProviderId);
define_id!(ModelId);

impl ProviderId {
    pub const OPENAI: &'static str = "openai";
    pub const OPENAI_COMPATIBLE: &'static str = "openai-compatible";
    pub const ANTHROPIC: &'static str = "anthropic";
}

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

    #[test]
    fn generated_ids_are_unique() {
        assert_ne!(SessionId::generate(), SessionId::generate());
    }

    #[test]
    fn ids_roundtrip_through_serde() {
        let id = RunId::from("run-123");
        let json = serde_json::to_string(&id).unwrap();
        assert_eq!(json, "\"run-123\"");
        let back: RunId = serde_json::from_str(&json).unwrap();
        assert_eq!(back, id);
    }

    #[test]
    fn ids_convert_from_str_and_string() {
        let a: BranchId = "b1".into();
        let b: BranchId = String::from("b2").into();
        assert_eq!(a.as_ref(), "b1");
        assert_eq!(b.to_string(), "b2");
    }

    #[test]
    fn provider_constants_match_spec() {
        assert_eq!(ProviderId::OPENAI, "openai");
        assert_eq!(ProviderId::OPENAI_COMPATIBLE, "openai-compatible");
        assert_eq!(ProviderId::ANTHROPIC, "anthropic");
    }
}