SullyTavern Auto Resend on Empty AI

Automatically clicks the send button in Sully Tavern when "Google AI Studio Candidate text empty" error occurs.

// ==UserScript==
// @name         SullyTavern Auto Resend on Empty AI
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Automatically clicks the send button in Sully Tavern when "Google AI Studio Candidate text empty" error occurs.
// @author       Your Helper
// @match        http://127.0.0.1:8000/*
// @match        http://localhost:8000/*
// @match        http://127.0.0.1:8000
// @match        http://localhost:8000
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    const TARGET_ERROR_SUBSTRING = "Google AI Studio Candidate text empty";
    const BUTTON_ID = "send_but";
    const SCRIPT_PREFIX = "[SullyTavern AutoResend] ";

    let errorHandlingInitialized = false;

    function handleError(errorSource, errorDetails) {
        let errorMessage = "";

        if (typeof errorDetails === 'string') {
            errorMessage = errorDetails;
        } else if (errorDetails instanceof Error) {
            errorMessage = errorDetails.message || "";
        } else if (errorDetails && typeof errorDetails.reason !== 'undefined') { // For unhandledrejection event
            if (errorDetails.reason instanceof Error) {
                errorMessage = errorDetails.reason.message || "";
            } else if (typeof errorDetails.reason === 'string') {
                errorMessage = errorDetails.reason;
            }
        }

        if (typeof errorMessage === 'string' && errorMessage.includes(TARGET_ERROR_SUBSTRING)) {
            console.log(SCRIPT_PREFIX + `Target error detected via ${errorSource}: "${errorMessage}". Clicking send button.`);
            clickSendButton();
        }
    }

    function initializeErrorHandlers() {
        if (errorHandlingInitialized) {
            return;
        }

        // 1. Hook console.error (as a fallback, unhandledrejection is primary for this error)
        if (typeof console !== 'undefined' && typeof console.error !== 'undefined') {
            const originalConsoleError = console.error;
            console.error = function(...args) {
                originalConsoleError.apply(console, args);
                if (args.length > 0) {
                    handleError("console.error", args[0]);
                }
            };
        }

        // 2. Hook unhandled promise rejections (primary method for this error)
        if (typeof window !== 'undefined') {
            window.addEventListener('unhandledrejection', function(event) {
                // We don't need to log the full event object in the final version
                // console.log(SCRIPT_PREFIX + "Unhandled rejection EVENT caught.");
                handleError("unhandledrejection", event);
            });
        }
        errorHandlingInitialized = true;
        console.log(SCRIPT_PREFIX + "Script loaded and error listeners active.");
    }

    function clickSendButton() {
        setTimeout(() => {
            const sendButton = document.getElementById(BUTTON_ID);
            if (sendButton) {
                if (sendButton.offsetParent !== null && !sendButton.disabled) {
                    sendButton.click();
                    // console.log(SCRIPT_PREFIX + "Send button clicked."); // Можно раскомментировать, если хотите видеть подтверждение клика
                } else {
                    console.warn(SCRIPT_PREFIX + `Send button found but is not clickable (Visible: ${sendButton.offsetParent !== null}, Disabled: ${sendButton.disabled}).`);
                }
            } else {
                console.warn(SCRIPT_PREFIX + `Send button with ID "${BUTTON_ID}" NOT FOUND.`);
            }
        }, 100); // 100 мс задержка
    }

    // Initialize handlers
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initializeErrorHandlers);
    } else {
        initializeErrorHandlers();
    }
    window.addEventListener('load', () => {
        if (!errorHandlingInitialized) {
            initializeErrorHandlers();
        }
    });

})();