Skip to content

Commit 8db21b8

Browse files
authored
Fix \r escaping in q3coder parser (#3809)
### 🛠 Summary ### 🧪 Checklist - [ ] Unit tests added. - [ ] The documentation updated. - [ ] Change follows security best practices. ``
1 parent 353a9d1 commit 8db21b8

File tree

2 files changed

+21
-4
lines changed

2 files changed

+21
-4
lines changed

src/llm/io_processing/qwen3coder/qwen3coder_tool_parser.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,14 +141,31 @@ static std::string escapeQuotes(const std::string& input) {
141141
}
142142
return output;
143143
}
144-
static std::string escapeNewline(const std::string& input) {
144+
static std::string escapeWithoutQuotes(const std::string& input) {
145145
std::string output;
146146
output.reserve(input.size());
147147
for (char c : input) {
148148
switch (c) {
149149
case '\n':
150150
output += "\\n";
151151
break;
152+
case '\r':
153+
output += "\\r";
154+
break;
155+
// escaping '/' is for now omitted as its creating issues in Continue
156+
157+
/*case '\\':
158+
output += "\\\\";
159+
break;*/
160+
case '\b':
161+
output += "\\b";
162+
break;
163+
case '\f':
164+
output += "\\f";
165+
break;
166+
case '\t':
167+
output += "\\t";
168+
break;
152169
default:
153170
output += c;
154171
}
@@ -250,7 +267,7 @@ bool Qwen3CoderToolParserImpl::parseUntilStateChange(ToolCalls_t& toolCalls) {
250267
SPDLOG_DEBUG("Tool schema not found for tool: {}, leaving parameter: {} as string", this->currentFunction.name, this->currentParameterName);
251268
} else {
252269
// we don't want to escape entry/exit " for string parameters
253-
parameterValue = escapeNewline(setCorrectValueType(parameterValue, this->currentParameterName, paramIt->second));
270+
parameterValue = escapeWithoutQuotes(setCorrectValueType(parameterValue, this->currentParameterName, paramIt->second));
254271
}
255272
auto res = this->currentFunction.parameters.try_emplace(this->currentParameterName, parameterValue);
256273
if (!res.second)

src/test/llm/output_parsers/qwen3coder_output_parser_test.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -652,9 +652,9 @@ if __name__ == "__main__":
652652
addresses["Hodor"] = """The door"""
653653
addresses["Arya"] = "Winterfell"
654654
for name, address in addresses.items():
655-
print(f'{name} lives at {address}')
655+
print(f'\n\t{name} lives at {address}\n\r')
656656
</parameter></function></tool_call>)",
657-
ov::genai::GenerationFinishReason::NONE, R"({"delta":{"tool_calls":[{"index":6,"function":{"arguments":"{\"arg1\": \"if __name__ == \\\"__main__\\\":\\n addresses = {}\\n addresses[\\\"Hodor\\\"] = \\\"\\\"\\\"The door\\\"\\\"\\\"\\n addresses[\\\"Arya\\\"] = \\\"Winterfell\\\"\\n for name, address in addresses.items():\\n print(f'{name} lives at {address}')\"}"}}]}})"}};
657+
ov::genai::GenerationFinishReason::NONE, R"({"delta":{"tool_calls":[{"index":6,"function":{"arguments":"{\"arg1\": \"if __name__ == \\\"__main__\\\":\\n addresses = {}\\n addresses[\\\"Hodor\\\"] = \\\"\\\"\\\"The door\\\"\\\"\\\"\\n addresses[\\\"Arya\\\"] = \\\"Winterfell\\\"\\n for name, address in addresses.items():\\n print(f'\\n\\t{name} lives at {address}\\n\\r')\"}"}}]}})"}};
658658
for (const auto& [chunk, finishReason, expectedDelta] : chunkToDeltaVec) {
659659
i++;
660660
std::optional<rapidjson::Document> doc = outputParser->parseChunk(chunk, true, ov::genai::GenerationFinishReason::NONE);

0 commit comments

Comments
 (0)