Support for Codex CLI by skipping unsupported Responses tools (#23041)
Some checks are pending
Python Type-Check / python type-check (push) Waiting to run

* Support for Codex CLI by skipping unsupported Responses tools

* Warn on skipped Responses tools and preserve gpt-oss apply_patch rejection

* Revert gpt-oss apply_patch special handling
This commit is contained in:
Sid Shaytay 2026-05-15 00:03:24 -07:00 committed by GitHub
parent 7155a49771
commit 91e84fed64
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 85 additions and 3 deletions

View file

@ -1664,6 +1664,83 @@ static void test_convert_responses_to_chatcmpl() {
assert_equals(false, result.contains("max_output_tokens"));
assert_equals(100, result.at("max_tokens").get<int>());
}
// Test mixed Responses tools: convert only function tools
{
json input = json::parse(R"({
"input": "Hello",
"model": "test-model",
"tools": [
{
"type": "web_search"
},
{
"type": "function",
"name": "get_weather",
"description": "Get weather for a location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string"
}
},
"required": ["location"]
}
},
{
"type": "image_generation"
},
{
"type": "mcp",
"server_label": "test-server"
},
{
"type": "namespace",
"name": "browser"
}
]
})");
json result = server_chat_convert_responses_to_chatcmpl(input);
assert_equals(true, result.contains("tools"));
assert_equals(true, result.at("tools").is_array());
assert_equals((size_t)1, result.at("tools").size());
const auto & tool = result.at("tools")[0];
assert_equals(std::string("function"), tool.at("type").get<std::string>());
assert_equals(std::string("get_weather"), tool.at("function").at("name").get<std::string>());
assert_equals(true, tool.at("function").at("strict").get<bool>());
}
// Test non-function Responses tools are ignored
{
json input = json::parse(R"({
"input": "Hello",
"model": "test-model",
"tools": [
{
"type": "web_search"
},
{
"type": "image_generation"
},
{
"type": "mcp",
"server_label": "test-server"
},
{
"type": "namespace",
"name": "browser"
}
]
})");
json result = server_chat_convert_responses_to_chatcmpl(input);
assert_equals(false, result.contains("tools"));
}
}
static void test_template_output_peg_parsers(bool detailed_debug) {

View file

@ -257,8 +257,11 @@ json server_chat_convert_responses_to_chatcmpl(const json & response_body) {
for (json resp_tool : response_body.at("tools")) {
json chatcmpl_tool;
if (json_value(resp_tool, "type", std::string()) != "function") {
throw std::invalid_argument("'type' of tool must be 'function'");
const std::string type = json_value(resp_tool, "type", std::string());
if (type != "function") {
// Non-function Responses tools have no Chat Completions equivalent.
SRV_WRN("unsupported Responses tool type '%s' skipped\n", type.c_str());
continue;
}
resp_tool.erase("type");
chatcmpl_tool["type"] = "function";
@ -270,7 +273,9 @@ json server_chat_convert_responses_to_chatcmpl(const json & response_body) {
chatcmpl_tools.push_back(chatcmpl_tool);
}
chatcmpl_body.erase("tools");
chatcmpl_body["tools"] = chatcmpl_tools;
if (!chatcmpl_tools.empty()) {
chatcmpl_body["tools"] = chatcmpl_tools;
}
}
if (response_body.contains("max_output_tokens")) {