Merge branch 'staging' into image-swipes
| @@ -34,3 +34,8 @@ | |||
| 34 | - What did you do to achieve this? | 34 | - What did you do to achieve this? |
| 35 | - How would a reviewer test the change? | 35 | - How would a reviewer test the change? |
| 36 | 6. Mind the license. Your contributions will be licensed under the GNU Affero General Public License. If you don't know what that implies, consult your lawyer. | 36 | 6. Mind the license. Your contributions will be licensed under the GNU Affero General Public License. If you don't know what that implies, consult your lawyer. |
| 37 | |||
| 38 | ## Further reading | ||
| 39 | |||
| 40 | 1. [How to write UI extensions](https://docs.sillytavern.app/for-contributors/writing-extensions/) | ||
| 41 | 2. [How to write server plugins](https://docs.sillytavern.app/for-contributors/server-plugins) | ||
| @@ -1391,12 +1391,11 @@ | |||
| 1391 | "license": "MIT" | 1391 | "license": "MIT" |
| 1392 | }, | 1392 | }, |
| 1393 | "node_modules/axios": { | 1393 | "node_modules/axios": { |
| 1394 | "version": "1.6.1", | 1394 | "version": "1.7.4", |
| 1395 | "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.1.tgz", | 1395 | "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", |
| 1396 | "integrity": "sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnS/VG4I5yxig1pCEXE4g==", | 1396 | "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", |
| 1397 | "license": "MIT", | ||
| 1398 | "dependencies": { | 1397 | "dependencies": { |
| 1399 | "follow-redirects": "^1.15.0", | 1398 | "follow-redirects": "^1.15.6", |
| 1400 | "form-data": "^4.0.0", | 1399 | "form-data": "^4.0.0", |
| 1401 | "proxy-from-env": "^1.1.0" | 1400 | "proxy-from-env": "^1.1.0" |
| 1402 | } | 1401 | } |
| @@ -383,7 +383,7 @@ | |||
| 383 | Max Response Length (tokens) | 383 | Max Response Length (tokens) |
| 384 | </div> | 384 | </div> |
| 385 | <div class="wide100p"> | 385 | <div class="wide100p"> |
| 386 | <input type="number" id="openai_max_tokens" name="openai_max_tokens" class="text_pole" min="50" max="8000"> | 386 | <input type="number" id="openai_max_tokens" name="openai_max_tokens" class="text_pole" min="1" max="16384"> |
| 387 | </div> | 387 | </div> |
| 388 | </div> | 388 | </div> |
| 389 | <div class="range-block" data-source="openai,custom"> | 389 | <div class="range-block" data-source="openai,custom"> |
| @@ -2573,6 +2573,7 @@ | |||
| 2573 | <option value="gpt-4o">gpt-4o</option> | 2573 | <option value="gpt-4o">gpt-4o</option> |
| 2574 | <option value="gpt-4o-2024-08-06">gpt-4o-2024-08-06</option> | 2574 | <option value="gpt-4o-2024-08-06">gpt-4o-2024-08-06</option> |
| 2575 | <option value="gpt-4o-2024-05-13">gpt-4o-2024-05-13</option> | 2575 | <option value="gpt-4o-2024-05-13">gpt-4o-2024-05-13</option> |
| 2576 | <option value="chatgpt-4o-latest">chatgpt-4o-latest</option> | ||
| 2576 | </optgroup> | 2577 | </optgroup> |
| 2577 | <optgroup label="gpt-4o-mini"> | 2578 | <optgroup label="gpt-4o-mini"> |
| 2578 | <option value="gpt-4o-mini">gpt-4o-mini</option> | 2579 | <option value="gpt-4o-mini">gpt-4o-mini</option> |
| @@ -204,6 +204,7 @@ export class QuickReplyApi { | |||
| 204 | * @param {boolean} [props.executeOnAi] whether to execute the quick reply after the AI has sent a message | 204 | * @param {boolean} [props.executeOnAi] whether to execute the quick reply after the AI has sent a message |
| 205 | * @param {boolean} [props.executeOnChatChange] whether to execute the quick reply when a new chat is loaded | 205 | * @param {boolean} [props.executeOnChatChange] whether to execute the quick reply when a new chat is loaded |
| 206 | * @param {boolean} [props.executeOnGroupMemberDraft] whether to execute the quick reply when a group member is selected | 206 | * @param {boolean} [props.executeOnGroupMemberDraft] whether to execute the quick reply when a group member is selected |
| 207 | * @param {boolean} [props.executeOnNewChat] whether to execute the quick reply when a new chat is created | ||
| 207 | * @param {string} [props.automationId] when not empty, the quick reply will be executed when the WI with the given automation ID is activated | 208 | * @param {string} [props.automationId] when not empty, the quick reply will be executed when the WI with the given automation ID is activated |
| 208 | * @returns {QuickReply} the new quick reply | 209 | * @returns {QuickReply} the new quick reply |
| 209 | */ | 210 | */ |
| @@ -218,6 +219,7 @@ export class QuickReplyApi { | |||
| 218 | executeOnAi, | 219 | executeOnAi, |
| 219 | executeOnChatChange, | 220 | executeOnChatChange, |
| 220 | executeOnGroupMemberDraft, | 221 | executeOnGroupMemberDraft, |
| 222 | executeOnNewChat, | ||
| 221 | automationId, | 223 | automationId, |
| 222 | } = {}) { | 224 | } = {}) { |
| 223 | const set = this.getSetByName(setName); | 225 | const set = this.getSetByName(setName); |
| @@ -236,6 +238,7 @@ export class QuickReplyApi { | |||
| 236 | qr.executeOnAi = executeOnAi ?? false; | 238 | qr.executeOnAi = executeOnAi ?? false; |
| 237 | qr.executeOnChatChange = executeOnChatChange ?? false; | 239 | qr.executeOnChatChange = executeOnChatChange ?? false; |
| 238 | qr.executeOnGroupMemberDraft = executeOnGroupMemberDraft ?? false; | 240 | qr.executeOnGroupMemberDraft = executeOnGroupMemberDraft ?? false; |
| 241 | qr.executeOnNewChat = executeOnNewChat ?? false; | ||
| 239 | qr.automationId = automationId ?? ''; | 242 | qr.automationId = automationId ?? ''; |
| 240 | qr.onUpdate(); | 243 | qr.onUpdate(); |
| 241 | return qr; | 244 | return qr; |
| @@ -258,6 +261,7 @@ export class QuickReplyApi { | |||
| 258 | * @param {boolean} [props.executeOnAi] whether to execute the quick reply after the AI has sent a message | 261 | * @param {boolean} [props.executeOnAi] whether to execute the quick reply after the AI has sent a message |
| 259 | * @param {boolean} [props.executeOnChatChange] whether to execute the quick reply when a new chat is loaded | 262 | * @param {boolean} [props.executeOnChatChange] whether to execute the quick reply when a new chat is loaded |
| 260 | * @param {boolean} [props.executeOnGroupMemberDraft] whether to execute the quick reply when a group member is selected | 263 | * @param {boolean} [props.executeOnGroupMemberDraft] whether to execute the quick reply when a group member is selected |
| 264 | * @param {boolean} [props.executeOnNewChat] whether to execute the quick reply when a new chat is created | ||
| 261 | * @param {string} [props.automationId] when not empty, the quick reply will be executed when the WI with the given automation ID is activated | 265 | * @param {string} [props.automationId] when not empty, the quick reply will be executed when the WI with the given automation ID is activated |
| 262 | * @returns {QuickReply} the altered quick reply | 266 | * @returns {QuickReply} the altered quick reply |
| 263 | */ | 267 | */ |
| @@ -273,6 +277,7 @@ export class QuickReplyApi { | |||
| 273 | executeOnAi, | 277 | executeOnAi, |
| 274 | executeOnChatChange, | 278 | executeOnChatChange, |
| 275 | executeOnGroupMemberDraft, | 279 | executeOnGroupMemberDraft, |
| 280 | executeOnNewChat, | ||
| 276 | automationId, | 281 | automationId, |
| 277 | } = {}) { | 282 | } = {}) { |
| 278 | const qr = this.getQrByLabel(setName, label); | 283 | const qr = this.getQrByLabel(setName, label); |
| @@ -290,6 +295,7 @@ export class QuickReplyApi { | |||
| 290 | qr.executeOnAi = executeOnAi ?? qr.executeOnAi; | 295 | qr.executeOnAi = executeOnAi ?? qr.executeOnAi; |
| 291 | qr.executeOnChatChange = executeOnChatChange ?? qr.executeOnChatChange; | 296 | qr.executeOnChatChange = executeOnChatChange ?? qr.executeOnChatChange; |
| 292 | qr.executeOnGroupMemberDraft = executeOnGroupMemberDraft ?? qr.executeOnGroupMemberDraft; | 297 | qr.executeOnGroupMemberDraft = executeOnGroupMemberDraft ?? qr.executeOnGroupMemberDraft; |
| 298 | qr.executeOnNewChat = executeOnNewChat ?? qr.executeOnNewChat; | ||
| 293 | qr.automationId = automationId ?? qr.automationId; | 299 | qr.automationId = automationId ?? qr.automationId; |
| 294 | qr.onUpdate(); | 300 | qr.onUpdate(); |
| 295 | return qr; | 301 | return qr; |
| @@ -109,6 +109,10 @@ | |||
| 109 | <span><i class="fa-solid fa-fw fa-message"></i><span data-i18n="Execute on chat change">Execute on chat change</span></span> | 109 | <span><i class="fa-solid fa-fw fa-message"></i><span data-i18n="Execute on chat change">Execute on chat change</span></span> |
| 110 | </label> | 110 | </label> |
| 111 | <label class="checkbox_label"> | 111 | <label class="checkbox_label"> |
| 112 | <input type="checkbox" id="qr--executeOnNewChat"> | ||
| 113 | <span><i class="fa-solid fa-fw fa-comments"></i><span data-i18n="Execute on new chat">Execute on new chat</span></span> | ||
| 114 | </label> | ||
| 115 | <label class="checkbox_label"> | ||
| 112 | <input type="checkbox" id="qr--executeOnGroupMemberDraft"> | 116 | <input type="checkbox" id="qr--executeOnGroupMemberDraft"> |
| 113 | <span><i class="fa-solid fa-fw fa-people-group"></i><span data-i18n="Execute on group member draft">Execute on group member draft</span></span> | 117 | <span><i class="fa-solid fa-fw fa-people-group"></i><span data-i18n="Execute on group member draft">Execute on group member draft</span></span> |
| 114 | </label> | 118 | </label> |
| @@ -105,6 +105,7 @@ const loadSets = async () => { | |||
| 105 | qr.executeOnAi = slot.autoExecute_botMessage ?? false; | 105 | qr.executeOnAi = slot.autoExecute_botMessage ?? false; |
| 106 | qr.executeOnChatChange = slot.autoExecute_chatLoad ?? false; | 106 | qr.executeOnChatChange = slot.autoExecute_chatLoad ?? false; |
| 107 | qr.executeOnGroupMemberDraft = slot.autoExecute_groupMemberDraft ?? false; | 107 | qr.executeOnGroupMemberDraft = slot.autoExecute_groupMemberDraft ?? false; |
| 108 | qr.executeOnNewChat = slot.autoExecute_newChat ?? false; | ||
| 108 | qr.automationId = slot.automationId ?? ''; | 109 | qr.automationId = slot.automationId ?? ''; |
| 109 | qr.contextList = (slot.contextMenu ?? []).map(it=>({ | 110 | qr.contextList = (slot.contextMenu ?? []).map(it=>({ |
| 110 | set: it.preset, | 111 | set: it.preset, |
| @@ -260,3 +261,8 @@ const onWIActivation = async (entries) => { | |||
| 260 | await autoExec.handleWIActivation(entries); | 261 | await autoExec.handleWIActivation(entries); |
| 261 | }; | 262 | }; |
| 262 | eventSource.on(event_types.WORLD_INFO_ACTIVATED, (...args) => executeIfReadyElseQueue(onWIActivation, args)); | 263 | eventSource.on(event_types.WORLD_INFO_ACTIVATED, (...args) => executeIfReadyElseQueue(onWIActivation, args)); |
| 264 | |||
| 265 | const onNewChat = async () => { | ||
| 266 | await autoExec.handleNewChat(); | ||
| 267 | }; | ||
| 268 | eventSource.on(event_types.CHAT_CREATED, (...args) => executeIfReadyElseQueue(onNewChat, args)); | ||
| @@ -83,6 +83,15 @@ export class AutoExecuteHandler { | |||
| 83 | await this.performAutoExecute(qrList); | 83 | await this.performAutoExecute(qrList); |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | async handleNewChat() { | ||
| 87 | if (!this.checkExecute()) return; | ||
| 88 | const qrList = [ | ||
| 89 | ...this.settings.config.setList.map(link=>link.set.qrList.filter(qr=>qr.executeOnNewChat)).flat(), | ||
| 90 | ...(this.settings.chatConfig?.setList?.map(link=>link.set.qrList.filter(qr=>qr.executeOnNewChat))?.flat() ?? []), | ||
| 91 | ]; | ||
| 92 | await this.performAutoExecute(qrList); | ||
| 93 | } | ||
| 94 | |||
| 86 | /** | 95 | /** |
| 87 | * @param {any[]} entries Set of activated entries | 96 | * @param {any[]} entries Set of activated entries |
| 88 | */ | 97 | */ |
| @@ -44,6 +44,7 @@ export class QuickReply { | |||
| 44 | /**@type {boolean}*/ executeOnAi = false; | 44 | /**@type {boolean}*/ executeOnAi = false; |
| 45 | /**@type {boolean}*/ executeOnChatChange = false; | 45 | /**@type {boolean}*/ executeOnChatChange = false; |
| 46 | /**@type {boolean}*/ executeOnGroupMemberDraft = false; | 46 | /**@type {boolean}*/ executeOnGroupMemberDraft = false; |
| 47 | /**@type {boolean}*/ executeOnNewChat = false; | ||
| 47 | /**@type {string}*/ automationId = ''; | 48 | /**@type {string}*/ automationId = ''; |
| 48 | 49 | ||
| 49 | /**@type {function}*/ onExecute; | 50 | /**@type {function}*/ onExecute; |
| @@ -1061,6 +1062,13 @@ export class QuickReply { | |||
| 1061 | this.updateContext(); | 1062 | this.updateContext(); |
| 1062 | }); | 1063 | }); |
| 1063 | /**@type {HTMLInputElement}*/ | 1064 | /**@type {HTMLInputElement}*/ |
| 1065 | const executeOnNewChat = dom.querySelector('#qr--executeOnNewChat'); | ||
| 1066 | executeOnNewChat.checked = this.executeOnNewChat; | ||
| 1067 | executeOnNewChat.addEventListener('click', ()=>{ | ||
| 1068 | this.executeOnNewChat = executeOnNewChat.checked; | ||
| 1069 | this.updateContext(); | ||
| 1070 | }); | ||
| 1071 | /**@type {HTMLInputElement}*/ | ||
| 1064 | const automationId = dom.querySelector('#qr--automationId'); | 1072 | const automationId = dom.querySelector('#qr--automationId'); |
| 1065 | automationId.value = this.automationId; | 1073 | automationId.value = this.automationId; |
| 1066 | automationId.addEventListener('input', () => { | 1074 | automationId.addEventListener('input', () => { |
| @@ -3921,7 +3921,7 @@ function getMaxContextOpenAI(value) { | |||
| 3921 | if (oai_settings.max_context_unlocked) { | 3921 | if (oai_settings.max_context_unlocked) { |
| 3922 | return unlocked_max; | 3922 | return unlocked_max; |
| 3923 | } | 3923 | } |
| 3924 | else if (value.includes('gpt-4-turbo') || value.includes('gpt-4o') || value.includes('gpt-4-1106') || value.includes('gpt-4-0125') || value.includes('gpt-4-vision')) { | 3924 | else if (value.includes('chatgpt-4o-latest') || value.includes('gpt-4-turbo') || value.includes('gpt-4o') || value.includes('gpt-4-1106') || value.includes('gpt-4-0125') || value.includes('gpt-4-vision')) { |
| 3925 | return max_128k; | 3925 | return max_128k; |
| 3926 | } | 3926 | } |
| 3927 | else if (value.includes('gpt-3.5-turbo-1106')) { | 3927 | else if (value.includes('gpt-3.5-turbo-1106')) { |
| @@ -4768,7 +4768,7 @@ export function isImageInliningSupported() { | |||
| 4768 | 4768 | ||
| 4769 | switch (oai_settings.chat_completion_source) { | 4769 | switch (oai_settings.chat_completion_source) { |
| 4770 | case chat_completion_sources.OPENAI: | 4770 | case chat_completion_sources.OPENAI: |
| 4771 | return visionSupportedModels.some(model => oai_settings.openai_model.includes(model) && !oai_settings.openai_model.includes('gpt-4-turbo-preview')); | 4771 | return visionSupportedModels.some(model => oai_settings.openai_model.includes(model) && !oai_settings.openai_model.includes('chatgpt-4o-latest') && !oai_settings.openai_model.includes('gpt-4-turbo-preview')); |
| 4772 | case chat_completion_sources.MAKERSUITE: | 4772 | case chat_completion_sources.MAKERSUITE: |
| 4773 | return visionSupportedModels.some(model => oai_settings.google_model.includes(model)); | 4773 | return visionSupportedModels.some(model => oai_settings.google_model.includes(model)); |
| 4774 | case chat_completion_sources.CLAUDE: | 4774 | case chat_completion_sources.CLAUDE: |
| @@ -268,6 +268,10 @@ function getTokenizerModel(requestModel) { | |||
| 268 | return 'gpt-4o'; | 268 | return 'gpt-4o'; |
| 269 | } | 269 | } |
| 270 | 270 | ||
| 271 | if (requestModel.includes('chatgpt-4o-latest')) { | ||
| 272 | return 'gpt-4o'; | ||
| 273 | } | ||
| 274 | |||
| 271 | if (requestModel.includes('gpt-4-32k')) { | 275 | if (requestModel.includes('gpt-4-32k')) { |
| 272 | return 'gpt-4-32k'; | 276 | return 'gpt-4-32k'; |
| 273 | } | 277 | } |
| @@ -1653,10 +1653,9 @@ | |||
| 1653 | "license": "MIT" | 1653 | "license": "MIT" |
| 1654 | }, | 1654 | }, |
| 1655 | "node_modules/axios": { | 1655 | "node_modules/axios": { |
| 1656 | "version": "1.7.2", | 1656 | "version": "1.7.4", |
| 1657 | "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", | 1657 | "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", |
| 1658 | "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", | 1658 | "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", |
| 1659 | "license": "MIT", | ||
| 1660 | "dependencies": { | 1659 | "dependencies": { |
| 1661 | "follow-redirects": "^1.15.6", | 1660 | "follow-redirects": "^1.15.6", |
| 1662 | "form-data": "^4.0.0", | 1661 | "form-data": "^4.0.0", |