Merge pull request #3152 from SillyTavern/getcontext-typed Add types for SillyTavern.getContext

51f89aaf7be1f8d2a71674b466f02c3be5933cac

Cohee <18619528+Cohee1207@users.noreply.github.com>

Signed
8 files changed, +234 -150Ignore whitespace
.eslintrc.cjs+1 -0
@@ -54,6 +54,7 @@ module.exports = {
5454 },
5555 // These scripts are loaded in HTML; tell ESLint not to complain about them being undefined
5656 globals: {
57+ globalThis: 'readonly',
5758 ePub: 'readonly',
5859 pdfjsLib: 'readonly',
5960 toastr: 'readonly',
public/global.d.ts+2 -1
@@ -1,4 +1,5 @@
11import libs from './lib';
2+import getContext from './scripts/st-context';
23
34// Global namespace modules
45declare var ai;
@@ -6,7 +7,7 @@ declare var pdfjsLib;
67declare var ePub;
78
89declare var SillyTavern: {
910 getContext(): anytypeof getContext;
1011 llm: any;
1112 libs: typeof libs;
1213};
public/jsconfig.json+2 -1
@@ -5,7 +5,8 @@
55 "module": "ESNext",
66 "moduleResolution": "node",
77 "allowUmdGlobalAccess": true,
88 "allowSyntheticDefaultImports": true,
9+ "strictBindCallApply": true
910 },
1011 "exclude": [
1112 "**/node_modules/**",
public/script.js+30 -127
@@ -13,7 +13,7 @@ import {
1313 default as libs,
1414} from './lib.js';
1515
1616import { humanizedDateTime, favsToHotswap, getMessageTimeStamp, dragElement, isMobile, initRossMods, shouldSendOnEnter } from './scripts/RossAscends-mods.js';
1717import { userStatsHandler, statMesProcess, initStats } from './scripts/stats.js';
1818import {
1919 generateKoboldWithStreaming,
@@ -37,8 +37,6 @@ import {
3737 parseTabbyLogprobs,
3838} from './scripts/textgen-settings.js';
3939
40-const { MANCER, TOGETHERAI, OOBA, VLLM, APHRODITE, TABBY, OLLAMA, INFERMATICAI, DREAMGEN, OPENROUTER, FEATHERLESS } = textgen_types;
41-
4240import {
4341 world_info,
4442 getWorldInfoPrompt,
@@ -67,9 +65,7 @@ import {
6765 getGroupChat,
6866 renameGroupMember,
6967 createNewGroupChat,
70- getGroupPastChats,
7168 getGroupAvatar,
72- openGroupChat,
7369 editGroup,
7470 deleteGroupChat,
7571 renameGroupChat,
@@ -173,8 +169,8 @@ import {
173169} from './scripts/utils.js';
174170import { debounce_timeout } from './scripts/constants.js';
175171
176172import { ModuleWorkerWrapper, doDailyExtensionUpdatesCheck, extension_settings, getContext, initExtensions, loadExtensionSettings, renderExtensionTemplate, renderExtensionTemplateAsync, runGenerationInterceptors, saveMetadataDebounced, writeExtensionField } from './scripts/extensions.js';
177173import { COMMENT_NAME_DEFAULT, executeSlashCommands, executeSlashCommandsOnChatInput, executeSlashCommandsWithOptions, getSlashCommandsHelp, initDefaultSlashCommands, isExecutingCommandsFromChatInput, pauseScriptExecution, processChatSlashCommands, registerSlashCommand, stopScriptExecution } from './scripts/slash-commands.js';
178174import {
179175 tag_map,
180176 tags,
@@ -224,8 +220,8 @@ import {
224220 instruct_presets,
225221 selectContextPreset,
226222} from './scripts/instruct-mode.js';
227223import { initLocales, t, translate } from './scripts/i18n.js';
228224import { getFriendlyTokenizerName, getTokenCount, getTokenCountAsync, getTokenizerModel, initTokenizers, saveTokenCache, TOKENIZER_SUPPORTED_KEY } from './scripts/tokenizers.js';
229225import {
230226 user_avatar,
231227 getUserAvatars,
@@ -241,11 +237,11 @@ import { BulkEditOverlay, CharacterContextMenu } from './scripts/BulkEditOverlay
241237import { loadFeatherlessModels, loadMancerModels, loadOllamaModels, loadTogetherAIModels, loadInfermaticAIModels, loadOpenRouterModels, loadVllmModels, loadAphroditeModels, loadDreamGenModels, initTextGenModels, loadTabbyModels } from './scripts/textgen-models.js';
242238import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, decodeStyleTags, encodeStyleTags, isExternalMediaAllowed, getCurrentEntityId, preserveNeutralChat, restoreNeutralChat } from './scripts/chats.js';
243239import { getPresetManager, initPresetManager } from './scripts/preset-manager.js';
244240import { MacrosParser, evaluateMacros, getLastMessageId, initMacros } from './scripts/macros.js';
245241import { currentUser, setUserControls } from './scripts/user.js';
246242import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup, fixToastrForDialogs } from './scripts/popup.js';
247243import { renderTemplate, renderTemplateAsync } from './scripts/templates.js';
248244import { initScrapers, ScraperManager } from './scripts/scrapers.js';
249245import { SlashCommandParser } from './scripts/slash-commands/SlashCommandParser.js';
250246import { SlashCommand } from './scripts/slash-commands/SlashCommand.js';
251247import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './scripts/slash-commands/SlashCommandArgument.js';
@@ -267,6 +263,13 @@ import { initServerHistory } from './scripts/server-history.js';
267263import { initSettingsSearch } from './scripts/setting-search.js';
268264import { initBulkEdit } from './scripts/bulk-edit.js';
269265import { deriveTemplatesFromChatTemplate } from './scripts/chat-templates.js';
266+import { getContext } from './scripts/st-context.js';
267+
268+// API OBJECT FOR EXTERNAL WIRING
269+globalThis.SillyTavern = {
270+ libs,
271+ getContext,
272+};
270273
271274//exporting functions and vars for mods
272275export {
@@ -426,10 +429,6 @@ DOMPurify.addHook('uponSanitizeElement', (node, _, config) => {
426429 }
427430});
428431
429-// API OBJECT FOR EXTERNAL WIRING
430-window['SillyTavern'] = {};
431-window['SillyTavern'].libs = libs;
432-
433432// Event source init
434433export const event_types = {
435434 APP_READY: 'app_ready',
@@ -535,7 +534,7 @@ let displayVersion = 'SillyTavern';
535534
536535let generatedPromptCache = '';
537536let generation_started = new Date();
538537/** @type {import('./scripts/char-data.js').v1CharData[]} */
539538export let characters = [];
540539export let this_chid;
541540let saveCharactersPage = 0;
@@ -811,7 +810,7 @@ export let menu_type = '';
811810export let selected_button = ''; //which button pressed
812811
813812//create pole save
814813export let create_save = {
815814 name: '',
816815 description: '',
817816 creator_notes: '',
@@ -863,7 +862,7 @@ export let amount_gen = 80; //default max length of AI generated responses
863862export let max_context = 2048;
864863
865864var swipes = true;
866865export let extension_prompts = {};
867866
868867export let main_api;// = "kobold";
869868//novel settings
@@ -1174,7 +1173,7 @@ async function getStatusTextgen() {
11741173 return resultCheckStatus();
11751174 }
11761175
11771176 if (textgen_settings.type == textgen_types.OOBA && textgen_settings.bypass_status_check) {
11781177 setOnlineStatus('Status check bypassed');
11791178 return resultCheckStatus();
11801179 }
@@ -1192,34 +1191,34 @@ async function getStatusTextgen() {
11921191
11931192 const data = await response.json();
11941193
11951194 if (textgen_settings.type === textgen_types.MANCER) {
11961195 loadMancerModels(data?.data);
11971196 setOnlineStatus(textgen_settings.mancer_model);
11981197 } else if (textgen_settings.type === textgen_types.TOGETHERAI) {
11991198 loadTogetherAIModels(data?.data);
12001199 setOnlineStatus(textgen_settings.togetherai_model);
12011200 } else if (textgen_settings.type === textgen_types.OLLAMA) {
12021201 loadOllamaModels(data?.data);
12031202 setOnlineStatus(textgen_settings.ollama_model || 'Connected');
12041203 } else if (textgen_settings.type === textgen_types.INFERMATICAI) {
12051204 loadInfermaticAIModels(data?.data);
12061205 setOnlineStatus(textgen_settings.infermaticai_model);
12071206 } else if (textgen_settings.type === textgen_types.DREAMGEN) {
12081207 loadDreamGenModels(data?.data);
12091208 setOnlineStatus(textgen_settings.dreamgen_model);
12101209 } else if (textgen_settings.type === textgen_types.OPENROUTER) {
12111210 loadOpenRouterModels(data?.data);
12121211 setOnlineStatus(textgen_settings.openrouter_model);
12131212 } else if (textgen_settings.type === textgen_types.VLLM) {
12141213 loadVllmModels(data?.data);
12151214 setOnlineStatus(textgen_settings.vllm_model);
12161215 } else if (textgen_settings.type === textgen_types.APHRODITE) {
12171216 loadAphroditeModels(data?.data);
12181217 setOnlineStatus(textgen_settings.aphrodite_model);
12191218 } else if (textgen_settings.type === textgen_types.FEATHERLESS) {
12201219 loadFeatherlessModels(data?.data);
12211220 setOnlineStatus(textgen_settings.featherless_model);
12221221 } else if (textgen_settings.type === textgen_types.TABBY) {
12231222 loadTabbyModels(data?.data);
12241223 setOnlineStatus(textgen_settings.tabby_model || data?.result);
12251224 } else {
@@ -5541,7 +5540,7 @@ function extractMultiSwipes(data, type) {
55415540 return swipes;
55425541 }
55435542
55445543 if (main_api === 'openai' || (main_api === 'textgenerationwebui' && [textgen_types.MANCER, textgen_types.VLLM, textgen_types.APHRODITE, textgen_types.TABBY, textgen_types.INFERMATICAI].includes(textgen_settings.type))) {
55455544 if (!Array.isArray(data.choices)) {
55465545 return swipes;
55475546 }
@@ -5704,7 +5703,7 @@ export function cleanUpMessage(getMessage, isImpersonate, isContinue, displayInc
57045703 return getMessage;
57055704}
57065705
57075706export async function saveReply(type, getMessage, fromStreaming, title, swipes) {
57085707 if (type != 'append' && type != 'continue' && type != 'appendFinal' && chat.length && (chat[chat.length - 1]['swipe_id'] === undefined ||
57095708 chat[chat.length - 1]['is_user'])) {
57105709 type = 'normal';
@@ -8234,102 +8233,6 @@ async function createOrEditCharacter(e) {
82348233 }
82358234}
82368235
8237-window['SillyTavern'].getContext = function () {
8238- return {
8239- chat: chat,
8240- characters: characters,
8241- groups: groups,
8242- name1: name1,
8243- name2: name2,
8244- characterId: this_chid,
8245- groupId: selected_group,
8246- chatId: selected_group
8247- ? groups.find(x => x.id == selected_group)?.chat_id
8248- : (this_chid && characters[this_chid] && characters[this_chid].chat),
8249- getCurrentChatId: getCurrentChatId,
8250- getRequestHeaders: getRequestHeaders,
8251- reloadCurrentChat: reloadCurrentChat,
8252- renameChat: renameChat,
8253- saveSettingsDebounced: saveSettingsDebounced,
8254- onlineStatus: online_status,
8255- maxContext: Number(max_context),
8256- chatMetadata: chat_metadata,
8257- streamingProcessor,
8258- eventSource: eventSource,
8259- eventTypes: event_types,
8260- addOneMessage: addOneMessage,
8261- generate: Generate,
8262- sendStreamingRequest: sendStreamingRequest,
8263- sendGenerationRequest: sendGenerationRequest,
8264- stopGeneration: stopGeneration,
8265- getTokenCount: getTokenCount,
8266- extensionPrompts: extension_prompts,
8267- setExtensionPrompt: setExtensionPrompt,
8268- updateChatMetadata: updateChatMetadata,
8269- saveChat: saveChatConditional,
8270- openCharacterChat: openCharacterChat,
8271- openGroupChat: openGroupChat,
8272- saveMetadata: saveMetadata,
8273- sendSystemMessage: sendSystemMessage,
8274- activateSendButtons,
8275- deactivateSendButtons,
8276- saveReply,
8277- substituteParams,
8278- substituteParamsExtended,
8279- SlashCommandParser,
8280- SlashCommand,
8281- SlashCommandArgument,
8282- SlashCommandNamedArgument,
8283- ARGUMENT_TYPE,
8284- executeSlashCommandsWithOptions,
8285- /** @deprecated Use SlashCommandParser.addCommandObject() instead */
8286- registerSlashCommand: registerSlashCommand,
8287- /** @deprecated Use executeSlashCommandWithOptions instead */
8288- executeSlashCommands: executeSlashCommands,
8289- timestampToMoment: timestampToMoment,
8290- /** @deprecated Handlebars for extensions are no longer supported. */
8291- registerHelper: () => { },
8292- registerMacro: MacrosParser.registerMacro.bind(MacrosParser),
8293- unregisterMacro: MacrosParser.unregisterMacro.bind(MacrosParser),
8294- registerFunctionTool: ToolManager.registerFunctionTool.bind(ToolManager),
8295- unregisterFunctionTool: ToolManager.unregisterFunctionTool.bind(ToolManager),
8296- isToolCallingSupported: ToolManager.isToolCallingSupported.bind(ToolManager),
8297- canPerformToolCalls: ToolManager.canPerformToolCalls.bind(ToolManager),
8298- registerDebugFunction: registerDebugFunction,
8299- /** @deprecated Use renderExtensionTemplateAsync instead. */
8300- renderExtensionTemplate: renderExtensionTemplate,
8301- renderExtensionTemplateAsync: renderExtensionTemplateAsync,
8302- registerDataBankScraper: ScraperManager.registerDataBankScraper,
8303- /** @deprecated Use callGenericPopup or Popup instead. */
8304- callPopup: callPopup,
8305- callGenericPopup: callGenericPopup,
8306- showLoader: showLoader,
8307- hideLoader: hideLoader,
8308- mainApi: main_api,
8309- extensionSettings: extension_settings,
8310- ModuleWorkerWrapper: ModuleWorkerWrapper,
8311- getTokenizerModel: getTokenizerModel,
8312- generateQuietPrompt: generateQuietPrompt,
8313- writeExtensionField: writeExtensionField,
8314- getThumbnailUrl: getThumbnailUrl,
8315- selectCharacterById: selectCharacterById,
8316- messageFormatting: messageFormatting,
8317- shouldSendOnEnter: shouldSendOnEnter,
8318- isMobile: isMobile,
8319- t: t,
8320- translate: translate,
8321- tags: tags,
8322- tagMap: tag_map,
8323- menuType: menu_type,
8324- createCharacterData: create_save,
8325- /** @deprecated Legacy snake-case naming, compatibility with old extensions */
8326- event_types: event_types,
8327- Popup: Popup,
8328- POPUP_TYPE: POPUP_TYPE,
8329- POPUP_RESULT: POPUP_RESULT,
8330- };
8331-};
8332-
83338236/**
83348237 * Formats a counter for a swipe view.
83358238 * @param {number} current The current number of items.
public/scripts/extensions.js+1 -1
@@ -5,6 +5,7 @@ import { showLoader } from './loader.js';
55import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js';
66import { renderTemplate, renderTemplateAsync } from './templates.js';
77import { isSubsetOf, setValueByPath } from './utils.js';
8+import { getContext } from './st-context.js';
89export {
910 getContext,
1011 getApiUrl,
@@ -174,7 +175,6 @@ const extension_settings = {
174175let modules = [];
175176let activeExtensions = new Set();
176177
177-const getContext = () => window['SillyTavern'].getContext();
178178const getApiUrl = () => extension_settings.apiUrl;
179179let connectedToApi = false;
180180
public/scripts/st-context.js+171 -0
@@ -0,0 +1,171 @@
1+import {
2+ activateSendButtons,
3+ addOneMessage,
4+ callPopup,
5+ characters,
6+ chat,
7+ chat_metadata,
8+ create_save,
9+ deactivateSendButtons,
10+ event_types,
11+ eventSource,
12+ extension_prompts,
13+ Generate,
14+ generateQuietPrompt,
15+ getCurrentChatId,
16+ getRequestHeaders,
17+ getThumbnailUrl,
18+ main_api,
19+ max_context,
20+ menu_type,
21+ messageFormatting,
22+ name1,
23+ name2,
24+ online_status,
25+ openCharacterChat,
26+ reloadCurrentChat,
27+ renameChat,
28+ saveChatConditional,
29+ saveMetadata,
30+ saveReply,
31+ saveSettingsDebounced,
32+ selectCharacterById,
33+ sendGenerationRequest,
34+ sendStreamingRequest,
35+ sendSystemMessage,
36+ setExtensionPrompt,
37+ stopGeneration,
38+ streamingProcessor,
39+ substituteParams,
40+ substituteParamsExtended,
41+ this_chid,
42+ updateChatMetadata,
43+} from '../script.js';
44+import {
45+ extension_settings,
46+ ModuleWorkerWrapper,
47+ renderExtensionTemplate,
48+ renderExtensionTemplateAsync,
49+ writeExtensionField,
50+} from './extensions.js';
51+import { groups, openGroupChat, selected_group } from './group-chats.js';
52+import { t, translate } from './i18n.js';
53+import { hideLoader, showLoader } from './loader.js';
54+import { MacrosParser } from './macros.js';
55+import { oai_settings } from './openai.js';
56+import { callGenericPopup, Popup, POPUP_RESULT, POPUP_TYPE } from './popup.js';
57+import { power_user, registerDebugFunction } from './power-user.js';
58+import { isMobile, shouldSendOnEnter } from './RossAscends-mods.js';
59+import { ScraperManager } from './scrapers.js';
60+import { executeSlashCommands, executeSlashCommandsWithOptions, registerSlashCommand } from './slash-commands.js';
61+import { SlashCommand } from './slash-commands/SlashCommand.js';
62+import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js';
63+import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
64+import { tag_map, tags } from './tags.js';
65+import { textgenerationwebui_settings } from './textgen-settings.js';
66+import { getTokenCount, getTokenCountAsync, getTokenizerModel } from './tokenizers.js';
67+import { ToolManager } from './tool-calling.js';
68+import { timestampToMoment } from './utils.js';
69+
70+export function getContext() {
71+ return {
72+ chat,
73+ characters,
74+ groups,
75+ name1,
76+ name2,
77+ characterId: this_chid,
78+ groupId: selected_group,
79+ chatId: selected_group
80+ ? groups.find(x => x.id == selected_group)?.chat_id
81+ : (characters[this_chid]?.chat),
82+ getCurrentChatId,
83+ getRequestHeaders,
84+ reloadCurrentChat,
85+ renameChat,
86+ saveSettingsDebounced,
87+ onlineStatus: online_status,
88+ maxContext: Number(max_context),
89+ chatMetadata: chat_metadata,
90+ streamingProcessor,
91+ eventSource,
92+ eventTypes: event_types,
93+ addOneMessage,
94+ generate: Generate,
95+ sendStreamingRequest,
96+ sendGenerationRequest,
97+ stopGeneration,
98+ /** @deprecated Use getTokenCountAsync instead */
99+ getTokenCount,
100+ getTokenCountAsync,
101+ extensionPrompts: extension_prompts,
102+ setExtensionPrompt,
103+ updateChatMetadata,
104+ saveChat: saveChatConditional,
105+ openCharacterChat,
106+ openGroupChat,
107+ saveMetadata,
108+ sendSystemMessage,
109+ activateSendButtons,
110+ deactivateSendButtons,
111+ saveReply,
112+ substituteParams,
113+ substituteParamsExtended,
114+ SlashCommandParser,
115+ SlashCommand,
116+ SlashCommandArgument,
117+ SlashCommandNamedArgument,
118+ ARGUMENT_TYPE,
119+ executeSlashCommandsWithOptions,
120+ /** @deprecated Use SlashCommandParser.addCommandObject() instead */
121+ registerSlashCommand,
122+ /** @deprecated Use executeSlashCommandWithOptions instead */
123+ executeSlashCommands,
124+ timestampToMoment,
125+ /** @deprecated Handlebars for extensions are no longer supported. */
126+ registerHelper: () => { },
127+ registerMacro: MacrosParser.registerMacro.bind(MacrosParser),
128+ unregisterMacro: MacrosParser.unregisterMacro.bind(MacrosParser),
129+ registerFunctionTool: ToolManager.registerFunctionTool.bind(ToolManager),
130+ unregisterFunctionTool: ToolManager.unregisterFunctionTool.bind(ToolManager),
131+ isToolCallingSupported: ToolManager.isToolCallingSupported.bind(ToolManager),
132+ canPerformToolCalls: ToolManager.canPerformToolCalls.bind(ToolManager),
133+ registerDebugFunction,
134+ /** @deprecated Use renderExtensionTemplateAsync instead. */
135+ renderExtensionTemplate,
136+ renderExtensionTemplateAsync,
137+ registerDataBankScraper: ScraperManager.registerDataBankScraper.bind(ScraperManager),
138+ /** @deprecated Use callGenericPopup or Popup instead. */
139+ callPopup,
140+ callGenericPopup,
141+ showLoader,
142+ hideLoader,
143+ mainApi: main_api,
144+ extensionSettings: extension_settings,
145+ ModuleWorkerWrapper,
146+ getTokenizerModel,
147+ generateQuietPrompt,
148+ writeExtensionField,
149+ getThumbnailUrl,
150+ selectCharacterById,
151+ messageFormatting,
152+ shouldSendOnEnter,
153+ isMobile,
154+ t,
155+ translate,
156+ tags,
157+ tagMap: tag_map,
158+ menuType: menu_type,
159+ createCharacterData: create_save,
160+ /** @deprecated Legacy snake-case naming, compatibility with old extensions */
161+ event_types: event_types,
162+ Popup,
163+ POPUP_TYPE,
164+ POPUP_RESULT,
165+ chatCompletionSettings: oai_settings,
166+ textCompletionSettings: textgenerationwebui_settings,
167+ powerUserSettings: power_user,
168+ };
169+}
170+
171+export default getContext;
public/scripts/textgen-settings.js+7 -10
@@ -18,13 +18,6 @@ import { getCurrentDreamGenModelTokenizer, getCurrentOpenRouterModelTokenizer }
1818import { ENCODE_TOKENIZERS, TEXTGEN_TOKENIZERS, getTextTokens, tokenizers } from './tokenizers.js';
1919import { getSortableDelay, onlyUnique } from './utils.js';
2020
21-export {
22- settings as textgenerationwebui_settings,
23- loadTextGenSettings,
24- generateTextGenWithStreaming,
25- formatTextGenURL,
26-};
27-
2821export const textgen_types = {
2922 OOBA: 'ooba',
3023 MANCER: 'mancer',
@@ -197,6 +190,10 @@ const settings = {
197190 featherless_model: '',
198191};
199192
193+export {
194+ settings as textgenerationwebui_settings,
195+};
196+
200197export let textgenerationwebui_banned_in_macros = [];
201198
202199export let textgenerationwebui_presets = [];
@@ -327,7 +324,7 @@ async function selectPreset(name) {
327324 saveSettingsDebounced();
328325}
329326
330327export function formatTextGenURL(value) {
331328 try {
332329 const noFormatTypes = [MANCER, TOGETHERAI, INFERMATICAI, DREAMGEN, OPENROUTER];
333330 if (noFormatTypes.includes(settings.type)) {
@@ -465,7 +462,7 @@ function calculateLogitBias() {
465462 return result;
466463}
467464
468465export function loadTextGenSettings(data, loadedSettings) {
469466 textgenerationwebui_presets = convertPresets(data.textgenerationwebui_presets);
470467 textgenerationwebui_preset_names = data.textgenerationwebui_preset_names ?? [];
471468 Object.assign(settings, loadedSettings.textgenerationwebui_settings ?? {});
@@ -889,7 +886,7 @@ function setSettingByName(setting, value, trigger) {
889886 * @returns {Promise<(function(): AsyncGenerator<{swipes: [], text: string, toolCalls: [], logprobs: {token: string, topLogprobs: Candidate[]}|null}, void, *>)|*>}
890887 * @throws {Error} - If the response status is not OK, or from within the generator
891888 */
892889export async function generateTextGenWithStreaming(generate_data, signal) {
893890 generate_data.stream = true;
894891
895892 const response = await fetch('/api/backends/text-completions/generate', {
public/scripts/tokenizers.js+20 -10
@@ -8,8 +8,6 @@ import { kai_flags } from './kai-settings.js';
88import { textgen_types, textgenerationwebui_settings as textgen_settings, getTextGenServer, getTextGenModel } from './textgen-settings.js';
99import { getCurrentDreamGenModelTokenizer, getCurrentOpenRouterModelTokenizer, openRouterModels } from './textgen-models.js';
1010
11-const { OOBA, TABBY, KOBOLDCPP, VLLM, APHRODITE, LLAMACPP, OPENROUTER, DREAMGEN } = textgen_types;
12-
1311export const CHARACTERS_PER_TOKEN_RATIO = 3.35;
1412export const TOKENIZER_WARNING_KEY = 'tokenizationWarningShown';
1513export const TOKENIZER_SUPPORTED_KEY = 'tokenizationSupported';
@@ -52,8 +50,12 @@ export const ENCODE_TOKENIZERS = [
5250 //tokenizers.NERD2,
5351];
5452
55-// A list of Text Completion sources that support remote tokenization.
53+/**
56-export const TEXTGEN_TOKENIZERS = [OOBA, TABBY, KOBOLDCPP, LLAMACPP, VLLM, APHRODITE];
54+ * A list of Text Completion sources that support remote tokenization.
55+ * Populated in initTokenziers due to circular dependencies.
56+ * @type {string[]}
57+ */
58+export const TEXTGEN_TOKENIZERS = [];
5759
5860const TOKENIZER_URLS = {
5961 [tokenizers.GPT2]: {
@@ -287,7 +289,7 @@ export function getTokenizerBestMatch(forApi) {
287289 const hasTokenizerError = sessionStorage.getItem(TOKENIZER_WARNING_KEY);
288290 const hasValidEndpoint = sessionStorage.getItem(TOKENIZER_SUPPORTED_KEY);
289291 const isConnected = online_status !== 'no_connection';
290292 const isTokenizerSupported = TEXTGEN_TOKENIZERS.includes(textgen_settings.type) && (textgen_settings.type !== textgen_types.OOBA || hasValidEndpoint);
291293
292294 if (!hasTokenizerError && isConnected) {
293295 if (forApi === 'kobold' && kai_flags.can_use_tokenization) {
@@ -297,10 +299,10 @@ export function getTokenizerBestMatch(forApi) {
297299 if (forApi === 'textgenerationwebui' && isTokenizerSupported) {
298300 return tokenizers.API_TEXTGENERATIONWEBUI;
299301 }
300302 if (forApi === 'textgenerationwebui' && textgen_settings.type === textgen_types.OPENROUTER) {
301303 return getCurrentOpenRouterModelTokenizer();
302304 }
303305 if (forApi === 'textgenerationwebui' && textgen_settings.type === textgen_types.DREAMGEN) {
304306 return getCurrentDreamGenModelTokenizer();
305307 }
306308 }
@@ -576,7 +578,7 @@ export function getTokenizerModel() {
576578
577579 // And for OpenRouter (if not a site model, then it's impossible to determine the tokenizer)
578580 if (main_api == 'openai' && oai_settings.chat_completion_source == chat_completion_sources.OPENROUTER && oai_settings.openrouter_model ||
579581 main_api == 'textgenerationwebui' && textgen_settings.type === textgen_types.OPENROUTER && textgen_settings.openrouter_model) {
580582 const model = main_api == 'openai'
581583 ? model_list.find(x => x.id === oai_settings.openrouter_model)
582584 : openRouterModels.find(x => x.id === textgen_settings.openrouter_model);
@@ -652,7 +654,7 @@ export function getTokenizerModel() {
652654 return oai_settings.custom_model;
653655 }
654656
655657 if (oai_settings.chat_completion_source === chat_completion_sources.PERPLEXITY) {
656658 if (oai_settings.perplexity_model.includes('llama-3') || oai_settings.perplexity_model.includes('llama3')) {
657659 return llama3Tokenizer;
658660 }
@@ -680,7 +682,7 @@ export function getTokenizerModel() {
680682 return yiTokenizer;
681683 }
682684
683685 if (oai_settings.chat_completion_source === chat_completion_sources.BLOCKENTROPY) {
684686 if (oai_settings.blockentropy_model.includes('llama3')) {
685687 return llama3Tokenizer;
686688 }
@@ -1121,6 +1123,14 @@ export function decodeTextTokens(tokenizerType, ids) {
11211123}
11221124
11231125export async function initTokenizers() {
1126+ TEXTGEN_TOKENIZERS.push(
1127+ textgen_types.OOBA,
1128+ textgen_types.TABBY,
1129+ textgen_types.KOBOLDCPP,
1130+ textgen_types.LLAMACPP,
1131+ textgen_types.VLLM,
1132+ textgen_types.APHRODITE,
1133+ );
11241134 await loadTokenCache();
11251135 registerDebugFunction('resetTokenCache', 'Reset token cache', 'Purges the calculated token counts. Use this if you want to force a full re-tokenization of all chats or suspect the token counts are wrong.', resetTokenCache);
11261136}