Skip to content
35 changes: 35 additions & 0 deletions tests/test-chat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1974,6 +1974,41 @@ static void test_convert_responses_to_chatcmpl() {

assert_equals(false, result.contains("tools"));
}

// Test JSON schema conversion
{
json input = json::parse(R"({
"input": "Hello",
"model": "test-model",
"text": {
"format": {
"type": "json_schema",
"name": "TestOutput",
"schema": {
"type": "object",
"properties": {
"message": {"type": "string"}
},
"required": ["message"],
"additionalProperties": false
},
"strict": true
}
}
})");

json result = server_chat_convert_responses_to_chatcmpl(input);

assert_equals(false, result.contains("text"));
assert_equals(true, result.contains("response_format"));
const auto & response_format = result.at("response_format");
assert_equals(std::string("json_schema"), response_format.at("type").get<std::string>());
const auto & json_schema = response_format.at("json_schema");
assert_equals(std::string("TestOutput"), json_schema.at("name").get<std::string>());
assert_equals(true, json_schema.at("strict").get<bool>());
assert_equals(std::string("object"), json_schema.at("schema").at("type").get<std::string>());
assert_equals(false, json_schema.contains("type"));
}
}

// Shared LFM2 parser cases - all variants use one output format and parser
Expand Down
28 changes: 28 additions & 0 deletions tools/server/server-chat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,34 @@ json server_chat_convert_responses_to_chatcmpl(const json & response_body) {
chatcmpl_body.erase("reasoning");
}

if (response_body.contains("text")) {
const json & text = response_body.at("text");
if (!text.is_object()) {
throw std::invalid_argument("'text' must be an object");
}

chatcmpl_body.erase("text");
if (text.contains("format")) {
const json & format = text.at("format");
if (!format.is_object()) {
throw std::invalid_argument("'text.format' must be an object");
}

const std::string type = json_value(format, "type", std::string());
if (type == "json_schema") {
chatcmpl_body["response_format"] = {
{"type", "json_schema"},
{"json_schema", format},
};
chatcmpl_body["response_format"]["json_schema"].erase("type");
} else if (type == "json_object" || type == "text") {
chatcmpl_body["response_format"] = format;
} else if (!type.empty()) {
throw std::invalid_argument("'text.format.type' must be one of 'text', 'json_object', or 'json_schema'");
}
}
}

return chatcmpl_body;
}

Expand Down
Loading