ai-agent 0.13.4

Idiomatic agent sdk inspired by the claude code source leak
Documentation
// Source: /data/home/swei/claudecode/openclaudecode/src/utils/uuid.ts
//! UUID utilities

use regex::Regex;
use uuid::Uuid;

/// AgentId type - a string identifier for agents
pub type AgentId = String;

/// UUID validation regex: 8-4-4-4-12 hex digits
const UUID_REGEX_PATTERN: &str = r"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$";

lazy_static::lazy_static! {
    static ref UUID_REGEX: Regex = Regex::new(UUID_REGEX_PATTERN).unwrap();
}

/// Validate uuid
/// Returns the string as UUID or None if it is not valid
pub fn validate_uuid(maybe_uuid: &dyn ToString) -> Option<String> {
    let s = maybe_uuid.to_string();
    if UUID_REGEX.is_match(&s) {
        Some(s)
    } else {
        None
    }
}

/// Generate a new agent ID with prefix for consistency with task IDs.
/// Format: a{label-}{16 hex chars}
/// Example: aa3f2c1b4d5e6f7a8, acompact-a3f2c1b4d5e6f7a8
pub fn create_agent_id(label: Option<&str>) -> AgentId {
    // Use only first 8 bytes (16 hex chars) of a v4 UUID to match TypeScript's randomBytes(8)
    let uuid = Uuid::new_v4();
    let bytes = uuid.as_bytes();
    let suffix = hex::encode(&bytes[..8]);
    match label {
        Some(l) => format!("a{}-{}", l, suffix),
        None => format!("a{}", suffix),
    }
}

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

    #[test]
    fn test_validate_uuid_valid() {
        let valid_uuid = "550e8400-e29b-41d4-a716-446655440000";
        assert_eq!(validate_uuid(&valid_uuid), Some(valid_uuid.to_string()));
    }

    #[test]
    fn test_validate_uuid_invalid() {
        assert_eq!(validate_uuid(&"not-a-uuid"), None);
        assert_eq!(validate_uuid(&"123"), None);
        assert_eq!(validate_uuid(&""), None);
    }

    #[test]
    fn test_create_agent_id_no_label() {
        let id = create_agent_id(None);
        assert!(id.starts_with('a'));
        assert!(!id.contains('-'));
        assert_eq!(id.len(), 17); // 'a' + 16 hex chars
    }

    #[test]
    fn test_create_agent_id_with_label() {
        let id = create_agent_id(Some("compact"));
        assert!(id.starts_with("acompact-"));
        assert!(id.len() > 17);
    }
}