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>
Signed| @@ -1619,13 +1619,14 @@ export async function sendTextareaMessage() { | ||
| 1619 | 1619 | // "Continue on send" is activated when the user hits "send" (or presses enter) on an empty chat box, and the last |
| 1620 | 1620 | // message was sent from a character (not the user or the system). |
| 1621 | 1621 | const textareaText = String($('#send_textarea').val()); |
| 1622 | + const lastMessage = chat[chat.length - 1]; | |
| 1622 | 1623 | if (power_user.continue_on_send && |
| 1623 | 1624 | !hasPendingFileAttachment() && |
| 1624 | 1625 | !textareaText && |
| 1625 | 1626 | !selected_group && |
| 1626 | 1627 | chat.length && |
| 1627 | 1628 | !chat[chat.length - 1]lastMessage['is_user'] && |
| 1628 | 1629 | !chat[chat.length - 1]lastMessage['is_system'] |
| 1629 | 1630 | ) { |
| 1630 | 1631 | generateType = 'continue'; |
| 1631 | 1632 | } |
| @@ -4191,6 +4192,8 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | ||
| 4191 | 4192 | return Promise.resolve(); |
| 4192 | 4193 | } |
| 4193 | 4194 | |
| 4195 | + const lastMessage = chat[chat.length - 1]; | |
| 4196 | + | |
| 4194 | 4197 | let textareaText; |
| 4195 | 4198 | if (type !== 'regenerate' && type !== 'swipe' && type !== 'quiet' && !isImpersonate && !dryRun) { |
| 4196 | 4199 | is_send_press = true; |
| @@ -4198,7 +4201,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | ||
| 4198 | 4201 | $('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles: true })); |
| 4199 | 4202 | } else { |
| 4200 | 4203 | textareaText = ''; |
| 4201 | 4204 | if (chat.length && chat[chat.length - 1]lastMessage['is_user']) { |
| 4202 | 4205 | //do nothing? why does this check exist? |
| 4203 | 4206 | } |
| 4204 | 4207 | 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 | ||
| 4212 | 4215 | |
| 4213 | 4216 | // Rewrite the generation timer to account for the time passed for all the continuations. |
| 4214 | 4217 | if (isContinue && chat.length) { |
| 4215 | 4218 | const prevFinished = chat[chat.length - 1]lastMessage['gen_finished']; |
| 4216 | 4219 | const prevStarted = chat[chat.length - 1]lastMessage['gen_started']; |
| 4217 | 4220 | |
| 4218 | 4221 | if (prevFinished && prevStarted) { |
| 4219 | 4222 | const timePassed = Number(prevFinished) - Number(prevStarted); |
| 4220 | 4223 | generation_started = new Date(Date.now() - timePassed); |
| 4221 | 4224 | chat[chat.length - 1]lastMessage['gen_started'] = generation_started; |
| 4222 | 4225 | } |
| 4223 | 4226 | } |
| 4224 | 4227 | |
| @@ -6387,18 +6390,20 @@ export async function saveReply({ type, getMessage, fromStreaming = false, title | ||
| 6387 | 6390 | [type, getMessage, fromStreaming, title, swipes, reasoning, imageUrls, reasoningSignature] = arguments; |
| 6388 | 6391 | } |
| 6389 | 6392 | |
| 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'])) { | |
| 6392 | 6397 | type = 'normal'; |
| 6393 | 6398 | } |
| 6394 | 6399 | |
| 6395 | 6400 | if (chat.length && (!chat[chat.length - 1]lastMessage['extra'] || typeof chat[chat.length - 1]lastMessage['extra'] !== 'object')) { |
| 6396 | 6401 | chat[chat.length - 1]lastMessage['extra'] = {}; |
| 6397 | 6402 | } |
| 6398 | 6403 | |
| 6399 | 6404 | // Coerce null/undefined to empty string |
| 6400 | 6405 | if (chat.length && !chat[chat.length - 1]lastMessage['extra']['reasoning']) { |
| 6401 | 6406 | chat[chat.length - 1]lastMessage['extra']['reasoning'] = ''; |
| 6402 | 6407 | } |
| 6403 | 6408 | |
| 6404 | 6409 | if (!reasoning) { |
| @@ -6408,70 +6413,70 @@ export async function saveReply({ type, getMessage, fromStreaming = false, title | ||
| 6408 | 6413 | let oldMessage = ''; |
| 6409 | 6414 | const generationFinished = new Date(); |
| 6410 | 6415 | if (type === 'swipe') { |
| 6411 | 6416 | oldMessage = chat[chat.length - 1]lastMessage['mes']; |
| 6412 | 6417 | chat[chat.length - 1]lastMessage['swipes'].length++; |
| 6413 | 6418 | if (chat[chat.length - 1]lastMessage['swipe_id'] === chat[chat.length - 1]lastMessage['swipes'].length - 1) { |
| 6414 | 6419 | chat[chat.length - 1]lastMessage['title'] = title; |
| 6415 | 6420 | chat[chat.length - 1]lastMessage['mes'] = getMessage; |
| 6416 | 6421 | chat[chat.length - 1]lastMessage['gen_started'] = generation_started; |
| 6417 | 6422 | chat[chat.length - 1]lastMessage['gen_finished'] = generationFinished; |
| 6418 | 6423 | chat[chat.length - 1]lastMessage['send_date'] = getMessageTimeStamp(); |
| 6419 | 6424 | chat[chat.length - 1]lastMessage['extra']['api'] = getGeneratingApi(); |
| 6420 | 6425 | chat[chat.length - 1]lastMessage['extra']['model'] = getGeneratingModel(); |
| 6421 | 6426 | chat[chat.length - 1]lastMessage['extra']['reasoning'] = reasoning; |
| 6422 | 6427 | chat[chat.length - 1]lastMessage['extra']['reasoning_duration'] = null; |
| 6423 | 6428 | chat[chat.length - 1]lastMessage['extra']['reasoning_signature'] = reasoningSignature; |
| 6424 | 6429 | await processImageAttachment(chat[chat.length - 1]lastMessage, { imageUrls }); |
| 6425 | 6430 | if (power_user.message_token_count_enabled) { |
| 6426 | 6431 | const tokenCountText = (reasoning || '') + chat[chat.length - 1]lastMessage['mes']; |
| 6427 | 6432 | chat[chat.length - 1]lastMessage['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0); |
| 6428 | 6433 | } |
| 6429 | 6434 | const chat_id = (chat.length - 1); |
| 6430 | 6435 | !fromStreaming && await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, type); |
| 6431 | 6436 | addOneMessage(chat[chat_id], { type: 'swipe' }); |
| 6432 | 6437 | !fromStreaming && await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, chat_id, type); |
| 6433 | 6438 | } else { |
| 6434 | 6439 | chat[chat.length - 1]lastMessage['mes'] = getMessage; |
| 6435 | 6440 | } |
| 6436 | 6441 | } else if (type === 'append' || type === 'continue') { |
| 6437 | 6442 | console.debug('Trying to append.'); |
| 6438 | 6443 | oldMessage = chat[chat.length - 1]lastMessage['mes']; |
| 6439 | 6444 | chat[chat.length - 1]lastMessage['title'] = title; |
| 6440 | 6445 | chat[chat.length - 1]lastMessage['mes'] += getMessage; |
| 6441 | 6446 | chat[chat.length - 1]lastMessage['gen_started'] = generation_started; |
| 6442 | 6447 | chat[chat.length - 1]lastMessage['gen_finished'] = generationFinished; |
| 6443 | 6448 | chat[chat.length - 1]lastMessage['send_date'] = getMessageTimeStamp(); |
| 6444 | 6449 | chat[chat.length - 1]lastMessage['extra']['api'] = getGeneratingApi(); |
| 6445 | 6450 | chat[chat.length - 1]lastMessage['extra']['model'] = getGeneratingModel(); |
| 6446 | 6451 | chat[chat.length - 1]lastMessage['extra']['reasoning'] = reasoning; |
| 6447 | 6452 | chat[chat.length - 1]lastMessage['extra']['reasoning_duration'] = null; |
| 6448 | 6453 | chat[chat.length - 1]lastMessage['extra']['reasoning_signature'] = reasoningSignature; |
| 6449 | 6454 | await processImageAttachment(chat[chat.length - 1]lastMessage, { imageUrls }); |
| 6450 | 6455 | if (power_user.message_token_count_enabled) { |
| 6451 | 6456 | const tokenCountText = (reasoning || '') + chat[chat.length - 1]lastMessage['mes']; |
| 6452 | 6457 | chat[chat.length - 1]lastMessage['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0); |
| 6453 | 6458 | } |
| 6454 | 6459 | const chat_id = (chat.length - 1); |
| 6455 | 6460 | !fromStreaming && await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, type); |
| 6456 | 6461 | addOneMessage(chat[chat_id], { type: 'swipe' }); |
| 6457 | 6462 | !fromStreaming && await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, chat_id, type); |
| 6458 | 6463 | } else if (type === 'appendFinal') { |
| 6459 | 6464 | oldMessage = chat[chat.length - 1]lastMessage['mes']; |
| 6460 | 6465 | console.debug('Trying to appendFinal.'); |
| 6461 | 6466 | chat[chat.length - 1]lastMessage['title'] = title; |
| 6462 | 6467 | chat[chat.length - 1]lastMessage['mes'] = getMessage; |
| 6463 | 6468 | chat[chat.length - 1]lastMessage['gen_started'] = generation_started; |
| 6464 | 6469 | chat[chat.length - 1]lastMessage['gen_finished'] = generationFinished; |
| 6465 | 6470 | chat[chat.length - 1]lastMessage['send_date'] = getMessageTimeStamp(); |
| 6466 | 6471 | chat[chat.length - 1]lastMessage['extra']['api'] = getGeneratingApi(); |
| 6467 | 6472 | chat[chat.length - 1]lastMessage['extra']['model'] = getGeneratingModel(); |
| 6468 | 6473 | chat[chat.length - 1]lastMessage['extra']['reasoning'] += reasoning; |
| 6469 | 6474 | chat[chat.length - 1]lastMessage['extra']['reasoning_signature'] = reasoningSignature; |
| 6470 | 6475 | await processImageAttachment(chat[chat.length - 1]lastMessage, { imageUrls }); |
| 6471 | 6476 | // We don't know if the reasoning duration extended, so we don't update it here on purpose. |
| 6472 | 6477 | if (power_user.message_token_count_enabled) { |
| 6473 | 6478 | const tokenCountText = (reasoning || '') + chat[chat.length - 1]lastMessage['mes']; |
| 6474 | 6479 | chat[chat.length - 1]lastMessage['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0); |
| 6475 | 6480 | } |
| 6476 | 6481 | const chat_id = (chat.length - 1); |
| 6477 | 6482 | !fromStreaming && await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, type); |
| @@ -6480,27 +6485,28 @@ export async function saveReply({ type, getMessage, fromStreaming = false, title | ||
| 6480 | 6485 | |
| 6481 | 6486 | } else { |
| 6482 | 6487 | console.debug('entering chat update routine for non-swipe post'); |
| 6483 | 6488 | chat[chat.length]const newMessage = {}; |
| 6484 | - chat[chat.length - 1]['extra'] = {}; | |
| 6489 | + chat.push(newMessage); | |
| 6485 | 6490 | chat[chat.length - 1]newMessage['nameextra'] = name2{}; |
| 6486 | 6491 | chat[chat.length - 1]newMessage['is_username'] = falsename2; |
| 6487 | 6492 | chat[chat.length - 1]newMessage['send_dateis_user'] = getMessageTimeStamp()false; |
| 6488 | 6493 | chat[chat.length - 1]['extra']newMessage['apisend_date'] = getGeneratingApigetMessageTimeStamp(); |
| 6489 | 6494 | chat[chat.length - 1]newMessage['extra']['modelapi'] = getGeneratingModelgetGeneratingApi(); |
| 6490 | 6495 | chat[chat.length - 1]newMessage['extra']['reasoningmodel'] = reasoninggetGeneratingModel(); |
| 6491 | 6496 | chat[chat.length - 1]newMessage['extra']['reasoning_durationreasoning'] = nullreasoning; |
| 6492 | 6497 | chat[chat.length - 1]newMessage['extra']['reasoning_signaturereasoning_duration'] = reasoningSignaturenull; |
| 6498 | + newMessage['extra']['reasoning_signature'] = reasoningSignature; | |
| 6493 | 6499 | if (power_user.trim_spaces) { |
| 6494 | 6500 | getMessage = getMessage.trim(); |
| 6495 | 6501 | } |
| 6496 | 6502 | chat[chat.length - 1]newMessage['mes'] = getMessage; |
| 6497 | 6503 | chat[chat.length - 1]newMessage['title'] = title; |
| 6498 | 6504 | chat[chat.length - 1]newMessage['gen_started'] = generation_started; |
| 6499 | 6505 | chat[chat.length - 1]newMessage['gen_finished'] = generationFinished; |
| 6500 | 6506 | |
| 6501 | 6507 | if (power_user.message_token_count_enabled) { |
| 6502 | 6508 | const tokenCountText = (reasoning || '') + chat[chat.length - 1]newMessage['mes']; |
| 6503 | 6509 | chat[chat.length - 1]newMessage['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0); |
| 6504 | 6510 | } |
| 6505 | 6511 | |
| 6506 | 6512 | if (selected_group) { |
| @@ -6509,12 +6515,12 @@ export async function saveReply({ type, getMessage, fromStreaming = false, title | ||
| 6509 | 6515 | if (characters[this_chid].avatar != 'none') { |
| 6510 | 6516 | avatarImg = getThumbnailUrl('avatar', characters[this_chid].avatar); |
| 6511 | 6517 | } |
| 6512 | 6518 | chat[chat.length - 1]newMessage['force_avatar'] = avatarImg; |
| 6513 | 6519 | chat[chat.length - 1]newMessage['original_avatar'] = characters[this_chid].avatar; |
| 6514 | 6520 | chat[chat.length - 1]newMessage['extra']['gen_id'] = group_generation_id; |
| 6515 | 6521 | } |
| 6516 | 6522 | |
| 6517 | 6523 | await processImageAttachment(chat[chat.length - 1]newMessage, { imageUrls }); |
| 6518 | 6524 | const chat_id = (chat.length - 1); |
| 6519 | 6525 | |
| 6520 | 6526 | !fromStreaming && await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, type); |
| @@ -6538,12 +6544,12 @@ export async function saveReply({ type, getMessage, fromStreaming = false, title | ||
| 6538 | 6544 | } else { |
| 6539 | 6545 | item['swipe_id'] = 0; |
| 6540 | 6546 | item['swipes'] = []; |
| 6541 | 6547 | item['swipes'][0] = chat[chat.length - 1]item['mes']; |
| 6542 | 6548 | item['swipe_info'][0] = { |
| 6543 | 6549 | send_date: chat[chat.length - 1]item['send_date'], |
| 6544 | 6550 | gen_started: chat[chat.length - 1]item['gen_started'], |
| 6545 | 6551 | gen_finished: chat[chat.length - 1]item['gen_finished'], |
| 6546 | 6552 | extra: structuredClone(chat[chat.length - 1]item['extra']), |
| 6547 | 6553 | }; |
| 6548 | 6554 | } |
| 6549 | 6555 | |
| @@ -6564,7 +6570,7 @@ export async function saveReply({ type, getMessage, fromStreaming = false, title | ||
| 6564 | 6570 | item.swipe_info.push(...swipeInfoArray); |
| 6565 | 6571 | } |
| 6566 | 6572 | |
| 6567 | 6573 | statMesProcess(chat[chat.length - 1]item, type, characters, this_chid, oldMessage); |
| 6568 | 6574 | return { type, getMessage }; |
| 6569 | 6575 | } |
| 6570 | 6576 | |
| @@ -12035,7 +12041,9 @@ jQuery(async function () { | ||
| 12035 | 12041 | } |
| 12036 | 12042 | if (this_edit_mes_id === undefined && $('#mes_stop').is(':visible')) { |
| 12037 | 12043 | $('#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) { | |
| 12039 | 12047 | $('.last_mes .swipe_left').trigger('click'); |
| 12040 | 12048 | } |
| 12041 | 12049 | } |
| @@ -427,9 +427,13 @@ async function onChatEvent() { | ||
| 427 | 427 | |
| 428 | 428 | const context = getContext(); |
| 429 | 429 | const chat = context.chat; |
| 430 | + // Chat can't be empty. | |
| 431 | + if (chat.length === 0) return; | |
| 432 | + | |
| 433 | + const lastMessage = chat[chat.length - 1]; | |
| 430 | 434 | |
| 431 | 435 | // No new messages - do nothing |
| 432 | 436 | if (chat.length === 0 || (lastMessageId === chat.length && getStringHash(chat[chat.length - 1]lastMessage.mes) === lastMessageHash)) { |
| 433 | 437 | return; |
| 434 | 438 | } |
| 435 | 439 | |
| @@ -441,11 +445,11 @@ async function onChatEvent() { | ||
| 441 | 445 | |
| 442 | 446 | // Message has been edited / regenerated - delete the saved memory |
| 443 | 447 | if (chat.length |
| 444 | 448 | && chat[chat.length - 1]lastMessage.extra |
| 445 | 449 | && chat[chat.length - 1]lastMessage.extra.memory |
| 446 | 450 | && lastMessageId === chat.length |
| 447 | 451 | && getStringHash(chat[chat.length - 1]lastMessage.mes) !== lastMessageHash) { |
| 448 | 452 | delete chat[chat.length - 1]lastMessage.extra.memory; |
| 449 | 453 | } |
| 450 | 454 | |
| 451 | 455 | summarizeChat(context) |