Merge pull request #3700 from SillyTavern/reasoning-template

Reasoning templates
This commit is contained in:
Cohee
2025-03-18 01:49:06 +02:00
committed by GitHub
13 changed files with 273 additions and 22 deletions

View File

@ -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"
} }
] ]

View File

@ -0,0 +1,6 @@
{
"name": "Blank",
"prefix": "",
"suffix": "",
"separator": ""
}

View File

@ -0,0 +1,6 @@
{
"name": "DeepSeek",
"prefix": "<think>\n",
"suffix": "\n</think>",
"separator": "\n\n"
}

View File

@ -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>

View File

@ -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
*/ */

View File

@ -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();

View File

@ -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));

View File

@ -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();

View File

@ -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',
}); });
/** /**

View File

@ -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;
} }

View File

@ -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 };
} }

View File

@ -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,

View File

@ -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
*/ */
/** /**