Merge branch 'staging' into gork-ai

91fc50b82da98466a96d5cbebd278d66509b7c31

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

6 files changed, +107 -29Ignore whitespace
public/index.html+1 -1
@@ -1975,7 +1975,7 @@
1975 <span data-i18n="enable_functions_desc_3">Can be utilized by various extensions to provide additional functionality.</span>1975 <span data-i18n="enable_functions_desc_3">Can be utilized by various extensions to provide additional functionality.</span>
1976 </div>1976 </div>
1977 </div>1977 </div>
1978 <div class="range-block" data-source="openai,openrouter,makersuite,claude,custom,01ai,xai">1978 <div class="range-block" data-source="openai,openrouter,mistralai,makersuite,claude,custom,01ai,xai">
1979 <label for="openai_image_inlining" class="checkbox_label flexWrap widthFreeExpand">1979 <label for="openai_image_inlining" class="checkbox_label flexWrap widthFreeExpand">
1980 <input id="openai_image_inlining" type="checkbox" />1980 <input id="openai_image_inlining" type="checkbox" />
1981 <span data-i18n="Send inline images">Send inline images</span>1981 <span data-i18n="Send inline images">Send inline images</span>
public/scripts/custom-request.js+11 -5
@@ -43,10 +43,12 @@ import EventSourceStream from './sse-stream.js';
43 * @property {boolean?} [stream=false] - Whether to stream the response43 * @property {boolean?} [stream=false] - Whether to stream the response
44 * @property {ChatCompletionMessage[]} messages - Array of chat messages44 * @property {ChatCompletionMessage[]} messages - Array of chat messages
45 * @property {string} [model] - Optional model name to use for completion45 * @property {string} [model] - Optional model name to use for completion
46 * @property {string} chat_completion_source - Source provider for chat completion46 * @property {string} chat_completion_source - Source provider
47 * @property {number} max_tokens - Maximum number of tokens to generate47 * @property {number} max_tokens - Maximum number of tokens to generate
48 * @property {number} [temperature] - Optional temperature parameter for response randomness48 * @property {number} [temperature] - Optional temperature parameter for response randomness
49 * @property {string} [custom_url] - Optional custom URL for chat completion49 * @property {string} [custom_url] - Optional custom URL
50 * @property {string} [reverse_proxy] - Optional reverse proxy URL
51 * @property {string} [proxy_password] - Optional proxy password
50 */52 */
5153
52/** @typedef {Record<string, any> & ChatCompletionPayloadBase} ChatCompletionPayload */54/** @typedef {Record<string, any> & ChatCompletionPayloadBase} ChatCompletionPayload */
@@ -80,7 +82,6 @@ export class TextCompletionService {
80 */82 */
81 static createRequestData({ stream = false, prompt, max_tokens, model, api_type, api_server, temperature, min_p, ...props }) {83 static createRequestData({ stream = false, prompt, max_tokens, model, api_type, api_server, temperature, min_p, ...props }) {
82 const payload = {84 const payload = {
83 ...props,
84 stream,85 stream,
85 prompt,86 prompt,
86 max_tokens,87 max_tokens,
@@ -90,6 +91,7 @@ export class TextCompletionService {
90 api_server: api_server ?? getTextGenServer(api_type),91 api_server: api_server ?? getTextGenServer(api_type),
91 temperature,92 temperature,
92 min_p,93 min_p,
94 ...props,
93 };95 };
9496
95 // Remove undefined values to avoid API errors97 // Remove undefined values to avoid API errors
@@ -387,9 +389,8 @@ export class ChatCompletionService {
387 * @param {ChatCompletionPayload} custom389 * @param {ChatCompletionPayload} custom
388 * @returns {ChatCompletionPayload}390 * @returns {ChatCompletionPayload}
389 */391 */
390 static createRequestData({ stream = false, messages, model, chat_completion_source, max_tokens, temperature, custom_url, ...props }) {392 static createRequestData({ stream = false, messages, model, chat_completion_source, max_tokens, temperature, custom_url, reverse_proxy, proxy_password, ...props }) {
391 const payload = {393 const payload = {
392 ...props,
393 stream,394 stream,
394 messages,395 messages,
395 model,396 model,
@@ -397,6 +398,11 @@ export class ChatCompletionService {
397 max_tokens,398 max_tokens,
398 temperature,399 temperature,
399 custom_url,400 custom_url,
401 reverse_proxy,
402 proxy_password,
403 use_makersuite_sysprompt: true,
404 claude_use_sysprompt: true,
405 ...props,
400 };406 };
401407
402 // Remove undefined values to avoid API errors408 // Remove undefined values to avoid API errors
public/scripts/extensions/shared.js+9 -2
@@ -1,7 +1,7 @@
1import { CONNECT_API_MAP, getRequestHeaders } from '../../script.js';1import { CONNECT_API_MAP, getRequestHeaders } from '../../script.js';
2import { extension_settings, openThirdPartyExtensionMenu } from '../extensions.js';2import { extension_settings, openThirdPartyExtensionMenu } from '../extensions.js';
3import { t } from '../i18n.js';3import { t } from '../i18n.js';
4import { oai_settings } from '../openai.js';4import { oai_settings, proxies } from '../openai.js';
5import { SECRET_KEYS, secret_state } from '../secrets.js';5import { SECRET_KEYS, secret_state } from '../secrets.js';
6import { textgen_types, textgenerationwebui_settings } from '../textgen-settings.js';6import { textgen_types, textgenerationwebui_settings } from '../textgen-settings.js';
7import { getTokenCountAsync } from '../tokenizers.js';7import { getTokenCountAsync } from '../tokenizers.js';
@@ -310,9 +310,10 @@ export class ConnectionManagerRequestService {
310 * @param {boolean?} [custom.includePreset=true]310 * @param {boolean?} [custom.includePreset=true]
311 * @param {boolean?} [custom.includeInstruct=true]311 * @param {boolean?} [custom.includeInstruct=true]
312 * @param {Partial<InstructSettings>?} [custom.instructSettings] Override instruct settings312 * @param {Partial<InstructSettings>?} [custom.instructSettings] Override instruct settings
313 * @param {Record<string, any>} [overridePayload] - Override payload for the request
313 * @returns {Promise<import('../custom-request.js').ExtractedData | (() => AsyncGenerator<import('../custom-request.js').StreamResponse>)>} If not streaming, returns extracted data; if streaming, returns a function that creates an AsyncGenerator314 * @returns {Promise<import('../custom-request.js').ExtractedData | (() => AsyncGenerator<import('../custom-request.js').StreamResponse>)>} If not streaming, returns extracted data; if streaming, returns a function that creates an AsyncGenerator
314 */315 */
315 static async sendRequest(profileId, prompt, maxTokens, custom = this.defaultSendRequestParams) {316 static async sendRequest(profileId, prompt, maxTokens, custom = this.defaultSendRequestParams, overridePayload = {}) {
316 const { stream, signal, extractData, includePreset, includeInstruct, instructSettings } = { ...this.defaultSendRequestParams, ...custom };317 const { stream, signal, extractData, includePreset, includeInstruct, instructSettings } = { ...this.defaultSendRequestParams, ...custom };
317318
318 const context = SillyTavern.getContext();319 const context = SillyTavern.getContext();
@@ -330,6 +331,8 @@ export class ConnectionManagerRequestService {
330 throw new Error(`API type ${selectedApiMap.selected} does not support chat completions`);331 throw new Error(`API type ${selectedApiMap.selected} does not support chat completions`);
331 }332 }
332333
334 const proxyPreset = proxies.find((p) => p.name === profile.proxy);
335
333 const messages = Array.isArray(prompt) ? prompt : [{ role: 'user', content: prompt }];336 const messages = Array.isArray(prompt) ? prompt : [{ role: 'user', content: prompt }];
334 return await context.ChatCompletionService.processRequest({337 return await context.ChatCompletionService.processRequest({
335 stream,338 stream,
@@ -338,6 +341,9 @@ export class ConnectionManagerRequestService {
338 model: profile.model,341 model: profile.model,
339 chat_completion_source: selectedApiMap.source,342 chat_completion_source: selectedApiMap.source,
340 custom_url: profile['api-url'],343 custom_url: profile['api-url'],
344 reverse_proxy: proxyPreset?.url,
345 proxy_password: proxyPreset?.password,
346 ...overridePayload,
341 }, {347 }, {
342 presetName: includePreset ? profile.preset : undefined,348 presetName: includePreset ? profile.preset : undefined,
343 }, extractData, signal);349 }, extractData, signal);
@@ -354,6 +360,7 @@ export class ConnectionManagerRequestService {
354 model: profile.model,360 model: profile.model,
355 api_type: selectedApiMap.type,361 api_type: selectedApiMap.type,
356 api_server: profile['api-url'],362 api_server: profile['api-url'],
363 ...overridePayload,
357 }, {364 }, {
358 instructName: includeInstruct ? profile.instruct : undefined,365 instructName: includeInstruct ? profile.instruct : undefined,
359 presetName: includePreset ? profile.preset : undefined,366 presetName: includePreset ? profile.preset : undefined,
public/scripts/openai.js+79 -20
@@ -4193,6 +4193,80 @@ function getMaxContextWindowAI(value) {
4193}4193}
41944194
4195/**4195/**
4196 * Get the maximum context size for the Mistral model
4197 * @param {string} model Model identifier
4198 * @param {boolean} isUnlocked Whether context limits are unlocked
4199 * @returns {number} Maximum context size in tokens
4200 */
4201function getMistralMaxContext(model, isUnlocked) {
4202 if (isUnlocked) {
4203 return unlocked_max;
4204 }
4205
4206 if (Array.isArray(model_list) && model_list.length > 0) {
4207 const contextLength = model_list.find((record) => record.id === model)?.max_context_length;
4208 if (contextLength) {
4209 return contextLength;
4210 }
4211 }
4212
4213 const contextMap = {
4214 'codestral-2411-rc5': 262144,
4215 'codestral-2412': 262144,
4216 'codestral-2501': 262144,
4217 'codestral-latest': 262144,
4218 'codestral-mamba-2407': 262144,
4219 'codestral-mamba-latest': 262144,
4220 'open-codestral-mamba': 262144,
4221 'ministral-3b-2410': 131072,
4222 'ministral-3b-latest': 131072,
4223 'ministral-8b-2410': 131072,
4224 'ministral-8b-latest': 131072,
4225 'mistral-large-2407': 131072,
4226 'mistral-large-2411': 131072,
4227 'mistral-large-latest': 131072,
4228 'mistral-large-pixtral-2411': 131072,
4229 'mistral-tiny-2407': 131072,
4230 'mistral-tiny-latest': 131072,
4231 'open-mistral-nemo': 131072,
4232 'open-mistral-nemo-2407': 131072,
4233 'pixtral-12b': 131072,
4234 'pixtral-12b-2409': 131072,
4235 'pixtral-12b-latest': 131072,
4236 'pixtral-large-2411': 131072,
4237 'pixtral-large-latest': 131072,
4238 'open-mixtral-8x22b': 65536,
4239 'open-mixtral-8x22b-2404': 65536,
4240 'codestral-2405': 32768,
4241 'mistral-embed': 32768,
4242 'mistral-large-2402': 32768,
4243 'mistral-medium': 32768,
4244 'mistral-medium-2312': 32768,
4245 'mistral-medium-latest': 32768,
4246 'mistral-moderation-2411': 32768,
4247 'mistral-moderation-latest': 32768,
4248 'mistral-ocr-2503': 32768,
4249 'mistral-ocr-latest': 32768,
4250 'mistral-saba-2502': 32768,
4251 'mistral-saba-latest': 32768,
4252 'mistral-small': 32768,
4253 'mistral-small-2312': 32768,
4254 'mistral-small-2402': 32768,
4255 'mistral-small-2409': 32768,
4256 'mistral-small-2501': 32768,
4257 'mistral-small-2503': 32768,
4258 'mistral-small-latest': 32768,
4259 'mistral-tiny': 32768,
4260 'mistral-tiny-2312': 32768,
4261 'open-mistral-7b': 32768,
4262 'open-mixtral-8x7b': 32768,
4263 };
4264
4265 // Return context size if model found, otherwise default to 32k
4266 return Object.entries(contextMap).find(([key]) => model.includes(key))?.[1] || 32768;
4267}
4268
4269/**
4196 * Get the maximum context size for the Groq model4270 * Get the maximum context size for the Groq model
4197 * @param {string} model Model identifier4271 * @param {string} model Model identifier
4198 * @param {boolean} isUnlocked Whether context limits are unlocked4272 * @param {boolean} isUnlocked Whether context limits are unlocked
@@ -4460,27 +4534,10 @@ async function onModelChange() {
4460 }4534 }
44614535
4462 if (oai_settings.chat_completion_source === chat_completion_sources.MISTRALAI) {4536 if (oai_settings.chat_completion_source === chat_completion_sources.MISTRALAI) {
4463 if (oai_settings.max_context_unlocked) {4537 const maxContext = getMistralMaxContext(oai_settings.mistralai_model, oai_settings.max_context_unlocked);
4464 $('#openai_max_context').attr('max', unlocked_max);4538 $('#openai_max_context').attr('max', maxContext);
4465 } else if (['codestral-latest', 'codestral-mamba-2407', 'codestral-2411-rc5', 'codestral-2412', 'codestral-2501'].includes(oai_settings.mistralai_model)) {
4466 $('#openai_max_context').attr('max', max_256k);
4467 } else if (['mistral-large-2407', 'mistral-large-2411', 'mistral-large-pixtral-2411', 'mistral-large-latest'].includes(oai_settings.mistralai_model)) {
4468 $('#openai_max_context').attr('max', max_128k);
4469 } else if (oai_settings.mistralai_model.includes('mistral-nemo')) {
4470 $('#openai_max_context').attr('max', max_128k);
4471 } else if (oai_settings.mistralai_model.includes('mixtral-8x22b')) {
4472 $('#openai_max_context').attr('max', max_64k);
4473 } else if (oai_settings.mistralai_model.includes('pixtral')) {
4474 $('#openai_max_context').attr('max', max_128k);
4475 } else if (oai_settings.mistralai_model.includes('ministral')) {
4476 $('#openai_max_context').attr('max', max_32k);
4477 } else {
4478 $('#openai_max_context').attr('max', max_32k);
4479 }
4480 oai_settings.openai_max_context = Math.min(oai_settings.openai_max_context, Number($('#openai_max_context').attr('max')));4539 oai_settings.openai_max_context = Math.min(oai_settings.openai_max_context, Number($('#openai_max_context').attr('max')));
4481 $('#openai_max_context').val(oai_settings.openai_max_context).trigger('input');4540 $('#openai_max_context').val(oai_settings.openai_max_context).trigger('input');
4482
4483 //mistral also caps temp at 1.0
4484 oai_settings.temp_openai = Math.min(claude_max_temp, oai_settings.temp_openai);4541 oai_settings.temp_openai = Math.min(claude_max_temp, oai_settings.temp_openai);
4485 $('#temp_openai').attr('max', claude_max_temp).val(oai_settings.temp_openai).trigger('input');4542 $('#temp_openai').attr('max', claude_max_temp).val(oai_settings.temp_openai).trigger('input');
4486 }4543 }
@@ -5070,7 +5127,9 @@ export function isImageInliningSupported() {
5070 'o1-2024-12-17',5127 'o1-2024-12-17',
5071 'chatgpt-4o-latest',5128 'chatgpt-4o-latest',
5072 'yi-vision',5129 'yi-vision',
5073 'pixtral-latest',5130 'mistral-large-pixtral-2411',
5131 'mistral-small-2503',
5132 'mistral-small-latest',
5074 'pixtral-12b-latest',5133 'pixtral-12b-latest',
5075 'pixtral-12b',5134 'pixtral-12b',
5076 'pixtral-12b-2409',5135 'pixtral-12b-2409',
public/scripts/textgen-models.js+5 -0
@@ -58,6 +58,8 @@ const OPENROUTER_PROVIDERS = [
58 'Minimax',58 'Minimax',
59 'Nineteen',59 'Nineteen',
60 'Liquid',60 'Liquid',
61 'Stealth',
62 'NCompass',
61 'InferenceNet',63 'InferenceNet',
62 'Friendli',64 'Friendli',
63 'AionLabs',65 'AionLabs',
@@ -69,6 +71,9 @@ const OPENROUTER_PROVIDERS = [
69 'Targon',71 'Targon',
70 'Ubicloud',72 'Ubicloud',
71 'Parasail',73 'Parasail',
74 'Phala',
75 'Cent-ML',
76 'Venice',
72 '01.AI',77 '01.AI',
73 'HuggingFace',78 'HuggingFace',
74 'Mancer',79 'Mancer',
src/endpoints/stable-diffusion.js+2 -1
@@ -1166,7 +1166,8 @@ falai.post('/models', async (_request, response) => {
1166 const models = data1166 const models = data
1167 .filter(x => !x.title.toLowerCase().includes('inpainting') &&1167 .filter(x => !x.title.toLowerCase().includes('inpainting') &&
1168 !x.title.toLowerCase().includes('control') &&1168 !x.title.toLowerCase().includes('control') &&
1169 !x.title.toLowerCase().includes('upscale'))1169 !x.title.toLowerCase().includes('upscale') &&
1170 !x.title.toLowerCase().includes('lora'))
1170 .sort((a, b) => a.title.localeCompare(b.title))1171 .sort((a, b) => a.title.localeCompare(b.title))
1171 .map(x => ({ value: x.modelUrl.split('fal-ai/')[1], text: x.title }));1172 .map(x => ({ value: x.modelUrl.split('fal-ai/')[1], text: x.title }));
1172 return response.send(models);1173 return response.send(models);