This commit is contained in:
Aldehir Rojas 2026-03-16 01:58:03 +00:00 committed by GitHub
commit 3f56bf7c67
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 114 additions and 13 deletions

View File

@ -1519,7 +1519,6 @@ static common_chat_params common_chat_templates_apply_jinja(const struct common_
// map developer to system for all models except for GPT-OSS // map developer to system for all models except for GPT-OSS
workaround::map_developer_role_to_system(params.messages); workaround::map_developer_role_to_system(params.messages);
} }
workaround::func_args_not_string(params.messages);
if (!tmpl.original_caps().supports_system_role) { if (!tmpl.original_caps().supports_system_role) {
workaround::system_message_not_supported(params.messages); workaround::system_message_not_supported(params.messages);
@ -1532,6 +1531,10 @@ static common_chat_params common_chat_templates_apply_jinja(const struct common_
workaround::requires_non_null_content(params.messages); workaround::requires_non_null_content(params.messages);
} }
if (tmpl.original_caps().supports_object_arguments) {
workaround::func_args_not_string(params.messages);
}
params.extra_context = common_chat_extra_context(); params.extra_context = common_chat_extra_context();
for (auto el : inputs.chat_template_kwargs) { for (auto el : inputs.chat_template_kwargs) {
params.extra_context[el.first] = json::parse(el.second); params.extra_context[el.first] = json::parse(el.second);

View File

@ -75,6 +75,7 @@ std::map<std::string, bool> caps::to_map() const {
{"supports_parallel_tool_calls", supports_parallel_tool_calls}, {"supports_parallel_tool_calls", supports_parallel_tool_calls},
{"supports_system_role", supports_system_role}, {"supports_system_role", supports_system_role},
{"supports_preserve_reasoning", supports_preserve_reasoning}, {"supports_preserve_reasoning", supports_preserve_reasoning},
{"supports_object_arguments", supports_object_arguments},
}; };
} }
@ -158,9 +159,9 @@ caps caps_get(jinja::program & prog) {
} }
); );
JJ_DEBUG("%s\n", ">>> Running capability check: single tool support"); JJ_DEBUG("%s\n", ">>> Running capability check: single tool with object arguments support");
// case: tools support: single call // case: tools support: single call with object arguments
caps_try_execute( caps_try_execute(
prog, prog,
[&]() { [&]() {
@ -226,9 +227,7 @@ caps caps_get(jinja::program & prog) {
}, },
[&](bool success, value & messages, value & tools) { [&](bool success, value & messages, value & tools) {
if (!success) { if (!success) {
result.supports_tool_calls = false; return; // Nothing can be inferred
result.supports_tools = false;
return;
} }
auto & tool_name = tools->at(0)->at("function")->at("name"); auto & tool_name = tools->at(0)->at("function")->at("name");
@ -242,16 +241,117 @@ caps caps_get(jinja::program & prog) {
caps_print_stats(tool_calls, "messages[1].tool_calls"); caps_print_stats(tool_calls, "messages[1].tool_calls");
if (!tool_calls->stats.used) { if (!tool_calls->stats.used) {
result.supports_tool_calls = false; result.supports_tool_calls = false;
return;
}
auto & tool_arg = tool_calls->at(0)->at("function")->at("arguments")->at("arg");
caps_print_stats(tool_arg, "messages[1].tool_calls[0].function.arguments.arg");
if (tool_arg->stats.used) {
result.supports_object_arguments = true;
} }
} }
); );
if (!result.supports_object_arguments) {
JJ_DEBUG("%s\n", ">>> Running capability check: single tool with string arguments support");
// case: tools support: single call with string arguments
caps_try_execute(
prog,
[&]() {
// messages
return json::array({
{
{"role", "user"},
{"content", "User message"},
},
{
{"role", "assistant"},
{"content", ""}, // Some templates expect content to be empty with tool calls
{"tool_calls", json::array({
{
{"id", "call00001"},
{"type", "function"},
{"function", {
{"name", "tool1"},
{"arguments", R"({"arg": "value"})"}
}}
}
})}
},
{
{"role", "tool"},
{"content", "Tool response"},
{"tool_call_id", "call00001"}
},
{
{"role", "assistant"},
{"content", "The tool response was 'tool response'"}
},
{
{"role", "user"},
{"content", "User message"},
},
});
},
[&]() {
// tools
return json::array({
{
{"name", "tool"},
{"type", "function"},
{"function", {
{"name", "tool1"},
{"description", "Tool description"},
{"parameters", {
{"type", "object"},
{"properties", {
{"arg", {
{"type", "string"},
{"description", "Arg description"},
}},
}},
{"required", json::array({ "arg" })},
}},
}},
},
});
},
[&](bool success, value & messages, value & tools) {
if (!success) {
result.supports_tool_calls = false;
result.supports_tools = false;
return;
}
auto & tool_name = tools->at(0)->at("function")->at("name");
caps_print_stats(tool_name, "tools[0].function.name");
caps_print_stats(tools, "tools");
if (!tool_name->stats.used) {
result.supports_tools = false;
}
auto & tool_calls = messages->at(1)->at("tool_calls");
caps_print_stats(tool_calls, "messages[1].tool_calls");
if (!tool_calls->stats.used) {
result.supports_tool_calls = false;
return;
}
}
);
}
JJ_DEBUG("%s\n", ">>> Running capability check: parallel tool support"); JJ_DEBUG("%s\n", ">>> Running capability check: parallel tool support");
// case: tools support: parallel calls // case: tools support: parallel calls
caps_try_execute( caps_try_execute(
prog, prog,
[&]() { [&]() {
json args = json(R"({"arg": "value"})");
if (result.supports_object_arguments) {
args = json{{"arg", "value"}};
}
// messages // messages
return json::array({ return json::array({
{ {
@ -267,9 +367,7 @@ caps caps_get(jinja::program & prog) {
{"type", "function"}, {"type", "function"},
{"function", { {"function", {
{"name", "tool1"}, {"name", "tool1"},
{"arguments", { {"arguments", args}
{"arg", "value"}
}}
}} }}
}, },
{ {
@ -277,9 +375,7 @@ caps caps_get(jinja::program & prog) {
{"type", "function"}, {"type", "function"},
{"function", { {"function", {
{"name", "tool1"}, {"name", "tool1"},
{"arguments", { {"arguments", args}
{"arg", "value"}
}}
}} }}
} }
})} })}
@ -328,7 +424,7 @@ caps caps_get(jinja::program & prog) {
return; return;
} }
auto & tool_calls = messages->at(1)->at("tool_calls");; auto & tool_calls = messages->at(1)->at("tool_calls");
caps_print_stats(tool_calls, "messages[1].tool_calls"); caps_print_stats(tool_calls, "messages[1].tool_calls");
// check for second tool call usage // check for second tool call usage

View File

@ -18,6 +18,8 @@ struct caps {
bool supports_string_content = true; bool supports_string_content = true;
bool supports_typed_content = false; bool supports_typed_content = false;
bool supports_object_arguments = false;
// for reporting on server // for reporting on server
std::map<std::string, bool> to_map() const; std::map<std::string, bool> to_map() const;