Commit 4e5116f47 for llama.cpp
commit 4e5116f47619dac4180c3007ef02a383f347554c
Author: eddiechen <Echen1246@gmail.com>
Date: Sun Nov 15 02:09:46 2026 -0800
server : fix output_config.effort being dropped in /v1/messages (#32321)
diff --git a/tools/server/server-chat.cpp b/tools/server/server-chat.cpp
index 7b080d17a..4e4622baf 100644
--- a/tools/server/server-chat.cpp
+++ b/tools/server/server-chat.cpp
@@ -659,6 +659,15 @@ json server_chat_convert_anthropic_to_oai(const json & body) {
}
}
+ // Handle Anthropic-specific output_config param
+ if (body.contains("output_config")) {
+ json output_config = json_value(body, "output_config", json::object());
+ std::string effort = json_value(output_config, "effort", std::string());
+ if (!effort.empty()) {
+ oai_body["reasoning_effort"] = effort;
+ }
+ }
+
// Handle Anthropic-specific metadata param
if (body.contains("metadata")) {
json metadata = json_value(body, "metadata", json::object());
diff --git a/tools/server/tests/unit/test_compat_anthropic.py b/tools/server/tests/unit/test_compat_anthropic.py
index 220417745..2346de02e 100644
--- a/tools/server/tests/unit/test_compat_anthropic.py
+++ b/tools/server/tests/unit/test_compat_anthropic.py
@@ -851,6 +851,32 @@ def test_anthropic_thinking():
assert res.body["type"] == "message"
+@pytest.mark.parametrize("effort", ["low", "high"])
+def test_anthropic_output_config_effort(effort):
+ """output_config.effort must reach the chat template, same as chat_template_kwargs.reasoning_effort"""
+ global server
+ server.jinja = True
+ server.chat_template_file = '../../../models/templates/openai-gpt-oss-120b.jinja'
+ server.start()
+
+ def count_tokens(extra):
+ res = server.make_request("POST", "/v1/messages/count_tokens", data={
+ "model": "test",
+ "messages": [{"role": "user", "content": "Hello"}],
+ **extra,
+ })
+ assert res.status_code == 200, res.body
+ return res.body["input_tokens"]
+
+ n_default = count_tokens({})
+ n_kwargs = count_tokens({"chat_template_kwargs": {"reasoning_effort": effort}})
+ n_output_config = count_tokens({"thinking": {"type": "adaptive"}, "output_config": {"effort": effort}})
+
+ # the template renders "Reasoning: medium" by default, so the effort must change the prompt
+ assert n_kwargs != n_default
+ assert n_output_config == n_kwargs
+
+
def test_anthropic_metadata():
"""Test metadata parameter"""
server.start()