mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Merge pull request #3700 from SillyTavern/reasoning-template
Reasoning templates
This commit is contained in:
@ -786,5 +786,13 @@
|
|||||||
{
|
{
|
||||||
"filename": "presets/context/DeepSeek-V2.5.json",
|
"filename": "presets/context/DeepSeek-V2.5.json",
|
||||||
"type": "context"
|
"type": "context"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "presets/reasoning/DeepSeek.json",
|
||||||
|
"type": "reasoning"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "presets/reasoning/Blank.json",
|
||||||
|
"type": "reasoning"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
6
default/content/presets/reasoning/Blank.json
Normal file
6
default/content/presets/reasoning/Blank.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"name": "Blank",
|
||||||
|
"prefix": "",
|
||||||
|
"suffix": "",
|
||||||
|
"separator": ""
|
||||||
|
}
|
6
default/content/presets/reasoning/DeepSeek.json
Normal file
6
default/content/presets/reasoning/DeepSeek.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"name": "DeepSeek",
|
||||||
|
"prefix": "<think>\n",
|
||||||
|
"suffix": "\n</think>",
|
||||||
|
"separator": "\n\n"
|
||||||
|
}
|
@ -3917,6 +3917,19 @@
|
|||||||
<summary data-i18n="Reasoning Formatting">
|
<summary data-i18n="Reasoning Formatting">
|
||||||
Reasoning Formatting
|
Reasoning Formatting
|
||||||
</summary>
|
</summary>
|
||||||
|
<div class="flex-container" title="Select your current Reasoning Template" data-i18n="[title]Select your current Reasoning Template">
|
||||||
|
<select id="reasoning_select" data-preset-manager-for="reasoning" class="flex1 text_pole"></select>
|
||||||
|
<div class="flex-container margin0 justifyCenter gap3px">
|
||||||
|
<input type="file" hidden data-preset-manager-file="reasoning" accept=".json, .settings">
|
||||||
|
<i data-preset-manager-update="reasoning" class="menu_button fa-solid fa-save" title="Update current template" data-i18n="[title]Update current template"></i>
|
||||||
|
<i data-preset-manager-rename="reasoning" class="menu_button fa-pencil fa-solid" title="Rename current template" data-i18n="[title]Rename current template"></i>
|
||||||
|
<i data-preset-manager-new="reasoning" class="menu_button fa-solid fa-file-circle-plus" title="Save template as" data-i18n="[title]Save template as"></i>
|
||||||
|
<i data-preset-manager-import="reasoning" class="displayNone menu_button fa-solid fa-file-import" title="Import template" data-i18n="[title]Import template"></i>
|
||||||
|
<i data-preset-manager-export="reasoning" class="displayNone menu_button fa-solid fa-file-export" title="Export template" data-i18n="[title]Export template"></i>
|
||||||
|
<i data-preset-manager-restore="reasoning" class="menu_button fa-solid fa-recycle" title="Restore current template" data-i18n="[title]Restore current template"></i>
|
||||||
|
<i data-preset-manager-delete="reasoning" class="menu_button fa-solid fa-trash-can" title="Delete template" data-i18n="[title]Delete template"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="flex-container">
|
<div class="flex-container">
|
||||||
<div class="flex1" title="Inserted before the reasoning content." data-i18n="[title]reasoning_prefix">
|
<div class="flex1" title="Inserted before the reasoning content." data-i18n="[title]reasoning_prefix">
|
||||||
<small data-i18n="Prefix">Prefix</small>
|
<small data-i18n="Prefix">Prefix</small>
|
||||||
|
@ -39,6 +39,7 @@ const CC_COMMANDS = [
|
|||||||
'proxy',
|
'proxy',
|
||||||
'stop-strings',
|
'stop-strings',
|
||||||
'start-reply-with',
|
'start-reply-with',
|
||||||
|
'reasoning-template',
|
||||||
];
|
];
|
||||||
|
|
||||||
const TC_COMMANDS = [
|
const TC_COMMANDS = [
|
||||||
@ -54,6 +55,7 @@ const TC_COMMANDS = [
|
|||||||
'tokenizer',
|
'tokenizer',
|
||||||
'stop-strings',
|
'stop-strings',
|
||||||
'start-reply-with',
|
'start-reply-with',
|
||||||
|
'reasoning-template',
|
||||||
];
|
];
|
||||||
|
|
||||||
const FANCY_NAMES = {
|
const FANCY_NAMES = {
|
||||||
@ -70,6 +72,7 @@ const FANCY_NAMES = {
|
|||||||
'tokenizer': 'Tokenizer',
|
'tokenizer': 'Tokenizer',
|
||||||
'stop-strings': 'Custom Stopping Strings',
|
'stop-strings': 'Custom Stopping Strings',
|
||||||
'start-reply-with': 'Start Reply With',
|
'start-reply-with': 'Start Reply With',
|
||||||
|
'reasoning-template': 'Reasoning Template',
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -154,6 +157,7 @@ const profilesProvider = () => [
|
|||||||
* @property {string} [tokenizer] Tokenizer
|
* @property {string} [tokenizer] Tokenizer
|
||||||
* @property {string} [stop-strings] Custom Stopping Strings
|
* @property {string} [stop-strings] Custom Stopping Strings
|
||||||
* @property {string} [start-reply-with] Start Reply With
|
* @property {string} [start-reply-with] Start Reply With
|
||||||
|
* @property {string} [reasoning-template] Reasoning Template
|
||||||
* @property {string[]} [exclude] Commands to exclude
|
* @property {string[]} [exclude] Commands to exclude
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -55,6 +55,7 @@ import { POPUP_TYPE, callGenericPopup } from './popup.js';
|
|||||||
import { loadSystemPrompts } from './sysprompt.js';
|
import { loadSystemPrompts } from './sysprompt.js';
|
||||||
import { fuzzySearchCategories } from './filters.js';
|
import { fuzzySearchCategories } from './filters.js';
|
||||||
import { accountStorage } from './util/AccountStorage.js';
|
import { accountStorage } from './util/AccountStorage.js';
|
||||||
|
import { DEFAULT_REASONING_TEMPLATE, loadReasoningTemplates } from './reasoning.js';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
loadPowerUserSettings,
|
loadPowerUserSettings,
|
||||||
@ -257,6 +258,7 @@ let power_user = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
reasoning: {
|
reasoning: {
|
||||||
|
name: DEFAULT_REASONING_TEMPLATE,
|
||||||
auto_parse: false,
|
auto_parse: false,
|
||||||
add_to_prompts: false,
|
add_to_prompts: false,
|
||||||
auto_expand: false,
|
auto_expand: false,
|
||||||
@ -1624,6 +1626,7 @@ async function loadPowerUserSettings(settings, data) {
|
|||||||
await loadInstructMode(data);
|
await loadInstructMode(data);
|
||||||
await loadContextSettings();
|
await loadContextSettings();
|
||||||
await loadSystemPrompts(data);
|
await loadSystemPrompts(data);
|
||||||
|
await loadReasoningTemplates(data);
|
||||||
loadMaxContextUnlocked();
|
loadMaxContextUnlocked();
|
||||||
switchWaifuMode();
|
switchWaifuMode();
|
||||||
switchSpoilerMode();
|
switchSpoilerMode();
|
||||||
|
@ -21,7 +21,7 @@ import { groups, selected_group } from './group-chats.js';
|
|||||||
import { instruct_presets } from './instruct-mode.js';
|
import { instruct_presets } from './instruct-mode.js';
|
||||||
import { kai_settings } from './kai-settings.js';
|
import { kai_settings } from './kai-settings.js';
|
||||||
import { convertNovelPreset } from './nai-settings.js';
|
import { convertNovelPreset } from './nai-settings.js';
|
||||||
import { openai_settings, openai_setting_names, oai_settings } from './openai.js';
|
import { openai_settings, openai_setting_names } from './openai.js';
|
||||||
import { Popup, POPUP_RESULT, POPUP_TYPE } from './popup.js';
|
import { Popup, POPUP_RESULT, POPUP_TYPE } from './popup.js';
|
||||||
import { context_presets, getContextSettings, power_user } from './power-user.js';
|
import { context_presets, getContextSettings, power_user } from './power-user.js';
|
||||||
import { SlashCommand } from './slash-commands/SlashCommand.js';
|
import { SlashCommand } from './slash-commands/SlashCommand.js';
|
||||||
@ -38,6 +38,7 @@ import {
|
|||||||
} from './textgen-settings.js';
|
} from './textgen-settings.js';
|
||||||
import { download, parseJsonFile, waitUntilCondition } from './utils.js';
|
import { download, parseJsonFile, waitUntilCondition } from './utils.js';
|
||||||
import { t } from './i18n.js';
|
import { t } from './i18n.js';
|
||||||
|
import { reasoning_templates } from './reasoning.js';
|
||||||
|
|
||||||
const presetManagers = {};
|
const presetManagers = {};
|
||||||
|
|
||||||
@ -168,6 +169,20 @@ class PresetManager {
|
|||||||
},
|
},
|
||||||
isValid: (data) => PresetManager.isPossiblyTextCompletionData(data),
|
isValid: (data) => PresetManager.isPossiblyTextCompletionData(data),
|
||||||
},
|
},
|
||||||
|
'reasoning': {
|
||||||
|
name: 'Reasoning Formatting',
|
||||||
|
getData: () => {
|
||||||
|
const manager = getPresetManager('reasoning');
|
||||||
|
const name = manager.getSelectedPresetName();
|
||||||
|
return manager.getPresetSettings(name);
|
||||||
|
},
|
||||||
|
setData: (data) => {
|
||||||
|
const manager = getPresetManager('reasoning');
|
||||||
|
const name = data.name;
|
||||||
|
return manager.savePreset(name, data);
|
||||||
|
},
|
||||||
|
isValid: (data) => PresetManager.isPossiblyReasoningData(data),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static isPossiblyInstructData(data) {
|
static isPossiblyInstructData(data) {
|
||||||
@ -190,6 +205,11 @@ class PresetManager {
|
|||||||
return data && textCompletionProps.every(prop => Object.keys(data).includes(prop));
|
return data && textCompletionProps.every(prop => Object.keys(data).includes(prop));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static isPossiblyReasoningData(data) {
|
||||||
|
const reasoningProps = ['name', 'prefix', 'suffix', 'separator'];
|
||||||
|
return data && reasoningProps.every(prop => Object.keys(data).includes(prop));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Imports master settings from JSON data.
|
* Imports master settings from JSON data.
|
||||||
* @param {object} data Data to import
|
* @param {object} data Data to import
|
||||||
@ -227,6 +247,12 @@ class PresetManager {
|
|||||||
return await getPresetManager('textgenerationwebui').savePreset(fileName, data);
|
return await getPresetManager('textgenerationwebui').savePreset(fileName, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 5. Reasoning Template
|
||||||
|
if (this.isPossiblyReasoningData(data)) {
|
||||||
|
toastr.info(t`Importing as reasoning template...`, t`Reasoning template detected`);
|
||||||
|
return await getPresetManager('reasoning').savePreset(data.name, data);
|
||||||
|
}
|
||||||
|
|
||||||
const validSections = [];
|
const validSections = [];
|
||||||
for (const [key, section] of Object.entries(this.masterSections)) {
|
for (const [key, section] of Object.entries(this.masterSections)) {
|
||||||
if (key in data && section.isValid(data[key])) {
|
if (key in data && section.isValid(data[key])) {
|
||||||
@ -478,6 +504,10 @@ class PresetManager {
|
|||||||
presets = system_prompts;
|
presets = system_prompts;
|
||||||
preset_names = system_prompts.map(x => x.name);
|
preset_names = system_prompts.map(x => x.name);
|
||||||
break;
|
break;
|
||||||
|
case 'reasoning':
|
||||||
|
presets = reasoning_templates;
|
||||||
|
preset_names = reasoning_templates.map(x => x.name);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.warn(`Unknown API ID ${api}`);
|
console.warn(`Unknown API ID ${api}`);
|
||||||
}
|
}
|
||||||
@ -490,7 +520,7 @@ class PresetManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isAdvancedFormatting() {
|
isAdvancedFormatting() {
|
||||||
return this.apiId == 'context' || this.apiId == 'instruct' || this.apiId == 'sysprompt';
|
return ['context', 'instruct', 'sysprompt', 'reasoning'].includes(this.apiId);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateList(name, preset) {
|
updateList(name, preset) {
|
||||||
@ -553,6 +583,11 @@ class PresetManager {
|
|||||||
sysprompt_preset['name'] = name || power_user.sysprompt.preset;
|
sysprompt_preset['name'] = name || power_user.sysprompt.preset;
|
||||||
return sysprompt_preset;
|
return sysprompt_preset;
|
||||||
}
|
}
|
||||||
|
case 'reasoning': {
|
||||||
|
const reasoning_preset = structuredClone(power_user.reasoning);
|
||||||
|
reasoning_preset['name'] = name || power_user.reasoning.preset;
|
||||||
|
return reasoning_preset;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
console.warn(`Unknown API ID ${apiId}`);
|
console.warn(`Unknown API ID ${apiId}`);
|
||||||
return {};
|
return {};
|
||||||
@ -599,6 +634,13 @@ class PresetManager {
|
|||||||
'include_reasoning',
|
'include_reasoning',
|
||||||
'global_banned_tokens',
|
'global_banned_tokens',
|
||||||
'send_banned_tokens',
|
'send_banned_tokens',
|
||||||
|
|
||||||
|
// Reasoning exclusions
|
||||||
|
'auto_parse',
|
||||||
|
'add_to_prompts',
|
||||||
|
'auto_expand',
|
||||||
|
'show_hidden',
|
||||||
|
'max_additions',
|
||||||
];
|
];
|
||||||
const settings = Object.assign({}, getSettingsByApiId(this.apiId));
|
const settings = Object.assign({}, getSettingsByApiId(this.apiId));
|
||||||
|
|
||||||
|
@ -7,14 +7,46 @@ import { getCurrentLocale, t, translate } from './i18n.js';
|
|||||||
import { MacrosParser } from './macros.js';
|
import { MacrosParser } from './macros.js';
|
||||||
import { chat_completion_sources, getChatCompletionModel, oai_settings } from './openai.js';
|
import { chat_completion_sources, getChatCompletionModel, oai_settings } from './openai.js';
|
||||||
import { Popup } from './popup.js';
|
import { Popup } from './popup.js';
|
||||||
import { power_user } from './power-user.js';
|
import { performFuzzySearch, power_user } from './power-user.js';
|
||||||
|
import { getPresetManager } from './preset-manager.js';
|
||||||
import { SlashCommand } from './slash-commands/SlashCommand.js';
|
import { SlashCommand } from './slash-commands/SlashCommand.js';
|
||||||
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js';
|
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js';
|
||||||
import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js';
|
import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js';
|
||||||
import { enumTypes, SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js';
|
import { enumTypes, SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js';
|
||||||
import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
|
import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
|
||||||
import { textgen_types, textgenerationwebui_settings } from './textgen-settings.js';
|
import { textgen_types, textgenerationwebui_settings } from './textgen-settings.js';
|
||||||
import { copyText, escapeRegex, isFalseBoolean, setDatasetProperty, trimSpaces } from './utils.js';
|
import { copyText, escapeRegex, isFalseBoolean, isTrueBoolean, setDatasetProperty, trimSpaces } from './utils.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {object} ReasoningTemplate
|
||||||
|
* @property {string} name - The name of the template
|
||||||
|
* @property {string} prefix - Reasoning prefix
|
||||||
|
* @property {string} suffix - Reasoning suffix
|
||||||
|
* @property {string} separator - Reasoning separator
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {ReasoningTemplate[]} List of reasoning templates
|
||||||
|
*/
|
||||||
|
export const reasoning_templates = [];
|
||||||
|
|
||||||
|
export const DEFAULT_REASONING_TEMPLATE = 'DeepSeek';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Record<string, JQuery<HTMLElement>>} List of UI elements for reasoning settings
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
const UI = {
|
||||||
|
$select: $('#reasoning_select'),
|
||||||
|
$suffix: $('#reasoning_suffix'),
|
||||||
|
$prefix: $('#reasoning_prefix'),
|
||||||
|
$separator: $('#reasoning_separator'),
|
||||||
|
$autoParse: $('#reasoning_auto_parse'),
|
||||||
|
$autoExpand: $('#reasoning_auto_expand'),
|
||||||
|
$showHidden: $('#reasoning_show_hidden'),
|
||||||
|
$addToPrompts: $('#reasoning_add_to_prompts'),
|
||||||
|
$maxAdditions: $('#reasoning_max_additions'),
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enum representing the type of the reasoning for a message (where it came from)
|
* Enum representing the type of the reasoning for a message (where it came from)
|
||||||
@ -61,7 +93,7 @@ export function extractReasoningFromData(data, {
|
|||||||
mainApi = null,
|
mainApi = null,
|
||||||
ignoreShowThoughts = false,
|
ignoreShowThoughts = false,
|
||||||
textGenType = null,
|
textGenType = null,
|
||||||
chatCompletionSource = null
|
chatCompletionSource = null,
|
||||||
} = {}) {
|
} = {}) {
|
||||||
switch (mainApi ?? main_api) {
|
switch (mainApi ?? main_api) {
|
||||||
case 'textgenerationwebui':
|
case 'textgenerationwebui':
|
||||||
@ -669,57 +701,102 @@ export class PromptReasoning {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function loadReasoningSettings() {
|
function loadReasoningSettings() {
|
||||||
$('#reasoning_add_to_prompts').prop('checked', power_user.reasoning.add_to_prompts);
|
UI.$addToPrompts.prop('checked', power_user.reasoning.add_to_prompts);
|
||||||
$('#reasoning_add_to_prompts').on('change', function () {
|
UI.$addToPrompts.on('change', function () {
|
||||||
power_user.reasoning.add_to_prompts = !!$(this).prop('checked');
|
power_user.reasoning.add_to_prompts = !!$(this).prop('checked');
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#reasoning_prefix').val(power_user.reasoning.prefix);
|
UI.$prefix.val(power_user.reasoning.prefix);
|
||||||
$('#reasoning_prefix').on('input', function () {
|
UI.$prefix.on('input', function () {
|
||||||
power_user.reasoning.prefix = String($(this).val());
|
power_user.reasoning.prefix = String($(this).val());
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#reasoning_suffix').val(power_user.reasoning.suffix);
|
UI.$suffix.val(power_user.reasoning.suffix);
|
||||||
$('#reasoning_suffix').on('input', function () {
|
UI.$suffix.on('input', function () {
|
||||||
power_user.reasoning.suffix = String($(this).val());
|
power_user.reasoning.suffix = String($(this).val());
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#reasoning_separator').val(power_user.reasoning.separator);
|
UI.$separator.val(power_user.reasoning.separator);
|
||||||
$('#reasoning_separator').on('input', function () {
|
UI.$separator.on('input', function () {
|
||||||
power_user.reasoning.separator = String($(this).val());
|
power_user.reasoning.separator = String($(this).val());
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#reasoning_max_additions').val(power_user.reasoning.max_additions);
|
UI.$maxAdditions.val(power_user.reasoning.max_additions);
|
||||||
$('#reasoning_max_additions').on('input', function () {
|
UI.$maxAdditions.on('input', function () {
|
||||||
power_user.reasoning.max_additions = Number($(this).val());
|
power_user.reasoning.max_additions = Number($(this).val());
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#reasoning_auto_parse').prop('checked', power_user.reasoning.auto_parse);
|
UI.$autoParse.prop('checked', power_user.reasoning.auto_parse);
|
||||||
$('#reasoning_auto_parse').on('change', function () {
|
UI.$autoParse.on('change', function () {
|
||||||
power_user.reasoning.auto_parse = !!$(this).prop('checked');
|
power_user.reasoning.auto_parse = !!$(this).prop('checked');
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#reasoning_auto_expand').prop('checked', power_user.reasoning.auto_expand);
|
UI.$autoExpand.prop('checked', power_user.reasoning.auto_expand);
|
||||||
$('#reasoning_auto_expand').on('change', function () {
|
UI.$autoExpand.on('change', function () {
|
||||||
power_user.reasoning.auto_expand = !!$(this).prop('checked');
|
power_user.reasoning.auto_expand = !!$(this).prop('checked');
|
||||||
toggleReasoningAutoExpand();
|
toggleReasoningAutoExpand();
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
toggleReasoningAutoExpand();
|
toggleReasoningAutoExpand();
|
||||||
|
|
||||||
$('#reasoning_show_hidden').prop('checked', power_user.reasoning.show_hidden);
|
UI.$showHidden.prop('checked', power_user.reasoning.show_hidden);
|
||||||
$('#reasoning_show_hidden').on('change', function () {
|
UI.$showHidden.on('change', function () {
|
||||||
power_user.reasoning.show_hidden = !!$(this).prop('checked');
|
power_user.reasoning.show_hidden = !!$(this).prop('checked');
|
||||||
$('#chat').attr('data-show-hidden-reasoning', power_user.reasoning.show_hidden ? 'true' : null);
|
$('#chat').attr('data-show-hidden-reasoning', power_user.reasoning.show_hidden ? 'true' : null);
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
$('#chat').attr('data-show-hidden-reasoning', power_user.reasoning.show_hidden ? 'true' : null);
|
$('#chat').attr('data-show-hidden-reasoning', power_user.reasoning.show_hidden ? 'true' : null);
|
||||||
|
|
||||||
|
UI.$select.on('change', async function () {
|
||||||
|
const name = String($(this).val());
|
||||||
|
const template = reasoning_templates.find(p => p.name === name);
|
||||||
|
if (!template) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UI.$prefix.val(template.prefix);
|
||||||
|
UI.$suffix.val(template.suffix);
|
||||||
|
UI.$separator.val(template.separator);
|
||||||
|
|
||||||
|
power_user.reasoning.name = name;
|
||||||
|
power_user.reasoning.prefix = template.prefix;
|
||||||
|
power_user.reasoning.suffix = template.suffix;
|
||||||
|
power_user.reasoning.separator = template.separator;
|
||||||
|
|
||||||
|
saveSettingsDebounced();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectReasoningTemplateCallback(args, name) {
|
||||||
|
if (!name) {
|
||||||
|
return power_user.reasoning.name ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const quiet = isTrueBoolean(args?.quiet);
|
||||||
|
const templateNames = reasoning_templates.map(preset => preset.name);
|
||||||
|
let foundName = templateNames.find(x => x.toLowerCase() === name.toLowerCase());
|
||||||
|
|
||||||
|
if (!foundName) {
|
||||||
|
const result = performFuzzySearch('reasoning-templates', templateNames, [], name);
|
||||||
|
|
||||||
|
if (result.length === 0) {
|
||||||
|
!quiet && toastr.warning(`Reasoning template "${name}" not found`);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
foundName = result[0].item;
|
||||||
|
}
|
||||||
|
|
||||||
|
UI.$select.val(foundName).trigger('change');
|
||||||
|
!quiet && toastr.success(`Reasoning template "${foundName}" selected`);
|
||||||
|
return foundName;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function registerReasoningSlashCommands() {
|
function registerReasoningSlashCommands() {
|
||||||
@ -853,6 +930,42 @@ function registerReasoningSlashCommands() {
|
|||||||
: parsedReasoning.reasoning;
|
: parsedReasoning.reasoning;
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||||
|
name: 'reasoning-template',
|
||||||
|
aliases: ['reasoning-formatting', 'reasoning-preset'],
|
||||||
|
callback: selectReasoningTemplateCallback,
|
||||||
|
returns: 'template name',
|
||||||
|
namedArgumentList: [
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'quiet',
|
||||||
|
description: 'Suppress the toast message on template change',
|
||||||
|
typeList: [ARGUMENT_TYPE.BOOLEAN],
|
||||||
|
defaultValue: 'false',
|
||||||
|
enumList: commonEnumProviders.boolean('trueFalse')(),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
unnamedArgumentList: [
|
||||||
|
SlashCommandArgument.fromProps({
|
||||||
|
description: 'reasoning template name',
|
||||||
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
|
enumProvider: () => reasoning_templates.map(x => new SlashCommandEnumValue(x.name, null, enumTypes.enum, enumIcons.preset)),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
helpString: `
|
||||||
|
<div>
|
||||||
|
Selects a reasoning template by name, using fuzzy search to find the closest match.
|
||||||
|
Gets the current template if no name is provided.
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<strong>Example:</strong>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<pre><code class="language-stscript">/reasoning-template DeepSeek</code></pre>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
function registerReasoningMacros() {
|
function registerReasoningMacros() {
|
||||||
@ -1212,6 +1325,53 @@ function registerReasoningAppEvents() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads reasoning templates from the settings data.
|
||||||
|
* @param {object} data Settings data
|
||||||
|
* @param {ReasoningTemplate[]} data.reasoning Reasoning templates
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
export async function loadReasoningTemplates(data) {
|
||||||
|
if (data.reasoning !== undefined) {
|
||||||
|
reasoning_templates.splice(0, reasoning_templates.length, ...data.reasoning);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const template of reasoning_templates) {
|
||||||
|
$('<option>').val(template.name).text(template.name).appendTo(UI.$select);
|
||||||
|
}
|
||||||
|
|
||||||
|
// No template name, need to migrate
|
||||||
|
if (power_user.reasoning.name === undefined) {
|
||||||
|
const defaultTemplate = reasoning_templates.find(p => p.name === DEFAULT_REASONING_TEMPLATE);
|
||||||
|
if (defaultTemplate) {
|
||||||
|
// If the reasoning settings were modified - migrate them to a custom template
|
||||||
|
if (power_user.reasoning.prefix !== defaultTemplate.prefix || power_user.reasoning.suffix !== defaultTemplate.suffix || power_user.reasoning.separator !== defaultTemplate.separator) {
|
||||||
|
/** @type {ReasoningTemplate} */
|
||||||
|
const data = {
|
||||||
|
name: '[Migrated] Custom',
|
||||||
|
prefix: power_user.reasoning.prefix,
|
||||||
|
suffix: power_user.reasoning.suffix,
|
||||||
|
separator: power_user.reasoning.separator,
|
||||||
|
};
|
||||||
|
await getPresetManager('reasoning')?.savePreset(data.name, data);
|
||||||
|
power_user.reasoning.name = data.name;
|
||||||
|
} else {
|
||||||
|
power_user.reasoning.name = defaultTemplate.name;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Template not found (deleted or content check skipped - leave blank)
|
||||||
|
power_user.reasoning.name = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
saveSettingsDebounced();
|
||||||
|
}
|
||||||
|
|
||||||
|
UI.$select.val(power_user.reasoning.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes reasoning settings and event handlers.
|
||||||
|
*/
|
||||||
export function initReasoning() {
|
export function initReasoning() {
|
||||||
loadReasoningSettings();
|
loadReasoningSettings();
|
||||||
setReasoningEventHandlers();
|
setReasoningEventHandlers();
|
||||||
|
@ -43,6 +43,7 @@ export const USER_DIRECTORY_TEMPLATE = Object.freeze({
|
|||||||
vectors: 'vectors',
|
vectors: 'vectors',
|
||||||
backups: 'backups',
|
backups: 'backups',
|
||||||
sysprompt: 'sysprompt',
|
sysprompt: 'sysprompt',
|
||||||
|
reasoning: 'reasoning',
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -48,6 +48,7 @@ export const CONTENT_TYPES = {
|
|||||||
MOVING_UI: 'moving_ui',
|
MOVING_UI: 'moving_ui',
|
||||||
QUICK_REPLIES: 'quick_replies',
|
QUICK_REPLIES: 'quick_replies',
|
||||||
SYSPROMPT: 'sysprompt',
|
SYSPROMPT: 'sysprompt',
|
||||||
|
REASONING: 'reasoning',
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -61,7 +62,7 @@ export function getDefaultPresets(directories) {
|
|||||||
const presets = [];
|
const presets = [];
|
||||||
|
|
||||||
for (const contentItem of contentIndex) {
|
for (const contentItem of contentIndex) {
|
||||||
if (contentItem.type.endsWith('_preset') || contentItem.type === 'instruct' || contentItem.type === 'context' || contentItem.type === 'sysprompt') {
|
if (contentItem.type.endsWith('_preset') || ['instruct', 'context', 'sysprompt', 'reasoning'].includes(contentItem.type)) {
|
||||||
contentItem.name = path.parse(contentItem.filename).name;
|
contentItem.name = path.parse(contentItem.filename).name;
|
||||||
contentItem.folder = getTargetByType(contentItem.type, directories);
|
contentItem.folder = getTargetByType(contentItem.type, directories);
|
||||||
presets.push(contentItem);
|
presets.push(contentItem);
|
||||||
@ -299,6 +300,8 @@ function getTargetByType(type, directories) {
|
|||||||
return directories.quickreplies;
|
return directories.quickreplies;
|
||||||
case CONTENT_TYPES.SYSPROMPT:
|
case CONTENT_TYPES.SYSPROMPT:
|
||||||
return directories.sysprompt;
|
return directories.sysprompt;
|
||||||
|
case CONTENT_TYPES.REASONING:
|
||||||
|
return directories.reasoning;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,8 @@ function getPresetSettingsByAPI(apiId, directories) {
|
|||||||
return { folder: directories.context, extension: '.json' };
|
return { folder: directories.context, extension: '.json' };
|
||||||
case 'sysprompt':
|
case 'sysprompt':
|
||||||
return { folder: directories.sysprompt, extension: '.json' };
|
return { folder: directories.sysprompt, extension: '.json' };
|
||||||
|
case 'reasoning':
|
||||||
|
return { folder: directories.reasoning, extension: '.json' };
|
||||||
default:
|
default:
|
||||||
return { folder: null, extension: null };
|
return { folder: null, extension: null };
|
||||||
}
|
}
|
||||||
|
@ -254,6 +254,7 @@ router.post('/get', (request, response) => {
|
|||||||
const instruct = readAndParseFromDirectory(request.user.directories.instruct);
|
const instruct = readAndParseFromDirectory(request.user.directories.instruct);
|
||||||
const context = readAndParseFromDirectory(request.user.directories.context);
|
const context = readAndParseFromDirectory(request.user.directories.context);
|
||||||
const sysprompt = readAndParseFromDirectory(request.user.directories.sysprompt);
|
const sysprompt = readAndParseFromDirectory(request.user.directories.sysprompt);
|
||||||
|
const reasoning = readAndParseFromDirectory(request.user.directories.reasoning);
|
||||||
|
|
||||||
response.send({
|
response.send({
|
||||||
settings,
|
settings,
|
||||||
@ -272,6 +273,7 @@ router.post('/get', (request, response) => {
|
|||||||
instruct,
|
instruct,
|
||||||
context,
|
context,
|
||||||
sysprompt,
|
sysprompt,
|
||||||
|
reasoning,
|
||||||
enable_extensions: ENABLE_EXTENSIONS,
|
enable_extensions: ENABLE_EXTENSIONS,
|
||||||
enable_extensions_auto_update: ENABLE_EXTENSIONS_AUTO_UPDATE,
|
enable_extensions_auto_update: ENABLE_EXTENSIONS_AUTO_UPDATE,
|
||||||
enable_accounts: ENABLE_ACCOUNTS,
|
enable_accounts: ENABLE_ACCOUNTS,
|
||||||
|
@ -95,6 +95,7 @@ const STORAGE_KEYS = {
|
|||||||
* @property {string} vectors - The directory where the vectors are stored
|
* @property {string} vectors - The directory where the vectors are stored
|
||||||
* @property {string} backups - The directory where the backups are stored
|
* @property {string} backups - The directory where the backups are stored
|
||||||
* @property {string} sysprompt - The directory where the system prompt data is stored
|
* @property {string} sysprompt - The directory where the system prompt data is stored
|
||||||
|
* @property {string} reasoning - The directory where the reasoning templates are stored
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user