feat(server): strip executed Bailing blocks from reasoning_content
vLLM Ling3 parity: reasoning ends where the executed call begins, so downstream panels never render converted calls as thinking text. Only complete blocks are removed; truncated fragments and narration survive. Separate commit on top of the rescue so each reverts independently.
This commit is contained in:
parent
86bc7658c5
commit
253cf76f59
|
|
@ -24,7 +24,9 @@ using json = nlohmann::ordered_json;
|
|||
// The PEG layer consumes the thinking region as reasoning_content before the
|
||||
// tool stage runs, so the call is lost: the response carries empty content,
|
||||
// no structured tool calls, and the call text parked in reasoning_content.
|
||||
// This parser recovers well-formed blocks from that region. It mirrors the
|
||||
// Reference semantic is vLLM's Ling3 parser (vllm/parser/ling3.py): <tool_call>
|
||||
// acts as an implicit reasoning terminator, thinking ends where the call
|
||||
// begins. This parser recovers well-formed blocks from that region. It mirrors the
|
||||
// behavior validated client-side (Hermes reasoning_tool_rescue.py, 330
|
||||
// rescued turns over a 2h probe with no loop breakage):
|
||||
// - only complete open-to-close blocks; truncated fragments are skipped,
|
||||
|
|
@ -119,4 +121,24 @@ static bool has_complete_block(const std::string & text) {
|
|||
}
|
||||
}
|
||||
|
||||
// Remove executed (complete) blocks from reasoning text. Mirrors the vLLM
|
||||
// Ling3 terminator semantic: reasoning ends where the call begins, so panels
|
||||
// downstream never display converted calls. Only complete blocks are removed;
|
||||
// truncated fragments are left untouched. Leading/trailing whitespace left by
|
||||
// removal is trimmed; internal formatting is preserved.
|
||||
static std::string remove_executed_blocks(const std::string & text) {
|
||||
try {
|
||||
std::regex block_regex(R"(<tool_call>[\s\S]*?</tool_call>)");
|
||||
std::string cleaned = std::regex_replace(text, block_regex, "");
|
||||
const char * ws = " \t\n\r";
|
||||
cleaned.erase(0, cleaned.find_first_not_of(ws));
|
||||
if (!cleaned.empty()) {
|
||||
cleaned.erase(cleaned.find_last_not_of(ws) + 1);
|
||||
}
|
||||
return cleaned;
|
||||
} catch (const std::exception &) {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace bailing
|
||||
|
|
|
|||
|
|
@ -749,6 +749,11 @@ const common_chat_msg& server_slot::update_chat_msg(bool is_partial, std::vector
|
|||
if (!rescued.empty() && !new_msg.tool_calls.empty()) {
|
||||
LLAMA_LOG_WARN("Bailing rescue: promoted %d tool call(s) trapped in reasoning_content\n",
|
||||
(int) new_msg.tool_calls.size());
|
||||
// Terminator display semantic (vLLM Ling3 parity): reasoning ends
|
||||
// where the executed call begins. Strip converted blocks so
|
||||
// downstream panels never render them as thinking text.
|
||||
new_msg.reasoning_content =
|
||||
bailing::remove_executed_blocks(new_msg.reasoning_content);
|
||||
}
|
||||
}
|
||||
//new_msg.ensure_tool_call_ids_set(generated_tool_call_ids, gen_tool_call_id);
|
||||
|
|
|
|||
|
|
@ -46,6 +46,16 @@ int main() {
|
|||
CHECK(bailing::parse_tool_calls("Just thinking aloud here.").empty());
|
||||
CHECK(bailing::parse_tool_calls("").empty());
|
||||
|
||||
// 7. Strip removes only executed (complete) blocks, preserves narration.
|
||||
std::string mixed = "Let me search for that now.\n" + trapped + "\nDone thinking.";
|
||||
std::string stripped = bailing::remove_executed_blocks(mixed);
|
||||
CHECK(stripped.find("<tool_call>") == std::string::npos);
|
||||
CHECK(stripped.find("Let me search for that now.") != std::string::npos);
|
||||
CHECK(stripped.find("Done thinking.") != std::string::npos);
|
||||
// Truncated fragments survive the strip.
|
||||
std::string partial = "thinking <tool_call>web_search\n<arg_key>q";
|
||||
CHECK(bailing::remove_executed_blocks(partial) == partial);
|
||||
|
||||
if (failures == 0) std::cout << "ALL BAILING PARSER CHECKS PASSED\n";
|
||||
return failures;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue