Merge branch 'staging' of https://github.com/joenunezb/SillyTavern into optimize/improve-search
| @@ -229,6 +229,46 @@ SillyTavern сохраняет ключи от ваших API в файле `sec | ||
| 229 | 229 | 1. Зайдите в файл `config.yaml` и установите `allowKeysExposure` в положение `true`. |
| 230 | 230 | 2. Перезапустите сервер SillyTavern. |
| 231 | 231 | |
| 232 | +## Аргументы командной строки | |
| 233 | + | |
| 234 | +Вы можете передавать аргументы командной строки при запуске сервера SillyTavern, чтобы переопределять настройки из `config.yaml`. | |
| 235 | + | |
| 236 | +### Примеры | |
| 237 | + | |
| 238 | +```shell | |
| 239 | +node server.js --port 8000 --listen false | |
| 240 | +# или | |
| 241 | +npm run start -- --port 8000 --listen false | |
| 242 | +# или (только на Windows) | |
| 243 | +Start.bat --port 8000 --listen false | |
| 244 | +``` | |
| 245 | + | |
| 246 | +### Поддерживаемые аргументы | |
| 247 | + | |
| 248 | +| Аргумент | Описание | Тип | | |
| 249 | +|-------------------------|----------------------------------------------------------------------------------------------------------------|----------| | |
| 250 | +| `--version` | Показывает номер версии. | boolean | | |
| 251 | +| `--enableIPv6` | Включает IPv6. | boolean | | |
| 252 | +| `--enableIPv4` | Включает IPv4. | boolean | | |
| 253 | +| `--port` | Устанавливает порт, котрый будет использовать SillyTavern. Если не указан, то используется yaml-конфиг 'port'. | number | | |
| 254 | +| `--dnsPreferIPv6` | Отдает предпочтение IPv6 для dns. Если не указан, то используется yaml-конфиг 'preferIPv6'. | boolean | | |
| 255 | +| `--autorun` | Автоматический запуск SillyTavern в браузере. Если не указан, то используется yaml-конфиг 'autorun'. | boolean | | |
| 256 | +| `--autorunHostname` | Имя хоста автозапуска, лучше оставить на 'auto'. | string | | |
| 257 | +| `--autorunPortOverride` | Переопределяет порт для автозапуска. | string | | |
| 258 | +| `--listen` | SillyTavern будет прослушивать все сетевые интерфейсы. Если не указан, то используется yaml-конфиг 'listen'. | boolean | | |
| 259 | +| `--corsProxy` | Включает CORS-прокси. Если не указан, то используется yaml-конфиг 'enableCorsProxy'. | boolean | | |
| 260 | +| `--disableCsrf` | Отключает защиту от CSRF. | boolean | | |
| 261 | +| `--ssl` | Включает SSL. | boolean | | |
| 262 | +| `--certPath` | Путь к файлу c сертификатом. | string | | |
| 263 | +| `--keyPath` | Путь к файлу с закрытым ключом. | string | | |
| 264 | +| `--whitelist` | Включает режим белого списка. | boolean | | |
| 265 | +| `--dataRoot` | Корневой каталог для хранения данных. | string | | |
| 266 | +| `--avoidLocalhost` | Избегает использования 'localhost' для автозапуска в режиме 'auto'. | boolean | | |
| 267 | +| `--basicAuthMode` | Включает простую аутентификацию. | boolean | | |
| 268 | +| `--requestProxyEnabled` | Разрешает использование прокси для исходящих запросов. | boolean | | |
| 269 | +| `--requestProxyUrl` | URL-адрес прокси (протоколы HTTP или SOCKS). | string | | |
| 270 | +| `--requestProxyBypass` | Bypass список прокси (список хостов, разделенных пробелами). | array | | |
| 271 | + | |
| 232 | 272 | ## Удалённое подключение |
| 233 | 273 | |
| 234 | 274 | В основном этим пользуются тогда, когда хотят использовать SillyTavern с телефона, запустив сервер SillyTavern на стационарном ПК в той же Wi-Fi-сети. |
| @@ -230,7 +230,6 @@ | ||
| 230 | 230 | "show_external_models": false, |
| 231 | 231 | "assistant_prefill": "", |
| 232 | 232 | "assistant_impersonation": "", |
| 233 | - "human_sysprompt_message": "Let's get started. Please generate your response based on the information and instructions provided above.", | |
| 234 | 233 | "claude_use_sysprompt": false, |
| 235 | 234 | "use_alt_scale": false, |
| 236 | 235 | "squash_system_messages": false, |
| @@ -1291,6 +1291,14 @@ | ||
| 1291 | 1291 | <input class="neo-range-slider" type="range" id="epsilon_cutoff_textgenerationwebui" name="volume" min="0" max="9" step="0.01"> |
| 1292 | 1292 | <input class="neo-range-input" type="number" min="0" max="9" step="0.01" data-for="epsilon_cutoff_textgenerationwebui" id="epsilon_cutoff_counter_textgenerationwebui"> |
| 1293 | 1293 | </div> |
| 1294 | + <div data-tg-type="aphrodite" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0"> | |
| 1295 | + <small> | |
| 1296 | + <span data-i18n="Top nsigma">Top nsigma</span> | |
| 1297 | + <div class="fa-solid fa-circle-info opacity50p" title="A sampling method that filters logits based on their statistical properties. It keeps tokens within n standard deviations of the maximum logit value, providing a simpler alternative to top-p/top-k sampling while maintaining sampling stability across different temperatures."></div> | |
| 1298 | + </small> | |
| 1299 | + <input class="neo-range-slider" type="range" id="nsigma_textgenerationwebui" name="volume" min="0" max="5" step="0.01"> | |
| 1300 | + <input class="neo-range-input" type="number" min="0" max="5" step="0.01" data-for="nsigma_textgenerationwebui" id="nsigma_counter_textgenerationwebui"> | |
| 1301 | + </div> | |
| 1294 | 1302 | <div data-tg-type="ooba,mancer,aphrodite" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0"> |
| 1295 | 1303 | <small> |
| 1296 | 1304 | <span data-i18n="Eta Cutoff">Eta Cutoff</span> |
| @@ -1334,12 +1342,12 @@ | ||
| 1334 | 1342 | <input class="neo-range-slider" type="range" id="presence_pen_textgenerationwebui" name="volume" min="-2" max="2" step="0.01" /> |
| 1335 | 1343 | <input class="neo-range-input" type="number" min="-2" max="2" step="0.01" data-for="presence_pen_textgenerationwebui" id="presence_pen_counter_textgenerationwebui"> |
| 1336 | 1344 | </div> |
| 1337 | 1345 | <div data-tg-type="aphrodite, ooba" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0"> |
| 1338 | 1346 | <small data-i18n="No Repeat Ngram Size">No Repeat Ngram Size</small> |
| 1339 | 1347 | <input class="neo-range-slider" type="range" id="no_repeat_ngram_size_textgenerationwebui" name="volume" min="0" max="20" step="1"> |
| 1340 | 1348 | <input class="neo-range-input" type="number" min="0" max="20" step="1" data-for="no_repeat_ngram_size_textgenerationwebui" id="no_repeat_ngram_size_counter_textgenerationwebui"> |
| 1341 | 1349 | </div> |
| 1342 | 1350 | <div data-tg-type="tabby, aphrodite" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0"> |
| 1343 | 1351 | <small data-i18n="Skew">Skew</small> |
| 1344 | 1352 | <input class="neo-range-slider" type="range" id="skew_textgenerationwebui" name="volume" min="-5" max="5" step="0.01" /> |
| 1345 | 1353 | <input class="neo-range-input" type="number" min="-5" max="5" step="0.01" data-for="skew_textgenerationwebui" id="skew_counter_textgenerationwebui"> |
| @@ -1394,7 +1402,7 @@ | ||
| 1394 | 1402 | </div> |
| 1395 | 1403 | </div> |
| 1396 | 1404 | |
| 1397 | 1405 | <div data-tg-type="aphrodite, ooba, koboldcpp, tabby, llamacpp" id="dryBlock" class="wide100p"> |
| 1398 | 1406 | <h4 class="wide100p textAlignCenter" title="DRY penalizes tokens that would extend the end of the input into a sequence that has previously occurred in the input. Set multiplier to 0 to disable." data-i18n="[title]DRY_Repetition_Penalty_desc"> |
| 1399 | 1407 | <label data-i18n="DRY Repetition Penalty">DRY Repetition Penalty</label> |
| 1400 | 1408 | <a href="https://github.com/oobabooga/text-generation-webui/pull/5677" target="_blank"> |
| @@ -1951,15 +1959,6 @@ | ||
| 1951 | 1959 | Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt. |
| 1952 | 1960 | </span> |
| 1953 | 1961 | </div> |
| 1954 | - <div id="claude_human_sysprompt_message_block" class="wide100p"> | |
| 1955 | - <div class="range-block-title openai_restorable"> | |
| 1956 | - <span data-i18n="User first message">User first message</span> | |
| 1957 | - <div id="claude_human_sysprompt_message_restore" title="Restore User first message" data-i18n="[title]Restore User first message" class="right_menu_button"> | |
| 1958 | - <div class="fa-solid fa-clock-rotate-left"></div> | |
| 1959 | - </div> | |
| 1960 | - </div> | |
| 1961 | - <textarea id="claude_human_sysprompt_textarea" class="text_pole textarea_compact autoSetHeight" rows="2" data-i18n="[placeholder]Human message" placeholder="Human message, instruction, etc. Adds nothing when empty, i.e. requires a new prompt with the role 'user'."></textarea> | |
| 1962 | - </div> | |
| 1963 | 1962 | </div> |
| 1964 | 1963 | </div> |
| 1965 | 1964 | <div class="range-block m-t-1" data-source="openai,openrouter,scale,custom"> |
| @@ -2805,9 +2804,6 @@ | ||
| 2805 | 2804 | <option value="claude-3-haiku-20240307">claude-3-haiku-20240307</option> |
| 2806 | 2805 | <option value="claude-2.1">claude-2.1</option> |
| 2807 | 2806 | <option value="claude-2.0">claude-2.0</option> |
| 2808 | - <option value="claude-1.3">claude-1.3</option> | |
| 2809 | - <option value="claude-instant-1.2">claude-instant-1.2</option> | |
| 2810 | - <option value="claude-instant-1.1">claude-instant-1.1</option> | |
| 2811 | 2807 | </optgroup> |
| 2812 | 2808 | </select> |
| 2813 | 2809 | </div> |
| @@ -2707,8 +2707,7 @@ export async function generateQuietPrompt(quiet_prompt, quietToLoud, skipWIAN, q | ||
| 2707 | 2707 | quietName: quietName, |
| 2708 | 2708 | }; |
| 2709 | 2709 | originalResponseLength = responseLengthCustomized ? saveResponseLength(main_api, responseLength) : -1; |
| 2710 | 2710 | const generateFinished =return await Generate('quiet', options); |
| 2711 | - return generateFinished; | |
| 2712 | 2711 | } finally { |
| 2713 | 2712 | if (responseLengthCustomized) { |
| 2714 | 2713 | restoreResponseLength(main_api, originalResponseLength); |
| @@ -3363,9 +3362,9 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy | ||
| 3363 | 3362 | |
| 3364 | 3363 | let data = {}; |
| 3365 | 3364 | |
| 3366 | 3365 | if (api === 'koboldhorde') { |
| 3367 | 3366 | data = await generateHorde(prompt, generateData, abortController.signal, false); |
| 3368 | 3367 | } else if (api === 'openai') { |
| 3369 | 3368 | data = await sendOpenAIRequest('quiet', generateData, abortController.signal); |
| 3370 | 3369 | } else { |
| 3371 | 3370 | const generateUrl = getGenerateUrl(api); |
| @@ -3378,13 +3377,15 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy | ||
| 3378 | 3377 | }); |
| 3379 | 3378 | |
| 3380 | 3379 | if (!response.ok) { |
| 3381 | 3380 | const error =throw await response.json(); |
| 3382 | - throw error; | |
| 3383 | 3381 | } |
| 3384 | 3382 | |
| 3385 | 3383 | data = await response.json(); |
| 3386 | 3384 | } |
| 3387 | 3385 | |
| 3386 | + // should only happen for text completions | |
| 3387 | + // other frontend paths do not return data if calling the backend fails, | |
| 3388 | + // they throw things instead | |
| 3388 | 3389 | if (data.error) { |
| 3389 | 3390 | throw new Error(data.response); |
| 3390 | 3391 | } |
| @@ -4436,6 +4437,11 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | ||
| 4436 | 4437 | return Promise.resolve(); |
| 4437 | 4438 | } |
| 4438 | 4439 | |
| 4440 | + /** | |
| 4441 | + * Saves itemized prompt bits and calls streaming or non-streaming generation API. | |
| 4442 | + * @returns {Promise<void|*|Awaited<*>|String|{fromStream}|string|undefined|Object>} | |
| 4443 | + * @throws {Error|object} Error with message text, or Error with response JSON (OAI/Horde), or the actual response JSON (novel|textgenerationwebui|kobold) | |
| 4444 | + */ | |
| 4439 | 4445 | async function finishGenerating() { |
| 4440 | 4446 | if (power_user.console_log_prompts) { |
| 4441 | 4447 | console.log(generate_data.prompt); |
| @@ -4547,6 +4553,12 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | ||
| 4547 | 4553 | |
| 4548 | 4554 | return finishGenerating().then(onSuccess, onError); |
| 4549 | 4555 | |
| 4556 | + /** | |
| 4557 | + * Handles the successful response from the generation API. | |
| 4558 | + * @param data | |
| 4559 | + * @returns {Promise<String|{fromStream}|*|string|string|void|Awaited<*>|undefined>} | |
| 4560 | + * @throws {Error} Throws an error if the response data contains an error message | |
| 4561 | + */ | |
| 4550 | 4562 | async function onSuccess(data) { |
| 4551 | 4563 | if (!data) return; |
| 4552 | 4564 | |
| @@ -4556,6 +4568,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | ||
| 4556 | 4568 | |
| 4557 | 4569 | let messageChunk = ''; |
| 4558 | 4570 | |
| 4571 | + // if an error was returned in data (textgenwebui), show it and throw it | |
| 4559 | 4572 | if (data.error) { |
| 4560 | 4573 | unblockGeneration(type); |
| 4561 | 4574 | generatedPromptCache = ''; |
| @@ -4670,9 +4683,15 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | ||
| 4670 | 4683 | return Object.defineProperty(new String(getMessage), 'messageChunk', { value: messageChunk }); |
| 4671 | 4684 | } |
| 4672 | 4685 | |
| 4686 | + /** | |
| 4687 | + * Exception handler for finishGenerating | |
| 4688 | + * @param {Error|object} exception Error or response JSON | |
| 4689 | + * @throws {Error|object} Re-throws the exception | |
| 4690 | + */ | |
| 4673 | 4691 | function onError(exception) { |
| 4692 | + // if the response JSON was thrown (novel|textgenerationwebui|kobold), show the error message | |
| 4674 | 4693 | if (typeof exception?.error?.message === 'string') { |
| 4675 | 4694 | toastr.error(exception.error.message, t`ErrorText generation error`, { timeOut: 10000, extendedTimeOut: 20000 }); |
| 4676 | 4695 | } |
| 4677 | 4696 | |
| 4678 | 4697 | generatedPromptCache = ''; |
| @@ -5340,6 +5359,7 @@ function setInContextMessages(lastmsg, type) { | ||
| 5340 | 5359 | * @param {string} type Generation type |
| 5341 | 5360 | * @param {object} data Generation data |
| 5342 | 5361 | * @returns {Promise<object>} Response data from the API |
| 5362 | + * @throws {Error|object} | |
| 5343 | 5363 | */ |
| 5344 | 5364 | export async function sendGenerationRequest(type, data) { |
| 5345 | 5365 | if (main_api === 'openai') { |
| @@ -5359,12 +5379,10 @@ export async function sendGenerationRequest(type, data) { | ||
| 5359 | 5379 | }); |
| 5360 | 5380 | |
| 5361 | 5381 | if (!response.ok) { |
| 5362 | 5382 | const error =throw await response.json(); |
| 5363 | - throw error; | |
| 5364 | 5383 | } |
| 5365 | 5384 | |
| 5366 | 5385 | const responseData =return await response.json(); |
| 5367 | - return responseData; | |
| 5368 | 5386 | } |
| 5369 | 5387 | |
| 5370 | 5388 | /** |
| @@ -5396,6 +5414,7 @@ export async function sendStreamingRequest(type, data) { | ||
| 5396 | 5414 | * Gets the generation endpoint URL for the specified API. |
| 5397 | 5415 | * @param {string} api API name |
| 5398 | 5416 | * @returns {string} Generation URL |
| 5417 | + * @throws {Error} If the API is unknown | |
| 5399 | 5418 | */ |
| 5400 | 5419 | function getGenerateUrl(api) { |
| 5401 | 5420 | switch (api) { |
| @@ -65,6 +65,11 @@ const parse_derivation = derivation => (typeof derivation === 'string') ? { | ||
| 65 | 65 | } : derivation; |
| 66 | 66 | |
| 67 | 67 | export async function deriveTemplatesFromChatTemplate(chat_template, hash) { |
| 68 | + if (chat_template.trim() === '') { | |
| 69 | + console.log('Missing chat template.'); | |
| 70 | + return null; | |
| 71 | + } | |
| 72 | + | |
| 68 | 73 | if (hash in hash_derivations) { |
| 69 | 74 | return parse_derivation(hash_derivations[hash]); |
| 70 | 75 | } |
| @@ -2373,6 +2373,7 @@ function ensureSelectionExists(setting, selector) { | ||
| 2373 | 2373 | * @param {string} [message] Chat message |
| 2374 | 2374 | * @param {function} [callback] Callback function |
| 2375 | 2375 | * @returns {Promise<string|undefined>} Image path |
| 2376 | + * @throws {Error} If the prompt or image generation fails | |
| 2376 | 2377 | */ |
| 2377 | 2378 | async function generatePicture(initiator, args, trigger, message, callback) { |
| 2378 | 2379 | if (!trigger || trigger.trim().length === 0) { |
| @@ -2391,7 +2392,7 @@ async function generatePicture(initiator, args, trigger, message, callback) { | ||
| 2391 | 2392 | trigger = trigger.trim(); |
| 2392 | 2393 | const generationType = getGenerationType(trigger); |
| 2393 | 2394 | const generationTypeKey = Object.keys(generationMode).find(key => generationMode[key] === generationType); |
| 2394 | 2395 | console.log(`GenerationImage generation mode ${generationTypeKey} triggered with "${trigger}"`); |
| 2395 | 2396 | |
| 2396 | 2397 | const quietPrompt = getQuietPrompt(generationType, trigger); |
| 2397 | 2398 | const context = getContext(); |
| @@ -2428,6 +2429,8 @@ async function generatePicture(initiator, args, trigger, message, callback) { | ||
| 2428 | 2429 | |
| 2429 | 2430 | try { |
| 2430 | 2431 | const combineNegatives = (prefix) => { negativePromptPrefix = combinePrefixes(negativePromptPrefix, prefix); }; |
| 2432 | + | |
| 2433 | + // generate the text prompt for the image | |
| 2431 | 2434 | const prompt = await getPrompt(generationType, message, trigger, quietPrompt, combineNegatives); |
| 2432 | 2435 | console.log('Processed image prompt:', prompt); |
| 2433 | 2436 | |
| @@ -2438,11 +2441,16 @@ async function generatePicture(initiator, args, trigger, message, callback) { | ||
| 2438 | 2441 | args._abortController.addEventListener('abort', stopListener); |
| 2439 | 2442 | } |
| 2440 | 2443 | |
| 2444 | + // generate the image | |
| 2441 | 2445 | imagePath = await sendGenerationRequest(generationType, prompt, negativePromptPrefix, characterName, callback, initiator, abortController.signal); |
| 2442 | 2446 | } catch (err) { |
| 2443 | 2447 | console.trace(err); |
| 2444 | - toastr.error('SD prompt text generation failed. Reason: ' + err, 'Image Generation'); | |
| 2448 | + // errors here are most likely due to text generation failure | |
| 2445 | - throw new Error('SD prompt text generation failed. Reason: ' + err); | |
| 2449 | + // sendGenerationRequest mostly deals with its own errors | |
| 2450 | + const reason = err.error?.message || err.message || 'Unknown error'; | |
| 2451 | + const errorText = 'SD prompt text generation failed. ' + reason; | |
| 2452 | + toastr.error(errorText, 'Image Generation'); | |
| 2453 | + throw new Error(errorText); | |
| 2446 | 2454 | } |
| 2447 | 2455 | finally { |
| 2448 | 2456 | $(stopButton).hide(); |
| @@ -2513,7 +2521,7 @@ function restoreOriginalDimensions(savedParams) { | ||
| 2513 | 2521 | */ |
| 2514 | 2522 | async function getPrompt(generationType, message, trigger, quietPrompt, combineNegatives) { |
| 2515 | 2523 | let prompt; |
| 2516 | - | |
| 2524 | + console.log('getPrompt: Generation mode', generationType, 'triggered with', trigger); | |
| 2517 | 2525 | switch (generationType) { |
| 2518 | 2526 | case generationMode.RAW_LAST: |
| 2519 | 2527 | prompt = message || getRawLastMessage(); |
| @@ -2729,7 +2737,7 @@ async function sendGenerationRequest(generationType, prompt, additionalNegativeP | ||
| 2729 | 2737 | throw new Error('Endpoint did not return image data.'); |
| 2730 | 2738 | } |
| 2731 | 2739 | } catch (err) { |
| 2732 | 2740 | console.error('Image generation request error: ', err); |
| 2733 | 2741 | toastr.error('Image generation failed. Please try again.' + '\n\n' + String(err), 'Image Generation'); |
| 2734 | 2742 | return; |
| 2735 | 2743 | } |
| @@ -181,6 +181,14 @@ function setContextSizePreview() { | ||
| 181 | 181 | } |
| 182 | 182 | } |
| 183 | 183 | |
| 184 | +/** Generates text using the Horde API. | |
| 185 | + * @param {string} prompt | |
| 186 | + * @param params | |
| 187 | + * @param signal | |
| 188 | + * @param reportProgress | |
| 189 | + * @returns {Promise<{text: *, workerName: string}>} | |
| 190 | + * @throws {Error} | |
| 191 | + */ | |
| 184 | 192 | async function generateHorde(prompt, params, signal, reportProgress) { |
| 185 | 193 | validateHordeModel(); |
| 186 | 194 | delete params.prompt; |
| @@ -99,7 +99,6 @@ const default_wi_format = '{0}'; | ||
| 99 | 99 | const default_new_chat_prompt = '[Start a new Chat]'; |
| 100 | 100 | const default_new_group_chat_prompt = '[Start a new group chat. Group members: {{group}}]'; |
| 101 | 101 | const default_new_example_chat_prompt = '[Example Chat]'; |
| 102 | -const default_claude_human_sysprompt_message = 'Let\'s get started. Please generate your response based on the information and instructions provided above.'; | |
| 103 | 102 | const default_continue_nudge_prompt = '[Continue the following message. Do not include ANY parts of the original message. Use capitalization and punctuation as if your reply is a part of the original message: {{lastChatMessage}}]'; |
| 104 | 103 | const default_bias = 'Default (none)'; |
| 105 | 104 | const default_personality_format = '[{{char}}\'s personality: {{personality}}]'; |
| @@ -276,7 +275,6 @@ const default_settings = { | ||
| 276 | 275 | proxy_password: '', |
| 277 | 276 | assistant_prefill: '', |
| 278 | 277 | assistant_impersonation: '', |
| 279 | - human_sysprompt_message: default_claude_human_sysprompt_message, | |
| 280 | 278 | claude_use_sysprompt: false, |
| 281 | 279 | use_makersuite_sysprompt: true, |
| 282 | 280 | use_alt_scale: false, |
| @@ -353,7 +351,6 @@ const oai_settings = { | ||
| 353 | 351 | proxy_password: '', |
| 354 | 352 | assistant_prefill: '', |
| 355 | 353 | assistant_impersonation: '', |
| 356 | - human_sysprompt_message: default_claude_human_sysprompt_message, | |
| 357 | 354 | claude_use_sysprompt: false, |
| 358 | 355 | use_makersuite_sysprompt: true, |
| 359 | 356 | use_alt_scale: false, |
| @@ -1313,6 +1310,11 @@ export async function prepareOpenAIMessages({ | ||
| 1313 | 1310 | return [chat, promptManager.tokenHandler.counts]; |
| 1314 | 1311 | } |
| 1315 | 1312 | |
| 1313 | +/** | |
| 1314 | + * Handles errors during streaming requests. | |
| 1315 | + * @param {Response} response | |
| 1316 | + * @param {string} decoded - response text or decoded stream data | |
| 1317 | + */ | |
| 1316 | 1318 | function tryParseStreamingError(response, decoded) { |
| 1317 | 1319 | try { |
| 1318 | 1320 | const data = JSON.parse(decoded); |
| @@ -1324,6 +1326,9 @@ function tryParseStreamingError(response, decoded) { | ||
| 1324 | 1326 | checkQuotaError(data); |
| 1325 | 1327 | checkModerationError(data); |
| 1326 | 1328 | |
| 1329 | + // these do not throw correctly (equiv to Error("[object Object]")) | |
| 1330 | + // if trying to fix "[object Object]" displayed to users, start here | |
| 1331 | + | |
| 1327 | 1332 | if (data.error) { |
| 1328 | 1333 | toastr.error(data.error.message || response.statusText, 'Chat Completion API'); |
| 1329 | 1334 | throw new Error(data); |
| @@ -1339,15 +1344,22 @@ function tryParseStreamingError(response, decoded) { | ||
| 1339 | 1344 | } |
| 1340 | 1345 | } |
| 1341 | 1346 | |
| 1342 | -async function checkQuotaError(data) { | |
| 1347 | +/** | |
| 1343 | - const errorText = await renderTemplateAsync('quotaError'); | |
| 1348 | + * Checks if the response contains a quota error and displays a popup if it does. | |
| 1344 | - | |
| 1349 | + * @param data | |
| 1350 | + * @returns {void} | |
| 1351 | + * @throws {object} - response JSON | |
| 1352 | + */ | |
| 1353 | +function checkQuotaError(data) { | |
| 1345 | 1354 | if (!data) { |
| 1346 | 1355 | return; |
| 1347 | 1356 | } |
| 1348 | 1357 | |
| 1349 | 1358 | if (data.quota_error) { |
| 1350 | - callPopup(errorText, 'text'); | |
| 1359 | + renderTemplateAsync('quotaError').then((html) => Popup.show.text('Quota Error', html)); | |
| 1360 | + | |
| 1361 | + // this does not throw correctly (equiv to Error("[object Object]")) | |
| 1362 | + // if trying to fix "[object Object]" displayed to users, start here | |
| 1351 | 1363 | throw new Error(data); |
| 1352 | 1364 | } |
| 1353 | 1365 | } |
| @@ -1766,6 +1778,15 @@ async function sendAltScaleRequest(messages, logit_bias, signal, type) { | ||
| 1766 | 1778 | return data.output; |
| 1767 | 1779 | } |
| 1768 | 1780 | |
| 1781 | +/** | |
| 1782 | + * Send a chat completion request to backend | |
| 1783 | + * @param {string} type (impersonate, quiet, continue, etc) | |
| 1784 | + * @param {Array} messages | |
| 1785 | + * @param {AbortSignal?} signal | |
| 1786 | + * @returns {Promise<unknown>} | |
| 1787 | + * @throws {Error} | |
| 1788 | + */ | |
| 1789 | + | |
| 1769 | 1790 | async function sendOpenAIRequest(type, messages, signal) { |
| 1770 | 1791 | // Provide default abort signal |
| 1771 | 1792 | if (!signal) { |
| @@ -1868,7 +1889,6 @@ async function sendOpenAIRequest(type, messages, signal) { | ||
| 1868 | 1889 | generate_data['top_k'] = Number(oai_settings.top_k_openai); |
| 1869 | 1890 | generate_data['claude_use_sysprompt'] = oai_settings.claude_use_sysprompt; |
| 1870 | 1891 | generate_data['stop'] = getCustomStoppingStrings(); // Claude shouldn't have limits on stop strings. |
| 1871 | - generate_data['human_sysprompt_message'] = substituteParams(oai_settings.human_sysprompt_message); | |
| 1872 | 1892 | // Don't add a prefill on quiet gens (summarization) and when using continue prefill. |
| 1873 | 1893 | if (!isQuiet && !(isContinue && oai_settings.continue_prefill)) { |
| 1874 | 1894 | generate_data['assistant_prefill'] = isImpersonate ? substituteParams(oai_settings.assistant_impersonation) : substituteParams(oai_settings.assistant_prefill); |
| @@ -2028,12 +2048,13 @@ async function sendOpenAIRequest(type, messages, signal) { | ||
| 2028 | 2048 | else { |
| 2029 | 2049 | const data = await response.json(); |
| 2030 | 2050 | |
| 2031 | 2051 | await checkQuotaError(data); |
| 2032 | 2052 | checkModerationError(data); |
| 2033 | 2053 | |
| 2034 | 2054 | if (data.error) { |
| 2035 | 2055 | toastr.error(const message = data.error.message || response.statusText, || t`API returned anUnknown error`); |
| 2036 | - throw new Error(data); | |
| 2056 | + toastr.error(message, t`API returned an error`); | |
| 2057 | + throw new Error(message); | |
| 2037 | 2058 | } |
| 2038 | 2059 | |
| 2039 | 2060 | if (type !== 'quiet') { |
| @@ -3005,7 +3026,6 @@ function loadOpenAISettings(data, settings) { | ||
| 3005 | 3026 | oai_settings.proxy_password = settings.proxy_password ?? default_settings.proxy_password; |
| 3006 | 3027 | oai_settings.assistant_prefill = settings.assistant_prefill ?? default_settings.assistant_prefill; |
| 3007 | 3028 | oai_settings.assistant_impersonation = settings.assistant_impersonation ?? default_settings.assistant_impersonation; |
| 3008 | - oai_settings.human_sysprompt_message = settings.human_sysprompt_message ?? default_settings.human_sysprompt_message; | |
| 3009 | 3029 | oai_settings.image_inlining = settings.image_inlining ?? default_settings.image_inlining; |
| 3010 | 3030 | oai_settings.inline_image_quality = settings.inline_image_quality ?? default_settings.inline_image_quality; |
| 3011 | 3031 | oai_settings.bypass_status_check = settings.bypass_status_check ?? default_settings.bypass_status_check; |
| @@ -3045,7 +3065,6 @@ function loadOpenAISettings(data, settings) { | ||
| 3045 | 3065 | $('#openai_proxy_password').val(oai_settings.proxy_password); |
| 3046 | 3066 | $('#claude_assistant_prefill').val(oai_settings.assistant_prefill); |
| 3047 | 3067 | $('#claude_assistant_impersonation').val(oai_settings.assistant_impersonation); |
| 3048 | - $('#claude_human_sysprompt_textarea').val(oai_settings.human_sysprompt_message); | |
| 3049 | 3068 | $('#openai_image_inlining').prop('checked', oai_settings.image_inlining); |
| 3050 | 3069 | $('#openai_bypass_status_check').prop('checked', oai_settings.bypass_status_check); |
| 3051 | 3070 | |
| @@ -3375,7 +3394,6 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) { | ||
| 3375 | 3394 | show_external_models: settings.show_external_models, |
| 3376 | 3395 | assistant_prefill: settings.assistant_prefill, |
| 3377 | 3396 | assistant_impersonation: settings.assistant_impersonation, |
| 3378 | - human_sysprompt_message: settings.human_sysprompt_message, | |
| 3379 | 3397 | claude_use_sysprompt: settings.claude_use_sysprompt, |
| 3380 | 3398 | use_makersuite_sysprompt: settings.use_makersuite_sysprompt, |
| 3381 | 3399 | use_alt_scale: settings.use_alt_scale, |
| @@ -3800,7 +3818,6 @@ function onSettingsPresetChange() { | ||
| 3800 | 3818 | proxy_password: ['#openai_proxy_password', 'proxy_password', false], |
| 3801 | 3819 | assistant_prefill: ['#claude_assistant_prefill', 'assistant_prefill', false], |
| 3802 | 3820 | assistant_impersonation: ['#claude_assistant_impersonation', 'assistant_impersonation', false], |
| 3803 | - human_sysprompt_message: ['#claude_human_sysprompt_textarea', 'human_sysprompt_message', false], | |
| 3804 | 3821 | claude_use_sysprompt: ['#claude_use_sysprompt', 'claude_use_sysprompt', true], |
| 3805 | 3822 | use_makersuite_sysprompt: ['#use_makersuite_sysprompt', 'use_makersuite_sysprompt', true], |
| 3806 | 3823 | use_alt_scale: ['#use_alt_scale', 'use_alt_scale', true], |
| @@ -4652,10 +4669,6 @@ function toggleChatCompletionForms() { | ||
| 4652 | 4669 | const validSources = $(this).data('source').split(','); |
| 4653 | 4670 | $(this).toggle(validSources.includes(oai_settings.chat_completion_source)); |
| 4654 | 4671 | }); |
| 4655 | - | |
| 4656 | - if (chat_completion_sources.CLAUDE == oai_settings.chat_completion_source) { | |
| 4657 | - $('#claude_human_sysprompt_message_block').toggle(oai_settings.claude_use_sysprompt); | |
| 4658 | - } | |
| 4659 | 4672 | } |
| 4660 | 4673 | |
| 4661 | 4674 | async function testApiConnection() { |
| @@ -5011,7 +5024,6 @@ export function initOpenAI() { | ||
| 5011 | 5024 | |
| 5012 | 5025 | $('#claude_use_sysprompt').on('change', function () { |
| 5013 | 5026 | oai_settings.claude_use_sysprompt = !!$('#claude_use_sysprompt').prop('checked'); |
| 5014 | - $('#claude_human_sysprompt_message_block').toggle(oai_settings.claude_use_sysprompt); | |
| 5015 | 5027 | saveSettingsDebounced(); |
| 5016 | 5028 | }); |
| 5017 | 5029 | |
| @@ -5088,12 +5100,6 @@ export function initOpenAI() { | ||
| 5088 | 5100 | saveSettingsDebounced(); |
| 5089 | 5101 | }); |
| 5090 | 5102 | |
| 5091 | - $('#claude_human_sysprompt_message_restore').on('click', function () { | |
| 5092 | - oai_settings.human_sysprompt_message = default_claude_human_sysprompt_message; | |
| 5093 | - $('#claude_human_sysprompt_textarea').val(oai_settings.human_sysprompt_message); | |
| 5094 | - saveSettingsDebounced(); | |
| 5095 | - }); | |
| 5096 | - | |
| 5097 | 5103 | $('#newgroupchat_prompt_restore').on('click', function () { |
| 5098 | 5104 | oai_settings.new_group_chat_prompt = default_new_group_chat_prompt; |
| 5099 | 5105 | $('#newgroupchat_prompt_textarea').val(oai_settings.new_group_chat_prompt); |
| @@ -5185,11 +5191,6 @@ export function initOpenAI() { | ||
| 5185 | 5191 | saveSettingsDebounced(); |
| 5186 | 5192 | }); |
| 5187 | 5193 | |
| 5188 | - $('#claude_human_sysprompt_textarea').on('input', function () { | |
| 5189 | - oai_settings.human_sysprompt_message = String($('#claude_human_sysprompt_textarea').val()); | |
| 5190 | - saveSettingsDebounced(); | |
| 5191 | - }); | |
| 5192 | - | |
| 5193 | 5194 | $('#openrouter_use_fallback').on('input', function () { |
| 5194 | 5195 | oai_settings.openrouter_use_fallback = !!$(this).prop('checked'); |
| 5195 | 5196 | saveSettingsDebounced(); |
| @@ -658,6 +658,10 @@ async function CreateZenSliders(elmnt) { | ||
| 658 | 658 | numSteps = 50; |
| 659 | 659 | decimals = 1; |
| 660 | 660 | } |
| 661 | + if (sliderID == 'nsigma') { | |
| 662 | + numSteps = 50; | |
| 663 | + decimals = 1; | |
| 664 | + } | |
| 661 | 665 | //customize steps |
| 662 | 666 | if (sliderID == 'mirostat_mode_textgenerationwebui' || |
| 663 | 667 | sliderID == 'mirostat_mode_kobold') { |
| @@ -702,6 +706,7 @@ async function CreateZenSliders(elmnt) { | ||
| 702 | 706 | sliderID == 'penalty_alpha_textgenerationwebui' || |
| 703 | 707 | sliderID == 'length_penalty_textgenerationwebui' || |
| 704 | 708 | sliderID == 'epsilon_cutoff_textgenerationwebui' || |
| 709 | + sliderID == 'nsigma' || | |
| 705 | 710 | sliderID == 'rep_pen_range' || |
| 706 | 711 | sliderID == 'eta_cutoff_textgenerationwebui' || |
| 707 | 712 | sliderID == 'top_a_textgenerationwebui' || |
| @@ -1,5 +1,4 @@ | ||
| 1 | 1 | import { escapeRegex } from '../utils.js'; |
| 2 | -import { SlashCommand } from './SlashCommand.js'; | |
| 3 | 2 | import { SlashCommandParser } from './SlashCommandParser.js'; |
| 4 | 3 | |
| 5 | 4 | export class SlashCommandBrowser { |
| @@ -30,7 +29,7 @@ export class SlashCommandBrowser { | ||
| 30 | 29 | this.details?.remove(); |
| 31 | 30 | this.details = null; |
| 32 | 31 | let query = inp.value.trim(); |
| 33 | 32 | if (query.slice(-1) === '"' && !/(?:^|\s+)"/.test(query)) { |
| 34 | 33 | query = `"${query}`; |
| 35 | 34 | } |
| 36 | 35 | let fuzzyList = []; |
| @@ -59,7 +58,7 @@ export class SlashCommandBrowser { | ||
| 59 | 58 | cmd.helpString, |
| 60 | 59 | ]; |
| 61 | 60 | const find = ()=>targets.find(t=>(fuzzyList.find(f=>f.test(t)) ?? quotedList.find(q=>t.includes(q))) !== undefined) !== undefined; |
| 62 | 61 | if (fuzzyList.length + quotedList.length === 0 || find()) { |
| 63 | 62 | this.itemMap[cmd.name].classList.remove('isFiltered'); |
| 64 | 63 | } else { |
| 65 | 64 | this.itemMap[cmd.name].classList.add('isFiltered'); |
| @@ -78,7 +77,7 @@ export class SlashCommandBrowser { | ||
| 78 | 77 | list.classList.add('autoComplete'); |
| 79 | 78 | this.cmdList = Object |
| 80 | 79 | .keys(SlashCommandParser.commands) |
| 81 | 80 | .filter(key => SlashCommandParser.commands[key].name === key) // exclude aliases |
| 82 | 81 | .sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase())) |
| 83 | 82 | .map(key => SlashCommandParser.commands[key]) |
| 84 | 83 | ; |
| @@ -97,7 +96,7 @@ export class SlashCommandBrowser { | ||
| 97 | 96 | } |
| 98 | 97 | } |
| 99 | 98 | } |
| 100 | 99 | if (this.details !== details) { |
| 101 | 100 | Array.from(list.querySelectorAll('.selected')).forEach(it=>it.classList.remove('selected')); |
| 102 | 101 | item.classList.add('selected'); |
| 103 | 102 | this.details?.remove(); |
| @@ -124,7 +123,7 @@ export class SlashCommandBrowser { | ||
| 124 | 123 | parent.append(this.dom); |
| 125 | 124 | |
| 126 | 125 | this.mo = new MutationObserver(muts=>{ |
| 127 | 126 | if (muts.find(mut=>Array.from(mut.removedNodes).find(it=>it === this.dom || it.contains(this.dom)))) { |
| 128 | 127 | this.mo.disconnect(); |
| 129 | 128 | window.removeEventListener('keydown', boundHandler); |
| 130 | 129 | } |
| @@ -136,7 +135,7 @@ export class SlashCommandBrowser { | ||
| 136 | 135 | } |
| 137 | 136 | |
| 138 | 137 | handleKeyDown(evt) { |
| 139 | 138 | if (!evt.shiftKey && !evt.altKey && evt.ctrlKey && evt.key.toLowerCase() === 'f') { |
| 140 | 139 | if (!this.dom.closest('body')) return; |
| 141 | 140 | if (this.dom.closest('.mes') && !this.dom.closest('.last_mes')) return; |
| 142 | 141 | evt.preventDefault(); |
| @@ -193,6 +193,7 @@ const settings = { | ||
| 193 | 193 | openrouter_allow_fallbacks: true, |
| 194 | 194 | xtc_threshold: 0.1, |
| 195 | 195 | xtc_probability: 0, |
| 196 | + nsigma: 0.0, | |
| 196 | 197 | featherless_model: '', |
| 197 | 198 | }; |
| 198 | 199 | |
| @@ -265,6 +266,7 @@ export const setting_names = [ | ||
| 265 | 266 | 'openrouter_allow_fallbacks', |
| 266 | 267 | 'xtc_threshold', |
| 267 | 268 | 'xtc_probability', |
| 269 | + 'nsigma', | |
| 268 | 270 | ]; |
| 269 | 271 | |
| 270 | 272 | const DYNATEMP_BLOCK = document.getElementById('dynatemp_block_ooba'); |
| @@ -880,6 +882,13 @@ function setSettingByName(setting, value, trigger) { | ||
| 880 | 882 | } |
| 881 | 883 | } |
| 882 | 884 | |
| 885 | +/** | |
| 886 | + * Sends a streaming request for textgenerationwebui. | |
| 887 | + * @param generate_data | |
| 888 | + * @param signal | |
| 889 | + * @returns {Promise<(function(): AsyncGenerator<{swipes: [], text: string, toolCalls: [], logprobs: {token: string, topLogprobs: Candidate[]}|null}, void, *>)|*>} | |
| 890 | + * @throws {Error} - If the response status is not OK, or from within the generator | |
| 891 | + */ | |
| 883 | 892 | async function generateTextGenWithStreaming(generate_data, signal) { |
| 884 | 893 | generate_data.stream = true; |
| 885 | 894 | |
| @@ -995,6 +1004,7 @@ export function parseTabbyLogprobs(data) { | ||
| 995 | 1004 | * @param {Response} response - Response from the server. |
| 996 | 1005 | * @param {string} decoded - Decoded response body. |
| 997 | 1006 | * @returns {void} Nothing. |
| 1007 | + * @throws {Error} If the response contains an error message, throws Error with the message. | |
| 998 | 1008 | */ |
| 999 | 1009 | function tryParseStreamingError(response, decoded) { |
| 1000 | 1010 | let data = {}; |
| @@ -1178,6 +1188,7 @@ export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate, | ||
| 1178 | 1188 | 'sampler_order': settings.type === textgen_types.KOBOLDCPP ? settings.sampler_order : undefined, |
| 1179 | 1189 | 'xtc_threshold': settings.xtc_threshold, |
| 1180 | 1190 | 'xtc_probability': settings.xtc_probability, |
| 1191 | + 'nsigma': settings.nsigma, | |
| 1181 | 1192 | }; |
| 1182 | 1193 | const nonAphroditeParams = { |
| 1183 | 1194 | 'rep_pen': settings.rep_pen, |
| @@ -1245,7 +1256,9 @@ export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate, | ||
| 1245 | 1256 | 'dynatemp_exponent': dynatemp ? settings.dynatemp_exponent : undefined, |
| 1246 | 1257 | 'xtc_threshold': settings.xtc_threshold, |
| 1247 | 1258 | 'xtc_probability': settings.xtc_probability, |
| 1259 | + 'nsigma': settings.nsigma, | |
| 1248 | 1260 | 'custom_token_bans': toIntArray(banned_tokens), |
| 1261 | + 'no_repeat_ngram_size': settings.no_repeat_ngram_size, | |
| 1249 | 1262 | }; |
| 1250 | 1263 | |
| 1251 | 1264 | if (settings.type === OPENROUTER) { |
| @@ -102,7 +102,7 @@ async function sendClaudeRequest(request, response) { | ||
| 102 | 102 | const additionalHeaders = {}; |
| 103 | 103 | const useTools = request.body.model.startsWith('claude-3') && Array.isArray(request.body.tools) && request.body.tools.length > 0; |
| 104 | 104 | const useSystemPrompt = (request.body.model.startsWith('claude-2') || request.body.model.startsWith('claude-3')) && request.body.claude_use_sysprompt; |
| 105 | 105 | const convertedPrompt = convertClaudeMessages(request.body.messages, request.body.assistant_prefill, useSystemPrompt, useTools, request.body.human_sysprompt_message, request.body.char_name, request.body.user_name); |
| 106 | 106 | // Add custom stop sequences |
| 107 | 107 | const stopSequences = []; |
| 108 | 108 | if (Array.isArray(request.body.stop)) { |
| @@ -1051,8 +1051,12 @@ router.post('/generate', jsonParser, function (request, response) { | ||
| 1051 | 1051 | } |
| 1052 | 1052 | } catch (error) { |
| 1053 | 1053 | console.log('Generation failed', error); |
| 1054 | + const message = error.code === 'ECONNREFUSED' | |
| 1055 | + ? `Connection refused: ${error.message}` | |
| 1056 | + : error.message || 'Unknown error occurred'; | |
| 1057 | + | |
| 1054 | 1058 | if (!response.headersSent) { |
| 1055 | 1059 | response.status(502).send({ error: true{ message, ...error } }); |
| 1056 | 1060 | } else { |
| 1057 | 1061 | response.end(); |
| 1058 | 1062 | } |
| @@ -1068,7 +1072,7 @@ router.post('/generate', jsonParser, function (request, response) { | ||
| 1068 | 1072 | |
| 1069 | 1073 | const message = errorResponse.statusText || 'Unknown error occurred'; |
| 1070 | 1074 | const quota_error = errorResponse.status === 429 && errorData?.error?.type === 'insufficient_quota'; |
| 1071 | 1075 | console.log('Chat completion request error: ', message, responseText); |
| 1072 | 1076 | |
| 1073 | 1077 | if (!response.headersSent) { |
| 1074 | 1078 | response.send({ error: { message }, quota_error: quota_error }); |
| @@ -24,6 +24,8 @@ const defaultAvatarPath = './public/img/ai4.png'; | ||
| 24 | 24 | |
| 25 | 25 | // KV-store for parsed character data |
| 26 | 26 | const characterDataCache = new Map(); |
| 27 | +// Some Android devices require tighter memory management | |
| 28 | +const isAndroid = process.platform === 'android'; | |
| 27 | 29 | |
| 28 | 30 | /** |
| 29 | 31 | * Reads the character card from the specified image file. |
| @@ -39,7 +41,7 @@ async function readCharacterData(inputFile, inputFormat = 'png') { | ||
| 39 | 41 | } |
| 40 | 42 | |
| 41 | 43 | const result = parse(inputFile, inputFormat); |
| 42 | 44 | !isAndroid && characterDataCache.set(cacheKey, result); |
| 43 | 45 | return result; |
| 44 | 46 | } |
| 45 | 47 | |
| @@ -6,7 +6,7 @@ import { publicLibConfig } from '../../webpack.config.js'; | ||
| 6 | 6 | export default function getWebpackServeMiddleware() { |
| 7 | 7 | const compiler = webpack(publicLibConfig); |
| 8 | 8 | |
| 9 | 9 | if (process.env.NODE_ENV === 'production' || process.platform === 'android') { |
| 10 | 10 | compiler.hooks.done.tap('serve', () => { |
| 11 | 11 | if (compiler.watching) { |
| 12 | 12 | compiler.watching.close(() => { }); |
| @@ -91,11 +91,10 @@ export function convertClaudePrompt(messages, addAssistantPostfix, addAssistantP | ||
| 91 | 91 | * @param {string} prefillString User determined prefill string |
| 92 | 92 | * @param {boolean} useSysPrompt See if we want to use a system prompt |
| 93 | 93 | * @param {boolean} useTools See if we want to use tools |
| 94 | - * @param {string} humanMsgFix Add Human message between system prompt and assistant. | |
| 95 | 94 | * @param {string} charName Character name |
| 96 | 95 | * @param {string} userName User name |
| 97 | 96 | */ |
| 98 | 97 | export function convertClaudeMessages(messages, prefillString, useSysPrompt, useTools, humanMsgFix, charName = '', userName = '') { |
| 99 | 98 | let systemPrompt = []; |
| 100 | 99 | if (useSysPrompt) { |
| 101 | 100 | // Collect all the system messages up until the first instance of a non-system message, and then remove them from the messages array. |
| @@ -122,10 +121,10 @@ export function convertClaudeMessages(messages, prefillString, useSysPrompt, use | ||
| 122 | 121 | |
| 123 | 122 | // Check if the first message in the array is of type user, if not, interject with humanMsgFix or a blank message. |
| 124 | 123 | // Also prevents erroring out if the messages array is empty. |
| 125 | 124 | if (messages.length === 0 || (messages.length > 0 && messages[0].role !== 'user')) { |
| 126 | 125 | messages.unshift({ |
| 127 | 126 | role: 'user', |
| 128 | 127 | content: humanMsgFix || PROMPT_PLACEHOLDER, |
| 129 | 128 | }); |
| 130 | 129 | } |
| 131 | 130 | } |