Removed 87 redundant `chat[chat.length - 1]` lookups. (#4963) * Removed redundant `chat[chat.length - 1]` lookups. * Readability. Don't chat[chat.push({}) - 1];. * Chat can't be empty. https://github.com/SillyTavern/SillyTavern/pull/4963#discussion_r2663006489 * Fixed mixup: https://github.com/SillyTavern/SillyTavern/pull/4963#discussion_r2663000183 * Rename it back to item * Add early return on empty chat. * Fix swipe assignment to use item message instead of last message --------- Co-authored-by: user <user@exmaple.com> Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>

ae5f69585b847e3a0f8e0b3b8d9f046edb070864

DeclineThyself <235079501+DeclineThyself@users.noreply.github.com>

Signed
2 files changed, +100 -88Ignore whitespace
public/script.js+91 -83
@@ -1619,13 +1619,14 @@ export async function sendTextareaMessage() {
16191619 // "Continue on send" is activated when the user hits "send" (or presses enter) on an empty chat box, and the last
16201620 // message was sent from a character (not the user or the system).
16211621 const textareaText = String($('#send_textarea').val());
1622+ const lastMessage = chat[chat.length - 1];
16221623 if (power_user.continue_on_send &&
16231624 !hasPendingFileAttachment() &&
16241625 !textareaText &&
16251626 !selected_group &&
16261627 chat.length &&
16271628 !chat[chat.length - 1]lastMessage['is_user'] &&
16281629 !chat[chat.length - 1]lastMessage['is_system']
16291630 ) {
16301631 generateType = 'continue';
16311632 }
@@ -4191,6 +4192,8 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
41914192 return Promise.resolve();
41924193 }
41934194
4195+ const lastMessage = chat[chat.length - 1];
4196+
41944197 let textareaText;
41954198 if (type !== 'regenerate' && type !== 'swipe' && type !== 'quiet' && !isImpersonate && !dryRun) {
41964199 is_send_press = true;
@@ -4198,7 +4201,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
41984201 $('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles: true }));
41994202 } else {
42004203 textareaText = '';
42014204 if (chat.length && chat[chat.length - 1]lastMessage['is_user']) {
42024205 //do nothing? why does this check exist?
42034206 }
42044207 else if (type !== 'quiet' && type !== 'swipe' && !isImpersonate && !dryRun && chat.length) {
@@ -4212,13 +4215,13 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
42124215
42134216 // Rewrite the generation timer to account for the time passed for all the continuations.
42144217 if (isContinue && chat.length) {
42154218 const prevFinished = chat[chat.length - 1]lastMessage['gen_finished'];
42164219 const prevStarted = chat[chat.length - 1]lastMessage['gen_started'];
42174220
42184221 if (prevFinished && prevStarted) {
42194222 const timePassed = Number(prevFinished) - Number(prevStarted);
42204223 generation_started = new Date(Date.now() - timePassed);
42214224 chat[chat.length - 1]lastMessage['gen_started'] = generation_started;
42224225 }
42234226 }
42244227
@@ -6387,18 +6390,20 @@ export async function saveReply({ type, getMessage, fromStreaming = false, title
63876390 [type, getMessage, fromStreaming, title, swipes, reasoning, imageUrls, reasoningSignature] = arguments;
63886391 }
63896392
6390- if (type != 'append' && type != 'continue' && type != 'appendFinal' && chat.length && (chat[chat.length - 1]['swipe_id'] === undefined ||
6393+ const lastMessage = chat[chat.length - 1];
6391- chat[chat.length - 1]['is_user'])) {
6394+
6395+ if (type != 'append' && type != 'continue' && type != 'appendFinal' && chat.length && (lastMessage['swipe_id'] === undefined ||
6396+ lastMessage['is_user'])) {
63926397 type = 'normal';
63936398 }
63946399
63956400 if (chat.length && (!chat[chat.length - 1]lastMessage['extra'] || typeof chat[chat.length - 1]lastMessage['extra'] !== 'object')) {
63966401 chat[chat.length - 1]lastMessage['extra'] = {};
63976402 }
63986403
63996404 // Coerce null/undefined to empty string
64006405 if (chat.length && !chat[chat.length - 1]lastMessage['extra']['reasoning']) {
64016406 chat[chat.length - 1]lastMessage['extra']['reasoning'] = '';
64026407 }
64036408
64046409 if (!reasoning) {
@@ -6408,70 +6413,70 @@ export async function saveReply({ type, getMessage, fromStreaming = false, title
64086413 let oldMessage = '';
64096414 const generationFinished = new Date();
64106415 if (type === 'swipe') {
64116416 oldMessage = chat[chat.length - 1]lastMessage['mes'];
64126417 chat[chat.length - 1]lastMessage['swipes'].length++;
64136418 if (chat[chat.length - 1]lastMessage['swipe_id'] === chat[chat.length - 1]lastMessage['swipes'].length - 1) {
64146419 chat[chat.length - 1]lastMessage['title'] = title;
64156420 chat[chat.length - 1]lastMessage['mes'] = getMessage;
64166421 chat[chat.length - 1]lastMessage['gen_started'] = generation_started;
64176422 chat[chat.length - 1]lastMessage['gen_finished'] = generationFinished;
64186423 chat[chat.length - 1]lastMessage['send_date'] = getMessageTimeStamp();
64196424 chat[chat.length - 1]lastMessage['extra']['api'] = getGeneratingApi();
64206425 chat[chat.length - 1]lastMessage['extra']['model'] = getGeneratingModel();
64216426 chat[chat.length - 1]lastMessage['extra']['reasoning'] = reasoning;
64226427 chat[chat.length - 1]lastMessage['extra']['reasoning_duration'] = null;
64236428 chat[chat.length - 1]lastMessage['extra']['reasoning_signature'] = reasoningSignature;
64246429 await processImageAttachment(chat[chat.length - 1]lastMessage, { imageUrls });
64256430 if (power_user.message_token_count_enabled) {
64266431 const tokenCountText = (reasoning || '') + chat[chat.length - 1]lastMessage['mes'];
64276432 chat[chat.length - 1]lastMessage['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0);
64286433 }
64296434 const chat_id = (chat.length - 1);
64306435 !fromStreaming && await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, type);
64316436 addOneMessage(chat[chat_id], { type: 'swipe' });
64326437 !fromStreaming && await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, chat_id, type);
64336438 } else {
64346439 chat[chat.length - 1]lastMessage['mes'] = getMessage;
64356440 }
64366441 } else if (type === 'append' || type === 'continue') {
64376442 console.debug('Trying to append.');
64386443 oldMessage = chat[chat.length - 1]lastMessage['mes'];
64396444 chat[chat.length - 1]lastMessage['title'] = title;
64406445 chat[chat.length - 1]lastMessage['mes'] += getMessage;
64416446 chat[chat.length - 1]lastMessage['gen_started'] = generation_started;
64426447 chat[chat.length - 1]lastMessage['gen_finished'] = generationFinished;
64436448 chat[chat.length - 1]lastMessage['send_date'] = getMessageTimeStamp();
64446449 chat[chat.length - 1]lastMessage['extra']['api'] = getGeneratingApi();
64456450 chat[chat.length - 1]lastMessage['extra']['model'] = getGeneratingModel();
64466451 chat[chat.length - 1]lastMessage['extra']['reasoning'] = reasoning;
64476452 chat[chat.length - 1]lastMessage['extra']['reasoning_duration'] = null;
64486453 chat[chat.length - 1]lastMessage['extra']['reasoning_signature'] = reasoningSignature;
64496454 await processImageAttachment(chat[chat.length - 1]lastMessage, { imageUrls });
64506455 if (power_user.message_token_count_enabled) {
64516456 const tokenCountText = (reasoning || '') + chat[chat.length - 1]lastMessage['mes'];
64526457 chat[chat.length - 1]lastMessage['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0);
64536458 }
64546459 const chat_id = (chat.length - 1);
64556460 !fromStreaming && await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, type);
64566461 addOneMessage(chat[chat_id], { type: 'swipe' });
64576462 !fromStreaming && await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, chat_id, type);
64586463 } else if (type === 'appendFinal') {
64596464 oldMessage = chat[chat.length - 1]lastMessage['mes'];
64606465 console.debug('Trying to appendFinal.');
64616466 chat[chat.length - 1]lastMessage['title'] = title;
64626467 chat[chat.length - 1]lastMessage['mes'] = getMessage;
64636468 chat[chat.length - 1]lastMessage['gen_started'] = generation_started;
64646469 chat[chat.length - 1]lastMessage['gen_finished'] = generationFinished;
64656470 chat[chat.length - 1]lastMessage['send_date'] = getMessageTimeStamp();
64666471 chat[chat.length - 1]lastMessage['extra']['api'] = getGeneratingApi();
64676472 chat[chat.length - 1]lastMessage['extra']['model'] = getGeneratingModel();
64686473 chat[chat.length - 1]lastMessage['extra']['reasoning'] += reasoning;
64696474 chat[chat.length - 1]lastMessage['extra']['reasoning_signature'] = reasoningSignature;
64706475 await processImageAttachment(chat[chat.length - 1]lastMessage, { imageUrls });
64716476 // We don't know if the reasoning duration extended, so we don't update it here on purpose.
64726477 if (power_user.message_token_count_enabled) {
64736478 const tokenCountText = (reasoning || '') + chat[chat.length - 1]lastMessage['mes'];
64746479 chat[chat.length - 1]lastMessage['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0);
64756480 }
64766481 const chat_id = (chat.length - 1);
64776482 !fromStreaming && await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, type);
@@ -6480,27 +6485,28 @@ export async function saveReply({ type, getMessage, fromStreaming = false, title
64806485
64816486 } else {
64826487 console.debug('entering chat update routine for non-swipe post');
64836488 chat[chat.length]const newMessage = {};
6484- chat[chat.length - 1]['extra'] = {};
6489+ chat.push(newMessage);
64856490 chat[chat.length - 1]newMessage['nameextra'] = name2{};
64866491 chat[chat.length - 1]newMessage['is_username'] = falsename2;
64876492 chat[chat.length - 1]newMessage['send_dateis_user'] = getMessageTimeStamp()false;
64886493 chat[chat.length - 1]['extra']newMessage['apisend_date'] = getGeneratingApigetMessageTimeStamp();
64896494 chat[chat.length - 1]newMessage['extra']['modelapi'] = getGeneratingModelgetGeneratingApi();
64906495 chat[chat.length - 1]newMessage['extra']['reasoningmodel'] = reasoninggetGeneratingModel();
64916496 chat[chat.length - 1]newMessage['extra']['reasoning_durationreasoning'] = nullreasoning;
64926497 chat[chat.length - 1]newMessage['extra']['reasoning_signaturereasoning_duration'] = reasoningSignaturenull;
6498+ newMessage['extra']['reasoning_signature'] = reasoningSignature;
64936499 if (power_user.trim_spaces) {
64946500 getMessage = getMessage.trim();
64956501 }
64966502 chat[chat.length - 1]newMessage['mes'] = getMessage;
64976503 chat[chat.length - 1]newMessage['title'] = title;
64986504 chat[chat.length - 1]newMessage['gen_started'] = generation_started;
64996505 chat[chat.length - 1]newMessage['gen_finished'] = generationFinished;
65006506
65016507 if (power_user.message_token_count_enabled) {
65026508 const tokenCountText = (reasoning || '') + chat[chat.length - 1]newMessage['mes'];
65036509 chat[chat.length - 1]newMessage['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0);
65046510 }
65056511
65066512 if (selected_group) {
@@ -6509,12 +6515,12 @@ export async function saveReply({ type, getMessage, fromStreaming = false, title
65096515 if (characters[this_chid].avatar != 'none') {
65106516 avatarImg = getThumbnailUrl('avatar', characters[this_chid].avatar);
65116517 }
65126518 chat[chat.length - 1]newMessage['force_avatar'] = avatarImg;
65136519 chat[chat.length - 1]newMessage['original_avatar'] = characters[this_chid].avatar;
65146520 chat[chat.length - 1]newMessage['extra']['gen_id'] = group_generation_id;
65156521 }
65166522
65176523 await processImageAttachment(chat[chat.length - 1]newMessage, { imageUrls });
65186524 const chat_id = (chat.length - 1);
65196525
65206526 !fromStreaming && await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, type);
@@ -6538,12 +6544,12 @@ export async function saveReply({ type, getMessage, fromStreaming = false, title
65386544 } else {
65396545 item['swipe_id'] = 0;
65406546 item['swipes'] = [];
65416547 item['swipes'][0] = chat[chat.length - 1]item['mes'];
65426548 item['swipe_info'][0] = {
65436549 send_date: chat[chat.length - 1]item['send_date'],
65446550 gen_started: chat[chat.length - 1]item['gen_started'],
65456551 gen_finished: chat[chat.length - 1]item['gen_finished'],
65466552 extra: structuredClone(chat[chat.length - 1]item['extra']),
65476553 };
65486554 }
65496555
@@ -6564,7 +6570,7 @@ export async function saveReply({ type, getMessage, fromStreaming = false, title
65646570 item.swipe_info.push(...swipeInfoArray);
65656571 }
65666572
65676573 statMesProcess(chat[chat.length - 1]item, type, characters, this_chid, oldMessage);
65686574 return { type, getMessage };
65696575}
65706576
@@ -12035,7 +12041,9 @@ jQuery(async function () {
1203512041 }
1203612042 if (this_edit_mes_id === undefined && $('#mes_stop').is(':visible')) {
1203712043 $('#mes_stop').trigger('click');
12038- if (chat.length && Array.isArray(chat[chat.length - 1].swipes) && chat[chat.length - 1].swipe_id == chat[chat.length - 1].swipes.length) {
12044+ if (chat.length === 0) return;
12045+ const lastMessage = chat[chat.length - 1];
12046+ if (Array.isArray(lastMessage.swipes) && lastMessage.swipe_id == lastMessage.swipes.length) {
1203912047 $('.last_mes .swipe_left').trigger('click');
1204012048 }
1204112049 }
public/scripts/extensions/memory/index.js+9 -5
@@ -427,9 +427,13 @@ async function onChatEvent() {
427427
428428 const context = getContext();
429429 const chat = context.chat;
430+ // Chat can't be empty.
431+ if (chat.length === 0) return;
432+
433+ const lastMessage = chat[chat.length - 1];
430434
431435 // No new messages - do nothing
432436 if (chat.length === 0 || (lastMessageId === chat.length && getStringHash(chat[chat.length - 1]lastMessage.mes) === lastMessageHash)) {
433437 return;
434438 }
435439
@@ -441,11 +445,11 @@ async function onChatEvent() {
441445
442446 // Message has been edited / regenerated - delete the saved memory
443447 if (chat.length
444448 && chat[chat.length - 1]lastMessage.extra
445449 && chat[chat.length - 1]lastMessage.extra.memory
446450 && lastMessageId === chat.length
447451 && getStringHash(chat[chat.length - 1]lastMessage.mes) !== lastMessageHash) {
448452 delete chat[chat.length - 1]lastMessage.extra.memory;
449453 }
450454
451455 summarizeChat(context)