ai-agent 0.13.4

Idiomatic agent sdk inspired by the claude code source leak
Documentation
// Source: /data/home/swei/claudecode/openclaudecode/src/services/api/logging.ts
//! API logging utilities

use serde::{Deserialize, Serialize};

/// Log level for API logging
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum ApiLogLevel {
    Debug,
    Info,
    Warn,
    Error,
}

impl Default for ApiLogLevel {
    fn default() -> Self {
        ApiLogLevel::Info
    }
}

/// API log entry
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiLogEntry {
    pub timestamp: String,
    pub level: ApiLogLevel,
    pub message: String,
    pub details: Option<serde_json::Value>,
}

impl ApiLogEntry {
    pub fn new(level: ApiLogLevel, message: impl Into<String>) -> Self {
        Self {
            timestamp: chrono::Utc::now().to_rfc3339(),
            level,
            message: message.into(),
            details: None,
        }
    }

    pub fn with_details(mut self, details: serde_json::Value) -> Self {
        self.details = Some(details);
        self
    }

    pub fn debug(message: impl Into<String>) -> Self {
        Self::new(ApiLogLevel::Debug, message)
    }

    pub fn info(message: impl Into<String>) -> Self {
        Self::new(ApiLogLevel::Info, message)
    }

    pub fn warn(message: impl Into<String>) -> Self {
        Self::new(ApiLogLevel::Warn, message)
    }

    pub fn error(message: impl Into<String>) -> Self {
        Self::new(ApiLogLevel::Error, message)
    }
}

/// Global API logger
pub struct ApiLogger {
    enabled: bool,
    min_level: ApiLogLevel,
}

impl ApiLogger {
    pub fn new() -> Self {
        Self {
            enabled: true,
            min_level: ApiLogLevel::Info,
        }
    }

    pub fn set_enabled(&mut self, enabled: bool) {
        self.enabled = enabled;
    }

    pub fn set_min_level(&mut self, level: ApiLogLevel) {
        self.min_level = level;
    }

    pub fn log(&self, entry: &ApiLogEntry) {
        if !self.enabled {
            return;
        }

        let level_priority = match entry.level {
            ApiLogLevel::Debug => 0,
            ApiLogLevel::Info => 1,
            ApiLogLevel::Warn => 2,
            ApiLogLevel::Error => 3,
        };

        let min_priority = match self.min_level {
            ApiLogLevel::Debug => 0,
            ApiLogLevel::Info => 1,
            ApiLogLevel::Warn => 2,
            ApiLogLevel::Error => 3,
        };

        if level_priority >= min_priority {
            // In a real implementation, this would write to a log
            eprintln!("[API] {:?}: {}", entry.level, entry.message);
        }
    }
}

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

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

    #[test]
    fn test_api_log_entry_creation() {
        let entry = ApiLogEntry::info("test message");
        assert_eq!(entry.level, ApiLogLevel::Info);
        assert_eq!(entry.message, "test message");
        assert!(entry.details.is_none());
    }

    #[test]
    fn test_api_log_entry_with_details() {
        let entry = ApiLogEntry::info("test").with_details(serde_json::json!({"key": "value"}));
        assert!(entry.details.is_some());
    }
}