Skip to content

Commit 8448520

Browse files
committed
Fix Hermes streaming deltas leaking tool-call wrappers
1 parent d4d9ce4 commit 8448520

File tree

1 file changed

+37
-2
lines changed

1 file changed

+37
-2
lines changed

common/chat.cpp

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <minja/chat-template.hpp>
1010
#include <minja/minja.hpp>
1111

12+
#include <cctype>
1213
#include <cstdio>
1314
#include <exception>
1415
#include <iostream>
@@ -43,6 +44,36 @@ static std::string string_diff(const std::string & last, const std::string & cur
4344
return current.substr(last.size());
4445
}
4546

47+
static std::string string_remove_tool_wrappers_suffix(const std::string & delta) {
48+
size_t cut_pos = std::string::npos;
49+
auto consider = [&](const std::string & token) {
50+
auto pos = delta.find(token);
51+
if (pos != std::string::npos) {
52+
cut_pos = cut_pos == std::string::npos ? pos : std::min(cut_pos, pos);
53+
}
54+
};
55+
56+
consider("<tool_call>");
57+
consider("<tool>");
58+
consider("<tools>");
59+
consider("<response>");
60+
consider("<json>");
61+
consider("<xml>");
62+
consider("<JSON>");
63+
consider("<function=");
64+
consider("<function ");
65+
66+
if (cut_pos == std::string::npos) {
67+
return delta;
68+
}
69+
70+
std::string cleaned = delta.substr(0, cut_pos);
71+
while (!cleaned.empty() && std::isspace(static_cast<unsigned char>(cleaned.back()))) {
72+
cleaned.pop_back();
73+
}
74+
return cleaned;
75+
}
76+
4677
static bool has_content_or_tool_calls(const common_chat_msg & msg) {
4778
return !msg.content.empty() || !msg.tool_calls.empty();
4879
}
@@ -89,8 +120,12 @@ std::vector<common_chat_msg_diff> common_chat_msg_diff::compute_diffs(const comm
89120
diff.reasoning_content_delta = string_diff(previous_msg.reasoning_content, new_msg.reasoning_content);
90121
}
91122
if (previous_msg.content != new_msg.content) {
92-
auto & diff = diffs.emplace_back();
93-
diff.content_delta = string_diff(previous_msg.content, new_msg.content);
123+
auto content_delta = string_diff(previous_msg.content, new_msg.content);
124+
auto cleaned_delta = string_remove_tool_wrappers_suffix(content_delta);
125+
if (!string_strip(cleaned_delta).empty()) {
126+
auto & diff = diffs.emplace_back();
127+
diff.content_delta = cleaned_delta;
128+
}
94129
}
95130

96131
if (new_msg.tool_calls.size() < previous_msg.tool_calls.size()) {

0 commit comments

Comments
 (0)