Skip to content

Commit d4d9ce4

Browse files
committed
trim wrapper preludes before Hermes tool calls
1 parent c048d4f commit d4d9ce4

File tree

2 files changed

+35
-9
lines changed

2 files changed

+35
-9
lines changed

common/chat.cpp

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2154,24 +2154,34 @@ static void common_chat_parse_hermes_2_pro(common_chat_msg_parser & builder) {
21542154
}
21552155
} else {
21562156
auto prelude = res->prelude;
2157-
bool prelude_wrappers_only = true;
2158-
auto trimmed_prelude = string_strip(prelude);
2159-
while (!trimmed_prelude.empty()) {
2157+
size_t suffix_to_remove = 0;
2158+
size_t cursor = prelude.size();
2159+
while (cursor > 0) {
2160+
size_t ws = cursor;
2161+
while (ws > 0 && std::isspace(static_cast<unsigned char>(prelude[ws - 1]))) {
2162+
--ws;
2163+
}
2164+
size_t trimmed_end = ws;
21602165
bool matched_wrapper = false;
21612166
for (const auto & tag : wrapper_open_tags) {
2162-
if (string_starts_with(trimmed_prelude, tag)) {
2163-
trimmed_prelude = string_strip(trimmed_prelude.substr(tag.size()));
2167+
const size_t tag_len = tag.size();
2168+
if (trimmed_end >= tag_len && prelude.compare(trimmed_end - tag_len, tag_len, tag) == 0) {
21642169
matched_wrapper = true;
2170+
suffix_to_remove += cursor - (trimmed_end - tag_len);
2171+
cursor = trimmed_end - tag_len;
21652172
break;
21662173
}
21672174
}
21682175
if (!matched_wrapper) {
2169-
prelude_wrappers_only = false;
21702176
break;
21712177
}
21722178
}
2173-
if (!prelude.empty() && prelude_wrappers_only) {
2174-
builder.remove_content_suffix(prelude.size());
2179+
if (suffix_to_remove > 0) {
2180+
while (cursor > 0 && std::isspace(static_cast<unsigned char>(prelude[cursor - 1]))) {
2181+
--cursor;
2182+
++suffix_to_remove;
2183+
}
2184+
builder.remove_content_suffix(suffix_to_remove);
21752185
}
21762186

21772187
auto function_name = builder.str(res->groups[4]);
@@ -2181,7 +2191,13 @@ static void common_chat_parse_hermes_2_pro(common_chat_msg_parser & builder) {
21812191
GGML_ASSERT(!function_name.empty());
21822192

21832193
close_tag = "</function>";
2184-
const bool had_block_start = res->prelude.find("```") != std::string::npos;
2194+
bool had_block_start = false;
2195+
{
2196+
const auto backtick_pos = res->prelude.rfind("```");
2197+
if (backtick_pos != std::string::npos) {
2198+
had_block_start = true;
2199+
}
2200+
}
21852201

21862202
if (auto arguments = builder.try_consume_json_with_dumped_args({{}})) {
21872203
if (!builder.add_tool_call(function_name, "", arguments->value) || arguments->is_partial) {

tests/test-chat.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,16 @@ static void test_template_output_parsers() {
826826
"</tool_call>",
827827
/* is_partial= */ false,
828828
{COMMON_CHAT_FORMAT_HERMES_2_PRO}));
829+
assert_msg_equals(message_assist_call_content,
830+
common_chat_parse(
831+
"Hello, world!\nWhat's up?\n"
832+
"<tool_call>\n"
833+
"<function=special_function>\n"
834+
"{\"arg1\": 1}\n"
835+
"</function>\n"
836+
"</tool_call>\n",
837+
/* is_partial= */ false,
838+
{COMMON_CHAT_FORMAT_HERMES_2_PRO}));
829839
assert_msg_equals(
830840
message_assist_call,
831841
common_chat_parse(

0 commit comments

Comments
 (0)