#![allow(unused_imports, dead_code)]
use super::super::*;
use super::*;
#[test]
fn parse_minimax_xml_single_param() {
let input = "<minimax:tool_call>\n\
<invoke name=\"get_weather\">\n\
<parameter name=\"location\">Paris</parameter>\n\
</invoke>\n\
</minimax:tool_call>";
let (content, calls) = parse_tool_calls(input);
assert!(
content.is_none(),
"expected no leading content, got {content:?}"
);
assert_eq!(calls.len(), 1);
assert_eq!(calls[0].function.name, "get_weather");
let args: serde_json::Value = serde_json::from_str(&calls[0].function.arguments).unwrap();
assert_eq!(args["location"], "Paris");
}
#[test]
fn parse_minimax_xml_multiple_params() {
let input = "<minimax:tool_call>\n\
<invoke name=\"search\">\n\
<parameter name=\"query\">rust async</parameter>\n\
<parameter name=\"limit\">10</parameter>\n\
</invoke>\n\
</minimax:tool_call>";
let (_, calls) = parse_tool_calls(input);
assert_eq!(calls.len(), 1);
assert_eq!(calls[0].function.name, "search");
let args: serde_json::Value = serde_json::from_str(&calls[0].function.arguments).unwrap();
assert_eq!(args["query"], "rust async");
assert_eq!(args["limit"], "10");
}
#[test]
fn parse_minimax_xml_with_content_prefix() {
let input = "Let me check. <minimax:tool_call>\n\
<invoke name=\"ls\">\n\
<parameter name=\"path\">/tmp</parameter>\n\
</invoke>\n\
</minimax:tool_call>";
let (content, calls) = parse_tool_calls(input);
assert_eq!(content.as_deref(), Some("Let me check."));
assert_eq!(calls.len(), 1);
assert_eq!(calls[0].function.name, "ls");
}
#[test]
fn minimax_xml_format_tool_calls_roundtrip() {
let parser = MinimaxXmlParser;
let call = IncomingToolCall {
id: None,
function: IncomingFunction {
name: "get_weather".into(),
arguments: "{\"location\":\"Tokyo\"}".into(),
},
};
let formatted = parser.format_tool_calls(&[call]);
let (_, parsed) = parse_tool_calls(&formatted);
assert_eq!(parsed.len(), 1);
assert_eq!(parsed[0].function.name, "get_weather");
let args: serde_json::Value = serde_json::from_str(&parsed[0].function.arguments).unwrap();
assert_eq!(args["location"], "Tokyo");
}
#[test]
fn parse_qwen3_coder_empty_body_then_backfill() {
let input = "<tool_call>\n\
<function=exec>\n\
</function>\n\
</tool_call>";
let (_c, mut calls) = parse_tool_calls(input);
assert_eq!(
calls.len(),
1,
"parser must yield the named call even with no params"
);
assert_eq!(calls[0].function.name, "exec");
assert_eq!(
calls[0].function.arguments, "{}",
"no params → empty JSON object"
);
let tool = ToolDefinition {
tool_type: "function".to_string(),
function: FunctionDefinition {
name: "exec".to_string(),
description: None,
parameters: Some(serde_json::json!({
"type": "object",
"properties": {"command": {"type": "string"}},
"required": ["command"]
})),
},
};
backfill_required_params(&mut calls, std::slice::from_ref(&tool));
let args: serde_json::Value = serde_json::from_str(&calls[0].function.arguments).unwrap();
assert_eq!(
args["command"], "",
"backfill must add the required string key with an empty default"
);
let err = validate_single_tool_call(&calls[0], std::slice::from_ref(&tool))
.expect_err("SHELL_FAMILY rejects `exec` with an empty command");
assert!(
err.contains("non-empty 'command'"),
"rejection must name the offending key so the model can recover; got {err:?}"
);
}
#[test]
fn parse_qwen3_coder_single_param() {
let input = "<tool_call>\n\
<function=get_weather>\n\
<parameter=location>\nParis\n</parameter>\n\
</function>\n\
</tool_call>";
let (c, calls) = parse_tool_calls(input);
assert!(c.is_none());
assert_eq!(calls.len(), 1);
assert_eq!(calls[0].function.name, "get_weather");
let args: serde_json::Value = serde_json::from_str(&calls[0].function.arguments).unwrap();
assert_eq!(args["location"], "Paris");
}