Fix incorrect coercion of strings to non-string types during parsing
This commit is contained in:
parent
fa52b43c2a
commit
1bcedc2bbb
|
|
@ -301,6 +301,25 @@ void common_chat_peg_unified_mapper::map(const common_peg_ast_node & node) {
|
|||
} else {
|
||||
buffer_needs_closing_quote = true;
|
||||
}
|
||||
} else if (is_arg_string_value) {
|
||||
// Schema declares this as string type but it parsed as non-string (e.g., number)
|
||||
// Force treatment as string value - add opening quote and escape content
|
||||
if (!current_tool->name.empty()) {
|
||||
if (!needs_closing_quote) {
|
||||
value_to_add = "\"";
|
||||
needs_closing_quote = true;
|
||||
}
|
||||
} else {
|
||||
if (!buffer_needs_closing_quote) {
|
||||
value_to_add = "\"";
|
||||
buffer_needs_closing_quote = true;
|
||||
}
|
||||
}
|
||||
std::string escaped = json(value_content).dump();
|
||||
if (escaped.size() >= 2 && escaped.front() == '"' && escaped.back() == '"') {
|
||||
escaped = escaped.substr(1, escaped.size() - 2);
|
||||
}
|
||||
value_to_add += escaped;
|
||||
} else {
|
||||
// For non-string values (number, bool, null, object, array), add raw value content
|
||||
// Using raw content instead of dump() ensures monotonicity for streaming
|
||||
|
|
|
|||
|
|
@ -321,6 +321,23 @@ static common_chat_tool edit_tool{
|
|||
})",
|
||||
};
|
||||
|
||||
static common_chat_tool magic_tool{
|
||||
/* .name = */ "magic",
|
||||
/* .description = */ "Magic tool that takes a hash",
|
||||
/* .parameters = */ R"({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"ref": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["name", "ref"]
|
||||
})",
|
||||
};
|
||||
|
||||
static std::vector<common_chat_tool> tools{ special_function_tool, special_function_tool_with_optional_param,
|
||||
python_tool, html_tool, todo_list };
|
||||
|
||||
|
|
@ -2079,6 +2096,25 @@ static void test_template_output_peg_parsers(bool detailed_debug) {
|
|||
expect_reasoning("I was thinking").
|
||||
expect_content("Now I'm not.")
|
||||
.run();
|
||||
|
||||
// Test that numeric-looking string values are coerced to strings per the schema
|
||||
tst.test(
|
||||
"Let me call the magic tool\n"
|
||||
"</think>\n"
|
||||
"<tool_call>\n"
|
||||
"<function=magic>\n"
|
||||
"<parameter=name>\nfooBar\n</parameter>\n"
|
||||
"<parameter=ref>\n5123123\n</parameter>\n"
|
||||
"</function>\n"
|
||||
"</tool_call>")
|
||||
.enable_thinking(true)
|
||||
.reasoning_format(COMMON_REASONING_FORMAT_DEEPSEEK)
|
||||
.tools({ magic_tool })
|
||||
.expect_reasoning("Let me call the magic tool")
|
||||
.expect_tool_calls({
|
||||
{ "magic", R"({"name": "fooBar", "ref": "5123123"})", {} },
|
||||
})
|
||||
.run();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue