195 lines
6.1 KiB
Rust
195 lines
6.1 KiB
Rust
//! Parser Registry Integration Tests
|
|
//!
|
|
//! Tests for model-to-parser mappings and registry functionality
|
|
|
|
use sglang_router_rs::tool_parser::ParserRegistry;
|
|
|
|
#[tokio::test]
|
|
async fn test_registry_has_all_parsers() {
|
|
let registry = ParserRegistry::new();
|
|
let parsers = registry.list_parsers();
|
|
|
|
assert!(parsers.contains(&"json"));
|
|
assert!(parsers.contains(&"mistral"));
|
|
assert!(parsers.contains(&"qwen"));
|
|
assert!(parsers.contains(&"pythonic"));
|
|
assert!(parsers.contains(&"llama"));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_openai_models_use_json() {
|
|
let registry = ParserRegistry::new();
|
|
|
|
let models = vec!["gpt-4", "gpt-4-turbo", "gpt-3.5-turbo", "gpt-4o"];
|
|
for model in models {
|
|
let parser = registry.get_parser(model).unwrap();
|
|
let test_input = r#"{"name": "test", "arguments": {}}"#;
|
|
let result = parser.parse_complete(test_input).await.unwrap();
|
|
assert_eq!(result.len(), 1);
|
|
assert_eq!(result[0].function.name, "test");
|
|
}
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_anthropic_models_use_json() {
|
|
let registry = ParserRegistry::new();
|
|
|
|
let models = vec!["claude-3-opus", "claude-3-sonnet", "claude-2.1"];
|
|
for model in models {
|
|
let parser = registry.get_parser(model).unwrap();
|
|
let test_input = r#"{"name": "test", "arguments": {}}"#;
|
|
let result = parser.parse_complete(test_input).await.unwrap();
|
|
assert_eq!(result.len(), 1);
|
|
}
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_mistral_models() {
|
|
let registry = ParserRegistry::new();
|
|
|
|
let models = vec!["mistral-large", "mistral-medium", "mixtral-8x7b"];
|
|
for model in models {
|
|
let parser = registry.get_parser(model).unwrap();
|
|
let test_input = r#"[TOOL_CALLS] [{"name": "test", "arguments": {}}]"#;
|
|
let result = parser.parse_complete(test_input).await.unwrap();
|
|
assert_eq!(result.len(), 1);
|
|
assert_eq!(result[0].function.name, "test");
|
|
}
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_qwen_models() {
|
|
let registry = ParserRegistry::new();
|
|
|
|
let models = vec!["qwen2.5-72b", "Qwen2-7B", "qwen-max"];
|
|
for model in models {
|
|
let parser = registry.get_parser(model).unwrap();
|
|
let test_input = r#"<tool_call>
|
|
{"name": "test", "arguments": {}}
|
|
</tool_call>"#;
|
|
let result = parser.parse_complete(test_input).await.unwrap();
|
|
assert_eq!(result.len(), 1);
|
|
assert_eq!(result[0].function.name, "test");
|
|
}
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_llama_model_variants() {
|
|
let registry = ParserRegistry::new();
|
|
|
|
// Llama 4 uses pythonic
|
|
let parser = registry.get_parser("llama-4-70b").unwrap();
|
|
let test_input = r#"[get_weather(city="NYC")]"#;
|
|
let result = parser.parse_complete(test_input).await.unwrap();
|
|
assert_eq!(result.len(), 1);
|
|
assert_eq!(result[0].function.name, "get_weather");
|
|
|
|
// Llama 3.2 uses python_tag
|
|
let parser = registry.get_parser("llama-3.2-8b").unwrap();
|
|
let test_input = r#"<|python_tag|>{"name": "test", "arguments": {}}"#;
|
|
let result = parser.parse_complete(test_input).await.unwrap();
|
|
assert_eq!(result.len(), 1);
|
|
assert_eq!(result[0].function.name, "test");
|
|
|
|
// Other Llama models use JSON
|
|
let parser = registry.get_parser("llama-2-70b").unwrap();
|
|
let test_input = r#"{"name": "test", "arguments": {}}"#;
|
|
let result = parser.parse_complete(test_input).await.unwrap();
|
|
assert_eq!(result.len(), 1);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_deepseek_models() {
|
|
let registry = ParserRegistry::new();
|
|
|
|
// DeepSeek uses pythonic format (simplified, v3 would need custom parser)
|
|
let parser = registry.get_parser("deepseek-coder").unwrap();
|
|
let test_input = r#"[function(arg="value")]"#;
|
|
let result = parser.parse_complete(test_input).await.unwrap();
|
|
assert_eq!(result.len(), 1);
|
|
assert_eq!(result[0].function.name, "function");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_unknown_model_fallback() {
|
|
let registry = ParserRegistry::new();
|
|
|
|
// Unknown models should fall back to JSON parser
|
|
let parser = registry.get_parser("unknown-model-xyz").unwrap();
|
|
let test_input = r#"{"name": "fallback", "arguments": {}}"#;
|
|
let result = parser.parse_complete(test_input).await.unwrap();
|
|
assert_eq!(result.len(), 1);
|
|
assert_eq!(result[0].function.name, "fallback");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_pattern_specificity() {
|
|
let registry = ParserRegistry::new();
|
|
|
|
// Test that more specific patterns take precedence
|
|
// llama-4* should match before llama-*
|
|
let parser = registry.get_parser("llama-4-70b").unwrap();
|
|
assert!(parser.detect_format(r#"[test_function(x=1)]"#)); // Pythonic format
|
|
|
|
let parser = registry.get_parser("llama-3-70b").unwrap();
|
|
assert!(parser.detect_format(r#"{"name": "test", "arguments": {}}"#)); // JSON format
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_real_world_model_outputs() {
|
|
let registry = ParserRegistry::new();
|
|
|
|
// Test with realistic outputs from different models
|
|
let test_cases = vec![
|
|
(
|
|
"gpt-4",
|
|
r#"I'll help you with that.
|
|
|
|
{"name": "search_web", "arguments": {"query": "latest AI news", "max_results": 5}}
|
|
|
|
Let me search for that information."#,
|
|
"search_web",
|
|
),
|
|
(
|
|
"mistral-large",
|
|
r#"Let me search for information about Rust.
|
|
|
|
[TOOL_CALLS] [
|
|
{"name": "search", "arguments": {"query": "Rust programming"}},
|
|
{"name": "get_weather", "arguments": {"city": "San Francisco"}}
|
|
]
|
|
|
|
I've initiated the search."#,
|
|
"search",
|
|
),
|
|
(
|
|
"qwen2.5",
|
|
r#"I'll check the weather for you.
|
|
|
|
<tool_call>
|
|
{
|
|
"name": "get_weather",
|
|
"arguments": {
|
|
"location": "Tokyo",
|
|
"units": "celsius"
|
|
}
|
|
}
|
|
</tool_call>
|
|
|
|
The weather information has been requested."#,
|
|
"get_weather",
|
|
),
|
|
];
|
|
|
|
for (model, output, expected_name) in test_cases {
|
|
let parser = registry.get_parser(model).unwrap();
|
|
let result = parser.parse_complete(output).await.unwrap();
|
|
assert!(!result.is_empty(), "No tools parsed for model {}", model);
|
|
assert_eq!(
|
|
result[0].function.name, expected_name,
|
|
"Wrong function name for model {}",
|
|
model
|
|
);
|
|
}
|
|
}
|