Support reasoning for OpenRouter text completion

753a99faf93ed4a6c0f36db4f2bf63d471ab5f0e

pcpthm <pcpthm@gmail.com>

6 files changed, +25 -4Showing whitespace changes
public/index.html+4 -0
@@ -1587,6 +1587,10 @@
15871587 <input type="checkbox" id="skip_special_tokens_textgenerationwebui" />
15881588 <small data-i18n="Skip Special Tokens">Skip Special Tokens</small>
15891589 </label>
1590+ <label data-tg-type="openrouter" class="checkbox_label flexGrow flexShrink" for="include_reasoning_textgenerationwebui">
1591+ <input type="checkbox" id="include_reasoning_textgenerationwebui" />
1592+ <small data-i18n="Request Model Reasoning">Request Model Reasoning</small>
1593+ </label>
15901594 <label data-tg-type="ooba, aphrodite, tabby" class="checkbox_label flexGrow flexShrink" for="temperature_last_textgenerationwebui">
15911595 <input type="checkbox" id="temperature_last_textgenerationwebui" />
15921596 <label>
public/script.js+12 -1
@@ -5704,7 +5704,17 @@ function extractMessageFromData(data) {
57045704 * @returns {string} Extracted reasoning
57055705 */
57065706function extractReasoningFromData(data) {
5707- if (main_api === 'openai' && oai_settings.show_thoughts) {
5707+ switch (main_api) {
5708+ case 'textgenerationwebui':
5709+ switch (textgen_settings.type) {
5710+ case textgen_types.OPENROUTER:
5711+ return data?.choices?.[0]?.reasoning ?? '';
5712+ }
5713+ break;
5714+
5715+ case 'openai':
5716+ if (!oai_settings.show_thoughts) break;
5717+
57085718 switch (oai_settings.chat_completion_source) {
57095719 case chat_completion_sources.DEEPSEEK:
57105720 return data?.choices?.[0]?.message?.reasoning_content ?? '';
@@ -5713,6 +5723,7 @@ function extractReasoningFromData(data) {
57135723 case chat_completion_sources.MAKERSUITE:
57145724 return data?.responseContent?.parts?.filter(part => part.thought)?.map(part => part.text)?.join('\n\n') ?? '';
57155725 }
5726+ break;
57165727 }
57175728
57185729 return '';
public/scripts/openai.js+1 -1
@@ -1913,7 +1913,7 @@ async function sendOpenAIRequest(type, messages, signal) {
19131913 'user_name': name1,
19141914 'char_name': name2,
19151915 'group_names': getGroupNames(),
19161916 'show_thoughtsinclude_reasoning': Boolean(oai_settings.show_thoughts),
19171917 };
19181918
19191919 // Empty array will produce a validation error
public/scripts/textgen-settings.js+6 -1
@@ -172,6 +172,7 @@ const settings = {
172172 //truncation_length: 2048,
173173 ban_eos_token: false,
174174 skip_special_tokens: true,
175+ include_reasoning: true,
175176 streaming: false,
176177 mirostat_mode: 0,
177178 mirostat_tau: 5,
@@ -263,6 +264,7 @@ export const setting_names = [
263264 'add_bos_token',
264265 'ban_eos_token',
265266 'skip_special_tokens',
267+ 'include_reasoning',
266268 'streaming',
267269 'mirostat_mode',
268270 'mirostat_tau',
@@ -740,6 +742,7 @@ jQuery(function () {
740742 'add_bos_token_textgenerationwebui': true,
741743 'temperature_last_textgenerationwebui': true,
742744 'skip_special_tokens_textgenerationwebui': true,
745+ 'include_reasoning_textgenerationwebui': true,
743746 'top_a_textgenerationwebui': 0,
744747 'top_a_counter_textgenerationwebui': 0,
745748 'mirostat_mode_textgenerationwebui': 0,
@@ -986,7 +989,7 @@ export async function generateTextGenWithStreaming(generate_data, signal) {
986989 let logprobs = null;
987990 const swipes = [];
988991 const toolCalls = [];
989992 const state = { reasoning: '' };
990993 while (true) {
991994 const { done, value } = await reader.read();
992995 if (done) return;
@@ -1003,6 +1006,7 @@ export async function generateTextGenWithStreaming(generate_data, signal) {
10031006 const newText = data?.choices?.[0]?.text || data?.content || '';
10041007 text += newText;
10051008 logprobs = parseTextgenLogprobs(newText, data.choices?.[0]?.logprobs || data?.completion_probabilities);
1009+ state.reasoning += data?.choices?.[0]?.reasoning ?? '';
10061010 }
10071011
10081012 yield { text, swipes, logprobs, toolCalls, state };
@@ -1266,6 +1270,7 @@ export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate,
12661270 'truncation_length': max_context,
12671271 'ban_eos_token': settings.ban_eos_token,
12681272 'skip_special_tokens': settings.skip_special_tokens,
1273+ 'include_reasoning': settings.include_reasoning,
12691274 'top_a': settings.top_a,
12701275 'tfs': settings.tfs,
12711276 'epsilon_cutoff': [OOBA, MANCER].includes(settings.type) ? settings.epsilon_cutoff : undefined,
src/constants.js+1 -0
@@ -369,6 +369,7 @@ export const OPENROUTER_KEYS = [
369369 'prompt',
370370 'stop',
371371 'provider',
372+ 'include_reasoning',
372373];
373374
374375// https://github.com/vllm-project/vllm/blob/0f8a91401c89ac0a8018def3756829611b57727f/vllm/entrypoints/openai/protocol.py#L220
src/endpoints/backends/chat-completions.js+1 -1
@@ -998,7 +998,7 @@ router.post('/generate', jsonParser, function (request, response) {
998998 bodyParams['route'] = 'fallback';
999999 }
10001000
10011001 if (request.body.show_thoughtsinclude_reasoning) {
10021002 bodyParams['include_reasoning'] = true;
10031003 }
10041004