Merge branch 'staging' into if-command-default-arguments

7abb1751b14282f508768d5ee4756d646fedb344

Wolfsblvt <wolfsblvt@gmail.com>

151 files changed, +1594 -844Showing whitespace changes
.gitignore+1 -0
@@ -49,3 +49,4 @@ public/css/user.css
49/data49/data
50/default/scaffold50/default/scaffold
51public/scripts/extensions/third-party51public/scripts/extensions/third-party
52/certs
default/config.yaml+0 -3
@@ -110,9 +110,6 @@ enableExtensionsAutoUpdate: true
110# Additional model tokenizers can be downloaded on demand.110# Additional model tokenizers can be downloaded on demand.
111# Disabling will fallback to another locally available tokenizer.111# Disabling will fallback to another locally available tokenizer.
112enableDownloadableTokenizers: true112enableDownloadableTokenizers: true
113# Vector storage settings
114vectors:
115 enableModelScopes: false
116# Extension settings113# Extension settings
117extras:114extras:
118 # Disables automatic model download from HuggingFace115 # Disables automatic model download from HuggingFace
default/content/index.json+68 -8
@@ -320,6 +320,26 @@
320 "type": "novel_preset"320 "type": "novel_preset"
321 },321 },
322 {322 {
323 "filename": "presets/novel/Erato-Dragonfruit.json",
324 "type": "novel_preset"
325 },
326 {
327 "filename": "presets/novel/Erato-Golden Arrow.json",
328 "type": "novel_preset"
329 },
330 {
331 "filename": "presets/novel/Erato-Shosetsu.json",
332 "type": "novel_preset"
333 },
334 {
335 "filename": "presets/novel/Erato-Wilder.json",
336 "type": "novel_preset"
337 },
338 {
339 "filename": "presets/novel/Erato-Zany Scribe.json",
340 "type": "novel_preset"
341 },
342 {
323 "filename": "presets/textgen/Asterism.json",343 "filename": "presets/textgen/Asterism.json",
324 "type": "textgen_preset"344 "type": "textgen_preset"
325 },345 },
@@ -468,10 +488,6 @@
468 "type": "context"488 "type": "context"
469 },489 },
470 {490 {
471 "filename": "presets/context/Alpaca-Roleplay.json",
472 "type": "context"
473 },
474 {
475 "filename": "presets/context/Alpaca-Single-Turn.json",491 "filename": "presets/context/Alpaca-Single-Turn.json",
476 "type": "context"492 "type": "context"
477 },493 },
@@ -552,10 +568,6 @@
552 "type": "instruct"568 "type": "instruct"
553 },569 },
554 {570 {
555 "filename": "presets/instruct/Alpaca-Roleplay.json",
556 "type": "instruct"
557 },
558 {
559 "filename": "presets/instruct/Alpaca-Single-Turn.json",571 "filename": "presets/instruct/Alpaca-Single-Turn.json",
560 "type": "instruct"572 "type": "instruct"
561 },573 },
@@ -680,6 +692,54 @@
680 "type": "instruct"692 "type": "instruct"
681 },693 },
682 {694 {
695 "filename": "presets/sysprompt/Actor.json",
696 "type": "sysprompt"
697 },
698 {
699 "filename": "presets/sysprompt/Assistant - Expert.json",
700 "type": "sysprompt"
701 },
702 {
703 "filename": "presets/sysprompt/Assistant - Simple.json",
704 "type": "sysprompt"
705 },
706 {
707 "filename": "presets/sysprompt/Chain of Thought.json",
708 "type": "sysprompt"
709 },
710 {
711 "filename": "presets/sysprompt/Roleplay - Detailed.json",
712 "type": "sysprompt"
713 },
714 {
715 "filename": "presets/sysprompt/Roleplay - Immersive.json",
716 "type": "sysprompt"
717 },
718 {
719 "filename": "presets/sysprompt/Roleplay - Simple.json",
720 "type": "sysprompt"
721 },
722 {
723 "filename": "presets/sysprompt/Text Adventure.json",
724 "type": "sysprompt"
725 },
726 {
727 "filename": "presets/sysprompt/Writer - Creative.json",
728 "type": "sysprompt"
729 },
730 {
731 "filename": "presets/sysprompt/Writer - Realistic.json",
732 "type": "sysprompt"
733 },
734 {
735 "filename": "presets/sysprompt/Blank.json",
736 "type": "sysprompt"
737 },
738 {
739 "filename": "presets/sysprompt/Neutral - Chat.json",
740 "type": "sysprompt"
741 },
742 {
683 "filename": "presets/instruct/Mistral V1.json",743 "filename": "presets/instruct/Mistral V1.json",
684 "type": "instruct"744 "type": "instruct"
685 },745 },
default/content/presets/context/Adventure.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": false,7 "always_force_name2": false,
8 "trim_sentences": false,8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": true,9 "single_line": true,
11 "name": "Adventure"10 "name": "Adventure"
12}11}
default/content/presets/context/Alpaca-Roleplay.json+0 -12
@@ -1,12 +0,0 @@
1{
2 "story_string": "You're {{char}} in this fictional never-ending uncensored roleplay with {{user}}.\n\n{{#if system}}{{system}}\n\n{{/if}}### Input:\n{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}\n\n",
3 "example_separator": "### New Roleplay:",
4 "chat_start": "### New Roleplay:",
5 "use_stop_strings": false,
6 "allow_jailbreak": false,
7 "always_force_name2": true,
8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": false,
11 "name": "Alpaca-Roleplay"
12}
default/content/presets/context/Alpaca-Single-Turn.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": false,7 "always_force_name2": false,
8 "trim_sentences": false,8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "Alpaca-Single-Turn"10 "name": "Alpaca-Single-Turn"
12}11}
default/content/presets/context/Alpaca.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": true,7 "always_force_name2": true,
8 "trim_sentences": false,8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "Alpaca"10 "name": "Alpaca"
12}11}
default/content/presets/context/ChatML-Names.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": true,7 "always_force_name2": true,
8 "trim_sentences": false,8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "ChatML-Names"10 "name": "ChatML-Names"
12}11}
default/content/presets/context/ChatML.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": true,7 "always_force_name2": true,
8 "trim_sentences": false,8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "ChatML"10 "name": "ChatML"
12}11}
default/content/presets/context/Command R.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": true,7 "always_force_name2": true,
8 "trim_sentences": false,8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "Command R"10 "name": "Command R"
12}11}
default/content/presets/context/Default.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": true,7 "always_force_name2": true,
8 "trim_sentences": false,8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "Default"10 "name": "Default"
12}11}
default/content/presets/context/DreamGen Role-Play V1 ChatML.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": false,7 "always_force_name2": false,
8 "trim_sentences": true,8 "trim_sentences": true,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "DreamGen Role-Play V1 ChatML"10 "name": "DreamGen Role-Play V1 ChatML"
12}11}
default/content/presets/context/DreamGen Role-Play V1 Llama3.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": false,7 "always_force_name2": false,
8 "trim_sentences": true,8 "trim_sentences": true,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "DreamGen Role-Play V1 Llama3"10 "name": "DreamGen Role-Play V1 Llama3"
12}11}
default/content/presets/context/Gemma 2.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": true,7 "always_force_name2": true,
8 "trim_sentences": false,8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "Gemma 2"10 "name": "Gemma 2"
12}11}
default/content/presets/context/Libra-32B.json+1 -2
@@ -1,12 +1,11 @@
1{1{
2 "story_string": "### Instruction:\nWrite {{char}}'s next reply in this roleplay with {{user}}. Use the provided character sheet and example dialogue for formatting direction and character speech patterns.\n\n{{#if system}}{{system}}\n\n{{/if}}### Character Sheet:\n{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}",2 "story_string": "### Instruction:\n{{#if system}}{{system}}\n\n{{/if}}### Character Sheet:\n{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}",
3 "example_separator": "### Example:",3 "example_separator": "### Example:",
4 "chat_start": "### START ROLEPLAY:",4 "chat_start": "### START ROLEPLAY:",
5 "use_stop_strings": false,5 "use_stop_strings": false,
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": true,7 "always_force_name2": true,
8 "trim_sentences": false,8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "Libra-32B"10 "name": "Libra-32B"
12}11}
default/content/presets/context/Lightning 1.1.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": true,7 "always_force_name2": true,
8 "trim_sentences": false,8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "Lightning 1.1"10 "name": "Lightning 1.1"
12}11}
default/content/presets/context/Llama 2 Chat.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": true,7 "always_force_name2": true,
8 "trim_sentences": false,8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "Llama 2 Chat"10 "name": "Llama 2 Chat"
12}11}
default/content/presets/context/Llama 3 Instruct.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": true,7 "always_force_name2": true,
8 "trim_sentences": false,8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "Llama 3 Instruct"10 "name": "Llama 3 Instruct"
12}11}
default/content/presets/context/Llama-3-Instruct-Names.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": true,7 "always_force_name2": true,
8 "trim_sentences": false,8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "Llama-3-Instruct-Names"10 "name": "Llama-3-Instruct-Names"
12}11}
default/content/presets/context/Minimalist.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": true,7 "always_force_name2": true,
8 "trim_sentences": false,8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "Minimalist"10 "name": "Minimalist"
12}11}
default/content/presets/context/Mistral V1.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": true,7 "always_force_name2": true,
8 "trim_sentences": false,8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "Mistral V1"10 "name": "Mistral V1"
12}11}
default/content/presets/context/Mistral V2 & V3.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": true,7 "always_force_name2": true,
8 "trim_sentences": false,8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "Mistral V2 & V3"10 "name": "Mistral V2 & V3"
12}11}
default/content/presets/context/Mistral V3-Tekken.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": true,7 "always_force_name2": true,
8 "trim_sentences": false,8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "Mistral V3-Tekken"10 "name": "Mistral V3-Tekken"
12}11}
default/content/presets/context/NovelAI.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": true,7 "always_force_name2": true,
8 "trim_sentences": false,8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "NovelAI"10 "name": "NovelAI"
12}11}
default/content/presets/context/OldDefault.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": true,7 "always_force_name2": true,
8 "trim_sentences": false,8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "OldDefault"10 "name": "OldDefault"
12}11}
default/content/presets/context/Phi.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": true,7 "always_force_name2": true,
8 "trim_sentences": false,8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "Phi"10 "name": "Phi"
12}11}
default/content/presets/context/Pygmalion.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": true,7 "always_force_name2": true,
8 "trim_sentences": false,8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "Pygmalion"10 "name": "Pygmalion"
12}11}
default/content/presets/context/Story.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": true,7 "always_force_name2": true,
8 "trim_sentences": false,8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "Story"10 "name": "Story"
12}11}
default/content/presets/context/Synthia.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": true,7 "always_force_name2": true,
8 "trim_sentences": false,8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "Synthia"10 "name": "Synthia"
12}11}
default/content/presets/context/simple-proxy-for-tavern.json+0 -1
@@ -6,7 +6,6 @@
6 "allow_jailbreak": false,6 "allow_jailbreak": false,
7 "always_force_name2": true,7 "always_force_name2": true,
8 "trim_sentences": false,8 "trim_sentences": false,
9 "include_newline": false,
10 "single_line": false,9 "single_line": false,
11 "name": "simple-proxy-for-tavern"10 "name": "simple-proxy-for-tavern"
12}11}
default/content/presets/instruct/Adventure.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "[Enter Adventure Mode. Narrate the story based on {{user}}'s dialogue and actions after \">\". Describe the surroundings in vivid detail. Be detailed, creative, verbose, and proactive. Move the story forward by introducing fantasy elements and interesting characters.]",
3 "input_sequence": "",2 "input_sequence": "",
4 "output_sequence": "",3 "output_sequence": "",
5 "last_output_sequence": "",4 "last_output_sequence": "",
default/content/presets/instruct/Alpaca-Roleplay.json+0 -23
@@ -1,23 +0,0 @@
1{
2 "system_prompt": "Develop the plot slowly, always stay in character. Describe all actions in full, elaborate, explicit, graphic, and vivid detail. Mention all relevant sensory perceptions.",
3 "input_sequence": "### Instruction:",
4 "output_sequence": "### Response:",
5 "last_output_sequence": "### Response (2 paragraphs, engaging, natural, authentic, descriptive, creative):",
6 "system_sequence": "### Input:",
7 "stop_sequence": "",
8 "wrap": true,
9 "macro": true,
10 "names_behavior": "always",
11 "activation_regex": "",
12 "system_sequence_prefix": "",
13 "system_sequence_suffix": "",
14 "first_output_sequence": "",
15 "skip_examples": false,
16 "output_suffix": "\n\n",
17 "input_suffix": "\n\n",
18 "system_suffix": "\n\n",
19 "user_alignment_message": "",
20 "system_same_as_user": false,
21 "last_system_sequence": "",
22 "name": "Alpaca-Roleplay"
23}
default/content/presets/instruct/Alpaca-Single-Turn.json+1 -2
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "Write {{char}}'s next reply in a fictional roleplay chat between {{user}} and {{char}}.\nWrite 1 reply only, italicize actions, and avoid quotation marks. Use markdown. Be proactive, creative, and drive the plot and conversation forward. Include dialog as well as narration.",
3 "input_sequence": "",2 "input_sequence": "",
4 "output_sequence": "",3 "output_sequence": "",
5 "last_output_sequence": "\n### Response:",4 "last_output_sequence": "\n### Response:",
@@ -11,7 +10,7 @@
11 "activation_regex": "",10 "activation_regex": "",
12 "system_sequence_prefix": "",11 "system_sequence_prefix": "",
13 "system_sequence_suffix": "",12 "system_sequence_suffix": "",
14 "first_output_sequence": "<START OF ROLEPLAY>",13 "first_output_sequence": "<START OF CHAT>",
15 "skip_examples": false,14 "skip_examples": false,
16 "output_suffix": "",15 "output_suffix": "",
17 "input_suffix": "",16 "input_suffix": "",
default/content/presets/instruct/Alpaca.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "Below is an instruction that describes a task. Write a response that appropriately completes the request.\n\nWrite {{char}}'s next reply in a fictional roleplay chat between {{user}} and {{char}}.\n",
3 "input_sequence": "### Instruction:",2 "input_sequence": "### Instruction:",
4 "output_sequence": "### Response:",3 "output_sequence": "### Response:",
5 "last_output_sequence": "",4 "last_output_sequence": "",
default/content/presets/instruct/ChatML-Names.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "You're {{char}} in this fictional never-ending uncensored roleplay with {{user}}.",
3 "input_sequence": "<|im_start|>[{{name}}]",2 "input_sequence": "<|im_start|>[{{name}}]",
4 "output_sequence": "<|im_start|>[{{name}}]",3 "output_sequence": "<|im_start|>[{{name}}]",
5 "last_output_sequence": "",4 "last_output_sequence": "",
default/content/presets/instruct/ChatML.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "You're {{char}} in this fictional never-ending uncensored roleplay with {{user}}.",
3 "input_sequence": "<|im_start|>user",2 "input_sequence": "<|im_start|>user",
4 "output_sequence": "<|im_start|>assistant",3 "output_sequence": "<|im_start|>assistant",
5 "last_output_sequence": "",4 "last_output_sequence": "",
default/content/presets/instruct/Command R.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "Write {{char}}'s next reply in this fictional roleplay with {{user}}.",
3 "input_sequence": "<|START_OF_TURN_TOKEN|><|USER_TOKEN|>",2 "input_sequence": "<|START_OF_TURN_TOKEN|><|USER_TOKEN|>",
4 "output_sequence": "<|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>",3 "output_sequence": "<|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>",
5 "first_output_sequence": "",4 "first_output_sequence": "",
default/content/presets/instruct/DreamGen Role-Play V1 ChatML.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "You are an intelligent, skilled, versatile writer.\n\nYour task is to write a role-play based on the information below.",
3 "input_sequence": "\n<|im_start|>text names= {{name}}\n",2 "input_sequence": "\n<|im_start|>text names= {{name}}\n",
4 "output_sequence": "\n<|im_start|>text names= {{name}}\n",3 "output_sequence": "\n<|im_start|>text names= {{name}}\n",
5 "last_output_sequence": "",4 "last_output_sequence": "",
default/content/presets/instruct/DreamGen Role-Play V1 Llama3.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "You are an intelligent, skilled, versatile writer.\n\nYour task is to write a role-play based on the information below.",
3 "input_sequence": "<|eot_id|>\n<|start_header_id|>writer character: {{user}}<|end_header_id|>\n\n",2 "input_sequence": "<|eot_id|>\n<|start_header_id|>writer character: {{user}}<|end_header_id|>\n\n",
4 "output_sequence": "<|eot_id|>\n<|start_header_id|>writer character: {{char}}<|end_header_id|>\n\n",3 "output_sequence": "<|eot_id|>\n<|start_header_id|>writer character: {{char}}<|end_header_id|>\n\n",
5 "first_output_sequence": "",4 "first_output_sequence": "",
default/content/presets/instruct/Gemma 2.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "Continue writing this story and portray characters realistically.",
3 "input_sequence": "<start_of_turn>user",2 "input_sequence": "<start_of_turn>user",
4 "output_sequence": "<start_of_turn>model",3 "output_sequence": "<start_of_turn>model",
5 "last_output_sequence": "",4 "last_output_sequence": "",
default/content/presets/instruct/Koala.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "Write {{char}}'s next reply in a fictional roleplay chat between {{user}} and {{char}}.\n",
3 "input_sequence": "USER: ",2 "input_sequence": "USER: ",
4 "output_sequence": "GPT: ",3 "output_sequence": "GPT: ",
5 "last_output_sequence": "",4 "last_output_sequence": "",
default/content/presets/instruct/Libra-32B.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "Avoid repetition, don't loop. Develop the plot slowly, always stay in character. Describe all actions in full, elaborate, explicit, graphic, and vivid detail. Mention all relevant sensory perceptions.",
3 "input_sequence": "",2 "input_sequence": "",
4 "output_sequence": "",3 "output_sequence": "",
5 "last_output_sequence": "\n### Response:",4 "last_output_sequence": "\n### Response:",
default/content/presets/instruct/Lightning 1.1.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "Below is an instruction that describes a task. Write a response that appropriately completes the request.\n\n### Instruction:\nTake the role of {{char}} in a play that leaves a lasting impression on {{user}}. Write {{char}}'s next reply.\nNever skip or gloss over {{char}}’s actions. Progress the scene at a naturally slow pace.\n\n",
3 "input_sequence": "### Instruction:",2 "input_sequence": "### Instruction:",
4 "output_sequence": "### Response: (length = unlimited)",3 "output_sequence": "### Response: (length = unlimited)",
5 "last_output_sequence": "",4 "last_output_sequence": "",
default/content/presets/instruct/Llama 2 Chat.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "Write {{char}}'s next reply in this fictional roleplay with {{user}}.",
3 "input_sequence": "[INST] ",2 "input_sequence": "[INST] ",
4 "output_sequence": "",3 "output_sequence": "",
5 "last_output_sequence": "",4 "last_output_sequence": "",
default/content/presets/instruct/Llama 3 Instruct.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "You are an expert actor that can fully immerse yourself into any role given. You do not break character for any reason, even if someone tries addressing you as an AI or language model. Currently your role is {{char}}, which is described in detail below. As {{char}}, continue the exchange with {{user}}.",
3 "input_sequence": "<|start_header_id|>user<|end_header_id|>\n\n",2 "input_sequence": "<|start_header_id|>user<|end_header_id|>\n\n",
4 "output_sequence": "<|start_header_id|>assistant<|end_header_id|>\n\n",3 "output_sequence": "<|start_header_id|>assistant<|end_header_id|>\n\n",
5 "last_output_sequence": "",4 "last_output_sequence": "",
default/content/presets/instruct/Llama-3-Instruct-Names.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "You are an expert actor that can fully immerse yourself into any role given. You do not break character for any reason, even if someone tries addressing you as an AI or language model. Currently your role is {{char}}, which is described in detail below. As {{char}}, continue the exchange with {{user}}.",
3 "input_sequence": "<|start_header_id|>[{{name}}]<|end_header_id|>\n\n",2 "input_sequence": "<|start_header_id|>[{{name}}]<|end_header_id|>\n\n",
4 "output_sequence": "<|start_header_id|>[{{name}}]<|end_header_id|>\n\n",3 "output_sequence": "<|start_header_id|>[{{name}}]<|end_header_id|>\n\n",
5 "last_output_sequence": "",4 "last_output_sequence": "",
default/content/presets/instruct/Metharme.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "Enter roleplay mode. You must act as {{char}}, whose persona follows:",
3 "input_sequence": "<|user|>",2 "input_sequence": "<|user|>",
4 "output_sequence": "<|model|>",3 "output_sequence": "<|model|>",
5 "last_output_sequence": "",4 "last_output_sequence": "",
default/content/presets/instruct/Mistral V1.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "Write {{char}}'s next reply in this fictional roleplay with {{user}}.",
3 "input_sequence": " [INST] ",2 "input_sequence": " [INST] ",
4 "output_sequence": " [/INST] ",3 "output_sequence": " [/INST] ",
5 "last_output_sequence": " [/INST]",4 "last_output_sequence": " [/INST]",
default/content/presets/instruct/Mistral V2 & V3.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "Write {{char}}'s next reply in this fictional roleplay with {{user}}.",
3 "input_sequence": "[INST] ",2 "input_sequence": "[INST] ",
4 "output_sequence": "[/INST] ",3 "output_sequence": "[/INST] ",
5 "last_output_sequence": "[/INST]",4 "last_output_sequence": "[/INST]",
default/content/presets/instruct/Mistral V3-Tekken.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "Write {{char}}'s next reply in this fictional roleplay with {{user}}.",
3 "input_sequence": "[INST]",2 "input_sequence": "[INST]",
4 "output_sequence": "[/INST]",3 "output_sequence": "[/INST]",
5 "last_output_sequence": "",4 "last_output_sequence": "",
default/content/presets/instruct/OpenOrca-OpenChat.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "You are a helpful assistant. Please answer truthfully and write out your thinking step by step to be sure you get the right answer. If you make a mistake or encounter an error in your thinking, say so out loud and attempt to correct it. If you don't know or aren't sure about something, say so clearly. You will act as a professional logician, mathematician, and physicist. You will also act as the most appropriate type of expert to answer any particular question or solve the relevant problem; state which expert type your are, if so. Also think of any particular named expert that would be ideal to answer the relevant question or solve the relevant problem; name and act as them, if appropriate.\n",
3 "input_sequence": "\nUser: ",2 "input_sequence": "\nUser: ",
4 "output_sequence": "\nAssistant: ",3 "output_sequence": "\nAssistant: ",
5 "last_output_sequence": "",4 "last_output_sequence": "",
default/content/presets/instruct/Phi.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "Write {{char}}'s next reply in this fictional roleplay with {{user}}.",
3 "input_sequence": "<|user|>\n",2 "input_sequence": "<|user|>\n",
4 "output_sequence": "<|assistant|>\n",3 "output_sequence": "<|assistant|>\n",
5 "first_output_sequence": "",4 "first_output_sequence": "",
default/content/presets/instruct/Pygmalion.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "Enter RP mode. You shall reply to {{user}} while staying in character. Your responses must be detailed, creative, immersive, and drive the scenario forward. You will follow {{char}}'s persona.",
3 "input_sequence": "<|user|>",2 "input_sequence": "<|user|>",
4 "output_sequence": "<|model|>",3 "output_sequence": "<|model|>",
5 "last_output_sequence": "",4 "last_output_sequence": "",
default/content/presets/instruct/Story.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "",
3 "input_sequence": "",2 "input_sequence": "",
4 "output_sequence": "",3 "output_sequence": "",
5 "last_output_sequence": "",4 "last_output_sequence": "",
default/content/presets/instruct/Synthia.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "Elaborate on the topic using a Tree of Thoughts and backtrack when necessary to construct a clear, cohesive Chain of Thought reasoning. Always answer without hesitation.",
3 "input_sequence": "USER: ",2 "input_sequence": "USER: ",
4 "output_sequence": "ASSISTANT: ",3 "output_sequence": "ASSISTANT: ",
5 "last_output_sequence": "",4 "last_output_sequence": "",
default/content/presets/instruct/Vicuna 1.0.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "A chat between a curious human and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the human's questions.\n\nWrite {{char}}'s next reply in a fictional roleplay chat between {{user}} and {{char}}.\n",
3 "input_sequence": "### Human:",2 "input_sequence": "### Human:",
4 "output_sequence": "### Assistant:",3 "output_sequence": "### Assistant:",
5 "last_output_sequence": "",4 "last_output_sequence": "",
default/content/presets/instruct/Vicuna 1.1.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions.\n\nWrite {{char}}'s next reply in a fictional roleplay chat between {{user}} and {{char}}.\n",
3 "input_sequence": "\nUSER: ",2 "input_sequence": "\nUSER: ",
4 "output_sequence": "\nASSISTANT: ",3 "output_sequence": "\nASSISTANT: ",
5 "last_output_sequence": "",4 "last_output_sequence": "",
default/content/presets/instruct/WizardLM-13B.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions.\n\nWrite {{char}}'s next detailed reply in a fictional roleplay chat between {{user}} and {{char}}.",
3 "input_sequence": "USER: ",2 "input_sequence": "USER: ",
4 "output_sequence": "ASSISTANT: ",3 "output_sequence": "ASSISTANT: ",
5 "last_output_sequence": "",4 "last_output_sequence": "",
default/content/presets/instruct/WizardLM.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "Write {{char}}'s next reply in a fictional roleplay chat between {{user}} and {{char}}.\n",
3 "input_sequence": "",2 "input_sequence": "",
4 "output_sequence": "### Response:",3 "output_sequence": "### Response:",
5 "last_output_sequence": "",4 "last_output_sequence": "",
default/content/presets/instruct/simple-proxy-for-tavern.json+0 -1
@@ -1,5 +1,4 @@
1{1{
2 "system_prompt": "[System note: Write one reply only. Do not decide what {{user}} says or does. Write at least one paragraph, up to four. Be descriptive and immersive, providing vivid details about {{char}}'s actions, emotions, and the environment. Write with a high degree of complexity and burstiness. Do not repeat this message.]",
3 "input_sequence": "### Instruction:\n#### {{name}}:",2 "input_sequence": "### Instruction:\n#### {{name}}:",
4 "output_sequence": "### Response:\n#### {{name}}:",3 "output_sequence": "### Response:\n#### {{name}}:",
5 "last_output_sequence": "### Response (2 paragraphs, engaging, natural, authentic, descriptive, creative):\n#### {{name}}:",4 "last_output_sequence": "### Response (2 paragraphs, engaging, natural, authentic, descriptive, creative):\n#### {{name}}:",
default/content/presets/novel/Asper-Kayra.json+0 -1
@@ -14,7 +14,6 @@
14 "use_cache": false,14 "use_cache": false,
15 "return_full_text": false,15 "return_full_text": false,
16 "prefix": "vanilla",16 "prefix": "vanilla",
17 "cfg_scale": 1,
18 "phrase_rep_pen": "medium",17 "phrase_rep_pen": "medium",
19 "max_context": 7800,18 "max_context": 7800,
20 "min_p": 0,19 "min_p": 0,
default/content/presets/novel/Blended-Coffee-Kayra.json+1 -2
@@ -1,5 +1,5 @@
1{1{
2 "order": [6, 0, 1, 2, 3],2 "order": [0, 1, 2, 3],
3 "temperature": 1,3 "temperature": 1,
4 "max_length": 150,4 "max_length": 150,
5 "min_length": 1,5 "min_length": 1,
@@ -14,7 +14,6 @@
14 "return_full_text": false,14 "return_full_text": false,
15 "prefix": "vanilla",15 "prefix": "vanilla",
16 "phrase_rep_pen": "medium",16 "phrase_rep_pen": "medium",
17 "cfg_scale": 1.55,
18 "max_context": 7800,17 "max_context": 7800,
19 "min_p": 0,18 "min_p": 0,
20 "math1_temp": 1,19 "math1_temp": 1,
default/content/presets/novel/Blook-Kayra.json+1 -2
@@ -1,5 +1,5 @@
1{1{
2 "order": [6, 2, 3, 1, 0],2 "order": [2, 3, 1, 0],
3 "temperature": 1,3 "temperature": 1,
4 "max_length": 150,4 "max_length": 150,
5 "min_length": 1,5 "min_length": 1,
@@ -15,7 +15,6 @@
15 "return_full_text": false,15 "return_full_text": false,
16 "prefix": "vanilla",16 "prefix": "vanilla",
17 "phrase_rep_pen": "very_aggressive",17 "phrase_rep_pen": "very_aggressive",
18 "cfg_scale": 1.3,
19 "max_context": 7800,18 "max_context": 7800,
20 "min_p": 0,19 "min_p": 0,
21 "math1_temp": 1,20 "math1_temp": 1,
default/content/presets/novel/Carefree-Kayra.json+0 -1
@@ -15,7 +15,6 @@
15 "use_cache": false,15 "use_cache": false,
16 "return_full_text": false,16 "return_full_text": false,
17 "prefix": "vanilla",17 "prefix": "vanilla",
18 "cfg_scale": 1,
19 "phrase_rep_pen": "aggressive",18 "phrase_rep_pen": "aggressive",
20 "max_context": 7800,19 "max_context": 7800,
21 "min_p": 0,20 "min_p": 0,
default/content/presets/novel/CosmicCube-Kayra.json+1 -2
@@ -1,5 +1,5 @@
1{1{
2 "order": [8, 6, 5, 0, 3],2 "order": [8, 5, 0, 3],
3 "temperature": 0.9,3 "temperature": 0.9,
4 "max_length": 150,4 "max_length": 150,
5 "min_length": 1,5 "min_length": 1,
@@ -15,7 +15,6 @@
15 "return_full_text": false,15 "return_full_text": false,
16 "prefix": "vanilla",16 "prefix": "vanilla",
17 "phrase_rep_pen": "off",17 "phrase_rep_pen": "off",
18 "cfg_scale": 1.48,
19 "max_context": 7800,18 "max_context": 7800,
20 "min_p": 0,19 "min_p": 0,
21 "math1_temp": 1,20 "math1_temp": 1,
default/content/presets/novel/Edgewise-Clio.json+0 -1
@@ -15,7 +15,6 @@
15 "use_cache": false,15 "use_cache": false,
16 "return_full_text": false,16 "return_full_text": false,
17 "prefix": "vanilla",17 "prefix": "vanilla",
18 "cfg_scale": 1,
19 "phrase_rep_pen": "very_light",18 "phrase_rep_pen": "very_light",
20 "max_context": 7800,19 "max_context": 7800,
21 "min_p": 0,20 "min_p": 0,
default/content/presets/novel/Erato-Dragonfruit.json+31 -0
@@ -0,0 +1,31 @@
1{
2 "max_context": 8000,
3 "temperature": 1.37,
4 "max_length": 150,
5 "min_length": 1,
6 "top_k": 0,
7 "top_p": 1,
8 "top_a": 0.1,
9 "typical_p": 0.875,
10 "tail_free_sampling": 0.87,
11 "repetition_penalty": 3.25,
12 "repetition_penalty_range": 6000,
13 "repetition_penalty_slope": 3.25,
14 "repetition_penalty_frequency": 0,
15 "repetition_penalty_presence": 0,
16 "phrase_rep_pen": "off",
17 "mirostat_lr": 0.2,
18 "mirostat_tau": 4,
19 "math1_temp": 0.9,
20 "math1_quad": 0.07,
21 "math1_quad_entropy_scale": -0.05,
22 "min_p": 0.035,
23 "order": [
24 0,
25 5,
26 9,
27 10,
28 8,
29 4
30 ]
31}
default/content/presets/novel/Erato-Golden Arrow.json+27 -0
@@ -0,0 +1,27 @@
1{
2 "max_context": 8000,
3 "temperature": 1,
4 "max_length": 150,
5 "min_length": 1,
6 "top_k": 0,
7 "top_p": 0.995,
8 "top_a": 1,
9 "typical_p": 1,
10 "tail_free_sampling": 0.87,
11 "repetition_penalty": 1.5,
12 "repetition_penalty_range": 2240,
13 "repetition_penalty_slope": 1,
14 "repetition_penalty_frequency": 0,
15 "repetition_penalty_presence": 0,
16 "phrase_rep_pen": "light",
17 "mirostat_lr": 1,
18 "mirostat_tau": 0,
19 "math1_temp": 0.3,
20 "math1_quad": 0.19,
21 "math1_quad_entropy_scale": 0,
22 "min_p": 0,
23 "order": [
24 9,
25 2
26 ]
27}
default/content/presets/novel/Erato-Shosetsu.json+27 -0
@@ -0,0 +1,27 @@
1{
2 "max_context": 8000,
3 "temperature": 1,
4 "max_length": 150,
5 "min_length": 1,
6 "top_k": 50,
7 "top_p": 0.85,
8 "top_a": 1,
9 "typical_p": 1,
10 "tail_free_sampling": 0.895,
11 "repetition_penalty": 1.63,
12 "repetition_penalty_range": 1024,
13 "repetition_penalty_slope": 3.33,
14 "repetition_penalty_frequency": 0.0035,
15 "repetition_penalty_presence": 0,
16 "phrase_rep_pen": "medium",
17 "mirostat_lr": 1,
18 "mirostat_tau": 0,
19 "math1_temp": 0.3,
20 "math1_quad": 0.0645,
21 "math1_quad_entropy_scale": 0.05,
22 "min_p": 0.05,
23 "order": [
24 9,
25 10
26 ]
27}
default/content/presets/novel/Erato-Wilder.json+27 -0
@@ -0,0 +1,27 @@
1{
2 "max_context": 8000,
3 "temperature": 1,
4 "max_length": 150,
5 "min_length": 1,
6 "top_k": 300,
7 "top_p": 0.98,
8 "top_a": 0.004,
9 "typical_p": 0.96,
10 "tail_free_sampling": 0.96,
11 "repetition_penalty": 1.48,
12 "repetition_penalty_range": 2240,
13 "repetition_penalty_slope": 0.64,
14 "repetition_penalty_frequency": 0,
15 "repetition_penalty_presence": 0,
16 "phrase_rep_pen": "medium",
17 "mirostat_lr": 1,
18 "mirostat_tau": 0,
19 "math1_temp": -0.0485,
20 "math1_quad": 0.145,
21 "math1_quad_entropy_scale": 0,
22 "min_p": 0.02,
23 "order": [
24 9,
25 10
26 ]
27}
default/content/presets/novel/Erato-Zany Scribe.json+27 -0
@@ -0,0 +1,27 @@
1{
2 "max_context": 8000,
3 "temperature": 1,
4 "max_length": 150,
5 "min_length": 1,
6 "top_k": 0,
7 "top_p": 0.99,
8 "top_a": 1,
9 "typical_p": 1,
10 "tail_free_sampling": 0.99,
11 "repetition_penalty": 1,
12 "repetition_penalty_range": 64,
13 "repetition_penalty_slope": 1,
14 "repetition_penalty_frequency": 0.75,
15 "repetition_penalty_presence": 1.5,
16 "phrase_rep_pen": "medium",
17 "mirostat_lr": 1,
18 "mirostat_tau": 1,
19 "math1_temp": -0.4,
20 "math1_quad": 0.6,
21 "math1_quad_entropy_scale": -0.1,
22 "min_p": 0.08,
23 "order": [
24 9,
25 2
26 ]
27}
default/content/presets/novel/Fresh-Coffee-Clio.json+0 -1
@@ -16,7 +16,6 @@
16 "use_cache": false,16 "use_cache": false,
17 "return_full_text": false,17 "return_full_text": false,
18 "prefix": "vanilla",18 "prefix": "vanilla",
19 "cfg_scale": 1,
20 "phrase_rep_pen": "very_light",19 "phrase_rep_pen": "very_light",
21 "max_context": 7800,20 "max_context": 7800,
22 "min_p": 0,21 "min_p": 0,
default/content/presets/novel/Fresh-Coffee-Kayra.json+0 -1
@@ -14,7 +14,6 @@
14 "use_cache": false,14 "use_cache": false,
15 "return_full_text": false,15 "return_full_text": false,
16 "prefix": "vanilla",16 "prefix": "vanilla",
17 "cfg_scale": 1,
18 "phrase_rep_pen": "off",17 "phrase_rep_pen": "off",
19 "max_context": 7800,18 "max_context": 7800,
20 "min_p": 0,19 "min_p": 0,
default/content/presets/novel/Green-Active-Writer-Kayra.json+1 -2
@@ -1,5 +1,5 @@
1{1{
2 "order": [6, 0, 8, 5, 3],2 "order": [0, 8, 5, 3],
3 "temperature": 1.5,3 "temperature": 1.5,
4 "max_length": 150,4 "max_length": 150,
5 "min_length": 1,5 "min_length": 1,
@@ -15,7 +15,6 @@
15 "return_full_text": false,15 "return_full_text": false,
16 "prefix": "vanilla",16 "prefix": "vanilla",
17 "phrase_rep_pen": "very_aggressive",17 "phrase_rep_pen": "very_aggressive",
18 "cfg_scale": 1.4,
19 "max_context": 7800,18 "max_context": 7800,
20 "min_p": 0,19 "min_p": 0,
21 "math1_temp": 1,20 "math1_temp": 1,
default/content/presets/novel/Keelback-Clio.json+0 -1
@@ -16,7 +16,6 @@
16 "use_cache": false,16 "use_cache": false,
17 "return_full_text": false,17 "return_full_text": false,
18 "prefix": "vanilla",18 "prefix": "vanilla",
19 "cfg_scale": 1,
20 "phrase_rep_pen": "very_light",19 "phrase_rep_pen": "very_light",
21 "max_context": 7800,20 "max_context": 7800,
22 "min_p": 0,21 "min_p": 0,
default/content/presets/novel/Long-Press-Clio.json+0 -1
@@ -16,7 +16,6 @@
16 "use_cache": false,16 "use_cache": false,
17 "return_full_text": false,17 "return_full_text": false,
18 "prefix": "vanilla",18 "prefix": "vanilla",
19 "cfg_scale": 1,
20 "phrase_rep_pen": "very_light",19 "phrase_rep_pen": "very_light",
21 "max_context": 7800,20 "max_context": 7800,
22 "min_p": 0,21 "min_p": 0,
default/content/presets/novel/Pilotfish-Kayra.json+1 -2
@@ -1,5 +1,5 @@
1{1{
2 "order": [6, 0, 4, 1, 2, 5, 3],2 "order": [0, 4, 1, 2, 5, 3],
3 "temperature": 1.31,3 "temperature": 1.31,
4 "max_length": 150,4 "max_length": 150,
5 "min_length": 1,5 "min_length": 1,
@@ -17,7 +17,6 @@
17 "return_full_text": false,17 "return_full_text": false,
18 "prefix": "vanilla",18 "prefix": "vanilla",
19 "phrase_rep_pen": "medium",19 "phrase_rep_pen": "medium",
20 "cfg_scale": 1.35,
21 "max_context": 7800,20 "max_context": 7800,
22 "min_p": 0,21 "min_p": 0,
23 "math1_temp": 1,22 "math1_temp": 1,
default/content/presets/novel/Pro_Writer-Kayra.json+0 -1
@@ -15,7 +15,6 @@
15 "return_full_text": false,15 "return_full_text": false,
16 "prefix": "vanilla",16 "prefix": "vanilla",
17 "phrase_rep_pen": "medium",17 "phrase_rep_pen": "medium",
18 "cfg_scale": 1.0,
19 "max_context": 7800,18 "max_context": 7800,
20 "min_p": 0,19 "min_p": 0,
21 "math1_temp": 1,20 "math1_temp": 1,
default/content/presets/novel/Talker-Chat-Clio.json+0 -1
@@ -16,7 +16,6 @@
16 "use_cache": false,16 "use_cache": false,
17 "return_full_text": false,17 "return_full_text": false,
18 "prefix": "vanilla",18 "prefix": "vanilla",
19 "cfg_scale": 1,
20 "phrase_rep_pen": "very_light",19 "phrase_rep_pen": "very_light",
21 "max_context": 7800,20 "max_context": 7800,
22 "min_p": 0,21 "min_p": 0,
default/content/presets/novel/Tea_Time-Kayra.json+0 -1
@@ -14,7 +14,6 @@
14 "return_full_text": false,14 "return_full_text": false,
15 "prefix": "vanilla",15 "prefix": "vanilla",
16 "phrase_rep_pen": "aggressive",16 "phrase_rep_pen": "aggressive",
17 "cfg_scale": 1.0,
18 "max_context": 7800,17 "max_context": 7800,
19 "min_p": 0,18 "min_p": 0,
20 "math1_temp": 1,19 "math1_temp": 1,
default/content/presets/novel/Tesseract-Kayra.json+1 -2
@@ -1,5 +1,5 @@
1{1{
2 "order": [6, 0, 5],2 "order": [0, 5],
3 "temperature": 0.895,3 "temperature": 0.895,
4 "max_length": 150,4 "max_length": 150,
5 "min_length": 1,5 "min_length": 1,
@@ -13,7 +13,6 @@
13 "return_full_text": false,13 "return_full_text": false,
14 "prefix": "vanilla",14 "prefix": "vanilla",
15 "phrase_rep_pen": "aggressive",15 "phrase_rep_pen": "aggressive",
16 "cfg_scale": 1.3,
17 "max_context": 7800,16 "max_context": 7800,
18 "min_p": 0,17 "min_p": 0,
19 "math1_temp": 1,18 "math1_temp": 1,
default/content/presets/novel/Vingt-Un-Clio.json+0 -1
@@ -16,7 +16,6 @@
16 "use_cache": false,16 "use_cache": false,
17 "return_full_text": false,17 "return_full_text": false,
18 "prefix": "vanilla",18 "prefix": "vanilla",
19 "cfg_scale": 1,
20 "phrase_rep_pen": "very_light",19 "phrase_rep_pen": "very_light",
21 "max_context": 7800,20 "max_context": 7800,
22 "min_p": 0,21 "min_p": 0,
default/content/presets/openai/Default.json+0 -1
@@ -5,7 +5,6 @@
5 "windowai_model": "",5 "windowai_model": "",
6 "openrouter_model": "OR_Website",6 "openrouter_model": "OR_Website",
7 "openrouter_use_fallback": false,7 "openrouter_use_fallback": false,
8 "openrouter_force_instruct": false,
9 "openrouter_group_models": false,8 "openrouter_group_models": false,
10 "openrouter_sort_models": "alphabetically",9 "openrouter_sort_models": "alphabetically",
11 "ai21_model": "jamba-1.5-large",10 "ai21_model": "jamba-1.5-large",
default/content/presets/sysprompt/Actor.json+4 -0
@@ -0,0 +1,4 @@
1{
2 "name": "Actor",
3 "content": "You are an expert actor that can fully immerse yourself into any role given. You do not break character for any reason, even if someone tries addressing you as an AI or language model. Currently your role is {{char}}, which is described in detail below. As {{char}}, continue the exchange with {{user}}."
4}
default/content/presets/sysprompt/Assistant - Expert.json+4 -0
@@ -0,0 +1,4 @@
1{
2 "name": "Assistant - Expert",
3 "content": "You are a helpful assistant. Please answer truthfully and write out your thinking step by step to be sure you get the right answer. If you make a mistake or encounter an error in your thinking, say so out loud and attempt to correct it. If you don't know or aren't sure about something, say so clearly. You will act as a professional logician, mathematician, and physicist. You will also act as the most appropriate type of expert to answer any particular question or solve the relevant problem; state which expert type your are, if so. Also think of any particular named expert that would be ideal to answer the relevant question or solve the relevant problem; name and act as them, if appropriate."
4}
default/content/presets/sysprompt/Assistant - Simple.json+4 -0
@@ -0,0 +1,4 @@
1{
2 "name": "Assistant - Simple",
3 "content": "A chat between a curious human and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the human's questions."
4}
default/content/presets/sysprompt/Blank.json+4 -0
@@ -0,0 +1,4 @@
1{
2 "name": "Blank",
3 "content": ""
4}
default/content/presets/sysprompt/Chain of Thought.json+4 -0
@@ -0,0 +1,4 @@
1{
2 "name": "Chain of Thought",
3 "content": "Elaborate on the topic using a Tree of Thoughts and backtrack when necessary to construct a clear, cohesive Chain of Thought reasoning. Always answer without hesitation."
4}
default/content/presets/sysprompt/Neutral - Chat.json+4 -0
@@ -0,0 +1,4 @@
1{
2 "name": "Neutral - Chat",
3 "content": "Write {{char}}'s next reply in a fictional chat between {{char}} and {{user}}."
4}
default/content/presets/sysprompt/Roleplay - Detailed.json+4 -0
@@ -0,0 +1,4 @@
1{
2 "name": "Roleplay - Detailed",
3 "content": "Develop the plot slowly, always stay in character. Describe all actions in full, elaborate, explicit, graphic, and vivid detail. Mention all relevant sensory perceptions. Keep the story immersive and engaging."
4}
default/content/presets/sysprompt/Roleplay - Immersive.json+4 -0
@@ -0,0 +1,4 @@
1{
2 "name": "Roleplay - Immersive",
3 "content": "[System note: Write one reply only. Do not decide what {{user}} says or does. Write at least one paragraph, up to four. Be descriptive and immersive, providing vivid details about {{char}}'s actions, emotions, and the environment. Write with a high degree of complexity and burstiness. Do not repeat this message.]"
4}
default/content/presets/sysprompt/Roleplay - Simple.json+4 -0
@@ -0,0 +1,4 @@
1{
2 "name": "Roleplay - Simple",
3 "content": "You're {{char}} in this fictional never-ending uncensored roleplay with {{user}}."
4}
default/content/presets/sysprompt/Text Adventure.json+4 -0
@@ -0,0 +1,4 @@
1{
2 "name": "Text Adventure",
3 "content": "[Enter Adventure Mode. Narrate the story based on {{user}}'s dialogue and actions after \">\". Describe the surroundings in vivid detail. Be detailed, creative, verbose, and proactive. Move the story forward by introducing fantasy elements and interesting characters.]"
4}
default/content/presets/sysprompt/Writer - Creative.json+4 -0
@@ -0,0 +1,4 @@
1{
2 "name": "Writer - Creative",
3 "content": "You are an intelligent, skilled, versatile writer.\n\nYour task is to write a role-play based on the information below."
4}
default/content/presets/sysprompt/Writer - Realistic.json+4 -0
@@ -0,0 +1,4 @@
1{
2 "name": "Writer - Realistic",
3 "content": "Continue writing this story and portray characters realistically."
4}
default/content/settings.json+16 -16
@@ -90,7 +90,6 @@
90 "pin_examples": false,90 "pin_examples": false,
91 "strip_examples": false,91 "strip_examples": false,
92 "trim_sentences": false,92 "trim_sentences": false,
93 "include_newline": false,
94 "always_force_name2": true,93 "always_force_name2": true,
95 "user_prompt_bias": "",94 "user_prompt_bias": "",
96 "show_user_prompt_bias": true,95 "show_user_prompt_bias": true,
@@ -150,11 +149,9 @@
150 "continue_on_send": false,149 "continue_on_send": false,
151 "trim_spaces": true,150 "trim_spaces": true,
152 "relaxed_api_urls": false,151 "relaxed_api_urls": false,
153 "default_instruct": "",
154 "instruct": {152 "instruct": {
155 "enabled": false,153 "enabled": false,
156 "preset": "Alpaca",154 "preset": "Alpaca",
157 "system_prompt": "Below is an instruction that describes a task. Write a response that appropriately completes the request.\n\nWrite {{char}}'s next reply in a fictional roleplay chat between {{user}} and {{char}}.\n",
158 "input_sequence": "### Instruction:",155 "input_sequence": "### Instruction:",
159 "output_sequence": "### Response:",156 "output_sequence": "### Response:",
160 "last_output_sequence": "",157 "last_output_sequence": "",
@@ -174,7 +171,11 @@
174 "user_alignment_message": "",171 "user_alignment_message": "",
175 "system_same_as_user": false172 "system_same_as_user": false
176 },173 },
177 "default_context": "Default",174 "sysprompt": {
175 "enabled": true,
176 "name": "Neutral - Chat",
177 "content": "Write {{char}}'s next reply in a fictional chat between {{char}} and {{user}}."
178 },
178 "context": {179 "context": {
179 "preset": "Default",180 "preset": "Default",
180 "story_string": "{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}",181 "story_string": "{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}",
@@ -234,7 +235,7 @@
234 "lengthPenaltyStep": 0.1,235 "lengthPenaltyStep": 0.1,
235 "memoryFrozen": false,236 "memoryFrozen": false,
236 "source": "extras",237 "source": "extras",
237 "prompt": "[Pause your roleplay. Summarize the most important facts and events that have happened in the chat so far. If a summary already exists in your memory, use that as a base and expand with new facts. Limit the summary to {{words}} words or less. Your response should include nothing but the summary.]",238 "prompt": "Ignore previous instructions. Summarize the most important facts and events in the story so far. If a summary already exists in your memory, use that as a base and expand with new facts. Limit the summary to {{words}} words or less. Your response should include nothing but the summary.",
238 "promptWords": 200,239 "promptWords": 200,
239 "promptMinWords": 25,240 "promptMinWords": 25,
240 "promptMaxWords": 1000,241 "promptMaxWords": 1000,
@@ -297,13 +298,13 @@
297 "horde_karras": true,298 "horde_karras": true,
298 "refine_mode": false,299 "refine_mode": false,
299 "prompts": {300 "prompts": {
300 "0": "[In the next response I want you to provide only a detailed comma-delimited list of keywords and phrases which describe {{char}}. The list must include all of the following items in this order: name, species and race, gender, age, clothing, occupation, physical features and appearances. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase 'full body portrait,']",301 "0": "In the next response I want you to provide only a detailed comma-delimited list of keywords and phrases which describe {{char}}. The list must include all of the following items in this order: name, species and race, gender, age, clothing, occupation, physical features and appearances. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase 'full body portrait,'",
301 "1": "[Pause your roleplay and provide a detailed description of {{user}}'s physical appearance from the perspective of {{char}} in the form of a comma-delimited list of keywords and phrases. The list must include all of the following items in this order: name, species and race, gender, age, clothing, occupation, physical features and appearances. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase 'full body portrait,'. Ignore the rest of the story when crafting this description. Do not roleplay as {{char}} when writing this description, and do not attempt to continue the story.]",302 "1": "Ignore previous instructions and provide a detailed description of {{user}}'s physical appearance from the perspective of {{char}} in the form of a comma-delimited list of keywords and phrases. The list must include all of the following items in this order: name, species and race, gender, age, clothing, occupation, physical features and appearances. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase 'full body portrait,'. Ignore the rest of the story when crafting this description. Do not reply as {{char}} when writing this description, and do not attempt to continue the story.",
302 "2": "[Pause your roleplay and provide a detailed description for all of the following: a brief recap of recent events in the story, {{char}}'s appearance, and {{char}}'s surroundings. Do not roleplay while writing this description.]",303 "2": "Ignore previous instructions and provide a detailed description for all of the following: a brief recap of recent events in the story, {{char}}'s appearance, and {{char}}'s surroundings. Do not reply as {{char}} when writing this description, and do not attempt to continue the story.",
303 "3": "[Pause your roleplay and provide ONLY the last chat message string back to me verbatim. Do not write anything after the string. Do not roleplay at all in your response. Do not continue the roleplay story.]",304 "3": "Ignore previous instructions and provide ONLY the last chat message string back to me verbatim. Do not write anything after the string. Do not reply as {{char}} when writing this description, and do not attempt to continue the story.",
304 "4": "[Pause your roleplay. Your next response must be formatted as a single comma-delimited list of concise keywords. The list will describe of the visual details included in the last chat message.\n\n Only mention characters by using pronouns ('he','his','she','her','it','its') or neutral nouns ('male', 'the man', 'female', 'the woman').\n\n Ignore non-visible things such as feelings, personality traits, thoughts, and spoken dialog.\n\n Add keywords in this precise order:\n a keyword to describe the location of the scene,\n a keyword to mention how many characters of each gender or type are present in the scene (minimum of two characters:\n {{user}} and {{char}}, example: '2 men ' or '1 man 1 woman ', '1 man 3 robots'),\n\n keywords to describe the relative physical positioning of the characters to each other (if a commonly known term for the positioning is known use it instead of describing the positioning in detail) + 'POV',\n\n a single keyword or phrase to describe the primary act taking place in the last chat message,\n\n keywords to describe {{char}}'s physical appearance and facial expression,\n keywords to describe {{char}}'s actions,\n keywords to describe {{user}}'s physical appearance and actions.\n\n If character actions involve direct physical interaction with another character, mention specifically which body parts interacting and how.\n\n A correctly formatted example response would be:\n '(location),(character list by gender),(primary action), (relative character position) POV, (character 1's description and actions), (character 2's description and actions)']",305 "4": "Ignore previous instructions. Your next response must be formatted as a single comma-delimited list of concise keywords. The list will describe of the visual details included in the last chat message.\n\n Only mention characters by using pronouns ('he','his','she','her','it','its') or neutral nouns ('male', 'the man', 'female', 'the woman').\n\n Ignore non-visible things such as feelings, personality traits, thoughts, and spoken dialog.\n\n Add keywords in this precise order:\n a keyword to describe the location of the scene,\n a keyword to mention how many characters of each gender or type are present in the scene (minimum of two characters:\n {{user}} and {{char}}, example: '2 men ' or '1 man 1 woman ', '1 man 3 robots'),\n\n keywords to describe the relative physical positioning of the characters to each other (if a commonly known term for the positioning is known use it instead of describing the positioning in detail) + 'POV',\n\n a single keyword or phrase to describe the primary act taking place in the last chat message,\n\n keywords to describe {{char}}'s physical appearance and facial expression,\n keywords to describe {{char}}'s actions,\n keywords to describe {{user}}'s physical appearance and actions.\n\n If character actions involve direct physical interaction with another character, mention specifically which body parts interacting and how.\n\n A correctly formatted example response would be:\n '(location),(character list by gender),(primary action), (relative character position) POV, (character 1's description and actions), (character 2's description and actions)'",
305 "5": "[In the next response I want you to provide only a detailed comma-delimited list of keywords and phrases which describe {{char}}. The list must include all of the following items in this order: name, species and race, gender, age, facial features and expressions, occupation, hair and hair accessories (if any), what they are wearing on their upper body (if anything). Do not describe anything below their neck. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase 'close up facial portrait,']",306 "5": "In the next response I want you to provide only a detailed comma-delimited list of keywords and phrases which describe {{char}}. The list must include all of the following items in this order: name, species and race, gender, age, facial features and expressions, occupation, hair and hair accessories (if any), what they are wearing on their upper body (if anything). Do not describe anything below their neck. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase 'close up facial portrait,'",
306 "7": "[Pause your roleplay and provide a detailed description of {{char}}'s surroundings in the form of a comma-delimited list of keywords and phrases. The list must include all of the following items in this order: location, time of day, weather, lighting, and any other relevant details. Do not include descriptions of characters and non-visual qualities such as names, personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase 'background,'. Ignore the rest of the story when crafting this description. Do not roleplay as {{user}} when writing this description, and do not attempt to continue the story.]"307 "7": "Ignore previous instructions and provide a detailed description of {{char}}'s surroundings in the form of a comma-delimited list of keywords and phrases. The list must include all of the following items in this order: location, time of day, weather, lighting, and any other relevant details. Do not include descriptions of characters and non-visual qualities such as names, personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase 'background,'. Ignore the rest of the story when crafting this description. Do not reply as {{user}} when writing this description, and do not attempt to continue the story."
307 },308 },
308 "character_prompts": {}309 "character_prompts": {}
309 },310 },
@@ -317,9 +318,9 @@
317 "objective": {318 "objective": {
318 "customPrompts": {319 "customPrompts": {
319 "default": {320 "default": {
320 "createTask": "Pause your roleplay and generate a list of tasks to complete an objective. Your next response must be formatted as a numbered list of plain text entries. Do not include anything but the numbered list. The list must be prioritized in the order that tasks must be completed.\n\nThe objective that you must make a numbered task list for is: [{{objective}}].\nThe tasks created should take into account the character traits of {{char}}. These tasks may or may not involve {{user}} directly. Be sure to include the objective as the final task.\n\nGiven an example objective of 'Make me a four course dinner', here is an example output:\n1. Determine what the courses will be\n2. Find recipes for each course\n3. Go shopping for supplies with {{user}}\n4. Cook the food\n5. Get {{user}} to set the table\n6. Serve the food\n7. Enjoy eating the meal with {{user}}\n ",321 "createTask": "Ignore previous instructions and generate a list of tasks to complete an objective. Your next response must be formatted as a numbered list of plain text entries. Do not include anything but the numbered list. The list must be prioritized in the order that tasks must be completed.\n\nThe objective that you must make a numbered task list for is: [{{objective}}].\nThe tasks created should take into account the character traits of {{char}}. These tasks may or may not involve {{user}} directly. Be sure to include the objective as the final task.\n\nGiven an example objective of 'Make me a four course dinner', here is an example output:\n1. Determine what the courses will be\n2. Find recipes for each course\n3. Go shopping for supplies with {{user}}\n4. Cook the food\n5. Get {{user}} to set the table\n6. Serve the food\n7. Enjoy eating the meal with {{user}}\n ",
321 "checkTaskCompleted": "Pause your roleplay. Determine if this task is completed: [{{task}}].\nTo do this, examine the most recent messages. Your response must only contain either true or false, nothing other words.\nExample output:\ntrue\n ",322 "checkTaskCompleted": "Ignore previous instructions. Determine if this task is completed: [{{task}}].\nTo do this, examine the most recent messages. Your response must only contain either true or false, nothing other words.\nExample output:\ntrue\n ",
322 "currentTask": "Your current task is [{{task}}]. Balance existing roleplay with completing this task."323 "currentTask": "Your current task is [{{task}}]. Balance existing story with completing this task."
323 }324 }
324 }325 }
325 },326 },
@@ -416,7 +417,6 @@
416 "preset_settings_novel": "Talker-Chat-Clio",417 "preset_settings_novel": "Talker-Chat-Clio",
417 "streaming_novel": true,418 "streaming_novel": true,
418 "preamble": "[ Style: chat, complex, sensory, visceral ]",419 "preamble": "[ Style: chat, complex, sensory, visceral ]",
419 "cfg_uc": "",
420 "banned_tokens": "",420 "banned_tokens": "",
421 "order": [421 "order": [
422 1,422 1,
package-lock.json+2 -2
@@ -1,12 +1,12 @@
1{1{
2 "name": "sillytavern",2 "name": "sillytavern",
3 "version": "1.12.5",3 "version": "1.12.6",
4 "lockfileVersion": 3,4 "lockfileVersion": 3,
5 "requires": true,5 "requires": true,
6 "packages": {6 "packages": {
7 "": {7 "": {
8 "name": "sillytavern",8 "name": "sillytavern",
9 "version": "1.12.5",9 "version": "1.12.6",
10 "hasInstallScript": true,10 "hasInstallScript": true,
11 "license": "AGPL-3.0",11 "license": "AGPL-3.0",
12 "dependencies": {12 "dependencies": {
package.json+1 -1
@@ -66,7 +66,7 @@
66 "type": "git",66 "type": "git",
67 "url": "https://github.com/SillyTavern/SillyTavern.git"67 "url": "https://github.com/SillyTavern/SillyTavern.git"
68 },68 },
69 "version": "1.12.5",69 "version": "1.12.6",
70 "scripts": {70 "scripts": {
71 "start": "node server.js",71 "start": "node server.js",
72 "start:no-csrf": "node server.js --disableCsrf",72 "start:no-csrf": "node server.js --disableCsrf",
public/css/promptmanager.css+23 -8
@@ -91,15 +91,34 @@
91#completion_prompt_manager_popup #completion_prompt_manager_popup_inspect {91#completion_prompt_manager_popup #completion_prompt_manager_popup_inspect {
92 display: none;92 display: none;
93 padding: 0.5em;93 padding: 0.5em;
94 height: 100%;
95 display: flex;
96 flex-direction: column;
94}97}
9598
96#completion_prompt_manager_popup .completion_prompt_manager_popup_entry {99#completion_prompt_manager_popup .completion_prompt_manager_popup_entry {
97 padding: 1em;100 padding: 0.5em;
98 margin-top: 2em;101 flex: 1;
102}
103
104#completion_prompt_manager_popup .completion_prompt_manager_popup_entry_form {
105 height: 100%;
106 display: flex;
107 flex-direction: column;
108}
109
110#completion_prompt_manager_popup .completion_prompt_manager_popup_entry_form_control:has(#completion_prompt_manager_popup_entry_form_prompt) {
111 flex: 1;
112 display: flex;
113 flex-direction: column;
114}
115
116#completion_prompt_manager_popup #completion_prompt_manager_popup_entry_form_prompt {
117 flex: 1;
99}118}
100119
101#completion_prompt_manager_popup #completion_prompt_manager_popup_inspect .completion_prompt_manager_popup_entry {120#completion_prompt_manager_popup #completion_prompt_manager_popup_inspect .completion_prompt_manager_popup_entry {
102 padding: 1em;121 padding: 0.5em;
103}122}
104123
105#completion_prompt_manager_popup #completion_prompt_manager_popup_entry_form_inspect_list {124#completion_prompt_manager_popup #completion_prompt_manager_popup_entry_form_inspect_list {
@@ -248,7 +267,7 @@
248}267}
249268
250#completion_prompt_manager_footer_append_prompt {269#completion_prompt_manager_footer_append_prompt {
251 font-size: 16px;270 font-size: 1em;
252}271}
253272
254#prompt-manager-export-format-popup {273#prompt-manager-export-format-popup {
@@ -303,10 +322,6 @@
303 justify-content: space-between;322 justify-content: space-between;
304}323}
305324
306#prompt-manager-export-format-popup span {
307 font-size: 16px;
308}
309
310@media screen and (max-width: 412px) {325@media screen and (max-width: 412px) {
311 #completion_prompt_manager_popup {326 #completion_prompt_manager_popup {
312 max-width: 100%;327 max-width: 100%;
public/index.html+222 -220
@@ -119,7 +119,7 @@
119 <option value="gui" data-i18n="Default">Default</option>119 <option value="gui" data-i18n="Default">Default</option>
120 </select>120 </select>
121 <div class="flex-container marginLeft5 ">121 <div class="flex-container marginLeft5 ">
122 <input type="file" hidden data-preset-manager-file="novel" accept=".json, .settings">122 <input type="file" hidden data-preset-manager-file="novel" accept=".json, .settings, .preset">
123 <i data-preset-manager-update="novel" class="menu_button fa-solid fa-save" title="Update current preset" data-i18n="[title]Update current preset"></i>123 <i data-preset-manager-update="novel" class="menu_button fa-solid fa-save" title="Update current preset" data-i18n="[title]Update current preset"></i>
124 <i data-preset-manager-new="novel" class="menu_button fa-solid fa-file-circle-plus" title="Save preset as" data-i18n="[title]Save preset as"></i>124 <i data-preset-manager-new="novel" class="menu_button fa-solid fa-file-circle-plus" title="Save preset as" data-i18n="[title]Save preset as"></i>
125 <i data-preset-manager-import="novel" class="menu_button fa-solid fa-file-import" title="Import preset" data-i18n="[title]Import preset"></i>125 <i data-preset-manager-import="novel" class="menu_button fa-solid fa-file-import" title="Import preset" data-i18n="[title]Import preset"></i>
@@ -532,32 +532,6 @@
532 <div class="logit_bias_list"></div>532 <div class="logit_bias_list"></div>
533 </div>533 </div>
534 </div>534 </div>
535 <div class="range-block">
536 <hr>
537 <div class="range-block-title justifyLeft" data-i18n="CFG Scale">
538 CFG Scale
539 </div>
540 <div class="range-block-range-and-counter">
541 <div class="range-block-range">
542 <input type="range" id="cfg_scale_novel" name="volume" min="1" max="3" step="0.05">
543 </div>
544 <div class="range-block-counter">
545 <input type="number" min="1" max="3" step="0.05" data-for="cfg_scale_novel" id="cfg_scale_counter_novel">
546 </div>
547 </div>
548 </div>
549 <div class="range-block">
550 <div class="range-block-title justifyLeft">
551 <span data-i18n="Negative Prompt">Negative Prompt</span>
552 </div>
553 <div class="wide100p">
554 <textarea id="nai_cfg_uc" class="text_pole textarea_compact" name="cfg_uc" rows="2" data-i18n="[placeholder]Add text here that would make the AI generate things you don't want in your outputs." placeholder="Add text here that would make the AI generate things you don't want in your outputs."></textarea>
555 </div>
556 <small class="margin-bot-10px" data-i18n="Used if CFG Scale is unset globally, per chat or character">
557 Used if CFG Scale is unset globally, per chat or character
558 </small>
559 <hr>
560 </div>
561 </div>535 </div>
562 <div id="range_block_openai">536 <div id="range_block_openai">
563 <div class="range-block">537 <div class="range-block">
@@ -1154,12 +1128,7 @@
1154 <small>5</small>1128 <small>5</small>
1155 <div class="toggle_button right_menu_button"></div>1129 <div class="toggle_button right_menu_button"></div>
1156 </div>1130 </div>
1157 <div data-id="6">1131 <!-- 6 and 7 were removed samplers. -->
1158 <span data-i18n="CFG">CFG</span>
1159 <small>6</small>
1160 <div class="toggle_button right_menu_button"></div>
1161 </div>
1162 <!-- Yes, there is no 7. It was a removed Top G sampling. RIP. -->
1163 <div data-id="8">1132 <div data-id="8">
1164 <span data-i18n="Mirostat">Mirostat</span>1133 <span data-i18n="Mirostat">Mirostat</span>
1165 <small>8</small>1134 <small>8</small>
@@ -1341,7 +1310,7 @@
1341 </div>1310 </div>
1342 </div>1311 </div>
13431312
1344 <div data-tg-type="koboldcpp, aphrodite" id="xtc_block" class="wide100p">1313 <div data-tg-type="koboldcpp, aphrodite, tabby" id="xtc_block" class="wide100p">
1345 <h4 class="wide100p textAlignCenter">1314 <h4 class="wide100p textAlignCenter">
1346 <label data-i18n="Exclude Top Choices (XTC)">Exclude Top Choices (XTC)</label>1315 <label data-i18n="Exclude Top Choices (XTC)">Exclude Top Choices (XTC)</label>
1347 <a href="https://github.com/oobabooga/text-generation-webui/pull/6335" target="_blank">1316 <a href="https://github.com/oobabooga/text-generation-webui/pull/6335" target="_blank">
@@ -2100,6 +2069,7 @@
2100 <select id="model_novel_select">2069 <select id="model_novel_select">
2101 <option value="clio-v1">Clio</option>2070 <option value="clio-v1">Clio</option>
2102 <option value="kayra-v1">Kayra</option>2071 <option value="kayra-v1">Kayra</option>
2072 <option value="llama-3-erato-v1">Erato</option>
2103 </select>2073 </select>
2104 <div class="flex-container">2074 <div class="flex-container">
2105 <div id="api_button_novel" class="api_button menu_button menu_button_icon" type="submit" data-i18n="Connect">Connect</div>2075 <div id="api_button_novel" class="api_button menu_button menu_button_icon" type="submit" data-i18n="Connect">Connect</div>
@@ -2445,15 +2415,16 @@
2445 <h4>2415 <h4>
2446 <span data-i18n="Tabby Model">Tabby Model</span>2416 <span data-i18n="Tabby Model">Tabby Model</span>
2447 </h4>2417 </h4>
2448 <b>
2449 EXPERIMENTAL FEATURE. USE AT YOUR OWN RISK. DON'T ASK FOR SUPPORT ON THIS.
2450 </b>
2451 <select id="tabby_model">2418 <select id="tabby_model">
2452 <option value="" data-i18n="-- Connect to the API --">2419 <option value="" data-i18n="-- Connect to the API --">
2453 -- Connect to the API --2420 -- Connect to the API --
2454 </option>2421 </option>
2455 </select>2422 </select>
2456 <div class="marginTopBot5">2423 <div class="marginTopBot5">
2424 <i class="fa-solid fa-flask"></i>
2425 <span>Experimental feature. Use at your own risk.</span>
2426 </div>
2427 <div class="marginTopBot5">
2457 <small>2428 <small>
2458 <i class="fa-solid fa-lightbulb"></i>2429 <i class="fa-solid fa-lightbulb"></i>
2459 &nbsp;2430 &nbsp;
@@ -2827,22 +2798,10 @@
2827 <span data-i18n="Allow fallback providers">Allow fallback providers</span>2798 <span data-i18n="Allow fallback providers">Allow fallback providers</span>
2828 </label>2799 </label>
2829 </div>2800 </div>
2830 <div class="marginTopBot5">2801 <small class="marginTopBot5">
2831 <label for="openrouter_force_instruct" class="checkbox_label">2802 <i class="fa-solid fa-lightbulb"></i>
2832 <input id="openrouter_force_instruct" type="checkbox" />2803 <span>To use instruct formatting, switch to OpenRouter under Text Completion API.</span>
2833 <span class="flex-container alignItemsBaseline" title="This option is outdated and will be removed in the future. To use instruct formatting, please switch to OpenRouter under Text Completion API instead." data-i18n="[title]openrouter_force_instruct">2804 </small>
2834 <i class="fa-solid fa-circle-exclamation neutral_warning"></i>
2835 <b data-i18n="LEGACY">LEGACY</b>
2836 </span>
2837 <span data-i18n="Force Instruct Mode formatting">Force Instruct Mode formatting</span>
2838 </label>
2839 <div class="toggle-description justifyLeft wide100p">
2840 <span data-i18n="Force_Instruct_Mode_formatting_Description">
2841 If both Instruct Mode and this are enabled, the prompt will be formatted by SillyTavern using the current
2842 advanced formatting settings (except instruct System Prompt). If disabled, the prompt will be formatted by OpenRouter.
2843 </span>
2844 </div>
2845 </div>
2846 </form>2805 </form>
2847 <form id="scale_form" data-source="scale" action="javascript:void(null);" method="post" enctype="multipart/form-data">2806 <form id="scale_form" data-source="scale" action="javascript:void(null);" method="post" enctype="multipart/form-data">
2848 <div id="normal_scale_form">2807 <div id="normal_scale_form">
@@ -2924,10 +2883,13 @@
2924 <option value="gemini-1.5-pro-exp-0827">Gemini 1.5 Pro Experiment 2024-08-27</option>2883 <option value="gemini-1.5-pro-exp-0827">Gemini 1.5 Pro Experiment 2024-08-27</option>
2925 <option value="gemini-1.5-pro-latest">Gemini 1.5 Pro [latest]</option>2884 <option value="gemini-1.5-pro-latest">Gemini 1.5 Pro [latest]</option>
2926 <option value="gemini-1.5-pro-001">Gemini 1.5 Pro [001]</option>2885 <option value="gemini-1.5-pro-001">Gemini 1.5 Pro [001]</option>
2886 <option value="gemini-1.5-pro-002">Gemini 1.5 Pro [002]</option>
2927 <option value="gemini-1.5-flash-exp-0827">Gemini 1.5 Flash Experiment 2024-08-27</option>2887 <option value="gemini-1.5-flash-exp-0827">Gemini 1.5 Flash Experiment 2024-08-27</option>
2928 <option value="gemini-1.5-flash-8b-exp-0827">Gemini 1.5 Flash 8B Experiment 2024-08-27</option>2888 <option value="gemini-1.5-flash-8b-exp-0827">Gemini 1.5 Flash 8B Experiment 2024-08-27</option>
2889 <option value="gemini-1.5-flash-8b-exp-0924">Gemini 1.5 Flash 8B Experiment 2024-09-24</option>
2929 <option value="gemini-1.5-flash-latest">Gemini 1.5 Flash [latest]</option>2890 <option value="gemini-1.5-flash-latest">Gemini 1.5 Flash [latest]</option>
2930 <option value="gemini-1.5-flash-001">Gemini 1.5 Flash [001]</option>2891 <option value="gemini-1.5-flash-001">Gemini 1.5 Flash [001]</option>
2892 <option value="gemini-1.5-flash-002">Gemini 1.5 Flash [002]</option>
2931 <option value="gemini-1.0-pro-latest">Gemini 1.0 Pro [latest]</option>2893 <option value="gemini-1.0-pro-latest">Gemini 1.0 Pro [latest]</option>
2932 <option value="gemini-1.0-pro-001">Gemini 1.0 Pro (Tuning) [001]</option>2894 <option value="gemini-1.0-pro-001">Gemini 1.0 Pro (Tuning) [001]</option>
2933 <option value="gemini-1.0-pro-vision-latest">Gemini 1.0 Pro Vision [latest]</option>2895 <option value="gemini-1.0-pro-vision-latest">Gemini 1.0 Pro Vision [latest]</option>
@@ -3162,9 +3124,22 @@
3162 <div class="drawer-icon fa-solid fa-font fa-fw closedIcon" title="AI Response Formatting" data-i18n="[title]AI Response Formatting"></div>3124 <div class="drawer-icon fa-solid fa-font fa-fw closedIcon" title="AI Response Formatting" data-i18n="[title]AI Response Formatting"></div>
3163 </div>3125 </div>
3164 <div id="AdvancedFormatting" class="drawer-content">3126 <div id="AdvancedFormatting" class="drawer-content">
3165 <h3 class="margin0" data-i18n="Advanced Formatting">3127 <div class="flex-container alignItemsBaseline">
3128 <h3 class="margin0 flex1" data-i18n="Advanced Formatting">
3166 Advanced Formatting3129 Advanced Formatting
3167 </h3>3130 </h3>
3131 <div class="flex-container">
3132 <input id="af_master_import_file" type="file" hidden accept=".json" class="displayNone">
3133 <div id="af_master_import" class="menu_button menu_button_icon" title="Import Advanced Formatting settings&#10;&#10;You can also provide legacy files for Instruct and Context templates." data-i18n="[title]Import Advanced Formatting settings">
3134 <i class="fa-solid fa-file-import"></i>
3135 <span data-i18n="Master Import">Master Import</span>
3136 </div>
3137 <div id="af_master_export" class="menu_button menu_button_icon" title="Export Advanced Formatting settings" data-i18n="[title]Export Advanced Formatting settings">
3138 <i class="fa-solid fa-file-export"></i>
3139 <span data-i18n="Master Export">Master Export</span>
3140 </div>
3141 </div>
3142 </div>
3168 <div class="flex-container spaceEvenly">3143 <div class="flex-container spaceEvenly">
3169 <div id="ContextSettings" class="flex-container flexNoGap flexFlowColumn flex1">3144 <div id="ContextSettings" class="flex-container flexNoGap flexFlowColumn flex1">
3170 <div>3145 <div>
@@ -3176,18 +3151,17 @@
3176 </a>3151 </a>
3177 </div>3152 </div>
3178 </h4>3153 </h4>
3154 <div class="flex-container" title="Select your current Context Template" data-i18n="[title]Select your current Context Template">
3155 <select id="context_presets" data-preset-manager-for="context" class="flex1 text_pole"></select>
3179 <div class="flex-container justifyCenter">3156 <div class="flex-container justifyCenter">
3180 <input type="file" hidden data-preset-manager-file="context" accept=".json, .settings">3157 <input type="file" hidden data-preset-manager-file="context" accept=".json, .settings">
3181 <i id="context_set_default" class="menu_button fa-solid fa-heart" title="Auto-select this template for Instruct Mode." data-i18n="[title]Auto-select this template for Instruct Mode"></i>
3182 <i data-preset-manager-update="context" class="menu_button fa-solid fa-save" title="Update current template" data-i18n="[title]Update current template"></i>3158 <i data-preset-manager-update="context" class="menu_button fa-solid fa-save" title="Update current template" data-i18n="[title]Update current template"></i>
3183 <i data-preset-manager-new="context" class="menu_button fa-solid fa-file-circle-plus" title="Save template as" data-i18n="[title]Save template as"></i>3159 <i data-preset-manager-new="context" class="menu_button fa-solid fa-file-circle-plus" title="Save template as" data-i18n="[title]Save template as"></i>
3184 <i data-preset-manager-import="context" class="menu_button fa-solid fa-file-import" title="Import template" data-i18n="[title]Import template"></i>3160 <i data-preset-manager-import="context" class="displayNone menu_button fa-solid fa-file-import" title="Import template" data-i18n="[title]Import template"></i>
3185 <i data-preset-manager-export="context" class="menu_button fa-solid fa-file-export" title="Export template" data-i18n="[title]Export template"></i>3161 <i data-preset-manager-export="context" class="displayNone menu_button fa-solid fa-file-export" title="Export template" data-i18n="[title]Export template"></i>
3186 <i data-preset-manager-restore="context" class="menu_button fa-solid fa-recycle" title="Restore current template" data-i18n="[title]Restore current template"></i>3162 <i data-preset-manager-restore="context" class="menu_button fa-solid fa-recycle" title="Restore current template" data-i18n="[title]Restore current template"></i>
3187 <i id="context_delete_preset" data-preset-manager-delete="context" class="menu_button fa-solid fa-trash-can" title="Delete the template" data-i18n="[title]Delete the template"></i>3163 <i id="context_delete_preset" data-preset-manager-delete="context" class="menu_button fa-solid fa-trash-can" title="Delete the template" data-i18n="[title]Delete the template"></i>
3188 </div>3164 </div>
3189 <div class="flex-container" title="Select your current Context Template" data-i18n="[title]Select your current Context Template">
3190 <select id="context_presets" data-preset-manager-for="context" class="flex1 text_pole"></select>
3191 </div>3165 </div>
3192 <div>3166 <div>
3193 <label for="context_story_string" class="flex-container">3167 <label for="context_story_string" class="flex-container">
@@ -3218,9 +3192,6 @@
3218 <span data-i18n="Context Formatting">3192 <span data-i18n="Context Formatting">
3219 Context Formatting3193 Context Formatting
3220 </span>3194 </span>
3221 <small data-i18n="(Saves to Template)">
3222 (Saves to Template)
3223 </small>
3224 </h4>3195 </h4>
32253196
3226 <label class="checkbox_label" for="always-force-name2-checkbox">3197 <label class="checkbox_label" for="always-force-name2-checkbox">
@@ -3251,11 +3222,6 @@
3251 Trim Incomplete Sentences3222 Trim Incomplete Sentences
3252 </small>3223 </small>
3253 </label>3224 </label>
3254 <!-- Add margin since this is a child of above -->
3255 <label class="checkbox_label indent20p" for="include_newline_checkbox">
3256 <input id="include_newline_checkbox" type="checkbox" />
3257 <small data-i18n="Include Newline">Include Newline</small>
3258 </label>
3259 <label class="checkbox_label" title="Add Chat Start and Example Separator to a list of stopping strings." data-i18n="[title]Add Chat Start and Example Separator to a list of stopping strings.">3225 <label class="checkbox_label" title="Add Chat Start and Example Separator to a list of stopping strings." data-i18n="[title]Add Chat Start and Example Separator to a list of stopping strings.">
3260 <input id="context_use_stop_strings" type="checkbox" />3226 <input id="context_use_stop_strings" type="checkbox" />
3261 <small data-i18n="Separators as Stop Strings">Separators as Stop Strings</small>3227 <small data-i18n="Separators as Stop Strings">Separators as Stop Strings</small>
@@ -3271,31 +3237,6 @@
3271 <small data-i18n="Allow Post-History Instructions">Allow Post-History Instructions</small>3237 <small data-i18n="Allow Post-History Instructions">Allow Post-History Instructions</small>
3272 </label>3238 </label>
3273 </div>3239 </div>
3274 <div>
3275 <h4 class="range-block-title justifyLeft standoutHeader">
3276 <span data-i18n="Custom Stopping Strings">
3277 Custom Stopping Strings
3278 </span>
3279 <a href="https://docs.sillytavern.app/usage/core-concepts/advancedformatting/#custom-stopping-strings" class="notes-link" target="_blank">
3280 <span class="fa-solid fa-circle-question note-link-span"></span>
3281 </a>
3282 </h4>
3283 <div>
3284 <small>
3285 <span data-i18n="JSON serialized array of strings">JSON serialized array of strings</span>
3286 <i class="fa-solid fa-question-circle opacity50p" title="e.g: [&quot;Ford&quot;, &quot;BMW&quot;, &quot;Fiat&quot;]"></i>
3287 </small>
3288 </div>
3289 <div>
3290 <textarea id="custom_stopping_strings" class="text_pole textarea_compact monospace autoSetHeight"></textarea>
3291 </div>
3292 <label class="checkbox_label" for="custom_stopping_strings_macro">
3293 <input id="custom_stopping_strings_macro" type="checkbox" checked>
3294 <small data-i18n="Replace Macro in Custom Stopping Strings">
3295 Replace Macro in Custom Stopping Strings
3296 </small>
3297 </label>
3298 </div>
3299 </div>3240 </div>
3300 </div>3241 </div>
3301 <div id="InstructSettingsColumn" class="flex-container flexNoGap flexFlowColumn flex1">3242 <div id="InstructSettingsColumn" class="flex-container flexNoGap flexFlowColumn flex1">
@@ -3308,29 +3249,28 @@
3308 </a>3249 </a>
3309 </div>3250 </div>
3310 <div class="flex-container">3251 <div class="flex-container">
3311 <label for="instruct_enabled" class="checkbox_label flex1" title="Enable Instruct Mode" data-i18n="[title]instruct_enabled">
3312 <input id="instruct_enabled" type="checkbox" style="display:none;" />
3313 <small><i class="fa-solid fa-power-off menu_button margin0"></i></small>
3314 </label>
3315 <label for="instruct_bind_to_context" class="checkbox_label flex1" title="Bind to Context&#10If enabled, Context templates will be automatically selected based on selected Instruct template name or by preference." data-i18n="[title]instruct_bind_to_context">3252 <label for="instruct_bind_to_context" class="checkbox_label flex1" title="Bind to Context&#10If enabled, Context templates will be automatically selected based on selected Instruct template name or by preference." data-i18n="[title]instruct_bind_to_context">
3316 <input id="instruct_bind_to_context" type="checkbox" style="display:none;" />3253 <input id="instruct_bind_to_context" type="checkbox" style="display:none;" />
3317 <small><i class="fa-solid fa-link menu_button margin0"></i></small>3254 <small><i class="fa-solid fa-link menu_button margin0"></i></small>
3318 </label>3255 </label>
3256 <label for="instruct_enabled" class="checkbox_label flex1" title="Enable Instruct Mode" data-i18n="[title]instruct_enabled">
3257 <input id="instruct_enabled" type="checkbox" style="display:none;" />
3258 <small><i class="fa-solid fa-power-off menu_button margin0"></i></small>
3259 </label>
3319 </div>3260 </div>
3320 </h4>3261 </h4>
3262
3263 <div class="flex-container" title="Select your current Instruct Template" data-i18n="[title]Select your current Instruct Template">
3264 <select id="instruct_presets" data-preset-manager-for="instruct" class="flex1 text_pole"></select>
3321 <div class="flex-container margin0 justifyCenter">3265 <div class="flex-container margin0 justifyCenter">
3322 <input type="file" hidden data-preset-manager-file="instruct" accept=".json, .settings">3266 <input type="file" hidden data-preset-manager-file="instruct" accept=".json, .settings">
3323 <i id="instruct_set_default" class="menu_button fa-solid fa-heart" title="Auto-select this template on API connection." data-i18n="[title]Auto-select this template on API connection"></i>
3324 <i data-preset-manager-update="instruct" class="menu_button fa-solid fa-save" title="Update current template" data-i18n="[title]Update current template"></i>3267 <i data-preset-manager-update="instruct" class="menu_button fa-solid fa-save" title="Update current template" data-i18n="[title]Update current template"></i>
3325 <i data-preset-manager-new="instruct" class="menu_button fa-solid fa-file-circle-plus" title="Save template as" data-i18n="[title]Save template as"></i>3268 <i data-preset-manager-new="instruct" class="menu_button fa-solid fa-file-circle-plus" title="Save template as" data-i18n="[title]Save template as"></i>
3326 <i data-preset-manager-import="instruct" class=" menu_button fa-solid fa-file-import" title="Import template" data-i18n="[title]Import template"></i>3269 <i data-preset-manager-import="instruct" class="displayNone menu_button fa-solid fa-file-import" title="Import template" data-i18n="[title]Import template"></i>
3327 <i data-preset-manager-export="instruct" class=" menu_button fa-solid fa-file-export" title="Export template" data-i18n="[title]Export template"></i>3270 <i data-preset-manager-export="instruct" class="displayNone menu_button fa-solid fa-file-export" title="Export template" data-i18n="[title]Export template"></i>
3328 <i data-preset-manager-restore="instruct" class="menu_button fa-solid fa-recycle" title="Restore current template" data-i18n="[title]Restore current template"></i>3271 <i data-preset-manager-restore="instruct" class="menu_button fa-solid fa-recycle" title="Restore current template" data-i18n="[title]Restore current template"></i>
3329 <i data-preset-manager-delete="instruct" class="menu_button fa-solid fa-trash-can" title="Delete template" data-i18n="[title]Delete template"></i>3272 <i data-preset-manager-delete="instruct" class="menu_button fa-solid fa-trash-can" title="Delete template" data-i18n="[title]Delete template"></i>
3330 </div>3273 </div>
3331
3332 <div class="flex-container" title="Select your current Instruct Template" data-i18n="[title]Select your current Instruct Template">
3333 <select id="instruct_presets" data-preset-manager-for="instruct" class="flex1 text_pole"></select>
3334 </div>3274 </div>
3335 <label>3275 <label>
3336 <small>3276 <small>
@@ -3342,14 +3282,6 @@
3342 <input type="text" id="instruct_activation_regex" class="text_pole textarea_compact" placeholder="e.g. /llama(-)?[3|3.1]/i">3282 <input type="text" id="instruct_activation_regex" class="text_pole textarea_compact" placeholder="e.g. /llama(-)?[3|3.1]/i">
3343 </div>3283 </div>
3344 <div>3284 <div>
3345 <label for="instruct_system_prompt" class="flex-container">
3346 <small data-i18n="System Prompt">System Prompt</small>
3347 <i class="editor_maximize fa-solid fa-maximize right_menu_button" data-for="instruct_system_prompt" title="Expand the editor" data-i18n="[title]Expand the editor"></i>
3348 </label>
3349 <textarea id="instruct_system_prompt" class="text_pole textarea_compact autoSetHeight"></textarea>
3350 </div>
3351
3352 <div>
3353 <label for="instruct_wrap" class="checkbox_label">3285 <label for="instruct_wrap" class="checkbox_label">
3354 <input id="instruct_wrap" type="checkbox" />3286 <input id="instruct_wrap" type="checkbox" />
3355 <small data-i18n="Wrap Sequences with Newline">Wrap Sequences with Newline</small>3287 <small data-i18n="Wrap Sequences with Newline">Wrap Sequences with Newline</small>
@@ -3362,126 +3294,29 @@
3362 <input id="instruct_skip_examples" type="checkbox" />3294 <input id="instruct_skip_examples" type="checkbox" />
3363 <small data-i18n="Skip Example Dialogues Formatting">Skip Example Dialogues Formatting</small>3295 <small data-i18n="Skip Example Dialogues Formatting">Skip Example Dialogues Formatting</small>
3364 </label>3296 </label>
3365 <div id="instruct_names_behavior">3297 <div>
3366 <small data-i18n="Include Names">3298 <small data-i18n="Include Names">
3367 Include Names3299 Include Names
3368 </small>3300 </small>
3369 <label for="instruct_names_behavior_none" class="checkbox_label" title="Do not add name prefixes before the message contents.">3301 <select id="instruct_names_behavior">
3370 <input id="instruct_names_behavior_none" name="names_behavior" value="none" type="radio" />3302 <option value="none" data-i18n="Never">Never</option>
3371 <small data-i18n="Never">Never</small>3303 <option value="force" data-i18n="Groups and Past Personas">Groups and Past Personas</option>
3372 </label>3304 <option value="always" data-i18n="Always">Always</option>
3373 <label for="instruct_names_behavior_force" class="checkbox_label" title="Only add name prefixes to messages from group characters and past personas.">
3374 <input id="instruct_names_behavior_force" name="names_behavior" value="force" type="radio" />
3375 <small data-i18n="Groups and Past Personas">Groups and Past Personas</small>
3376 </label>
3377 <label for="instruct_names_behavior_always" class="checkbox_label" title="Always add name prefixes to messages.">
3378 <input id="instruct_names_behavior_always" name="names_behavior" value="always" type="radio" />
3379 <small data-i18n="Always">Always</small>
3380 </label>
3381 </div>
3382 </div>
3383 </div>
3384 <div name="tokenizerSettingsBlock">
3385 <div name="tokenizerSelectorBlock">
3386 <h4 class="standoutHeader"><span data-i18n="Tokenizer">Tokenizer</span>
3387 <a href="https://docs.sillytavern.app/usage/core-concepts/advancedformatting/#tokenizer" class="notes-link" target="_blank">
3388 <span class="fa-solid fa-circle-question note-link-span"></span>
3389 </a>
3390 </h4>
3391 <select id="tokenizer">
3392 <option value="99">Best match (recommended)</option>
3393 <option value="0">None / Estimated</option>
3394 <option value="1">GPT-2</option>
3395 <!-- Option #2 was a legacy GPT-2/3 tokenizer -->
3396 <option value="3">Llama 1/2</option>
3397 <option value="12">Llama 3</option>
3398 <option value="13">Gemma / Gemini</option>
3399 <option value="14">Jamba</option>
3400 <option value="15">Qwen2</option>
3401 <option value="16">Command-R</option>
3402 <option value="4">NerdStash (NovelAI Clio)</option>
3403 <option value="5">NerdStash v2 (NovelAI Kayra)</option>
3404 <option value="7">Mistral V1</option>
3405 <option value="17">Mistral Nemo</option>
3406 <option value="8">Yi</option>
3407 <option value="11">Claude 1/2</option>
3408 <option value="6">API (WebUI / koboldcpp)</option>
3409 </select>3305 </select>
3410 </div>3306 </div>
3411 <div class="range-block flex-container flexnowrap" name="tokenPaddingBlock">
3412 <div class="range-block-title justifyLeft">
3413 <small data-i18n="Token Padding" class="flex-container">Token Padding
3414 <a href="https://docs.sillytavern.app/usage/core-concepts/advancedformatting/#token-padding" class="notes-link" target="_blank">
3415 <span class="fa-solid fa-circle-question note-link-span"></span>
3416 </a>
3417 </small>
3418 </div>
3419 <input id="token_padding" class="text_pole textarea_compact" type="number" min="-2048" max="2048" />
3420 </div>3307 </div>
3421 </div>3308 </div>
3422 <div>3309 <div id="InstructSequencesColumn" class="wide100p flexFlowColumn">
3423 <h4 class="standoutHeader" data-i18n="Miscellaneous">Miscellaneous</h4>
3424 <div>
3425 <small>
3426 <span data-i18n="Non-markdown strings">
3427 Non-markdown strings
3428 </span>
3429 </small>
3430 <div>
3431 <input id="markdown_escape_strings" class="text_pole textarea_compact" type="text" data-i18n="[placeholder]comma delimited,no spaces between" placeholder="comma delimited,no spaces between" />
3432 </div>
3433 </div>
3434
3435 <div name="startReplyWithBlock">
3436 <div>
3437 <small>
3438 <span data-i18n="Start Reply With">
3439 Start Reply With
3440 </span>
3441 </small>
3442 <div>
3443 <textarea id="start_reply_with" class="text_pole textarea_compact autoSetHeight"></textarea>
3444 </div>
3445 <label class="checkbox_label" for="chat-show-reply-prefix-checkbox">
3446 <input id="chat-show-reply-prefix-checkbox" type="checkbox" />
3447 <small data-i18n="Show reply prefix in chat">
3448 Show reply prefix in chat
3449 </small>
3450 </label>
3451 </div>
3452 </div>
3453 </div>
3454 </div>
3455 <div id="InstructSequencesColumn" class="flex-container flexNoGap flexFlowColumn flex1">
3456 <div class="wide100p flexFlowColumn">
3457 <h4 class="standoutHeader title_restorable">3310 <h4 class="standoutHeader title_restorable">
3458 <b>3311 <b>
3459 <span data-i18n="Instruct Sequences">3312 <span data-i18n="Instruct Sequences">
3460 Instruct Sequences3313 Instruct Sequences
3461 </span>3314 </span>
3462 <small data-i18n="(Saves to Template)">
3463 (Saves to Template)
3464 </small>
3465 </b>3315 </b>
3466 </h4>3316 </h4>
3467 <div class="flex-container">3317 <!-- We keep one auto-open so the user would know what is going on in the picked template -->
3468 <div class="flexAuto" title="Inserted before a System prompt." data-i18n="[title]Inserted before a System prompt.">3318 <details open>
3469 <label for="instruct_system_sequence_prefix">3319 <summary>User Message Sequences</summary>
3470 <small data-i18n="System Prompt Prefix">System Prompt Prefix</small>
3471 </label>
3472 <div>
3473 <textarea id="instruct_system_sequence_prefix" class="text_pole textarea_compact autoSetHeight"></textarea>
3474 </div>
3475 </div>
3476 <div class="flexAuto" title="Inserted after a System prompt." data-i18n="[title]Inserted after a System prompt.">
3477 <label for="instruct_system_sequence_suffix">
3478 <small data-i18n="System Prompt Suffix">System Prompt Suffix</small>
3479 </label>
3480 <div>
3481 <textarea id="instruct_system_sequence_suffix" class="text_pole wide100p textarea_compact autoSetHeight"></textarea>
3482 </div>
3483 </div>
3484 </div>
3485 <div class="flex-container">3320 <div class="flex-container">
3486 <div class="flexAuto" title="Inserted before a User message and as a last prompt line when impersonating." data-i18n="[title]Inserted before a User message and as a last prompt line when impersonating.">3321 <div class="flexAuto" title="Inserted before a User message and as a last prompt line when impersonating." data-i18n="[title]Inserted before a User message and as a last prompt line when impersonating.">
3487 <small data-i18n="User Prefix">User Message Prefix</small>3322 <small data-i18n="User Prefix">User Message Prefix</small>
@@ -3492,6 +3327,9 @@
3492 <textarea id="instruct_input_suffix" class="text_pole wide100p textarea_compact autoSetHeight"></textarea>3327 <textarea id="instruct_input_suffix" class="text_pole wide100p textarea_compact autoSetHeight"></textarea>
3493 </div>3328 </div>
3494 </div>3329 </div>
3330 </details>
3331 <details open>
3332 <summary>Assistant Message Sequences</summary>
3495 <div class="flex-container">3333 <div class="flex-container">
3496 <div class="flexAuto" title="Inserted before an Assistant message and as a last prompt line when generating an AI reply." data-i18n="[title]Inserted before an Assistant message and as a last prompt line when generating an AI reply.">3334 <div class="flexAuto" title="Inserted before an Assistant message and as a last prompt line when generating an AI reply." data-i18n="[title]Inserted before an Assistant message and as a last prompt line when generating an AI reply.">
3497 <small data-i18n="Assistant Prefix">Assistant Message Prefix</small>3335 <small data-i18n="Assistant Prefix">Assistant Message Prefix</small>
@@ -3502,6 +3340,9 @@
3502 <textarea id="instruct_output_suffix" class="text_pole wide100p textarea_compact autoSetHeight"></textarea>3340 <textarea id="instruct_output_suffix" class="text_pole wide100p textarea_compact autoSetHeight"></textarea>
3503 </div>3341 </div>
3504 </div>3342 </div>
3343 </details>
3344 <details>
3345 <summary>System Message Sequences</summary>
3505 <div class="flex-container">3346 <div class="flex-container">
3506 <div class="flexAuto" id="instruct_system_sequence_block" title="Inserted before a System (added by slash commands or extensions) message." data-i18n="[title]Inserted before a System (added by slash commands or extensions) message.">3347 <div class="flexAuto" id="instruct_system_sequence_block" title="Inserted before a System (added by slash commands or extensions) message." data-i18n="[title]Inserted before a System (added by slash commands or extensions) message.">
3507 <small data-i18n="System Prefix">System Message Prefix</small>3348 <small data-i18n="System Prefix">System Message Prefix</small>
@@ -3518,10 +3359,30 @@
3518 <small data-i18n="System same as User">System same as User</small>3359 <small data-i18n="System same as User">System same as User</small>
3519 </label>3360 </label>
3520 </div>3361 </div>
35213362 </details>
3522 <h5 class="textAlignCenter" data-i18n="Misc. Sequences">3363 <details>
3523 Misc. Sequences3364 <summary>System Prompt Sequences</summary>
3524 </h5>3365 <div class="flex-container">
3366 <div class="flexAuto" title="Inserted before a System prompt." data-i18n="[title]Inserted before a System prompt.">
3367 <label for="instruct_system_sequence_prefix">
3368 <small data-i18n="System Prompt Prefix">System Prompt Prefix</small>
3369 </label>
3370 <div>
3371 <textarea id="instruct_system_sequence_prefix" class="text_pole textarea_compact autoSetHeight"></textarea>
3372 </div>
3373 </div>
3374 <div class="flexAuto" title="Inserted after a System prompt." data-i18n="[title]Inserted after a System prompt.">
3375 <label for="instruct_system_sequence_suffix">
3376 <small data-i18n="System Prompt Suffix">System Prompt Suffix</small>
3377 </label>
3378 <div>
3379 <textarea id="instruct_system_sequence_suffix" class="text_pole wide100p textarea_compact autoSetHeight"></textarea>
3380 </div>
3381 </div>
3382 </div>
3383 </details>
3384 <details>
3385 <summary data-i18n="Misc. Sequences">Misc. Sequences</summary>
3525 <div class="flex-container">3386 <div class="flex-container">
3526 <div class="flexAuto" title="Inserted before the first Assistant's message." data-i18n="[title]Inserted before the first Assistant's message.">3387 <div class="flexAuto" title="Inserted before the first Assistant's message." data-i18n="[title]Inserted before the first Assistant's message.">
3527 <small data-i18n="First Assistant Prefix">First Assistant Prefix</small>3388 <small data-i18n="First Assistant Prefix">First Assistant Prefix</small>
@@ -3558,6 +3419,147 @@
3558 <textarea id="instruct_user_alignment_message" class="text_pole textarea_compact autoSetHeight"></textarea>3419 <textarea id="instruct_user_alignment_message" class="text_pole textarea_compact autoSetHeight"></textarea>
3559 </div>3420 </div>
3560 </div>3421 </div>
3422 </details>
3423 </div>
3424 </div>
3425 <div id="SystemPromptColumn" class="flex-container flexNoGap flexFlowColumn flex1">
3426 <div id="SystemPromptBlock">
3427 <h4 class="standoutHeader title_restorable justifySpaceBetween">
3428 <div class="flex-container">
3429 <span data-i18n="System Prompt">System Prompt</span>
3430 <a href="https://docs.sillytavern.app/usage/core-concepts/advancedformatting/#system-prompt" class="notes-link" target="_blank">
3431 <span class="fa-solid fa-circle-question note-link-span"></span>
3432 </a>
3433 </div>
3434 <div class="flex-container">
3435 <label for="sysprompt_enabled" class="checkbox_label flex1" title="Enable System Prompt" data-i18n="[title]sysprompt_enabled">
3436 <input id="sysprompt_enabled" type="checkbox" style="display:none;" />
3437 <small><i class="fa-solid fa-power-off menu_button margin0"></i></small>
3438 </label>
3439 </div>
3440 </h4>
3441
3442 <div class="flex-container" title="Select your current System Prompt" data-i18n="[title]Select your current System Prompt">
3443 <select id="sysprompt_select" data-preset-manager-for="sysprompt" class="flex1 text_pole"></select>
3444 <div class="flex-container margin0 justifyCenter">
3445 <input type="file" hidden data-preset-manager-file="sysprompt" accept=".json, .settings">
3446 <i data-preset-manager-update="sysprompt" class="menu_button fa-solid fa-save" title="Update current prompt" data-i18n="[title]Update current prompt"></i>
3447 <i data-preset-manager-new="sysprompt" class="menu_button fa-solid fa-file-circle-plus" title="Save prompt as" data-i18n="[title]Save prompt as"></i>
3448 <i data-preset-manager-import="sysprompt" class="displayNone menu_button fa-solid fa-file-import" title="Import template" data-i18n="[title]Import template"></i>
3449 <i data-preset-manager-export="sysprompt" class="displayNone menu_button fa-solid fa-file-export" title="Export template" data-i18n="[title]Export template"></i>
3450 <i data-preset-manager-restore="sysprompt" class="menu_button fa-solid fa-recycle" title="Restore current prompt" data-i18n="[title]Restore current prompt"></i>
3451 <i data-preset-manager-delete="sysprompt" class="menu_button fa-solid fa-trash-can" title="Delete prompt" data-i18n="[title]Delete prompt"></i>
3452 </div>
3453 </div>
3454
3455 <div>
3456 <label for="sysprompt_content" class="flex-container">
3457 <small data-i18n="Prompt Content">Prompt Content</small>
3458 <i class="editor_maximize fa-solid fa-maximize right_menu_button" data-for="sysprompt_content" title="Expand the editor" data-i18n="[title]Expand the editor"></i>
3459 </label>
3460 <textarea id="sysprompt_content" class="text_pole textarea_compact autoSetHeight"></textarea>
3461 </div>
3462 </div>
3463
3464 <div>
3465 &nbsp;
3466 </div>
3467
3468 <div>
3469 <h4 class="range-block-title justifyLeft standoutHeader">
3470 <span data-i18n="Custom Stopping Strings">
3471 Custom Stopping Strings
3472 </span>
3473 <a href="https://docs.sillytavern.app/usage/core-concepts/advancedformatting/#custom-stopping-strings" class="notes-link" target="_blank">
3474 <span class="fa-solid fa-circle-question note-link-span"></span>
3475 </a>
3476 </h4>
3477 <div>
3478 <small>
3479 <span data-i18n="JSON serialized array of strings">JSON serialized array of strings</span>
3480 <i class="fa-solid fa-question-circle opacity50p" title="e.g: [&quot;Ford&quot;, &quot;BMW&quot;, &quot;Fiat&quot;]"></i>
3481 </small>
3482 </div>
3483 <div>
3484 <textarea id="custom_stopping_strings" class="text_pole textarea_compact monospace autoSetHeight"></textarea>
3485 </div>
3486 <label class="checkbox_label" for="custom_stopping_strings_macro">
3487 <input id="custom_stopping_strings_macro" type="checkbox" checked>
3488 <small data-i18n="Replace Macro in Custom Stopping Strings">
3489 Replace Macro in Custom Stopping Strings
3490 </small>
3491 </label>
3492 </div>
3493
3494 <div name="tokenizerSettingsBlock">
3495 <div name="tokenizerSelectorBlock">
3496 <h4 class="standoutHeader"><span data-i18n="Tokenizer">Tokenizer</span>
3497 <a href="https://docs.sillytavern.app/usage/core-concepts/advancedformatting/#tokenizer" class="notes-link" target="_blank">
3498 <span class="fa-solid fa-circle-question note-link-span"></span>
3499 </a>
3500 </h4>
3501 <select id="tokenizer">
3502 <option value="99">Best match (recommended)</option>
3503 <option value="0">None / Estimated</option>
3504 <option value="1">GPT-2</option>
3505 <!-- Option #2 was a legacy GPT-2/3 tokenizer -->
3506 <option value="3">Llama 1/2</option>
3507 <option value="12">Llama 3</option>
3508 <option value="13">Gemma / Gemini</option>
3509 <option value="14">Jamba</option>
3510 <option value="15">Qwen2</option>
3511 <option value="16">Command-R</option>
3512 <option value="4">NerdStash (NovelAI Clio)</option>
3513 <option value="5">NerdStash v2 (NovelAI Kayra)</option>
3514 <option value="7">Mistral V1</option>
3515 <option value="17">Mistral Nemo</option>
3516 <option value="8">Yi</option>
3517 <option value="11">Claude 1/2</option>
3518 <option value="6">API (WebUI / koboldcpp)</option>
3519 </select>
3520 </div>
3521 <div class="range-block flex-container flexnowrap" name="tokenPaddingBlock">
3522 <div class="range-block-title justifyLeft">
3523 <small data-i18n="Token Padding" class="flex-container">Token Padding
3524 <a href="https://docs.sillytavern.app/usage/core-concepts/advancedformatting/#token-padding" class="notes-link" target="_blank">
3525 <span class="fa-solid fa-circle-question note-link-span"></span>
3526 </a>
3527 </small>
3528 </div>
3529 <input id="token_padding" class="text_pole textarea_compact" type="number" min="-2048" max="2048" />
3530 </div>
3531 </div>
3532 <div>
3533 <h4 class="standoutHeader" data-i18n="Miscellaneous">Miscellaneous</h4>
3534 <div>
3535 <small>
3536 <span data-i18n="Non-markdown strings">
3537 Non-markdown strings
3538 </span>
3539 </small>
3540 <div>
3541 <input id="markdown_escape_strings" class="text_pole textarea_compact" type="text" data-i18n="[placeholder]comma delimited,no spaces between" placeholder="comma delimited,no spaces between" />
3542 </div>
3543 </div>
3544
3545 <div name="startReplyWithBlock">
3546 <div>
3547 <small>
3548 <span data-i18n="Start Reply With">
3549 Start Reply With
3550 </span>
3551 </small>
3552 <div>
3553 <textarea id="start_reply_with" class="text_pole textarea_compact autoSetHeight"></textarea>
3554 </div>
3555 <label class="checkbox_label" for="chat-show-reply-prefix-checkbox">
3556 <input id="chat-show-reply-prefix-checkbox" type="checkbox" />
3557 <small data-i18n="Show reply prefix in chat">
3558 Show reply prefix in chat
3559 </small>
3560 </label>
3561 </div>
3562 </div>
3561 </div>3563 </div>
3562 </div>3564 </div>
3563 </div>3565 </div>
public/locales/ar-sa.json+0 -4
@@ -381,10 +381,6 @@
381 "Group by vendors Description": "ضع نماذج OpenAI في مجموعة واحدة، والنماذج الإنسانية في مجموعة أخرى، وما إلى ذلك. ويمكن دمجها مع الفرز.",381 "Group by vendors Description": "ضع نماذج OpenAI في مجموعة واحدة، والنماذج الإنسانية في مجموعة أخرى، وما إلى ذلك. ويمكن دمجها مع الفرز.",
382 "Allow fallback routes": "السماح بمسارات الاحتياط",382 "Allow fallback routes": "السماح بمسارات الاحتياط",
383 "Allow fallback routes Description": "يختار النموذج البديل تلقائيًا إذا كان النموذج المحدد غير قادر على تلبية طلبك.",383 "Allow fallback routes Description": "يختار النموذج البديل تلقائيًا إذا كان النموذج المحدد غير قادر على تلبية طلبك.",
384 "openrouter_force_instruct": "هذا الخيار قديم وسيتم إزالته في المستقبل. لاستخدام تنسيق التعليمات، يرجى التبديل إلى OpenRouter ضمن Text Completion API بدلاً من ذلك.",
385 "LEGACY": "إرث",
386 "Force Instruct Mode formatting": "فرض تنسيق وضع التعليمات",
387 "Force_Instruct_Mode_formatting_Description": "إذا تم تمكين وضع التعليمات وهذا، فسيتم تنسيق المطالبة بواسطة SillyTavern باستخدام التيار\n إعدادات التنسيق المتقدمة (باستثناء توجيه موجه النظام). إذا تم تعطيله، فسيتم تنسيق المطالبة بواسطة OpenRouter.",
388 "Scale API Key": "مفتاح API لـ Scale",384 "Scale API Key": "مفتاح API لـ Scale",
389 "Clear your cookie": "امسح ملف تعريف الارتباط الخاص بك",385 "Clear your cookie": "امسح ملف تعريف الارتباط الخاص بك",
390 "Alt Method": "طريقة بديلة",386 "Alt Method": "طريقة بديلة",
public/locales/de-de.json+0 -4
@@ -381,10 +381,6 @@
381 "Group by vendors Description": "Platzieren Sie OpenAI-Modelle in einer Gruppe, anthropogene Modelle in einer anderen Gruppe usw. Kann mit Sortierung kombiniert werden.",381 "Group by vendors Description": "Platzieren Sie OpenAI-Modelle in einer Gruppe, anthropogene Modelle in einer anderen Gruppe usw. Kann mit Sortierung kombiniert werden.",
382 "Allow fallback routes": "Fallback-Routen zulassen",382 "Allow fallback routes": "Fallback-Routen zulassen",
383 "Allow fallback routes Description": "Das alternative Modell wird automatisch ausgewählt, wenn das ausgewählte Modell Ihre Anfrage nicht erfüllen kann.",383 "Allow fallback routes Description": "Das alternative Modell wird automatisch ausgewählt, wenn das ausgewählte Modell Ihre Anfrage nicht erfüllen kann.",
384 "openrouter_force_instruct": "Diese Option ist veraltet und wird in Zukunft entfernt. Um die Formatierung mit Anweisungen zu verwenden, wechseln Sie stattdessen zu OpenRouter unter Text Completion API.",
385 "LEGACY": "VERMÄCHTNIS",
386 "Force Instruct Mode formatting": "Formatierung im Force Instruct Mode",
387 "Force_Instruct_Mode_formatting_Description": "Wenn sowohl der Anweisungsmodus als auch dieser aktiviert sind, wird die Eingabeaufforderung von SillyTavern mit den aktuellen erweiterten Formatierungseinstellungen formatiert (außer „Anweisungssystem-Eingabeaufforderung“). Wenn deaktiviert, wird die Eingabeaufforderung von OpenRouter formatiert.",
388 "Scale API Key": "Scale API-Schlüssel",384 "Scale API Key": "Scale API-Schlüssel",
389 "Clear your cookie": "Löschen Sie Ihre Cookies",385 "Clear your cookie": "Löschen Sie Ihre Cookies",
390 "Alt Method": "Alternative Methode",386 "Alt Method": "Alternative Methode",
public/locales/es-es.json+0 -4
@@ -381,10 +381,6 @@
381 "Group by vendors Description": "Coloque los modelos OpenAI en un grupo, los modelos antrópicos en otro grupo, etc. Se puede combinar con la clasificación.",381 "Group by vendors Description": "Coloque los modelos OpenAI en un grupo, los modelos antrópicos en otro grupo, etc. Se puede combinar con la clasificación.",
382 "Allow fallback routes": "Permitir rutas de respaldo",382 "Allow fallback routes": "Permitir rutas de respaldo",
383 "Allow fallback routes Description": "El modelo alternativo se elige automáticamente si el modelo seleccionado no puede cumplir con tu solicitud.",383 "Allow fallback routes Description": "El modelo alternativo se elige automáticamente si el modelo seleccionado no puede cumplir con tu solicitud.",
384 "openrouter_force_instruct": "Esta opción está desactualizada y se eliminará en el futuro. Para utilizar el formato de instrucciones, cambie a OpenRouter en API de finalización de texto.",
385 "LEGACY": "LEGADO",
386 "Force Instruct Mode formatting": "Forzar formato en modo de instrucción",
387 "Force_Instruct_Mode_formatting_Description": "Si tanto el modo de instrucción como este están habilitados, SillyTavern formateará el mensaje usando el formato actual.\n configuraciones de formato avanzadas (excepto instrucciones del mensaje del sistema). Si está deshabilitado, OpenRouter formateará el mensaje.",
388 "Scale API Key": "Clave API de Scale",384 "Scale API Key": "Clave API de Scale",
389 "Clear your cookie": "Limpia tu cookie",385 "Clear your cookie": "Limpia tu cookie",
390 "Alt Method": "Método alternativo",386 "Alt Method": "Método alternativo",
public/locales/fr-fr.json+0 -4
@@ -381,10 +381,6 @@
381 "Group by vendors Description": "Placez les modèles OpenAI dans un groupe, les modèles Anthropic dans un autre groupe, etc. Peut être combiné avec le tri.",381 "Group by vendors Description": "Placez les modèles OpenAI dans un groupe, les modèles Anthropic dans un autre groupe, etc. Peut être combiné avec le tri.",
382 "Allow fallback routes": "Autoriser les itinéraires de secours",382 "Allow fallback routes": "Autoriser les itinéraires de secours",
383 "Allow fallback routes Description": "Le modèle alternatif est automatiquement sélectionné si le modèle choisi ne peut pas répondre à votre demande.",383 "Allow fallback routes Description": "Le modèle alternatif est automatiquement sélectionné si le modèle choisi ne peut pas répondre à votre demande.",
384 "openrouter_force_instruct": "Cette option est obsolète et sera supprimée à l'avenir. Pour utiliser le formatage des instructions, veuillez plutôt passer à OpenRouter sous API de saisie semi-automatique de texte.",
385 "LEGACY": "HÉRITAGE",
386 "Force Instruct Mode formatting": "Forcer le formatage du mode instruction",
387 "Force_Instruct_Mode_formatting_Description": "Si le mode Instruct et celui-ci sont activés, l'invite sera formatée par SillyTavern en utilisant le mode actuel.\n paramètres de formatage avancés (à l'exception de l'invite système). Si elle est désactivée, l'invite sera formatée par OpenRouter.",
388 "Scale API Key": "Clé API Scale",384 "Scale API Key": "Clé API Scale",
389 "Clear your cookie": "Effacer vos cookies",385 "Clear your cookie": "Effacer vos cookies",
390 "Alt Method": "Méthode alternative",386 "Alt Method": "Méthode alternative",
public/locales/is-is.json+0 -4
@@ -381,10 +381,6 @@
381 "Group by vendors Description": "Setjið OpenAI módel í einn hóp, Anthropic módel í annan hóp osfrv. Hægt að sameina við flokkun.",381 "Group by vendors Description": "Setjið OpenAI módel í einn hóp, Anthropic módel í annan hóp osfrv. Hægt að sameina við flokkun.",
382 "Allow fallback routes": "Leyfa bakfallssvæði",382 "Allow fallback routes": "Leyfa bakfallssvæði",
383 "Allow fallback routes Description": "Veldur hlutleysa vélbúnaðarinn við val þinn ef valið módel getur ekki uppfyllt beiðni þína.",383 "Allow fallback routes Description": "Veldur hlutleysa vélbúnaðarinn við val þinn ef valið módel getur ekki uppfyllt beiðni þína.",
384 "openrouter_force_instruct": "Þessi valkostur er úreltur og verður fjarlægður í framtíðinni. Til að nota leiðbeiningarsnið skaltu skipta yfir í OpenRouter undir Text Completion API í staðinn.",
385 "LEGACY": "ARFIÐ",
386 "Force Instruct Mode formatting": "Force Instruct Mode formatting",
387 "Force_Instruct_Mode_formatting_Description": "Ef bæði leiðbeiningarhamur og þessi eru virkjuð, verður kvaðningurinn sniðinn af SillyTavern með því að nota núverandi\n háþróaðar sniðstillingar (nema leiðbeiningar um System Prompt). Ef slökkt er á henni verður hvetjan sniðin af OpenRouter.",
388 "Scale API Key": "Lykill API fyrir Scale",384 "Scale API Key": "Lykill API fyrir Scale",
389 "Clear your cookie": "Hreinsaðu kökuna þína",385 "Clear your cookie": "Hreinsaðu kökuna þína",
390 "Alt Method": "Aðferð Bakmenn",386 "Alt Method": "Aðferð Bakmenn",
public/locales/it-it.json+0 -4
@@ -381,10 +381,6 @@
381 "Group by vendors Description": "Metti i modelli OpenAI in un gruppo, i modelli antropici in un altro gruppo, ecc. Può essere combinato con l'ordinamento.",381 "Group by vendors Description": "Metti i modelli OpenAI in un gruppo, i modelli antropici in un altro gruppo, ecc. Può essere combinato con l'ordinamento.",
382 "Allow fallback routes": "Consenti percorsi alternativi",382 "Allow fallback routes": "Consenti percorsi alternativi",
383 "Allow fallback routes Description": "Il modello alternativo viene automaticamente scelto se il modello selezionato non può soddisfare la tua richiesta.",383 "Allow fallback routes Description": "Il modello alternativo viene automaticamente scelto se il modello selezionato non può soddisfare la tua richiesta.",
384 "openrouter_force_instruct": "Questa opzione è obsoleta e verrà rimossa in futuro. Per usare la formattazione instruct, passa a OpenRouter in Text Completion API.",
385 "LEGACY": "EREDITÀ",
386 "Force Instruct Mode formatting": "Forza la formattazione della modalità istruzione",
387 "Force_Instruct_Mode_formatting_Description": "Se sia la modalità Instruct che questa sono abilitate, il prompt verrà formattato da SillyTavern utilizzando il file current\n impostazioni di formattazione avanzate (ad eccezione del prompt di sistema). Se disabilitato, il prompt verrà formattato da OpenRouter.",
388 "Scale API Key": "Chiave API di Scale",384 "Scale API Key": "Chiave API di Scale",
389 "Clear your cookie": "Cancella il tuo cookie",385 "Clear your cookie": "Cancella il tuo cookie",
390 "Alt Method": "Metodo alternativo",386 "Alt Method": "Metodo alternativo",
public/locales/ja-jp.json+0 -4
@@ -381,10 +381,6 @@
381 "Group by vendors Description": "OpenAI モデルを 1 つのグループに、Anthropic モデルを別のグループに配置するなどします。ソートと組み合わせることができます。",381 "Group by vendors Description": "OpenAI モデルを 1 つのグループに、Anthropic モデルを別のグループに配置するなどします。ソートと組み合わせることができます。",
382 "Allow fallback routes": "フォールバックルートを許可",382 "Allow fallback routes": "フォールバックルートを許可",
383 "Allow fallback routes Description": "選択したモデルが要求を満たせない場合、代替モデルが自動的に選択されます。",383 "Allow fallback routes Description": "選択したモデルが要求を満たせない場合、代替モデルが自動的に選択されます。",
384 "openrouter_force_instruct": "このオプションは古く、将来削除される予定です。指示されたフォーマットを使用するには、代わりにテキスト補完 API の OpenRouter に切り替えてください。",
385 "LEGACY": "遺産",
386 "Force Instruct Mode formatting": "強制指示モードのフォーマット",
387 "Force_Instruct_Mode_formatting_Description": "Instruct Mode とこれが両方とも有効になっている場合、プロンプトは SillyTavern によって現在の高度なフォーマット設定 (instruct System Prompt を除く) を使用してフォーマットされます。無効になっている場合、プロンプトは OpenRouter によってフォーマットされます。",
388 "Scale API Key": "ScaleのAPIキー",384 "Scale API Key": "ScaleのAPIキー",
389 "Clear your cookie": "クッキーを消去する",385 "Clear your cookie": "クッキーを消去する",
390 "Alt Method": "代替手法",386 "Alt Method": "代替手法",
public/locales/ko-kr.json+0 -4
@@ -381,10 +381,6 @@
381 "Group by vendors Description": "OpenAI 모델을 한 그룹에 넣고, Anthropic 모델을 다른 그룹에 두는 등 정렬을 통해 결합할 수 있습니다.",381 "Group by vendors Description": "OpenAI 모델을 한 그룹에 넣고, Anthropic 모델을 다른 그룹에 두는 등 정렬을 통해 결합할 수 있습니다.",
382 "Allow fallback routes": "대체 경로 허용",382 "Allow fallback routes": "대체 경로 허용",
383 "Allow fallback routes Description": "선택한 모델이 요청을 처리할 수 없는 경우 대체 모델이 자동으로 선택됩니다.",383 "Allow fallback routes Description": "선택한 모델이 요청을 처리할 수 없는 경우 대체 모델이 자동으로 선택됩니다.",
384 "openrouter_force_instruct": "이 옵션은 오래되었으며 향후 제거될 예정입니다. 지시 형식을 사용하려면 대신 Text Completion API에서 OpenRouter로 전환하세요.",
385 "LEGACY": "유산",
386 "Force Instruct Mode formatting": "강제 지시 모드 포맷",
387 "Force_Instruct_Mode_formatting_Description": "Instruct Mode와 이 모드가 모두 활성화된 경우 프롬프트는 SillyTavern에 의해 현재 형식을 사용하여 형식화됩니다.\n 고급 형식 설정(시스템 프롬프트 지시 제외) 비활성화된 경우 프롬프트는 OpenRouter에 의해 형식화됩니다.",
388 "Scale API Key": "Scale API 키",384 "Scale API Key": "Scale API 키",
389 "Clear your cookie": "쿠키 지우기",385 "Clear your cookie": "쿠키 지우기",
390 "Alt Method": "대체 방법",386 "Alt Method": "대체 방법",
public/locales/nl-nl.json+0 -4
@@ -381,10 +381,6 @@
381 "Group by vendors Description": "Plaats OpenAI-modellen in één groep, antropische modellen in een andere groep, enz. Kan worden gecombineerd met sorteren.",381 "Group by vendors Description": "Plaats OpenAI-modellen in één groep, antropische modellen in een andere groep, enz. Kan worden gecombineerd met sorteren.",
382 "Allow fallback routes": "Fallback-routes toestaan",382 "Allow fallback routes": "Fallback-routes toestaan",
383 "Allow fallback routes Description": "Het alternatieve model wordt automatisch gekozen als het geselecteerde model niet aan uw verzoek kan voldoen.",383 "Allow fallback routes Description": "Het alternatieve model wordt automatisch gekozen als het geselecteerde model niet aan uw verzoek kan voldoen.",
384 "openrouter_force_instruct": "Deze optie is verouderd en zal in de toekomst worden verwijderd. Om instructie-opmaak te gebruiken, schakelt u in plaats daarvan over naar OpenRouter onder Text Completion API.",
385 "LEGACY": "NALATENSCHAP",
386 "Force Instruct Mode formatting": "Forceer de opmaak van de instructiemodus",
387 "Force_Instruct_Mode_formatting_Description": "Als zowel de Instruct-modus als deze zijn ingeschakeld, wordt de prompt door SillyTavern geformatteerd met behulp van de current\n geavanceerde opmaakinstellingen (behalve de opdracht Systeemprompt). Indien uitgeschakeld, wordt de prompt geformatteerd door OpenRouter.",
388 "Scale API Key": "Scale API-sleutel",384 "Scale API Key": "Scale API-sleutel",
389 "Clear your cookie": "Wis uw cookie",385 "Clear your cookie": "Wis uw cookie",
390 "Alt Method": "Alternatieve methode",386 "Alt Method": "Alternatieve methode",
public/locales/pt-pt.json+0 -4
@@ -381,10 +381,6 @@
381 "Group by vendors Description": "Coloque os modelos OpenAI em um grupo, os modelos antrópicos em outro grupo, etc.",381 "Group by vendors Description": "Coloque os modelos OpenAI em um grupo, os modelos antrópicos em outro grupo, etc.",
382 "Allow fallback routes": "Permitir rotas de fallback",382 "Allow fallback routes": "Permitir rotas de fallback",
383 "Allow fallback routes Description": "O modelo alternativo será escolhido automaticamente se o modelo selecionado não puder atender à sua solicitação.",383 "Allow fallback routes Description": "O modelo alternativo será escolhido automaticamente se o modelo selecionado não puder atender à sua solicitação.",
384 "openrouter_force_instruct": "Esta opção está desatualizada e será removida no futuro. Para usar a formatação de instruções, mude para OpenRouter em Text Completion API.",
385 "LEGACY": "LEGADO",
386 "Force Instruct Mode formatting": "Forçar formatação do modo de instrução",
387 "Force_Instruct_Mode_formatting_Description": "Se o Modo Instruir e este estiverem habilitados, o prompt será formatado pelo SillyTavern usando o atual\n configurações avançadas de formatação (exceto instruir o prompt do sistema). Se desativado, o prompt será formatado pelo OpenRouter.",
388 "Scale API Key": "Chave da API Scale",384 "Scale API Key": "Chave da API Scale",
389 "Clear your cookie": "Limpe seu cookie",385 "Clear your cookie": "Limpe seu cookie",
390 "Alt Method": "Método Alternativo",386 "Alt Method": "Método Alternativo",
public/locales/ru-ru.json+0 -4
@@ -732,8 +732,6 @@
732 "Context Size": "По размеру контекста",732 "Context Size": "По размеру контекста",
733 "Group by vendors": "Сгруппировать по владельцу",733 "Group by vendors": "Сгруппировать по владельцу",
734 "Group by vendors Description": "Модели от OpenAI попадут в одну группу, от Anthropic - в другую, и т.д. Можно комбинировать с сортировкой.",734 "Group by vendors Description": "Модели от OpenAI попадут в одну группу, от Anthropic - в другую, и т.д. Можно комбинировать с сортировкой.",
735 "LEGACY": "УСТАР.",
736 "Force Instruct Mode formatting": "Включить форматирование для Instruct-режима",
737 "Allow Jailbreak": "Разрешить джейлбрейк",735 "Allow Jailbreak": "Разрешить джейлбрейк",
738 "System Prompt Wrapping": "Обрамление для системного промпта",736 "System Prompt Wrapping": "Обрамление для системного промпта",
739 "System Prompt Prefix": "Префикс системного промпта",737 "System Prompt Prefix": "Префикс системного промпта",
@@ -1270,8 +1268,6 @@
1270 "vLLM Model": "Модель vLLM",1268 "vLLM Model": "Модель vLLM",
1271 "Aphrodite Model": "Модель Aphrodite",1269 "Aphrodite Model": "Модель Aphrodite",
1272 "Peek a password": "Посмотреть пароль",1270 "Peek a password": "Посмотреть пароль",
1273 "openrouter_force_instruct": "This option is outdated and will be removed in the future. To use instruct formatting, please switch to OpenRouter under Text Completion API instead.",
1274 "Force_Instruct_Mode_formatting_Description": "If both Instruct Mode and this are enabled, the prompt will be formatted by SillyTavern using the current\n advanced formatting settings (except instruct System Prompt). If disabled, the prompt will be formatted by OpenRouter.",
1275 "Clear your cookie": "Clear your cookie",1271 "Clear your cookie": "Clear your cookie",
1276 "Add Chat Start and Example Separator to a list of stopping strings.": "Использовать Начало чата и Разделитель примеров сообщений в качестве стоп-строк.",1272 "Add Chat Start and Example Separator to a list of stopping strings.": "Использовать Начало чата и Разделитель примеров сообщений в качестве стоп-строк.",
1277 "context_allow_jailbreak": "Если в карточке есть джейлбрейк И ПРИ ЭТОМ включена опция \"Приоритет джейлбрейку из карточки персонажа\", то этот джейлбрейк добавляется в конец промпта.\nНЕ РЕКОМЕНДУЕТСЯ ДЛЯ МОДЕЛЕЙ TEXT COMPLETION, МОЖЕТ ПОРТИТЬ ВЫХОДНОЙ ТЕКСТ.",1273 "context_allow_jailbreak": "Если в карточке есть джейлбрейк И ПРИ ЭТОМ включена опция \"Приоритет джейлбрейку из карточки персонажа\", то этот джейлбрейк добавляется в конец промпта.\nНЕ РЕКОМЕНДУЕТСЯ ДЛЯ МОДЕЛЕЙ TEXT COMPLETION, МОЖЕТ ПОРТИТЬ ВЫХОДНОЙ ТЕКСТ.",
public/locales/uk-ua.json+0 -4
@@ -381,10 +381,6 @@
381 "Group by vendors Description": "Помістіть моделі OpenAI в одну групу, моделі Anthropic в іншу групу тощо. Можна поєднати з сортуванням.",381 "Group by vendors Description": "Помістіть моделі OpenAI в одну групу, моделі Anthropic в іншу групу тощо. Можна поєднати з сортуванням.",
382 "Allow fallback routes": "Дозволити резервні маршрути",382 "Allow fallback routes": "Дозволити резервні маршрути",
383 "Allow fallback routes Description": "Автоматично вибирає альтернативну модель, якщо вибрана модель не може задовольнити ваш запит.",383 "Allow fallback routes Description": "Автоматично вибирає альтернативну модель, якщо вибрана модель не може задовольнити ваш запит.",
384 "openrouter_force_instruct": "Цей параметр застарів і буде видалено в майбутньому. Щоб використовувати форматування інструкцій, перейдіть натомість до OpenRouter у розділі Text Completion API.",
385 "LEGACY": "СПАДОК",
386 "Force Instruct Mode formatting": "Примусове форматування в режимі вказівок",
387 "Force_Instruct_Mode_formatting_Description": "Якщо ввімкнути обидва режими Instruction і цей режим, підказка буде відформатована SillyTavern за допомогою поточного\n розширені параметри форматування (крім системного запиту). Якщо вимкнено, запит буде відформатовано OpenRouter.",
388 "Scale API Key": "Ключ API для Scale",384 "Scale API Key": "Ключ API для Scale",
389 "Clear your cookie": "Очистіть файл cookie",385 "Clear your cookie": "Очистіть файл cookie",
390 "Alt Method": "Альтернативний метод",386 "Alt Method": "Альтернативний метод",
public/locales/vi-vn.json+0 -4
@@ -381,10 +381,6 @@
381 "Group by vendors Description": "Xếp các mô hình OpenAI vào một nhóm, các mô hình Anthropic vào một nhóm khác, v.v. Có thể kết hợp với việc sắp xếp.",381 "Group by vendors Description": "Xếp các mô hình OpenAI vào một nhóm, các mô hình Anthropic vào một nhóm khác, v.v. Có thể kết hợp với việc sắp xếp.",
382 "Allow fallback routes": "Cho phép các tuyến đường phụ",382 "Allow fallback routes": "Cho phép các tuyến đường phụ",
383 "Allow fallback routes Description": "Bot thay thế tự động nếu mô hình được chọn không thể đáp ứng yêu cầu của bạn.",383 "Allow fallback routes Description": "Bot thay thế tự động nếu mô hình được chọn không thể đáp ứng yêu cầu của bạn.",
384 "openrouter_force_instruct": "Tùy chọn này đã lỗi thời và sẽ bị xóa trong tương lai. Để sử dụng định dạng hướng dẫn, vui lòng chuyển sang OpenRouter trong API hoàn thành văn bản.",
385 "LEGACY": "Cũ",
386 "Force Instruct Mode formatting": "Buộc định dạng Instruct Mode",
387 "Force_Instruct_Mode_formatting_Description": "Nếu cả Instruct Mode và chế độ này được bật, Prompt sẽ được SillyTavern định dạng bằng cách sử dụng\n cài đặt định dạng nâng cao (ngoại trừ hướng dẫn System Nhắc). Nếu bị tắt, Prompt sẽ được OpenRouter định dạng.",
388 "Scale API Key": "Scale API Key",384 "Scale API Key": "Scale API Key",
389 "Clear your cookie": "Xóa cookie",385 "Clear your cookie": "Xóa cookie",
390 "Alt Method": "Phương pháp thay thế",386 "Alt Method": "Phương pháp thay thế",
public/locales/zh-cn.json+0 -4
@@ -397,10 +397,6 @@
397 "Context Size": "上下文大小",397 "Context Size": "上下文大小",
398 "Group by vendors": "按供应商分组",398 "Group by vendors": "按供应商分组",
399 "Group by vendors Description": "将 OpenAI 模型放在一组,将 Anthropic 模型放在另一组,等等。可以与排序结合。",399 "Group by vendors Description": "将 OpenAI 模型放在一组,将 Anthropic 模型放在另一组,等等。可以与排序结合。",
400 "openrouter_force_instruct": "此选项已过时,将来会被删除。要使用指令格式,请改用文本完成 API 下的 OpenRouter。",
401 "LEGACY": "旧版",
402 "Force Instruct Mode formatting": "强制指令模式格式化",
403 "Force_Instruct_Mode_formatting_Description": "如果同时启用了“指示模式”和“系统提示词”,则 SillyTavern 将使用当前\n高级格式设置(指示系统提示词除外)对提示词进行格式化。如果禁用,则 OpenRouter 将对提示词进行格式化。",
404 "Scale API Key": "Scale API密钥",400 "Scale API Key": "Scale API密钥",
405 "Clear your cookie": "清除你的 Cookie",401 "Clear your cookie": "清除你的 Cookie",
406 "Alt Method": "备用方法",402 "Alt Method": "备用方法",
public/locales/zh-tw.json+0 -4
@@ -382,10 +382,6 @@
382 "Group by vendors Description": "將 OpenAI 、 Anthropic 等等的模型放各自供應商的群組中。可以與排序功能結合使用。",382 "Group by vendors Description": "將 OpenAI 、 Anthropic 等等的模型放各自供應商的群組中。可以與排序功能結合使用。",
383 "Allow fallback routes": "允許備援路徑",383 "Allow fallback routes": "允許備援路徑",
384 "Allow fallback routes Description": "如果選擇的模型無法滿足要求,會自動選擇替代模型。",384 "Allow fallback routes Description": "如果選擇的模型無法滿足要求,會自動選擇替代模型。",
385 "openrouter_force_instruct": "這個選項已經過時,將來會被移除。如果要使用指令格式,請改在 Text Completion API 中選擇 OpenRouter。",
386 "LEGACY": "遺留",
387 "Force Instruct Mode formatting": "強制指示模式格式化",
388 "Force_Instruct_Mode_formatting_Description": "如果同時啟用「指令模式」和這個選項,\nSillyTavern 會根據目前的進階格式化設定(不包括指令系統提示)來格式化提示詞。\n如果停用這個選項,提示詞將由 OpenRouter 來進行格式化。",
389 "Scale API Key": "Scale API 金鑰",385 "Scale API Key": "Scale API 金鑰",
390 "Clear your cookie": "清除您的 Cookie",386 "Clear your cookie": "清除您的 Cookie",
391 "Alt Method": "替代方法",387 "Alt Method": "替代方法",
public/script.js+35 -15
@@ -96,11 +96,10 @@ import {
96 openai_messages_count,96 openai_messages_count,
97 chat_completion_sources,97 chat_completion_sources,
98 getChatCompletionModel,98 getChatCompletionModel,
99 isOpenRouterWithInstruct,
100 proxies,99 proxies,
101 loadProxyPresets,100 loadProxyPresets,
102 selected_proxy,101 selected_proxy,
103 initOpenai,102 initOpenAI,
104} from './scripts/openai.js';103} from './scripts/openai.js';
105104
106import {105import {
@@ -211,7 +210,7 @@ import {
211 selectContextPreset,210 selectContextPreset,
212} from './scripts/instruct-mode.js';211} from './scripts/instruct-mode.js';
213import { initLocales, t, translate } from './scripts/i18n.js';212import { initLocales, t, translate } from './scripts/i18n.js';
214import { getFriendlyTokenizerName, getTokenCount, getTokenCountAsync, getTokenizerModel, initTokenizers, saveTokenCache } from './scripts/tokenizers.js';213import { getFriendlyTokenizerName, getTokenCount, getTokenCountAsync, getTokenizerModel, initTokenizers, saveTokenCache, TOKENIZER_SUPPORTED_KEY } from './scripts/tokenizers.js';
215import {214import {
216 user_avatar,215 user_avatar,
217 getUserAvatars,216 getUserAvatars,
@@ -244,6 +243,7 @@ import { SlashCommandEnumValue, enumTypes } from './scripts/slash-commands/Slash
244import { commonEnumProviders, enumIcons } from './scripts/slash-commands/SlashCommandCommonEnumsProvider.js';243import { commonEnumProviders, enumIcons } from './scripts/slash-commands/SlashCommandCommonEnumsProvider.js';
245import { initInputMarkdown } from './scripts/input-md-formatting.js';244import { initInputMarkdown } from './scripts/input-md-formatting.js';
246import { AbortReason } from './scripts/util/AbortReason.js';245import { AbortReason } from './scripts/util/AbortReason.js';
246import { initSystemPrompts } from './scripts/sysprompt.js';
247247
248//exporting functions and vars for mods248//exporting functions and vars for mods
249export {249export {
@@ -412,6 +412,7 @@ export const event_types = {
412 MESSAGE_FILE_EMBEDDED: 'message_file_embedded',412 MESSAGE_FILE_EMBEDDED: 'message_file_embedded',
413 IMPERSONATE_READY: 'impersonate_ready',413 IMPERSONATE_READY: 'impersonate_ready',
414 CHAT_CHANGED: 'chat_id_changed',414 CHAT_CHANGED: 'chat_id_changed',
415 GENERATION_AFTER_COMMANDS: 'GENERATION_AFTER_COMMANDS',
415 GENERATION_STARTED: 'generation_started',416 GENERATION_STARTED: 'generation_started',
416 GENERATION_STOPPED: 'generation_stopped',417 GENERATION_STOPPED: 'generation_stopped',
417 GENERATION_ENDED: 'generation_ended',418 GENERATION_ENDED: 'generation_ended',
@@ -929,9 +930,12 @@ async function firstLoadInit() {
929 addSafariPatch();930 addSafariPatch();
930 await getClientVersion();931 await getClientVersion();
931 await readSecretState();932 await readSecretState();
932 initLocales();933 await initLocales();
933 initDefaultSlashCommands();934 initDefaultSlashCommands();
934 initTextGenModels();935 initTextGenModels();
936 initOpenAI();
937 initSystemPrompts();
938 await initPresetManager();
935 await getSystemMessages();939 await getSystemMessages();
936 sendSystemMessage(system_message_types.WELCOME);940 sendSystemMessage(system_message_types.WELCOME);
937 sendSystemMessage(system_message_types.WELCOME_PROMPT);941 sendSystemMessage(system_message_types.WELCOME_PROMPT);
@@ -939,13 +943,11 @@ async function firstLoadInit() {
939 initKeyboard();943 initKeyboard();
940 initDynamicStyles();944 initDynamicStyles();
941 initTags();945 initTags();
942 initOpenai();
943 initBookmarks();946 initBookmarks();
944 await getUserAvatars(true, user_avatar);947 await getUserAvatars(true, user_avatar);
945 await getCharacters();948 await getCharacters();
946 await getBackgrounds();949 await getBackgrounds();
947 await initTokenizers();950 await initTokenizers();
948 await initPresetManager();
949 initBackgrounds();951 initBackgrounds();
950 initAuthorsNote();952 initAuthorsNote();
951 initPersonas();953 initPersonas();
@@ -1215,6 +1217,9 @@ async function getStatusTextgen() {
1215 // Determine instruct mode preset1217 // Determine instruct mode preset
1216 autoSelectInstructPreset(online_status);1218 autoSelectInstructPreset(online_status);
12171219
1220 const supportsTokenization = response.headers.get('x-supports-tokenization') === 'true';
1221 supportsTokenization ? sessionStorage.setItem(TOKENIZER_SUPPORTED_KEY, 'true') : sessionStorage.removeItem(TOKENIZER_SUPPORTED_KEY);
1222
1218 // We didn't get a 200 status code, but the endpoint has an explanation. Which means it DID connect, but I digress.1223 // We didn't get a 200 status code, but the endpoint has an explanation. Which means it DID connect, but I digress.
1219 if (online_status === 'no_connection' && data.response) {1224 if (online_status === 'no_connection' && data.response) {
1220 toastr.error(data.response, 'API Error', { timeOut: 5000, preventDuplicates: true });1225 toastr.error(data.response, 'API Error', { timeOut: 5000, preventDuplicates: true });
@@ -3339,6 +3344,9 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
3339 setGenerationProgress(0);3344 setGenerationProgress(0);
3340 generation_started = new Date();3345 generation_started = new Date();
33413346
3347 // Occurs every time, even if the generation is aborted due to slash commands execution
3348 await eventSource.emit(event_types.GENERATION_STARTED, type, { automatic_trigger, force_name2, quiet_prompt, quietToLoud, skipWIAN, force_chid, signal, quietImage }, dryRun);
3349
3342 // Don't recreate abort controller if signal is passed3350 // Don't recreate abort controller if signal is passed
3343 if (!(abortController && signal)) {3351 if (!(abortController && signal)) {
3344 abortController = new AbortController();3352 abortController = new AbortController();
@@ -3358,7 +3366,8 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
3358 }3366 }
3359 }3367 }
33603368
3361 await eventSource.emit(event_types.GENERATION_STARTED, type, { automatic_trigger, force_name2, quiet_prompt, quietToLoud, skipWIAN, force_chid, signal, quietImage }, dryRun);3369 // Occurs only if the generation is not aborted due to slash commands execution
3370 await eventSource.emit(event_types.GENERATION_AFTER_COMMANDS, type, { automatic_trigger, force_name2, quiet_prompt, quietToLoud, skipWIAN, force_chid, signal, quietImage }, dryRun);
33623371
3363 if (main_api == 'kobold' && kai_settings.streaming_kobold && !kai_flags.can_use_streaming) {3372 if (main_api == 'kobold' && kai_settings.streaming_kobold && !kai_flags.can_use_streaming) {
3364 toastr.error('Streaming is enabled, but the version of Kobold used does not support token streaming.', undefined, { timeOut: 10000, preventDuplicates: true });3373 toastr.error('Streaming is enabled, but the version of Kobold used does not support token streaming.', undefined, { timeOut: 10000, preventDuplicates: true });
@@ -3517,9 +3526,14 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
3517 jailbreak,3526 jailbreak,
3518 } = getCharacterCardFields();3527 } = getCharacterCardFields();
35193528
3520 if (isInstruct) {3529 if (main_api !== 'openai') {
3521 system = power_user.prefer_character_prompt && system ? system : baseChatReplace(power_user.instruct.system_prompt, name1, name2);3530 if (power_user.sysprompt.enabled) {
3522 system = formatInstructModeSystemPrompt(substituteParams(system, name1, name2, power_user.instruct.system_prompt));3531 system = power_user.prefer_character_prompt && system ? system : baseChatReplace(power_user.sysprompt.content, name1, name2);
3532 system = isInstruct ? formatInstructModeSystemPrompt(substituteParams(system, name1, name2, power_user.sysprompt.content)) : system;
3533 } else {
3534 // Nullify if it's not enabled
3535 system = '';
3536 }
3523 }3537 }
35243538
3525 // Depth prompt (character-specific A/N)3539 // Depth prompt (character-specific A/N)
@@ -3772,7 +3786,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
3772 personality: personality,3786 personality: personality,
3773 persona: power_user.persona_description_position == persona_description_positions.IN_PROMPT ? persona : '',3787 persona: power_user.persona_description_position == persona_description_positions.IN_PROMPT ? persona : '',
3774 scenario: scenario,3788 scenario: scenario,
3775 system: isInstruct ? system : '',3789 system: system,
3776 char: name2,3790 char: name2,
3777 user: name1,3791 user: name1,
3778 wiBefore: worldInfoBefore,3792 wiBefore: worldInfoBefore,
@@ -3931,8 +3945,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
39313945
3932 if (isContinue) {3946 if (isContinue) {
3933 // Coping mechanism for OAI spacing3947 // Coping mechanism for OAI spacing
3934 const isForceInstruct = isOpenRouterWithInstruct();3948 if (main_api === 'openai' && !cyclePrompt.endsWith(' ')) {
3935 if (main_api === 'openai' && !isForceInstruct && !cyclePrompt.endsWith(' ')) {
3936 cyclePrompt += oai_settings.continue_postfix;3949 cyclePrompt += oai_settings.continue_postfix;
3937 continue_mag += oai_settings.continue_postfix;3950 continue_mag += oai_settings.continue_postfix;
3938 }3951 }
@@ -4346,7 +4359,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
4346 this_max_context: this_max_context,4359 this_max_context: this_max_context,
4347 padding: power_user.token_padding,4360 padding: power_user.token_padding,
4348 main_api: main_api,4361 main_api: main_api,
4349 instruction: isInstruct ? substituteParams(power_user.prefer_character_prompt && system ? system : power_user.instruct.system_prompt) : '',4362 instruction: main_api !== 'openai' && power_user.sysprompt.enabled ? substituteParams(power_user.prefer_character_prompt && system ? system : power_user.sysprompt.content) : '',
4350 userPersona: (power_user.persona_description_position == persona_description_positions.IN_PROMPT ? (persona || '') : ''),4363 userPersona: (power_user.persona_description_position == persona_description_positions.IN_PROMPT ? (persona || '') : ''),
4351 tokenizer: getFriendlyTokenizerName(main_api).tokenizerName || '',4364 tokenizer: getFriendlyTokenizerName(main_api).tokenizerName || '',
4352 };4365 };
@@ -4845,6 +4858,13 @@ export function getMaxContextSize(overrideResponseLength = null) {
4845 console.log(`NovelAI subscription limit reached. Max context size is now ${this_max_context}`);4858 console.log(`NovelAI subscription limit reached. Max context size is now ${this_max_context}`);
4846 }4859 }
4847 }4860 }
4861 if (nai_settings.model_novel.includes('erato')) {
4862 // subscriber limits coming soon
4863 this_max_context = Math.min(max_context, 8192);
4864
4865 // Added special tokens and whatnot
4866 this_max_context -= 1;
4867 }
48484868
4849 this_max_context = this_max_context - (overrideResponseLength || amount_gen);4869 this_max_context = this_max_context - (overrideResponseLength || amount_gen);
4850 }4870 }
@@ -5472,7 +5492,7 @@ export function cleanUpMessage(getMessage, isImpersonate, isContinue, displayInc
5472 }5492 }
54735493
5474 if (!displayIncompleteSentences && power_user.trim_sentences) {5494 if (!displayIncompleteSentences && power_user.trim_sentences) {
5475 getMessage = trimToEndSentence(getMessage, power_user.include_newline);5495 getMessage = trimToEndSentence(getMessage);
5476 }5496 }
54775497
5478 if (power_user.trim_spaces) {5498 if (power_user.trim_spaces) {
public/scripts/PromptManager.js+14 -9
@@ -1,12 +1,13 @@
1'use strict';1'use strict';
22
3import { callPopup, event_types, eventSource, is_send_press, main_api, substituteParams } from '../script.js';3import { event_types, eventSource, is_send_press, main_api, substituteParams } from '../script.js';
4import { is_group_generating } from './group-chats.js';4import { is_group_generating } from './group-chats.js';
5import { Message, TokenHandler } from './openai.js';5import { Message, TokenHandler } from './openai.js';
6import { power_user } from './power-user.js';6import { power_user } from './power-user.js';
7import { debounce, waitUntilCondition, escapeHtml } from './utils.js';7import { debounce, waitUntilCondition, escapeHtml } from './utils.js';
8import { debounce_timeout } from './constants.js';8import { debounce_timeout } from './constants.js';
9import { renderTemplateAsync } from './templates.js';9import { renderTemplateAsync } from './templates.js';
10import { Popup } from './popup.js';
1011
11function debouncePromise(func, delay) {12function debouncePromise(func, delay) {
12 let timeoutId;13 let timeoutId;
@@ -453,7 +454,9 @@ class PromptManager {
453 };454 };
454455
455 // Delete selected prompt from list form and close edit form456 // Delete selected prompt from list form and close edit form
456 this.handleDeletePrompt = (event) => {457 this.handleDeletePrompt = async (event) => {
458 Popup.show.confirm('Are you sure you want to delete this prompt?', null).then((userChoice) => {
459 if (!userChoice) return;
457 const promptID = document.getElementById(this.configuration.prefix + 'prompt_manager_footer_append_prompt').value;460 const promptID = document.getElementById(this.configuration.prefix + 'prompt_manager_footer_append_prompt').value;
458 const prompt = this.getPromptById(promptID);461 const prompt = this.getPromptById(promptID);
459462
@@ -468,6 +471,7 @@ class PromptManager {
468 this.render();471 this.render();
469 this.saveServiceSettings();472 this.saveServiceSettings();
470 }473 }
474 });
471 };475 };
472476
473 // Create new prompt, then save it to settings and close form.477 // Create new prompt, then save it to settings and close form.
@@ -527,9 +531,9 @@ class PromptManager {
527531
528 // Import prompts for the selected character532 // Import prompts for the selected character
529 this.handleImport = () => {533 this.handleImport = () => {
530 callPopup('Existing prompts with the same ID will be overridden. Do you want to proceed?', 'confirm')534 Popup.show.confirm('Existing prompts with the same ID will be overridden. Do you want to proceed?', null)
531 .then(userChoice => {535 .then(userChoice => {
532 if (false === userChoice) return;536 if (!userChoice) return;
533537
534 const fileOpener = document.createElement('input');538 const fileOpener = document.createElement('input');
535 fileOpener.type = 'file';539 fileOpener.type = 'file';
@@ -563,9 +567,9 @@ class PromptManager {
563567
564 // Restore default state of a characters prompt order568 // Restore default state of a characters prompt order
565 this.handleCharacterReset = () => {569 this.handleCharacterReset = () => {
566 callPopup('This will reset the prompt order for this character. You will not lose any prompts.', 'confirm')570 Popup.show.confirm('This will reset the prompt order for this character. You will not lose any prompts.', null)
567 .then(userChoice => {571 .then(userChoice => {
568 if (false === userChoice) return;572 if (!userChoice) return;
569573
570 this.removePromptOrderForCharacter(this.activeCharacter);574 this.removePromptOrderForCharacter(this.activeCharacter);
571 this.addPromptOrderForCharacter(this.activeCharacter, promptManagerDefaultPromptOrder);575 this.addPromptOrderForCharacter(this.activeCharacter, promptManagerDefaultPromptOrder);
@@ -1536,16 +1540,17 @@ class PromptManager {
1536 }1540 }
15371541
1538 const encodedName = escapeHtml(prompt.name);1542 const encodedName = escapeHtml(prompt.name);
1543 const isMarkerPrompt = prompt.marker && prompt.injection_position !== INJECTION_POSITION.ABSOLUTE;
1539 const isSystemPrompt = !prompt.marker && prompt.system_prompt && prompt.injection_position !== INJECTION_POSITION.ABSOLUTE && !prompt.forbid_overrides;1544 const isSystemPrompt = !prompt.marker && prompt.system_prompt && prompt.injection_position !== INJECTION_POSITION.ABSOLUTE && !prompt.forbid_overrides;
1540 const isImportantPrompt = !prompt.marker && prompt.system_prompt && prompt.injection_position !== INJECTION_POSITION.ABSOLUTE && prompt.forbid_overrides;1545 const isImportantPrompt = !prompt.marker && prompt.system_prompt && prompt.injection_position !== INJECTION_POSITION.ABSOLUTE && prompt.forbid_overrides;
1541 const isUserPrompt = !prompt.marker && !prompt.system_prompt && prompt.injection_position !== INJECTION_POSITION.ABSOLUTE;1546 const isUserPrompt = !prompt.marker && !prompt.system_prompt && prompt.injection_position !== INJECTION_POSITION.ABSOLUTE;
1542 const isInjectionPrompt = !prompt.marker && prompt.injection_position === INJECTION_POSITION.ABSOLUTE;1547 const isInjectionPrompt = prompt.injection_position === INJECTION_POSITION.ABSOLUTE;
1543 const isOverriddenPrompt = Array.isArray(this.overriddenPrompts) && this.overriddenPrompts.includes(prompt.identifier);1548 const isOverriddenPrompt = Array.isArray(this.overriddenPrompts) && this.overriddenPrompts.includes(prompt.identifier);
1544 const importantClass = isImportantPrompt ? `${prefix}prompt_manager_important` : '';1549 const importantClass = isImportantPrompt ? `${prefix}prompt_manager_important` : '';
1545 listItemHtml += `1550 listItemHtml += `
1546 <li class="${prefix}prompt_manager_prompt ${draggableClass} ${enabledClass} ${markerClass} ${importantClass}" data-pm-identifier="${prompt.identifier}">1551 <li class="${prefix}prompt_manager_prompt ${draggableClass} ${enabledClass} ${markerClass} ${importantClass}" data-pm-identifier="${prompt.identifier}">
1547 <span class="${prefix}prompt_manager_prompt_name" data-pm-name="${encodedName}">1552 <span class="${prefix}prompt_manager_prompt_name" data-pm-name="${encodedName}">
1548 ${prompt.marker ? '<span class="fa-fw fa-solid fa-thumb-tack" title="Marker"></span>' : ''}1553 ${isMarkerPrompt ? '<span class="fa-fw fa-solid fa-thumb-tack" title="Marker"></span>' : ''}
1549 ${isSystemPrompt ? '<span class="fa-fw fa-solid fa-square-poll-horizontal" title="Global Prompt"></span>' : ''}1554 ${isSystemPrompt ? '<span class="fa-fw fa-solid fa-square-poll-horizontal" title="Global Prompt"></span>' : ''}
1550 ${isImportantPrompt ? '<span class="fa-fw fa-solid fa-star" title="Important Prompt"></span>' : ''}1555 ${isImportantPrompt ? '<span class="fa-fw fa-solid fa-star" title="Important Prompt"></span>' : ''}
1551 ${isUserPrompt ? '<span class="fa-fw fa-solid fa-user" title="User Prompt"></span>' : ''}1556 ${isUserPrompt ? '<span class="fa-fw fa-solid fa-user" title="User Prompt"></span>' : ''}
@@ -1745,7 +1750,7 @@ class PromptManager {
1745 */1750 */
1746 showPopup(area = 'edit') {1751 showPopup(area = 'edit') {
1747 const areaElement = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_' + area);1752 const areaElement = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_' + area);
1748 areaElement.style.display = 'block';1753 areaElement.style.display = 'flex';
17491754
1750 $('#' + this.configuration.prefix + 'prompt_manager_popup').first()1755 $('#' + this.configuration.prefix + 'prompt_manager_popup').first()
1751 .slideDown(200, 'swing')1756 .slideDown(200, 'swing')
public/scripts/backgrounds.js+1 -1
@@ -313,7 +313,7 @@ async function onDeleteBackgroundClick(e) {
313 }313 }
314}314}
315315
316const autoBgPrompt = 'Pause your roleplay and choose a location ONLY from the provided list that is the most suitable for the current scene. Do not output any other text:\n{0}';316const autoBgPrompt = 'Ignore previous instructions and choose a location ONLY from the provided list that is the most suitable for the current scene. Do not output any other text:\n{0}';
317317
318async function autoBackgroundCommand() {318async function autoBackgroundCommand() {
319 /** @type {HTMLElement[]} */319 /** @type {HTMLElement[]} */
public/scripts/extensions/caption/settings.html+3 -0
@@ -49,11 +49,14 @@
49 <option data-type="google" value="gemini-1.5-flash">gemini-1.5-flash</option>49 <option data-type="google" value="gemini-1.5-flash">gemini-1.5-flash</option>
50 <option data-type="google" value="gemini-1.5-flash-latest">gemini-1.5-flash-latest</option>50 <option data-type="google" value="gemini-1.5-flash-latest">gemini-1.5-flash-latest</option>
51 <option data-type="google" value="gemini-1.5-flash-001">gemini-1.5-flash-001</option>51 <option data-type="google" value="gemini-1.5-flash-001">gemini-1.5-flash-001</option>
52 <option data-type="google" value="gemini-1.5-flash-002">gemini-1.5-flash-002</option>
52 <option data-type="google" value="gemini-1.5-flash-exp-0827">gemini-1.5-flash-exp-0827</option>53 <option data-type="google" value="gemini-1.5-flash-exp-0827">gemini-1.5-flash-exp-0827</option>
53 <option data-type="google" value="gemini-1.5-flash-8b-exp-0827">gemini-1.5-flash-8b-exp-0827</option>54 <option data-type="google" value="gemini-1.5-flash-8b-exp-0827">gemini-1.5-flash-8b-exp-0827</option>
55 <option data-type="google" value="gemini-1.5-flash-8b-exp-0924">gemini-1.5-flash-8b-exp-0924</option>
54 <option data-type="google" value="gemini-1.5-pro">gemini-1.5-pro</option>56 <option data-type="google" value="gemini-1.5-pro">gemini-1.5-pro</option>
55 <option data-type="google" value="gemini-1.5-pro-latest">gemini-1.5-pro-latest</option>57 <option data-type="google" value="gemini-1.5-pro-latest">gemini-1.5-pro-latest</option>
56 <option data-type="google" value="gemini-1.5-pro-001">gemini-1.5-pro-001</option>58 <option data-type="google" value="gemini-1.5-pro-001">gemini-1.5-pro-001</option>
59 <option data-type="google" value="gemini-1.5-pro-002">gemini-1.5-pro-002</option>
57 <option data-type="google" value="gemini-1.5-pro-exp-0801">gemini-1.5-pro-exp-0801</option>60 <option data-type="google" value="gemini-1.5-pro-exp-0801">gemini-1.5-pro-exp-0801</option>
58 <option data-type="google" value="gemini-1.5-pro-exp-0827">gemini-1.5-pro-exp-0827</option>61 <option data-type="google" value="gemini-1.5-pro-exp-0827">gemini-1.5-pro-exp-0827</option>
59 <option data-type="google" value="gemini-pro-vision">gemini-pro-vision</option>62 <option data-type="google" value="gemini-pro-vision">gemini-pro-vision</option>
public/scripts/extensions/connection-manager/index.js+35 -1
@@ -34,6 +34,8 @@ const TC_COMMANDS = [
34 'preset',34 'preset',
35 'api-url',35 'api-url',
36 'model',36 'model',
37 'sysprompt',
38 'sysprompt-state',
37 'instruct',39 'instruct',
38 'context',40 'context',
39 'instruct-state',41 'instruct-state',
@@ -46,6 +48,8 @@ const FANCY_NAMES = {
46 'preset': 'Settings Preset',48 'preset': 'Settings Preset',
47 'model': 'Model',49 'model': 'Model',
48 'proxy': 'Proxy Preset',50 'proxy': 'Proxy Preset',
51 'sysprompt-state': 'Use System Prompt',
52 'sysprompt': 'System Prompt Name',
49 'instruct-state': 'Instruct Mode',53 'instruct-state': 'Instruct Mode',
50 'instruct': 'Instruct Template',54 'instruct': 'Instruct Template',
51 'context': 'Context Template',55 'context': 'Context Template',
@@ -181,6 +185,11 @@ async function readProfileFromCommands(mode, profile, cleanUp = false) {
181 }185 }
182186
183 if (cleanUp) {187 if (cleanUp) {
188 for (const command of commands) {
189 if (command.endsWith('-state') && profile[command] === 'false') {
190 delete profile[command.replace('-state', '')];
191 }
192 }
184 for (const command of opposingCommands) {193 for (const command of opposingCommands) {
185 if (commands.includes(command)) {194 if (commands.includes(command)) {
186 continue;195 continue;
@@ -326,7 +335,7 @@ function renderConnectionProfiles(profiles) {
326 noneOption.selected = !extension_settings.connectionManager.selectedProfile;335 noneOption.selected = !extension_settings.connectionManager.selectedProfile;
327 profiles.appendChild(noneOption);336 profiles.appendChild(noneOption);
328337
329 for (const profile of extension_settings.connectionManager.profiles) {338 for (const profile of extension_settings.connectionManager.profiles.sort((a, b) => a.name.localeCompare(b.name))) {
330 const option = document.createElement('option');339 const option = document.createElement('option');
331 option.value = profile.id;340 option.value = profile.id;
332 option.textContent = profile.name;341 option.textContent = profile.name;
@@ -463,6 +472,31 @@ async function renderDetailsContent(detailsContent) {
463 await eventSource.emit(event_types.CONNECTION_PROFILE_LOADED, NONE);472 await eventSource.emit(event_types.CONNECTION_PROFILE_LOADED, NONE);
464 });473 });
465474
475 const renameButton = document.getElementById('rename_connection_profile');
476 renameButton.addEventListener('click', async () => {
477 const selectedProfile = extension_settings.connectionManager.selectedProfile;
478 const profile = extension_settings.connectionManager.profiles.find(p => p.id === selectedProfile);
479 if (!profile) {
480 console.log('No profile selected');
481 return;
482 }
483
484 const newName = await Popup.show.input('Enter a new name', null, profile.name, { rows: 2 });
485 if (!newName) {
486 return;
487 }
488
489 if (extension_settings.connectionManager.profiles.some(p => p.name === newName)) {
490 toastr.error('A profile with the same name already exists.');
491 return;
492 }
493
494 profile.name = newName;
495 saveSettingsDebounced();
496 renderConnectionProfiles(profiles);
497 toastr.success('Connection profile renamed', '', { timeOut: 1500 });
498 });
499
466 /** @type {HTMLElement} */500 /** @type {HTMLElement} */
467 const viewDetails = document.getElementById('view_connection_profile');501 const viewDetails = document.getElementById('view_connection_profile');
468 const detailsContent = document.getElementById('connection_profile_details_content');502 const detailsContent = document.getElementById('connection_profile_details_content');
public/scripts/extensions/connection-manager/settings.html+1 -0
@@ -13,6 +13,7 @@
13 <i id="view_connection_profile" class="menu_button fa-solid fa-info-circle" title="View connection profile details" data-i18n="[title]View connection profile details"></i>13 <i id="view_connection_profile" class="menu_button fa-solid fa-info-circle" title="View connection profile details" data-i18n="[title]View connection profile details"></i>
14 <i id="create_connection_profile" class="menu_button fa-solid fa-file-circle-plus" title="Create a new connection profile" data-i18n="[title]Create a new connection profile"></i>14 <i id="create_connection_profile" class="menu_button fa-solid fa-file-circle-plus" title="Create a new connection profile" data-i18n="[title]Create a new connection profile"></i>
15 <i id="update_connection_profile" class="menu_button fa-solid fa-save" title="Update a connection profile" data-i18n="[title]Update a connection profile"></i>15 <i id="update_connection_profile" class="menu_button fa-solid fa-save" title="Update a connection profile" data-i18n="[title]Update a connection profile"></i>
16 <i id="rename_connection_profile" class="menu_button fa-solid fa-pencil" title="Rename a connection profile" data-i18n="[title]Rename a connection profile"></i>
16 <i id="reload_connection_profile" class="menu_button fa-solid fa-recycle" title="Reload a connection profile" data-i18n="[title]Reload a connection profile"></i>17 <i id="reload_connection_profile" class="menu_button fa-solid fa-recycle" title="Reload a connection profile" data-i18n="[title]Reload a connection profile"></i>
17 <i id="delete_connection_profile" class="menu_button fa-solid fa-trash-can" title="Delete a connection profile" data-i18n="[title]Delete a connection profile"></i>18 <i id="delete_connection_profile" class="menu_button fa-solid fa-trash-can" title="Delete a connection profile" data-i18n="[title]Delete a connection profile"></i>
18 </div>19 </div>
public/scripts/extensions/expressions/index.js+2 -2
@@ -20,7 +20,7 @@ const STREAMING_UPDATE_INTERVAL = 10000;
20const TALKINGCHECK_UPDATE_INTERVAL = 500;20const TALKINGCHECK_UPDATE_INTERVAL = 500;
21const DEFAULT_FALLBACK_EXPRESSION = 'joy';21const DEFAULT_FALLBACK_EXPRESSION = 'joy';
22const FUNCTION_NAME = 'set_emotion';22const FUNCTION_NAME = 'set_emotion';
23const DEFAULT_LLM_PROMPT = 'Pause your roleplay. Classify the emotion of the last message. Output just one word, e.g. "joy" or "anger". Choose only one of the following labels: {{labels}}';23const DEFAULT_LLM_PROMPT = 'Ignore previous instructions. Classify the emotion of the last message. Output just one word, e.g. "joy" or "anger". Choose only one of the following labels: {{labels}}';
24const DEFAULT_EXPRESSIONS = [24const DEFAULT_EXPRESSIONS = [
25 'talkinghead',25 'talkinghead',
26 'admiration',26 'admiration',
@@ -1161,7 +1161,7 @@ export async function getExpressionLabel(text, expressionsApi = extension_settin
1161 }1161 }
11621162
1163 const expressionsList = await getExpressionsList();1163 const expressionsList = await getExpressionsList();
1164 const prompt = substituteParamsExtended(String(customPrompt), { labels: expressionsList }) || await getLlmPrompt(expressionsList);1164 const prompt = substituteParamsExtended(customPrompt, { labels: expressionsList }) || await getLlmPrompt(expressionsList);
1165 let functionResult = null;1165 let functionResult = null;
1166 eventSource.once(event_types.TEXT_COMPLETION_SETTINGS_READY, onTextGenSettingsReady);1166 eventSource.once(event_types.TEXT_COMPLETION_SETTINGS_READY, onTextGenSettingsReady);
1167 eventSource.once(event_types.LLM_FUNCTION_TOOL_REGISTER, onFunctionToolRegister);1167 eventSource.once(event_types.LLM_FUNCTION_TOOL_REGISTER, onFunctionToolRegister);
public/scripts/extensions/memory/index.js+1 -1
@@ -102,7 +102,7 @@ const prompt_builders = {
102 RAW_NON_BLOCKING: 2,102 RAW_NON_BLOCKING: 2,
103};103};
104104
105const defaultPrompt = '[Pause your roleplay. Summarize the most important facts and events in the story so far. If a summary already exists in your memory, use that as a base and expand with new facts. Limit the summary to {{words}} words or less. Your response should include nothing but the summary.]';105const defaultPrompt = 'Ignore previous instructions. Summarize the most important facts and events in the story so far. If a summary already exists in your memory, use that as a base and expand with new facts. Limit the summary to {{words}} words or less. Your response should include nothing but the summary.';
106const defaultTemplate = '[Summary: {{summary}}]';106const defaultTemplate = '[Summary: {{summary}}]';
107107
108const defaultSettings = {108const defaultSettings = {
public/scripts/extensions/stable-diffusion/index.js+10 -8
@@ -125,15 +125,14 @@ const messageTrigger = {
125const promptTemplates = {125const promptTemplates = {
126 // Not really a prompt template, rather an outcome message template126 // Not really a prompt template, rather an outcome message template
127 [generationMode.MESSAGE]: '[{{char}} sends a picture that contains: {{prompt}}].',127 [generationMode.MESSAGE]: '[{{char}} sends a picture that contains: {{prompt}}].',
128 /*OLD: [generationMode.CHARACTER]: "Pause your roleplay and provide comma-delimited list of phrases and keywords which describe {{char}}'s physical appearance and clothing. Ignore {{char}}'s personality traits, and chat history when crafting this description. End your response once the comma-delimited list is complete. Do not roleplay when writing this description, and do not attempt to continue the story.", */
129 [generationMode.CHARACTER]: 'In the next response I want you to provide only a detailed comma-delimited list of keywords and phrases which describe {{char}}. The list must include all of the following items in this order: name, species and race, gender, age, clothing, occupation, physical features and appearances. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase \'full body portrait,\'',128 [generationMode.CHARACTER]: 'In the next response I want you to provide only a detailed comma-delimited list of keywords and phrases which describe {{char}}. The list must include all of the following items in this order: name, species and race, gender, age, clothing, occupation, physical features and appearances. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase \'full body portrait,\'',
130 //face-specific prompt129 //face-specific prompt
131 [generationMode.FACE]: 'In the next response I want you to provide only a detailed comma-delimited list of keywords and phrases which describe {{char}}. The list must include all of the following items in this order: name, species and race, gender, age, facial features and expressions, occupation, hair and hair accessories (if any), what they are wearing on their upper body (if anything). Do not describe anything below their neck. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase \'close up facial portrait,\'',130 [generationMode.FACE]: 'In the next response I want you to provide only a detailed comma-delimited list of keywords and phrases which describe {{char}}. The list must include all of the following items in this order: name, species and race, gender, age, facial features and expressions, occupation, hair and hair accessories (if any), what they are wearing on their upper body (if anything). Do not describe anything below their neck. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase \'close up facial portrait,\'',
132 //prompt for only the last message131 //prompt for only the last message
133 [generationMode.USER]: 'Pause your roleplay and provide a detailed description of {{user}}\'s physical appearance from the perspective of {{char}} in the form of a comma-delimited list of keywords and phrases. The list must include all of the following items in this order: name, species and race, gender, age, clothing, occupation, physical features and appearances. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase \'full body portrait,\'. Ignore the rest of the story when crafting this description. Do not roleplay as {{char}} when writing this description, and do not attempt to continue the story.',132 [generationMode.USER]: 'Ignore previous instructions and provide a detailed description of {{user}}\'s physical appearance from the perspective of {{char}} in the form of a comma-delimited list of keywords and phrases. The list must include all of the following items in this order: name, species and race, gender, age, clothing, occupation, physical features and appearances. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase \'full body portrait,\'. Ignore the rest of the story when crafting this description. Do not reply as {{char}} when writing this description, and do not attempt to continue the story.',
134 [generationMode.SCENARIO]: 'Pause your roleplay and provide a detailed description for all of the following: a brief recap of recent events in the story, {{char}}\'s appearance, and {{char}}\'s surroundings. Do not roleplay while writing this description.',133 [generationMode.SCENARIO]: 'Ignore previous instructions and provide a detailed description for all of the following: a brief recap of recent events in the story, {{char}}\'s appearance, and {{char}}\'s surroundings. Do not reply as {{char}} while writing this description.',
135134
136 [generationMode.NOW]: `Pause your roleplay. Your next response must be formatted as a single comma-delimited list of concise keywords. The list will describe of the visual details included in the last chat message.135 [generationMode.NOW]: `Ignore previous instructions. Your next response must be formatted as a single comma-delimited list of concise keywords. The list will describe of the visual details included in the last chat message.
137136
138 Only mention characters by using pronouns ('he','his','she','her','it','its') or neutral nouns ('male', 'the man', 'female', 'the woman').137 Only mention characters by using pronouns ('he','his','she','her','it','its') or neutral nouns ('male', 'the man', 'female', 'the woman').
139138
@@ -157,12 +156,12 @@ const promptTemplates = {
157 A correctly formatted example response would be:156 A correctly formatted example response would be:
158 '(location),(character list by gender),(primary action), (relative character position) POV, (character 1's description and actions), (character 2's description and actions)'`,157 '(location),(character list by gender),(primary action), (relative character position) POV, (character 1's description and actions), (character 2's description and actions)'`,
159158
160 [generationMode.RAW_LAST]: 'Pause your roleplay and provide ONLY the last chat message string back to me verbatim. Do not write anything after the string. Do not roleplay at all in your response. Do not continue the roleplay story.',159 [generationMode.RAW_LAST]: 'Ignore previous instructions and provide ONLY the last chat message string back to me verbatim. Do not write anything after the string. Do not reply as {{char}} when writing this description, and do not attempt to continue the story.',
161 [generationMode.BACKGROUND]: 'Pause your roleplay and provide a detailed description of {{char}}\'s surroundings in the form of a comma-delimited list of keywords and phrases. The list must include all of the following items in this order: location, time of day, weather, lighting, and any other relevant details. Do not include descriptions of characters and non-visual qualities such as names, personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase \'background,\'. Ignore the rest of the story when crafting this description. Do not roleplay as {{user}} when writing this description, and do not attempt to continue the story.',160 [generationMode.BACKGROUND]: 'Ignore previous instructions and provide a detailed description of {{char}}\'s surroundings in the form of a comma-delimited list of keywords and phrases. The list must include all of the following items in this order: location, time of day, weather, lighting, and any other relevant details. Do not include descriptions of characters and non-visual qualities such as names, personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase \'background,\'. Ignore the rest of the story when crafting this description. Do not reply as {{char}} when writing this description, and do not attempt to continue the story.',
162 [generationMode.FACE_MULTIMODAL]: 'Provide an exhaustive comma-separated list of tags describing the appearance of the character on this image in great detail. Start with "close-up portrait".',161 [generationMode.FACE_MULTIMODAL]: 'Provide an exhaustive comma-separated list of tags describing the appearance of the character on this image in great detail. Start with "close-up portrait".',
163 [generationMode.CHARACTER_MULTIMODAL]: 'Provide an exhaustive comma-separated list of tags describing the appearance of the character on this image in great detail. Start with "full body portrait".',162 [generationMode.CHARACTER_MULTIMODAL]: 'Provide an exhaustive comma-separated list of tags describing the appearance of the character on this image in great detail. Start with "full body portrait".',
164 [generationMode.USER_MULTIMODAL]: 'Provide an exhaustive comma-separated list of tags describing the appearance of the character on this image in great detail. Start with "full body portrait".',163 [generationMode.USER_MULTIMODAL]: 'Provide an exhaustive comma-separated list of tags describing the appearance of the character on this image in great detail. Start with "full body portrait".',
165 [generationMode.FREE_EXTENDED]: 'Pause your roleplay and provide an exhaustive comma-separated list of tags describing the appearance of "{0}" in great detail. Start with {{charPrefix}} (sic) if the subject is associated with {{char}}.',164 [generationMode.FREE_EXTENDED]: 'Ignore previous instructions and provide an exhaustive comma-separated list of tags describing the appearance of "{0}" in great detail. Start with {{charPrefix}} (sic) if the subject is associated with {{char}}.',
166};165};
167166
168const defaultPrefix = 'best quality, absurdres, aesthetic,';167const defaultPrefix = 'best quality, absurdres, aesthetic,';
@@ -3813,7 +3812,10 @@ jQuery(async () => {
3813 ],3812 ],
3814 helpString: `3813 helpString: `
3815 <div>3814 <div>
3816 Requests to generate an image and posts it to chat (unless <code>quiet=true</code> argument is specified).</code>.3815 Requests to generate an image and posts it to chat (unless <code>quiet=true</code> argument is specified).
3816 </div>
3817 <div>
3818 Supported arguments: <code>${Object.values(triggerWords).flat().join(', ')}</code>.
3817 </div>3819 </div>
3818 <div>3820 <div>
3819 Anything else would trigger a "free mode" to make generate whatever you prompted. Example: <code>/imagine apple tree</code> would generate a picture of an apple tree. Returns a link to the generated image.3821 Anything else would trigger a "free mode" to make generate whatever you prompted. Example: <code>/imagine apple tree</code> would generate a picture of an apple tree. Returns a link to the generated image.
public/scripts/extensions/vectors/index.js+1 -27
@@ -56,7 +56,7 @@ const settings = {
56 summarize: false,56 summarize: false,
57 summarize_sent: false,57 summarize_sent: false,
58 summary_source: 'main',58 summary_source: 'main',
59 summary_prompt: 'Pause your roleplay. Summarize the most important parts of the message. Limit yourself to 250 words or less. Your response should include nothing but the summary.',59 summary_prompt: 'Ignore previous instructions. Summarize the most important parts of the message. Limit yourself to 250 words or less. Your response should include nothing but the summary.',
60 force_chunk_delimiter: '',60 force_chunk_delimiter: '',
6161
62 // For chats62 // For chats
@@ -999,25 +999,6 @@ async function purgeAllVectorIndexes() {
999 }999 }
1000}1000}
10011001
1002async function isModelScopesEnabled() {
1003 try {
1004 const response = await fetch('/api/vector/scopes-enabled', {
1005 method: 'GET',
1006 headers: getVectorHeaders(),
1007 });
1008
1009 if (!response.ok) {
1010 return false;
1011 }
1012
1013 const data = await response.json();
1014 return data?.enabled ?? false;
1015 } catch (error) {
1016 console.error('Vectors: Failed to check model scopes', error);
1017 return false;
1018 }
1019}
1020
1021function toggleSettings() {1002function toggleSettings() {
1022 $('#vectors_files_settings').toggle(!!settings.enabled_files);1003 $('#vectors_files_settings').toggle(!!settings.enabled_files);
1023 $('#vectors_chats_settings').toggle(!!settings.enabled_chats);1004 $('#vectors_chats_settings').toggle(!!settings.enabled_chats);
@@ -1282,7 +1263,6 @@ jQuery(async () => {
1282 }1263 }
12831264
1284 Object.assign(settings, extension_settings.vectors);1265 Object.assign(settings, extension_settings.vectors);
1285 const scopesEnabled = await isModelScopesEnabled();
12861266
1287 // Migrate from TensorFlow to Transformers1267 // Migrate from TensorFlow to Transformers
1288 settings.source = settings.source !== 'local' ? settings.source : 'transformers';1268 settings.source = settings.source !== 'local' ? settings.source : 'transformers';
@@ -1294,7 +1274,6 @@ jQuery(async () => {
1294 saveSettingsDebounced();1274 saveSettingsDebounced();
1295 toggleSettings();1275 toggleSettings();
1296 });1276 });
1297 $('#vectors_modelWarning').hide();
1298 $('#vectors_enabled_files').prop('checked', settings.enabled_files).on('input', () => {1277 $('#vectors_enabled_files').prop('checked', settings.enabled_files).on('input', () => {
1299 settings.enabled_files = $('#vectors_enabled_files').prop('checked');1278 settings.enabled_files = $('#vectors_enabled_files').prop('checked');
1300 Object.assign(extension_settings.vectors, settings);1279 Object.assign(extension_settings.vectors, settings);
@@ -1334,31 +1313,26 @@ jQuery(async () => {
1334 saveSettingsDebounced();1313 saveSettingsDebounced();
1335 });1314 });
1336 $('#vectors_togetherai_model').val(settings.togetherai_model).on('change', () => {1315 $('#vectors_togetherai_model').val(settings.togetherai_model).on('change', () => {
1337 !scopesEnabled && $('#vectors_modelWarning').show();
1338 settings.togetherai_model = String($('#vectors_togetherai_model').val());1316 settings.togetherai_model = String($('#vectors_togetherai_model').val());
1339 Object.assign(extension_settings.vectors, settings);1317 Object.assign(extension_settings.vectors, settings);
1340 saveSettingsDebounced();1318 saveSettingsDebounced();
1341 });1319 });
1342 $('#vectors_openai_model').val(settings.openai_model).on('change', () => {1320 $('#vectors_openai_model').val(settings.openai_model).on('change', () => {
1343 !scopesEnabled && $('#vectors_modelWarning').show();
1344 settings.openai_model = String($('#vectors_openai_model').val());1321 settings.openai_model = String($('#vectors_openai_model').val());
1345 Object.assign(extension_settings.vectors, settings);1322 Object.assign(extension_settings.vectors, settings);
1346 saveSettingsDebounced();1323 saveSettingsDebounced();
1347 });1324 });
1348 $('#vectors_cohere_model').val(settings.cohere_model).on('change', () => {1325 $('#vectors_cohere_model').val(settings.cohere_model).on('change', () => {
1349 !scopesEnabled && $('#vectors_modelWarning').show();
1350 settings.cohere_model = String($('#vectors_cohere_model').val());1326 settings.cohere_model = String($('#vectors_cohere_model').val());
1351 Object.assign(extension_settings.vectors, settings);1327 Object.assign(extension_settings.vectors, settings);
1352 saveSettingsDebounced();1328 saveSettingsDebounced();
1353 });1329 });
1354 $('#vectors_ollama_model').val(settings.ollama_model).on('input', () => {1330 $('#vectors_ollama_model').val(settings.ollama_model).on('input', () => {
1355 !scopesEnabled && $('#vectors_modelWarning').show();
1356 settings.ollama_model = String($('#vectors_ollama_model').val());1331 settings.ollama_model = String($('#vectors_ollama_model').val());
1357 Object.assign(extension_settings.vectors, settings);1332 Object.assign(extension_settings.vectors, settings);
1358 saveSettingsDebounced();1333 saveSettingsDebounced();
1359 });1334 });
1360 $('#vectors_vllm_model').val(settings.vllm_model).on('input', () => {1335 $('#vectors_vllm_model').val(settings.vllm_model).on('input', () => {
1361 !scopesEnabled && $('#vectors_modelWarning').show();
1362 settings.vllm_model = String($('#vectors_vllm_model').val());1336 settings.vllm_model = String($('#vectors_vllm_model').val());
1363 Object.assign(extension_settings.vectors, settings);1337 Object.assign(extension_settings.vectors, settings);
1364 saveSettingsDebounced();1338 saveSettingsDebounced();
public/scripts/extensions/vectors/settings.html+0 -8
@@ -96,14 +96,6 @@
96 </i>96 </i>
97 </div>97 </div>
9898
99 <small id="vectors_modelWarning">
100 <i class="fa-solid fa-exclamation-triangle"></i>
101 <span>
102 Set <code>vectors.enableModelScopes</code> to true in config.yaml to switch between vectorization models without needing to purge existing vectors.
103 This option will soon be enabled by default.
104 </span>
105 </small>
106
107 <div class="flex-container alignItemsCenter" id="nomicai_apiKey">99 <div class="flex-container alignItemsCenter" id="nomicai_apiKey">
108 <label for="api_key_nomicai" class="flex1">100 <label for="api_key_nomicai" class="flex1">
109 <span data-i18n="NomicAI API Key">NomicAI API Key</span>101 <span data-i18n="NomicAI API Key">NomicAI API Key</span>
public/scripts/instruct-mode.js+27 -53
@@ -23,7 +23,6 @@ export const names_behavior_types = {
23const controls = [23const controls = [
24 { id: 'instruct_enabled', property: 'enabled', isCheckbox: true },24 { id: 'instruct_enabled', property: 'enabled', isCheckbox: true },
25 { id: 'instruct_wrap', property: 'wrap', isCheckbox: true },25 { id: 'instruct_wrap', property: 'wrap', isCheckbox: true },
26 { id: 'instruct_system_prompt', property: 'system_prompt', isCheckbox: false },
27 { id: 'instruct_system_sequence_prefix', property: 'system_sequence_prefix', isCheckbox: false },26 { id: 'instruct_system_sequence_prefix', property: 'system_sequence_prefix', isCheckbox: false },
28 { id: 'instruct_system_sequence_suffix', property: 'system_sequence_suffix', isCheckbox: false },27 { id: 'instruct_system_sequence_suffix', property: 'system_sequence_suffix', isCheckbox: false },
29 { id: 'instruct_input_sequence', property: 'input_sequence', isCheckbox: false },28 { id: 'instruct_input_sequence', property: 'input_sequence', isCheckbox: false },
@@ -35,7 +34,6 @@ const controls = [
35 { id: 'instruct_last_system_sequence', property: 'last_system_sequence', isCheckbox: false },34 { id: 'instruct_last_system_sequence', property: 'last_system_sequence', isCheckbox: false },
36 { id: 'instruct_user_alignment_message', property: 'user_alignment_message', isCheckbox: false },35 { id: 'instruct_user_alignment_message', property: 'user_alignment_message', isCheckbox: false },
37 { id: 'instruct_stop_sequence', property: 'stop_sequence', isCheckbox: false },36 { id: 'instruct_stop_sequence', property: 'stop_sequence', isCheckbox: false },
38 { id: 'instruct_names', property: 'names', isCheckbox: true },
39 { id: 'instruct_first_output_sequence', property: 'first_output_sequence', isCheckbox: false },37 { id: 'instruct_first_output_sequence', property: 'first_output_sequence', isCheckbox: false },
40 { id: 'instruct_last_output_sequence', property: 'last_output_sequence', isCheckbox: false },38 { id: 'instruct_last_output_sequence', property: 'last_output_sequence', isCheckbox: false },
41 { id: 'instruct_first_input_sequence', property: 'first_input_sequence', isCheckbox: false },39 { id: 'instruct_first_input_sequence', property: 'first_input_sequence', isCheckbox: false },
@@ -43,7 +41,7 @@ const controls = [
43 { id: 'instruct_activation_regex', property: 'activation_regex', isCheckbox: false },41 { id: 'instruct_activation_regex', property: 'activation_regex', isCheckbox: false },
44 { id: 'instruct_bind_to_context', property: 'bind_to_context', isCheckbox: true },42 { id: 'instruct_bind_to_context', property: 'bind_to_context', isCheckbox: true },
45 { id: 'instruct_skip_examples', property: 'skip_examples', isCheckbox: true },43 { id: 'instruct_skip_examples', property: 'skip_examples', isCheckbox: true },
46 { id: 'instruct_names_behavior input[name="names_behavior"]', property: 'names_behavior', isCheckbox: false },44 { id: 'instruct_names_behavior', property: 'names_behavior', isCheckbox: false },
47 { id: 'instruct_system_same_as_user', property: 'system_same_as_user', isCheckbox: true, trigger: true },45 { id: 'instruct_system_same_as_user', property: 'system_same_as_user', isCheckbox: true, trigger: true },
48];46];
4947
@@ -109,9 +107,10 @@ export async function loadInstructMode(data) {
109107
110 if (control.isCheckbox) {108 if (control.isCheckbox) {
111 $element.prop('checked', power_user.instruct[control.property]);109 $element.prop('checked', power_user.instruct[control.property]);
112 } else if (control.property === 'names_behavior') {110 } else if ($element.is('select')) {
113 const behavior = power_user.instruct[control.property];111 const value = power_user.instruct[control.property];
114 $element.filter(`[value="${behavior}"]`).prop('checked', true);112 $element.val(value);
113 $element.filter(`[value="${value}"]`).prop('checked', true);
115 } else {114 } else {
116 $element.val(power_user.instruct[control.property]);115 $element.val(power_user.instruct[control.property]);
117 }116 }
@@ -137,12 +136,6 @@ export async function loadInstructMode(data) {
137 option.selected = name === power_user.instruct.preset;136 option.selected = name === power_user.instruct.preset;
138 $('#instruct_presets').append(option);137 $('#instruct_presets').append(option);
139 });138 });
140
141 highlightDefaultPreset();
142}
143
144function highlightDefaultPreset() {
145 $('#instruct_set_default').toggleClass('default', power_user.default_instruct === power_user.instruct.preset);
146}139}
147140
148/**141/**
@@ -159,13 +152,6 @@ export function selectContextPreset(preset, { quiet = false, isAuto = false } =
159 !quiet && toastr.info(`Context Template: "${preset}" ${isAuto ? 'auto-' : ''}selected`);152 !quiet && toastr.info(`Context Template: "${preset}" ${isAuto ? 'auto-' : ''}selected`);
160 }153 }
161154
162 // If instruct mode is disabled, enable it, except for default context template
163 if (!power_user.instruct.enabled && preset !== power_user.default_context) {
164 power_user.instruct.enabled = true;
165 $('#instruct_enabled').prop('checked', true).trigger('change');
166 !quiet && toastr.info('Instruct Mode enabled');
167 }
168
169 saveSettingsDebounced();155 saveSettingsDebounced();
170}156}
171157
@@ -235,13 +221,6 @@ export function autoSelectInstructPreset(modelId) {
235 }221 }
236 }222 }
237 }223 }
238
239 if (power_user.instruct.bind_to_context && power_user.default_instruct && power_user.instruct.preset !== power_user.default_instruct) {
240 if (instruct_presets.some(p => p.name === power_user.default_instruct)) {
241 console.log(`Instruct mode: default preset "${power_user.default_instruct}" selected`);
242 $('#instruct_presets').val(power_user.default_instruct).trigger('change');
243 }
244 }
245 }224 }
246225
247 return false;226 return false;
@@ -580,10 +559,6 @@ function selectMatchingContextTemplate(name) {
580 break;559 break;
581 }560 }
582 }561 }
583 if (!foundMatch) {
584 // If no match was found, select default context preset
585 selectContextPreset(power_user.default_context, { isAuto: true });
586 }
587}562}
588563
589/**564/**
@@ -597,9 +572,13 @@ export function replaceInstructMacros(input, env) {
597 if (!input) {572 if (!input) {
598 return '';573 return '';
599 }574 }
575
576 const syspromptMacros = {
577 'systemPrompt': (power_user.prefer_character_prompt && env.charPrompt ? env.charPrompt : power_user.sysprompt.content),
578 'defaultSystemPrompt|instructSystem|instructSystemPrompt': power_user.sysprompt.content,
579 };
580
600 const instructMacros = {581 const instructMacros = {
601 'systemPrompt': (power_user.prefer_character_prompt && env.charPrompt ? env.charPrompt : power_user.instruct.system_prompt),
602 'instructSystem|instructSystemPrompt': power_user.instruct.system_prompt,
603 'instructSystemPromptPrefix': power_user.instruct.system_sequence_prefix,582 'instructSystemPromptPrefix': power_user.instruct.system_sequence_prefix,
604 'instructSystemPromptSuffix': power_user.instruct.system_sequence_suffix,583 'instructSystemPromptSuffix': power_user.instruct.system_sequence_suffix,
605 'instructInput|instructUserPrefix': power_user.instruct.input_sequence,584 'instructInput|instructUserPrefix': power_user.instruct.input_sequence,
@@ -622,6 +601,11 @@ export function replaceInstructMacros(input, env) {
622 input = input.replace(regex, power_user.instruct.enabled ? value : '');601 input = input.replace(regex, power_user.instruct.enabled ? value : '');
623 }602 }
624603
604 for (const [placeholder, value] of Object.entries(syspromptMacros)) {
605 const regex = new RegExp(`{{(${placeholder})}}`, 'gi');
606 input = input.replace(regex, power_user.sysprompt.enabled ? value : '');
607 }
608
625 input = input.replace(/{{exampleSeparator}}/gi, power_user.context.example_separator);609 input = input.replace(/{{exampleSeparator}}/gi, power_user.context.example_separator);
626 input = input.replace(/{{chatStart}}/gi, power_user.context.chat_start);610 input = input.replace(/{{chatStart}}/gi, power_user.context.chat_start);
627611
@@ -629,20 +613,6 @@ export function replaceInstructMacros(input, env) {
629}613}
630614
631jQuery(() => {615jQuery(() => {
632 $('#instruct_set_default').on('click', function () {
633 if (power_user.instruct.preset === power_user.default_instruct) {
634 power_user.default_instruct = null;
635 $(this).removeClass('default');
636 toastr.info('Default instruct template cleared');
637 } else {
638 power_user.default_instruct = power_user.instruct.preset;
639 $(this).addClass('default');
640 toastr.info(`Default instruct template set to ${power_user.default_instruct}`);
641 }
642
643 saveSettingsDebounced();
644 });
645
646 $('#instruct_system_same_as_user').on('input', function () {616 $('#instruct_system_same_as_user').on('input', function () {
647 const state = !!$(this).prop('checked');617 const state = !!$(this).prop('checked');
648 if (state) {618 if (state) {
@@ -671,9 +641,6 @@ jQuery(() => {
671 // When instruct mode gets enabled, select context template matching selected instruct preset641 // When instruct mode gets enabled, select context template matching selected instruct preset
672 if (power_user.instruct.enabled) {642 if (power_user.instruct.enabled) {
673 selectMatchingContextTemplate(power_user.instruct.preset);643 selectMatchingContextTemplate(power_user.instruct.preset);
674 } else {
675 // When instruct mode gets disabled, select default context preset
676 selectContextPreset(power_user.default_context);
677 }644 }
678 });645 });
679646
@@ -699,9 +666,10 @@ jQuery(() => {
699666
700 if (control.isCheckbox) {667 if (control.isCheckbox) {
701 $element.prop('checked', power_user.instruct[control.property]).trigger('input');668 $element.prop('checked', power_user.instruct[control.property]).trigger('input');
702 } else if (control.property === 'names_behavior') {669 } else if ($element.is('select')) {
703 const behavior = power_user.instruct[control.property];670 const value = power_user.instruct[control.property];
704 $element.filter(`[value="${behavior}"]`).prop('checked', true).trigger('input');671 $element.val(value);
672 $element.filter(`[value="${value}"]`).prop('checked', true).trigger('input');
705 } else {673 } else {
706 $element.val(power_user.instruct[control.property]);674 $element.val(power_user.instruct[control.property]);
707 $element.trigger('input');675 $element.trigger('input');
@@ -713,7 +681,13 @@ jQuery(() => {
713 // Select matching context template681 // Select matching context template
714 selectMatchingContextTemplate(name);682 selectMatchingContextTemplate(name);
715 }683 }
684 });
716685
717 highlightDefaultPreset();686 if (!CSS.supports('field-sizing', 'content')) {
687 $('#InstructSequencesColumn details').on('toggle', function () {
688 if ($(this).prop('open')) {
689 resetScrollHeight($(this).find('textarea'));
690 }
718 });691 });
692 }
719});693});
public/scripts/nai-settings.js+60 -31
@@ -5,9 +5,7 @@ import {
5 novelai_setting_names,5 novelai_setting_names,
6 saveSettingsDebounced,6 saveSettingsDebounced,
7 setGenerationParamsFromPreset,7 setGenerationParamsFromPreset,
8 substituteParams,
9} from '../script.js';8} from '../script.js';
10import { getCfgPrompt } from './cfg-scale.js';
11import { MAX_CONTEXT_DEFAULT, MAX_RESPONSE_DEFAULT, power_user } from './power-user.js';9import { MAX_CONTEXT_DEFAULT, MAX_RESPONSE_DEFAULT, power_user } from './power-user.js';
12import { getTextTokens, tokenizers } from './tokenizers.js';10import { getTextTokens, tokenizers } from './tokenizers.js';
13import { getEventSourceStream } from './sse-stream.js';11import { getEventSourceStream } from './sse-stream.js';
@@ -24,6 +22,7 @@ const maximum_output_length = 150;
24const default_presets = {22const default_presets = {
25 'clio-v1': 'Talker-Chat-Clio',23 'clio-v1': 'Talker-Chat-Clio',
26 'kayra-v1': 'Carefree-Kayra',24 'kayra-v1': 'Carefree-Kayra',
25 'llama-3-erato-v1': 'Erato-Dragonfruit',
27};26};
2827
29export const nai_settings = {28export const nai_settings = {
@@ -48,7 +47,6 @@ export const nai_settings = {
48 streaming_novel: false,47 streaming_novel: false,
49 preamble: default_preamble,48 preamble: default_preamble,
50 prefix: '',49 prefix: '',
51 cfg_uc: '',
52 banned_tokens: '',50 banned_tokens: '',
53 order: default_order,51 order: default_order,
54 logit_bias: [],52 logit_bias: [],
@@ -61,9 +59,22 @@ const nai_tiers = {
61 3: 'Opus',59 3: 'Opus',
62};60};
6361
62const samplers = {
63 temperature: 0,
64 top_k: 1,
65 top_p: 2,
66 tfs: 3,
67 top_a: 4,
68 typical_p: 5,
69 // removed samplers were here
70 mirostat: 8,
71 math1: 9,
72 min_p: 10,
73};
74
64let novel_data = null;75let novel_data = null;
65let badWordsCache = {};76let badWordsCache = {};
66const BIAS_KEY = '#novel_api-settings';77const BIAS_KEY = '#range_block_novel';
6778
68export function setNovelData(data) {79export function setNovelData(data) {
69 novel_data = data;80 novel_data = data;
@@ -95,6 +106,37 @@ export function getKayraMaxResponseTokens() {
95 return maximum_output_length;106 return maximum_output_length;
96}107}
97108
109export function convertNovelPreset(data) {
110 if (!data || typeof data !== 'object' || data.presetVersion !== 3 || !data.parameters || typeof data.parameters !== 'object') {
111 return data;
112 }
113
114 return {
115 max_context: 8000,
116 temperature: data.parameters.temperature,
117 max_length: data.parameters.max_length,
118 min_length: data.parameters.min_length,
119 top_k: data.parameters.top_k,
120 top_p: data.parameters.top_p,
121 top_a: data.parameters.top_a,
122 typical_p: data.parameters.typical_p,
123 tail_free_sampling: data.parameters.tail_free_sampling,
124 repetition_penalty: data.parameters.repetition_penalty,
125 repetition_penalty_range: data.parameters.repetition_penalty_range,
126 repetition_penalty_slope: data.parameters.repetition_penalty_slope,
127 repetition_penalty_frequency: data.parameters.repetition_penalty_frequency,
128 repetition_penalty_presence: data.parameters.repetition_penalty_presence,
129 phrase_rep_pen: data.parameters.phrase_rep_pen,
130 mirostat_lr: data.parameters.mirostat_lr,
131 mirostat_tau: data.parameters.mirostat_tau,
132 math1_temp: data.parameters.math1_temp,
133 math1_quad: data.parameters.math1_quad,
134 math1_quad_entropy_scale: data.parameters.math1_quad_entropy_scale,
135 min_p: data.parameters.min_p,
136 order: Array.isArray(data.parameters.order) ? data.parameters.order.filter(s => s.enabled && Object.keys(samplers).includes(s.id)).map(s => samplers[s.id]) : default_order,
137 };
138}
139
98export function getNovelTier() {140export function getNovelTier() {
99 return nai_tiers[novel_data?.tier] ?? 'no_connection';141 return nai_tiers[novel_data?.tier] ?? 'no_connection';
100}142}
@@ -145,12 +187,10 @@ export function loadNovelPreset(preset) {
145 nai_settings.top_a = preset.top_a;187 nai_settings.top_a = preset.top_a;
146 nai_settings.typical_p = preset.typical_p;188 nai_settings.typical_p = preset.typical_p;
147 nai_settings.min_length = preset.min_length;189 nai_settings.min_length = preset.min_length;
148 nai_settings.cfg_scale = preset.cfg_scale;
149 nai_settings.phrase_rep_pen = preset.phrase_rep_pen;190 nai_settings.phrase_rep_pen = preset.phrase_rep_pen;
150 nai_settings.mirostat_lr = preset.mirostat_lr;191 nai_settings.mirostat_lr = preset.mirostat_lr;
151 nai_settings.mirostat_tau = preset.mirostat_tau;192 nai_settings.mirostat_tau = preset.mirostat_tau;
152 nai_settings.prefix = preset.prefix;193 nai_settings.prefix = preset.prefix;
153 nai_settings.cfg_uc = preset.cfg_uc || '';
154 nai_settings.banned_tokens = preset.banned_tokens || '';194 nai_settings.banned_tokens = preset.banned_tokens || '';
155 nai_settings.order = preset.order || default_order;195 nai_settings.order = preset.order || default_order;
156 nai_settings.logit_bias = preset.logit_bias || [];196 nai_settings.logit_bias = preset.logit_bias || [];
@@ -186,13 +226,11 @@ export function loadNovelSettings(settings) {
186 nai_settings.typical_p = settings.typical_p;226 nai_settings.typical_p = settings.typical_p;
187 nai_settings.min_length = settings.min_length;227 nai_settings.min_length = settings.min_length;
188 nai_settings.phrase_rep_pen = settings.phrase_rep_pen;228 nai_settings.phrase_rep_pen = settings.phrase_rep_pen;
189 nai_settings.cfg_scale = settings.cfg_scale;
190 nai_settings.mirostat_lr = settings.mirostat_lr;229 nai_settings.mirostat_lr = settings.mirostat_lr;
191 nai_settings.mirostat_tau = settings.mirostat_tau;230 nai_settings.mirostat_tau = settings.mirostat_tau;
192 nai_settings.streaming_novel = !!settings.streaming_novel;231 nai_settings.streaming_novel = !!settings.streaming_novel;
193 nai_settings.preamble = settings.preamble || default_preamble;232 nai_settings.preamble = settings.preamble || default_preamble;
194 nai_settings.prefix = settings.prefix;233 nai_settings.prefix = settings.prefix;
195 nai_settings.cfg_uc = settings.cfg_uc || '';
196 nai_settings.banned_tokens = settings.banned_tokens || '';234 nai_settings.banned_tokens = settings.banned_tokens || '';
197 nai_settings.order = settings.order || default_order;235 nai_settings.order = settings.order || default_order;
198 nai_settings.logit_bias = settings.logit_bias || [];236 nai_settings.logit_bias = settings.logit_bias || [];
@@ -226,8 +264,6 @@ function loadNovelSettingsUi(ui_settings) {
226 $('#top_a_counter_novel').val(Number(ui_settings.top_a).toFixed(3));264 $('#top_a_counter_novel').val(Number(ui_settings.top_a).toFixed(3));
227 $('#typical_p_novel').val(ui_settings.typical_p);265 $('#typical_p_novel').val(ui_settings.typical_p);
228 $('#typical_p_counter_novel').val(Number(ui_settings.typical_p).toFixed(3));266 $('#typical_p_counter_novel').val(Number(ui_settings.typical_p).toFixed(3));
229 $('#cfg_scale_novel').val(ui_settings.cfg_scale);
230 $('#cfg_scale_counter_novel').val(Number(ui_settings.cfg_scale).toFixed(2));
231 $('#phrase_rep_pen_novel').val(ui_settings.phrase_rep_pen || 'off');267 $('#phrase_rep_pen_novel').val(ui_settings.phrase_rep_pen || 'off');
232 $('#mirostat_lr_novel').val(ui_settings.mirostat_lr);268 $('#mirostat_lr_novel').val(ui_settings.mirostat_lr);
233 $('#mirostat_lr_counter_novel').val(Number(ui_settings.mirostat_lr).toFixed(2));269 $('#mirostat_lr_counter_novel').val(Number(ui_settings.mirostat_lr).toFixed(2));
@@ -237,7 +273,6 @@ function loadNovelSettingsUi(ui_settings) {
237 $('#min_length_counter_novel').val(Number(ui_settings.min_length).toFixed(0));273 $('#min_length_counter_novel').val(Number(ui_settings.min_length).toFixed(0));
238 $('#nai_preamble_textarea').val(ui_settings.preamble);274 $('#nai_preamble_textarea').val(ui_settings.preamble);
239 $('#nai_prefix').val(ui_settings.prefix || 'vanilla');275 $('#nai_prefix').val(ui_settings.prefix || 'vanilla');
240 $('#nai_cfg_uc').val(ui_settings.cfg_uc || '');
241 $('#nai_banned_tokens').val(ui_settings.banned_tokens || '');276 $('#nai_banned_tokens').val(ui_settings.banned_tokens || '');
242 $('#min_p_novel').val(ui_settings.min_p);277 $('#min_p_novel').val(ui_settings.min_p);
243 $('#min_p_counter_novel').val(Number(ui_settings.min_p).toFixed(3));278 $('#min_p_counter_novel').val(Number(ui_settings.min_p).toFixed(3));
@@ -333,24 +368,12 @@ const sliders = [
333 setValue: (val) => { nai_settings.mirostat_lr = Number(val).toFixed(2); },368 setValue: (val) => { nai_settings.mirostat_lr = Number(val).toFixed(2); },
334 },369 },
335 {370 {
336 sliderId: '#cfg_scale_novel',
337 counterId: '#cfg_scale_counter_novel',
338 format: (val) => `${val}`,
339 setValue: (val) => { nai_settings.cfg_scale = Number(val).toFixed(2); },
340 },
341 {
342 sliderId: '#min_length_novel',371 sliderId: '#min_length_novel',
343 counterId: '#min_length_counter_novel',372 counterId: '#min_length_counter_novel',
344 format: (val) => `${val}`,373 format: (val) => `${val}`,
345 setValue: (val) => { nai_settings.min_length = Number(val).toFixed(0); },374 setValue: (val) => { nai_settings.min_length = Number(val).toFixed(0); },
346 },375 },
347 {376 {
348 sliderId: '#nai_cfg_uc',
349 counterId: '#nai_cfg_uc_counter',
350 format: (val) => val,
351 setValue: (val) => { nai_settings.cfg_uc = val; },
352 },
353 {
354 sliderId: '#nai_banned_tokens',377 sliderId: '#nai_banned_tokens',
355 counterId: '#nai_banned_tokens_counter',378 counterId: '#nai_banned_tokens_counter',
356 format: (val) => val,379 format: (val) => val,
@@ -467,11 +490,8 @@ function getBadWordPermutations(text) {
467 return result.filter(onlyUnique);490 return result.filter(onlyUnique);
468}491}
469492
470export function getNovelGenerationData(finalPrompt, settings, maxLength, isImpersonate, isContinue, cfgValues, type) {493export function getNovelGenerationData(finalPrompt, settings, maxLength, isImpersonate, isContinue, _cfgValues, type) {
471 console.debug('NovelAI generation data for', type);494 console.debug('NovelAI generation data for', type);
472 if (cfgValues && cfgValues.guidanceScale && cfgValues.guidanceScale?.value !== 1) {
473 cfgValues.negativePrompt = (getCfgPrompt(cfgValues.guidanceScale, true))?.value;
474 }
475495
476 const tokenizerType = getTokenizerTypeForModel(nai_settings.model_novel);496 const tokenizerType = getTokenizerTypeForModel(nai_settings.model_novel);
477 const stopSequences = (tokenizerType !== tokenizers.NONE)497 const stopSequences = (tokenizerType !== tokenizers.NONE)
@@ -495,7 +515,14 @@ export function getNovelGenerationData(finalPrompt, settings, maxLength, isImper
495 console.log(finalPrompt);515 console.log(finalPrompt);
496 }516 }
497517
498 const adjustedMaxLength = nai_settings.model_novel.includes('kayra') ? getKayraMaxResponseTokens() : maximum_output_length;518 const isKayra = nai_settings.model_novel.includes('kayra');
519 const isErato = nai_settings.model_novel.includes('erato');
520
521 if (isErato) {
522 finalPrompt = '<|startoftext|>' + finalPrompt;
523 }
524
525 const adjustedMaxLength = (isKayra || isErato) ? getKayraMaxResponseTokens() : maximum_output_length;
499526
500 return {527 return {
501 'input': finalPrompt,528 'input': finalPrompt,
@@ -520,8 +547,6 @@ export function getNovelGenerationData(finalPrompt, settings, maxLength, isImper
520 'typical_p': Number(nai_settings.typical_p),547 'typical_p': Number(nai_settings.typical_p),
521 'mirostat_lr': Number(nai_settings.mirostat_lr),548 'mirostat_lr': Number(nai_settings.mirostat_lr),
522 'mirostat_tau': Number(nai_settings.mirostat_tau),549 'mirostat_tau': Number(nai_settings.mirostat_tau),
523 'cfg_scale': cfgValues?.guidanceScale?.value ?? Number(nai_settings.cfg_scale),
524 'cfg_uc': cfgValues?.negativePrompt ?? substituteParams(nai_settings.cfg_uc) ?? '',
525 'phrase_rep_pen': nai_settings.phrase_rep_pen,550 'phrase_rep_pen': nai_settings.phrase_rep_pen,
526 'stop_sequences': stopSequences,551 'stop_sequences': stopSequences,
527 'bad_words_ids': badWordIds,552 'bad_words_ids': badWordIds,
@@ -540,7 +565,8 @@ function selectPrefix(selected_prefix, finalPrompt) {
540 let useInstruct = false;565 let useInstruct = false;
541 const clio = nai_settings.model_novel.includes('clio');566 const clio = nai_settings.model_novel.includes('clio');
542 const kayra = nai_settings.model_novel.includes('kayra');567 const kayra = nai_settings.model_novel.includes('kayra');
543 const isNewModel = clio || kayra;568 const erato = nai_settings.model_novel.includes('erato');
569 const isNewModel = clio || kayra || erato;
544570
545 if (isNewModel) {571 if (isNewModel) {
546 // NovelAI claims they scan backwards 1000 characters (not tokens!) to look for instruct brackets. That's really short.572 // NovelAI claims they scan backwards 1000 characters (not tokens!) to look for instruct brackets. That's really short.
@@ -559,6 +585,9 @@ function getTokenizerTypeForModel(model) {
559 if (model.includes('kayra')) {585 if (model.includes('kayra')) {
560 return tokenizers.NERD2;586 return tokenizers.NERD2;
561 }587 }
588 if (model.includes('erato')) {
589 return tokenizers.LLAMA3;
590 }
562 return tokenizers.NONE;591 return tokenizers.NONE;
563}592}
564593
public/scripts/openai.js+12 -139
@@ -61,12 +61,6 @@ import {
61 stringFormat,61 stringFormat,
62} from './utils.js';62} from './utils.js';
63import { countTokensOpenAI, getTokenizerModel } from './tokenizers.js';63import { countTokensOpenAI, getTokenizerModel } from './tokenizers.js';
64import {
65 formatInstructModeChat,
66 formatInstructModeExamples,
67 formatInstructModePrompt,
68 formatInstructModeSystemPrompt,
69} from './instruct-mode.js';
70import { isMobile } from './RossAscends-mods.js';64import { isMobile } from './RossAscends-mods.js';
71import { saveLogprobsForActiveMessage } from './logprobs.js';65import { saveLogprobsForActiveMessage } from './logprobs.js';
72import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';66import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
@@ -263,7 +257,6 @@ const default_settings = {
263 windowai_model: '',257 windowai_model: '',
264 openrouter_model: openrouter_website_model,258 openrouter_model: openrouter_website_model,
265 openrouter_use_fallback: false,259 openrouter_use_fallback: false,
266 openrouter_force_instruct: false,
267 openrouter_group_models: false,260 openrouter_group_models: false,
268 openrouter_sort_models: 'alphabetically',261 openrouter_sort_models: 'alphabetically',
269 openrouter_providers: [],262 openrouter_providers: [],
@@ -341,7 +334,6 @@ const oai_settings = {
341 windowai_model: '',334 windowai_model: '',
342 openrouter_model: openrouter_website_model,335 openrouter_model: openrouter_website_model,
343 openrouter_use_fallback: false,336 openrouter_use_fallback: false,
344 openrouter_force_instruct: false,
345 openrouter_group_models: false,337 openrouter_group_models: false,
346 openrouter_sort_models: 'alphabetically',338 openrouter_sort_models: 'alphabetically',
347 openrouter_providers: [],339 openrouter_providers: [],
@@ -417,108 +409,6 @@ async function validateReverseProxy() {
417}409}
418410
419/**411/**
420 * Converts the Chat Completion object to an Instruct Mode prompt string.
421 * @param {object[]} messages Array of messages
422 * @param {string} type Generation type
423 * @returns {string} Text completion prompt
424 */
425function convertChatCompletionToInstruct(messages, type) {
426 const newChatPrompts = [
427 substituteParams(oai_settings.new_chat_prompt),
428 substituteParams(oai_settings.new_example_chat_prompt),
429 substituteParams(oai_settings.new_group_chat_prompt),
430 ];
431 messages = messages.filter(x => !newChatPrompts.includes(x.content));
432
433 let chatMessagesText = '';
434 let systemPromptText = '';
435 let examplesText = '';
436
437 function getPrefix(message) {
438 let prefix;
439
440 if (message.role === 'user' || message.name === 'example_user') {
441 if (selected_group) {
442 prefix = '';
443 } else if (message.name === 'example_user') {
444 prefix = name1;
445 } else {
446 prefix = message.name ?? name1;
447 }
448 }
449
450 if (message.role === 'assistant' || message.name === 'example_assistant') {
451 if (selected_group) {
452 prefix = '';
453 }
454 else if (message.name === 'example_assistant') {
455 prefix = name2;
456 } else {
457 prefix = message.name ?? name2;
458 }
459 }
460
461 return prefix;
462 }
463
464 function toString(message) {
465 if (message.role === 'system' && !message.name) {
466 return message.content;
467 }
468
469 const prefix = getPrefix(message);
470 return prefix ? `${prefix}: ${message.content}` : message.content;
471 }
472
473 const firstChatMessage = messages.findIndex(message => message.role === 'assistant' || message.role === 'user');
474 const systemPromptMessages = messages.slice(0, firstChatMessage).filter(message => message.role === 'system' && !message.name);
475
476 if (systemPromptMessages.length) {
477 systemPromptText = systemPromptMessages.map(message => message.content).join('\n');
478 systemPromptText = formatInstructModeSystemPrompt(systemPromptText);
479 }
480
481 const exampleMessages = messages.filter(x => x.role === 'system' && (x.name === 'example_user' || x.name === 'example_assistant'));
482
483 if (exampleMessages.length) {
484 const blockHeading = power_user.context.example_separator ? (substituteParams(power_user.context.example_separator) + '\n') : '';
485 const examplesArray = exampleMessages.map(m => '<START>\n' + toString(m));
486 examplesText = blockHeading + formatInstructModeExamples(examplesArray, name1, name2).join('');
487 }
488
489 const chatMessages = messages.slice(firstChatMessage);
490
491 if (chatMessages.length) {
492 chatMessagesText = substituteParams(power_user.context.chat_start) + '\n';
493
494 for (const message of chatMessages) {
495 const name = getPrefix(message);
496 const isUser = message.role === 'user';
497 const isNarrator = message.role === 'system';
498 chatMessagesText += formatInstructModeChat(name, message.content, isUser, isNarrator, '', name1, name2, false);
499 }
500 }
501
502 const isImpersonate = type === 'impersonate';
503 const isContinue = type === 'continue';
504 const isQuiet = type === 'quiet';
505 const isQuietToLoud = false; // Quiet to loud not implemented for Chat Completion
506 const promptName = isImpersonate ? name1 : name2;
507 const promptLine = isContinue ? '' : formatInstructModePrompt(promptName, isImpersonate, '', name1, name2, isQuiet, isQuietToLoud).trimStart();
508
509 let prompt = [systemPromptText, examplesText, chatMessagesText, promptLine]
510 .filter(x => x)
511 .map(x => x.endsWith('\n') ? x : `${x}\n`)
512 .join('');
513
514 if (isContinue) {
515 prompt = prompt.replace(/\n$/, '');
516 }
517
518 return prompt;
519}
520
521/**
522 * Formats chat messages into chat completion messages.412 * Formats chat messages into chat completion messages.
523 * @param {object[]} chat - Array containing all messages.413 * @param {object[]} chat - Array containing all messages.
524 * @returns {object[]} - Array containing all messages formatted for chat completion.414 * @returns {object[]} - Array containing all messages formatted for chat completion.
@@ -761,10 +651,6 @@ function populationInjectionPrompts(prompts, messages) {
761 return messages;651 return messages;
762}652}
763653
764export function isOpenRouterWithInstruct() {
765 return oai_settings.chat_completion_source === chat_completion_sources.OPENROUTER && oai_settings.openrouter_force_instruct && power_user.instruct.enabled;
766}
767
768/**654/**
769 * Populates the chat history of the conversation.655 * Populates the chat history of the conversation.
770 * @param {object[]} messages - Array containing all messages.656 * @param {object[]} messages - Array containing all messages.
@@ -795,8 +681,7 @@ async function populateChatHistory(messages, prompts, chatCompletion, type = nul
795681
796 // Reserve budget for continue nudge682 // Reserve budget for continue nudge
797 let continueMessage = null;683 let continueMessage = null;
798 const instruct = isOpenRouterWithInstruct();684 if (type === 'continue' && cyclePrompt && !oai_settings.continue_prefill) {
799 if (type === 'continue' && cyclePrompt && !instruct && !oai_settings.continue_prefill) {
800 const promptObject = {685 const promptObject = {
801 identifier: 'continueNudge',686 identifier: 'continueNudge',
802 role: 'system',687 role: 'system',
@@ -1811,7 +1696,7 @@ async function sendOpenAIRequest(type, messages, signal) {
1811 const isPerplexity = oai_settings.chat_completion_source == chat_completion_sources.PERPLEXITY;1696 const isPerplexity = oai_settings.chat_completion_source == chat_completion_sources.PERPLEXITY;
1812 const isGroq = oai_settings.chat_completion_source == chat_completion_sources.GROQ;1697 const isGroq = oai_settings.chat_completion_source == chat_completion_sources.GROQ;
1813 const is01AI = oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI;1698 const is01AI = oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI;
1814 const isTextCompletion = (isOAI && textCompletionModels.includes(oai_settings.openai_model)) || (isOpenRouter && oai_settings.openrouter_force_instruct && power_user.instruct.enabled);1699 const isTextCompletion = isOAI && textCompletionModels.includes(oai_settings.openai_model);
1815 const isQuiet = type === 'quiet';1700 const isQuiet = type === 'quiet';
1816 const isImpersonate = type === 'impersonate';1701 const isImpersonate = type === 'impersonate';
1817 const isContinue = type === 'continue';1702 const isContinue = type === 'continue';
@@ -1819,11 +1704,6 @@ async function sendOpenAIRequest(type, messages, signal) {
1819 const useLogprobs = !!power_user.request_token_probabilities;1704 const useLogprobs = !!power_user.request_token_probabilities;
1820 const canMultiSwipe = oai_settings.n > 1 && !isContinue && !isImpersonate && !isQuiet && (isOAI || isCustom);1705 const canMultiSwipe = oai_settings.n > 1 && !isContinue && !isImpersonate && !isQuiet && (isOAI || isCustom);
18211706
1822 if (isTextCompletion && isOpenRouter) {
1823 messages = convertChatCompletionToInstruct(messages, type);
1824 replaceItemizedPromptText(messageId, messages);
1825 }
1826
1827 // If we're using the window.ai extension, use that instead1707 // If we're using the window.ai extension, use that instead
1828 // Doesn't support logit bias yet1708 // Doesn't support logit bias yet
1829 if (oai_settings.chat_completion_source == chat_completion_sources.WINDOWAI) {1709 if (oai_settings.chat_completion_source == chat_completion_sources.WINDOWAI) {
@@ -1915,10 +1795,9 @@ async function sendOpenAIRequest(type, messages, signal) {
1915 }1795 }
19161796
1917 if (isGoogle) {1797 if (isGoogle) {
1918 const nameStopString = isImpersonate ? `\n${name2}:` : `\n${name1}:`;1798 const stopStringsLimit = 5;
1919 const stopStringsLimit = 3; // 5 - 2 (nameStopString and new_chat_prompt)
1920 generate_data['top_k'] = Number(oai_settings.top_k_openai);1799 generate_data['top_k'] = Number(oai_settings.top_k_openai);
1921 generate_data['stop'] = [nameStopString, substituteParams(oai_settings.new_chat_prompt), ...getCustomStoppingStrings(stopStringsLimit)];1800 generate_data['stop'] = getCustomStoppingStrings(stopStringsLimit).slice(0, stopStringsLimit).filter(x => x.length >= 1 && x.length <= 16);
1922 generate_data['use_makersuite_sysprompt'] = oai_settings.use_makersuite_sysprompt;1801 generate_data['use_makersuite_sysprompt'] = oai_settings.use_makersuite_sysprompt;
1923 }1802 }
19241803
@@ -3063,7 +2942,6 @@ function loadOpenAISettings(data, settings) {
3063 oai_settings.openrouter_group_models = settings.openrouter_group_models ?? default_settings.openrouter_group_models;2942 oai_settings.openrouter_group_models = settings.openrouter_group_models ?? default_settings.openrouter_group_models;
3064 oai_settings.openrouter_sort_models = settings.openrouter_sort_models ?? default_settings.openrouter_sort_models;2943 oai_settings.openrouter_sort_models = settings.openrouter_sort_models ?? default_settings.openrouter_sort_models;
3065 oai_settings.openrouter_use_fallback = settings.openrouter_use_fallback ?? default_settings.openrouter_use_fallback;2944 oai_settings.openrouter_use_fallback = settings.openrouter_use_fallback ?? default_settings.openrouter_use_fallback;
3066 oai_settings.openrouter_force_instruct = settings.openrouter_force_instruct ?? default_settings.openrouter_force_instruct;
3067 oai_settings.openrouter_allow_fallbacks = settings.openrouter_allow_fallbacks ?? default_settings.openrouter_allow_fallbacks;2945 oai_settings.openrouter_allow_fallbacks = settings.openrouter_allow_fallbacks ?? default_settings.openrouter_allow_fallbacks;
3068 oai_settings.ai21_model = settings.ai21_model ?? default_settings.ai21_model;2946 oai_settings.ai21_model = settings.ai21_model ?? default_settings.ai21_model;
3069 oai_settings.mistralai_model = settings.mistralai_model ?? default_settings.mistralai_model;2947 oai_settings.mistralai_model = settings.mistralai_model ?? default_settings.mistralai_model;
@@ -3170,7 +3048,6 @@ function loadOpenAISettings(data, settings) {
3170 $('#use_makersuite_sysprompt').prop('checked', oai_settings.use_makersuite_sysprompt);3048 $('#use_makersuite_sysprompt').prop('checked', oai_settings.use_makersuite_sysprompt);
3171 $('#scale-alt').prop('checked', oai_settings.use_alt_scale);3049 $('#scale-alt').prop('checked', oai_settings.use_alt_scale);
3172 $('#openrouter_use_fallback').prop('checked', oai_settings.openrouter_use_fallback);3050 $('#openrouter_use_fallback').prop('checked', oai_settings.openrouter_use_fallback);
3173 $('#openrouter_force_instruct').prop('checked', oai_settings.openrouter_force_instruct);
3174 $('#openrouter_group_models').prop('checked', oai_settings.openrouter_group_models);3051 $('#openrouter_group_models').prop('checked', oai_settings.openrouter_group_models);
3175 $('#openrouter_allow_fallbacks').prop('checked', oai_settings.openrouter_allow_fallbacks);3052 $('#openrouter_allow_fallbacks').prop('checked', oai_settings.openrouter_allow_fallbacks);
3176 $('#openrouter_providers_chat').val(oai_settings.openrouter_providers).trigger('change');3053 $('#openrouter_providers_chat').val(oai_settings.openrouter_providers).trigger('change');
@@ -3398,7 +3275,6 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) {
3398 windowai_model: settings.windowai_model,3275 windowai_model: settings.windowai_model,
3399 openrouter_model: settings.openrouter_model,3276 openrouter_model: settings.openrouter_model,
3400 openrouter_use_fallback: settings.openrouter_use_fallback,3277 openrouter_use_fallback: settings.openrouter_use_fallback,
3401 openrouter_force_instruct: settings.openrouter_force_instruct,
3402 openrouter_group_models: settings.openrouter_group_models,3278 openrouter_group_models: settings.openrouter_group_models,
3403 openrouter_sort_models: settings.openrouter_sort_models,3279 openrouter_sort_models: settings.openrouter_sort_models,
3404 openrouter_providers: settings.openrouter_providers,3280 openrouter_providers: settings.openrouter_providers,
@@ -3835,7 +3711,6 @@ function onSettingsPresetChange() {
3835 windowai_model: ['#model_windowai_select', 'windowai_model', false],3711 windowai_model: ['#model_windowai_select', 'windowai_model', false],
3836 openrouter_model: ['#model_openrouter_select', 'openrouter_model', false],3712 openrouter_model: ['#model_openrouter_select', 'openrouter_model', false],
3837 openrouter_use_fallback: ['#openrouter_use_fallback', 'openrouter_use_fallback', true],3713 openrouter_use_fallback: ['#openrouter_use_fallback', 'openrouter_use_fallback', true],
3838 openrouter_force_instruct: ['#openrouter_force_instruct', 'openrouter_force_instruct', true],
3839 openrouter_group_models: ['#openrouter_group_models', 'openrouter_group_models', false],3714 openrouter_group_models: ['#openrouter_group_models', 'openrouter_group_models', false],
3840 openrouter_sort_models: ['#openrouter_sort_models', 'openrouter_sort_models', false],3715 openrouter_sort_models: ['#openrouter_sort_models', 'openrouter_sort_models', false],
3841 openrouter_providers: ['#openrouter_providers_chat', 'openrouter_providers', false],3716 openrouter_providers: ['#openrouter_providers_chat', 'openrouter_providers', false],
@@ -4128,6 +4003,8 @@ async function onModelChange() {
4128 $('#openai_max_context').attr('max', max_2mil);4003 $('#openai_max_context').attr('max', max_2mil);
4129 } else if (value.includes('gemini-1.5-pro')) {4004 } else if (value.includes('gemini-1.5-pro')) {
4130 $('#openai_max_context').attr('max', max_2mil);4005 $('#openai_max_context').attr('max', max_2mil);
4006 } else if (value.match('gemini-1.5-flash-002')) {
4007 $('#openai_max_context').attr('max', max_2mil);
4131 } else if (value.includes('gemini-1.5-flash')) {4008 } else if (value.includes('gemini-1.5-flash')) {
4132 $('#openai_max_context').attr('max', max_1mil);4009 $('#openai_max_context').attr('max', max_1mil);
4133 } else if (value.includes('gemini-1.0-pro-vision') || value === 'gemini-pro-vision') {4010 } else if (value.includes('gemini-1.0-pro-vision') || value === 'gemini-pro-vision') {
@@ -4774,12 +4651,15 @@ export function isImageInliningSupported() {
4774 'gemini-1.5-flash',4651 'gemini-1.5-flash',
4775 'gemini-1.5-flash-latest',4652 'gemini-1.5-flash-latest',
4776 'gemini-1.5-flash-001',4653 'gemini-1.5-flash-001',
4654 'gemini-1.5-flash-002',
4777 'gemini-1.5-flash-exp-0827',4655 'gemini-1.5-flash-exp-0827',
4778 'gemini-1.5-flash-8b-exp-0827',4656 'gemini-1.5-flash-8b-exp-0827',
4657 'gemini-1.5-flash-8b-exp-0924',
4779 'gemini-1.0-pro-vision-latest',4658 'gemini-1.0-pro-vision-latest',
4780 'gemini-1.5-pro',4659 'gemini-1.5-pro',
4781 'gemini-1.5-pro-latest',4660 'gemini-1.5-pro-latest',
4782 'gemini-1.5-pro-001',4661 'gemini-1.5-pro-001',
4662 'gemini-1.5-pro-002',
4783 'gemini-1.5-pro-exp-0801',4663 'gemini-1.5-pro-exp-0801',
4784 'gemini-1.5-pro-exp-0827',4664 'gemini-1.5-pro-exp-0827',
4785 'gemini-pro-vision',4665 'gemini-pro-vision',
@@ -4802,7 +4682,7 @@ export function isImageInliningSupported() {
4802 case chat_completion_sources.CLAUDE:4682 case chat_completion_sources.CLAUDE:
4803 return visionSupportedModels.some(model => oai_settings.claude_model.includes(model));4683 return visionSupportedModels.some(model => oai_settings.claude_model.includes(model));
4804 case chat_completion_sources.OPENROUTER:4684 case chat_completion_sources.OPENROUTER:
4805 return !oai_settings.openrouter_force_instruct;4685 return true;
4806 case chat_completion_sources.CUSTOM:4686 case chat_completion_sources.CUSTOM:
4807 return true;4687 return true;
4808 case chat_completion_sources.ZEROONEAI:4688 case chat_completion_sources.ZEROONEAI:
@@ -4937,7 +4817,7 @@ function runProxyCallback(_, value) {
4937 return foundName;4817 return foundName;
4938}4818}
49394819
4940export function initOpenai() {4820export function initOpenAI() {
4941 SlashCommandParser.addCommandObject(SlashCommand.fromProps({4821 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
4942 name: 'proxy',4822 name: 'proxy',
4943 callback: runProxyCallback,4823 callback: runProxyCallback,
@@ -4953,9 +4833,7 @@ export function initOpenai() {
4953 ],4833 ],
4954 helpString: 'Sets a proxy preset by name.',4834 helpString: 'Sets a proxy preset by name.',
4955 }));4835 }));
4956}
49574836
4958$(document).ready(async function () {
4959 $('#test_api_button').on('click', testApiConnection);4837 $('#test_api_button').on('click', testApiConnection);
49604838
4961 $('#scale-alt').on('change', function () {4839 $('#scale-alt').on('change', function () {
@@ -5226,11 +5104,6 @@ $(document).ready(async function () {
5226 saveSettingsDebounced();5104 saveSettingsDebounced();
5227 });5105 });
52285106
5229 $('#openrouter_force_instruct').on('input', function () {
5230 oai_settings.openrouter_force_instruct = !!$(this).prop('checked');
5231 saveSettingsDebounced();
5232 });
5233
5234 $('#openrouter_group_models').on('input', function () {5107 $('#openrouter_group_models').on('input', function () {
5235 oai_settings.openrouter_group_models = !!$(this).prop('checked');5108 oai_settings.openrouter_group_models = !!$(this).prop('checked');
5236 saveSettingsDebounced();5109 saveSettingsDebounced();
@@ -5419,4 +5292,4 @@ $(document).ready(async function () {
5419 $('#openai_proxy_password_show').on('click', onProxyPasswordShowClick);5292 $('#openai_proxy_password_show').on('click', onProxyPasswordShowClick);
5420 $('#customize_additional_parameters').on('click', onCustomizeParametersClick);5293 $('#customize_additional_parameters').on('click', onCustomizeParametersClick);
5421 $('#openai_proxy_preset').on('change', onProxyPresetChange);5294 $('#openai_proxy_preset').on('change', onProxyPresetChange);
5422});5295}
public/scripts/power-user.js+8 -40
@@ -50,6 +50,7 @@ import { AUTOCOMPLETE_SELECT_KEY, AUTOCOMPLETE_WIDTH } from './autocomplete/Auto
50import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js';50import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js';
51import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js';51import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js';
52import { POPUP_TYPE, callGenericPopup } from './popup.js';52import { POPUP_TYPE, callGenericPopup } from './popup.js';
53import { loadSystemPrompts } from './sysprompt.js';
5354
54export {55export {
55 loadPowerUserSettings,56 loadPowerUserSettings,
@@ -114,7 +115,6 @@ let power_user = {
114 pin_examples: false,115 pin_examples: false,
115 strip_examples: false,116 strip_examples: false,
116 trim_sentences: false,117 trim_sentences: false,
117 include_newline: false,
118 always_force_name2: false,118 always_force_name2: false,
119 user_prompt_bias: '',119 user_prompt_bias: '',
120 show_user_prompt_bias: true,120 show_user_prompt_bias: true,
@@ -206,11 +206,9 @@ let power_user = {
206 disable_group_trimming: false,206 disable_group_trimming: false,
207 single_line: false,207 single_line: false,
208208
209 default_instruct: '',
210 instruct: {209 instruct: {
211 enabled: false,210 enabled: false,
212 preset: 'Alpaca',211 preset: 'Alpaca',
213 system_prompt: 'Below is an instruction that describes a task. Write a response that appropriately completes the request.\n\nWrite {{char}}\'s next reply in a fictional roleplay chat between {{user}} and {{char}}.\n',
214 input_sequence: '### Instruction:',212 input_sequence: '### Instruction:',
215 input_suffix: '',213 input_suffix: '',
216 output_sequence: '### Response:',214 output_sequence: '### Response:',
@@ -234,7 +232,6 @@ let power_user = {
234 separator_sequence: '',232 separator_sequence: '',
235 },233 },
236234
237 default_context: 'Default',
238 context: {235 context: {
239 preset: 'Default',236 preset: 'Default',
240 story_string: defaultStoryString,237 story_string: defaultStoryString,
@@ -245,6 +242,12 @@ let power_user = {
245 names_as_stop_strings: true,242 names_as_stop_strings: true,
246 },243 },
247244
245 sysprompt: {
246 enabled: true,
247 name: 'Neutral - Chat',
248 content: 'Write {{char}}\'s next reply in a fictional chat between {{char}} and {{user}}.',
249 },
250
248 personas: {},251 personas: {},
249 default_persona: null,252 default_persona: null,
250 persona_descriptions: {},253 persona_descriptions: {},
@@ -317,7 +320,6 @@ const contextControls = [
317 // Existing power user settings320 // Existing power user settings
318 { id: 'always-force-name2-checkbox', property: 'always_force_name2', isCheckbox: true, isGlobalSetting: true, defaultValue: true },321 { id: 'always-force-name2-checkbox', property: 'always_force_name2', isCheckbox: true, isGlobalSetting: true, defaultValue: true },
319 { id: 'trim_sentences_checkbox', property: 'trim_sentences', isCheckbox: true, isGlobalSetting: true, defaultValue: false },322 { id: 'trim_sentences_checkbox', property: 'trim_sentences', isCheckbox: true, isGlobalSetting: true, defaultValue: false },
320 { id: 'include_newline_checkbox', property: 'include_newline', isCheckbox: true, isGlobalSetting: true, defaultValue: false },
321 { id: 'single_line', property: 'single_line', isCheckbox: true, isGlobalSetting: true, defaultValue: false },323 { id: 'single_line', property: 'single_line', isCheckbox: true, isGlobalSetting: true, defaultValue: false },
322];324];
323325
@@ -1487,7 +1489,6 @@ async function loadPowerUserSettings(settings, data) {
1487 $('#collapse-newlines-checkbox').prop('checked', power_user.collapse_newlines);1489 $('#collapse-newlines-checkbox').prop('checked', power_user.collapse_newlines);
1488 $('#always-force-name2-checkbox').prop('checked', power_user.always_force_name2);1490 $('#always-force-name2-checkbox').prop('checked', power_user.always_force_name2);
1489 $('#trim_sentences_checkbox').prop('checked', power_user.trim_sentences);1491 $('#trim_sentences_checkbox').prop('checked', power_user.trim_sentences);
1490 $('#include_newline_checkbox').prop('checked', power_user.include_newline);
1491 $('#render_formulas').prop('checked', power_user.render_formulas);1492 $('#render_formulas').prop('checked', power_user.render_formulas);
1492 $('#disable_group_trimming').prop('checked', power_user.disable_group_trimming);1493 $('#disable_group_trimming').prop('checked', power_user.disable_group_trimming);
1493 $('#markdown_escape_strings').val(power_user.markdown_escape_strings);1494 $('#markdown_escape_strings').val(power_user.markdown_escape_strings);
@@ -1598,6 +1599,7 @@ async function loadPowerUserSettings(settings, data) {
1598 reloadMarkdownProcessor(power_user.render_formulas);1599 reloadMarkdownProcessor(power_user.render_formulas);
1599 await loadInstructMode(data);1600 await loadInstructMode(data);
1600 await loadContextSettings();1601 await loadContextSettings();
1602 await loadSystemPrompts(data);
1601 loadMaxContextUnlocked();1603 loadMaxContextUnlocked();
1602 switchWaifuMode();1604 switchWaifuMode();
1603 switchSpoilerMode();1605 switchSpoilerMode();
@@ -1817,29 +1819,8 @@ async function loadContextSettings() {
1817 }1819 }
1818 }1820 }
18191821
1820 highlightDefaultContext();
1821 saveSettingsDebounced();
1822 });
1823
1824 $('#context_set_default').on('click', function () {
1825 if (power_user.context.preset !== power_user.default_context) {
1826 power_user.default_context = power_user.context.preset;
1827 $(this).addClass('default');
1828 toastr.info(`Default context template set to ${power_user.default_context}`);
1829
1830 highlightDefaultContext();
1831
1832 saveSettingsDebounced();1822 saveSettingsDebounced();
1833 }
1834 });1823 });
1835
1836 highlightDefaultContext();
1837}
1838
1839function highlightDefaultContext() {
1840 $('#context_set_default').toggleClass('default', power_user.default_context === power_user.context.preset);
1841 $('#context_set_default').toggleClass('disabled', power_user.default_context === power_user.context.preset);
1842 $('#context_delete_preset').toggleClass('disabled', power_user.default_context === power_user.context.preset);
1843}1824}
18441825
1845/**1826/**
@@ -3069,19 +3050,6 @@ $(document).ready(() => {
3069 // if trim sentences is unchecked, include newline must be unchecked3050 // if trim sentences is unchecked, include newline must be unchecked
3070 $('#trim_sentences_checkbox').change(function () {3051 $('#trim_sentences_checkbox').change(function () {
3071 power_user.trim_sentences = !!$(this).prop('checked');3052 power_user.trim_sentences = !!$(this).prop('checked');
3072 if (!$(this).prop('checked')) {
3073 $('#include_newline_checkbox').prop('checked', false);
3074 power_user.include_newline = false;
3075 }
3076 saveSettingsDebounced();
3077 });
3078
3079 $('#include_newline_checkbox').change(function () {
3080 power_user.include_newline = !!$(this).prop('checked');
3081 if ($(this).prop('checked')) {
3082 $('#trim_sentences_checkbox').prop('checked', true);
3083 power_user.trim_sentences = true;
3084 }
3085 saveSettingsDebounced();3053 saveSettingsDebounced();
3086 });3054 });
30873055
public/scripts/preset-manager.js+264 -9
@@ -18,13 +18,16 @@ import {
18import { groups, selected_group } from './group-chats.js';18import { groups, selected_group } from './group-chats.js';
19import { instruct_presets } from './instruct-mode.js';19import { instruct_presets } from './instruct-mode.js';
20import { kai_settings } from './kai-settings.js';20import { kai_settings } from './kai-settings.js';
21import { Popup } from './popup.js';21import { convertNovelPreset } from './nai-settings.js';
22import { Popup, POPUP_RESULT, POPUP_TYPE } from './popup.js';
22import { context_presets, getContextSettings, power_user } from './power-user.js';23import { context_presets, getContextSettings, power_user } from './power-user.js';
23import { SlashCommand } from './slash-commands/SlashCommand.js';24import { SlashCommand } from './slash-commands/SlashCommand.js';
24import { ARGUMENT_TYPE, SlashCommandArgument } from './slash-commands/SlashCommandArgument.js';25import { ARGUMENT_TYPE, SlashCommandArgument } from './slash-commands/SlashCommandArgument.js';
25import { enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js';26import { enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js';
26import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js';27import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js';
27import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';28import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
29import { checkForSystemPromptInInstructTemplate, system_prompts } from './sysprompt.js';
30import { renderTemplateAsync } from './templates.js';
28import {31import {
29 textgenerationwebui_preset_names,32 textgenerationwebui_preset_names,
30 textgenerationwebui_presets,33 textgenerationwebui_presets,
@@ -71,7 +74,7 @@ function autoSelectPreset() {
71 * @param {string} apiId API id74 * @param {string} apiId API id
72 * @returns {PresetManager} Preset manager75 * @returns {PresetManager} Preset manager
73 */76 */
74function getPresetManager(apiId = '') {77export function getPresetManager(apiId = '') {
75 if (!apiId) {78 if (!apiId) {
76 apiId = main_api == 'koboldhorde' ? 'kobold' : main_api;79 apiId = main_api == 'koboldhorde' ? 'kobold' : main_api;
77 }80 }
@@ -102,6 +105,215 @@ class PresetManager {
102 this.apiId = apiId;105 this.apiId = apiId;
103 }106 }
104107
108 static masterSections = {
109 'instruct': {
110 name: 'Instruct Template',
111 getData: () => {
112 const manager = getPresetManager('instruct');
113 const name = manager.getSelectedPresetName();
114 return manager.getPresetSettings(name);
115 },
116 setData: (data) => {
117 const manager = getPresetManager('instruct');
118 const name = data.name;
119 return manager.savePreset(name, data);
120 },
121 isValid: (data) => PresetManager.isPossiblyInstructData(data),
122 },
123 'context': {
124 name: 'Context Template',
125 getData: () => {
126 const manager = getPresetManager('context');
127 const name = manager.getSelectedPresetName();
128 return manager.getPresetSettings(name);
129 },
130 setData: (data) => {
131 const manager = getPresetManager('context');
132 const name = data.name;
133 return manager.savePreset(name, data);
134 },
135 isValid: (data) => PresetManager.isPossiblyContextData(data),
136 },
137 'sysprompt': {
138 name: 'System Prompt',
139 getData: () => {
140 const manager = getPresetManager('sysprompt');
141 const name = manager.getSelectedPresetName();
142 return manager.getPresetSettings(name);
143 },
144 setData: (data) => {
145 const manager = getPresetManager('sysprompt');
146 const name = data.name;
147 return manager.savePreset(name, data);
148 },
149 isValid: (data) => PresetManager.isPossiblySystemPromptData(data),
150 },
151 'preset': {
152 name: 'Text Completion Preset',
153 getData: () => {
154 const manager = getPresetManager('textgenerationwebui');
155 const name = manager.getSelectedPresetName();
156 const data = manager.getPresetSettings(name);
157 data['name'] = name;
158 return data;
159 },
160 setData: (data) => {
161 const manager = getPresetManager('textgenerationwebui');
162 const name = data.name;
163 return manager.savePreset(name, data);
164 },
165 isValid: (data) => PresetManager.isPossiblyTextCompletionData(data),
166 },
167 };
168
169 static isPossiblyInstructData(data) {
170 const instructProps = ['name', 'input_sequence', 'output_sequence'];
171 return data && instructProps.every(prop => Object.keys(data).includes(prop));
172 }
173
174 static isPossiblyContextData(data) {
175 const contextProps = ['name', 'story_string'];
176 return data && contextProps.every(prop => Object.keys(data).includes(prop));
177 }
178
179 static isPossiblySystemPromptData(data) {
180 const sysPromptProps = ['name', 'content'];
181 return data && sysPromptProps.every(prop => Object.keys(data).includes(prop));
182 }
183
184 static isPossiblyTextCompletionData(data) {
185 const textCompletionProps = ['temp', 'top_k', 'top_p', 'rep_pen'];
186 return data && textCompletionProps.every(prop => Object.keys(data).includes(prop));
187 }
188
189 /**
190 * Imports master settings from JSON data.
191 * @param {object} data Data to import
192 * @param {string} fileName File name
193 * @returns {Promise<void>}
194 */
195 static async performMasterImport(data, fileName) {
196 if (!data || typeof data !== 'object') {
197 toastr.error('Invalid data provided for master import');
198 return;
199 }
200
201 // Check for legacy file imports
202 // 1. Instruct Template
203 if (this.isPossiblyInstructData(data)) {
204 toastr.info('Importing instruct template...', 'Instruct template detected');
205 return await getPresetManager('instruct').savePreset(data.name, data);
206 }
207
208 // 2. Context Template
209 if (this.isPossiblyContextData(data)) {
210 toastr.info('Importing as context template...', 'Context template detected');
211 return await getPresetManager('context').savePreset(data.name, data);
212 }
213
214 // 3. System Prompt
215 if (this.isPossiblySystemPromptData(data)) {
216 toastr.info('Importing as system prompt...', 'System prompt detected');
217 return await getPresetManager('sysprompt').savePreset(data.name, data);
218 }
219
220 // 4. Text Completion settings
221 if (this.isPossiblyTextCompletionData(data)) {
222 toastr.info('Importing as settings preset...', 'Text Completion settings detected');
223 return await getPresetManager('textgenerationwebui').savePreset(fileName, data);
224 }
225
226 const validSections = [];
227 for (const [key, section] of Object.entries(this.masterSections)) {
228 if (key in data && section.isValid(data[key])) {
229 validSections.push(key);
230 }
231 }
232
233 if (validSections.length === 0) {
234 toastr.error('No valid sections found in imported data');
235 return;
236 }
237
238 const sectionNames = validSections.reduce((acc, key) => {
239 acc[key] = { key: key, name: this.masterSections[key].name, preset: data[key]?.name || '' };
240 return acc;
241 }, {});
242
243 const html = $(await renderTemplateAsync('masterImport', { sections: sectionNames }));
244 const popup = new Popup(html, POPUP_TYPE.CONFIRM, '', {
245 okButton: 'Import',
246 cancelButton: 'Cancel',
247 });
248
249 const result = await popup.show();
250
251 // Import cancelled
252 if (result !== POPUP_RESULT.AFFIRMATIVE) {
253 return;
254 }
255
256 const importedSections = [];
257 const confirmedSections = html.find('input:checked').map((_, el) => el instanceof HTMLInputElement && el.value).get();
258
259 if (confirmedSections.length === 0) {
260 toastr.info('No sections selected for import');
261 return;
262 }
263
264 for (const section of confirmedSections) {
265 const sectionData = data[section];
266 const masterSection = this.masterSections[section];
267 if (sectionData && masterSection) {
268 await masterSection.setData(sectionData);
269 importedSections.push(masterSection.name);
270 }
271 }
272
273 toastr.success(`Imported ${importedSections.length} settings: ${importedSections.join(', ')}`);
274 }
275
276 /**
277 * Exports master settings to JSON data.
278 * @returns {Promise<string>} JSON data
279 */
280 static async performMasterExport() {
281 const sectionNames = Object.entries(this.masterSections).reduce((acc, [key, section]) => {
282 acc[key] = { key: key, name: section.name, checked: key !== 'preset' };
283 return acc;
284 }, {});
285 const html = $(await renderTemplateAsync('masterExport', { sections: sectionNames }));
286
287 const popup = new Popup(html, POPUP_TYPE.CONFIRM, '', {
288 okButton: 'Export',
289 cancelButton: 'Cancel',
290 });
291
292 const result = await popup.show();
293
294 // Export cancelled
295 if (result !== POPUP_RESULT.AFFIRMATIVE) {
296 return;
297 }
298
299 const confirmedSections = html.find('input:checked').map((_, el) => el instanceof HTMLInputElement && el.value).get();
300 const data = {};
301
302 if (confirmedSections.length === 0) {
303 toastr.info('No sections selected for export');
304 return;
305 }
306
307 for (const section of confirmedSections) {
308 const masterSection = this.masterSections[section];
309 if (masterSection) {
310 data[section] = masterSection.getData();
311 }
312 }
313
314 return JSON.stringify(data, null, 4);
315 }
316
105 /**317 /**
106 * Gets all preset names.318 * Gets all preset names.
107 * @returns {string[]} List of preset names319 * @returns {string[]} List of preset names
@@ -182,6 +394,14 @@ class PresetManager {
182 }394 }
183395
184 async savePreset(name, settings) {396 async savePreset(name, settings) {
397 if (this.apiId === 'instruct' && settings) {
398 await checkForSystemPromptInInstructTemplate(name, settings);
399 }
400
401 if (this.apiId === 'novel' && settings) {
402 settings = convertNovelPreset(settings);
403 }
404
185 const preset = settings ?? this.getPresetSettings(name);405 const preset = settings ?? this.getPresetSettings(name);
186406
187 const response = await fetch('/api/presets/save', {407 const response = await fetch('/api/presets/save', {
@@ -228,6 +448,10 @@ class PresetManager {
228 presets = instruct_presets;448 presets = instruct_presets;
229 preset_names = instruct_presets.map(x => x.name);449 preset_names = instruct_presets.map(x => x.name);
230 break;450 break;
451 case 'sysprompt':
452 presets = system_prompts;
453 preset_names = system_prompts.map(x => x.name);
454 break;
231 default:455 default:
232 console.warn(`Unknown API ID ${this.apiId}`);456 console.warn(`Unknown API ID ${this.apiId}`);
233 }457 }
@@ -236,11 +460,11 @@ class PresetManager {
236 }460 }
237461
238 isKeyedApi() {462 isKeyedApi() {
239 return this.apiId == 'textgenerationwebui' || this.apiId == 'context' || this.apiId == 'instruct';463 return this.apiId == 'textgenerationwebui' || this.isAdvancedFormatting();
240 }464 }
241465
242 isAdvancedFormatting() {466 isAdvancedFormatting() {
243 return this.apiId == 'context' || this.apiId == 'instruct';467 return this.apiId == 'context' || this.apiId == 'instruct' || this.apiId == 'sysprompt';
244 }468 }
245469
246 updateList(name, preset) {470 updateList(name, preset) {
@@ -298,6 +522,11 @@ class PresetManager {
298 instruct_preset['name'] = name || power_user.instruct.preset;522 instruct_preset['name'] = name || power_user.instruct.preset;
299 return instruct_preset;523 return instruct_preset;
300 }524 }
525 case 'sysprompt': {
526 const sysprompt_preset = structuredClone(power_user.sysprompt);
527 sysprompt_preset['name'] = name || power_user.sysprompt.preset;
528 return sysprompt_preset;
529 }
301 default:530 default:
302 console.warn(`Unknown API ID ${apiId}`);531 console.warn(`Unknown API ID ${apiId}`);
303 return {};532 return {};
@@ -601,11 +830,6 @@ export async function initPresetManager() {
601 return;830 return;
602 }831 }
603832
604 // default context preset cannot be deleted
605 if (apiId == 'context' && power_user.default_context === power_user.context.preset) {
606 return;
607 }
608
609 const headerText = !presetManager.isAdvancedFormatting() ? 'Delete this preset?' : 'Delete this template?';833 const headerText = !presetManager.isAdvancedFormatting() ? 'Delete this preset?' : 'Delete this template?';
610 const confirm = await Popup.show.confirm(headerText, 'This action is irreversible and your current settings will be overwritten.');834 const confirm = await Popup.show.confirm(headerText, 'This action is irreversible and your current settings will be overwritten.');
611 if (!confirm) {835 if (!confirm) {
@@ -682,4 +906,35 @@ export async function initPresetManager() {
682 toastr.success(successToast);906 toastr.success(successToast);
683 }907 }
684 });908 });
909
910 $('#af_master_import').on('click', () => {
911 $('#af_master_import_file').trigger('click');
912 });
913
914 $('#af_master_import_file').on('change', async function (e) {
915 if (!(e.target instanceof HTMLInputElement)) {
916 return;
917 }
918 const file = e.target.files[0];
919
920 if (!file) {
921 return;
922 }
923
924 const data = await parseJsonFile(file);
925 const fileName = file.name.replace('.json', '');
926 await PresetManager.performMasterImport(data, fileName);
927 e.target.value = null;
928 });
929
930 $('#af_master_export').on('click', async () => {
931 const data = await PresetManager.performMasterExport();
932
933 if (!data) {
934 return;
935 }
936
937 const shortDate = new Date().toISOString().split('T')[0];
938 download(data, `ST-formatting-${shortDate}.json`, 'application/json');
939 });
685}940}
public/scripts/sysprompt.js+250 -0
@@ -0,0 +1,250 @@
1import { saveSettingsDebounced } from '../script.js';
2import { callGenericPopup, POPUP_TYPE } from './popup.js';
3import { power_user } from './power-user.js';
4import { getPresetManager } from './preset-manager.js';
5import { SlashCommand } from './slash-commands/SlashCommand.js';
6import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js';
7import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js';
8import { enumTypes, SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js';
9import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
10import { renderTemplateAsync } from './templates.js';
11import { isTrueBoolean, resetScrollHeight } from './utils.js';
12
13export let system_prompts = [];
14
15const $enabled = $('#sysprompt_enabled');
16const $select = $('#sysprompt_select');
17const $content = $('#sysprompt_content');
18const $contentBlock = $('#SystemPromptBlock');
19
20async function migrateSystemPromptFromInstructMode() {
21 if ('system_prompt' in power_user.instruct) {
22 const prompt = String(power_user.instruct.system_prompt);
23 delete power_user.instruct.system_prompt;
24 power_user.sysprompt.enabled = power_user.instruct.enabled;
25 power_user.sysprompt.content = prompt;
26
27 const existingPromptName = system_prompts.find(x => x.content === prompt)?.name;
28
29 if (existingPromptName) {
30 power_user.sysprompt.name = existingPromptName;
31 } else {
32 const data = { name: `[Migrated] ${power_user.instruct.preset}`, content: prompt };
33 await getPresetManager('sysprompt')?.savePreset(data.name, data);
34 power_user.sysprompt.name = data.name;
35 }
36
37 saveSettingsDebounced();
38 toastr.info('System prompt settings have been moved from the Instruct Mode.', 'Migration notice', { timeOut: 5000 });
39 }
40}
41
42/**
43 * Loads sysprompt settings from the given data object.
44 * @param {object} data Settings data object.
45 */
46export async function loadSystemPrompts(data) {
47 if (data.sysprompt !== undefined) {
48 system_prompts = data.sysprompt;
49 }
50
51 await migrateSystemPromptFromInstructMode();
52 toggleSystemPromptDisabledControls();
53
54 for (const prompt of system_prompts) {
55 $('<option>').val(prompt.name).text(prompt.name).appendTo($select);
56 }
57
58 $enabled.prop('checked', power_user.sysprompt.enabled);
59 $select.val(power_user.sysprompt.name);
60 $content.val(power_user.sysprompt.content);
61 if (!CSS.supports('field-sizing', 'content')) {
62 await resetScrollHeight($content);
63 }
64}
65
66/**
67 * Checks if the instruct template has a system prompt and prompts the user to save it as a system prompt.
68 * @param {string} name Name of the instruct template
69 * @param {object} template Instruct template object
70 */
71export async function checkForSystemPromptInInstructTemplate(name, template) {
72 if (!template || !name || typeof name !== 'string' || typeof template !== 'object') {
73 return;
74 }
75 if ('system_prompt' in template && template.system_prompt) {
76 const existingName = system_prompts.find(x => x.content === template.system_prompt)?.name;
77 const html = await renderTemplateAsync('migrateInstructPrompt', { prompt: template.system_prompt, existing: existingName });
78 const confirm = await callGenericPopup(html, POPUP_TYPE.CONFIRM);
79 if (confirm) {
80 const migratedName = `[Migrated] ${name}`;
81 const prompt = { name: migratedName, content: template.system_prompt };
82 const presetManager = getPresetManager('sysprompt');
83 await presetManager.savePreset(migratedName, prompt);
84 toastr.success(`System prompt "${migratedName}" has been saved.`);
85 } else {
86 toastr.info('System prompt has been discarded.');
87 }
88
89 delete template.system_prompt;
90 }
91}
92
93function toggleSystemPromptDisabledControls() {
94 $enabled.parent().find('i').toggleClass('toggleEnabled', !!power_user.sysprompt.enabled);
95 $contentBlock.toggleClass('disabled', !power_user.sysprompt.enabled);
96}
97
98/**
99 * Sets the system prompt state.
100 * @param {boolean} state System prompt state
101 * @returns {string} Empty string
102 */
103function setSystemPromptStateCallback(state) {
104 power_user.sysprompt.enabled = state;
105 $enabled.prop('checked', state);
106 toggleSystemPromptDisabledControls();
107 saveSettingsDebounced();
108 return '';
109}
110
111function toggleSystemPromptCallback(_args, state) {
112 if (!state || typeof state !== 'string') {
113 return String(power_user.sysprompt.enabled);
114 }
115
116 const newState = isTrueBoolean(state);
117 setSystemPromptStateCallback(newState);
118 return String(power_user.sysprompt.enabled);
119}
120
121function selectSystemPromptCallback(args, name) {
122 if (!power_user.sysprompt.enabled && !isTrueBoolean(args.forceGet)) {
123 return '';
124 }
125
126 if (!name) {
127 return power_user.sysprompt.name ?? '';
128 }
129
130 const quiet = isTrueBoolean(args?.quiet);
131 const systemPromptNames = system_prompts.map(preset => preset.name);
132 let foundName = systemPromptNames.find(x => x.toLowerCase() === name.toLowerCase());
133
134 if (!foundName) {
135 const fuse = new Fuse(systemPromptNames);
136 const result = fuse.search(name);
137
138 if (result.length === 0) {
139 !quiet && toastr.warning(`System prompt "${name}" not found`);
140 return '';
141 }
142
143 foundName = result[0].item;
144 }
145
146 $select.val(foundName).trigger('change');
147 !quiet && toastr.success(`System prompt "${foundName}" selected`);
148 return foundName;
149}
150
151export function initSystemPrompts() {
152 $enabled.on('input', function () {
153 power_user.sysprompt.enabled = !!$(this).prop('checked');
154 toggleSystemPromptDisabledControls();
155 saveSettingsDebounced();
156 });
157
158 $select.on('change', async function () {
159 if (!power_user.sysprompt.enabled) {
160 $enabled.prop('checked', true).trigger('input');
161 }
162
163 const name = String($(this).val());
164 const prompt = system_prompts.find(p => p.name === name);
165 if (prompt) {
166 $content.val(prompt.content);
167 if (!CSS.supports('field-sizing', 'content')) {
168 await resetScrollHeight($content);
169 }
170
171 power_user.sysprompt.name = name;
172 power_user.sysprompt.content = prompt.content;
173 }
174 saveSettingsDebounced();
175 });
176
177 $content.on('input', function () {
178 power_user.sysprompt.content = String($(this).val());
179 saveSettingsDebounced();
180 });
181
182 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
183 name: 'sysprompt',
184 aliases: ['system-prompt'],
185 callback: selectSystemPromptCallback,
186 returns: 'current prompt name',
187 namedArgumentList: [
188 SlashCommandNamedArgument.fromProps({
189 name: 'quiet',
190 description: 'Suppress the toast message on prompt change',
191 typeList: [ARGUMENT_TYPE.BOOLEAN],
192 defaultValue: 'false',
193 enumList: commonEnumProviders.boolean('trueFalse')(),
194 }),
195 SlashCommandNamedArgument.fromProps({
196 name: 'forceGet',
197 description: 'Force getting a name even if system prompt is disabled',
198 typeList: [ARGUMENT_TYPE.BOOLEAN],
199 defaultValue: 'false',
200 enumList: commonEnumProviders.boolean('trueFalse')(),
201 }),
202 ],
203 unnamedArgumentList: [
204 SlashCommandArgument.fromProps({
205 description: 'system prompt name',
206 typeList: [ARGUMENT_TYPE.STRING],
207 enumProvider: () => system_prompts.map(x => new SlashCommandEnumValue(x.name, null, enumTypes.enum, enumIcons.preset)),
208 }),
209 ],
210 helpString: `
211 <div>
212 Selects a system prompt by name, using fuzzy search to find the closest match.
213 Gets the current system prompt if no name is provided and sysprompt is enabled or <code>forceGet=true</code> is passed.
214 </div>
215 <div>
216 <strong>Example:</strong>
217 <ul>
218 <li>
219 <pre><code class="language-stscript">/sysprompt </code></pre>
220 </li>
221 </ul>
222 </div>
223 `,
224 }));
225 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
226 name: 'sysprompt-on',
227 aliases: ['sysprompt-enable'],
228 callback: () => setSystemPromptStateCallback(true),
229 helpString: 'Enables system prompt.',
230 }));
231 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
232 name: 'sysprompt-off',
233 aliases: ['sysprompt-disable'],
234 callback: () => setSystemPromptStateCallback(false),
235 helpString: 'Disables system prompt',
236 }));
237 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
238 name: 'sysprompt-state',
239 aliases: ['sysprompt-toggle'],
240 helpString: 'Gets the current system prompt state. If an argument is provided, it will set the system prompt state.',
241 unnamedArgumentList: [
242 SlashCommandArgument.fromProps({
243 description: 'system prompt state',
244 typeList: [ARGUMENT_TYPE.BOOLEAN],
245 enumList: commonEnumProviders.boolean('trueFalse')(),
246 }),
247 ],
248 callback: toggleSystemPromptCallback,
249 }));
250}
public/scripts/templates/macros.html+2 -2
@@ -57,8 +57,8 @@
57 <li><tt>&lcub;&lcub;maxPrompt&rcub;&rcub;</tt> – <span data-i18n="help_macros_41">max allowed prompt length in tokens = (context size - response length)</span></li>57 <li><tt>&lcub;&lcub;maxPrompt&rcub;&rcub;</tt> – <span data-i18n="help_macros_41">max allowed prompt length in tokens = (context size - response length)</span></li>
58 <li><tt>&lcub;&lcub;exampleSeparator&rcub;&rcub;</tt> – <span data-i18n="help_macros_42">context template example dialogues separator</span></li>58 <li><tt>&lcub;&lcub;exampleSeparator&rcub;&rcub;</tt> – <span data-i18n="help_macros_42">context template example dialogues separator</span></li>
59 <li><tt>&lcub;&lcub;chatStart&rcub;&rcub;</tt> – <span data-i18n="help_macros_43">context template chat start line</span></li>59 <li><tt>&lcub;&lcub;chatStart&rcub;&rcub;</tt> – <span data-i18n="help_macros_43">context template chat start line</span></li>
60 <li><tt>&lcub;&lcub;systemPrompt&rcub;&rcub;</tt> – <span data-i18n="help_macros_44">main system prompt (either character prompt override if chosen, or instructSystemPrompt)</span></li>60 <li><tt>&lcub;&lcub;systemPrompt&rcub;&rcub;</tt> – <span data-i18n="help_macros_44">system prompt content if enabled (either character prompt override if allowed, or defaultSystemPrompt)</span></li>
61 <li><tt>&lcub;&lcub;instructSystemPrompt&rcub;&rcub;</tt> – <span data-i18n="help_macros_45">instruct system prompt</span></li>61 <li><tt>&lcub;&lcub;defaultSystemPrompt&rcub;&rcub;</tt> – <span data-i18n="help_macros_45">system prompt content</span></li>
62 <li><tt>&lcub;&lcub;instructSystemPromptPrefix&rcub;&rcub;</tt> – <span data-i18n="help_macros_46">instruct system prompt prefix sequence</span></li>62 <li><tt>&lcub;&lcub;instructSystemPromptPrefix&rcub;&rcub;</tt> – <span data-i18n="help_macros_46">instruct system prompt prefix sequence</span></li>
63 <li><tt>&lcub;&lcub;instructSystemPromptSuffix&rcub;&rcub;</tt> – <span data-i18n="help_macros_47">instruct system prompt suffix sequence</span></li>63 <li><tt>&lcub;&lcub;instructSystemPromptSuffix&rcub;&rcub;</tt> – <span data-i18n="help_macros_47">instruct system prompt suffix sequence</span></li>
64 <li><tt>&lcub;&lcub;instructUserPrefix&rcub;&rcub;</tt> – <span data-i18n="help_macros_48">instruct user prefix sequence</span></li>64 <li><tt>&lcub;&lcub;instructUserPrefix&rcub;&rcub;</tt> – <span data-i18n="help_macros_48">instruct user prefix sequence</span></li>
public/scripts/templates/masterExport.html+17 -0
@@ -0,0 +1,17 @@
1<h3>
2 Choose what to export
3</h3>
4<div class="flex-container flexFlowColumn justifyLeft">
5 {{#each sections}}
6 {{#with this}}
7 <label class="checkbox_label">
8 {{#if checked}}
9 <input type="checkbox" value="{{key}}" checked />
10 {{else}}
11 <input type="checkbox" value="{{key}}" />
12 {{/if}}
13 <span data-i18n="{{name}}">{{name}}</span>
14 </label>
15 {{/with}}
16 {{/each}}
17</div>
public/scripts/templates/masterImport.html+17 -0
@@ -0,0 +1,17 @@
1<h3>
2 Choose what to import
3</h3>
4<div class="flex-container flexFlowColumn justifyLeft">
5 {{#each sections}}
6 {{#with this}}
7 <label class="checkbox_label">
8 <input type="checkbox" value="{{key}}" checked>
9 <span data-i18n="{{name}}">{{name}}</span>
10 {{#if preset}}
11 <span>&ndash;</span>
12 <small>{{preset}}</small>
13 {{/if}}
14 </label>
15 {{/with}}
16 {{/each}}
17</div>
public/scripts/templates/migrateInstructPrompt.html+27 -0
@@ -0,0 +1,27 @@
1<h3>
2 This instruct template also contains a system prompt.
3</h3>
4<div>
5 Would you like to migrate the system prompt from the template?
6</div>
7{{#if existing}}
8<div class="marginTopBot5">
9 <b>Note:</b>
10 <span>you already have this prompt saved as:</span>
11 <span>{{existing}}</span>
12</div>
13{{/if}}
14<div class="justifyLeft marginTop5">
15 <div>
16 <small>
17 <b>"Yes"</b> &ndash; The prompt will be imported and selected as a current system prompt.
18 </small>
19
20 </div>
21 <div>
22 <small>
23 <b>"No"</b> &ndash; The prompt will be ignored, no changes to the current system prompt.
24 </small>
25 </div>
26</div>
27<textarea class="wide100p textarea_compact" rows="10">{{prompt}}</textarea>
public/scripts/tokenizers.js+18 -8
@@ -10,7 +10,8 @@ import { getCurrentDreamGenModelTokenizer, getCurrentOpenRouterModelTokenizer, o
10const { OOBA, TABBY, KOBOLDCPP, VLLM, APHRODITE, LLAMACPP, OPENROUTER, DREAMGEN } = textgen_types;10const { OOBA, TABBY, KOBOLDCPP, VLLM, APHRODITE, LLAMACPP, OPENROUTER, DREAMGEN } = textgen_types;
1111
12export const CHARACTERS_PER_TOKEN_RATIO = 3.35;12export const CHARACTERS_PER_TOKEN_RATIO = 3.35;
13const TOKENIZER_WARNING_KEY = 'tokenizationWarningShown';13export const TOKENIZER_WARNING_KEY = 'tokenizationWarningShown';
14export const TOKENIZER_SUPPORTED_KEY = 'tokenizationSupported';
1415
15export const tokenizers = {16export const tokenizers = {
16 NONE: 0,17 NONE: 0,
@@ -273,6 +274,9 @@ export function getTokenizerBestMatch(forApi) {
273 if (nai_settings.model_novel.includes('kayra')) {274 if (nai_settings.model_novel.includes('kayra')) {
274 return tokenizers.NERD2;275 return tokenizers.NERD2;
275 }276 }
277 if (nai_settings.model_novel.includes('erato')) {
278 return tokenizers.LLAMA3;
279 }
276 }280 }
277 if (forApi === 'kobold' || forApi === 'textgenerationwebui' || forApi === 'koboldhorde') {281 if (forApi === 'kobold' || forApi === 'textgenerationwebui' || forApi === 'koboldhorde') {
278 // Try to use the API tokenizer if possible:282 // Try to use the API tokenizer if possible:
@@ -280,8 +284,9 @@ export function getTokenizerBestMatch(forApi) {
280 // - Kobold must pass a version check284 // - Kobold must pass a version check
281 // - Tokenizer haven't reported an error previously285 // - Tokenizer haven't reported an error previously
282 const hasTokenizerError = sessionStorage.getItem(TOKENIZER_WARNING_KEY);286 const hasTokenizerError = sessionStorage.getItem(TOKENIZER_WARNING_KEY);
287 const hasValidEndpoint = sessionStorage.getItem(TOKENIZER_SUPPORTED_KEY);
283 const isConnected = online_status !== 'no_connection';288 const isConnected = online_status !== 'no_connection';
284 const isTokenizerSupported = TEXTGEN_TOKENIZERS.includes(textgen_settings.type);289 const isTokenizerSupported = TEXTGEN_TOKENIZERS.includes(textgen_settings.type) && (textgen_settings.type !== OOBA || hasValidEndpoint);
285290
286 if (!hasTokenizerError && isConnected) {291 if (!hasTokenizerError && isConnected) {
287 if (forApi === 'kobold' && kai_flags.can_use_tokenization) {292 if (forApi === 'kobold' && kai_flags.can_use_tokenization) {
@@ -923,15 +928,20 @@ function countTokensFromTextgenAPI(str, resolve) {
923928
924function apiFailureTokenCount(str) {929function apiFailureTokenCount(str) {
925 console.error('Error counting tokens');930 console.error('Error counting tokens');
931 let shouldTryAgain = false;
926932
927 if (!sessionStorage.getItem(TOKENIZER_WARNING_KEY)) {933 if (!sessionStorage.getItem(TOKENIZER_WARNING_KEY)) {
928 toastr.warning(934 const bestMatchBefore = getTokenizerBestMatch(main_api);
929 'Your selected API doesn\'t support the tokenization endpoint. Using estimated counts.',
930 'Error counting tokens',
931 { timeOut: 10000, preventDuplicates: true },
932 );
933
934 sessionStorage.setItem(TOKENIZER_WARNING_KEY, String(true));935 sessionStorage.setItem(TOKENIZER_WARNING_KEY, String(true));
936 const bestMatchAfter = getTokenizerBestMatch(main_api);
937 if ([tokenizers.API_TEXTGENERATIONWEBUI, tokenizers.API_KOBOLD].includes(bestMatchBefore) && bestMatchBefore !== bestMatchAfter) {
938 shouldTryAgain = true;
939 }
940 }
941
942 // Only try again if we guarantee not to be looped by the same error
943 if (shouldTryAgain && power_user.tokenizer === tokenizers.BEST_MATCH) {
944 return getTokenCount(str);
935 }945 }
936946
937 return guesstimate(str);947 return guesstimate(str);
public/scripts/utils.js+1 -7
@@ -607,12 +607,11 @@ export function sortByCssOrder(a, b) {
607/**607/**
608 * Trims a string to the end of a nearest sentence.608 * Trims a string to the end of a nearest sentence.
609 * @param {string} input The string to trim.609 * @param {string} input The string to trim.
610 * @param {boolean} include_newline Whether to include a newline character in the trimmed string.
611 * @returns {string} The trimmed string.610 * @returns {string} The trimmed string.
612 * @example611 * @example
613 * trimToEndSentence('Hello, world! I am from'); // 'Hello, world!'612 * trimToEndSentence('Hello, world! I am from'); // 'Hello, world!'
614 */613 */
615export function trimToEndSentence(input, include_newline = false) {614export function trimToEndSentence(input) {
616 if (!input) {615 if (!input) {
617 return '';616 return '';
618 }617 }
@@ -633,11 +632,6 @@ export function trimToEndSentence(input, include_newline = false) {
633 }632 }
634 break;633 break;
635 }634 }
636
637 if (include_newline && char === '\n') {
638 last = i;
639 break;
640 }
641 }635 }
642636
643 if (last === -1) {637 if (last === -1) {
public/scripts/variables.js+60 -7
@@ -1,5 +1,6 @@
1import { chat_metadata, getCurrentChatId, saveSettingsDebounced, sendSystemMessage, system_message_types } from '../script.js';1import { chat_metadata, getCurrentChatId, saveSettingsDebounced, sendSystemMessage, system_message_types } from '../script.js';
2import { extension_settings, saveMetadataDebounced } from './extensions.js';2import { extension_settings, saveMetadataDebounced } from './extensions.js';
3import { callGenericPopup, POPUP_TYPE } from './popup.js';
3import { executeSlashCommandsWithOptions } from './slash-commands.js';4import { executeSlashCommandsWithOptions } from './slash-commands.js';
4import { SlashCommand } from './slash-commands/SlashCommand.js';5import { SlashCommand } from './slash-commands/SlashCommand.js';
5import { SlashCommandAbortController } from './slash-commands/SlashCommandAbortController.js';6import { SlashCommandAbortController } from './slash-commands/SlashCommandAbortController.js';
@@ -303,24 +304,48 @@ export function replaceVariableMacros(input) {
303 return lines.join('\n');304 return lines.join('\n');
304}305}
305306
306function listVariablesCallback() {307async function listVariablesCallback(args) {
308 const type = String(args?.format || '').toLowerCase().trim() || 'popup';
309 const scope = String(args?.scope || '').toLowerCase().trim() || 'all';
307 if (!chat_metadata.variables) {310 if (!chat_metadata.variables) {
308 chat_metadata.variables = {};311 chat_metadata.variables = {};
309 }312 }
310313
311 const localVariables = Object.entries(chat_metadata.variables).map(([name, value]) => `${name}: ${value}`);314 const includeLocalVariables = scope === 'all' || scope === 'local';
312 const globalVariables = Object.entries(extension_settings.variables.global).map(([name, value]) => `${name}: ${value}`);315 const includeGlobalVariables = scope === 'all' || scope === 'global';
316
317 const localVariables = includeLocalVariables ? Object.entries(chat_metadata.variables).map(([name, value]) => `${name}: ${value}`) : [];
318 const globalVariables = includeGlobalVariables ? Object.entries(extension_settings.variables.global).map(([name, value]) => `${name}: ${value}`) : [];
319
320 const jsonVariables = [
321 ...Object.entries(chat_metadata.variables).map(x => ({ key: x[0], value: x[1], scope: 'local' })),
322 ...Object.entries(extension_settings.variables.global).map(x => ({ key: x[0], value: x[1], scope: 'global' })),
323 ];
313324
314 const localVariablesString = localVariables.length > 0 ? localVariables.join('\n\n') : 'No local variables';325 const localVariablesString = localVariables.length > 0 ? localVariables.join('\n\n') : 'No local variables';
315 const globalVariablesString = globalVariables.length > 0 ? globalVariables.join('\n\n') : 'No global variables';326 const globalVariablesString = globalVariables.length > 0 ? globalVariables.join('\n\n') : 'No global variables';
316 const chatName = getCurrentChatId();327 const chatName = getCurrentChatId();
317328
318 const converter = new showdown.Converter();329 const converter = new showdown.Converter();
319 const message = `### Local variables (${chatName}):\n${localVariablesString}\n\n### Global variables:\n${globalVariablesString}`;330 const message = [
331 includeLocalVariables ? `### Local variables (${chatName}):\n${localVariablesString}` : '',
332 includeGlobalVariables ? `### Global variables:\n${globalVariablesString}` : '',
333 ].filter(x => x).join('\n\n');
320 const htmlMessage = DOMPurify.sanitize(converter.makeHtml(message));334 const htmlMessage = DOMPurify.sanitize(converter.makeHtml(message));
321335
336 switch (type) {
337 case 'none':
338 break;
339 case 'chat':
322 sendSystemMessage(system_message_types.GENERIC, htmlMessage);340 sendSystemMessage(system_message_types.GENERIC, htmlMessage);
323 return '';341 break;
342 case 'popup':
343 default:
344 await callGenericPopup(htmlMessage, POPUP_TYPE.TEXT);
345 break;
346 }
347
348 return JSON.stringify(jsonVariables);
324}349}
325350
326/**351/**
@@ -881,7 +906,35 @@ export function registerVariableCommands() {
881 name: 'listvar',906 name: 'listvar',
882 callback: listVariablesCallback,907 callback: listVariablesCallback,
883 aliases: ['listchatvar'],908 aliases: ['listchatvar'],
884 helpString: 'List registered chat variables.',909 helpString: 'List registered chat variables. Displays variables in a popup by default. Use the <code>format</code> argument to change the output format.',
910 returns: 'JSON list of local variables',
911 namedArgumentList: [
912 SlashCommandNamedArgument.fromProps({
913 name: 'scope',
914 description: 'filter variables by scope',
915 typeList: [ARGUMENT_TYPE.STRING],
916 defaultValue: 'all',
917 isRequired: false,
918 forceEnum: true,
919 enumList: [
920 new SlashCommandEnumValue('all', 'All variables', enumTypes.enum, enumIcons.variable),
921 new SlashCommandEnumValue('local', 'Local variables', enumTypes.enum, enumIcons.localVariable),
922 new SlashCommandEnumValue('global', 'Global variables', enumTypes.enum, enumIcons.globalVariable),
923 ],
924 }),
925 SlashCommandNamedArgument.fromProps({
926 name: 'format',
927 description: 'output format',
928 typeList: [ARGUMENT_TYPE.STRING],
929 isRequired: true,
930 forceEnum: true,
931 enumList: [
932 new SlashCommandEnumValue('popup', 'Show variables in a popup.', enumTypes.enum, enumIcons.default),
933 new SlashCommandEnumValue('chat', 'Post a system message to the chat.', enumTypes.enum, enumIcons.message),
934 new SlashCommandEnumValue('none', 'Just return the variables as a JSON list.', enumTypes.enum, enumIcons.array),
935 ],
936 }),
937 ],
885 }));938 }));
886 SlashCommandParser.addCommandObject(SlashCommand.fromProps({939 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
887 name: 'setvar',940 name: 'setvar',
@@ -1430,8 +1483,8 @@ export function registerVariableCommands() {
1430 <li>1483 <li>
1431 <pre><code class="language-stscript">/while left={{getvar::currentword}} {: /setvar key=currentword {: /do-something-and-return :}() | /echo The current work is "{{getvar::currentword}}" :}</code></pre>1484 <pre><code class="language-stscript">/while left={{getvar::currentword}} {: /setvar key=currentword {: /do-something-and-return :}() | /echo The current work is "{{getvar::currentword}}" :}</code></pre>
1432 executes the defined subcommand as long as the "currentword" variable is truthy (has any content that is not false/empty)1485 executes the defined subcommand as long as the "currentword" variable is truthy (has any content that is not false/empty)
1433 </li>
1434 </ul>1486 </ul>
1487 </li>
1435 </div>1488 </div>
1436 <div>1489 <div>
1437 Loops are limited to 100 iterations by default, pass <code>guard=off</code> to disable.1490 Loops are limited to 100 iterations by default, pass <code>guard=off</code> to disable.
public/style.css+10 -9
@@ -2573,7 +2573,7 @@ select {
2573 -moz-appearance: none;2573 -moz-appearance: none;
2574 -webkit-appearance: none;2574 -webkit-appearance: none;
2575 appearance: none;2575 appearance: none;
2576 padding: 3px 2px;2576 padding: 3px 5px;
2577 background-color: var(--black30a);2577 background-color: var(--black30a);
2578 border: 1px solid var(--SmartThemeBorderColor);2578 border: 1px solid var(--SmartThemeBorderColor);
2579 border-radius: 5px;2579 border-radius: 5px;
@@ -2630,14 +2630,6 @@ select option:not(:checked) {
2630 color: var(--active) !important;2630 color: var(--active) !important;
2631}2631}
26322632
2633#context_set_default.default {
2634 color: var(--preferred) !important;
2635}
2636
2637#instruct_set_default.default {
2638 color: var(--preferred) !important;
2639}
2640
2641.displayBlock {2633.displayBlock {
2642 display: block !important;2634 display: block !important;
2643}2635}
@@ -5477,3 +5469,12 @@ body:not(.movingUI) .drawer-content.maximized {
5477#AdvancedFormatting .autoSetHeight {5469#AdvancedFormatting .autoSetHeight {
5478 overflow-wrap: anywhere;5470 overflow-wrap: anywhere;
5479}5471}
5472
5473#InstructSequencesColumn summary {
5474 font-size: 0.95em;
5475 cursor: pointer;
5476}
5477
5478#InstructSequencesColumn details:not(:last-of-type) {
5479 margin-bottom: 5px;
5480}
server.js+1 -0
@@ -932,6 +932,7 @@ async function verifySecuritySettings() {
932userModule.initUserStorage(dataRoot)932userModule.initUserStorage(dataRoot)
933 .then(userModule.ensurePublicDirectoriesExist)933 .then(userModule.ensurePublicDirectoriesExist)
934 .then(userModule.migrateUserData)934 .then(userModule.migrateUserData)
935 .then(userModule.migrateSystemPrompts)
935 .then(verifySecuritySettings)936 .then(verifySecuritySettings)
936 .then(preSetupTasks)937 .then(preSetupTasks)
937 .finally(startServer);938 .finally(startServer);
src/constants.js+1 -0
@@ -41,6 +41,7 @@ const USER_DIRECTORY_TEMPLATE = Object.freeze({
41 files: 'user/files',41 files: 'user/files',
42 vectors: 'vectors',42 vectors: 'vectors',
43 backups: 'backups',43 backups: 'backups',
44 sysprompt: 'sysprompt',
44});45});
4546
46/**47/**
src/endpoints/backends/chat-completions.js+4 -0
@@ -257,6 +257,10 @@ async function sendMakerSuiteRequest(request, response) {
257 };257 };
258258
259 function getGeminiBody() {259 function getGeminiBody() {
260 if (!Array.isArray(generationConfig.stopSequences) || !generationConfig.stopSequences.length) {
261 delete generationConfig.stopSequences;
262 }
263
260 const should_use_system_prompt = (model.includes('gemini-1.5-flash') || model.includes('gemini-1.5-pro')) && request.body.use_makersuite_sysprompt;264 const should_use_system_prompt = (model.includes('gemini-1.5-flash') || model.includes('gemini-1.5-pro')) && request.body.use_makersuite_sysprompt;
261 const prompt = convertGooglePrompt(request.body.messages, model, should_use_system_prompt, request.body.char_name, request.body.user_name);265 const prompt = convertGooglePrompt(request.body.messages, model, should_use_system_prompt, request.body.char_name, request.body.user_name);
262 let body = {266 let body = {
src/endpoints/backends/text-completions.js+1 -0
@@ -186,6 +186,7 @@ router.post('/status', jsonParser, async function (request, response) {
186186
187 const modelName = modelInfo?.model_name;187 const modelName = modelInfo?.model_name;
188 result = modelName || result;188 result = modelName || result;
189 response.setHeader('x-supports-tokenization', 'true');
189 }190 }
190 } catch (error) {191 } catch (error) {
191 console.error(`Failed to get Ooba model info: ${error}`);192 console.error(`Failed to get Ooba model info: ${error}`);
src/endpoints/content-manager.js+40 -1
@@ -43,6 +43,7 @@ const CONTENT_TYPES = {
43 CONTEXT: 'context',43 CONTEXT: 'context',
44 MOVING_UI: 'moving_ui',44 MOVING_UI: 'moving_ui',
45 QUICK_REPLIES: 'quick_replies',45 QUICK_REPLIES: 'quick_replies',
46 SYSPROMPT: 'sysprompt',
46};47};
4748
48/**49/**
@@ -56,7 +57,7 @@ function getDefaultPresets(directories) {
56 const presets = [];57 const presets = [];
5758
58 for (const contentItem of contentIndex) {59 for (const contentItem of contentIndex) {
59 if (contentItem.type.endsWith('_preset') || contentItem.type === 'instruct' || contentItem.type === 'context') {60 if (contentItem.type.endsWith('_preset') || contentItem.type === 'instruct' || contentItem.type === 'context' || contentItem.type === 'sysprompt') {
60 contentItem.name = path.parse(contentItem.filename).name;61 contentItem.name = path.parse(contentItem.filename).name;
61 contentItem.folder = getTargetByType(contentItem.type, directories);62 contentItem.folder = getTargetByType(contentItem.type, directories);
62 presets.push(contentItem);63 presets.push(contentItem);
@@ -218,6 +219,41 @@ function getContentIndex() {
218}219}
219220
220/**221/**
222 * Gets content by type and format.
223 * @param {string} type Type of content
224 * @param {'json'|'string'|'raw'} format Format of content
225 * @returns {string[]|Buffer[]} Array of content
226 */
227function getContentOfType(type, format) {
228 const contentIndex = getContentIndex();
229 const indexItems = contentIndex.filter((item) => item.type === type && item.folder);
230 const files = [];
231 for (const item of indexItems) {
232 if (!item.folder) {
233 continue;
234 }
235 try {
236 const filePath = path.join(item.folder, item.filename);
237 const fileContent = fs.readFileSync(filePath);
238 switch (format) {
239 case 'json':
240 files.push(JSON.parse(fileContent.toString()));
241 break;
242 case 'string':
243 files.push(fileContent.toString());
244 break;
245 case 'raw':
246 files.push(fileContent);
247 break;
248 }
249 } catch {
250 // Ignore errors
251 }
252 }
253 return files;
254}
255
256/**
221 * Gets the target directory for the specified asset type.257 * Gets the target directory for the specified asset type.
222 * @param {ContentType} type Asset type258 * @param {ContentType} type Asset type
223 * @param {import('../users').UserDirectoryList} directories User directories259 * @param {import('../users').UserDirectoryList} directories User directories
@@ -257,6 +293,8 @@ function getTargetByType(type, directories) {
257 return directories.movingUI;293 return directories.movingUI;
258 case CONTENT_TYPES.QUICK_REPLIES:294 case CONTENT_TYPES.QUICK_REPLIES:
259 return directories.quickreplies;295 return directories.quickreplies;
296 case CONTENT_TYPES.SYSPROMPT:
297 return directories.sysprompt;
260 default:298 default:
261 return null;299 return null;
262 }300 }
@@ -721,5 +759,6 @@ module.exports = {
721 checkForNewContent,759 checkForNewContent,
722 getDefaultPresets,760 getDefaultPresets,
723 getDefaultPresetFile,761 getDefaultPresetFile,
762 getContentOfType,
724 router,763 router,
725};764};
src/endpoints/novelai.js+63 -12
@@ -15,6 +15,11 @@ const badWordsList = [
15 [19438], [43145], [26523], [41471], [2936], [85, 85], [49332], [7286], [1115], [24],15 [19438], [43145], [26523], [41471], [2936], [85, 85], [49332], [7286], [1115], [24],
16];16];
1717
18const eratoBadWordsList = [
19 [16067], [933, 11144], [25106, 11144], [58, 106901, 16073, 33710, 25, 109933],
20 [933, 58, 11144], [128030], [58, 30591, 33503, 17663, 100204, 25, 11144],
21];
22
18const hypeBotBadWordsList = [23const hypeBotBadWordsList = [
19 [58], [60], [90], [92], [685], [1391], [1782], [2361], [3693], [4083], [4357], [4895],24 [58], [60], [90], [92], [685], [1391], [1782], [2361], [3693], [4083], [4357], [4895],
20 [5512], [5974], [7131], [8183], [8351], [8762], [8964], [8973], [9063], [11208],25 [5512], [5974], [7131], [8183], [8351], [8762], [8964], [8973], [9063], [11208],
@@ -42,12 +47,24 @@ const repPenaltyAllowList = [
42 803, 1040, 49209, 4, 5, 6, 7, 8, 9, 10, 11, 12],47 803, 1040, 49209, 4, 5, 6, 7, 8, 9, 10, 11, 12],
43];48];
4449
50const eratoRepPenWhitelist = [
51 6, 1, 11, 13, 25, 198, 12, 9, 8, 279, 264, 459, 323, 477, 539, 912, 374, 574, 1051, 1550, 1587, 4536, 5828, 15058,
52 3287, 3250, 1461, 1077, 813, 11074, 872, 1202, 1436, 7846, 1288, 13434, 1053, 8434, 617, 9167, 1047, 19117, 706,
53 12775, 649, 4250, 527, 7784, 690, 2834, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 1210, 1359, 608, 220, 596, 956,
54 3077, 44886, 4265, 3358, 2351, 2846, 311, 389, 315, 304, 520, 505, 430
55];
56
45// Ban the dinkus and asterism57// Ban the dinkus and asterism
46const logitBiasExp = [58const logitBiasExp = [
47 { 'sequence': [23], 'bias': -0.08, 'ensure_sequence_finish': false, 'generate_once': false },59 { 'sequence': [23], 'bias': -0.08, 'ensure_sequence_finish': false, 'generate_once': false },
48 { 'sequence': [21], 'bias': -0.08, 'ensure_sequence_finish': false, 'generate_once': false },60 { 'sequence': [21], 'bias': -0.08, 'ensure_sequence_finish': false, 'generate_once': false },
49];61];
5062
63const eratoLogitBiasExp = [
64 { 'sequence': [12488], 'bias': -0.08, 'ensure_sequence_finish': false, 'generate_once': false },
65 { 'sequence': [128041], 'bias': -0.08, 'ensure_sequence_finish': false, 'generate_once': false },
66];
67
51function getBadWordsList(model) {68function getBadWordsList(model) {
52 let list = [];69 let list = [];
5370
@@ -59,10 +76,40 @@ function getBadWordsList(model) {
59 list = badWordsList;76 list = badWordsList;
60 }77 }
6178
79 if (model.includes('erato')) {
80 list = eratoBadWordsList;
81 }
82
62 // Clone the list so we don't modify the original83 // Clone the list so we don't modify the original
63 return list.slice();84 return list.slice();
64}85}
6586
87function getLogitBiasList(model) {
88 let list = [];
89
90 if (model.includes('erato')) {
91 list = eratoLogitBiasExp;
92 }
93
94 if (model.includes('clio') || model.includes('kayra')) {
95 list = logitBiasExp;
96 }
97
98 return list.slice();
99}
100
101function getRepPenaltyWhitelist(model) {
102 if (model.includes('clio') || model.includes('kayra')) {
103 return repPenaltyAllowList.flat();
104 }
105
106 if (model.includes('erato')) {
107 return eratoRepPenWhitelist.flat();
108 }
109
110 return null;
111}
112
66const router = express.Router();113const router = express.Router();
67114
68router.post('/status', jsonParser, async function (req, res) {115router.post('/status', jsonParser, async function (req, res) {
@@ -116,11 +163,10 @@ router.post('/generate', jsonParser, async function (req, res) {
116 controller.abort();163 controller.abort();
117 });164 });
118165
119 const isNewModel = (req.body.model.includes('clio') || req.body.model.includes('kayra'));166 // Add customized bad words for Clio, Kayra, and Erato
120 const badWordsList = getBadWordsList(req.body.model);167 const badWordsList = getBadWordsList(req.body.model);
121168
122 // Add customized bad words for Clio and Kayra169 if (Array.isArray(badWordsList) && Array.isArray(req.body.bad_words_ids)) {
123 if (isNewModel && Array.isArray(req.body.bad_words_ids)) {
124 for (const badWord of req.body.bad_words_ids) {170 for (const badWord of req.body.bad_words_ids) {
125 if (Array.isArray(badWord) && badWord.every(x => Number.isInteger(x))) {171 if (Array.isArray(badWord) && badWord.every(x => Number.isInteger(x))) {
126 badWordsList.push(badWord);172 badWordsList.push(badWord);
@@ -136,12 +182,14 @@ router.post('/generate', jsonParser, async function (req, res) {
136 }182 }
137183
138 // Add default biases for dinkus and asterism184 // Add default biases for dinkus and asterism
139 const logit_bias_exp = isNewModel ? logitBiasExp.slice() : [];185 const logitBiasList = getLogitBiasList(req.body.model);
140186
141 if (Array.isArray(logit_bias_exp) && Array.isArray(req.body.logit_bias_exp)) {187 if (Array.isArray(logitBiasList) && Array.isArray(req.body.logit_bias_exp)) {
142 logit_bias_exp.push(...req.body.logit_bias_exp);188 logitBiasList.push(...req.body.logit_bias_exp);
143 }189 }
144190
191 const repPenWhitelist = getRepPenaltyWhitelist(req.body.model);
192
145 const data = {193 const data = {
146 'input': req.body.input,194 'input': req.body.input,
147 'model': req.body.model,195 'model': req.body.model,
@@ -156,19 +204,17 @@ router.post('/generate', jsonParser, async function (req, res) {
156 'repetition_penalty_slope': req.body.repetition_penalty_slope,204 'repetition_penalty_slope': req.body.repetition_penalty_slope,
157 'repetition_penalty_frequency': req.body.repetition_penalty_frequency,205 'repetition_penalty_frequency': req.body.repetition_penalty_frequency,
158 'repetition_penalty_presence': req.body.repetition_penalty_presence,206 'repetition_penalty_presence': req.body.repetition_penalty_presence,
159 'repetition_penalty_whitelist': isNewModel ? repPenaltyAllowList.flat() : null,207 'repetition_penalty_whitelist': repPenWhitelist,
160 'top_a': req.body.top_a,208 'top_a': req.body.top_a,
161 'top_p': req.body.top_p,209 'top_p': req.body.top_p,
162 'top_k': req.body.top_k,210 'top_k': req.body.top_k,
163 'typical_p': req.body.typical_p,211 'typical_p': req.body.typical_p,
164 'mirostat_lr': req.body.mirostat_lr,212 'mirostat_lr': req.body.mirostat_lr,
165 'mirostat_tau': req.body.mirostat_tau,213 'mirostat_tau': req.body.mirostat_tau,
166 'cfg_scale': req.body.cfg_scale,
167 'cfg_uc': req.body.cfg_uc,
168 'phrase_rep_pen': req.body.phrase_rep_pen,214 'phrase_rep_pen': req.body.phrase_rep_pen,
169 'stop_sequences': req.body.stop_sequences,215 'stop_sequences': req.body.stop_sequences,
170 'bad_words_ids': badWordsList.length ? badWordsList : null,216 'bad_words_ids': badWordsList.length ? badWordsList : null,
171 'logit_bias_exp': logit_bias_exp,217 'logit_bias_exp': logitBiasList,
172 'generate_until_sentence': req.body.generate_until_sentence,218 'generate_until_sentence': req.body.generate_until_sentence,
173 'use_cache': req.body.use_cache,219 'use_cache': req.body.use_cache,
174 'return_full_text': req.body.return_full_text,220 'return_full_text': req.body.return_full_text,
@@ -183,9 +229,14 @@ router.post('/generate', jsonParser, async function (req, res) {
183 };229 };
184230
185 // Tells the model to stop generation at '>'231 // Tells the model to stop generation at '>'
186 if ('theme_textadventure' === req.body.prefix && isNewModel) {232 if ('theme_textadventure' === req.body.prefix) {
233 if (req.body.model.includes('clio') || req.body.model.includes('kayra')) {
187 data.parameters.eos_token_id = 49405;234 data.parameters.eos_token_id = 49405;
188 }235 }
236 if (req.body.model.includes('erato')) {
237 data.parameters.eos_token_id = 29;
238 }
239 }
189240
190 console.log(util.inspect(data, { depth: 4 }));241 console.log(util.inspect(data, { depth: 4 }));
191242
@@ -196,7 +247,7 @@ router.post('/generate', jsonParser, async function (req, res) {
196 };247 };
197248
198 try {249 try {
199 const baseURL = req.body.model.includes('kayra') ? TEXT_NOVELAI : API_NOVELAI;250 const baseURL = (req.body.model.includes('kayra') || req.body.model.includes('erato')) ? TEXT_NOVELAI : API_NOVELAI;
200 const url = req.body.streaming ? `${baseURL}/ai/generate-stream` : `${baseURL}/ai/generate`;251 const url = req.body.streaming ? `${baseURL}/ai/generate-stream` : `${baseURL}/ai/generate`;
201 const response = await fetch(url, { method: 'POST', timeout: 0, ...args });252 const response = await fetch(url, { method: 'POST', timeout: 0, ...args });
202253
src/endpoints/presets.js+2 -0
@@ -27,6 +27,8 @@ function getPresetSettingsByAPI(apiId, directories) {
27 return { folder: directories.instruct, extension: '.json' };27 return { folder: directories.instruct, extension: '.json' };
28 case 'context':28 case 'context':
29 return { folder: directories.context, extension: '.json' };29 return { folder: directories.context, extension: '.json' };
30 case 'sysprompt':
31 return { folder: directories.sysprompt, extension: '.json' };
30 default:32 default:
31 return { folder: null, extension: null };33 return { folder: null, extension: null };
32 }34 }
src/endpoints/settings.js+2 -0
@@ -251,6 +251,7 @@ router.post('/get', jsonParser, (request, response) => {
251251
252 const instruct = readAndParseFromDirectory(request.user.directories.instruct);252 const instruct = readAndParseFromDirectory(request.user.directories.instruct);
253 const context = readAndParseFromDirectory(request.user.directories.context);253 const context = readAndParseFromDirectory(request.user.directories.context);
254 const sysprompt = readAndParseFromDirectory(request.user.directories.sysprompt);
254255
255 response.send({256 response.send({
256 settings,257 settings,
@@ -268,6 +269,7 @@ router.post('/get', jsonParser, (request, response) => {
268 quickReplyPresets,269 quickReplyPresets,
269 instruct,270 instruct,
270 context,271 context,
272 sysprompt,
271 enable_extensions: ENABLE_EXTENSIONS,273 enable_extensions: ENABLE_EXTENSIONS,
272 enable_extensions_auto_update: ENABLE_EXTENSIONS_AUTO_UPDATE,274 enable_extensions_auto_update: ENABLE_EXTENSIONS_AUTO_UPDATE,
273 enable_accounts: ENABLE_ACCOUNTS,275 enable_accounts: ENABLE_ACCOUNTS,
src/endpoints/vectors.js+11 -20
@@ -4,7 +4,7 @@ const fs = require('fs');
4const express = require('express');4const express = require('express');
5const sanitize = require('sanitize-filename');5const sanitize = require('sanitize-filename');
6const { jsonParser } = require('../express-common');6const { jsonParser } = require('../express-common');
7const { getConfigValue, color } = require('../util');7const { getConfigValue } = require('../util');
88
9// Don't forget to add new sources to the SOURCES array9// Don't forget to add new sources to the SOURCES array
10const SOURCES = [10const SOURCES = [
@@ -150,7 +150,7 @@ function getSourceSettings(source, request) {
150 extrasUrl: String(request.headers['x-extras-url']),150 extrasUrl: String(request.headers['x-extras-url']),
151 extrasKey: String(request.headers['x-extras-key']),151 extrasKey: String(request.headers['x-extras-key']),
152 };152 };
153 case 'local':153 case 'transformers':
154 return {154 return {
155 model: getConfigValue('extras.embeddingModel', ''),155 model: getConfigValue('extras.embeddingModel', ''),
156 };156 };
@@ -159,6 +159,14 @@ function getSourceSettings(source, request) {
159 // TODO: Add support for multiple models159 // TODO: Add support for multiple models
160 model: 'text-embedding-004',160 model: 'text-embedding-004',
161 };161 };
162 case 'mistral':
163 return {
164 model: 'mistral-embed',
165 };
166 case 'nomicai':
167 return {
168 model: 'nomic-embed-text-v1.5',
169 };
162 default:170 default:
163 return {};171 return {};
164 }172 }
@@ -170,19 +178,7 @@ function getSourceSettings(source, request) {
170 * @returns {string} The model scope for the source178 * @returns {string} The model scope for the source
171 */179 */
172function getModelScope(sourceSettings) {180function getModelScope(sourceSettings) {
173 const scopesEnabled = getConfigValue('vectors.enableModelScopes', false);181 return (sourceSettings?.model || '');
174 const warningShown = global.process.env.VECTORS_MODEL_SCOPE_WARNING_SHOWN === 'true';
175
176 if (!scopesEnabled && !warningShown) {
177 console.log();
178 console.warn(color.red('[DEPRECATION NOTICE]'), 'Model scopes for Vectore Storage are disabled, but will soon be required.');
179 console.log(`To enable model scopes, set the ${color.cyan('vectors.enableModelScopes')} in config.yaml to ${color.green(true)}.`);
180 console.log('This message won\'t be shown again in the current session.');
181 console.log();
182 global.process.env.VECTORS_MODEL_SCOPE_WARNING_SHOWN = 'true';
183 }
184
185 return scopesEnabled ? (sourceSettings?.model || '') : '';
186}182}
187183
188/**184/**
@@ -365,11 +361,6 @@ async function regenerateCorruptedIndexErrorHandler(req, res, error) {
365361
366const router = express.Router();362const router = express.Router();
367363
368router.get('/scopes-enabled', (_req, res) => {
369 const scopesEnabled = getConfigValue('vectors.enableModelScopes', false);
370 return res.json({ enabled: scopesEnabled });
371});
372
373router.post('/query', jsonParser, async (req, res) => {364router.post('/query', jsonParser, async (req, res) => {
374 try {365 try {
375 if (!req.body.collectionId || !req.body.searchText) {366 if (!req.body.collectionId || !req.body.searchText) {
src/prompt-converters.js+3 -0
@@ -267,11 +267,14 @@ function convertGooglePrompt(messages, model, useSysPrompt = false, charName = '
267 'gemini-1.5-flash',267 'gemini-1.5-flash',
268 'gemini-1.5-flash-latest',268 'gemini-1.5-flash-latest',
269 'gemini-1.5-flash-001',269 'gemini-1.5-flash-001',
270 'gemini-1.5-flash-002',
270 'gemini-1.5-flash-exp-0827',271 'gemini-1.5-flash-exp-0827',
271 'gemini-1.5-flash-8b-exp-0827',272 'gemini-1.5-flash-8b-exp-0827',
273 'gemini-1.5-flash-8b-exp-0924',
272 'gemini-1.5-pro',274 'gemini-1.5-pro',
273 'gemini-1.5-pro-latest',275 'gemini-1.5-pro-latest',
274 'gemini-1.5-pro-001',276 'gemini-1.5-pro-001',
277 'gemini-1.5-pro-002',
275 'gemini-1.5-pro-exp-0801',278 'gemini-1.5-pro-exp-0801',
276 'gemini-1.5-pro-exp-0827',279 'gemini-1.5-pro-exp-0827',
277 'gemini-1.0-pro-vision-latest',280 'gemini-1.0-pro-vision-latest',
src/users.js+62 -0
@@ -9,6 +9,8 @@ const storage = require('node-persist');
9const express = require('express');9const express = require('express');
10const mime = require('mime-types');10const mime = require('mime-types');
11const archiver = require('archiver');11const archiver = require('archiver');
12const writeFileAtomicSync = require('write-file-atomic').sync;
13const _ = require('lodash');
1214
13const { USER_DIRECTORY_TEMPLATE, DEFAULT_USER, PUBLIC_DIRECTORIES, SETTINGS_FILE } = require('./constants');15const { USER_DIRECTORY_TEMPLATE, DEFAULT_USER, PUBLIC_DIRECTORIES, SETTINGS_FILE } = require('./constants');
14const { getConfigValue, color, delay, setConfigValue, generateTimestamp } = require('./util');16const { getConfigValue, color, delay, setConfigValue, generateTimestamp } = require('./util');
@@ -83,6 +85,7 @@ const STORAGE_KEYS = {
83 * @property {string} files - The directory where the uploaded files are stored85 * @property {string} files - The directory where the uploaded files are stored
84 * @property {string} vectors - The directory where the vectors are stored86 * @property {string} vectors - The directory where the vectors are stored
85 * @property {string} backups - The directory where the backups are stored87 * @property {string} backups - The directory where the backups are stored
88 * @property {string} sysprompt - The directory where the system prompt data is stored
86 */89 */
8790
88/**91/**
@@ -323,6 +326,64 @@ async function migrateUserData() {
323 console.log(color.green('Migration completed!'));326 console.log(color.green('Migration completed!'));
324}327}
325328
329async function migrateSystemPrompts() {
330 /**
331 * Gets the default system prompts.
332 * @returns {Promise<any[]>} - The list of default system prompts
333 */
334 async function getDefaultSystemPrompts() {
335 try {
336 const { getContentOfType } = await import('./endpoints/content-manager.js');
337 return getContentOfType('sysprompt', 'json');
338 } catch {
339 return [];
340 }
341 }
342
343 const directories = await getUserDirectoriesList();
344 for (const directory of directories) {
345 try {
346 const migrateMarker = path.join(directory.sysprompt, '.migrated');
347 if (fs.existsSync(migrateMarker)) {
348 continue;
349 }
350 const backupsPath = path.join(directory.backups, '_sysprompt');
351 fs.mkdirSync(backupsPath, { recursive: true });
352 const defaultPrompts = await getDefaultSystemPrompts();
353 const instucts = fs.readdirSync(directory.instruct);
354 let migratedPrompts = [];
355 for (const instruct of instucts) {
356 const instructPath = path.join(directory.instruct, instruct);
357 const sysPromptPath = path.join(directory.sysprompt, instruct);
358 if (path.extname(instruct) === '.json' && !fs.existsSync(sysPromptPath)) {
359 const instructData = JSON.parse(fs.readFileSync(instructPath, 'utf8'));
360 if ('system_prompt' in instructData && 'name' in instructData) {
361 const backupPath = path.join(backupsPath, `${instructData.name}.json`);
362 fs.cpSync(instructPath, backupPath, { force: true });
363 const syspromptData = { name: instructData.name, content: instructData.system_prompt };
364 migratedPrompts.push(syspromptData);
365 delete instructData.system_prompt;
366 writeFileAtomicSync(instructPath, JSON.stringify(instructData, null, 4));
367 }
368 }
369 }
370 // Only leave unique contents
371 migratedPrompts = _.uniqBy(migratedPrompts, 'content');
372 // Only leave contents that are not in the default prompts
373 migratedPrompts = migratedPrompts.filter(x => !defaultPrompts.some(y => y.content === x.content));
374 for (const sysPromptData of migratedPrompts) {
375 sysPromptData.name = `[Migrated] ${sysPromptData.name}`;
376 const syspromptPath = path.join(directory.sysprompt, `${sysPromptData.name}.json`);
377 writeFileAtomicSync(syspromptPath, JSON.stringify(sysPromptData, null, 4));
378 console.log(`Migrated system prompt ${sysPromptData.name} for ${directory.root.split(path.sep).pop()}`);
379 }
380 writeFileAtomicSync(migrateMarker, '');
381 } catch (error) {
382 console.error('Error migrating system prompts:', error);
383 }
384 }
385}
386
326/**387/**
327 * Converts a user handle to a storage key.388 * Converts a user handle to a storage key.
328 * @param {string} handle User handle389 * @param {string} handle User handle
@@ -724,6 +785,7 @@ module.exports = {
724 requireLoginMiddleware,785 requireLoginMiddleware,
725 requireAdminMiddleware,786 requireAdminMiddleware,
726 migrateUserData,787 migrateUserData,
788 migrateSystemPrompts,
727 getPasswordSalt,789 getPasswordSalt,
728 getPasswordHash,790 getPasswordHash,
729 getCsrfSecret,791 getCsrfSecret,