import { MacroRegistry, MacroCategory, MacroValueType } from '../engine/MacroRegistry.js'; import { chat, chat_metadata } from '../../../script.js'; /** * Registers macros that inspect the current chat log and swipe state * (message texts, indices, swipes, and context boundaries). */ export function registerChatMacros() { MacroRegistry.registerMacro('lastMessage', { category: MacroCategory.CHAT, description: 'Last message in the chat.', returns: 'Last message in the chat.', handler: () => String(getLastMessage() ?? ''), }); MacroRegistry.registerMacro('lastMessageId', { category: MacroCategory.CHAT, description: 'Index of the last message in the chat.', returns: 'Index of the last message in the chat.', returnType: MacroValueType.INTEGER, handler: () => String(getLastMessageId() ?? ''), }); MacroRegistry.registerMacro('lastUserMessage', { category: MacroCategory.CHAT, description: 'Last user message in the chat.', returns: 'Last user message in the chat.', handler: () => String(getLastUserMessage() ?? ''), }); MacroRegistry.registerMacro('lastCharMessage', { category: MacroCategory.CHAT, description: 'Last character/bot message in the chat.', returns: 'Last character/bot message in the chat.', handler: () => String(getLastCharMessage() ?? ''), }); MacroRegistry.registerMacro('firstIncludedMessageId', { category: MacroCategory.CHAT, description: 'Index of the first message included in the current context.', returns: 'Index of the first message included in the context.', returnType: MacroValueType.INTEGER, handler: () => String(getFirstIncludedMessageId() ?? ''), }); MacroRegistry.registerMacro('firstDisplayedMessageId', { category: MacroCategory.CHAT, description: 'Index of the first displayed message in the chat.', returns: 'Index of the first displayed message in the chat.', returnType: MacroValueType.INTEGER, handler: () => String(getFirstDisplayedMessageId() ?? ''), }); MacroRegistry.registerMacro('lastSwipeId', { category: MacroCategory.CHAT, description: '1-based index of the last swipe for the last message.', returns: '1-based index of the last swipe.', returnType: MacroValueType.INTEGER, handler: () => String(getLastSwipeId() ?? ''), }); MacroRegistry.registerMacro('currentSwipeId', { category: MacroCategory.CHAT, description: '1-based index of the current swipe.', returns: '1-based index of the current swipe.', returnType: MacroValueType.INTEGER, handler: () => String(getCurrentSwipeId() ?? ''), }); } function getLastMessageId({ exclude_swipe_in_propress = true, filter = null } = {}) { if (!Array.isArray(chat) || chat.length === 0) { return null; } for (let i = chat.length - 1; i >= 0; i--) { const message = chat[i]; if (exclude_swipe_in_propress && message.swipes && message.swipe_id >= message.swipes.length) { continue; } if (!filter || filter(message)) { return i; } } return null; } function getLastMessage() { const mid = getLastMessageId(); return typeof mid === 'number' ? (chat[mid]?.mes ?? '') : ''; } function getLastUserMessage() { const mid = getLastMessageId({ filter: m => m.is_user && !m.is_system }); return typeof mid === 'number' ? (chat[mid]?.mes ?? '') : ''; } function getLastCharMessage() { const mid = getLastMessageId({ filter: m => !m.is_user && !m.is_system }); return typeof mid === 'number' ? (chat[mid]?.mes ?? '') : ''; } function getFirstIncludedMessageId() { const value = chat_metadata['lastInContextMessageId']; return typeof value === 'number' ? value : null; } function getFirstDisplayedMessageId() { const mesElement = document.querySelector('#chat .mes'); const mesId = Number(mesElement?.getAttribute('mesid')); if (!Number.isNaN(mesId) && mesId >= 0) { return mesId; } return null; } function getLastSwipeId() { const mid = getLastMessageId({ exclude_swipe_in_propress: false }); if (typeof mid !== 'number') { return null; } const swipes = chat[mid]?.swipes; return Array.isArray(swipes) ? swipes.length : null; } function getCurrentSwipeId() { const mid = getLastMessageId({ exclude_swipe_in_propress: false }); if (typeof mid !== 'number') { return null; } const swipeId = chat[mid]?.swipe_id; return typeof swipeId === 'number' ? swipeId + 1 : null; }