Google AI Studio | Clear Chat Button

Automates clicking chat turn options and delete buttons in Gemini.

// ==UserScript==
// @name         Google AI Studio | Clear Chat Button
// @namespace    http://violentmonkey.net/
// @version      1.3
// @description  Automates clicking chat turn options and delete buttons in Gemini.
// @author       Vibecoded by Piknockyou
// @match        https://aistudio.google.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=aistudio.google.com
// @grant        GM_addStyle
// @run-at       document-idle
// ==/UserScript==

(function() {
    'use strict';

    // Exit if running in an iframe to avoid duplicate script execution
    if (window.self !== window.top) {
        console.log('[Gemini Chat Cleaner] Exiting script in iframe.');
        return;
    }

    console.log('[Gemini Chat Cleaner] Script loaded and starting...');
    console.log('[Gemini Chat Cleaner] Current URL:', window.location.href);

    //================================================================================
    // CONFIGURATION - All settings, selectors, and values that might need to be changed.
    //================================================================================
    const CHAT_TURN_OPTIONS_SELECTOR = 'ms-chat-turn-options span[class="material-symbols-outlined notranslate ms-button-icon-symbol ng-star-inserted"]';
    const DELETE_BUTTON_MENU_SELECTOR = 'div.mat-mdc-menu-content > button:first-of-type';
    const DELETE_BUTTON_TEXT = "delete Delete";

    //================================================================================
    // STYLES - CSS for the toolbar button (minimal, uses existing toolbar styles)
    //================================================================================
    GM_addStyle(`
        #gemini-cleaner-button {
            margin: 0 4px;
        }
    `);

    //================================================================================
    // HELPER FUNCTIONS - Reusable utility functions
    //================================================================================

    /**
     * Clicks all elements matching a given CSS selector.
     * @param {string} selector The CSS selector for the elements to click.
     */
    function clickAllElements(selector) {
        try {
            const elements = document.querySelectorAll(selector);
            if (elements.length === 0) {
                console.warn(`[Gemini Chat Cleaner] No elements found for selector: ${selector}`);
                return;
            }
            elements.forEach(element => {
                element.click();
            });
            console.log(`[Gemini Chat Cleaner] Clicked ${elements.length} elements for selector: ${selector}`);
        } catch (error) {
            console.error(`[Gemini Chat Cleaner] Error clicking elements for selector ${selector}:`, error);
        }
    }

    /**
     * Clicks delete buttons within a menu content, identified by specific text.
     * @param {string} selector The CSS selector for the menu buttons.
     * @param {string} text The text content to match for the delete button.
     */
    function clickDeleteButtonsInMenu(selector, text) {
        try {
            const elements = document.querySelectorAll(selector);
            if (elements.length === 0) {
                console.warn(`[Gemini Chat Cleaner] No menu elements found for selector: ${selector}`);
                return;
            }
            elements.forEach(element => {
                if (element.textContent.trim() === text) {
                    element.click();
                    console.log(`[Gemini Chat Cleaner] Clicked delete button with text: "${text}"`);
                }
            });
        } catch (error) {
            console.error(`[Gemini Chat Cleaner] Error clicking delete buttons in menu for selector ${selector}:`, error);
        }
    }

    /**
     * Creates and appends a floating button to trigger the cleaning functionality.
     */
    function createToolbarButton() {
        const toolbarRight = document.querySelector('ms-toolbar .toolbar-right');

        // If the toolbar isn't ready, or the button already exists, do nothing.
        if (!toolbarRight || document.getElementById('gemini-cleaner-button')) {
            return;
        }

        console.log('[Gemini Chat Cleaner] Toolbar found, creating button...');

        const button = document.createElement('button');
        button.id = 'gemini-cleaner-button';
        button.title = 'Clear Chat Turns';
        button.setAttribute('ms-button', '');
        button.setAttribute('variant', 'icon-borderless');
        button.setAttribute('mattooltip', 'Clear Chat Turns');
        button.setAttribute('mattooltipposition', 'below');
        button.setAttribute('iconname', 'refresh');
        button.className = 'mat-mdc-tooltip-trigger ng-tns-c2648639672-5 ms-button-borderless ms-button-icon ng-star-inserted';
        button.setAttribute('aria-label', 'Clear Chat Turns');
        button.setAttribute('aria-disabled', 'false');
        button.addEventListener('click', main);

        const iconSpan = document.createElement('span');
        iconSpan.className = 'material-symbols-outlined notranslate ms-button-icon-symbol ng-star-inserted';
        iconSpan.setAttribute('aria-hidden', 'true');
        iconSpan.textContent = 'refresh';

        button.appendChild(iconSpan);

        const moreButton = toolbarRight.querySelector('button[iconname="more_vert"]');
        if (moreButton) {
            toolbarRight.insertBefore(button, moreButton);
            console.log('[Gemini Chat Cleaner] Button inserted before more_vert button.');
        } else {
            toolbarRight.appendChild(button);
            console.log('[Gemini Chat Cleaner] Button appended to toolbar.');
        }

        // Verify button is in DOM
        setTimeout(() => {
            if (document.getElementById('gemini-cleaner-button')) {
                console.log('[Gemini Chat Cleaner] Button successfully added to toolbar.');
            } else {
                console.error('[Gemini Chat Cleaner] Button not found in toolbar after append.');
            }
        }, 100);
    }

    //================================================================================
    // MAIN EXECUTION - Core logic of the script
    //================================================================================
    function main() {
        console.log('[Gemini Chat Cleaner] Main function triggered');
        // Click all chat turn option icons
        clickAllElements(CHAT_TURN_OPTIONS_SELECTOR);

        // Click delete buttons in menu content
        clickDeleteButtonsInMenu(DELETE_BUTTON_MENU_SELECTOR, DELETE_BUTTON_TEXT);
    }

    // --- MutationObserver to watch for toolbar changes ---
    const observer = new MutationObserver((mutationsList) => {
        for (const mutation of mutationsList) {
            if (mutation.type === 'childList') {
                for (const node of mutation.addedNodes) {
                    if (node.nodeType === 1 && (node.tagName === 'MS-TOOLBAR' || node.querySelector('ms-toolbar'))) {
                        // The toolbar was added, so try to add our button.
                        createToolbarButton();
                        return; // Exit after finding the toolbar
                    }
                }
            }
        }
    });

    // --- Initial Execution ---
    function initialize() {
        // Try to add the button immediately in case the toolbar is already there.
        createToolbarButton();

        // Start observing the body for changes.
        observer.observe(document.body, { childList: true, subtree: true });
        console.log('[Gemini Chat Cleaner] MutationObserver started.');
    }

    initialize();

})();