met 1.0.0-beta-preview

Metrale Engine: pure Rust LLM inference server (HTTP API, scheduler, TUI, CLI).
// SPDX-License-Identifier: MIT OR Apache-2.0

use super::super::*;

const CALL: &str = r#"answer

<|DSML|tool_calls>
<|DSML|invoke name="search">
<|DSML|parameter name="query" string="true">DeepSeek V4</|DSML|parameter>
<|DSML|parameter name="limit" string="false">3</|DSML|parameter>
<|DSML|parameter name="fresh" string="false">true</|DSML|parameter>
</|DSML|invoke>
</|DSML|tool_calls>"#;

#[test]
fn blocking_dsml_parser_preserves_typed_arguments() {
    let (content, calls) = parse_tool_calls(CALL);
    assert_eq!(content.as_deref(), Some("answer"));
    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,
        serde_json::json!({"query": "DeepSeek V4", "limit": 3, "fresh": true})
    );
}

#[test]
fn streaming_dsml_parser_handles_split_special_tokens() {
    let mut detector = StreamingToolDetector::new();
    let mut outputs = Vec::new();
    let chars: Vec<char> = CALL.chars().collect();
    for chunk in chars.chunks(7) {
        outputs.extend(detector.process(&chunk.iter().collect::<String>()));
    }
    outputs.extend(detector.flush());

    let mut content = String::new();
    let mut calls = Vec::new();
    for output in outputs {
        match output {
            DetectorOutput::Content(text) => content.push_str(&text),
            DetectorOutput::ToolCall(call, index) => calls.push((index, call)),
            _ => {}
        }
    }
    assert_eq!(content.trim(), "answer");
    assert_eq!(calls.len(), 1);
    assert_eq!(calls[0].0, 0);
    assert_eq!(calls[0].1.function.name, "search");
}

#[test]
fn deepseek_v4_parser_is_registered() {
    let parser = "deepseek_v4"
        .parse::<ToolCallFormat>()
        .expect("registered DSML parser")
        .into_parser();
    assert_eq!(parser.name(), "deepseek_v4");
    assert!(
        parser
            .system_prompt(&[], &ToolChoice::Mode("auto".into()), &PromptLevers::OFF)
            .is_empty()
    );
}