From 070b68df378e38c6d6044ff44df5c6e7eb9d9260 Mon Sep 17 00:00:00 2001 From: Alde Rojas Date: Fri, 20 Feb 2026 18:11:32 -0600 Subject: [PATCH 1/4] server : merge contiguous input items into a single assistant message --- tools/server/server-common.cpp | 88 +++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 39 deletions(-) diff --git a/tools/server/server-common.cpp b/tools/server/server-common.cpp index d717fb6698f..fda1fe3958d 100644 --- a/tools/server/server-common.cpp +++ b/tools/server/server-common.cpp @@ -1104,6 +1104,11 @@ json convert_responses_to_chatcmpl(const json & response_body) { return j.contains(key) && j.at(key).is_string(); }; + // Return true if we should merge with the last message + auto should_merge = [&chatcmpl_messages]() -> bool { + return !chatcmpl_messages.empty() && chatcmpl_messages.back().value("role", "") == "assistant"; + }; + for (json item : input_value) { if (exists_and_is_string(item, "content")) { // #responses_create-input-input_item_list-input_message-content-text_input @@ -1210,10 +1215,15 @@ json convert_responses_to_chatcmpl(const json & response_body) { }); } - item.erase("status"); - item.erase("type"); - item["content"] = chatcmpl_content; - chatcmpl_messages.push_back(item); + if (should_merge()) { + auto & prev_msg = chatcmpl_messages.back(); + prev_msg["content"] = chatcmpl_content; + } else { + item.erase("status"); + item.erase("type"); + item["content"] = chatcmpl_content; + chatcmpl_messages.push_back(item); + } } else if (exists_and_is_string(item, "arguments") && exists_and_is_string(item, "call_id") && exists_and_is_string(item, "name") && @@ -1221,24 +1231,34 @@ json convert_responses_to_chatcmpl(const json & response_body) { item.at("type") == "function_call" ) { // #responses_create-input-input_item_list-item-function_tool_call - json msg = json { - {"role", "assistant"}, - {"tool_calls", json::array({ json { - {"function", json { - {"arguments", item.at("arguments")}, - {"name", item.at("name")}, - }}, - {"id", item.at("call_id")}, - {"type", "function"}, - }})}, + json tool_call = { + {"function", json { + {"arguments", item.at("arguments")}, + {"name", item.at("name")}, + }}, + {"id", item.at("call_id")}, + {"type", "function"}, }; - if (!chatcmpl_messages.empty() && chatcmpl_messages.back().contains("reasoning_content")) { - // Move reasoning content from dummy message to tool call message - msg["reasoning_content"] = chatcmpl_messages.back().at("reasoning_content"); - chatcmpl_messages.pop_back(); + if (should_merge()) { + auto & prev_msg = chatcmpl_messages.back(); + if (!exists_and_is_array(prev_msg, "tool_calls")) { + prev_msg["tool_calls"] = json::array(); + } + prev_msg["tool_calls"].push_back(tool_call); + } else { + chatcmpl_messages.push_back(json { + {"role", "assistant"}, + {"tool_calls", json { + {"function", json { + {"arguments", item.at("arguments")}, + {"name", item.at("name")}, + }}, + {"id", item.at("call_id")}, + {"type", "function"}, + }} + }); } - chatcmpl_messages.push_back(msg); } else if (exists_and_is_string(item, "call_id") && (exists_and_is_string(item, "output") || exists_and_is_array(item, "output")) && exists_and_is_string(item, "type") && @@ -1282,12 +1302,16 @@ json convert_responses_to_chatcmpl(const json & response_body) { throw std::invalid_argument("item['content']['text'] is not a string"); } - // Pack reasoning content in dummy message - chatcmpl_messages.push_back(json { - {"role", "assistant"}, - {"content", json::array()}, - {"reasoning_content", item.at("content")[0].at("text")}, - }); + if (should_merge()) { + auto & prev_msg = chatcmpl_messages.back(); + prev_msg["reasoning_content"] = item.at("content")[0].at("text"); + } else { + chatcmpl_messages.push_back(json { + {"role", "assistant"}, + {"content", json::array()}, + {"reasoning_content", item.at("content")[0].at("text")}, + }); + } } else { throw std::invalid_argument("Cannot determine type of 'item'"); } @@ -1296,20 +1320,6 @@ json convert_responses_to_chatcmpl(const json & response_body) { throw std::invalid_argument("'input' must be a string or array of objects"); } - // Remove unused dummy message which contains - // reasoning content not followed by tool call - chatcmpl_messages.erase(std::remove_if( - chatcmpl_messages.begin(), - chatcmpl_messages.end(), - [](const json & x){ return x.contains("role") && - x.at("role") == "assistant" && - x.contains("content") && - x.at("content") == json::array() && - x.contains("reasoning_content"); - }), - chatcmpl_messages.end() - ); - chatcmpl_body["messages"] = chatcmpl_messages; if (response_body.contains("tools")) { From 38dc926b6314cf10955b52b172ea895faf94f4f5 Mon Sep 17 00:00:00 2001 From: Alde Rojas Date: Fri, 20 Feb 2026 18:39:16 -0600 Subject: [PATCH 2/4] cont : simplify tool call msg --- tools/server/server-common.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/tools/server/server-common.cpp b/tools/server/server-common.cpp index fda1fe3958d..521a555bfbb 100644 --- a/tools/server/server-common.cpp +++ b/tools/server/server-common.cpp @@ -1249,14 +1249,7 @@ json convert_responses_to_chatcmpl(const json & response_body) { } else { chatcmpl_messages.push_back(json { {"role", "assistant"}, - {"tool_calls", json { - {"function", json { - {"arguments", item.at("arguments")}, - {"name", item.at("name")}, - }}, - {"id", item.at("call_id")}, - {"type", "function"}, - }} + {"tool_calls", json::array({tool_call})} }); } } else if (exists_and_is_string(item, "call_id") && From 304a0e9b4562355ff2b57fb8b4c4175d735fd2cf Mon Sep 17 00:00:00 2001 From: Alde Rojas Date: Fri, 20 Feb 2026 19:44:11 -0600 Subject: [PATCH 3/4] cont : reduce and combine content --- tools/server/server-common.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/tools/server/server-common.cpp b/tools/server/server-common.cpp index 521a555bfbb..68738db2e40 100644 --- a/tools/server/server-common.cpp +++ b/tools/server/server-common.cpp @@ -1104,12 +1104,9 @@ json convert_responses_to_chatcmpl(const json & response_body) { return j.contains(key) && j.at(key).is_string(); }; - // Return true if we should merge with the last message - auto should_merge = [&chatcmpl_messages]() -> bool { - return !chatcmpl_messages.empty() && chatcmpl_messages.back().value("role", "") == "assistant"; - }; - for (json item : input_value) { + bool merge_prev = !chatcmpl_messages.empty() && chatcmpl_messages.back().value("role", "") == "assistant"; + if (exists_and_is_string(item, "content")) { // #responses_create-input-input_item_list-input_message-content-text_input // Only "Input message" contains item["content"]::string @@ -1215,9 +1212,13 @@ json convert_responses_to_chatcmpl(const json & response_body) { }); } - if (should_merge()) { + if (merge_prev) { auto & prev_msg = chatcmpl_messages.back(); - prev_msg["content"] = chatcmpl_content; + if (!exists_and_is_array(prev_msg, "content")) { + prev_msg["content"] = json::array(); + } + auto & prev_content = prev_msg["content"]; + prev_content.insert(prev_content.end(), chatcmpl_content); } else { item.erase("status"); item.erase("type"); @@ -1240,7 +1241,7 @@ json convert_responses_to_chatcmpl(const json & response_body) { {"type", "function"}, }; - if (should_merge()) { + if (merge_prev) { auto & prev_msg = chatcmpl_messages.back(); if (!exists_and_is_array(prev_msg, "tool_calls")) { prev_msg["tool_calls"] = json::array(); @@ -1295,7 +1296,7 @@ json convert_responses_to_chatcmpl(const json & response_body) { throw std::invalid_argument("item['content']['text'] is not a string"); } - if (should_merge()) { + if (merge_prev) { auto & prev_msg = chatcmpl_messages.back(); prev_msg["reasoning_content"] = item.at("content")[0].at("text"); } else { From 3c4ff183a48f278e315a5f0dfbab601651d8f77c Mon Sep 17 00:00:00 2001 From: Alde Rojas Date: Fri, 20 Feb 2026 20:58:15 -0600 Subject: [PATCH 4/4] cont : fix merging content items --- tools/server/server-common.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/server/server-common.cpp b/tools/server/server-common.cpp index 68738db2e40..88b6e77d82b 100644 --- a/tools/server/server-common.cpp +++ b/tools/server/server-common.cpp @@ -1195,7 +1195,7 @@ json convert_responses_to_chatcmpl(const json & response_body) { item.at("type") == "message" ) { // #responses_create-input-input_item_list-item-output_message - std::vector chatcmpl_content; + auto chatcmpl_content = json::array(); for (const auto & output_text : item.at("content")) { const std::string type = json_value(output_text, "type", std::string()); @@ -1218,7 +1218,7 @@ json convert_responses_to_chatcmpl(const json & response_body) { prev_msg["content"] = json::array(); } auto & prev_content = prev_msg["content"]; - prev_content.insert(prev_content.end(), chatcmpl_content); + prev_content.insert(prev_content.end(), chatcmpl_content.begin(), chatcmpl_content.end()); } else { item.erase("status"); item.erase("type");