* chat : fix out_of_range crash in throw path (#20424 regression) #20424 introduced effective_input = generation_prompt + input, but the throw path uses input.substr(result.end) where result.end is a position within effective_input. Every thinking model with a non-empty generation_prompt crashes with std::out_of_range instead of the intended error message. Test crashes on unpatched master, passes with fix: cmake -B build -DLLAMA_BUILD_TESTS=ON -DLLAMA_BUILD_TOOLS=OFF cmake --build build --target test-chat ./build/bin/test-chat * Update test-chat.cpp * Update test-chat.cpp * Update test-chat.cpp --------- Co-authored-by: Piotr Wilkin (ilintar) <piotr.wilkin@syndatis.com>
This commit is contained in:
parent
c1b911654a
commit
c46583b86b
|
|
@ -1774,7 +1774,7 @@ common_chat_msg common_chat_peg_parse(const common_peg_arena & src_pars
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
throw std::runtime_error(std::string("Failed to parse input at pos ") + std::to_string(result.end) + ": " +
|
throw std::runtime_error(std::string("Failed to parse input at pos ") + std::to_string(result.end) + ": " +
|
||||||
input.substr(result.end));
|
effective_input.substr(result.end));
|
||||||
}
|
}
|
||||||
|
|
||||||
common_chat_msg msg;
|
common_chat_msg msg;
|
||||||
|
|
|
||||||
|
|
@ -1954,6 +1954,61 @@ static void test_template_output_peg_parsers(bool detailed_debug) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify the throw path produces a readable error message, not std::out_of_range.
|
||||||
|
// #20424 introduced effective_input = generation_prompt + input, but the throw
|
||||||
|
// uses input.substr(result.end) where result.end is in effective_input space.
|
||||||
|
{
|
||||||
|
auto tmpls = common_chat_templates_ptr(
|
||||||
|
common_chat_templates_init(nullptr, read_file("models/templates/GLM-4.7-Flash.jinja")));
|
||||||
|
|
||||||
|
static common_chat_tool weather_tool{
|
||||||
|
"get_weather", "Get weather",
|
||||||
|
R"({"type":"object","properties":{"city":{"type":"string"}},"required":["city"]})",
|
||||||
|
};
|
||||||
|
|
||||||
|
common_chat_templates_inputs inputs;
|
||||||
|
inputs.tools = { weather_tool };
|
||||||
|
inputs.enable_thinking = true;
|
||||||
|
inputs.reasoning_format = COMMON_REASONING_FORMAT_AUTO;
|
||||||
|
inputs.add_generation_prompt = true;
|
||||||
|
inputs.use_jinja = true;
|
||||||
|
common_chat_msg msg;
|
||||||
|
msg.role = "user";
|
||||||
|
msg.content = "get_weather";
|
||||||
|
inputs.messages = { msg };
|
||||||
|
|
||||||
|
auto params = common_chat_templates_apply(tmpls.get(), inputs);
|
||||||
|
common_peg_arena arena;
|
||||||
|
arena.load(params.parser);
|
||||||
|
common_chat_parser_params pp(params);
|
||||||
|
|
||||||
|
// generation_prompt is non-empty for thinking models, so result.end
|
||||||
|
// will be offset by generation_prompt.size() into effective_input space.
|
||||||
|
assert(!pp.generation_prompt.empty());
|
||||||
|
|
||||||
|
std::string bad_input =
|
||||||
|
"Thinking.\n"
|
||||||
|
"</think>"
|
||||||
|
"<tool_call>get_weather"
|
||||||
|
"<arg_key>city</arg_key><arg_value>Tokyo</arg_value>"
|
||||||
|
"</tool_call>\n";
|
||||||
|
|
||||||
|
bool got_runtime_error = false;
|
||||||
|
bool got_out_of_range = false;
|
||||||
|
std::string error_msg;
|
||||||
|
try {
|
||||||
|
common_chat_peg_parse(arena, bad_input, /*is_partial=*/false, pp);
|
||||||
|
} catch (const std::out_of_range & e) {
|
||||||
|
got_out_of_range = true;
|
||||||
|
error_msg = e.what();
|
||||||
|
} catch (const std::runtime_error & e) {
|
||||||
|
got_runtime_error = true;
|
||||||
|
error_msg = e.what();
|
||||||
|
}
|
||||||
|
GGML_ASSERT(!got_out_of_range && "throw path crashed with out_of_range (input.substr in effective_input space)");
|
||||||
|
GGML_ASSERT(got_runtime_error && "throw path should produce std::runtime_error with parse position");
|
||||||
|
}
|
||||||
|
|
||||||
// Kimi-K2-Thinking tests - custom parser
|
// Kimi-K2-Thinking tests - custom parser
|
||||||
// Unique feature: tool call ID embeds function name as functions.<name>:<counter>
|
// Unique feature: tool call ID embeds function name as functions.<name>:<counter>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue