sglang_v0.5.2/sglang/sgl-router/tests/tool_parser_mistral.rs

154 lines
5.1 KiB
Rust

//! Mistral Parser Integration Tests
//!
//! Tests for the Mistral parser which handles [TOOL_CALLS] format
use serde_json::json;
use sglang_router_rs::tool_parser::{MistralParser, ToolParser};
#[tokio::test]
async fn test_mistral_single_tool() {
let parser = MistralParser::new();
let input = r#"Let me search for that.
[TOOL_CALLS] [{"name": "search_web", "arguments": {"query": "latest news", "max_results": 5}}]"#;
let result = parser.parse_complete(input).await.unwrap();
assert_eq!(result.len(), 1);
assert_eq!(result[0].function.name, "search_web");
let args: serde_json::Value = serde_json::from_str(&result[0].function.arguments).unwrap();
assert_eq!(args["query"], "latest news");
assert_eq!(args["max_results"], 5);
}
#[tokio::test]
async fn test_mistral_multiple_tools() {
let parser = MistralParser::new();
let input = r#"I'll help you with both tasks.
[TOOL_CALLS] [
{"name": "get_weather", "arguments": {"city": "Tokyo", "units": "celsius"}},
{"name": "search_news", "arguments": {"query": "AI developments", "limit": 10}}
]"#;
let result = parser.parse_complete(input).await.unwrap();
assert_eq!(result.len(), 2);
assert_eq!(result[0].function.name, "get_weather");
let args0: serde_json::Value = serde_json::from_str(&result[0].function.arguments).unwrap();
assert_eq!(args0["city"], "Tokyo");
assert_eq!(result[1].function.name, "search_news");
let args1: serde_json::Value = serde_json::from_str(&result[1].function.arguments).unwrap();
assert_eq!(args1["query"], "AI developments");
}
#[tokio::test]
async fn test_mistral_nested_json() {
let parser = MistralParser::new();
let input = r#"Processing complex data.
[TOOL_CALLS] [{"name": "process_data", "arguments": {"config": {"nested": {"value": [1, 2, 3]}}, "enabled": true}}]"#;
let result = parser.parse_complete(input).await.unwrap();
assert_eq!(result.len(), 1);
let args: serde_json::Value = serde_json::from_str(&result[0].function.arguments).unwrap();
assert_eq!(args["config"]["nested"]["value"], json!([1, 2, 3]));
assert_eq!(args["enabled"], true);
}
#[tokio::test]
async fn test_mistral_with_text_after() {
let parser = MistralParser::new();
let input = r#"[TOOL_CALLS] [{"name": "test", "arguments": {}}]
And here's some text after the tool call that should be ignored."#;
let result = parser.parse_complete(input).await.unwrap();
assert_eq!(result.len(), 1);
assert_eq!(result[0].function.name, "test");
}
#[tokio::test]
async fn test_mistral_empty_arguments() {
let parser = MistralParser::new();
let input = r#"[TOOL_CALLS] [{"name": "ping", "arguments": {}}]"#;
let result = parser.parse_complete(input).await.unwrap();
assert_eq!(result.len(), 1);
assert_eq!(result[0].function.name, "ping");
}
#[tokio::test]
async fn test_mistral_with_brackets_in_strings() {
let parser = MistralParser::new();
let input = r#"[TOOL_CALLS] [{"name": "echo", "arguments": {"text": "Array notation: arr[0] = value[1]"}}]"#;
let result = parser.parse_complete(input).await.unwrap();
assert_eq!(result.len(), 1);
let args: serde_json::Value = serde_json::from_str(&result[0].function.arguments).unwrap();
assert_eq!(args["text"], "Array notation: arr[0] = value[1]");
}
#[tokio::test]
async fn test_mistral_format_detection() {
let parser = MistralParser::new();
assert!(parser.detect_format("[TOOL_CALLS] ["));
assert!(parser.detect_format("Some text [TOOL_CALLS] ["));
assert!(!parser.detect_format("Just plain text"));
assert!(!parser.detect_format("[{\"name\": \"test\"}]")); // JSON array without TOOL_CALLS
}
#[tokio::test]
async fn test_mistral_malformed_json() {
let parser = MistralParser::new();
// Missing closing bracket
let input = r#"[TOOL_CALLS] [{"name": "test", "arguments": {}"#;
if let Ok(result) = parser.parse_complete(input).await {
assert_eq!(result.len(), 0);
}
// Error is also acceptable for malformed input
// Invalid JSON inside
let input = r#"[TOOL_CALLS] [{"name": invalid}]"#;
if let Ok(result) = parser.parse_complete(input).await {
assert_eq!(result.len(), 0);
}
// Error is also acceptable for malformed input
}
#[tokio::test]
async fn test_mistral_real_world_output() {
let parser = MistralParser::new();
// Actual output from Mistral model
let input = r#"I'll search for information about Rust programming and check the weather in San Francisco.
[TOOL_CALLS] [
{
"name": "web_search",
"arguments": {
"query": "Rust programming language features 2024",
"max_results": 3,
"include_snippets": true
}
},
{
"name": "get_weather",
"arguments": {
"location": "San Francisco, CA",
"units": "fahrenheit",
"include_forecast": false
}
}
]
Let me execute these searches for you."#;
let result = parser.parse_complete(input).await.unwrap();
assert_eq!(result.len(), 2);
assert_eq!(result[0].function.name, "web_search");
assert_eq!(result[1].function.name, "get_weather");
}