]> git.djapps.eu Git - pkg/ggml/sources/llama.cpp/commitdiff
chat : handle tool calls with no required args in TAG_WITH_TAGGED format (#20764)
authorJames O'Leary <redacted>
Thu, 19 Mar 2026 16:53:11 +0000 (09:53 -0700)
committerGitHub <redacted>
Thu, 19 Mar 2026 16:53:11 +0000 (17:53 +0100)
* chat : handle tool calls with no required args in TAG_WITH_TAGGED format

* Update tests/test-chat.cpp [no ci]

Co-authored-by: Aldehir Rojas <redacted>
---------

Co-authored-by: Piotr Wilkin (ilintar) <redacted>
Co-authored-by: Aldehir Rojas <redacted>
common/chat-auto-parser-generator.cpp
tests/test-chat.cpp

index e1105c146ada31691dc4ebfd5e9ec7d195b67f2e..aa03aea5a916d8874bc75f694191cfb7a4f670e9 100644 (file)
@@ -369,7 +369,9 @@ common_peg_parser analyze_tools::build_tool_parser_tag_tagged(parser_build_conte
             func_parser = p.atomic(p.tool_open(function.name_prefix + p.tool_name(p.literal(name)) + function.name_suffix) +
                 call_id_section) + p.space() + args_seq;
             matched_atomic = true;
-        } else if (!arguments.name_prefix.empty() && properties.size() > 0) {
+        } else if (!arguments.name_prefix.empty() && !required_parsers.empty()) {
+            // Only peek for an arg tag when there are required args that must follow.
+            // When all args are optional, the model may emit no arg tags at all (#20650).
             func_parser = p.atomic(p.tool_open(function.name_prefix + p.tool_name(p.literal(name)) + function.name_suffix) +
                 call_id_section + p.space() + p.peek(p.literal(arguments.name_prefix))) + args_seq;
             matched_atomic = true;
index 727cb3574856995a59be1df5d7fc269a3841b798..58fef8e99c7a49232283215053ffe97abada2fa8 100644 (file)
@@ -1934,6 +1934,24 @@ static void test_template_output_peg_parsers(bool detailed_debug) {
                 { "special_function_with_opt", R"({"arg1": 1, "arg2": 2})", {} },
             })
             .run();
+
+        // #20650: tool with no required args, model emits <tool_call>name</tool_call> with no arg tags.
+        {
+            static common_chat_tool no_args_tool{
+                "read_file_diff_md", "Reads a file diff",
+                R"({"type":"object","properties":{"review_id":{"type":"string"},"file_id":{"type":"string"}}})",
+            };
+            tst.test(
+                   "Let me read the diff content."
+                   "</think>"
+                   "<tool_call>read_file_diff_md</tool_call>")
+                .enable_thinking(true)
+                .reasoning_format(COMMON_REASONING_FORMAT_DEEPSEEK)
+                .tools({ no_args_tool })
+                .expect_reasoning("Let me read the diff content.")
+                .expect_tool_calls({{ "read_file_diff_md", "{}", {} }})
+                .run();
+        }
     }
 
     // Kimi-K2-Thinking tests - custom parser