Commit 6f1e65437 for llama.cpp
commit 6f1e6543704bc5b080c7a98e7b6f707b31f6ed51
Author: Tom Vaucourt <34662901+T0mSIlver@users.noreply.github.com>
Date: Wed Nov 4 12:34:58 2026 -0800
server : realtime: send an error event instead of crashing on exceptions (#31632)
* server : realtime: send an error event instead of crashing on exceptions
* server : route websocket handlers through ex_wrapper, remove the realtime test
* server : realtime: keep the previous tools when the chat template rejects new ones
* server : realtime: reject tool schemas the grammar cannot convert, drop ws_ex_wrapper
* server : realtime: clarify the tool schema check comment
diff --git a/tools/server/server-realtime.cpp b/tools/server/server-realtime.cpp
index 76faaba3c..e4ce8deb1 100644
--- a/tools/server/server-realtime.cpp
+++ b/tools/server/server-realtime.cpp
@@ -7,6 +7,7 @@
#include "base64.hpp"
#include "chat.h"
#include "common.h"
+#include "json-schema-to-grammar.h"
#include "mtmd.h"
#include "mtmd-helper.h"
@@ -75,7 +76,12 @@ bool parse_max_output_tokens(const json & j, int32_t & n) {
// realtime tools have the format of the Responses API
bool parse_tools(const json & j, std::vector<common_chat_tool> & tools, std::string & err) {
try {
- tools = common_chat_tools_parse_oaicompat(server_chat_convert_responses_tools(j));
+ auto parsed = common_chat_tools_parse_oaicompat(server_chat_convert_responses_tools(j));
+ // reject the schemas that would fail later, when the chat template builds the tool call grammar
+ for (const auto & tool : parsed) {
+ json_schema_to_grammar(json::parse(tool.parameters));
+ }
+ tools = std::move(parsed);
} catch (const std::exception & e) {
err = std::string("tools: ") + e.what();
return false;
@@ -855,7 +861,11 @@ struct realtime_conversation {
std::thread reader([this]() {
std::string msg;
while (conn.read(msg) != 0) {
- handle(msg);
+ try {
+ handle(msg);
+ } catch (const std::exception & e) {
+ send_error(e.what(), "server_error");
+ }
}
closed = true;
conn.close();
@@ -871,7 +881,12 @@ struct realtime_conversation {
break;
}
if (auto * res = dynamic_cast<server_task_result_realtime *>(result.get())) {
- on_result(*res);
+ try {
+ on_result(*res);
+ } catch (const std::exception & e) {
+ send_error(e.what(), "server_error");
+ break;
+ }
}
}