use harmony_response::{
chat::{Conversation, DeveloperContent, Message, Role, SystemContent, ToolDescription, ToolNamespaceConfig},
load_harmony_encoding, HarmonyEncodingName, StreamableParser,
};
#[test]
fn test_full_conversation_roundtrip() {
let system_content = SystemContent::new()
.with_model_identity("Test Assistant")
.with_required_channels(["analysis", "commentary", "final"])
.with_browser_tool();
let tools = vec![
ToolDescription::new(
"calculate",
"Performs calculations",
Some(serde_json::json!({
"type": "object",
"properties": {
"expression": {"type": "string"}
},
"required": ["expression"]
}))
)
];
let dev_content = DeveloperContent::new()
.with_instructions("You are a helpful assistant.")
.with_function_tools(tools);
let conversation = Conversation::from_messages([
Message::from_role_and_content(Role::System, system_content),
Message::from_role_and_content(Role::Developer, dev_content),
Message::from_role_and_content(Role::User, "What is 2 + 2?"),
Message::from_role_and_content(Role::Assistant, "I need to calculate this.")
.with_channel("analysis"),
Message::from_role_and_content(Role::Assistant, "The answer is 4.")
.with_channel("final"),
]);
match load_harmony_encoding(HarmonyEncodingName::HarmonyGptOss) {
Ok(encoding) => {
let tokens = encoding
.render_conversation(&conversation, None)
.expect("Should render conversation");
assert!(!tokens.is_empty(), "Should generate tokens");
let completion_tokens = encoding
.render_conversation_for_completion(&conversation, Role::Assistant, None)
.expect("Should render for completion");
assert!(completion_tokens.len() > tokens.len(), "Completion should have more tokens");
let training_tokens = encoding
.render_conversation_for_training(&conversation, None)
.expect("Should render for training");
assert!(!training_tokens.is_empty(), "Should generate training tokens");
println!("✅ Full conversation roundtrip test passed with {} tokens", tokens.len());
}
Err(e) => {
println!("⚠️ Encoding load failed (expected without network): {}", e);
}
}
}
#[test]
fn test_streaming_parser_comprehensive() {
match load_harmony_encoding(HarmonyEncodingName::HarmonyGptOss) {
Ok(encoding) => {
let conversation = Conversation::from_messages([
Message::from_role_and_content(Role::User, "Hello"),
]);
let tokens = encoding
.render_conversation_for_completion(&conversation, Role::Assistant, None)
.expect("Should render");
let mut parser = StreamableParser::new(encoding.clone(), Some(Role::Assistant))
.expect("Should create parser");
for (i, &token) in tokens.iter().enumerate().take(10) { if let Err(e) = parser.process(token) {
println!("Warning: Token processing failed at position {}: {}", i, e);
break; }
let _current_role = parser.current_role();
let _current_content = parser.current_content().unwrap_or_default();
let _current_channel = parser.current_channel();
let _current_recipient = parser.current_recipient();
println!("Processed token {} at position {}", token, i);
}
match parser.process_eos() {
Ok(_) => println!("✅ Streaming parser completed successfully"),
Err(e) => println!("⚠️ Parser EOS warning (expected with partial tokens): {}", e),
}
let messages = parser.into_messages();
println!("✅ Streaming parser processed {} messages", messages.len());
}
Err(e) => {
println!("⚠️ Encoding load failed (expected without network): {}", e);
}
}
}
#[test]
fn test_message_validation() {
let valid_system = Message::from_role_and_content(Role::System, SystemContent::new());
assert_eq!(valid_system.author.role, Role::System);
let valid_dev = Message::from_role_and_content(Role::Developer, DeveloperContent::new());
assert_eq!(valid_dev.author.role, Role::Developer);
let user_with_channel = Message::from_role_and_content(Role::User, "Hello")
.with_channel("test")
.with_recipient("assistant");
assert_eq!(user_with_channel.channel, Some("test".to_string()));
assert_eq!(user_with_channel.recipient, Some("assistant".to_string()));
let tool_msg = Message::from_role_and_content(Role::Tool, "Tool response")
.with_recipient("user");
assert_eq!(tool_msg.author.role, Role::Tool);
}
#[test]
fn test_complex_tool_definitions() {
let browser_ns = ToolNamespaceConfig::browser();
assert_eq!(browser_ns.name, "browser");
assert!(!browser_ns.tools.is_empty());
let python_ns = ToolNamespaceConfig::python();
assert_eq!(python_ns.name, "python");
let custom_tools = vec![
ToolDescription::new(
"complex_tool",
"A complex tool with nested schema",
Some(serde_json::json!({
"type": "object",
"properties": {
"config": {
"type": "object",
"properties": {
"mode": {"type": "string", "enum": ["fast", "accurate"]},
"threshold": {"type": "number", "minimum": 0, "maximum": 1}
},
"required": ["mode"]
},
"data": {
"type": "array",
"items": {"type": "string"}
}
},
"required": ["config"]
}))
)
];
let custom_ns = ToolNamespaceConfig::new(
"custom",
Some("Custom tool namespace".to_string()),
custom_tools
);
assert_eq!(custom_ns.name, "custom");
assert_eq!(custom_ns.tools.len(), 1);
assert_eq!(custom_ns.tools[0].name, "complex_tool");
}
#[test]
fn test_channel_configuration() {
let channel_config = SystemContent::new()
.with_required_channels(["analysis", "commentary", "final"])
.with_conversation_start_date("2024-01-01")
.with_knowledge_cutoff("2024-06");
if let Some(config) = &channel_config.channel_config {
assert_eq!(config.valid_channels.len(), 3);
assert!(config.channel_required);
assert!(config.valid_channels.contains(&"analysis".to_string()));
}
assert_eq!(channel_config.conversation_start_date, Some("2024-01-01".to_string()));
assert_eq!(channel_config.knowledge_cutoff, Some("2024-06".to_string()));
}
#[test]
fn test_error_handling() {
let invalid_role = Role::try_from("invalid_role");
assert!(invalid_role.is_err());
assert_eq!(Role::try_from("user").unwrap(), Role::User);
assert_eq!(Role::try_from("assistant").unwrap(), Role::Assistant);
assert_eq!(Role::try_from("system").unwrap(), Role::System);
assert_eq!(Role::try_from("developer").unwrap(), Role::Developer);
assert_eq!(Role::try_from("tool").unwrap(), Role::Tool);
assert_eq!(Role::User.as_str(), "user");
assert_eq!(Role::Assistant.as_str(), "assistant");
}