Skip to main content

llama_cpp_bindings/tool_call_template_overrides/
gemma4_call_block.rs

1use llama_cpp_bindings_types::PairedQuoteShape;
2use llama_cpp_bindings_types::ToolCallArgsShape;
3use llama_cpp_bindings_types::ToolCallMarkers;
4use llama_cpp_bindings_types::ToolCallValueQuote;
5
6pub struct Gemma4CallBlockOverride;
7
8impl Gemma4CallBlockOverride {
9    const TEMPLATE_FINGERPRINT: &'static str = "'<|tool_call>call:'";
10
11    #[must_use]
12    pub fn markers() -> ToolCallMarkers {
13        ToolCallMarkers {
14            open: "<|tool_call>call:".to_owned(),
15            close: "}".to_owned(),
16            args_shape: ToolCallArgsShape::PairedQuote(PairedQuoteShape {
17                name_args_separator: "{".to_owned(),
18                value_quote: ToolCallValueQuote {
19                    open: "<|\"|>".to_owned(),
20                    close: "<|\"|>".to_owned(),
21                },
22            }),
23        }
24    }
25
26    #[must_use]
27    pub fn detect(template: &str) -> Option<ToolCallMarkers> {
28        if !template.contains(Self::TEMPLATE_FINGERPRINT) {
29            return None;
30        }
31        Some(Self::markers())
32    }
33}
34
35#[cfg(test)]
36mod tests {
37    use llama_cpp_bindings_types::ToolCallArgsShape;
38
39    use super::Gemma4CallBlockOverride;
40
41    #[test]
42    fn detects_gemma4_template_with_tool_call_call_literal() {
43        use llama_cpp_bindings_types::PairedQuoteShape;
44        use llama_cpp_bindings_types::ToolCallValueQuote;
45
46        let template = "...{{- '<|tool_call>call:' + function['name'] + '{' -}}...";
47        let markers =
48            Gemma4CallBlockOverride::detect(template).expect("Gemma 4 template must be detected");
49
50        assert_eq!(markers.open, "<|tool_call>call:");
51        assert_eq!(markers.close, "}");
52        assert_eq!(
53            markers.args_shape,
54            ToolCallArgsShape::PairedQuote(PairedQuoteShape {
55                name_args_separator: "{".to_owned(),
56                value_quote: ToolCallValueQuote {
57                    open: "<|\"|>".to_owned(),
58                    close: "<|\"|>".to_owned(),
59                },
60            })
61        );
62    }
63
64    #[test]
65    fn returns_none_for_template_without_fingerprint() {
66        assert!(Gemma4CallBlockOverride::detect("just some plain template body").is_none());
67    }
68
69    #[test]
70    fn returns_none_for_empty_template() {
71        assert!(Gemma4CallBlockOverride::detect("").is_none());
72    }
73
74    #[test]
75    fn returns_none_when_fingerprint_substring_appears_without_jinja_apostrophes() {
76        let template = "doc explaining the <|tool_call>call: format in prose, not as a literal";
77        assert!(Gemma4CallBlockOverride::detect(template).is_none());
78    }
79}