diff --git a/common/arg.cpp b/common/arg.cpp index 8382c1d85dde..705fe5f0c367 100644 --- a/common/arg.cpp +++ b/common/arg.cpp @@ -3163,9 +3163,10 @@ 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)", + "(default: deepseek)", [](common_params & params, const std::string & value) { params.reasoning_format = common_reasoning_format_from_name(value); } diff --git a/tools/server/README.md b/tools/server/README.md index b41491059020..0361edd3ab29 100644 --- a/tools/server/README.md +++ b/tools/server/README.md @@ -1246,6 +1246,10 @@ 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. + +`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 2b89a8bc5a13..b2ff1197594c 100644 --- a/tools/server/server-common.cpp +++ b/tools/server/server-common.cpp @@ -1132,18 +1132,25 @@ json oaicompat_chat_params_parse( }); } - // Reasoning budget: pass parameters through to sampling layer + // Reasoning budget: the per-request thinking_budget_tokens takes precedence, + // falling back to the CLI default. The exhaustion message defaults to the CLI + // value, falling back to the per-request thinking_budget_message. { int reasoning_budget = json_value(body, "thinking_budget_tokens", -1); if (reasoning_budget == -1) { reasoning_budget = opt.reasoning_budget; } + 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); } }