From 0e37c9d6ed077825378e2491635515c9e3bca91b Mon Sep 17 00:00:00 2001 From: thiswillbeyourgithub <26625900+thiswillbeyourgithub@users.noreply.github.com> Date: Mon, 25 May 2026 13:19:06 +0200 Subject: [PATCH 1/5] server: align --reasoning-format default with the docs The `common_params` default was `COMMON_REASONING_FORMAT_DEEPSEEK` while the CLI help text, README, and the enum's own "in most cases, use AUTO" comment all said the default was `auto`. Switch the default to `AUTO` so the docs match the behavior, and list `auto` explicitly in the option enumeration in both the CLI help and the server README (it was a valid input but missing from the listed values). --- common/arg.cpp | 1 + common/common.h | 2 +- tools/server/README.md | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/common/arg.cpp b/common/arg.cpp index 1ffaf704858d..b15cbbf12149 100644 --- a/common/arg.cpp +++ b/common/arg.cpp @@ -3156,6 +3156,7 @@ common_params_context common_params_parser_init(common_params & params, llama_ex {"--reasoning-format"}, "FORMAT", "controls whether thought tags are allowed and/or extracted from the response, and in which format they're returned; one of:\n" "- none: leaves thoughts unparsed in `message.content`\n" + "- auto: same behavior as `deepseek`, recommended default\n" "- deepseek: puts thoughts in `message.reasoning_content`\n" "- deepseek-legacy: keeps `` tags in `message.content` while also populating `message.reasoning_content`\n" "(default: auto)", diff --git a/common/common.h b/common/common.h index 13f387271d81..f8b5926d81e3 100644 --- a/common/common.h +++ b/common/common.h @@ -608,7 +608,7 @@ struct common_params { bool use_jinja = true; // NOLINT bool enable_chat_template = true; bool force_pure_content_parser = false; - common_reasoning_format reasoning_format = COMMON_REASONING_FORMAT_DEEPSEEK; + common_reasoning_format reasoning_format = COMMON_REASONING_FORMAT_AUTO; int enable_reasoning = -1; // -1 = auto, 0 = disable, 1 = enable bool prefill_assistant = true; // if true, any trailing assistant message will be prefilled into the response int sleep_idle_seconds = -1; // if >0, server will sleep after this many seconds of idle time diff --git a/tools/server/README.md b/tools/server/README.md index 3e14f5e6a207..e3e9b3badcc4 100644 --- a/tools/server/README.md +++ b/tools/server/README.md @@ -220,7 +220,7 @@ For the full list of features, please refer to [server's changelog](https://gith | `--models-max N` | for router server, maximum number of models to load simultaneously (default: 4, 0 = unlimited)
(env: LLAMA_ARG_MODELS_MAX) | | `--models-autoload, --no-models-autoload` | for router server, whether to automatically load models (default: enabled)
(env: LLAMA_ARG_MODELS_AUTOLOAD) | | `--jinja, --no-jinja` | whether to use jinja template engine for chat (default: enabled)
(env: LLAMA_ARG_JINJA) | -| `--reasoning-format FORMAT` | controls whether thought tags are allowed and/or extracted from the response, and in which format they're returned; one of:
- none: leaves thoughts unparsed in `message.content`
- deepseek: puts thoughts in `message.reasoning_content`
- deepseek-legacy: keeps `` tags in `message.content` while also populating `message.reasoning_content`
(default: auto)
(env: LLAMA_ARG_THINK) | +| `--reasoning-format FORMAT` | controls whether thought tags are allowed and/or extracted from the response, and in which format they're returned; one of:
- none: leaves thoughts unparsed in `message.content`
- auto: same behavior as `deepseek`, recommended default
- deepseek: puts thoughts in `message.reasoning_content`
- deepseek-legacy: keeps `` tags in `message.content` while also populating `message.reasoning_content`
(default: auto)
(env: LLAMA_ARG_THINK) | | `-rea, --reasoning [on\|off\|auto]` | Use reasoning/thinking in the chat ('on', 'off', or 'auto', default: 'auto' (detect from template))
(env: LLAMA_ARG_REASONING) | | `--reasoning-budget N` | token budget for thinking: -1 for unrestricted, 0 for immediate end, N>0 for token budget (default: -1)
(env: LLAMA_ARG_THINK_BUDGET) | | `--reasoning-budget-message MESSAGE` | message injected before the end-of-thinking tag when reasoning budget is exhausted (default: none)
(env: LLAMA_ARG_THINK_BUDGET_MESSAGE) | From 882e1917614ece2613995d5d37e5c6edbf0a7d16 Mon Sep 17 00:00:00 2001 From: thiswillbeyourgithub <26625900+thiswillbeyourgithub@users.noreply.github.com> Date: Mon, 25 May 2026 13:29:25 +0200 Subject: [PATCH 2/5] server: enforce --reasoning-budget as a hard ceiling on the chat endpoint The chat endpoint previously ignored `thinking_budget_tokens` in the request body whenever `--reasoning-budget` had been set, and accepted it without any cap when the CLI was at the default. Both behaviors are wrong: an admin needs the CLI flag to act as an upper bound that clients cannot escape (so `--reasoning-budget 0` reliably forbids thinking), and a client should still be able to lower the budget for an individual request. Treat the CLI value as a permission ceiling: the body field may lower it but never raise it, with -1 meaning unrestricted on both sides. Document the behavior in both the CLI flag entry and the chat-completions body field, and point users at the raw `/completion` field names since that endpoint has no Jinja template to introspect for thinking tags. --- tools/server/README.md | 4 +++- tools/server/server-common.cpp | 13 ++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/tools/server/README.md b/tools/server/README.md index e3e9b3badcc4..dd36a73ba794 100644 --- a/tools/server/README.md +++ b/tools/server/README.md @@ -222,7 +222,7 @@ For the full list of features, please refer to [server's changelog](https://gith | `--jinja, --no-jinja` | whether to use jinja template engine for chat (default: enabled)
(env: LLAMA_ARG_JINJA) | | `--reasoning-format FORMAT` | controls whether thought tags are allowed and/or extracted from the response, and in which format they're returned; one of:
- none: leaves thoughts unparsed in `message.content`
- auto: same behavior as `deepseek`, recommended default
- deepseek: puts thoughts in `message.reasoning_content`
- deepseek-legacy: keeps `` tags in `message.content` while also populating `message.reasoning_content`
(default: auto)
(env: LLAMA_ARG_THINK) | | `-rea, --reasoning [on\|off\|auto]` | Use reasoning/thinking in the chat ('on', 'off', or 'auto', default: 'auto' (detect from template))
(env: LLAMA_ARG_REASONING) | -| `--reasoning-budget N` | token budget for thinking: -1 for unrestricted, 0 for immediate end, N>0 for token budget (default: -1)
(env: LLAMA_ARG_THINK_BUDGET) | +| `--reasoning-budget N` | token budget for thinking: -1 for unrestricted, 0 for immediate end, N>0 for token budget (default: -1)
this value is **always respected** as a hard ceiling: clients may lower it per request via the `thinking_budget_tokens` body field on `/v1/chat/completions`, but they can never raise it past the cap set here
(env: LLAMA_ARG_THINK_BUDGET) | | `--reasoning-budget-message MESSAGE` | message injected before the end-of-thinking tag when reasoning budget is exhausted (default: none)
(env: LLAMA_ARG_THINK_BUDGET_MESSAGE) | | `--chat-template JINJA_TEMPLATE` | set custom jinja chat template (default: template taken from model's metadata)
if suffix/prefix are specified, template will be disabled
only commonly used templates are accepted (unless --jinja is set before this flag):
list of built-in templates:
bailing, bailing-think, bailing2, chatglm3, chatglm4, chatml, command-r, deepseek, deepseek-ocr, deepseek2, deepseek3, exaone-moe, exaone3, exaone4, falcon3, gemma, gigachat, glmedge, gpt-oss, granite, granite-4.0, granite-4.1, grok-2, hunyuan-dense, hunyuan-moe, hunyuan-vl, kimi-k2, llama2, llama2-sys, llama2-sys-bos, llama2-sys-strip, llama3, llama4, megrez, minicpm, mistral-v1, mistral-v3, mistral-v3-tekken, mistral-v7, mistral-v7-tekken, monarch, openchat, orion, pangu-embedded, phi3, phi4, rwkv-world, seed_oss, smolvlm, solar-open, vicuna, vicuna-orca, yandex, zephyr
(env: LLAMA_ARG_CHAT_TEMPLATE) | | `--chat-template-file JINJA_TEMPLATE_FILE` | set custom jinja chat template file (default: template taken from model's metadata)
if suffix/prefix are specified, template will be disabled
only commonly used templates are accepted (unless --jinja is set before this flag):
list of built-in templates:
bailing, bailing-think, bailing2, chatglm3, chatglm4, chatml, command-r, deepseek, deepseek-ocr, deepseek2, deepseek3, exaone-moe, exaone3, exaone4, falcon3, gemma, gigachat, glmedge, gpt-oss, granite, granite-4.0, granite-4.1, grok-2, hunyuan-dense, hunyuan-moe, hunyuan-vl, kimi-k2, llama2, llama2-sys, llama2-sys-bos, llama2-sys-strip, llama3, llama4, megrez, minicpm, mistral-v1, mistral-v3, mistral-v3-tekken, mistral-v7, mistral-v7-tekken, monarch, openchat, orion, pangu-embedded, phi3, phi4, rwkv-world, seed_oss, smolvlm, solar-open, vicuna, vicuna-orca, yandex, zephyr
(env: LLAMA_ARG_CHAT_TEMPLATE_FILE) | @@ -1246,6 +1246,8 @@ The `response_format` parameter supports both plain JSON output (e.g. `{"type": `reasoning_control`: Arms realtime reasoning control for this completion so it can be ended early via `/v1/chat/completions/control`. Defaults to `false`. +`thinking_budget_tokens`: Per-request tweak of the thinking budget. `-1` for unrestricted, `0` for immediate end, `N>0` for a token budget. The server-side `--reasoning-budget` flag is **always respected** as a hard ceiling and this field can only lower the budget below that cap, never raise it. A server started with `--reasoning-budget 0` forbids thinking regardless of what any client sends; a server started with `--reasoning-budget 100` lets a client request 10 (honored) or 200 (clamped back to 100). Only applies when the chat template exposes start/end-of-thinking tags; otherwise the field is silently ignored. The raw `/completion` endpoint accepts the equivalent field as `reasoning_budget_tokens` (with explicit `reasoning_budget_start_tag` / `reasoning_budget_end_tag` strings) since it has no Jinja template to introspect. + `generation_prompt`: The generation prompt that was prefilled in by the template. Prepended to model output before parsing. `parse_tool_calls`: Whether to parse the generated tool call. diff --git a/tools/server/server-common.cpp b/tools/server/server-common.cpp index 4c3f16a0a3d2..9bc3657d0fc0 100644 --- a/tools/server/server-common.cpp +++ b/tools/server/server-common.cpp @@ -1120,11 +1120,18 @@ json oaicompat_chat_params_parse( }); } - // Reasoning budget: pass parameters through to sampling layer + // Reasoning budget: pass parameters through to sampling layer. + // The CLI flag (--reasoning-budget) acts as a hard ceiling enforced by + // the server admin. The request body may lower the budget but cannot + // raise it past the cap, so `--reasoning-budget 0` reliably forbids + // thinking regardless of what the client asks for. -1 means unrestricted. { int reasoning_budget = opt.reasoning_budget; - if (reasoning_budget == -1 && body.contains("thinking_budget_tokens")) { - reasoning_budget = json_value(body, "thinking_budget_tokens", -1); + if (body.contains("thinking_budget_tokens")) { + int requested = json_value(body, "thinking_budget_tokens", -1); + if (requested >= 0 && (reasoning_budget < 0 || requested < reasoning_budget)) { + reasoning_budget = requested; + } } if (!chat_params.thinking_end_tag.empty()) { From 5e393ffaa8d0f4575d6fe166fe89d8660262144c Mon Sep 17 00:00:00 2001 From: thiswillbeyourgithub <26625900+thiswillbeyourgithub@users.noreply.github.com> Date: Mon, 25 May 2026 14:16:36 +0200 Subject: [PATCH 3/5] server: allow per-request thinking_budget_message when admin didn't set one The budget exhaustion message is a quality knob (it primes the model with a graceful "wrap it up" phrase before the end-of-thinking tag, leading to better final answers than an abrupt cut) rather than a policy lever, so the ceiling rule used for the numeric budget doesn't translate. Use a simpler "admin-wins-when-set" rule instead: if `--reasoning-budget-message` was supplied at startup, that value is always respected; otherwise the chat endpoint accepts `thinking_budget_message` from the request body and uses it. Document the rule in the CLI flag entry and the body-field paragraph. --- tools/server/README.md | 4 +++- tools/server/server-common.cpp | 16 ++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/tools/server/README.md b/tools/server/README.md index dd36a73ba794..8e39a41e263f 100644 --- a/tools/server/README.md +++ b/tools/server/README.md @@ -223,7 +223,7 @@ For the full list of features, please refer to [server's changelog](https://gith | `--reasoning-format FORMAT` | controls whether thought tags are allowed and/or extracted from the response, and in which format they're returned; one of:
- none: leaves thoughts unparsed in `message.content`
- auto: same behavior as `deepseek`, recommended default
- deepseek: puts thoughts in `message.reasoning_content`
- deepseek-legacy: keeps `` tags in `message.content` while also populating `message.reasoning_content`
(default: auto)
(env: LLAMA_ARG_THINK) | | `-rea, --reasoning [on\|off\|auto]` | Use reasoning/thinking in the chat ('on', 'off', or 'auto', default: 'auto' (detect from template))
(env: LLAMA_ARG_REASONING) | | `--reasoning-budget N` | token budget for thinking: -1 for unrestricted, 0 for immediate end, N>0 for token budget (default: -1)
this value is **always respected** as a hard ceiling: clients may lower it per request via the `thinking_budget_tokens` body field on `/v1/chat/completions`, but they can never raise it past the cap set here
(env: LLAMA_ARG_THINK_BUDGET) | -| `--reasoning-budget-message MESSAGE` | message injected before the end-of-thinking tag when reasoning budget is exhausted (default: none)
(env: LLAMA_ARG_THINK_BUDGET_MESSAGE) | +| `--reasoning-budget-message MESSAGE` | message injected before the end-of-thinking tag when reasoning budget is exhausted (default: none)
when set, this value is **always respected** and cannot be overridden per request; when left unset, clients may supply their own via the `thinking_budget_message` body field on `/v1/chat/completions`
(env: LLAMA_ARG_THINK_BUDGET_MESSAGE) | | `--chat-template JINJA_TEMPLATE` | set custom jinja chat template (default: template taken from model's metadata)
if suffix/prefix are specified, template will be disabled
only commonly used templates are accepted (unless --jinja is set before this flag):
list of built-in templates:
bailing, bailing-think, bailing2, chatglm3, chatglm4, chatml, command-r, deepseek, deepseek-ocr, deepseek2, deepseek3, exaone-moe, exaone3, exaone4, falcon3, gemma, gigachat, glmedge, gpt-oss, granite, granite-4.0, granite-4.1, grok-2, hunyuan-dense, hunyuan-moe, hunyuan-vl, kimi-k2, llama2, llama2-sys, llama2-sys-bos, llama2-sys-strip, llama3, llama4, megrez, minicpm, mistral-v1, mistral-v3, mistral-v3-tekken, mistral-v7, mistral-v7-tekken, monarch, openchat, orion, pangu-embedded, phi3, phi4, rwkv-world, seed_oss, smolvlm, solar-open, vicuna, vicuna-orca, yandex, zephyr
(env: LLAMA_ARG_CHAT_TEMPLATE) | | `--chat-template-file JINJA_TEMPLATE_FILE` | set custom jinja chat template file (default: template taken from model's metadata)
if suffix/prefix are specified, template will be disabled
only commonly used templates are accepted (unless --jinja is set before this flag):
list of built-in templates:
bailing, bailing-think, bailing2, chatglm3, chatglm4, chatml, command-r, deepseek, deepseek-ocr, deepseek2, deepseek3, exaone-moe, exaone3, exaone4, falcon3, gemma, gigachat, glmedge, gpt-oss, granite, granite-4.0, granite-4.1, grok-2, hunyuan-dense, hunyuan-moe, hunyuan-vl, kimi-k2, llama2, llama2-sys, llama2-sys-bos, llama2-sys-strip, llama3, llama4, megrez, minicpm, mistral-v1, mistral-v3, mistral-v3-tekken, mistral-v7, mistral-v7-tekken, monarch, openchat, orion, pangu-embedded, phi3, phi4, rwkv-world, seed_oss, smolvlm, solar-open, vicuna, vicuna-orca, yandex, zephyr
(env: LLAMA_ARG_CHAT_TEMPLATE_FILE) | | `--skip-chat-parsing, --no-skip-chat-parsing` | force a pure content parser, even if a Jinja template is specified; model will output everything in the content section, including any reasoning and/or tool calls (default: disabled)
(env: LLAMA_ARG_SKIP_CHAT_PARSING) | @@ -1248,6 +1248,8 @@ The `response_format` parameter supports both plain JSON output (e.g. `{"type": `thinking_budget_tokens`: Per-request tweak of the thinking budget. `-1` for unrestricted, `0` for immediate end, `N>0` for a token budget. The server-side `--reasoning-budget` flag is **always respected** as a hard ceiling and this field can only lower the budget below that cap, never raise it. A server started with `--reasoning-budget 0` forbids thinking regardless of what any client sends; a server started with `--reasoning-budget 100` lets a client request 10 (honored) or 200 (clamped back to 100). Only applies when the chat template exposes start/end-of-thinking tags; otherwise the field is silently ignored. The raw `/completion` endpoint accepts the equivalent field as `reasoning_budget_tokens` (with explicit `reasoning_budget_start_tag` / `reasoning_budget_end_tag` strings) since it has no Jinja template to introspect. +`thinking_budget_message`: Per-request text spliced before the end-of-thinking tag when the budget is exhausted, used as a graceful "wrap it up" phrase that primes the model for its final answer (e.g., `"\nOk, I'll answer now.\n"`). Only honored when the server was started **without** `--reasoning-budget-message`; if the admin set that flag, their value is **always respected** and the body field is silently ignored. Like `thinking_budget_tokens`, this only applies when the chat template exposes thinking tags, and only fires when the budget actually runs out, not on natural end-of-thinking. + `generation_prompt`: The generation prompt that was prefilled in by the template. Prepended to model output before parsing. `parse_tool_calls`: Whether to parse the generated tool call. diff --git a/tools/server/server-common.cpp b/tools/server/server-common.cpp index 9bc3657d0fc0..7b5a6d512607 100644 --- a/tools/server/server-common.cpp +++ b/tools/server/server-common.cpp @@ -1121,10 +1121,13 @@ json oaicompat_chat_params_parse( } // Reasoning budget: pass parameters through to sampling layer. - // The CLI flag (--reasoning-budget) acts as a hard ceiling enforced by + // The CLI flag (--reasoning-budget) is the hard ceiling chosed by // the server admin. The request body may lower the budget but cannot - // raise it past the cap, so `--reasoning-budget 0` reliably forbids - // thinking regardless of what the client asks for. -1 means unrestricted. + // raise it past the cap. + // The exhaustion message follows a different rule: it's a quality knob, + // not a policy lever, so the admin's choice still wins when set, but if + // the server was started without --reasoning-budget-message the client + // may supply its own via `thinking_budget_message`. { int reasoning_budget = opt.reasoning_budget; if (body.contains("thinking_budget_tokens")) { @@ -1134,11 +1137,16 @@ json oaicompat_chat_params_parse( } } + std::string reasoning_budget_message = opt.reasoning_budget_message; + if (reasoning_budget_message.empty() && body.contains("thinking_budget_message")) { + reasoning_budget_message = json_value(body, "thinking_budget_message", std::string()); + } + if (!chat_params.thinking_end_tag.empty()) { llama_params["reasoning_budget_tokens"] = reasoning_budget; llama_params["reasoning_budget_start_tag"] = chat_params.thinking_start_tag; llama_params["reasoning_budget_end_tag"] = chat_params.thinking_end_tag; - llama_params["reasoning_budget_message"] = opt.reasoning_budget_message; + llama_params["reasoning_budget_message"] = reasoning_budget_message; llama_params["reasoning_control"] = json_value(body, "reasoning_control", false); } } From 5e80b0370582807e202aeac840df45de00fb8b73 Mon Sep 17 00:00:00 2001 From: thiswillbeyourgithub <26625900+thiswillbeyourgithub@users.noreply.github.com> Date: Tue, 26 May 2026 15:30:45 +0200 Subject: [PATCH 4/5] server: revert --reasoning-format default change, just fix the help text Per code review feedback, keep COMMON_REASONING_FORMAT_DEEPSEEK as the default and instead align the CLI help to say `(default: deepseek)`. Also revert all edits inside the auto-generated `<\!-- HELP_START --> ... <\!-- HELP_END -->` block in tools/server/README.md, which is produced by llama-gen-docs and must not be hand-edited; only the hand-written API-parameters prose outside that block stays. --- common/arg.cpp | 2 +- common/common.h | 2 +- tools/server/README.md | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/common/arg.cpp b/common/arg.cpp index b15cbbf12149..3c2a05138077 100644 --- a/common/arg.cpp +++ b/common/arg.cpp @@ -3159,7 +3159,7 @@ common_params_context common_params_parser_init(common_params & params, llama_ex "- auto: same behavior as `deepseek`, recommended default\n" "- deepseek: puts thoughts in `message.reasoning_content`\n" "- deepseek-legacy: keeps `` tags in `message.content` while also populating `message.reasoning_content`\n" - "(default: auto)", + "(default: deepseek)", [](common_params & params, const std::string & value) { params.reasoning_format = common_reasoning_format_from_name(value); } diff --git a/common/common.h b/common/common.h index f8b5926d81e3..13f387271d81 100644 --- a/common/common.h +++ b/common/common.h @@ -608,7 +608,7 @@ struct common_params { bool use_jinja = true; // NOLINT bool enable_chat_template = true; bool force_pure_content_parser = false; - common_reasoning_format reasoning_format = COMMON_REASONING_FORMAT_AUTO; + common_reasoning_format reasoning_format = COMMON_REASONING_FORMAT_DEEPSEEK; int enable_reasoning = -1; // -1 = auto, 0 = disable, 1 = enable bool prefill_assistant = true; // if true, any trailing assistant message will be prefilled into the response int sleep_idle_seconds = -1; // if >0, server will sleep after this many seconds of idle time diff --git a/tools/server/README.md b/tools/server/README.md index 8e39a41e263f..5f1c02135a18 100644 --- a/tools/server/README.md +++ b/tools/server/README.md @@ -220,10 +220,10 @@ For the full list of features, please refer to [server's changelog](https://gith | `--models-max N` | for router server, maximum number of models to load simultaneously (default: 4, 0 = unlimited)
(env: LLAMA_ARG_MODELS_MAX) | | `--models-autoload, --no-models-autoload` | for router server, whether to automatically load models (default: enabled)
(env: LLAMA_ARG_MODELS_AUTOLOAD) | | `--jinja, --no-jinja` | whether to use jinja template engine for chat (default: enabled)
(env: LLAMA_ARG_JINJA) | -| `--reasoning-format FORMAT` | controls whether thought tags are allowed and/or extracted from the response, and in which format they're returned; one of:
- none: leaves thoughts unparsed in `message.content`
- auto: same behavior as `deepseek`, recommended default
- deepseek: puts thoughts in `message.reasoning_content`
- deepseek-legacy: keeps `` tags in `message.content` while also populating `message.reasoning_content`
(default: auto)
(env: LLAMA_ARG_THINK) | +| `--reasoning-format FORMAT` | controls whether thought tags are allowed and/or extracted from the response, and in which format they're returned; one of:
- none: leaves thoughts unparsed in `message.content`
- deepseek: puts thoughts in `message.reasoning_content`
- deepseek-legacy: keeps `` tags in `message.content` while also populating `message.reasoning_content`
(default: auto)
(env: LLAMA_ARG_THINK) | | `-rea, --reasoning [on\|off\|auto]` | Use reasoning/thinking in the chat ('on', 'off', or 'auto', default: 'auto' (detect from template))
(env: LLAMA_ARG_REASONING) | -| `--reasoning-budget N` | token budget for thinking: -1 for unrestricted, 0 for immediate end, N>0 for token budget (default: -1)
this value is **always respected** as a hard ceiling: clients may lower it per request via the `thinking_budget_tokens` body field on `/v1/chat/completions`, but they can never raise it past the cap set here
(env: LLAMA_ARG_THINK_BUDGET) | -| `--reasoning-budget-message MESSAGE` | message injected before the end-of-thinking tag when reasoning budget is exhausted (default: none)
when set, this value is **always respected** and cannot be overridden per request; when left unset, clients may supply their own via the `thinking_budget_message` body field on `/v1/chat/completions`
(env: LLAMA_ARG_THINK_BUDGET_MESSAGE) | +| `--reasoning-budget N` | token budget for thinking: -1 for unrestricted, 0 for immediate end, N>0 for token budget (default: -1)
(env: LLAMA_ARG_THINK_BUDGET) | +| `--reasoning-budget-message MESSAGE` | message injected before the end-of-thinking tag when reasoning budget is exhausted (default: none)
(env: LLAMA_ARG_THINK_BUDGET_MESSAGE) | | `--chat-template JINJA_TEMPLATE` | set custom jinja chat template (default: template taken from model's metadata)
if suffix/prefix are specified, template will be disabled
only commonly used templates are accepted (unless --jinja is set before this flag):
list of built-in templates:
bailing, bailing-think, bailing2, chatglm3, chatglm4, chatml, command-r, deepseek, deepseek-ocr, deepseek2, deepseek3, exaone-moe, exaone3, exaone4, falcon3, gemma, gigachat, glmedge, gpt-oss, granite, granite-4.0, granite-4.1, grok-2, hunyuan-dense, hunyuan-moe, hunyuan-vl, kimi-k2, llama2, llama2-sys, llama2-sys-bos, llama2-sys-strip, llama3, llama4, megrez, minicpm, mistral-v1, mistral-v3, mistral-v3-tekken, mistral-v7, mistral-v7-tekken, monarch, openchat, orion, pangu-embedded, phi3, phi4, rwkv-world, seed_oss, smolvlm, solar-open, vicuna, vicuna-orca, yandex, zephyr
(env: LLAMA_ARG_CHAT_TEMPLATE) | | `--chat-template-file JINJA_TEMPLATE_FILE` | set custom jinja chat template file (default: template taken from model's metadata)
if suffix/prefix are specified, template will be disabled
only commonly used templates are accepted (unless --jinja is set before this flag):
list of built-in templates:
bailing, bailing-think, bailing2, chatglm3, chatglm4, chatml, command-r, deepseek, deepseek-ocr, deepseek2, deepseek3, exaone-moe, exaone3, exaone4, falcon3, gemma, gigachat, glmedge, gpt-oss, granite, granite-4.0, granite-4.1, grok-2, hunyuan-dense, hunyuan-moe, hunyuan-vl, kimi-k2, llama2, llama2-sys, llama2-sys-bos, llama2-sys-strip, llama3, llama4, megrez, minicpm, mistral-v1, mistral-v3, mistral-v3-tekken, mistral-v7, mistral-v7-tekken, monarch, openchat, orion, pangu-embedded, phi3, phi4, rwkv-world, seed_oss, smolvlm, solar-open, vicuna, vicuna-orca, yandex, zephyr
(env: LLAMA_ARG_CHAT_TEMPLATE_FILE) | | `--skip-chat-parsing, --no-skip-chat-parsing` | force a pure content parser, even if a Jinja template is specified; model will output everything in the content section, including any reasoning and/or tool calls (default: disabled)
(env: LLAMA_ARG_SKIP_CHAT_PARSING) | From 7624f401fe3eb2acb6200241f4bcafe602f158e3 Mon Sep 17 00:00:00 2001 From: thiswillbeyourgithub <26625900+thiswillbeyourgithub@users.noreply.github.com> Date: Sun, 31 May 2026 11:50:43 +0200 Subject: [PATCH 5/5] server: trim verbose reasoning-budget comment Co-Authored-By: Claude Opus 4.8 --- tools/server/server-common.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/tools/server/server-common.cpp b/tools/server/server-common.cpp index 7b5a6d512607..24a0aba35c6a 100644 --- a/tools/server/server-common.cpp +++ b/tools/server/server-common.cpp @@ -1120,14 +1120,8 @@ json oaicompat_chat_params_parse( }); } - // Reasoning budget: pass parameters through to sampling layer. - // The CLI flag (--reasoning-budget) is the hard ceiling chosed by - // the server admin. The request body may lower the budget but cannot - // raise it past the cap. - // The exhaustion message follows a different rule: it's a quality knob, - // not a policy lever, so the admin's choice still wins when set, but if - // the server was started without --reasoning-budget-message the client - // may supply its own via `thinking_budget_message`. + // Reasoning budget: request may lower the CLI cap but not raise it. + // The exhaustion message defaults to the CLI value, falling back to the request. { int reasoning_budget = opt.reasoning_budget; if (body.contains("thinking_budget_tokens")) {