Allow arbitrary arguments order for Q3C, Q3CN, and Qwen3.5 (#1352)
This should fix the read file at offset/limit issue, where the tool definition has offset before limit, while the model sets limit before offset.
This commit is contained in:
parent
505e2c57f9
commit
ea3e8e30e1
|
|
@ -245,15 +245,28 @@ void build_grammar_xml_tool_call(common_chat_params & data, const json & tools,
|
||||||
|
|
||||||
auto next_arg_with_sep = builder.add_rule(name + "-last-arg-end", form.last_val_end ? gbnf_format_literal(*form.last_val_end) : gbnf_format_literal(form.val_end));
|
auto next_arg_with_sep = builder.add_rule(name + "-last-arg-end", form.last_val_end ? gbnf_format_literal(*form.last_val_end) : gbnf_format_literal(form.val_end));
|
||||||
decltype(next_arg_with_sep) next_arg = "\"\"";
|
decltype(next_arg_with_sep) next_arg = "\"\"";
|
||||||
for (auto i = arg_rules.size() - 1; /* i >= 0 && */ i < arg_rules.size(); --i) {
|
if (form.relax_arg) {
|
||||||
std::string include_this_arg = arg_rules[i].symbol_name + " " + next_arg_with_sep;
|
if (!arg_rules.empty()) {
|
||||||
next_arg = builder.add_rule(name + "-arg-after-" + std::to_string(i), arg_rules[i].is_required ?
|
std::vector<std::string> arg_symbols;
|
||||||
include_this_arg : "( " + include_this_arg + " ) | " + next_arg
|
arg_symbols.reserve(arg_rules.size());
|
||||||
);
|
for (const auto & rule : arg_rules) {
|
||||||
include_this_arg = gbnf_format_literal(form.val_end) + " " + include_this_arg;
|
arg_symbols.push_back(rule.symbol_name);
|
||||||
next_arg_with_sep = builder.add_rule(name + "-arg-after-" + std::to_string(i) + "-with-sep", arg_rules[i].is_required ?
|
}
|
||||||
include_this_arg : "( " + include_this_arg + " ) | " + next_arg_with_sep
|
auto any_arg = builder.add_rule(name + "-any-arg", string_join(arg_symbols, " | "));
|
||||||
);
|
auto any_arg_with_end = builder.add_rule(name + "-any-arg-with-end", any_arg + " " + next_arg_with_sep);
|
||||||
|
next_arg = builder.add_rule(name + "-args-relaxed", "( " + any_arg_with_end + " )*");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (auto i = arg_rules.size() - 1; /* i >= 0 && */ i < arg_rules.size(); --i) {
|
||||||
|
std::string include_this_arg = arg_rules[i].symbol_name + " " + next_arg_with_sep;
|
||||||
|
next_arg = builder.add_rule(name + "-arg-after-" + std::to_string(i), arg_rules[i].is_required ?
|
||||||
|
include_this_arg : "( " + include_this_arg + " ) | " + next_arg
|
||||||
|
);
|
||||||
|
include_this_arg = gbnf_format_literal(form.val_end) + " " + include_this_arg;
|
||||||
|
next_arg_with_sep = builder.add_rule(name + "-arg-after-" + std::to_string(i) + "-with-sep", arg_rules[i].is_required ?
|
||||||
|
include_this_arg : "( " + include_this_arg + " ) | " + next_arg_with_sep
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string quoted_name = name;
|
std::string quoted_name = name;
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,9 @@ struct xml_tool_call_format {
|
||||||
std::optional<std::string> last_tool_end = std::nullopt;
|
std::optional<std::string> last_tool_end = std::nullopt;
|
||||||
bool trim_raw_argval = false;
|
bool trim_raw_argval = false;
|
||||||
bool allow_toolcall_in_think = false;
|
bool allow_toolcall_in_think = false;
|
||||||
|
// Set true to allows function arguments in arbitrary order and without
|
||||||
|
// enforcing required field.
|
||||||
|
bool relax_arg = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// make a GBNF that accept any strings except those containing any of the forbidden strings.
|
// make a GBNF that accept any strings except those containing any of the forbidden strings.
|
||||||
|
|
|
||||||
|
|
@ -1250,16 +1250,19 @@ static common_chat_params common_chat_params_init_qwen3_coder_xml(const common_c
|
||||||
}
|
}
|
||||||
|
|
||||||
// build grammar for tool call
|
// build grammar for tool call
|
||||||
static const xml_tool_call_format form {
|
static const xml_tool_call_format form = ([]() {
|
||||||
/* form.scope_start = */ "",
|
xml_tool_call_format form {};
|
||||||
/* form.tool_start = */ "\n<tool_call>\n<function=",
|
form.scope_start = "";
|
||||||
/* form.tool_sep = */ ">\n",
|
form.tool_start = "\n<tool_call>\n<function=";
|
||||||
/* form.key_start = */ "<parameter=",
|
form.tool_sep = ">\n";
|
||||||
/* form.key_val_sep = */ ">\n",
|
form.key_start = "<parameter=";
|
||||||
/* form.val_end = */ "\n</parameter>\n",
|
form.key_val_sep = ">\n";
|
||||||
/* form.tool_end = */ "</function>\n</tool_call>",
|
form.val_end = "\n</parameter>\n";
|
||||||
/* form.scope_end = */ "",
|
form.tool_end = "</function>\n</tool_call>";
|
||||||
};
|
form.scope_end = "";
|
||||||
|
form.relax_arg = true;
|
||||||
|
return form;
|
||||||
|
})();
|
||||||
build_grammar_xml_tool_call(data, params.tools, form);
|
build_grammar_xml_tool_call(data, params.tools, form);
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue