Merge branch 'staging' into image-swipes

e2a2e3869e80649e6e0d478f86bafb721f78bd18

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

11 files changed, +53 -12Showing whitespace changes
CONTRIBUTING.md+5 -0
@@ -34,3 +34,8 @@
3434 - What did you do to achieve this?
3535 - How would a reviewer test the change?
36366. 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)
package-lock.json+4 -5
@@ -1391,12 +1391,11 @@
13911391 "license": "MIT"
13921392 },
13931393 "node_modules/axios": {
13941394 "version": "1.67.14",
13951395 "resolved": "https://registry.npmjs.org/axios/-/axios-1.67.14.tgz",
13961396 "integrity": "sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnSDukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/VG4I5yxig1pCEXE4gTWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==",
1397- "license": "MIT",
13981397 "dependencies": {
13991398 "follow-redirects": "^1.15.06",
14001399 "form-data": "^4.0.0",
14011400 "proxy-from-env": "^1.1.0"
14021401 }
public/index.html+2 -1
@@ -383,7 +383,7 @@
383383 Max Response Length (tokens)
384384 </div>
385385 <div class="wide100p">
386386 <input type="number" id="openai_max_tokens" name="openai_max_tokens" class="text_pole" min="501" max="800016384">
387387 </div>
388388 </div>
389389 <div class="range-block" data-source="openai,custom">
@@ -2573,6 +2573,7 @@
25732573 <option value="gpt-4o">gpt-4o</option>
25742574 <option value="gpt-4o-2024-08-06">gpt-4o-2024-08-06</option>
25752575 <option value="gpt-4o-2024-05-13">gpt-4o-2024-05-13</option>
2576+ <option value="chatgpt-4o-latest">chatgpt-4o-latest</option>
25762577 </optgroup>
25772578 <optgroup label="gpt-4o-mini">
25782579 <option value="gpt-4o-mini">gpt-4o-mini</option>
public/scripts/extensions/quick-reply/api/QuickReplyApi.js+6 -0
@@ -204,6 +204,7 @@ export class QuickReplyApi {
204204 * @param {boolean} [props.executeOnAi] whether to execute the quick reply after the AI has sent a message
205205 * @param {boolean} [props.executeOnChatChange] whether to execute the quick reply when a new chat is loaded
206206 * @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
207208 * @param {string} [props.automationId] when not empty, the quick reply will be executed when the WI with the given automation ID is activated
208209 * @returns {QuickReply} the new quick reply
209210 */
@@ -218,6 +219,7 @@ export class QuickReplyApi {
218219 executeOnAi,
219220 executeOnChatChange,
220221 executeOnGroupMemberDraft,
222+ executeOnNewChat,
221223 automationId,
222224 } = {}) {
223225 const set = this.getSetByName(setName);
@@ -236,6 +238,7 @@ export class QuickReplyApi {
236238 qr.executeOnAi = executeOnAi ?? false;
237239 qr.executeOnChatChange = executeOnChatChange ?? false;
238240 qr.executeOnGroupMemberDraft = executeOnGroupMemberDraft ?? false;
241+ qr.executeOnNewChat = executeOnNewChat ?? false;
239242 qr.automationId = automationId ?? '';
240243 qr.onUpdate();
241244 return qr;
@@ -258,6 +261,7 @@ export class QuickReplyApi {
258261 * @param {boolean} [props.executeOnAi] whether to execute the quick reply after the AI has sent a message
259262 * @param {boolean} [props.executeOnChatChange] whether to execute the quick reply when a new chat is loaded
260263 * @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
261265 * @param {string} [props.automationId] when not empty, the quick reply will be executed when the WI with the given automation ID is activated
262266 * @returns {QuickReply} the altered quick reply
263267 */
@@ -273,6 +277,7 @@ export class QuickReplyApi {
273277 executeOnAi,
274278 executeOnChatChange,
275279 executeOnGroupMemberDraft,
280+ executeOnNewChat,
276281 automationId,
277282 } = {}) {
278283 const qr = this.getQrByLabel(setName, label);
@@ -290,6 +295,7 @@ export class QuickReplyApi {
290295 qr.executeOnAi = executeOnAi ?? qr.executeOnAi;
291296 qr.executeOnChatChange = executeOnChatChange ?? qr.executeOnChatChange;
292297 qr.executeOnGroupMemberDraft = executeOnGroupMemberDraft ?? qr.executeOnGroupMemberDraft;
298+ qr.executeOnNewChat = executeOnNewChat ?? qr.executeOnNewChat;
293299 qr.automationId = automationId ?? qr.automationId;
294300 qr.onUpdate();
295301 return qr;
public/scripts/extensions/quick-reply/html/qrEditor.html+4 -0
@@ -109,6 +109,10 @@
109109 <span><i class="fa-solid fa-fw fa-message"></i><span data-i18n="Execute on chat change">Execute on chat change</span></span>
110110 </label>
111111 <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">
112116 <input type="checkbox" id="qr--executeOnGroupMemberDraft">
113117 <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>
114118 </label>
public/scripts/extensions/quick-reply/index.js+6 -0
@@ -105,6 +105,7 @@ const loadSets = async () => {
105105 qr.executeOnAi = slot.autoExecute_botMessage ?? false;
106106 qr.executeOnChatChange = slot.autoExecute_chatLoad ?? false;
107107 qr.executeOnGroupMemberDraft = slot.autoExecute_groupMemberDraft ?? false;
108+ qr.executeOnNewChat = slot.autoExecute_newChat ?? false;
108109 qr.automationId = slot.automationId ?? '';
109110 qr.contextList = (slot.contextMenu ?? []).map(it=>({
110111 set: it.preset,
@@ -260,3 +261,8 @@ const onWIActivation = async (entries) => {
260261 await autoExec.handleWIActivation(entries);
261262};
262263eventSource.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));
public/scripts/extensions/quick-reply/src/AutoExecuteHandler.js+9 -0
@@ -83,6 +83,15 @@ export class AutoExecuteHandler {
8383 await this.performAutoExecute(qrList);
8484 }
8585
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+
8695 /**
8796 * @param {any[]} entries Set of activated entries
8897 */
public/scripts/extensions/quick-reply/src/QuickReply.js+8 -0
@@ -44,6 +44,7 @@ export class QuickReply {
4444 /**@type {boolean}*/ executeOnAi = false;
4545 /**@type {boolean}*/ executeOnChatChange = false;
4646 /**@type {boolean}*/ executeOnGroupMemberDraft = false;
47+ /**@type {boolean}*/ executeOnNewChat = false;
4748 /**@type {string}*/ automationId = '';
4849
4950 /**@type {function}*/ onExecute;
@@ -1061,6 +1062,13 @@ export class QuickReply {
10611062 this.updateContext();
10621063 });
10631064 /**@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}*/
10641072 const automationId = dom.querySelector('#qr--automationId');
10651073 automationId.value = this.automationId;
10661074 automationId.addEventListener('input', () => {
public/scripts/openai.js+2 -2
@@ -3921,7 +3921,7 @@ function getMaxContextOpenAI(value) {
39213921 if (oai_settings.max_context_unlocked) {
39223922 return unlocked_max;
39233923 }
39243924 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')) {
39253925 return max_128k;
39263926 }
39273927 else if (value.includes('gpt-3.5-turbo-1106')) {
@@ -4768,7 +4768,7 @@ export function isImageInliningSupported() {
47684768
47694769 switch (oai_settings.chat_completion_source) {
47704770 case chat_completion_sources.OPENAI:
47714771 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'));
47724772 case chat_completion_sources.MAKERSUITE:
47734773 return visionSupportedModels.some(model => oai_settings.google_model.includes(model));
47744774 case chat_completion_sources.CLAUDE:
src/endpoints/tokenizers.js+4 -0
@@ -268,6 +268,10 @@ function getTokenizerModel(requestModel) {
268268 return 'gpt-4o';
269269 }
270270
271+ if (requestModel.includes('chatgpt-4o-latest')) {
272+ return 'gpt-4o';
273+ }
274+
271275 if (requestModel.includes('gpt-4-32k')) {
272276 return 'gpt-4-32k';
273277 }
tests/package-lock.json+3 -4
@@ -1653,10 +1653,9 @@
16531653 "license": "MIT"
16541654 },
16551655 "node_modules/axios": {
16561656 "version": "1.7.24",
16571657 "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.24.tgz",
16581658 "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDhDukmaFRnY6AzAALSH4J2M3k6PkaC+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0RmgwMfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==",
1659- "license": "MIT",
16601659 "dependencies": {
16611660 "follow-redirects": "^1.15.6",
16621661 "form-data": "^4.0.0",