mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Merge branch 'staging' into geminiStructured
This commit is contained in:
@@ -1,8 +1,6 @@
|
|||||||
# -- DATA CONFIGURATION --
|
# -- DATA CONFIGURATION --
|
||||||
# Root directory for user data storage
|
# Root directory for user data storage
|
||||||
dataRoot: ./data
|
dataRoot: ./data
|
||||||
# The maximum amount of memory that parsed character cards can use in MB
|
|
||||||
cardsCacheCapacity: 100
|
|
||||||
# -- SERVER CONFIGURATION --
|
# -- SERVER CONFIGURATION --
|
||||||
# Listen for incoming connections
|
# Listen for incoming connections
|
||||||
listen: false
|
listen: false
|
||||||
@@ -135,6 +133,14 @@ thumbnails:
|
|||||||
# Maximum thumbnail dimensions per type [width, height]
|
# Maximum thumbnail dimensions per type [width, height]
|
||||||
dimensions: { 'bg': [160, 90], 'avatar': [96, 144] }
|
dimensions: { 'bg': [160, 90], 'avatar': [96, 144] }
|
||||||
|
|
||||||
|
# PERFORMANCE-RELATED CONFIGURATION
|
||||||
|
performance:
|
||||||
|
# Enables lazy loading of character cards. Improves performances with large card libraries.
|
||||||
|
# May have compatibility issues with some extensions.
|
||||||
|
lazyLoadCharacters: false
|
||||||
|
# The maximum amount of memory that parsed character cards can use. Set to 0 to disable memory caching.
|
||||||
|
memoryCacheCapacity: '100mb'
|
||||||
|
|
||||||
# Allow secret keys exposure via API
|
# Allow secret keys exposure via API
|
||||||
allowKeysExposure: false
|
allowKeysExposure: false
|
||||||
# Skip new default content checks
|
# Skip new default content checks
|
||||||
|
34
index.d.ts
vendored
34
index.d.ts
vendored
@@ -1,8 +1,36 @@
|
|||||||
import { UserDirectoryList, User } from "./src/users";
|
import { EventEmitter } from 'node:events';
|
||||||
import { CommandLineArguments } from "./src/command-line";
|
import { CsrfSyncedToken } from 'csrf-sync';
|
||||||
import { CsrfSyncedToken } from "csrf-sync";
|
import { UserDirectoryList, User } from './src/users.js';
|
||||||
|
import { CommandLineArguments } from './src/command-line.js';
|
||||||
|
import { EVENT_NAMES } from './src/server-events.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event payload for SERVER_STARTED event.
|
||||||
|
*/
|
||||||
|
export interface ServerStartedEvent {
|
||||||
|
/**
|
||||||
|
* The URL the server is listening on.
|
||||||
|
*/
|
||||||
|
url: URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of all server events to their payload types.
|
||||||
|
*/
|
||||||
|
export interface ServerEventMap {
|
||||||
|
[EVENT_NAMES.SERVER_STARTED]: [ServerStartedEvent];
|
||||||
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
declare namespace NodeJS {
|
||||||
|
export interface Process {
|
||||||
|
/**
|
||||||
|
* A global instance of the server events emitter.
|
||||||
|
*/
|
||||||
|
serverEvents: EventEmitter<ServerEventMap>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
declare namespace CookieSessionInterfaces {
|
declare namespace CookieSessionInterfaces {
|
||||||
export interface CookieSessionObject {
|
export interface CookieSessionObject {
|
||||||
/**
|
/**
|
||||||
|
12
package-lock.json
generated
12
package-lock.json
generated
@@ -21,6 +21,7 @@
|
|||||||
"bing-translate-api": "^4.0.2",
|
"bing-translate-api": "^4.0.2",
|
||||||
"body-parser": "^1.20.2",
|
"body-parser": "^1.20.2",
|
||||||
"bowser": "^2.11.0",
|
"bowser": "^2.11.0",
|
||||||
|
"bytes": "^3.1.2",
|
||||||
"chalk": "^5.4.1",
|
"chalk": "^5.4.1",
|
||||||
"command-exists": "^1.2.9",
|
"command-exists": "^1.2.9",
|
||||||
"compression": "^1.8.0",
|
"compression": "^1.8.0",
|
||||||
@@ -83,6 +84,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/archiver": "^6.0.3",
|
"@types/archiver": "^6.0.3",
|
||||||
|
"@types/bytes": "^3.1.5",
|
||||||
"@types/command-exists": "^1.2.3",
|
"@types/command-exists": "^1.2.3",
|
||||||
"@types/compression": "^1.7.5",
|
"@types/compression": "^1.7.5",
|
||||||
"@types/cookie-parser": "^1.4.8",
|
"@types/cookie-parser": "^1.4.8",
|
||||||
@@ -1105,6 +1107,13 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/bytes": {
|
||||||
|
"version": "3.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/bytes/-/bytes-3.1.5.tgz",
|
||||||
|
"integrity": "sha512-VgZkrJckypj85YxEsEavcMmmSOIzkUHqWmM4CCyia5dc54YwsXzJ5uT4fYxBQNEXx+oF1krlhgCbvfubXqZYsQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/cacheable-request": {
|
"node_modules/@types/cacheable-request": {
|
||||||
"version": "6.0.3",
|
"version": "6.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",
|
||||||
@@ -3399,6 +3408,9 @@
|
|||||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"get-intrinsic": "^1.2.4"
|
||||||
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
"bing-translate-api": "^4.0.2",
|
"bing-translate-api": "^4.0.2",
|
||||||
"body-parser": "^1.20.2",
|
"body-parser": "^1.20.2",
|
||||||
"bowser": "^2.11.0",
|
"bowser": "^2.11.0",
|
||||||
|
"bytes": "^3.1.2",
|
||||||
"chalk": "^5.4.1",
|
"chalk": "^5.4.1",
|
||||||
"command-exists": "^1.2.9",
|
"command-exists": "^1.2.9",
|
||||||
"compression": "^1.8.0",
|
"compression": "^1.8.0",
|
||||||
@@ -92,7 +93,8 @@
|
|||||||
"version": "1.12.12",
|
"version": "1.12.12",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node server.js",
|
"start": "node server.js",
|
||||||
"debug": "node server.js --inspect",
|
"debug": "node --inspect server.js",
|
||||||
|
"electron": "electron ./src/electron",
|
||||||
"start:deno": "deno run --allow-run --allow-net --allow-read --allow-write --allow-sys --allow-env server.js",
|
"start:deno": "deno run --allow-run --allow-net --allow-read --allow-write --allow-sys --allow-env server.js",
|
||||||
"start:bun": "bun server.js",
|
"start:bun": "bun server.js",
|
||||||
"start:no-csrf": "node server.js --disableCsrf",
|
"start:no-csrf": "node server.js --disableCsrf",
|
||||||
@@ -112,6 +114,7 @@
|
|||||||
"main": "server.js",
|
"main": "server.js",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/archiver": "^6.0.3",
|
"@types/archiver": "^6.0.3",
|
||||||
|
"@types/bytes": "^3.1.5",
|
||||||
"@types/command-exists": "^1.2.3",
|
"@types/command-exists": "^1.2.3",
|
||||||
"@types/compression": "^1.7.5",
|
"@types/compression": "^1.7.5",
|
||||||
"@types/cookie-parser": "^1.4.8",
|
"@types/cookie-parser": "^1.4.8",
|
||||||
|
@@ -96,6 +96,11 @@ const keyMigrationMap = [
|
|||||||
newKey: 'logging.minLogLevel',
|
newKey: 'logging.minLogLevel',
|
||||||
migrate: (value) => value,
|
migrate: (value) => value,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
oldKey: 'cardsCacheCapacity',
|
||||||
|
newKey: 'performance.memoryCacheCapacity',
|
||||||
|
migrate: (value) => `${value}mb`,
|
||||||
|
},
|
||||||
// uncomment one release after 1.12.13
|
// uncomment one release after 1.12.13
|
||||||
/*
|
/*
|
||||||
{
|
{
|
||||||
|
@@ -1951,7 +1951,18 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="range-block" data-source="openai,cohere,mistralai,custom,claude,openrouter,groq,deepseek">
|
<div class="range-block" data-source="makersuite,openrouter">
|
||||||
|
<label for="openai_enable_web_search" class="checkbox_label flexWrap widthFreeExpand">
|
||||||
|
<input id="openai_enable_web_search" type="checkbox" />
|
||||||
|
<span data-i18n="Enable web search">Enable web search</span>
|
||||||
|
</label>
|
||||||
|
<div class="flexBasis100p toggle-description justifyLeft">
|
||||||
|
<span>
|
||||||
|
Use search capabilities provided by the backend.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="range-block" data-source="openai,cohere,mistralai,custom,claude,openrouter,groq,deepseek,makersuite">
|
||||||
<label for="openai_function_calling" class="checkbox_label flexWrap widthFreeExpand">
|
<label for="openai_function_calling" class="checkbox_label flexWrap widthFreeExpand">
|
||||||
<input id="openai_function_calling" type="checkbox" />
|
<input id="openai_function_calling" type="checkbox" />
|
||||||
<span data-i18n="Enable function calling">Enable function calling</span>
|
<span data-i18n="Enable function calling">Enable function calling</span>
|
||||||
|
@@ -453,6 +453,8 @@ export const event_types = {
|
|||||||
MESSAGE_DELETED: 'message_deleted',
|
MESSAGE_DELETED: 'message_deleted',
|
||||||
MESSAGE_UPDATED: 'message_updated',
|
MESSAGE_UPDATED: 'message_updated',
|
||||||
MESSAGE_FILE_EMBEDDED: 'message_file_embedded',
|
MESSAGE_FILE_EMBEDDED: 'message_file_embedded',
|
||||||
|
MESSAGE_REASONING_EDITED: 'message_reasoning_edited',
|
||||||
|
MESSAGE_REASONING_DELETED: 'message_reasoning_deleted',
|
||||||
MORE_MESSAGES_LOADED: 'more_messages_loaded',
|
MORE_MESSAGES_LOADED: 'more_messages_loaded',
|
||||||
IMPERSONATE_READY: 'impersonate_ready',
|
IMPERSONATE_READY: 'impersonate_ready',
|
||||||
CHAT_CHANGED: 'chat_id_changed',
|
CHAT_CHANGED: 'chat_id_changed',
|
||||||
@@ -1780,9 +1782,7 @@ export async function getCharacters() {
|
|||||||
const response = await fetch('/api/characters/all', {
|
const response = await fetch('/api/characters/all', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: getRequestHeaders(),
|
headers: getRequestHeaders(),
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({}),
|
||||||
'': '',
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
if (response.ok === true) {
|
if (response.ok === true) {
|
||||||
characters.splice(0, characters.length);
|
characters.splice(0, characters.length);
|
||||||
@@ -3678,6 +3678,9 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
|
|||||||
setGenerationProgress(0);
|
setGenerationProgress(0);
|
||||||
generation_started = new Date();
|
generation_started = new Date();
|
||||||
|
|
||||||
|
// Prevent generation from shallow characters
|
||||||
|
await unshallowCharacter(this_chid);
|
||||||
|
|
||||||
// Occurs every time, even if the generation is aborted due to slash commands execution
|
// Occurs every time, even if the generation is aborted due to slash commands execution
|
||||||
await eventSource.emit(event_types.GENERATION_STARTED, type, { automatic_trigger, force_name2, quiet_prompt, quietToLoud, skipWIAN, force_chid, signal, quietImage }, dryRun);
|
await eventSource.emit(event_types.GENERATION_STARTED, type, { automatic_trigger, force_name2, quiet_prompt, quietToLoud, skipWIAN, force_chid, signal, quietImage }, dryRun);
|
||||||
|
|
||||||
@@ -6724,9 +6727,43 @@ export function buildAvatarList(block, entities, { templateId = 'inline_avatar_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads all the data of a shallow character.
|
||||||
|
* @param {string|undefined} characterId Array index
|
||||||
|
* @returns {Promise<void>} Promise that resolves when the character is unshallowed
|
||||||
|
*/
|
||||||
|
export async function unshallowCharacter(characterId) {
|
||||||
|
if (characterId === undefined) {
|
||||||
|
console.warn('Undefined character cannot be unshallowed');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {import('./scripts/char-data.js').v1CharData} */
|
||||||
|
const character = characters[characterId];
|
||||||
|
if (!character) {
|
||||||
|
console.warn('Character not found:', characterId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Character is not shallow
|
||||||
|
if (!character.shallow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const avatar = character.avatar;
|
||||||
|
if (!avatar) {
|
||||||
|
console.warn('Character has no avatar field:', characterId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await getOneCharacter(avatar);
|
||||||
|
}
|
||||||
|
|
||||||
export async function getChat() {
|
export async function getChat() {
|
||||||
//console.log('/api/chats/get -- entered for -- ' + characters[this_chid].name);
|
//console.log('/api/chats/get -- entered for -- ' + characters[this_chid].name);
|
||||||
try {
|
try {
|
||||||
|
await unshallowCharacter(this_chid);
|
||||||
|
|
||||||
const response = await $.ajax({
|
const response = await $.ajax({
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
url: '/api/chats/get',
|
url: '/api/chats/get',
|
||||||
|
@@ -316,7 +316,10 @@ export async function favsToHotswap() {
|
|||||||
const entities = getEntitiesList({ doFilter: false });
|
const entities = getEntitiesList({ doFilter: false });
|
||||||
const container = $('#right-nav-panel .hotswap');
|
const container = $('#right-nav-panel .hotswap');
|
||||||
|
|
||||||
const favs = entities.filter(x => x.item.fav || x.item.fav == 'true');
|
// Hard limit is required because even if all hotswaps don't fit the screen, their images would still be loaded
|
||||||
|
// 25 is roughly calculated as the maximum number of favs that can fit an ultrawide monitor with the default theme
|
||||||
|
const FAVS_LIMIT = 25;
|
||||||
|
const favs = entities.filter(x => x.item.fav || x.item.fav == 'true').slice(0, FAVS_LIMIT);
|
||||||
|
|
||||||
//helpful instruction message if no characters are favorited
|
//helpful instruction message if no characters are favorited
|
||||||
if (favs.length == 0) {
|
if (favs.length == 0) {
|
||||||
|
@@ -113,5 +113,6 @@
|
|||||||
* @property {string} chat - name of the current chat file chat
|
* @property {string} chat - name of the current chat file chat
|
||||||
* @property {string} avatar - file name of the avatar image (acts as a unique identifier)
|
* @property {string} avatar - file name of the avatar image (acts as a unique identifier)
|
||||||
* @property {string} json_data - the full raw JSON data of the character
|
* @property {string} json_data - the full raw JSON data of the character
|
||||||
|
* @property {boolean?} shallow - if the data is shallow (lazy-loaded)
|
||||||
*/
|
*/
|
||||||
export default 0;// now this file is a module
|
export default 0;// now this file is a module
|
||||||
|
@@ -11,6 +11,7 @@ import {
|
|||||||
} from '../../../script.js';
|
} from '../../../script.js';
|
||||||
import { extension_settings, getContext, renderExtensionTemplateAsync } from '../../extensions.js';
|
import { extension_settings, getContext, renderExtensionTemplateAsync } from '../../extensions.js';
|
||||||
import { POPUP_RESULT, POPUP_TYPE, callGenericPopup } from '../../popup.js';
|
import { POPUP_RESULT, POPUP_TYPE, callGenericPopup } from '../../popup.js';
|
||||||
|
import { updateReasoningUI } from '../../reasoning.js';
|
||||||
import { findSecret, secret_state, writeSecret } from '../../secrets.js';
|
import { findSecret, secret_state, writeSecret } from '../../secrets.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';
|
||||||
@@ -172,21 +173,38 @@ function loadSettings() {
|
|||||||
showKeysButton();
|
showKeysButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the swipe is being generated for a message.
|
||||||
|
* @param {string|number} messageId Message ID
|
||||||
|
* @returns {boolean} Whether the swipe is being generated
|
||||||
|
*/
|
||||||
|
function isGeneratingSwipe(messageId) {
|
||||||
|
return $(`#chat .mes[mesid="${messageId}"] .mes_text`).text() === '...';
|
||||||
|
}
|
||||||
|
|
||||||
async function translateImpersonate(text) {
|
async function translateImpersonate(text) {
|
||||||
const translatedText = await translate(text, extension_settings.translate.target_language);
|
const translatedText = await translate(text, extension_settings.translate.target_language);
|
||||||
$('#send_textarea').val(translatedText);
|
$('#send_textarea').val(translatedText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translates the contents of an incoming message.
|
||||||
|
* @param {string | number} messageId Message ID
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
async function translateIncomingMessage(messageId) {
|
async function translateIncomingMessage(messageId) {
|
||||||
const context = getContext();
|
const context = getContext();
|
||||||
const message = context.chat[messageId];
|
const message = context.chat[messageId];
|
||||||
|
|
||||||
|
if (!message) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof message.extra !== 'object') {
|
if (typeof message.extra !== 'object') {
|
||||||
message.extra = {};
|
message.extra = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// New swipe is being generated. Don't translate that
|
if (isGeneratingSwipe(messageId)) {
|
||||||
if ($(`#chat .mes[mesid="${messageId}"] .mes_text`).text() == '...') {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,7 +212,36 @@ async function translateIncomingMessage(messageId) {
|
|||||||
const translation = await translate(textToTranslate, extension_settings.translate.target_language);
|
const translation = await translate(textToTranslate, extension_settings.translate.target_language);
|
||||||
message.extra.display_text = translation;
|
message.extra.display_text = translation;
|
||||||
|
|
||||||
updateMessageBlock(messageId, message);
|
updateMessageBlock(Number(messageId), message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translates the reasoning of an incoming message.
|
||||||
|
* @param {string | number} messageId
|
||||||
|
* @returns {Promise<boolean>} translated or not
|
||||||
|
*/
|
||||||
|
async function translateIncomingMessageReasoning(messageId) {
|
||||||
|
const context = getContext();
|
||||||
|
const message = context.chat[messageId];
|
||||||
|
|
||||||
|
if (!message) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof message.extra !== 'object') {
|
||||||
|
message.extra = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!message.extra.reasoning || isGeneratingSwipe(messageId)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const textToTranslate = substituteParams(message.extra.reasoning, context.name1, message.name);
|
||||||
|
const translation = await translate(textToTranslate, extension_settings.translate.target_language);
|
||||||
|
message.extra.reasoning_display_text = translation;
|
||||||
|
|
||||||
|
updateReasoningUI(Number(messageId));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function translateProviderOneRing(text, lang) {
|
async function translateProviderOneRing(text, lang) {
|
||||||
@@ -535,6 +582,7 @@ async function onTranslateChatClick() {
|
|||||||
toastr.info(`${chat.length} message(s) queued for translation.`, 'Please wait...');
|
toastr.info(`${chat.length} message(s) queued for translation.`, 'Please wait...');
|
||||||
|
|
||||||
for (let i = 0; i < chat.length; i++) {
|
for (let i = 0; i < chat.length; i++) {
|
||||||
|
await translateIncomingMessageReasoning(i);
|
||||||
await translateIncomingMessage(i);
|
await translateIncomingMessage(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -561,6 +609,7 @@ async function onTranslationsClearClick() {
|
|||||||
for (const mes of chat) {
|
for (const mes of chat) {
|
||||||
if (mes.extra) {
|
if (mes.extra) {
|
||||||
delete mes.extra.display_text;
|
delete mes.extra.display_text;
|
||||||
|
delete mes.extra.reasoning_display_text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,12 +622,47 @@ async function translateMessageEdit(messageId) {
|
|||||||
const chat = context.chat;
|
const chat = context.chat;
|
||||||
const message = chat[messageId];
|
const message = chat[messageId];
|
||||||
|
|
||||||
if (message.is_system || extension_settings.translate.auto_mode == autoModeOptions.NONE) {
|
let anyChange = false;
|
||||||
return;
|
if (message.is_system || (extension_settings.translate.auto_mode == autoModeOptions.NONE && message.extra?.display_text)) {
|
||||||
|
delete message.extra.display_text;
|
||||||
|
updateMessageBlock(messageId, message);
|
||||||
|
anyChange = true;
|
||||||
|
} else if ((message.is_user && shouldTranslate(outgoingTypes)) || (!message.is_user && shouldTranslate(incomingTypes))) {
|
||||||
|
await translateIncomingMessage(messageId);
|
||||||
|
anyChange = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((message.is_user && shouldTranslate(outgoingTypes)) || (!message.is_user && shouldTranslate(incomingTypes))) {
|
if (anyChange) {
|
||||||
await translateIncomingMessage(messageId);
|
await context.saveChat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function translateMessageReasoningEdit(messageId) {
|
||||||
|
const context = getContext();
|
||||||
|
const chat = context.chat;
|
||||||
|
const message = chat[messageId];
|
||||||
|
|
||||||
|
let anyChange = false;
|
||||||
|
if (message.is_system || (extension_settings.translate.auto_mode == autoModeOptions.NONE && message.extra?.reasoning_display_text)) {
|
||||||
|
delete message.extra.reasoning_display_text;
|
||||||
|
updateReasoningUI(Number(messageId));
|
||||||
|
anyChange = true;
|
||||||
|
} else if ((message.is_user && shouldTranslate(outgoingTypes)) || (!message.is_user && shouldTranslate(incomingTypes))) {
|
||||||
|
anyChange = await translateIncomingMessageReasoning(messageId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (anyChange) {
|
||||||
|
await context.saveChat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function removeReasoningDisplayText(messageId) {
|
||||||
|
const context = getContext();
|
||||||
|
const message = context.chat[messageId];
|
||||||
|
if (message.extra?.reasoning_display_text) {
|
||||||
|
delete message.extra.reasoning_display_text;
|
||||||
|
updateReasoningUI(Number(messageId));
|
||||||
|
await context.saveChat();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -588,22 +672,36 @@ async function onMessageTranslateClick() {
|
|||||||
const message = context.chat[messageId];
|
const message = context.chat[messageId];
|
||||||
|
|
||||||
// If the message is already translated, revert it back to the original text
|
// If the message is already translated, revert it back to the original text
|
||||||
|
let alreadyTranslated = false;
|
||||||
if (message?.extra?.display_text) {
|
if (message?.extra?.display_text) {
|
||||||
delete message.extra.display_text;
|
delete message.extra.display_text;
|
||||||
updateMessageBlock(messageId, message);
|
updateMessageBlock(Number(messageId), message);
|
||||||
|
alreadyTranslated = true;
|
||||||
}
|
}
|
||||||
|
if (message?.extra?.reasoning_display_text) {
|
||||||
|
delete message.extra.reasoning_display_text;
|
||||||
|
updateReasoningUI(Number(messageId));
|
||||||
|
alreadyTranslated = true;
|
||||||
|
}
|
||||||
|
|
||||||
// If the message is not translated, translate it
|
// If the message is not translated, translate it
|
||||||
else {
|
if (!alreadyTranslated) {
|
||||||
|
await translateIncomingMessageReasoning(messageId);
|
||||||
await translateIncomingMessage(messageId);
|
await translateIncomingMessage(messageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
await context.saveChat();
|
await context.saveChat();
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleIncomingMessage = createEventHandler(translateIncomingMessage, () => shouldTranslate(incomingTypes));
|
const handleIncomingMessage = createEventHandler(async (messageId) => {
|
||||||
|
await translateIncomingMessageReasoning(messageId);
|
||||||
|
await translateIncomingMessage(messageId);
|
||||||
|
}, () => shouldTranslate(incomingTypes));
|
||||||
const handleOutgoingMessage = createEventHandler(translateOutgoingMessage, () => shouldTranslate(outgoingTypes));
|
const handleOutgoingMessage = createEventHandler(translateOutgoingMessage, () => shouldTranslate(outgoingTypes));
|
||||||
const handleImpersonateReady = createEventHandler(translateImpersonate, () => shouldTranslate(incomingTypes));
|
const handleImpersonateReady = createEventHandler(translateImpersonate, () => shouldTranslate(incomingTypes));
|
||||||
const handleMessageEdit = createEventHandler(translateMessageEdit, () => true);
|
const handleMessageEdit = createEventHandler(translateMessageEdit, () => true);
|
||||||
|
const handleMessageReasoningEdit = createEventHandler(translateMessageReasoningEdit, () => true);
|
||||||
|
const handleMessageReasoningDelete = createEventHandler(removeReasoningDisplayText, () => true);
|
||||||
|
|
||||||
globalThis.translate = translate;
|
globalThis.translate = translate;
|
||||||
|
|
||||||
@@ -717,6 +815,8 @@ jQuery(async () => {
|
|||||||
eventSource.on(event_types.MESSAGE_SWIPED, handleIncomingMessage);
|
eventSource.on(event_types.MESSAGE_SWIPED, handleIncomingMessage);
|
||||||
eventSource.on(event_types.IMPERSONATE_READY, handleImpersonateReady);
|
eventSource.on(event_types.IMPERSONATE_READY, handleImpersonateReady);
|
||||||
eventSource.on(event_types.MESSAGE_UPDATED, handleMessageEdit);
|
eventSource.on(event_types.MESSAGE_UPDATED, handleMessageEdit);
|
||||||
|
eventSource.on(event_types.MESSAGE_REASONING_EDITED, handleMessageReasoningEdit);
|
||||||
|
eventSource.on(event_types.MESSAGE_REASONING_DELETED, handleMessageReasoningDelete);
|
||||||
|
|
||||||
document.body.classList.add('translate');
|
document.body.classList.add('translate');
|
||||||
|
|
||||||
|
@@ -72,6 +72,7 @@ import {
|
|||||||
animation_duration,
|
animation_duration,
|
||||||
depth_prompt_role_default,
|
depth_prompt_role_default,
|
||||||
shouldAutoContinue,
|
shouldAutoContinue,
|
||||||
|
unshallowCharacter,
|
||||||
} from '../script.js';
|
} from '../script.js';
|
||||||
import { printTagList, createTagMapFromList, applyTagsOnCharacterSelect, tag_map, applyTagsOnGroupSelect } from './tags.js';
|
import { printTagList, createTagMapFromList, applyTagsOnCharacterSelect, tag_map, applyTagsOnGroupSelect } from './tags.js';
|
||||||
import { FILTER_TYPES, FilterHelper } from './filters.js';
|
import { FILTER_TYPES, FilterHelper } from './filters.js';
|
||||||
@@ -216,6 +217,7 @@ export async function getGroupChat(groupId, reload = false) {
|
|||||||
|
|
||||||
// Run validation before any loading
|
// Run validation before any loading
|
||||||
validateGroup(group);
|
validateGroup(group);
|
||||||
|
await unshallowGroupMembers(groupId);
|
||||||
|
|
||||||
const chat_id = group.chat_id;
|
const chat_id = group.chat_id;
|
||||||
const data = await loadGroupChat(chat_id);
|
const data = await loadGroupChat(chat_id);
|
||||||
@@ -824,6 +826,8 @@ async function generateGroupWrapper(by_auto_mode, type = null, params = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
await unshallowGroupMembers(selected_group);
|
||||||
|
|
||||||
throwIfAborted();
|
throwIfAborted();
|
||||||
hideSwipeButtons();
|
hideSwipeButtons();
|
||||||
is_group_generating = true;
|
is_group_generating = true;
|
||||||
@@ -1137,6 +1141,29 @@ export async function editGroup(id, immediately, reload = true) {
|
|||||||
saveGroupDebounced(group, reload);
|
saveGroupDebounced(group, reload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unshallows all definitions of group members.
|
||||||
|
* @param {string} groupId Id of the group
|
||||||
|
* @returns {Promise<void>} Promise that resolves when all group members are unshallowed
|
||||||
|
*/
|
||||||
|
export async function unshallowGroupMembers(groupId) {
|
||||||
|
const group = groups.find(x => x.id == groupId);
|
||||||
|
if (!group) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const members = group.members;
|
||||||
|
if (!Array.isArray(members)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const member of members) {
|
||||||
|
const index = characters.findIndex(x => x.avatar === member);
|
||||||
|
if (index === -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
await unshallowCharacter(String(index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let groupAutoModeAbortController = null;
|
let groupAutoModeAbortController = null;
|
||||||
|
|
||||||
async function groupChatAutoModeWorker() {
|
async function groupChatAutoModeWorker() {
|
||||||
@@ -1158,9 +1185,9 @@ async function groupChatAutoModeWorker() {
|
|||||||
await generateGroupWrapper(true, 'auto', { signal: groupAutoModeAbortController.signal });
|
await generateGroupWrapper(true, 'auto', { signal: groupAutoModeAbortController.signal });
|
||||||
}
|
}
|
||||||
|
|
||||||
async function modifyGroupMember(chat_id, groupMember, isDelete) {
|
async function modifyGroupMember(groupId, groupMember, isDelete) {
|
||||||
const id = groupMember.data('id');
|
const id = groupMember.data('id');
|
||||||
const thisGroup = groups.find((x) => x.id == chat_id);
|
const thisGroup = groups.find((x) => x.id == groupId);
|
||||||
const membersArray = thisGroup?.members ?? newGroupMembers;
|
const membersArray = thisGroup?.members ?? newGroupMembers;
|
||||||
|
|
||||||
if (isDelete) {
|
if (isDelete) {
|
||||||
@@ -1173,6 +1200,7 @@ async function modifyGroupMember(chat_id, groupMember, isDelete) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (openGroupId) {
|
if (openGroupId) {
|
||||||
|
await unshallowGroupMembers(openGroupId);
|
||||||
await editGroup(openGroupId, false, false);
|
await editGroup(openGroupId, false, false);
|
||||||
updateGroupAvatar(thisGroup);
|
updateGroupAvatar(thisGroup);
|
||||||
}
|
}
|
||||||
@@ -1638,7 +1666,7 @@ async function onGroupActionClick(event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (action === 'view') {
|
if (action === 'view') {
|
||||||
openCharacterDefinition(member);
|
await openCharacterDefinition(member);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action === 'speak') {
|
if (action === 'speak') {
|
||||||
@@ -1690,7 +1718,7 @@ export async function openGroupById(groupId) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function openCharacterDefinition(characterSelect) {
|
async function openCharacterDefinition(characterSelect) {
|
||||||
if (is_group_generating) {
|
if (is_group_generating) {
|
||||||
toastr.warning(t`Can't peek a character while group reply is being generated`);
|
toastr.warning(t`Can't peek a character while group reply is being generated`);
|
||||||
console.warn('Can\'t peek a character def while group reply is being generated');
|
console.warn('Can\'t peek a character def while group reply is being generated');
|
||||||
@@ -1703,6 +1731,7 @@ function openCharacterDefinition(characterSelect) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await unshallowCharacter(chid);
|
||||||
setCharacterId(chid);
|
setCharacterId(chid);
|
||||||
select_selected_character(chid);
|
select_selected_character(chid);
|
||||||
// Gentle nudge to recalculate tokens
|
// Gentle nudge to recalculate tokens
|
||||||
|
@@ -300,6 +300,7 @@ export const settingsToUpdate = {
|
|||||||
function_calling: ['#openai_function_calling', 'function_calling', true],
|
function_calling: ['#openai_function_calling', 'function_calling', true],
|
||||||
show_thoughts: ['#openai_show_thoughts', 'show_thoughts', true],
|
show_thoughts: ['#openai_show_thoughts', 'show_thoughts', true],
|
||||||
reasoning_effort: ['#openai_reasoning_effort', 'reasoning_effort', false],
|
reasoning_effort: ['#openai_reasoning_effort', 'reasoning_effort', false],
|
||||||
|
enable_web_search: ['#openai_enable_web_search', 'enable_web_search', true],
|
||||||
seed: ['#seed_openai', 'seed', false],
|
seed: ['#seed_openai', 'seed', false],
|
||||||
n: ['#n_openai', 'n', false],
|
n: ['#n_openai', 'n', false],
|
||||||
bypass_status_check: ['#openai_bypass_status_check', 'bypass_status_check', true],
|
bypass_status_check: ['#openai_bypass_status_check', 'bypass_status_check', true],
|
||||||
@@ -380,6 +381,7 @@ const default_settings = {
|
|||||||
custom_prompt_post_processing: custom_prompt_post_processing_types.NONE,
|
custom_prompt_post_processing: custom_prompt_post_processing_types.NONE,
|
||||||
show_thoughts: true,
|
show_thoughts: true,
|
||||||
reasoning_effort: 'medium',
|
reasoning_effort: 'medium',
|
||||||
|
enable_web_search: false,
|
||||||
seed: -1,
|
seed: -1,
|
||||||
n: 1,
|
n: 1,
|
||||||
};
|
};
|
||||||
@@ -459,6 +461,7 @@ const oai_settings = {
|
|||||||
custom_prompt_post_processing: custom_prompt_post_processing_types.NONE,
|
custom_prompt_post_processing: custom_prompt_post_processing_types.NONE,
|
||||||
show_thoughts: true,
|
show_thoughts: true,
|
||||||
reasoning_effort: 'medium',
|
reasoning_effort: 'medium',
|
||||||
|
enable_web_search: false,
|
||||||
seed: -1,
|
seed: -1,
|
||||||
n: 1,
|
n: 1,
|
||||||
};
|
};
|
||||||
@@ -2000,6 +2003,7 @@ async function sendOpenAIRequest(type, messages, signal) {
|
|||||||
'group_names': getGroupNames(),
|
'group_names': getGroupNames(),
|
||||||
'include_reasoning': Boolean(oai_settings.show_thoughts),
|
'include_reasoning': Boolean(oai_settings.show_thoughts),
|
||||||
'reasoning_effort': String(oai_settings.reasoning_effort),
|
'reasoning_effort': String(oai_settings.reasoning_effort),
|
||||||
|
'enable_web_search': Boolean(oai_settings.enable_web_search),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!canMultiSwipe && ToolManager.canPerformToolCalls(type)) {
|
if (!canMultiSwipe && ToolManager.canPerformToolCalls(type)) {
|
||||||
@@ -3222,6 +3226,7 @@ function loadOpenAISettings(data, settings) {
|
|||||||
oai_settings.bypass_status_check = settings.bypass_status_check ?? default_settings.bypass_status_check;
|
oai_settings.bypass_status_check = settings.bypass_status_check ?? default_settings.bypass_status_check;
|
||||||
oai_settings.show_thoughts = settings.show_thoughts ?? default_settings.show_thoughts;
|
oai_settings.show_thoughts = settings.show_thoughts ?? default_settings.show_thoughts;
|
||||||
oai_settings.reasoning_effort = settings.reasoning_effort ?? default_settings.reasoning_effort;
|
oai_settings.reasoning_effort = settings.reasoning_effort ?? default_settings.reasoning_effort;
|
||||||
|
oai_settings.enable_web_search = settings.enable_web_search ?? default_settings.enable_web_search;
|
||||||
oai_settings.seed = settings.seed ?? default_settings.seed;
|
oai_settings.seed = settings.seed ?? default_settings.seed;
|
||||||
oai_settings.n = settings.n ?? default_settings.n;
|
oai_settings.n = settings.n ?? default_settings.n;
|
||||||
|
|
||||||
@@ -3349,6 +3354,7 @@ function loadOpenAISettings(data, settings) {
|
|||||||
$('#seed_openai').val(oai_settings.seed);
|
$('#seed_openai').val(oai_settings.seed);
|
||||||
$('#n_openai').val(oai_settings.n);
|
$('#n_openai').val(oai_settings.n);
|
||||||
$('#openai_show_thoughts').prop('checked', oai_settings.show_thoughts);
|
$('#openai_show_thoughts').prop('checked', oai_settings.show_thoughts);
|
||||||
|
$('#openai_enable_web_search').prop('checked', oai_settings.enable_web_search);
|
||||||
|
|
||||||
$('#openai_reasoning_effort').val(oai_settings.reasoning_effort);
|
$('#openai_reasoning_effort').val(oai_settings.reasoning_effort);
|
||||||
$(`#openai_reasoning_effort option[value="${oai_settings.reasoning_effort}"]`).prop('selected', true);
|
$(`#openai_reasoning_effort option[value="${oai_settings.reasoning_effort}"]`).prop('selected', true);
|
||||||
@@ -3613,6 +3619,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) {
|
|||||||
function_calling: settings.function_calling,
|
function_calling: settings.function_calling,
|
||||||
show_thoughts: settings.show_thoughts,
|
show_thoughts: settings.show_thoughts,
|
||||||
reasoning_effort: settings.reasoning_effort,
|
reasoning_effort: settings.reasoning_effort,
|
||||||
|
enable_web_search: settings.enable_web_search,
|
||||||
seed: settings.seed,
|
seed: settings.seed,
|
||||||
n: settings.n,
|
n: settings.n,
|
||||||
};
|
};
|
||||||
@@ -5572,6 +5579,11 @@ export function initOpenAI() {
|
|||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#openai_enable_web_search').on('input', function () {
|
||||||
|
oai_settings.enable_web_search = !!$(this).prop('checked');
|
||||||
|
saveSettingsDebounced();
|
||||||
|
});
|
||||||
|
|
||||||
if (!CSS.supports('field-sizing', 'content')) {
|
if (!CSS.supports('field-sizing', 'content')) {
|
||||||
$(document).on('input', '#openai_settings .autoSetHeight', function () {
|
$(document).on('input', '#openai_settings .autoSetHeight', function () {
|
||||||
resetScrollHeight($(this));
|
resetScrollHeight($(this));
|
||||||
|
@@ -167,6 +167,8 @@ export class ReasoningHandler {
|
|||||||
this.type = null;
|
this.type = null;
|
||||||
/** @type {string} The reasoning output */
|
/** @type {string} The reasoning output */
|
||||||
this.reasoning = '';
|
this.reasoning = '';
|
||||||
|
/** @type {string?} The reasoning output display in case of translate or other */
|
||||||
|
this.reasoningDisplayText = null;
|
||||||
/** @type {Date} When the reasoning started */
|
/** @type {Date} When the reasoning started */
|
||||||
this.startTime = null;
|
this.startTime = null;
|
||||||
/** @type {Date} When the reasoning ended */
|
/** @type {Date} When the reasoning ended */
|
||||||
@@ -234,6 +236,7 @@ export class ReasoningHandler {
|
|||||||
|
|
||||||
this.type = extra?.reasoning_type;
|
this.type = extra?.reasoning_type;
|
||||||
this.reasoning = extra?.reasoning ?? '';
|
this.reasoning = extra?.reasoning ?? '';
|
||||||
|
this.reasoningDisplayText = extra?.reasoning_display_text ?? null;
|
||||||
|
|
||||||
if (this.state !== ReasoningState.None) {
|
if (this.state !== ReasoningState.None) {
|
||||||
this.initialTime = new Date(chat[messageId].gen_started);
|
this.initialTime = new Date(chat[messageId].gen_started);
|
||||||
@@ -249,6 +252,7 @@ export class ReasoningHandler {
|
|||||||
this.state = this.#isHiddenReasoningModel ? ReasoningState.Thinking : ReasoningState.None;
|
this.state = this.#isHiddenReasoningModel ? ReasoningState.Thinking : ReasoningState.None;
|
||||||
this.type = null;
|
this.type = null;
|
||||||
this.reasoning = '';
|
this.reasoning = '';
|
||||||
|
this.reasoningDisplayText = null;
|
||||||
this.initialTime = new Date();
|
this.initialTime = new Date();
|
||||||
this.startTime = null;
|
this.startTime = null;
|
||||||
this.endTime = null;
|
this.endTime = null;
|
||||||
@@ -434,7 +438,7 @@ export class ReasoningHandler {
|
|||||||
setDatasetProperty(this.messageReasoningDetailsDom, 'type', this.type);
|
setDatasetProperty(this.messageReasoningDetailsDom, 'type', this.type);
|
||||||
|
|
||||||
// Update the reasoning message
|
// Update the reasoning message
|
||||||
const reasoning = trimSpaces(this.reasoning);
|
const reasoning = trimSpaces(this.reasoningDisplayText ?? this.reasoning);
|
||||||
const displayReasoning = messageFormatting(reasoning, '', false, false, messageId, {}, true);
|
const displayReasoning = messageFormatting(reasoning, '', false, false, messageId, {}, true);
|
||||||
this.messageReasoningContentDom.innerHTML = displayReasoning;
|
this.messageReasoningContentDom.innerHTML = displayReasoning;
|
||||||
|
|
||||||
@@ -888,12 +892,17 @@ function setReasoningEventHandlers() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const textarea = messageBlock.find('.reasoning_edit_textarea');
|
const textarea = messageBlock.find('.reasoning_edit_textarea');
|
||||||
updateReasoningFromValue(message, String(textarea.val()));
|
const newReasoning = String(textarea.val());
|
||||||
|
textarea.remove();
|
||||||
|
if (newReasoning === message.extra.reasoning) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateReasoningFromValue(message, newReasoning);
|
||||||
await saveChatConditional();
|
await saveChatConditional();
|
||||||
updateMessageBlock(messageId, message);
|
updateMessageBlock(messageId, message);
|
||||||
textarea.remove();
|
|
||||||
|
|
||||||
messageBlock.find('.mes_edit_done:visible').trigger('click');
|
messageBlock.find('.mes_edit_done:visible').trigger('click');
|
||||||
|
await eventSource.emit(event_types.MESSAGE_REASONING_EDITED, messageId);
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on('click', '.mes_reasoning_edit_cancel', function (e) {
|
$(document).on('click', '.mes_reasoning_edit_cancel', function (e) {
|
||||||
@@ -955,6 +964,7 @@ function setReasoningEventHandlers() {
|
|||||||
updateMessageBlock(messageId, message);
|
updateMessageBlock(messageId, message);
|
||||||
const textarea = messageBlock.find('.reasoning_edit_textarea');
|
const textarea = messageBlock.find('.reasoning_edit_textarea');
|
||||||
textarea.remove();
|
textarea.remove();
|
||||||
|
await eventSource.emit(event_types.MESSAGE_REASONING_DELETED, messageId);
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on('pointerup', '.mes_reasoning_copy', async function () {
|
$(document).on('pointerup', '.mes_reasoning_copy', async function () {
|
||||||
|
@@ -137,9 +137,14 @@ async function* parseStreamData(json) {
|
|||||||
else if (Array.isArray(json.candidates)) {
|
else if (Array.isArray(json.candidates)) {
|
||||||
for (let i = 0; i < json.candidates.length; i++) {
|
for (let i = 0; i < json.candidates.length; i++) {
|
||||||
const isNotPrimary = json.candidates?.[0]?.index > 0;
|
const isNotPrimary = json.candidates?.[0]?.index > 0;
|
||||||
|
const hasToolCalls = json?.candidates?.[0]?.content?.parts?.some(p => p?.functionCall);
|
||||||
if (isNotPrimary || json.candidates.length === 0) {
|
if (isNotPrimary || json.candidates.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (hasToolCalls) {
|
||||||
|
yield { data: json, chunk: '' };
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (typeof json.candidates[0].content === 'object' && Array.isArray(json.candidates[i].content.parts)) {
|
if (typeof json.candidates[0].content === 'object' && Array.isArray(json.candidates[i].content.parts)) {
|
||||||
for (let j = 0; j < json.candidates[i].content.parts.length; j++) {
|
for (let j = 0; j < json.candidates[i].content.parts.length; j++) {
|
||||||
if (typeof json.candidates[i].content.parts[j].text === 'string') {
|
if (typeof json.candidates[i].content.parts[j].text === 'string') {
|
||||||
|
@@ -47,6 +47,7 @@ import {
|
|||||||
updateMessageBlock,
|
updateMessageBlock,
|
||||||
printMessages,
|
printMessages,
|
||||||
clearChat,
|
clearChat,
|
||||||
|
unshallowCharacter,
|
||||||
} from '../script.js';
|
} from '../script.js';
|
||||||
import {
|
import {
|
||||||
extension_settings,
|
extension_settings,
|
||||||
@@ -55,7 +56,7 @@ import {
|
|||||||
renderExtensionTemplateAsync,
|
renderExtensionTemplateAsync,
|
||||||
writeExtensionField,
|
writeExtensionField,
|
||||||
} from './extensions.js';
|
} from './extensions.js';
|
||||||
import { groups, openGroupChat, selected_group } from './group-chats.js';
|
import { groups, openGroupChat, selected_group, unshallowGroupMembers } from './group-chats.js';
|
||||||
import { addLocaleData, getCurrentLocale, t, translate } from './i18n.js';
|
import { addLocaleData, getCurrentLocale, t, translate } from './i18n.js';
|
||||||
import { hideLoader, showLoader } from './loader.js';
|
import { hideLoader, showLoader } from './loader.js';
|
||||||
import { MacrosParser } from './macros.js';
|
import { MacrosParser } from './macros.js';
|
||||||
@@ -78,6 +79,7 @@ import { timestampToMoment, uuidv4 } from './utils.js';
|
|||||||
import { getGlobalVariable, getLocalVariable, setGlobalVariable, setLocalVariable } from './variables.js';
|
import { getGlobalVariable, getLocalVariable, setGlobalVariable, setLocalVariable } from './variables.js';
|
||||||
import { convertCharacterBook, loadWorldInfo, saveWorldInfo, updateWorldInfoList } from './world-info.js';
|
import { convertCharacterBook, loadWorldInfo, saveWorldInfo, updateWorldInfoList } from './world-info.js';
|
||||||
import { ChatCompletionService, TextCompletionService } from './custom-request.js';
|
import { ChatCompletionService, TextCompletionService } from './custom-request.js';
|
||||||
|
import { updateReasoningUI } from './reasoning.js';
|
||||||
|
|
||||||
export function getContext() {
|
export function getContext() {
|
||||||
return {
|
return {
|
||||||
@@ -210,6 +212,9 @@ export function getContext() {
|
|||||||
clearChat,
|
clearChat,
|
||||||
ChatCompletionService,
|
ChatCompletionService,
|
||||||
TextCompletionService,
|
TextCompletionService,
|
||||||
|
updateReasoningUI,
|
||||||
|
unshallowCharacter,
|
||||||
|
unshallowGroupMembers,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -506,6 +506,26 @@ export class ToolManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (Array.isArray(parsed?.candidates)) {
|
||||||
|
for (let choiceIndex = 0; choiceIndex < parsed.candidates.length; choiceIndex++) {
|
||||||
|
const candidate = parsed.candidates[choiceIndex];
|
||||||
|
if (Array.isArray(candidate?.content?.parts)) {
|
||||||
|
for (let toolCallIndex = 0; toolCallIndex < candidate.content.parts.length; toolCallIndex++) {
|
||||||
|
const part = candidate.content.parts[toolCallIndex];
|
||||||
|
if (part.functionCall) {
|
||||||
|
if (!Array.isArray(toolCalls[choiceIndex])) {
|
||||||
|
toolCalls[choiceIndex] = [];
|
||||||
|
}
|
||||||
|
if (toolCalls[choiceIndex][toolCallIndex] === undefined) {
|
||||||
|
toolCalls[choiceIndex][toolCallIndex] = {};
|
||||||
|
}
|
||||||
|
const targetToolCall = toolCalls[choiceIndex][toolCallIndex];
|
||||||
|
ToolManager.#applyToolCallDelta(targetToolCall, part.functionCall);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -564,6 +584,7 @@ export class ToolManager {
|
|||||||
chat_completion_sources.GROQ,
|
chat_completion_sources.GROQ,
|
||||||
chat_completion_sources.COHERE,
|
chat_completion_sources.COHERE,
|
||||||
chat_completion_sources.DEEPSEEK,
|
chat_completion_sources.DEEPSEEK,
|
||||||
|
chat_completion_sources.MAKERSUITE,
|
||||||
];
|
];
|
||||||
return supportedSources.includes(oai_settings.chat_completion_source);
|
return supportedSources.includes(oai_settings.chat_completion_source);
|
||||||
}
|
}
|
||||||
@@ -585,8 +606,11 @@ export class ToolManager {
|
|||||||
* @returns {any[]} Tool calls from the response data
|
* @returns {any[]} Tool calls from the response data
|
||||||
*/
|
*/
|
||||||
static #getToolCallsFromData(data) {
|
static #getToolCallsFromData(data) {
|
||||||
|
const getRandomId = () => Math.random().toString(36).substring(2);
|
||||||
const isClaudeToolCall = c => Array.isArray(c) ? c.filter(x => x).every(isClaudeToolCall) : c?.input && c?.name && c?.id;
|
const isClaudeToolCall = c => Array.isArray(c) ? c.filter(x => x).every(isClaudeToolCall) : c?.input && c?.name && c?.id;
|
||||||
|
const isGoogleToolCall = c => Array.isArray(c) ? c.filter(x => x).every(isGoogleToolCall) : c?.name && c?.args;
|
||||||
const convertClaudeToolCall = c => ({ id: c.id, function: { name: c.name, arguments: c.input } });
|
const convertClaudeToolCall = c => ({ id: c.id, function: { name: c.name, arguments: c.input } });
|
||||||
|
const convertGoogleToolCall = (c) => ({ id: getRandomId(), function: { name: c.name, arguments: c.args } });
|
||||||
|
|
||||||
// Parsed tool calls from streaming data
|
// Parsed tool calls from streaming data
|
||||||
if (Array.isArray(data) && data.length > 0 && Array.isArray(data[0])) {
|
if (Array.isArray(data) && data.length > 0 && Array.isArray(data[0])) {
|
||||||
@@ -594,6 +618,10 @@ export class ToolManager {
|
|||||||
return data[0].filter(x => x).map(convertClaudeToolCall);
|
return data[0].filter(x => x).map(convertClaudeToolCall);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isGoogleToolCall(data[0])) {
|
||||||
|
return data[0].filter(x => x).map(convertGoogleToolCall);
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof data[0]?.[0]?.tool_calls === 'object') {
|
if (typeof data[0]?.[0]?.tool_calls === 'object') {
|
||||||
return Array.isArray(data[0]?.[0]?.tool_calls) ? data[0][0].tool_calls : [data[0][0].tool_calls];
|
return Array.isArray(data[0]?.[0]?.tool_calls) ? data[0][0].tool_calls : [data[0][0].tool_calls];
|
||||||
}
|
}
|
||||||
@@ -601,6 +629,11 @@ export class ToolManager {
|
|||||||
return data[0];
|
return data[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Google AI Studio tool calls
|
||||||
|
if (Array.isArray(data?.responseContent?.parts)) {
|
||||||
|
return data.responseContent.parts.filter(p => p.functionCall).map(p => convertGoogleToolCall(p.functionCall));
|
||||||
|
}
|
||||||
|
|
||||||
// Parsed tool calls from non-streaming data
|
// Parsed tool calls from non-streaming data
|
||||||
if (Array.isArray(data?.choices)) {
|
if (Array.isArray(data?.choices)) {
|
||||||
// Find a choice with 0-index
|
// Find a choice with 0-index
|
||||||
|
@@ -20,6 +20,7 @@ import bodyParser from 'body-parser';
|
|||||||
import open from 'open';
|
import open from 'open';
|
||||||
|
|
||||||
// local library imports
|
// local library imports
|
||||||
|
import { serverEvents, EVENT_NAMES } from './src/server-events.js';
|
||||||
import { CommandLineParser } from './src/command-line.js';
|
import { CommandLineParser } from './src/command-line.js';
|
||||||
import { loadPlugins } from './src/plugin-loader.js';
|
import { loadPlugins } from './src/plugin-loader.js';
|
||||||
import {
|
import {
|
||||||
@@ -348,6 +349,7 @@ async function postSetupTasks(result) {
|
|||||||
console.log('\n' + getSeparator(plainGoToLog.length) + '\n');
|
console.log('\n' + getSeparator(plainGoToLog.length) + '\n');
|
||||||
|
|
||||||
setupLogLevel();
|
setupLogLevel();
|
||||||
|
serverEvents.emit(EVENT_NAMES.SERVER_STARTED, { url: autorunUrl });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
6
src/electron/Start.bat
Normal file
6
src/electron/Start.bat
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
@echo off
|
||||||
|
pushd %~dp0
|
||||||
|
call npm install --no-audit --no-fund --loglevel=error --no-progress --omit=dev
|
||||||
|
npm run start server.js %*
|
||||||
|
pause
|
||||||
|
popd
|
62
src/electron/index.js
Normal file
62
src/electron/index.js
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
import { app, BrowserWindow } from 'electron';
|
||||||
|
import path from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import yargs from 'yargs';
|
||||||
|
import { serverEvents, EVENT_NAMES } from '../server-events.js';
|
||||||
|
|
||||||
|
const cliArguments = yargs(process.argv)
|
||||||
|
.usage('Usage: <your-start-script> [options]')
|
||||||
|
.option('width', {
|
||||||
|
type: 'number',
|
||||||
|
default: 800,
|
||||||
|
describe: 'The width of the window',
|
||||||
|
})
|
||||||
|
.option('height', {
|
||||||
|
type: 'number',
|
||||||
|
default: 600,
|
||||||
|
describe: 'The height of the window',
|
||||||
|
})
|
||||||
|
.parseSync();
|
||||||
|
|
||||||
|
/** @type {string} The URL to load in the window. */
|
||||||
|
let appUrl;
|
||||||
|
|
||||||
|
function createSillyTavernWindow() {
|
||||||
|
if (!appUrl) {
|
||||||
|
console.error('The server has not started yet.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
new BrowserWindow({
|
||||||
|
height: cliArguments.height,
|
||||||
|
width: cliArguments.width,
|
||||||
|
}).loadURL(appUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
function startServer() {
|
||||||
|
return new Promise((_resolve, _reject) => {
|
||||||
|
serverEvents.addListener(EVENT_NAMES.SERVER_STARTED, ({ url }) => {
|
||||||
|
appUrl = url.toString();
|
||||||
|
createSillyTavernWindow();
|
||||||
|
});
|
||||||
|
const sillyTavernRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
|
||||||
|
process.chdir(sillyTavernRoot);
|
||||||
|
|
||||||
|
import('../../server.js');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
app.whenReady().then(() => {
|
||||||
|
app.on('activate', () => {
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
|
createSillyTavernWindow();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
startServer();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit();
|
||||||
|
}
|
||||||
|
});
|
802
src/electron/package-lock.json
generated
Normal file
802
src/electron/package-lock.json
generated
Normal file
@@ -0,0 +1,802 @@
|
|||||||
|
{
|
||||||
|
"name": "sillytavern-electron",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "sillytavern-electron",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "AGPL-3.0",
|
||||||
|
"dependencies": {
|
||||||
|
"electron": "^35.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@electron/get": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "^4.1.1",
|
||||||
|
"env-paths": "^2.2.0",
|
||||||
|
"fs-extra": "^8.1.0",
|
||||||
|
"got": "^11.8.5",
|
||||||
|
"progress": "^2.0.3",
|
||||||
|
"semver": "^6.2.0",
|
||||||
|
"sumchecker": "^3.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"global-agent": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sindresorhus/is": {
|
||||||
|
"version": "4.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
|
||||||
|
"integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sindresorhus/is?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@szmarczak/http-timer": {
|
||||||
|
"version": "4.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
|
||||||
|
"integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"defer-to-connect": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/cacheable-request": {
|
||||||
|
"version": "6.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",
|
||||||
|
"integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/http-cache-semantics": "*",
|
||||||
|
"@types/keyv": "^3.1.4",
|
||||||
|
"@types/node": "*",
|
||||||
|
"@types/responselike": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/http-cache-semantics": {
|
||||||
|
"version": "4.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz",
|
||||||
|
"integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@types/keyv": {
|
||||||
|
"version": "3.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz",
|
||||||
|
"integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/node": {
|
||||||
|
"version": "22.13.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.9.tgz",
|
||||||
|
"integrity": "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~6.20.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/responselike": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/yauzl": {
|
||||||
|
"version": "2.10.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
|
||||||
|
"integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/boolean": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==",
|
||||||
|
"deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"node_modules/buffer-crc32": {
|
||||||
|
"version": "0.2.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
|
||||||
|
"integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cacheable-lookup": {
|
||||||
|
"version": "5.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz",
|
||||||
|
"integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cacheable-request": {
|
||||||
|
"version": "7.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz",
|
||||||
|
"integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"clone-response": "^1.0.2",
|
||||||
|
"get-stream": "^5.1.0",
|
||||||
|
"http-cache-semantics": "^4.0.0",
|
||||||
|
"keyv": "^4.0.0",
|
||||||
|
"lowercase-keys": "^2.0.0",
|
||||||
|
"normalize-url": "^6.0.1",
|
||||||
|
"responselike": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/clone-response": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"mimic-response": "^1.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/debug": {
|
||||||
|
"version": "4.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
||||||
|
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "^2.1.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/decompress-response": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"mimic-response": "^3.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/decompress-response/node_modules/mimic-response": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/defer-to-connect": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/define-data-property": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"es-define-property": "^1.0.0",
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"gopd": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/define-properties": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"define-data-property": "^1.0.1",
|
||||||
|
"has-property-descriptors": "^1.0.0",
|
||||||
|
"object-keys": "^1.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/detect-node": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"node_modules/electron": {
|
||||||
|
"version": "35.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/electron/-/electron-35.0.0.tgz",
|
||||||
|
"integrity": "sha512-mwNQNktYLPnUWZVR8iNkfWCBjmM5e2/CmB1rhACwE9ASDbVU7CYPgp/jLUB3bj/LyQsfSuubD82OUite6SN8Uw==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@electron/get": "^2.0.0",
|
||||||
|
"@types/node": "^22.7.7",
|
||||||
|
"extract-zip": "^2.0.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"electron": "cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.20.55"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/end-of-stream": {
|
||||||
|
"version": "1.4.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
||||||
|
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"once": "^1.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/env-paths": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/es-define-property": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/es-errors": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/es6-error": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"node_modules/escape-string-regexp": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/extract-zip": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "^4.1.1",
|
||||||
|
"get-stream": "^5.1.0",
|
||||||
|
"yauzl": "^2.10.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"extract-zip": "cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.17.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@types/yauzl": "^2.9.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fd-slicer": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"pend": "~1.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fs-extra": {
|
||||||
|
"version": "8.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
|
||||||
|
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"graceful-fs": "^4.2.0",
|
||||||
|
"jsonfile": "^4.0.0",
|
||||||
|
"universalify": "^0.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6 <7 || >=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/get-stream": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"pump": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/global-agent": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"boolean": "^3.0.1",
|
||||||
|
"es6-error": "^4.1.1",
|
||||||
|
"matcher": "^3.0.0",
|
||||||
|
"roarr": "^2.15.3",
|
||||||
|
"semver": "^7.3.2",
|
||||||
|
"serialize-error": "^7.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/global-agent/node_modules/semver": {
|
||||||
|
"version": "7.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
|
||||||
|
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"optional": true,
|
||||||
|
"bin": {
|
||||||
|
"semver": "bin/semver.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/globalthis": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"define-properties": "^1.2.1",
|
||||||
|
"gopd": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/gopd": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/got": {
|
||||||
|
"version": "11.8.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz",
|
||||||
|
"integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sindresorhus/is": "^4.0.0",
|
||||||
|
"@szmarczak/http-timer": "^4.0.5",
|
||||||
|
"@types/cacheable-request": "^6.0.1",
|
||||||
|
"@types/responselike": "^1.0.0",
|
||||||
|
"cacheable-lookup": "^5.0.3",
|
||||||
|
"cacheable-request": "^7.0.2",
|
||||||
|
"decompress-response": "^6.0.0",
|
||||||
|
"http2-wrapper": "^1.0.0-beta.5.2",
|
||||||
|
"lowercase-keys": "^2.0.0",
|
||||||
|
"p-cancelable": "^2.0.0",
|
||||||
|
"responselike": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.19.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sindresorhus/got?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/graceful-fs": {
|
||||||
|
"version": "4.2.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||||
|
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/has-property-descriptors": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"es-define-property": "^1.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/http-cache-semantics": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==",
|
||||||
|
"license": "BSD-2-Clause"
|
||||||
|
},
|
||||||
|
"node_modules/http2-wrapper": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"quick-lru": "^5.1.1",
|
||||||
|
"resolve-alpn": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.19.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/json-buffer": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/json-stringify-safe": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"node_modules/jsonfile": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optionalDependencies": {
|
||||||
|
"graceful-fs": "^4.1.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/keyv": {
|
||||||
|
"version": "4.5.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||||
|
"integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"json-buffer": "3.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lowercase-keys": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/matcher": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"escape-string-regexp": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mimic-response": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ms": {
|
||||||
|
"version": "2.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/normalize-url": {
|
||||||
|
"version": "6.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
|
||||||
|
"integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/object-keys": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/once": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"wrappy": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/p-cancelable": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pend": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/progress": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pump": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"end-of-stream": "^1.1.0",
|
||||||
|
"once": "^1.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/quick-lru": {
|
||||||
|
"version": "5.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
|
||||||
|
"integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/resolve-alpn": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/responselike": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"lowercase-keys": "^2.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/roarr": {
|
||||||
|
"version": "2.15.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz",
|
||||||
|
"integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"boolean": "^3.0.1",
|
||||||
|
"detect-node": "^2.0.4",
|
||||||
|
"globalthis": "^1.0.1",
|
||||||
|
"json-stringify-safe": "^5.0.1",
|
||||||
|
"semver-compare": "^1.0.0",
|
||||||
|
"sprintf-js": "^1.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/semver": {
|
||||||
|
"version": "6.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||||
|
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"bin": {
|
||||||
|
"semver": "bin/semver.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/semver-compare": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"node_modules/serialize-error": {
|
||||||
|
"version": "7.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz",
|
||||||
|
"integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"type-fest": "^0.13.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sprintf-js": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"node_modules/sumchecker": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "^4.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/type-fest": {
|
||||||
|
"version": "0.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
|
||||||
|
"integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==",
|
||||||
|
"license": "(MIT OR CC0-1.0)",
|
||||||
|
"optional": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/undici-types": {
|
||||||
|
"version": "6.20.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
|
||||||
|
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/universalify": {
|
||||||
|
"version": "0.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||||
|
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/wrappy": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/yauzl": {
|
||||||
|
"version": "2.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
|
||||||
|
"integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"buffer-crc32": "~0.2.3",
|
||||||
|
"fd-slicer": "~1.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
src/electron/package.json
Normal file
16
src/electron/package.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "sillytavern-electron",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Electron server for SillyTavern",
|
||||||
|
"license": "AGPL-3.0",
|
||||||
|
"author": "",
|
||||||
|
"type": "module",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
"start": "electron ."
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"electron": "^35.0.0"
|
||||||
|
}
|
||||||
|
}
|
11
src/electron/start.sh
Executable file
11
src/electron/start.sh
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Make sure pwd is the directory of the script
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
|
echo "Assuming nodejs and npm is already installed. If you haven't installed them already, do so now"
|
||||||
|
echo "Installing Electron Wrapper's Node Modules..."
|
||||||
|
npm i --no-audit --no-fund --loglevel=error --no-progress --omit=dev
|
||||||
|
|
||||||
|
echo "Starting Electron Wrapper..."
|
||||||
|
npm run start -- "$@"
|
@@ -98,6 +98,21 @@ function getOpenRouterTransforms(request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets OpenRouter plugins based on the request.
|
||||||
|
* @param {import('express').Request} request
|
||||||
|
* @returns {any[]} OpenRouter plugins
|
||||||
|
*/
|
||||||
|
function getOpenRouterPlugins(request) {
|
||||||
|
const plugins = [];
|
||||||
|
|
||||||
|
if (request.body.enable_web_search) {
|
||||||
|
plugins.push({ 'id': 'web' });
|
||||||
|
}
|
||||||
|
|
||||||
|
return plugins;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a request to Claude API.
|
* Sends a request to Claude API.
|
||||||
* @param {express.Request} request Express request
|
* @param {express.Request} request Express request
|
||||||
@@ -323,6 +338,7 @@ async function sendMakerSuiteRequest(request, response) {
|
|||||||
|
|
||||||
const model = String(request.body.model);
|
const model = String(request.body.model);
|
||||||
const stream = Boolean(request.body.stream);
|
const stream = Boolean(request.body.stream);
|
||||||
|
const enableWebSearch = Boolean(request.body.enable_web_search);
|
||||||
const isThinking = model.includes('thinking');
|
const isThinking = model.includes('thinking');
|
||||||
|
|
||||||
const generationConfig = {
|
const generationConfig = {
|
||||||
@@ -350,6 +366,7 @@ async function sendMakerSuiteRequest(request, response) {
|
|||||||
model.startsWith('gemini-exp')
|
model.startsWith('gemini-exp')
|
||||||
) && request.body.use_makersuite_sysprompt;
|
) && request.body.use_makersuite_sysprompt;
|
||||||
|
|
||||||
|
const tools = [];
|
||||||
const prompt = convertGooglePrompt(request.body.messages, model, should_use_system_prompt, getPromptNames(request));
|
const prompt = convertGooglePrompt(request.body.messages, model, should_use_system_prompt, getPromptNames(request));
|
||||||
let safetySettings = GEMINI_SAFETY;
|
let safetySettings = GEMINI_SAFETY;
|
||||||
|
|
||||||
@@ -363,6 +380,26 @@ async function sendMakerSuiteRequest(request, response) {
|
|||||||
}
|
}
|
||||||
// Most of the other models allow for setting the threshold of filters, except for HARM_CATEGORY_CIVIC_INTEGRITY, to OFF.
|
// Most of the other models allow for setting the threshold of filters, except for HARM_CATEGORY_CIVIC_INTEGRITY, to OFF.
|
||||||
|
|
||||||
|
if (enableWebSearch) {
|
||||||
|
const searchTool = model.includes('1.5') || model.includes('1.0')
|
||||||
|
? ({ google_search_retrieval: {} })
|
||||||
|
: ({ google_search: {} });
|
||||||
|
tools.push(searchTool);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(request.body.tools) && request.body.tools.length > 0) {
|
||||||
|
const functionDeclarations = [];
|
||||||
|
for (const tool of request.body.tools) {
|
||||||
|
if (tool.type === 'function') {
|
||||||
|
if (tool.function.parameters?.$schema) {
|
||||||
|
delete tool.function.parameters.$schema;
|
||||||
|
}
|
||||||
|
functionDeclarations.push(tool.function);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tools.push({ function_declarations: functionDeclarations });
|
||||||
|
}
|
||||||
|
|
||||||
let body = {
|
let body = {
|
||||||
contents: prompt.contents,
|
contents: prompt.contents,
|
||||||
safetySettings: safetySettings,
|
safetySettings: safetySettings,
|
||||||
@@ -374,6 +411,10 @@ async function sendMakerSuiteRequest(request, response) {
|
|||||||
body.systemInstruction = prompt.system_instruction;
|
body.systemInstruction = prompt.system_instruction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tools.length) {
|
||||||
|
body.tools = tools;
|
||||||
|
}
|
||||||
|
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,10 +470,11 @@ async function sendMakerSuiteRequest(request, response) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const responseContent = candidates[0].content ?? candidates[0].output;
|
const responseContent = candidates[0].content ?? candidates[0].output;
|
||||||
|
const functionCall = (candidates?.[0]?.content?.parts ?? []).some(part => part.functionCall);
|
||||||
console.warn('Google AI Studio response:', responseContent);
|
console.warn('Google AI Studio response:', responseContent);
|
||||||
|
|
||||||
const responseText = typeof responseContent === 'string' ? responseContent : responseContent?.parts?.filter(part => !part.thought)?.map(part => part.text)?.join('\n\n');
|
const responseText = typeof responseContent === 'string' ? responseContent : responseContent?.parts?.filter(part => !part.thought)?.map(part => part.text)?.join('\n\n');
|
||||||
if (!responseText) {
|
if (!responseText && !functionCall) {
|
||||||
let message = 'Google AI Studio Candidate text empty';
|
let message = 'Google AI Studio Candidate text empty';
|
||||||
console.warn(message, generateResponseJson);
|
console.warn(message, generateResponseJson);
|
||||||
return response.send({ error: { message } });
|
return response.send({ error: { message } });
|
||||||
@@ -1017,6 +1059,7 @@ router.post('/generate', jsonParser, function (request, response) {
|
|||||||
headers = { ...OPENROUTER_HEADERS };
|
headers = { ...OPENROUTER_HEADERS };
|
||||||
bodyParams = {
|
bodyParams = {
|
||||||
'transforms': getOpenRouterTransforms(request),
|
'transforms': getOpenRouterTransforms(request),
|
||||||
|
'plugins': getOpenRouterPlugins(request),
|
||||||
'include_reasoning': Boolean(request.body.include_reasoning),
|
'include_reasoning': Boolean(request.body.include_reasoning),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1185,6 +1228,7 @@ router.post('/generate', jsonParser, function (request, response) {
|
|||||||
*/
|
*/
|
||||||
async function makeRequest(config, response, request, retries = 5, timeout = 5000) {
|
async function makeRequest(config, response, request, retries = 5, timeout = 5000) {
|
||||||
try {
|
try {
|
||||||
|
controller.signal.throwIfAborted();
|
||||||
const fetchResponse = await fetch(endpointUrl, config);
|
const fetchResponse = await fetch(endpointUrl, config);
|
||||||
|
|
||||||
if (request.body.stream) {
|
if (request.body.stream) {
|
||||||
|
@@ -23,12 +23,13 @@ import { invalidateThumbnail } from './thumbnails.js';
|
|||||||
import { importRisuSprites } from './sprites.js';
|
import { importRisuSprites } from './sprites.js';
|
||||||
const defaultAvatarPath = './public/img/ai4.png';
|
const defaultAvatarPath = './public/img/ai4.png';
|
||||||
|
|
||||||
// KV-store for parsed character data
|
|
||||||
const cacheCapacity = Number(getConfigValue('cardsCacheCapacity', 100, 'number')); // MB
|
|
||||||
// With 100 MB limit it would take roughly 3000 characters to reach this limit
|
// With 100 MB limit it would take roughly 3000 characters to reach this limit
|
||||||
const characterDataCache = new MemoryLimitedMap(1024 * 1024 * cacheCapacity);
|
const memoryCacheCapacity = getConfigValue('performance.memoryCacheCapacity', '100mb');
|
||||||
|
const memoryCache = new MemoryLimitedMap(memoryCacheCapacity);
|
||||||
// Some Android devices require tighter memory management
|
// Some Android devices require tighter memory management
|
||||||
const isAndroid = process.platform === 'android';
|
const isAndroid = process.platform === 'android';
|
||||||
|
// Use shallow character data for the character list
|
||||||
|
const useShallowCharacters = !!getConfigValue('performance.lazyLoadCharacters', false, 'boolean');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the character card from the specified image file.
|
* Reads the character card from the specified image file.
|
||||||
@@ -39,12 +40,12 @@ const isAndroid = process.platform === 'android';
|
|||||||
async function readCharacterData(inputFile, inputFormat = 'png') {
|
async function readCharacterData(inputFile, inputFormat = 'png') {
|
||||||
const stat = fs.statSync(inputFile);
|
const stat = fs.statSync(inputFile);
|
||||||
const cacheKey = `${inputFile}-${stat.mtimeMs}`;
|
const cacheKey = `${inputFile}-${stat.mtimeMs}`;
|
||||||
if (characterDataCache.has(cacheKey)) {
|
if (memoryCache.has(cacheKey)) {
|
||||||
return characterDataCache.get(cacheKey);
|
return memoryCache.get(cacheKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = parse(inputFile, inputFormat);
|
const result = parse(inputFile, inputFormat);
|
||||||
!isAndroid && characterDataCache.set(cacheKey, result);
|
!isAndroid && memoryCache.set(cacheKey, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,12 +61,12 @@ async function readCharacterData(inputFile, inputFormat = 'png') {
|
|||||||
async function writeCharacterData(inputFile, data, outputFile, request, crop = undefined) {
|
async function writeCharacterData(inputFile, data, outputFile, request, crop = undefined) {
|
||||||
try {
|
try {
|
||||||
// Reset the cache
|
// Reset the cache
|
||||||
for (const key of characterDataCache.keys()) {
|
for (const key of memoryCache.keys()) {
|
||||||
if (Buffer.isBuffer(inputFile)) {
|
if (Buffer.isBuffer(inputFile)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (key.startsWith(inputFile)) {
|
if (key.startsWith(inputFile)) {
|
||||||
characterDataCache.delete(key);
|
memoryCache.delete(key);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,14 +201,45 @@ const calculateDataSize = (data) => {
|
|||||||
return typeof data === 'object' ? Object.values(data).reduce((acc, val) => acc + String(val).length, 0) : 0;
|
return typeof data === 'object' ? Object.values(data).reduce((acc, val) => acc + String(val).length, 0) : 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only get fields that are used to display the character list.
|
||||||
|
* @param {object} character Character object
|
||||||
|
* @returns {{shallow: true, [key: string]: any}} Shallow character
|
||||||
|
*/
|
||||||
|
const toShallow = (character) => {
|
||||||
|
return {
|
||||||
|
shallow: true,
|
||||||
|
name: character.name,
|
||||||
|
avatar: character.avatar,
|
||||||
|
chat: character.chat,
|
||||||
|
fav: character.fav,
|
||||||
|
date_added: character.date_added,
|
||||||
|
create_date: character.create_date,
|
||||||
|
date_last_chat: character.date_last_chat,
|
||||||
|
chat_size: character.chat_size,
|
||||||
|
data_size: character.data_size,
|
||||||
|
data: {
|
||||||
|
name: _.get(character, 'data.name', ''),
|
||||||
|
character_version: _.get(character, 'data.character_version', ''),
|
||||||
|
creator: _.get(character, 'data.creator', ''),
|
||||||
|
creator_notes: _.get(character, 'data.creator_notes', ''),
|
||||||
|
extensions: {
|
||||||
|
fav: _.get(character, 'data.extensions.fav', false),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* processCharacter - Process a given character, read its data and calculate its statistics.
|
* processCharacter - Process a given character, read its data and calculate its statistics.
|
||||||
*
|
*
|
||||||
* @param {string} item The name of the character.
|
* @param {string} item The name of the character.
|
||||||
* @param {import('../users.js').UserDirectoryList} directories User directories
|
* @param {import('../users.js').UserDirectoryList} directories User directories
|
||||||
|
* @param {object} options Options for the character processing
|
||||||
|
* @param {boolean} options.shallow If true, only return the core character's metadata
|
||||||
* @return {Promise<object>} A Promise that resolves when the character processing is done.
|
* @return {Promise<object>} A Promise that resolves when the character processing is done.
|
||||||
*/
|
*/
|
||||||
const processCharacter = async (item, directories) => {
|
const processCharacter = async (item, directories, { shallow }) => {
|
||||||
try {
|
try {
|
||||||
const imgFile = path.join(directories.characters, item);
|
const imgFile = path.join(directories.characters, item);
|
||||||
const imgData = await readCharacterData(imgFile);
|
const imgData = await readCharacterData(imgFile);
|
||||||
@@ -226,7 +258,7 @@ const processCharacter = async (item, directories) => {
|
|||||||
character['chat_size'] = chatSize;
|
character['chat_size'] = chatSize;
|
||||||
character['date_last_chat'] = dateLastChat;
|
character['date_last_chat'] = dateLastChat;
|
||||||
character['data_size'] = calculateDataSize(jsonObject?.data);
|
character['data_size'] = calculateDataSize(jsonObject?.data);
|
||||||
return character;
|
return shallow ? toShallow(character) : character;
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
console.error(`Could not process character: ${item}`);
|
console.error(`Could not process character: ${item}`);
|
||||||
@@ -993,7 +1025,7 @@ router.post('/all', jsonParser, async function (request, response) {
|
|||||||
try {
|
try {
|
||||||
const files = fs.readdirSync(request.user.directories.characters);
|
const files = fs.readdirSync(request.user.directories.characters);
|
||||||
const pngFiles = files.filter(file => file.endsWith('.png'));
|
const pngFiles = files.filter(file => file.endsWith('.png'));
|
||||||
const processingPromises = pngFiles.map(file => processCharacter(file, request.user.directories));
|
const processingPromises = pngFiles.map(file => processCharacter(file, request.user.directories, { shallow: useShallowCharacters }));
|
||||||
const data = (await Promise.all(processingPromises)).filter(c => c.name);
|
const data = (await Promise.all(processingPromises)).filter(c => c.name);
|
||||||
return response.send(data);
|
return response.send(data);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -1012,7 +1044,7 @@ router.post('/get', jsonParser, validateAvatarUrlMiddleware, async function (req
|
|||||||
return response.sendStatus(404);
|
return response.sendStatus(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await processCharacter(item, request.user.directories);
|
const data = await processCharacter(item, request.user.directories, { shallow: false });
|
||||||
|
|
||||||
return response.send(data);
|
return response.send(data);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -1022,11 +1054,11 @@ router.post('/get', jsonParser, validateAvatarUrlMiddleware, async function (req
|
|||||||
});
|
});
|
||||||
|
|
||||||
router.post('/chats', jsonParser, validateAvatarUrlMiddleware, async function (request, response) {
|
router.post('/chats', jsonParser, validateAvatarUrlMiddleware, async function (request, response) {
|
||||||
|
try {
|
||||||
if (!request.body) return response.sendStatus(400);
|
if (!request.body) return response.sendStatus(400);
|
||||||
|
|
||||||
const characterDirectory = (request.body.avatar_url).replace('.png', '');
|
const characterDirectory = (request.body.avatar_url).replace('.png', '');
|
||||||
|
|
||||||
try {
|
|
||||||
const chatsDirectory = path.join(request.user.directories.chats, characterDirectory);
|
const chatsDirectory = path.join(request.user.directories.chats, characterDirectory);
|
||||||
|
|
||||||
if (!fs.existsSync(chatsDirectory)) {
|
if (!fs.existsSync(chatsDirectory)) {
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import crypto from 'node:crypto';
|
import crypto from 'node:crypto';
|
||||||
import { getConfigValue } from './util.js';
|
import { getConfigValue, tryParse } from './util.js';
|
||||||
|
|
||||||
const PROMPT_PLACEHOLDER = getConfigValue('promptPlaceholder', 'Let\'s get started.');
|
const PROMPT_PLACEHOLDER = getConfigValue('promptPlaceholder', 'Let\'s get started.');
|
||||||
|
|
||||||
@@ -411,11 +411,12 @@ export function convertGooglePrompt(messages, model, useSysPrompt, names) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const system_instruction = { parts: { text: sys_prompt.trim() } };
|
const system_instruction = { parts: { text: sys_prompt.trim() } };
|
||||||
|
const toolNameMap = {};
|
||||||
|
|
||||||
const contents = [];
|
const contents = [];
|
||||||
messages.forEach((message, index) => {
|
messages.forEach((message, index) => {
|
||||||
// fix the roles
|
// fix the roles
|
||||||
if (message.role === 'system') {
|
if (message.role === 'system' || message.role === 'tool') {
|
||||||
message.role = 'user';
|
message.role = 'user';
|
||||||
} else if (message.role === 'assistant') {
|
} else if (message.role === 'assistant') {
|
||||||
message.role = 'model';
|
message.role = 'model';
|
||||||
@@ -423,7 +424,21 @@ export function convertGooglePrompt(messages, model, useSysPrompt, names) {
|
|||||||
|
|
||||||
// Convert the content to an array of parts
|
// Convert the content to an array of parts
|
||||||
if (!Array.isArray(message.content)) {
|
if (!Array.isArray(message.content)) {
|
||||||
message.content = [{ type: 'text', text: String(message.content ?? '') }];
|
const content = (() => {
|
||||||
|
const hasToolCalls = Array.isArray(message.tool_calls) && message.tool_calls.length > 0;
|
||||||
|
const hasToolCallId = typeof message.tool_call_id === 'string' && message.tool_call_id.length > 0;
|
||||||
|
|
||||||
|
if (hasToolCalls) {
|
||||||
|
return { type: 'tool_calls', tool_calls: message.tool_calls };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasToolCallId) {
|
||||||
|
return { type: 'tool_call_id', tool_call_id: message.tool_call_id, content: String(message.content ?? '') };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { type: 'text', text: String(message.content ?? '') };
|
||||||
|
})();
|
||||||
|
message.content = [content];
|
||||||
}
|
}
|
||||||
|
|
||||||
// similar story as claude
|
// similar story as claude
|
||||||
@@ -455,6 +470,25 @@ export function convertGooglePrompt(messages, model, useSysPrompt, names) {
|
|||||||
message.content.forEach((part) => {
|
message.content.forEach((part) => {
|
||||||
if (part.type === 'text') {
|
if (part.type === 'text') {
|
||||||
parts.push({ text: part.text });
|
parts.push({ text: part.text });
|
||||||
|
} else if (part.type === 'tool_call_id') {
|
||||||
|
const name = toolNameMap[part.tool_call_id] ?? 'unknown';
|
||||||
|
parts.push({
|
||||||
|
functionResponse: {
|
||||||
|
name: name,
|
||||||
|
response: { name: name, content: part.content },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else if (part.type === 'tool_calls') {
|
||||||
|
part.tool_calls.forEach((toolCall) => {
|
||||||
|
parts.push({
|
||||||
|
functionCall: {
|
||||||
|
name: toolCall.function.name,
|
||||||
|
args: tryParse(toolCall.function.arguments) ?? toolCall.function.arguments,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
toolNameMap[toolCall.id] = toolCall.function.name;
|
||||||
|
});
|
||||||
} else if (part.type === 'image_url' && isMultimodal) {
|
} else if (part.type === 'image_url' && isMultimodal) {
|
||||||
const mimeType = part.image_url.url.split(';')[0].split(':')[1];
|
const mimeType = part.image_url.url.split(';')[0].split(':')[1];
|
||||||
const base64Data = part.image_url.url.split(',')[1];
|
const base64Data = part.image_url.url.split(',')[1];
|
||||||
@@ -473,7 +507,7 @@ export function convertGooglePrompt(messages, model, useSysPrompt, names) {
|
|||||||
if (part.text) {
|
if (part.text) {
|
||||||
contents[contents.length - 1].parts[0].text += '\n\n' + part.text;
|
contents[contents.length - 1].parts[0].text += '\n\n' + part.text;
|
||||||
}
|
}
|
||||||
if (part.inlineData) {
|
if (part.inlineData || part.functionCall || part.functionResponse) {
|
||||||
contents[contents.length - 1].parts.push(part);
|
contents[contents.length - 1].parts.push(part);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
21
src/server-events.js
Normal file
21
src/server-events.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import EventEmitter from 'node:events';
|
||||||
|
import process from 'node:process';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('../index').ServerEventMap} ServerEventMap
|
||||||
|
* @type {EventEmitter<ServerEventMap>} The default event source.
|
||||||
|
*/
|
||||||
|
export const serverEvents = new EventEmitter();
|
||||||
|
process.serverEvents = serverEvents;
|
||||||
|
export default serverEvents;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {string}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
export const EVENT_NAMES = Object.freeze({
|
||||||
|
/**
|
||||||
|
* Emitted when the server has started.
|
||||||
|
*/
|
||||||
|
SERVER_STARTED: 'server-started',
|
||||||
|
});
|
15
src/util.js
15
src/util.js
@@ -16,6 +16,7 @@ import mime from 'mime-types';
|
|||||||
import { default as simpleGit } from 'simple-git';
|
import { default as simpleGit } from 'simple-git';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import { LOG_LEVELS } from './constants.js';
|
import { LOG_LEVELS } from './constants.js';
|
||||||
|
import bytes from 'bytes';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parsed config object.
|
* Parsed config object.
|
||||||
@@ -856,14 +857,10 @@ export function setupLogLevel() {
|
|||||||
export class MemoryLimitedMap {
|
export class MemoryLimitedMap {
|
||||||
/**
|
/**
|
||||||
* Creates an instance of MemoryLimitedMap.
|
* Creates an instance of MemoryLimitedMap.
|
||||||
* @param {number} maxMemoryInBytes - The maximum allowed memory in bytes for string values.
|
* @param {string} cacheCapacity - Maximum memory usage in human-readable format (e.g., '1 GB').
|
||||||
*/
|
*/
|
||||||
constructor(maxMemoryInBytes) {
|
constructor(cacheCapacity) {
|
||||||
if (typeof maxMemoryInBytes !== 'number' || maxMemoryInBytes <= 0 || isNaN(maxMemoryInBytes)) {
|
this.maxMemory = bytes.parse(cacheCapacity) ?? 0;
|
||||||
console.warn('Invalid maxMemoryInBytes, using a fallback value of 1 GB.');
|
|
||||||
maxMemoryInBytes = 1024 * 1024 * 1024; // 1 GB
|
|
||||||
}
|
|
||||||
this.maxMemory = maxMemoryInBytes;
|
|
||||||
this.currentMemory = 0;
|
this.currentMemory = 0;
|
||||||
this.map = new Map();
|
this.map = new Map();
|
||||||
this.queue = [];
|
this.queue = [];
|
||||||
@@ -886,6 +883,10 @@ export class MemoryLimitedMap {
|
|||||||
* @param {string} value
|
* @param {string} value
|
||||||
*/
|
*/
|
||||||
set(key, value) {
|
set(key, value) {
|
||||||
|
if (this.maxMemory <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof key !== 'string' || typeof value !== 'string') {
|
if (typeof key !== 'string' || typeof value !== 'string') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user