Add Harmony template (#4431) * Add Harmony template * Add Thinking instruct variant and reasoning template * Specify template hash from unsloth * Add ggml-org template hash

e37b709e96c8fc3fdf38f696707ab014cb947f28

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

Signed
7 files changed, +108 -22Showing whitespace changes
default/content/index.json+16 -0
@@ -838,5 +838,21 @@
838 {838 {
839 "filename": "presets/context/Moonshot AI.json",839 "filename": "presets/context/Moonshot AI.json",
840 "type": "context"840 "type": "context"
841 },
842 {
843 "filename": "presets/context/OpenAI Harmony.json",
844 "type": "context"
845 },
846 {
847 "filename": "presets/instruct/OpenAI Harmony.json",
848 "type": "instruct"
849 },
850 {
851 "filename": "presets/instruct/OpenAI Harmony (Thinking).json",
852 "type": "instruct"
853 },
854 {
855 "filename": "presets/reasoning/OpenAI Harmony.json",
856 "type": "reasoning"
841 }857 }
842]858]
default/content/presets/context/OpenAI Harmony.json+14 -0
@@ -0,0 +1,14 @@
1{
2 "story_string": "{{#if anchorBefore}}{{anchorBefore}}\n{{/if}}{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{personality}}\n{{/if}}{{#if scenario}}{{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}{{#if anchorAfter}}{{anchorAfter}}\n{{/if}}{{trim}}",
3 "example_separator": "",
4 "chat_start": "",
5 "use_stop_strings": false,
6 "names_as_stop_strings": true,
7 "story_string_position": 0,
8 "story_string_depth": 1,
9 "story_string_role": 0,
10 "always_force_name2": true,
11 "trim_sentences": false,
12 "single_line": false,
13 "name": "OpenAI Harmony"
14}
default/content/presets/instruct/OpenAI Harmony (Thinking).json+25 -0
@@ -0,0 +1,25 @@
1{
2 "input_sequence": "<|start|>user<|message|>",
3 "output_sequence": "<|start|>assistant<|channel|>final<|message|>",
4 "last_output_sequence": "{{noop}}",
5 "system_sequence": "<|start|>developer<|message|>",
6 "stop_sequence": "",
7 "wrap": false,
8 "macro": true,
9 "activation_regex": "",
10 "first_output_sequence": "",
11 "skip_examples": false,
12 "output_suffix": "<|end|>",
13 "input_suffix": "<|end|>",
14 "system_suffix": "<|end|>",
15 "user_alignment_message": "",
16 "system_same_as_user": false,
17 "last_system_sequence": "",
18 "first_input_sequence": "",
19 "last_input_sequence": "",
20 "names_behavior": "force",
21 "sequences_as_stop_strings": false,
22 "story_string_prefix": "<|start|>system<|message|>",
23 "story_string_suffix": "<|end|>",
24 "name": "OpenAI Harmony (Thinking)"
25}
default/content/presets/instruct/OpenAI Harmony.json+25 -0
@@ -0,0 +1,25 @@
1{
2 "input_sequence": "<|start|>user<|message|>",
3 "output_sequence": "<|start|>assistant<|channel|>final<|message|>",
4 "last_output_sequence": "",
5 "system_sequence": "<|start|>developer<|message|>",
6 "stop_sequence": "",
7 "wrap": false,
8 "macro": true,
9 "activation_regex": "",
10 "first_output_sequence": "",
11 "skip_examples": false,
12 "output_suffix": "<|end|>",
13 "input_suffix": "<|end|>",
14 "system_suffix": "<|end|>",
15 "user_alignment_message": "",
16 "system_same_as_user": false,
17 "last_system_sequence": "",
18 "first_input_sequence": "",
19 "last_input_sequence": "",
20 "names_behavior": "force",
21 "sequences_as_stop_strings": true,
22 "story_string_prefix": "<|start|>system<|message|>",
23 "story_string_suffix": "<|end|>",
24 "name": "OpenAI Harmony"
25}
default/content/presets/reasoning/OpenAI Harmony.json+6 -0
@@ -0,0 +1,6 @@
1{
2 "prefix": "<|start|>assistant<|channel|>analysis<|message|>",
3 "suffix": "<|start|>assistant<|channel|>final<|message|>",
4 "separator": "",
5 "name": "OpenAI Harmony"
6}
public/script.js+11 -22
@@ -5522,30 +5522,19 @@ export function cleanUpMessage({ getMessage, isImpersonate, isContinue, displayI
5522 getMessage = getMessage.substring(0, getMessage.indexOf(power_user.instruct.input_sequence));5522 getMessage = getMessage.substring(0, getMessage.indexOf(power_user.instruct.input_sequence));
5523 }5523 }
5524 }5524 }
5525 if (isInstruct && power_user.instruct.input_sequence && isImpersonate) {5525
5526 //getMessage = getMessage.replaceAll(power_user.instruct.input_sequence, '');5526 // Remove instruct sequences leaking to the output
5527 power_user.instruct.input_sequence.split('\n')5527 if (isInstruct && power_user.instruct.sequences_as_stop_strings) {
5528 .filter(line => line.trim() !== '')5528 const sequences = [
5529 .forEach(line => {5529 { value: power_user.instruct.input_sequence, apply: isImpersonate && isNotEmpty(power_user.instruct.input_sequence) },
5530 getMessage = getMessage.replaceAll(line, '');5530 { value: power_user.instruct.output_sequence, apply: !isImpersonate && isNotEmpty(power_user.instruct.output_sequence) },
5531 });5531 { value: power_user.instruct.last_output_sequence, apply: !isImpersonate && isNotEmpty(power_user.instruct.last_output_sequence) },
5532 }5532 ];
5533 if (isInstruct && power_user.instruct.output_sequence && !isImpersonate) {5533 for (const seq of sequences.filter(s => s.apply)) {
5534 //getMessage = getMessage.replaceAll(power_user.instruct.output_sequence, '');5534 seq.value.split('\n').filter(line => line.trim() !== '').forEach(line => { getMessage = getMessage.replaceAll(line, ''); });
5535 power_user.instruct.output_sequence.split('\n')
5536 .filter(line => line.trim() !== '')
5537 .forEach(line => {
5538 getMessage = getMessage.replaceAll(line, '');
5539 });
5540 }5535 }
5541 if (isInstruct && power_user.instruct.last_output_sequence && !isImpersonate) {
5542 //getMessage = getMessage.replaceAll(power_user.instruct.last_output_sequence, '');
5543 power_user.instruct.last_output_sequence.split('\n')
5544 .filter(line => line.trim() !== '')
5545 .forEach(line => {
5546 getMessage = getMessage.replaceAll(line, '');
5547 });
5548 }5536 }
5537
5549 // clean-up group message from excessive generations5538 // clean-up group message from excessive generations
5550 if (selected_group) {5539 if (selected_group) {
5551 getMessage = cleanGroupMessage(getMessage);5540 getMessage = cleanGroupMessage(getMessage);
public/scripts/chat-templates.js+11 -0
@@ -90,10 +90,21 @@ const hash_derivations = {
90 'aab20feb9bc6881f941ea649356130ffbc4943b3c2577c0991e1fba90de5a0fc':90 'aab20feb9bc6881f941ea649356130ffbc4943b3c2577c0991e1fba90de5a0fc':
91 'Moonshot AI'91 'Moonshot AI'
92 ,92 ,
93
94 // gpt-oss (unsloth)
95 '70da0d2348e40aaf8dad05f04a316835fd10547bd7e3392ce337e4c79ba91c01':
96 'OpenAI Harmony'
97 ,
98
99 // gpt-oss (ggml-org)
100 'a4c9919cbbd4acdd51ccffe22da049264b1b73e59055fa58811a99efbd7c8146':
101 'OpenAI Harmony'
102 ,
93};103};
94104
95const substr_derivations = [105const substr_derivations = [
96 ['Moonshot AI', ['<|im_user|>user<|im_middle|>', '<|im_assistant|>assistant<|im_middle|>', '<|im_end|>']],106 ['Moonshot AI', ['<|im_user|>user<|im_middle|>', '<|im_assistant|>assistant<|im_middle|>', '<|im_end|>']],
107 ['OpenAI Harmony', ['<|start|>user<|message|>', '<|start|>assistant<|channel|>final<|message|>', '<|end|>']],
97108
98 // Generic cases109 // Generic cases
99 ['ChatML', ['<|im_start|>user', '<|im_start|>assistant', '<|im_end|>']],110 ['ChatML', ['<|im_start|>user', '<|im_start|>assistant', '<|im_end|>']],