Merge branch 'staging' into reasoning-parsing-streaming

This commit is contained in:
Cohee
2025-02-16 23:12:41 +02:00
11 changed files with 101 additions and 8 deletions

View File

@ -80,6 +80,8 @@ body:
required: true required: true
- label: I have checked the [docs](https://docs.sillytavern.app/) ![important](https://img.shields.io/badge/Important!-F6094E) - label: I have checked the [docs](https://docs.sillytavern.app/) ![important](https://img.shields.io/badge/Important!-F6094E)
required: true required: true
- label: I confirm that my issue is not related to third-party content, unofficial extension or patch. If in doubt, check with a new [user account](https://docs.sillytavern.app/administration/multi-user/) and with extensions disabled
required: true
- type: markdown - type: markdown
attributes: attributes:

View File

@ -210,3 +210,5 @@ claude:
cachingAtDepth: -1 cachingAtDepth: -1
# -- SERVER PLUGIN CONFIGURATION -- # -- SERVER PLUGIN CONFIGURATION --
enableServerPlugins: false enableServerPlugins: false
# Attempt to automatically update server plugins on startup
enableServerPluginsAutoUpdate: true

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "sillytavern", "name": "sillytavern",
"version": "1.12.11", "version": "1.12.12",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "sillytavern", "name": "sillytavern",
"version": "1.12.11", "version": "1.12.12",
"hasInstallScript": true, "hasInstallScript": true,
"license": "AGPL-3.0", "license": "AGPL-3.0",
"dependencies": { "dependencies": {

View File

@ -87,7 +87,7 @@
"type": "git", "type": "git",
"url": "https://github.com/SillyTavern/SillyTavern.git" "url": "https://github.com/SillyTavern/SillyTavern.git"
}, },
"version": "1.12.11", "version": "1.12.12",
"scripts": { "scripts": {
"start": "node server.js", "start": "node server.js",
"debug": "node server.js --inspect", "debug": "node server.js --inspect",

View File

@ -48,6 +48,13 @@ async function updatePlugins() {
console.log(`Updating plugin ${color.green(directory)}...`); console.log(`Updating plugin ${color.green(directory)}...`);
const pluginPath = path.join(pluginsPath, directory); const pluginPath = path.join(pluginsPath, directory);
const pluginRepo = git(pluginPath); const pluginRepo = git(pluginPath);
const isRepo = await pluginRepo.checkIsRepo();
if (!isRepo) {
console.log(`Directory ${color.yellow(directory)} is not a Git repository`);
continue;
}
await pluginRepo.fetch(); await pluginRepo.fetch();
const commitHash = await pluginRepo.revparse(['HEAD']); const commitHash = await pluginRepo.revparse(['HEAD']);
const trackingBranch = await pluginRepo.revparse(['--abbrev-ref', '@{u}']); const trackingBranch = await pluginRepo.revparse(['--abbrev-ref', '@{u}']);

View File

@ -5931,6 +5931,7 @@ export async function saveReply(type, getMessage, fromStreaming, title, swipes,
chat[chat.length - 1]['extra']['api'] = getGeneratingApi(); chat[chat.length - 1]['extra']['api'] = getGeneratingApi();
chat[chat.length - 1]['extra']['model'] = getGeneratingModel(); chat[chat.length - 1]['extra']['model'] = getGeneratingModel();
chat[chat.length - 1]['extra']['reasoning'] = reasoning; chat[chat.length - 1]['extra']['reasoning'] = reasoning;
chat[chat.length - 1]['extra']['reasoning_duration'] = null;
if (power_user.message_token_count_enabled) { if (power_user.message_token_count_enabled) {
const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes']; const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes'];
chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0); chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0);
@ -5953,6 +5954,7 @@ export async function saveReply(type, getMessage, fromStreaming, title, swipes,
chat[chat.length - 1]['extra']['api'] = getGeneratingApi(); chat[chat.length - 1]['extra']['api'] = getGeneratingApi();
chat[chat.length - 1]['extra']['model'] = getGeneratingModel(); chat[chat.length - 1]['extra']['model'] = getGeneratingModel();
chat[chat.length - 1]['extra']['reasoning'] = reasoning; chat[chat.length - 1]['extra']['reasoning'] = reasoning;
chat[chat.length - 1]['extra']['reasoning_duration'] = null;
if (power_user.message_token_count_enabled) { if (power_user.message_token_count_enabled) {
const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes']; const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes'];
chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0); chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0);
@ -5972,6 +5974,7 @@ export async function saveReply(type, getMessage, fromStreaming, title, swipes,
chat[chat.length - 1]['extra']['api'] = getGeneratingApi(); chat[chat.length - 1]['extra']['api'] = getGeneratingApi();
chat[chat.length - 1]['extra']['model'] = getGeneratingModel(); chat[chat.length - 1]['extra']['model'] = getGeneratingModel();
chat[chat.length - 1]['extra']['reasoning'] += reasoning; chat[chat.length - 1]['extra']['reasoning'] += reasoning;
// We don't know if the reasoning duration extended, so we don't update it here on purpose.
if (power_user.message_token_count_enabled) { if (power_user.message_token_count_enabled) {
const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes']; const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes'];
chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0); chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0);
@ -5991,6 +5994,7 @@ export async function saveReply(type, getMessage, fromStreaming, title, swipes,
chat[chat.length - 1]['extra']['api'] = getGeneratingApi(); chat[chat.length - 1]['extra']['api'] = getGeneratingApi();
chat[chat.length - 1]['extra']['model'] = getGeneratingModel(); chat[chat.length - 1]['extra']['model'] = getGeneratingModel();
chat[chat.length - 1]['extra']['reasoning'] = reasoning; chat[chat.length - 1]['extra']['reasoning'] = reasoning;
chat[chat.length - 1]['extra']['reasoning_duration'] = null;
if (power_user.trim_spaces) { if (power_user.trim_spaces) {
getMessage = getMessage.trim(); getMessage = getMessage.trim();
} }

View File

@ -346,7 +346,7 @@ export class SettingsUi {
} }
async addQrSet() { async addQrSet() {
const name = await Popup.show.input('Create a new World Info', 'Enter a name for the new Quick Reply Set:'); const name = await Popup.show.input('Create a new Quick Reply Set', 'Enter a name for the new Quick Reply Set:');
if (name && name.length > 0) { if (name && name.length > 0) {
const oldQrs = QuickReplySet.get(name); const oldQrs = QuickReplySet.get(name);
if (oldQrs) { if (oldQrs) {

View File

@ -106,7 +106,7 @@ export function isHiddenReasoningModel() {
{ name: 'gemini-2.0-pro-exp', func: FUNCS.startsWith }, { name: 'gemini-2.0-pro-exp', func: FUNCS.startsWith },
]; ];
const model = getChatCompletionModel(); const model = getChatCompletionModel() || '';
const isHidden = hiddenReasoningModels.some(({ name, func }) => func(model, name)); const isHidden = hiddenReasoningModels.some(({ name, func }) => func(model, name));
return isHidden; return isHidden;

View File

@ -58,9 +58,14 @@ const OPENROUTER_PROVIDERS = [
'Minimax', 'Minimax',
'Nineteen', 'Nineteen',
'Liquid', 'Liquid',
'InferenceNet',
'Friendli',
'AionLabs',
'Alibaba',
'Nebius', 'Nebius',
'Chutes', 'Chutes',
'Kluster', 'Kluster',
'Targon',
'01.AI', '01.AI',
'HuggingFace', 'HuggingFace',
'Mancer', 'Mancer',

View File

@ -1275,7 +1275,8 @@ falai.post('/generate', jsonParser, async (request, response) => {
num_inference_steps: request.body.steps, num_inference_steps: request.body.steps,
seed: request.body.seed ?? null, seed: request.body.seed ?? null,
guidance_scale: request.body.guidance, guidance_scale: request.body.guidance,
enable_safety_checker: false, enable_safety_checker: false, // Disable general safety checks
safety_tolerance: 6 // Make Flux the least strict
}; };
console.debug('FAL.AI request:', requestBody); console.debug('FAL.AI request:', requestBody);

View File

@ -3,8 +3,12 @@ import path from 'node:path';
import url from 'node:url'; import url from 'node:url';
import express from 'express'; import express from 'express';
import { getConfigValue } from './util.js'; import { default as git } from 'simple-git';
const enableServerPlugins = getConfigValue('enableServerPlugins', false); import { sync as commandExistsSync } from 'command-exists';
import { getConfigValue, color } from './util.js';
const enableServerPlugins = !!getConfigValue('enableServerPlugins', false);
const enableServerPluginsAutoUpdate = !!getConfigValue('enableServerPluginsAutoUpdate', true);
/** /**
* Map of loaded plugins. * Map of loaded plugins.
@ -54,6 +58,8 @@ export async function loadPlugins(app, pluginsPath) {
return emptyFn; return emptyFn;
} }
await updatePlugins(pluginsPath);
for (const file of files) { for (const file of files) {
const pluginFilePath = path.join(pluginsPath, file); const pluginFilePath = path.join(pluginsPath, file);
@ -70,6 +76,10 @@ export async function loadPlugins(app, pluginsPath) {
await loadFromFile(app, pluginFilePath, exitHooks); await loadFromFile(app, pluginFilePath, exitHooks);
} }
if (loadedPlugins.size > 0) {
console.log(`${loadedPlugins.size} server plugin(s) are currently loaded. Make sure you know exactly what they do, and only install plugins from trusted sources!`);
}
// Call all plugin "exit" functions at once and wait for them to finish // Call all plugin "exit" functions at once and wait for them to finish
return () => Promise.all(exitHooks.map(exitFn => exitFn())); return () => Promise.all(exitHooks.map(exitFn => exitFn()));
} }
@ -214,3 +224,65 @@ async function initPlugin(app, plugin, exitHooks) {
return true; return true;
} }
/**
* Automatically update all git plugins in the ./plugins directory
* @param {string} pluginsPath Path to plugins directory
*/
async function updatePlugins(pluginsPath) {
if (!enableServerPluginsAutoUpdate) {
return;
}
const directories = fs.readdirSync(pluginsPath)
.filter(file => !file.startsWith('.'))
.filter(file => fs.statSync(path.join(pluginsPath, file)).isDirectory());
if (directories.length === 0) {
return;
}
console.log(color.blue('Auto-updating server plugins... Set'), color.yellow('enableServerPluginsAutoUpdate: false'), color.blue('in config.yaml to disable this feature.'));
if (!commandExistsSync('git')) {
console.error(color.red('Git is not installed. Please install Git to enable auto-updating of server plugins.'));
return;
}
let pluginsToUpdate = 0;
for (const directory of directories) {
try {
const pluginPath = path.join(pluginsPath, directory);
const pluginRepo = git(pluginPath);
const isRepo = await pluginRepo.checkIsRepo();
if (!isRepo) {
continue;
}
await pluginRepo.fetch();
const commitHash = await pluginRepo.revparse(['HEAD']);
const trackingBranch = await pluginRepo.revparse(['--abbrev-ref', '@{u}']);
const log = await pluginRepo.log({
from: commitHash,
to: trackingBranch,
});
if (log.total === 0) {
continue;
}
pluginsToUpdate++;
await pluginRepo.pull();
const latestCommit = await pluginRepo.revparse(['HEAD']);
console.log(`Plugin ${color.green(directory)} updated to commit ${color.cyan(latestCommit)}`);
} catch (error) {
console.error(color.red(`Failed to update plugin ${directory}: ${error.message}`));
}
}
if (pluginsToUpdate === 0) {
console.log('All plugins are up to date.');
}
}