Skip to main content

llama_cpp_bindings/tool_call_template_overrides/
detect.rs

1use llama_cpp_bindings_types::ToolCallMarkers;
2
3use crate::tool_call_template_overrides::gemma4_call_block::Gemma4CallBlockOverride;
4use crate::tool_call_template_overrides::glm47_key_value_tags::Glm47KeyValueTagsOverride;
5use crate::tool_call_template_overrides::mistral3_arrow_args::Mistral3ArrowArgsOverride;
6use crate::tool_call_template_overrides::qwen_xml_tags::QwenXmlTagsOverride;
7use crate::tool_call_template_overrides::qwen3_json_inside_tool_call::Qwen3JsonInsideToolCallOverride;
8
9#[must_use]
10pub fn detect(template: &str) -> Option<ToolCallMarkers> {
11    let detectors: [fn(&str) -> Option<ToolCallMarkers>; 5] = [
12        Gemma4CallBlockOverride::detect,
13        Glm47KeyValueTagsOverride::detect,
14        Mistral3ArrowArgsOverride::detect,
15        Qwen3JsonInsideToolCallOverride::detect,
16        QwenXmlTagsOverride::detect,
17    ];
18    detectors
19        .into_iter()
20        .find_map(|detector| detector(template))
21}
22
23#[cfg(test)]
24mod tests {
25    use llama_cpp_bindings_types::ToolCallArgsShape;
26
27    use super::detect;
28
29    #[test]
30    fn dispatches_to_gemma4_override() {
31        let template = "{{- '<|tool_call>call:' + function['name'] + '{' -}}";
32        let markers = detect(template).expect("must dispatch to Gemma 4");
33
34        assert_eq!(markers.open, "<|tool_call>call:");
35        assert!(matches!(
36            markers.args_shape,
37            ToolCallArgsShape::PairedQuote(_)
38        ));
39    }
40
41    #[test]
42    fn dispatches_to_mistral3_override() {
43        let template = "{{- name + '[ARGS]' + arguments }}";
44        let markers = detect(template).expect("must dispatch to Mistral 3");
45
46        assert_eq!(markers.open, "[TOOL_CALLS]");
47        assert!(matches!(
48            markers.args_shape,
49            ToolCallArgsShape::BracketedJson(_)
50        ));
51    }
52
53    #[test]
54    fn dispatches_to_qwen_xml_tags_override() {
55        let template = "{{- '<tool_call>\\n<function=' + tool_call.name + '>\\n' }}";
56        let markers = detect(template).expect("must dispatch to Qwen XML tags");
57
58        assert_eq!(markers.open, "<tool_call>");
59        assert!(matches!(markers.args_shape, ToolCallArgsShape::XmlTags(_)));
60    }
61
62    #[test]
63    fn returns_none_when_no_override_matches() {
64        assert!(detect("plain unrelated template").is_none());
65    }
66}