common : add support for multiple end sequences in the reasoning budget sampler (#25544)

* common : extract trie/ac to a separate file

* common : support multiple token sequences in the reasoning budget sampler

* common/trie : return matched word index

* common/trie : rename "word" to "pattern"

* common/reasoning-budget : expose matched end sequence

* common/sampling : replay end sequence when reasoning budget is done

* cont : update to use multiple end sequences

* cont : clean up
This commit is contained in:
Aldehir Rojas
2026-07-25 11:58:09 +02:00
committed by GitHub
parent d67c0b4107
commit 910196f6b3
14 changed files with 497 additions and 254 deletions
+9 -7
View File
@@ -1144,7 +1144,7 @@ static void test_peg_parser(common_chat_templates * tmpls,
// budget sampler inhibits grammar application while inside thinking blocks —
// triggers inside <think>...</think> are suppressed.
bool use_reasoning_budget_path = false;
if (parser.params_.grammar_lazy && !parser.params_.thinking_end_tag.empty()) {
if (parser.params_.grammar_lazy && !parser.params_.thinking_end_tags.empty()) {
use_reasoning_budget_path = true;
for (const auto & trigger : parser.params_.grammar_triggers) {
if (trigger.type != COMMON_GRAMMAR_TRIGGER_TYPE_WORD) {
@@ -1162,7 +1162,7 @@ static void test_peg_parser(common_chat_templates * tmpls,
// Walk through full_input tracking thinking state; only match triggers
// when outside thinking blocks.
const auto & think_start = parser.params_.thinking_start_tag;
const auto & think_end = parser.params_.thinking_end_tag;
const auto & think_ends = parser.params_.thinking_end_tags;
bool in_thinking = false;
for (size_t i = 0; i < full_input.size(); ++i) {
@@ -1172,12 +1172,14 @@ static void test_peg_parser(common_chat_templates * tmpls,
i += think_start.size() - 1;
continue;
}
if (in_thinking && full_input.compare(i, think_end.size(), think_end) == 0) {
in_thinking = false;
i += think_end.size() - 1;
continue;
}
if (in_thinking) {
for (const auto & think_end : think_ends) {
if (full_input.compare(i, think_end.size(), think_end) == 0) {
in_thinking = false;
i += think_end.size() - 1;
break;
}
}
continue;
}
// Outside thinking — check if any trigger word starts here