From 437dfff70b0ac0ce6142c3bcf9981211d0951b29 Mon Sep 17 00:00:00 2001 From: BenjaminBruenau Date: Fri, 19 Sep 2025 14:09:28 +0000 Subject: [PATCH 1/2] server: fix SSE and OpenAI compatibility for error messages when streaming --- tools/server/server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/server/server.cpp b/tools/server/server.cpp index c0ffe17692ddf..a4cd7debcc690 100644 --- a/tools/server/server.cpp +++ b/tools/server/server.cpp @@ -4689,7 +4689,7 @@ int main(int argc, char ** argv) { return server_sent_event(sink, "data", res_json); } }, [&](const json & error_data) { - server_sent_event(sink, "error", error_data); + server_sent_event(sink, "data", json{{"error", error_data}}); }, [&sink]() { // note: do not use req.is_connection_closed here because req is already destroyed return !sink.is_writable(); From a79382359582153335c175a73412e3d8095a7ebc Mon Sep 17 00:00:00 2001 From: BenjaminBruenau Date: Fri, 19 Sep 2025 16:47:40 +0000 Subject: [PATCH 2/2] server: remove obsolete event parameter and use required data fieldname instead --- tools/server/server.cpp | 6 +++--- tools/server/utils.hpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/server/server.cpp b/tools/server/server.cpp index a4cd7debcc690..d6072e5ece266 100644 --- a/tools/server/server.cpp +++ b/tools/server/server.cpp @@ -4679,17 +4679,17 @@ int main(int argc, char ** argv) { json res_json = result->to_json(); if (res_json.is_array()) { for (const auto & res : res_json) { - if (!server_sent_event(sink, "data", res)) { + if (!server_sent_event(sink, res)) { // sending failed (HTTP connection closed), cancel the generation return false; } } return true; } else { - return server_sent_event(sink, "data", res_json); + return server_sent_event(sink, res_json); } }, [&](const json & error_data) { - server_sent_event(sink, "data", json{{"error", error_data}}); + server_sent_event(sink, json{{"error", error_data}}); }, [&sink]() { // note: do not use req.is_connection_closed here because req is already destroyed return !sink.is_writable(); diff --git a/tools/server/utils.hpp b/tools/server/utils.hpp index 85fe25e0085fb..64d702930ce96 100644 --- a/tools/server/utils.hpp +++ b/tools/server/utils.hpp @@ -459,9 +459,9 @@ static std::string tokens_to_output_formatted_string(const llama_context * ctx, return out; } -static bool server_sent_event(httplib::DataSink & sink, const char * event, const json & data) { +static bool server_sent_event(httplib::DataSink & sink, const json & data) { const std::string str = - std::string(event) + ": " + + "data: " + data.dump(-1, ' ', false, json::error_handler_t::replace) + "\n\n"; // required by RFC 8895 - A message is terminated by a blank line (two line terminators in a row).