chat : pass reasoning_effort to template

* chat: add reasoning_effort to common_chat_templates_inputs

Store OpenAI Chat Completions reasoning_effort and make it
available to jinja templates (with model specific translations
where required).

Assisted-by: llama.cpp:Muse-Glimmer-30B

* server : fixup reading reasoning effort from body

server_chat_convert_responses_to_chatcmpl already handles conversion of
Responses API reasoning.effort to reasoning_effort

* chat : expose reasoning effort

Assisted-by: Claude Opus 5

* chat : add reasoning_effort to generation_params

Assisted-by: Claude Opus 5

* chat : move reasoning_effort next to enable_thinking

Assisted-by: Claude Opus 5

* cont : mirror preserve_reasoning

* cont : pass context through analyze function

---------

Co-authored-by: Alde Rojas <hello@alde.dev>
This commit is contained in:
Andy Williams
2026-08-14 13:23:11 -05:00
committed by GitHub
co-authored by Alde Rojas
parent 9b05354ec6
commit 7e4c0a9688
9 changed files with 89 additions and 11 deletions
+41 -8
View File
@@ -17,7 +17,7 @@ namespace jinja {
using caps_json_fn = std::function<json()>;
using caps_ctx_fn = std::function<void(context &)>;
using caps_analyze_fn = std::function<void(bool, value &, value &, const std::string &)>;
using caps_analyze_fn = std::function<void(context &, bool, value &, value &, const std::string &)>;
void caps_apply_preserve_reasoning(jinja::context & ctx, bool enabled) {
ctx.set_val("preserve_thinking", mk_val<value_bool>(enabled));
@@ -26,6 +26,12 @@ void caps_apply_preserve_reasoning(jinja::context & ctx, bool enabled) {
ctx.set_val("drop_thinking", mk_val<value_bool>(!enabled));
}
void caps_apply_reasoning_effort(jinja::context & ctx, const std::string & effort) {
value var = mk_val<value_string>(effort); // bind to the same value for stats
ctx.set_val("reasoning_effort", var);
ctx.set_val("reasoning_strength", var);
}
static void caps_try_execute(jinja::program & prog,
const caps_json_fn & messages_fn,
const caps_ctx_fn & ctx_fn,
@@ -62,7 +68,7 @@ static void caps_try_execute(jinja::program & prog,
// ignore exceptions during capability analysis
}
analyze_fn(success, messages, tools, result);
analyze_fn(ctx, success, messages, tools, result);
}
// for debugging only
@@ -87,6 +93,7 @@ std::map<std::string, bool> caps::to_map() const {
{"supports_parallel_tool_calls", supports_parallel_tool_calls},
{"supports_system_role", supports_system_role},
{"supports_preserve_reasoning", supports_preserve_reasoning},
{"supports_reasoning_effort", supports_reasoning_effort},
{"supports_object_arguments", supports_object_arguments},
};
}
@@ -124,7 +131,7 @@ caps caps_get(jinja::program & prog) {
},
nullptr, // ctx_fn
nullptr, // tools_fn
[&](bool success, value & messages, value &, const std::string &) {
[&](context &, bool success, value & messages, value &, const std::string &) {
auto & content = messages->at(0)->at("content");
caps_print_stats(content, "messages[0].content");
if (has_op(content, "selectattr") || has_op(content, "array_access")) {
@@ -158,7 +165,7 @@ caps caps_get(jinja::program & prog) {
},
nullptr, // ctx_fn
nullptr, // tools_fn
[&](bool, value & messages, value &, const std::string &) {
[&](context &, bool, value & messages, value &, const std::string &) {
auto & content = messages->at(0)->at("content");
caps_print_stats(content, "messages[0].content");
if (!content->stats.used) {
@@ -234,7 +241,7 @@ caps caps_get(jinja::program & prog) {
},
});
},
[&](bool success, value & messages, value & tools, const std::string &) {
[&](context &, bool success, value & messages, value & tools, const std::string &) {
if (!success) {
return; // Nothing can be inferred
}
@@ -327,7 +334,7 @@ caps caps_get(jinja::program & prog) {
},
});
},
[&](bool success, value & messages, value & tools, const std::string &) {
[&](context &, bool success, value & messages, value & tools, const std::string &) {
if (!success) {
result.supports_tool_calls = false;
result.supports_tools = false;
@@ -429,7 +436,7 @@ caps caps_get(jinja::program & prog) {
},
});
},
[&](bool success, value & messages, value &, const std::string &) {
[&](context &, bool success, value & messages, value &, const std::string &) {
if (!success) {
result.supports_parallel_tool_calls = false;
return;
@@ -486,7 +493,7 @@ caps caps_get(jinja::program & prog) {
caps_apply_preserve_reasoning(ctx, true);
},
nullptr, // tools_fn
[&](bool, value &, value &, const std::string & output) {
[&](context &, bool, value &, value &, const std::string & output) {
// note: we cannot use stats here because the reasoning_content may be used for "if" condition test, but not actually outputted in the final result
if (output.find(reasoning_placeholder) != std::string::npos) {
result.supports_preserve_reasoning = true;
@@ -494,6 +501,32 @@ caps caps_get(jinja::program & prog) {
}
);
JJ_DEBUG("%s\n", ">>> Running capability check: reasoning effort");
// case: reasoning effort level
caps_try_execute(
prog,
[&]() {
// messages
return json::array({
{
{"role", "user"},
{"content", "User message"}
},
});
},
[&](context & ctx) {
ctx.set_val("enable_thinking", mk_val<value_bool>(true));
caps_apply_reasoning_effort(ctx, "low");
},
nullptr, // tools_fn
[&](context & ctx, bool, value &, value &, const std::string &) {
value effort = ctx.get_val("reasoning_effort");
caps_print_stats(effort, "reasoning_effort");
result.supports_reasoning_effort = effort->stats.used;
}
);
JJ_DEBUG("%s\n", result.to_string().c_str());
return result;