harmony-protocol 0.1.0

Reverse-engineered OpenAI Harmony response format library for structured conversation handling
Documentation
use crate::{
    chat::{Conversation, Message, Role, SystemContent},
    load_harmony_encoding,
    HarmonyEncodingName,
};

const _ENCODINGS: [HarmonyEncodingName; 1] = [HarmonyEncodingName::HarmonyGptOss];

#[test]
fn test_basic_message_creation() {
    let message = Message::from_role_and_content(Role::User, "Hello, world!");
    assert_eq!(message.author.role, Role::User);
    assert_eq!(message.author.name, None);
    assert_eq!(message.content.len(), 1);
}

#[test]
fn test_conversation_creation() {
    let convo = Conversation::from_messages([
        Message::from_role_and_content(Role::System, SystemContent::new()),
        Message::from_role_and_content(Role::User, "Test message"),
    ]);
    assert_eq!(convo.messages.len(), 2);
}

#[test]
fn test_system_content_builder() {
    let system_content = SystemContent::new()
        .with_model_identity("Test Model")
        .with_required_channels(["test", "channel"]);

    assert_eq!(system_content.model_identity, Some("Test Model".to_string()));
    assert!(system_content.channel_config.is_some());
}

#[test]
fn test_encoding_load() {
    // This test will fail in CI without network access, but demonstrates the API
    // In a real implementation, you might want to mock the vocabulary loading
    let result = load_harmony_encoding(HarmonyEncodingName::HarmonyGptOss);
    // Just test that the function signature works
    match result {
        Ok(encoding) => {
            assert_eq!(encoding.name(), "HarmonyGptOss");
        }
        Err(_) => {
            // Expected to fail without network access or cached vocab
            println!("Encoding load failed (expected in test environment)");
        }
    }
}

#[test]
fn test_role_conversions() {
    assert_eq!(Role::User.as_str(), "user");
    assert_eq!(Role::Assistant.as_str(), "assistant");
    assert_eq!(Role::System.as_str(), "system");
    assert_eq!(Role::Developer.as_str(), "developer");
    assert_eq!(Role::Tool.as_str(), "tool");

    assert_eq!(Role::try_from("user").unwrap(), Role::User);
    assert_eq!(Role::try_from("assistant").unwrap(), Role::Assistant);
    assert!(Role::try_from("invalid").is_err());
}

#[test]
fn test_message_builder_pattern() {
    let message = Message::from_role_and_content(Role::Assistant, "Test")
        .with_channel("final")
        .with_recipient("user");

    assert_eq!(message.channel, Some("final".to_string()));
    assert_eq!(message.recipient, Some("user".to_string()));
}

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

    #[test]
    fn test_complete_conversation_flow() {
        // This demonstrates the complete API usage
        let system_msg = Message::from_role_and_content(
            Role::System,
            SystemContent::new()
                .with_model_identity("Test Assistant")
                .with_required_channels(["analysis", "final"])
        );

        let user_msg = Message::from_role_and_content(Role::User, "What is 2 + 2?");

        let assistant_analysis = Message::from_role_and_content(Role::Assistant, "This is a simple arithmetic problem.")
            .with_channel("analysis");

        let assistant_final = Message::from_role_and_content(Role::Assistant, "2 + 2 = 4")
            .with_channel("final");

        let conversation = Conversation::from_messages([
            system_msg,
            user_msg,
            assistant_analysis,
            assistant_final,
        ]);

        assert_eq!(conversation.messages.len(), 4);
        assert_eq!(conversation.messages[2].channel, Some("analysis".to_string()));
        assert_eq!(conversation.messages[3].channel, Some("final".to_string()));
    }
}